Setting Up a Matrix Server on Ubuntu 20.04 – Part 1

For about the past six months or so, I’ve been interested in the open, decentralized communications standard called Matrix. In May of this year, it was announced on TechCrunch that Automattic had invested $4.6 million into the company behind the Matrix standard. The company in question, New Vector (now rebranded as Element) also develop an open-source chat client, which is a rival to Slack, that runs on the Matrix standard. This is the part that made me sit up and take notice. Matt Mullenweg is the CEO of Automattic and the co-founder and BDFL for WordPress. His decision to invest in this open-source communications standard, which offers an alternative to Slack, could very well mean that in the near future, both the internal communication at Automattic and that of the WordPress project, could end up running on Matrix.

For some time now, myself and the other admins of the WP South Africa Slack community, have been considering switching away from Slack. The main reason for this is that Slack doesn’t offer an option for open source communities to get any premium plan features, so unless we’re prepared to pay $8 USD per person for our over 1000 members we’re stuck with the free version. It also means we don’t “own” our open source community’s communication channels. If Slack ever dropped the free plan, which could happen, we’d be stuck up the proverbial creek.

I decided it was time I took a look at what it would take to get a Matrix homeserver set up, what the pros and cons would be, and if it would be possible to migrate all our users over to our own homeserver.


In order to set up a Matrix homeserver, I would need a web server instance to host it. Fortunately, I have a Digital Ocean account, so spinning up a new basic VPS droplet with Ubuntu 20.04, 1GB of RAM, 1 vCPU and 25GB of storage at $5 a month was a click of a few buttons. The other requirement was to have a public domain pointing to the IP address of the server. I asked Hugh, who manages the domain, to set up an A record in the DNS to point the subdomain to the new server IP address. You can also use a regular top-level domain (eg but if you already have a domain (for example for your community website), using a subdomain for the Matrix server means not needing to purchase a new one.

Initial set up

A note on commands, I’m running all the commands for this server as the root user. If you have access to your web server via another user with sudo privileges, I suggest switching to the root user, it will just make everything easier.

sudo su

The first step with a new server is to make sure the server software is up to date.

apt update && apt upgrade

Then, I needed to ensure that any package dependencies for the matrix-synapse server software are installed.

apt install lsb-release wget apt-transport-https

While there are official matrix-synapse packages in the Ubuntu repositories, the matrix-synapse docs recommend using their own packages. To do that I first had to enable those packages, by adding the GPG key and the matrix-synapse repository for a Debian/Ubuntu-based system.

wget -qO /usr/share/keyrings/matrix-org-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/matrix-org-archive-keyring.gpg] $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/matrix-org.list

Once the repository is set up, I can get the latest package updates, which will now include the Matrix ones, and install the matrix-synapse homeserver software.

apt update
apt install matrix-synapse-py3

During the install, I enter the chosen domain (in my case our subdomain) as the server name. I can also choose not to send Anonymous Data Statistics, but that’s entirely up to you.

Once it’s all installed, I start the matrix-synapse server, and enable it to auto-start on system boot.

systemctl start matrix-synapse
systemctl enable matrix-synapse

Configure Matrix Synapse

Firstly, I needed to generate a random string which is used as the Matrix Synapse registration secret. This I did using the following command.

cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1

The server outputs the random key, which I copied and saved somewhere safe for later.


No, this isn’t the key for our Matrix homeserver! 🙂

The next step is to edit the homeserver.yaml configuration file, which is in the /etc/matrix-synapse directory. For this tutorial, I’m using nano, but you can use whatever CLI text editor you prefer.

nano /etc/matrix-synapse/homeserver.yaml

I searched for and changed the registration_shared_secret entry, and used the randomly generated key created earlier. It’s important to note that the key should be enclosed by double-quotes.

registration_shared_secret: "YC9h8djIiCaCinWxkE2zt9cgvXYGX25P"

I then saved and closed the homeserver.yaml file.

Then, I restarted the matrix-synapse service, which will apply the new configuration.

