Introduction
Before we start I have made the step-by-step guide linked in the Table of Contents so you can skip the story and jump straight to the guide if you don't want to read my adventure.
If your anything like me, the recent news about discord rolling out it's age-verification globally[1] has you a bit on edge. I am not one that particularly likes corporations having all my info, but I tolerate it for some services. The part that made this particular announcement spur me to action is the fact that they recently had a massive data breach of "a third party service provider ... [effecting] approximately 70,000 users that may have had government-ID photos exposed"[2]. Due to privacy and identity theft concerns I began to look into alternatives to discord that I could host myself, and that is when I found Matrix. As someone with a background in IT and running a home-lab (I run some home-lab alternatives, Immich (A Google Photos Alternative), Jellyfin (A Netflix Alternative), and Truenas (A Network Storage server that runs the previous apps and can replace Google Drive - I personally use HexOS to make the Truenas easier)) I set out to spin up a Matrix server.
Initial Set Up
I began my journey by looking into what exactly Matrix is. Matrix is a federated service protocol, that means its like e-mail, you can have a bunch of different providers that can all talk and send info to one another using a defined protocol. This means by its very nature it is decentralized, using the e-mail analogy, if you have an account at gmail, you can talk to people that have an account at yahoo, and if yahoo shuts down you still have your e-mail, and people can still talk to you from other e-mail providers like proton. Matrix works the same way, you have an account on a server and can talk to anyone else with a Matrix account, even if they are not on the same server.
This is nice because it allows you to host your own server and store all your personal information on it, only sending the messages to another server if you talk to a user on that server. Matrix also supports end-to-end encryption, allowing any group of people to communicate securely as log as everyone's clients support the encryption.
Now that we have a better understanding of why I chose Matrix, let get into the set-up. I started setting it up by making a fresh Hyper-V virtual machine (any VM software should work, VirtualBox is a good choice too) and installing Ubuntu Server on it. I chose to go with a new virtual machine because I did not have a dedicated kubernetes machine and I wanted to make one for any kubernetes based servers I may want to add in the future. I chose to go with the Element Server Suite (ESS) Community Edition, as it had several feature I wanted, including a web-based client built into the package. I followed the guide and got it installed, but it was not quite working. See I use an Apache server as a reverse proxy and web host (This is so that I can manage all my SSL certificates in one place, and use https with non-https services), so I needed to configure it to work.
Troubleshooting
This is where I started running into problems. See most of the documentation on ESS is for the Pro version, so it doesn't really help when using the Community Edition. The first problem I ran into was that my server was not able to be found by clients or by other servers. (You can test and see if your server can be found by other servers with this tool.) Turns out that there is specific files that your domain is checked for located at "/.well-known/matrix/". The problem with this is that they are generated inside the kubernetes, and need to be located on the main domain, not your matrix subdomain. To do this you need to modify your apache configuration for the main site to direct /.well-known/matrix url calls to your kubernetes box. Once I had done that I began running into a different issues with the client configuration. See I wanted to use a central identity server hosted by Element, Vector.im. An Identity server is a central location that can pair your e-mail and phone with your username, allowing people with your contact information to look you up on Matrix. The problem with this is that it requires modifying the /.well-known/matrix/client file, which would have been easier to do during the initial install.
Once I had finished fixing all those issues I encountered my final and largest issue, voice calls. See Matrix uses a Real-Time Communications (RTC) server to handel the voice and video calls. This requires some port-forwarding for it to work, which I had already done. It took me several hours of research before I would eventually stumble onto the problem I was have. See the RTC server uses websockets to handel the calls, not too surprising, but the problem I had was that I was not properly passing the http upgrade to websocket requests to the RTC server, instead they were getting stuck in my apache server. Once I had tweaked the Apache configuration to properly pass the upgrade requests I finally had a working Matrix server, completely behind my reverse proxy.
Conclusion
I set out to run an alternative to Discord on my own hardware, and I succeeded, despite the issues I ran into. I would highly recommend doing this if you are concerned about the growing mass of personal information companies have and are regularly having breached (a record breaking 3,332 U.S. based data breaches in 2025 alone[3]). Hopefully you can use the below guide to skip the hour os troubleshooting it took for me to get it working.
Step-By-Step Guide
Note: These steps are for debian-based linux, specifically Ubuntu Server. This guide is similar to the one found on the project's Github, however I have tweaked some of the steps to make it work with an apache reverse proxy server.- Your first step is to register your domain and subdomains with your registrar (I
personally
use No-IP). You want to register the main domain
and
then five subdomains. The tld below stands for top-level domain, which is (com, org,
us,
io, net, etc.) These are:
- yourdomain.tld
- account.yourdomain.tld
- admin.yourdomain.tld
- chat.yourdomain.tld
- matrix.yourdomain.tld
- mrtc.yourdomain.tld
- Your second step is to set up a kubernetes box
using
the steps below. (Skip to step three if you already have a kubernetes box with Helm installed)
- Run the following command to install K3s:
Copy to clipboardcurl -sfL https://get.k3s.io | sh - - Once K3s is set up, copy its kubeconfig to your home directory to get access
to it:
- Add export KUBECONFIG=~/.kube/config to ~/.bashrc to make it persistent:
Copy to clipboardecho 'export KUBECONFIG=~/.kube/config' >> ~/.bashrc - Install Helm, the Kubernetes Package Manager. You can use your OS repository
or call the following command:
- Run the following command to install K3s:
- Next you need to port forward the following ports to your kubernetes box:
- TCP 30881: This port will be used for the TCP WebRTC connections of Matrix RTC Backend.
- UDP 30882: This port will be used for the Muxed WebRTC connections of Matrix RTC Backend.
- Create your Kubernetes namespace where you will deploy the Element Server Suite
Community:
Copy to clipboardkubectl create namespace ess - Create a directory containing your Element Server Suite configuration values:
Copy to clipboardmkdir ~/ess-config-values - Use the following command to get the external-ip provisioned by Kubernetes for
Traefik :
Copy to clipboardkubectl get svc/traefik -n kube-system
The results will look something like:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.43.184.49 172.20.1.60 80:32100/TCP,443:30129/TCP 5d18h - In such a case, you will need to set up K3S with custom ports. Create a file
`/var/lib/rancher/k3s/server/manifests/traefik-config.yaml` with the following:
traefik-config.yaml
- K3s will apply the file content automatically. You can verify its ports using the
command :
Copy to clipboardkubectl get svc -n kube-system | grep traefik
The results will look something like:
traefik LoadBalancer 10.43.184.49 172.20.1.60 8080:32100/TCP,8443:30129/TCP 5d18h - If the certificates are handled in your reverse proxy, you can point to port 8080
(HTTP) only and disable TLS in ESS. Copy the file
'charts/matrix-stack/ci/fragments/quick-setup-external-cert.yaml' to tls.yaml.
- Configure your reverse proxy so that the DNS names you configured are routed to the
external IP of Traefik on port 8080 (HTTP) and 8443 (HTTPS). (Since I am using the
reverse proxy for the certificates, you will see the Apache site configuration files below contain
only port
8080):
account.yourdomain.tld.conf
account.yourdomain.tld-le-ssl.conf
admin.yourdomain.tld.conf
admin.yourdomain.tld-le-ssl.conf
chat.yourdomain.tld.conf
chat.yourdomain.tld-le-ssl.conf
matrix.yourdomain.tld.conf
matrix.yourdomain.tld-le-ssl.conf
mrtc.yourdomain.tld.conf
mrtc.yourdomain.tld-le-ssl.conf
- For a quick setup using the default settings, copy the file from
'charts/matrix-stack/ci/fragments/quick-setup-hostnames.yaml' to hostnames.yaml in
your ESS configuration values directory and edit the hostnames accordingly.
- Create the following ~/ess-config-values/values.yaml file:
values.yaml
- Run the setup using the following helm command (If it times out you can add
`--timeout 10m` to the end to extent the timeout time (Default is 5m) as long as you
need (10m is 10 minutes)):
- Once that is complete it is time to set up your first user using the command
below:
- The final step is to test and make sure everything works, listed below is what you
need to check:
- Log into your Element Web client website (https://client.yourdomain.tld) and log in with the user you created above.
- Verify that federation works fine using Matrix Federation Tester.
- Login with an Element X mobile client with the user you created above.
- Login with a desktop client like Element
- Preform a test video call to verify that the RTC server is working properly.
Resources and Information
- Resources used in this Project:
- Matrix - Information about the Protocol, server options, and client options
- VirtualBox - Virtual Machine Hosting Software
- Ubuntu Server - The Operating System used in this Setup
- Kubernetes Documentation - In case you get stuck trying to do something not covered here
- Element Server Suite (ESS) Community Edition - The Matrix server used
- Element Server Suite (ESS) Community Edition Github - Contains the guide that this was based from, as well as extra documentation
- Matrix Federation Tester - A toll that will test the domain you give it to see if it can find your Matrix server
- Vector.im - This is the link to the identity server used in this set up, but you could use a different one
- Matrix-Stack Documentation - Good resource if you want to add more values to the values.yaml file to modify the setup
- LetsEncrypt - Free SSL Certificate service
- Certbot - The tool used to obtain signed SSL certificates from LetsEncrypt
- Other Self Hosting Alternatives: