---
title: "Hosting Mumble on a Subdomain with Nginx"
date: 2024-01-04T10:04:57-07:00
description: 'How to host a mumble server on a subdomain behind nginx reverse proxy'
tags: ["nginx"]
showTableOfContents: true
image: "/images/nginx-mumble.webp"
weight: 1
type: "post"
---

# 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 receive 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 separate services. So pick a new port for the other ssl nginx services to listen on,
as well as pass traffic to, internally.

`nginx.conf`

```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:

```conf
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 @ tom@fosscat.com

