Homeserver at Home

What is a Homerserver and why should it be at home?

Matrix is a federated messaging network. In other words, matrix is an alternative to IRC (slack, Facebook messenger or WhatsApp if you like), which allows everyone to run their own server.

The benefits of running your own server, are your messages are stored on your hardware, this prevents administrators and hosting providers from reading your messages and checking out your contacts. Why not use Signal, Drew DeVault wrote a blog post called “I don’t trust Signal”, which raises some interesting points.

While you don’t need to run your own server to accomplish this, since Matrix supports end-to-end encryption (Yes, the very same as signal!), self hosting is a good way to learn about server administration and in my option… it’s fun.

Logistics

A Matrix homeserver, if you want to communicate with other matrix users, requires a fast and stable internet connection along with a server.

I have a number of rented dedicated and virtual servers floating around in cyberspace, all of these are owned by one company or another. I don’t want my messages hosted on them.

I will be running my homeserver at home! But since I don’t want to shell out coins to get a dedicated IP address for my house, I decided to use a VPN to bridge my homeserver to another server in cyberspace.

Quickly running through the setup guides for running a matrix homeserver, I found that many deployments ended the TLS connection on the first hop. See the diagram below:

Diagram showing  NGINX ProxyPass

This meant that the return connection from the server to my homeserver would be in plaintext. After some more searching, I found the key phrase “SSL Pass Through”, which looks better:

Diagram showing  NGINX SSL Pass Through

Now, any connection made to my homeserver will not be terminated on the cyber-server (lol) but at my home. Which means I can keep my TLS keys safe and secure.

Technical Details

As explained a bit above,VPN is used in place of Dynamic DNS or a static IP Address at home. If you have all then, then you’re set and don’t really need to read the rest of this post.

A few reasons for my decisions, I don’t really remember them all now:

  • I want to only use NGINX, because that’s what I already have.
    • HAProxy et.al are out of the question, because I’m lazy.
  • The Reverse Proxying NGINX also hosts other sites
    • I need to be able to do SSL Pass Trough based on server name.
  • I want SSL keys stored at home
  • I don’t want to use DDNS or static IP address, no reason.
  • The Homeserver is running on FreeBSD and the Server is running Ubuntu 18.04.

VPN: Tinc

tinc is a really easy to use VPN, it supports some of the things wireguard is trying to do.

Anyway, tinc is used to connect the Homeserver to the server, and bypass the need for static IP address at home or the use of Dynamic DNS.

Nothing special needed here, worked fine, follow the documentation and if stuck run in debug mode etc.etc.

SSL Pass Through: NGINX

This was performed by taking advantage of NGINX’s stream mapping and ssl_preread.

ssl_preread defines an number of variables that can be obtained from SSL connections.

Since the stream needs to listen on port 443, other servers are not able to. This means that if NGINX hosts other sites, they now need to listen on another port. I chose 8443 for the alternative port.

Since I want my matrix homeserver to be reachable from matrix.port22.co.uk I added that to the map, so that if an SSL connection is initiated with a matching SNI, the upstream will be the VPN tunnel, otherwise the default is the local server’s sites (now port 8443).

...
stream {
        map $ssl_preread_server_name $name {
                hostnames;
                .matrix.port22.co.uk matrix;
                default hammerfall_backend;
        }

        upstream hammerfall_backend {
                server 127.0.0.1:8443;
        }

        upstream matrix {
                server 172.172.10.2:443;
        }

        server {
                listen 443;
                proxy_pass $name;
                ssl_preread on;
        }
}
...

SERVER: /etc/nginx/nginx.conf

The similar was included for the matrix federation port 8448, but since this host does not run any other virtual sites on that port it was as simple as adding proxy_pass to the VPN interface.

...
stream {
        map $ssl_preread_server_name $name {
                hostnames;
                .matrix.port22.co.uk matrix;
                default hammerfall_backend;
        }

        upstream hammerfall_backend {
                server 127.0.0.1:8443;
        }

        upstream matrix {
                server 172.172.10.2:443;
        }

        server {
                listen 443;
                proxy_pass $name;
                ssl_preread on;
        }

         # Federation Ports - below

        upstream matrix_fed {
                server 172.172.10.2:8448;
        }

        server {
                listen 8448;
                proxy_pass matrix_fed; 
        }
}
...

SERVER: /etc/nginx/nginx.conf

Homeserver: Synapse

Synapse, the homeserver daemon, was configured as per the documentation.

Another NGINX instance is run in front of it on port 443 and 8448 for federation to accept connections from the server.

LetsEncrypt was used for TLS. Nothing complicated about this configuration, however running it on FreeBSD did allow me to raise a few bugs against dated documentation.

The End

I’m very happy with the outcome, I learnt a lot configuring FreeBSD. Not sure if I can say I learnt more about NGINX, only that it gets more complicated every time I read into the docs.

If I were to do this again, I would try to understand NGINX in more detail as well as check out some alternatives for the SSL Pass Through.

I am sad however, since I can’t find my list of posts and articles that helped me get here, maybe they will turn up and I can amend the post.