I've stomped multiple traps alone the way and I'm going to give a minimal set-up for reference. This set up uses Nginx as reverse proxy for both client and federation on port 8008, with Let's Encrypt SSL.

DNS set-up

let's say "matrix.<domain>" === <your_domain>, so that <sub_domain> is "matrix"

  1. an A record: <sub_domain>.<domain> to your server IP
  2. an SRV record: <sub_domain> 10 0 443 <your_domain>

Installation:

sudo apt install -y lsb-release wget apt-transport-https
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-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt update 
sudo apt install matrix-synapse-py3 nginx python-certbot-nginx
sudo apt install sqlite3

Upon installing synapse, you will be prompt to input your domain, just do so.

homeserver.yaml

This file is located @ /etc/matrix-synapse/homeserver.yaml. Take a look at https://www.howtoforge.com/tutorial/how-to-install-matrix-synapse-on-ubuntu-1804/ for cross comparison.

...
  - port: 8008
    tls: false
    bind_addresses: ['::1', '127.0.0.1']
    type: http
    x_forwarded: true

    resources:
      - names: [client, federation]
        compress: false
...
tls_certificate_path: "/etc/letsencrypt/live/<your_domain>/fullchain.pem"

# PEM-encoded private key for TLS
#
tls_private_key_path: "/etc/letsencrypt/live/<your_domain>/privkey.pem"
...
and other things

CERTBOT

To the first order, this is as easy as:

sudo certbot --nginx certonly -d <your_domain>

nginx config

make a new file /etc/nginx/sites-available/matrix and link it by:

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

the file content:

server {
       listen 80;
       server_name <your_domain>;
       return 301 https://$server_name$request_uri;
}
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name <your_domain>;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/<your_domain>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<your_domain>/privkey.pem;
    client_max_body_size 10M;
           
    location / {
        proxy_pass http://localhost:8008;
        #proxy_set_header X-Forwarded-For $remote_addr;
    }
}
server {
    listen 8448 ssl default_server;
    listen [::]:8448 ssl default_server;
    server_name <your_domain>;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/<your_domain>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<your_domain>/privkey.pem;

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

Done!