systemctl restart matrix-synapse

Generate SSL

My next step was setting up the webserver software Nginx as a reverse proxy for the Matrix Synapse server. Before I could do that, I needed to generate an SSL certificate, to make sure the traffic to and from the server is secure. This can be accomplished using a LetsEncrypt certificate, for which I need to install certbot.

apt install certbot

Once certbot is installed, I generated the SSL certificate, using my email address, and the subdomain we have pointing to the IP address of the webserver.

certbot certonly --rsa-key-size 2048 --standalone --agree-tos --no-eff-email --email -d

Once this is completed, the SSL certificate and chain were saved at /etc/letsencrypt/live/ and the SSL key file was been saved at /etc/letsencrypt/live/ This information will become useful when I set up Nginx in the next step.

Setup Nginx as a Reverse Proxy

Setting up a reverse proxy allows Matrix clients to connect to your server securely through the default HTTPS port (443) without needing to run Synapse with root privileges. So first I install Nginx.

apt install nginx

Once installed, I create a virtual host file, to manage the incoming connections.

nano /etc/nginx/sites-available/matrix

The virtual host file configuration redirects all traffic from port 80 (HTTP) to port 443 (HTTPS), configures the SSL port with the certificates created earlier, redirects any requests to the /_matrix endpoint on the domain to the Matrix Synpse server, and configures port 8448, which is used by the Matrix Federation APIs to allow Matrix homeservers to communicate with each other.

