All I Found Was Tumble Weeds

Well I couldn’t find any actual examples of someone doing what I wanted, namely, hosting the murmur server on a subdomain on my machine behind an nginx proxy. I only have ports 80 and 443 opened on my router, so I chose to recieve the mumble traffic to come in on port 443. Sounds easy enough, but the problem comes when you let nginx decrypt the packets in the process of passing them to the murmur server, it raises a TLS/SSL Termination Error. Murmur insists on End to End Encryption (E2EE), which is a good thing.

To not repeat the classic Cooking Recipe website mistake and put the solution at the bottom of an Ad riddled page, here is the nginx config that got my setup working, all of this is the default on an Arch Linux install, minus the stream block. Ports need to be defined for your setup for INTERNAL_MUMBLE_PORT (port that murmur is listening on) and NEW_NGINX_SSL_PORT. Previously, NEW_NGINX_SSL_PORT was 443, but the stream block now will be using 443, and you can’t bind to the same port with seperate services. So pick a new port for the other ssl nginx services to listen on, as well as pass traffic to, internally.

nginx.conf

worker_processes 4;

events {
    worker_connections 1024;
}

stream {
    # Define upstreams that nginx can route traffic to
    upstream mumble {
        server localhost:<INTERNAL_MUMBLE_PORT>;
    }

    upstream fosscat {
        server localhost:<NEW_NGINX_SSL_PORT>; # Was 443 until I added murmur
    }

    # SNI, route to murmur if the subdomain matches
    map $ssl_preread_server_name $name {
        # Destination         Upstream (above) to Route traffic to
        mumble.fosscat.com    mumble;
        default               fosscat;
    }

    server {
        # TCP traffic
        listen 443;
        # UDP traffic
        listen 443 udp;
        proxy_pass $name;
        # Necessary line
        # Dont decrypt packets, just pass them along
        ssl_preread on;
    }
}

http {
    include       mime.types;
    include       /etc/nginx/sites-enabled/*;
    default_type  application/octet-stream;

    sendfile           on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
}

Then here is this blog’s nginx config file in /etc/nginx/sites-available that is sim-linked into /etc/nginx/sites-enabled. I’m using certbot for ssl certs. Note that a port needs to be provided in the second server block that matches the one provided above.

fosscat.com file:

server {
    if ($host = www.fosscat.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = fosscat.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    server_name fosscat.com www.fosscat.com;

}

server {
    listen <NEW_NGINX_SSL_PORT> ssl;
    server_name fosscat.com www.fosscat.com;
    ssl_certificate /etc/letsencrypt/live/fosscat.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/fosscat.com/privkey.pem; # managed by Certbot

    root /usr/share/nginx/html/fosscat-site/public/; #Absolute path to where your hugo site is
    index index.html; # Hugo generates HTML

    location / {
        root /usr/share/nginx/html/fosscat-site/public;
        try_files $uri $uri/ =404;
    }

    error_page 404 /404.html;
    location = /404.html {
        root /usr/share/nginx/html/fosscat-site/public;
        internal;
    }
}

Caveats

I figured this setup out cobbling together some sparse posts online, the nginx docs, and asking chatGPT for explanations.

Currently, all of my sites and services work as expected with TLS and whatnot, however the murmur server doesn’t report as being online to clients before they connect. Also, the mumble client reports that only TLS is supported so it switches to TLS only mode automatically, i.e. increased latency. I’m not sure why either of these are the case.

To use the stream block and ssl_preread you have to have your nginx compiled with those options. Running nginx -V should tell you whether you have a compatible nginx version.

Thought I’d share my discovery in case anyone else runs into the same problem I did.

As always, questions or corrections, feel free to open a PR on my git instance or email me @ [email protected]