fosscat-site/content/posts/hosting-mumble-on-a-subdomain-with-nginx.md

157 lines
4.9 KiB
Markdown

---
title: "Hosting Mumble on a Subdomain with Nginx"
date: 2024-01-04T10:04:57-07:00
draft: false
tags: ['nginx', 'self host', 'mumble']
summary: 'How to host a mumble server on a subdomain behind nginx reverse proxy'
tocOpen: true
cover:
image: "/images/nginx-mumble.png"
alt: "Nginx logo and Mumble Logo"
caption: "Star-crossed lovers"
relative: false
---
# 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`
```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