server {
    listen 80;
    return 301 https://$host$request_uri;

server {
    listen 443 ssl;

    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;

    location /_matrix {
        proxy_pass http://localhost:8008;
        proxy_set_header X-Forwarded-For $remote_addr;
        # Nginx by default only allows file uploads up to 1M in size
        # Increase client_max_body_size to match max_upload_size defined in homeserver.yaml
        client_max_body_size 10M;

# This is used for Matrix Federation
# which is using default TCP port '8448'
server {
    listen 8448 ssl;

    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;

    location / {
        proxy_pass http://localhost:8008;
        proxy_set_header X-Forwarded-For $remote_addr;

Once the file is saved and closed, I can enable the Nginx virtual host, and test to make sure there were no issues.

ln -s /etc/nginx/sites-available/matrix /etc/nginx/sites-enabled/
nginx -t

Finally, I restart Nginx, and enable it to start at system boot.

systemctl restart nginx
systemctl enable nginx

UFW Firewall

With the basics set up, it would now be a good idea to add some firewall rules, to ensure the rest of the server ports are locked down. I add the ssh, http, https, and the TCP port ‘8448’ to the UFW firewall using the command below.

for svc in ssh http https 8448
ufw allow $svc

After the rules are added, I enable the firewall and check the firewall rules, using these two commands.

ufw enable
ufw status numbered

At this point, I usually log into the server via SSH in a new terminal just to be sure I’ve not locked myself out of SSH access.

Test the Matrix Synapse homeserver

If everything is set up correctly, at this point you should be able to browse to the below URL, enter the server domain, and check if a successful call can be made to your homeserver.

If you see Success message, congratulations! You’ve successfully set up your Matrix Synapse server. However, there’s still more to be done, which we will dive into in part 2 of this tutorial.






17 responses to “Setting Up a Matrix Server on Ubuntu 20.04 – Part 1”

  1. Aaron Avatar

    Reading both part 1 and 2 are a pretty a good intro to setting up your first Matrix server but there is one big thing I would change about the post.

    Setting the server name is a very important thing to get right because once you set it, it can never be changed later without completely resetting the database and starting over. In general you should set the server name to the same domain you already use for your website or your email address. So if your website is on or your email addresses are in the format then your Matrix server name should be

    You should avoid using a Matrix specific domain such as This would cause you to have usernames like or room aliases like Having the matrix subdomain on there is a bit unnecessary and ugly. It would be like having email addresses in the format of It’s extra stuff to type for really no good reason.

    Setting your server name to does NOT mean that you have to mess up any existing websites or services you host there. The server name is the human facing name of your server but you don’t have to serve the Matrix APIs from that domain. The Matrix APIs can delegated from to another other domain such as See for how to do that.

    (Another tip is to just go ahead and setup the Postgres database from the beginning rather than using SQLite to start with and then having to switch to Postgres later)

    1. Jonathan Avatar

      Thanks Aaron, I was not aware of this. I’ll look at redoing the server this week, and updating the post.

  2. Wolf Avatar

    Hi Jonothan, good howto, unsuccessfully tried a number of different ones. Yours worked sweetly. I used to live in Durban 30 years ago, so know the sethafrican approach 🙂

    I am looking for an admin GUI or web GUi or admin tool to create users without going the command line route via ssh.

    Or can I use a mobile client as an admin user to create new users on my home server?

    Any tips?

    1. Jonathan Avatar

      Howzit! 🙂

      What I’ve been doing is getting folks to install the Element desktop client, and signing up to join my homeserver.

      The steps are:

      1. Install the Element client for your OS here
      2. Open Element, and click the “Create Account” link at the bottom of the sign up screen
      3. Select the Advanced -> Other option, enter the url to your Matrix homeserver as the homeserver URL and click next
      4. Enter thei chosen username and password combination, and click Register

      If you are using Element you can also invite external users to your homeserver via the Start Chat option next to People, apparently, if you invite someone via email they’d be able to sign up, but I’ve not tried that yet.

      1. Jonathan Avatar

        Aaron, that’s extremely useful, thanks. I will add this to my next blog post.

  3. H F Avatar


    I followed your instructions and set up the server. However, when I make a call with another user on the same server, the connection could not be established. Element pops up a message: Debug: event type “”. If the other user is in the same wifi network, the call can be made.

    Please could you give some suggestions on the problems?

    Many thanks.

  4. Vincent Heuken Avatar
    Vincent Heuken


    Great tutorial. I had some issues with the Matrix Federation Tester giving me a connection refused error with the IPv6 address associated with my server and domain. Worked fine with IPv4, though.

    I fixed it by changing the following line in the Nginx config:

    listen 8448 ssl;


    listen [::]:8448 ssl ipv6only=off;

    This fixed my issue.

    I’m not an expert so I’m not sure if that will work in the absence of an IPv6 address, but it seems to work fine for me.

  5. Trevor Avatar

    Everything was great except nginx reverse proxy didn’t work and I just got the nginx welcome page. I dispensed with the sites-available/enabled and dumped a conf file in /etc/nginx/conf.d and that did the trick.

    Thanks for you guide. I’m setting this up for a friend.

    1. Jonathan Avatar

      Awesome, glad it worked for you.

    2. Ethan Avatar

      Hi Trevor,

      What exactly did you put in the conf file? I can’t seem to get anything other than the default welcome page to display.

      1. Vitaly Ivanov Avatar
        Vitaly Ivanov

        I had the exact same problem. What you need to do is dump the contents of nginx config to /etc/nginx/conf.d/default.conf (instead of saving it to /etc/nginx/sites-available/matrix and creating symlinks)

  6. Matthew Avatar

    When I try to do the CertBot certificate part, I always get an error.

    1. Jonathan Avatar

      What error are you getting?

  7. Ethan Avatar

    I’ve followed the guide and it seems to have worked, I can connect to the service just fine. But when accessed through a browser, I’m just getting the nginx welcome page. Would you be able to point me in the right direction to resolve this?

  8. Ethan Avatar

    The guide worked almost perfectly, I’m able to connect and use Matrix. Thank you for the very helpful guide!

    I’ve just had one issue, connecting to my server through a browser just shows the nginx welcome page. I double checked everything here and I can’t find where I’ve made a mistake. Would you be able to suggest something I may have missed?

  9. […] Its main drawback as a tool is accessibility. Matrix is only a framework and to utilise it both an app and a server is required, which not every user has the technical skill or capability to develop for themselves (guide to setting up a Matrix server here).  […]

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: