Build Your Own Matrix Server Behind An Nginx Reverse Proxy

25-08-2021 - 5 minutes, 6 seconds -

There are lots of articles on installing a Matrix server but they are mostly duplicates of the official documentation where your proxying is done on the server itself. Most people who are the type that would want to host their own Matrix server are going to have several servers built already behind an existing proxy. If that is you, this article may prevent you from pulling your hair out. If that is not you but you would still like to host more than one server, I highly suggest running your proxy on its own dedicated machine. Nginx is extremely light-weight on its own and using it as just a proxy consumes very little resources, you can comfortably get by with a small, under $20, arm powered machine with 512MB of RAM. I would even recommend a Raspberry Pi Zero if it had an ethernet connection. I'm currently running my proxy on a Rock64 1GB and it is more than enough for 8 existing servers. My setup for this article is an Nginx reverse proxy running on a Rock64 1GB SBC on top of Armbian Buster, and a small x86-64 mini PC with 8GB of RAM, a J4125 quad-core CPU, and 128GB internal SSD with Debian 11 for Synapse, both connected to a 24 port switch. Synapse (the actual application using the Matrix protocol) can be a RAM hog, especially as you start to explore more popular rooms or add widgets such as Jitsi or various bridges, and you will see prolonged CPU spikes when joining big rooms or video conferencing, so I recommend a proper PC and not a single board computer for running Synapse on.

If you don't have a proxy yet and want to get one up and running quickly, I recommend this simple article.

You will also need a domain. There are a million providers to choose from but I recommend not cheaping out and using a reliable domain provider who offers unlimited subdomains. You do not need web hosting (if you did, why are you reading this?). From here on out I will use example.com to refer to your parent domain, and matrix.example.com to refer to the domain for your Matrix server.

Setting up your DNS:

Create an A record for your parent domain example.com within the interface of your domain provider. Next create a CNAME record for your subdomain, matrix.example.com. I highly recommend enabling DNSSEC as well if your domain provider offers it to prevent spoofing and cache attacks.

Installing matrix-synapse and postgres:

I am using Debian, so I will install the maintainers .deb package. You can also build from source but I had an issue with postgres when doing so.

sudo apt install -y lsb-release wget apt-transport-https
sudo wget -O /usr/share/keyrings/matrix-org-archive-keyring.gpg https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/matrix-org-archive-keyring.gpg] https://packages.matrix.org/debian/ $(lsb_release -cs) main" |
    sudo tee /etc/apt/sources.list.d/matrix-org.list
sudo apt update
sudo apt install matrix-synapse-py3

During installation you will be asked for your server name. Make sure to use your parent domain and not your matrix subdomain.

Install Postgres:

sudo apt install postgresql

Configuration:

Create postgres user:

sudo user -i -u postgres
createuser --pwprompt synapse_user

Enter a password.

Create postgres database:

createdb --encoding=UTF8 --locale=C --template=template0 --owner=synapse_user synapse
exit

Next you'll adjust synapse's configuration file, homeserver.yaml.

sudoedit /etc/matrix-synapse/homeserver.yaml

Find listeners and make the following changes:

- port: 8000
   tls: false
   type: http
   x_forwarded: true
   # bind_addresses: ['::1', '127.0.0.1']
   resources:
      - names: [client, federation]
        compress: false

Find database:

database:
   name: psycopg2
   args:
      user: synapse_user
      password: <your postgres password>
      database: synapse
      host: localhost
      cp_min: 5
      cp_max: 10

If you want to allow registrations for users on your server, you need to enable it. I keep it disabled unless someone I know specifically asks me to register to my server:

enable_registration: true

You will need to enable and set a registration_shared_secret to register yourself or anyone else:

registration_shared_secret: <choose a shared secret password>

That will be enough to get you up and running, delegated and federated, but there are million other configurations you will want to dig into, most notable setting up email for server notifications and password retrieval. As well as optimizing postgres for better performance.

Configuring Nginx:

Log in to your proxy server and create a new conf within /etc/nginx/sites-enabled/ for your matrix subdomain. Remember to change the addresses to your own.

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    # For the federation port
    listen 8448 ssl http2 default_server;
    listen [::]:8448 ssl http2 default_server;

    server_name matrix.example.com;

    location ~* ^(\/_matrix|\/_synapse\/client) {
        proxy_pass http://<your matrix server local address>:8008;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;

        # 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 50M;
    }

}

Next create a conf for your parent doman within /etc/nginx/sites-enabled.

server {

        server_name example.com;

     location /.well-known/matrix/server {
     return 200 '{"m.server": "matrix.example.com:443"}';
     default_type application/json;
     add_header Access-Control-Allow-Origin *;

}

     location /.well-known/matrix/client {
     return 200 '{"m.homeserver": {"base_url": "https://matrix.example.com"}}';
     default_type application/json;
     add_header Access-Control-Allow-Origin *;

  }

}

While still logged into your proxy server, you'll need to get certbot next to install your certificates for your domains. The snap package is the easiest way to install certbot.

sudo apt install snapd
sudo snap install core

Test to make sure it's valid

sudo snap install hello-world
hello-world

Install certbot

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Go ahead and forward ports 80, 443, and 8448 in your router to your proxy server now. Get your certs.

sudo certbot --nginx

Certbot will give you a list of domains that you have confs for. Choose the ones you have setup and if everything is in order, you should now have SSL for HTTPS.

Restart nginx

sudo systemctl restart nginx

Log in to your matrix server and restart synapse.

sudo systemctl restart matrix-synapse

Lastly close port 80 in your router as this is only needed when obtaining your certs. That should be it. This article covers my own equipment and choice of OS, if yours are different you will have to make changes accordingly. Also read the official Matrix docs for installing and configuring voice and video, various widgets, and bridging capabilities.