-
Notifications
You must be signed in to change notification settings - Fork 0
Reverse Proxy and TLS
Brum is built from the ground up to run seamlessly behind any reverse proxy, mesh VPN, or Cloudflare Tunnel with zero configuration required.
It supports:
-
Automatic WebSockets over HTTPS (
wss://) for the interactive PTY terminal. -
Dynamic Viewport & Safe Area (
100dvh) for mobile browsers (Vivaldi, Chrome, Firefox, Safari). -
Permissive Cross-Origin & Private IP Routing (Tailscale
100.x.y.z, NetBird100.x.y.z, LAN192.168.x.x, Localhost). - Large File Uploads up to 10GB+ with streaming chunk processing.
Tailscale provides encrypted peer-to-peer WireGuard connections and automatic TLS certificates via MagicDNS.
Serve Brum securely to devices on your private Tailscale network with a signed Let's Encrypt HTTPS certificate:
# Run Brum in the background on port 3140
brum &
# Expose to your Tailnet over HTTPS
tailscale serve --bg 3140Your Brum instance is now available at:
https://<node-name>.<tailnet-name>.ts.net
Expose Brum to the public Internet with full TLS and WebSocket proxying:
tailscale funnel --bg 3140If you prefer direct IP connections over your Tailnet:
http://100.x.y.z:3140
NetBird provides fast peer-to-peer overlay networking over WireGuard.
Brum listens on 0.0.0.0:3140 by default. Once your host is joined to NetBird, access Brum directly from any peer machine:
http://100.x.y.z:3140
If you have configured a NetBird Routing Peer with domain resolution (e.g. commander.netbird.internal), simply point your reverse proxy (Caddy/Nginx) to localhost:3140.
Caddy provides automatic HTTPS certificates, HTTP/2, HTTP/3, and built-in WebSocket proxying with zero configuration.
files.yourdomain.com {
reverse_proxy localhost:3140
}Reload Caddy:
sudo systemctl reload caddyWhen using Nginx, you must configure WebSocket upgrade headers and disable request buffering for large file uploads and real-time terminal streaming.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name files.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name files.yourdomain.com;
# SSL Certificates (Let's Encrypt / Certbot)
ssl_certificate /etc/letsencrypt/live/files.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/files.yourdomain.com/privkey.pem;
# Allow large uploads (10GB)
client_max_body_size 10240M;
location / {
proxy_pass http://127.0.0.1:3140;
proxy_http_version 1.1;
# WebSocket Support (Required for Terminal)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Standard Proxy Headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts for Long-Running Terminal Sessions & Uploads
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_buffering off;
}
}Enable and reload Nginx:
sudo ln -s /etc/nginx/sites-available/brum /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginxIn the Nginx Proxy Manager Web UI:
-
Details Tab:
- Domain Names:
files.yourdomain.com - Scheme:
http - Forward Hostname / IP:
127.0.0.1(or container IP) - Forward Port:
3140 - Check: Cache Assets: OFF
- Check: Block Common Exploits: ON
- Check: Websockets Support: ON (Crucial for Terminal)
- Domain Names:
-
SSL Tab:
- Select SSL Certificate (Let's Encrypt)
- Check: Force SSL: ON
- Check: HTTP/2 Support: ON
-
Advanced Tab (Custom Nginx Configuration):
client_max_body_size 10240M; proxy_read_timeout 86400s; proxy_send_timeout 86400s; proxy_buffering off;
version: '3.8'
services:
brum:
image: ghcr.io/woofson/brum:latest
container_name: brum
restart: unless-stopped
volumes:
- /:/host-root
- ./data:/etc/brum
labels:
- "traefik.enable=true"
- "traefik.http.routers.brum.rule=Host(`files.yourdomain.com`)"
- "traefik.http.routers.brum.entrypoints=websecure"
- "traefik.http.routers.brum.tls.certresolver=letsencrypt"
- "traefik.http.services.brum.loadbalancer.server.port=3140"
- "traefik.http.middlewares.cd-buffering.buffering.maxRequestBodyBytes=10485760000"
- "traefik.http.routers.brum.middlewares=cd-buffering"tunnel: <TUNNEL_ID>
credentials-file: /root/.cloudflared/<TUNNEL_ID>.json
ingress:
- hostname: files.yourdomain.com
service: http://localhost:3140
originRequest:
noTLSVerify: true
- service: http_status:404Note: In your Cloudflare Dashboard, ensure Network ➔ WebSockets is toggled ON so terminal sessions connect cleanly.
Ensure mod_proxy, mod_proxy_http, and mod_proxy_wstunnel are enabled:
sudo a2enmod proxy proxy_http proxy_wstunnel ssl<VirtualHost *:443>
ServerName files.yourdomain.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/files.yourdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/files.yourdomain.com/privkey.pem
# WebSocket Proxy for Terminal
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://127.0.0.1:3140/$1" [P,L]
# HTTP Proxy
ProxyPass / http://127.0.0.1:3140/
ProxyPassReverse / http://127.0.0.1:3140/
# Allow 10GB Uploads
LimitRequestBody 10737418240
</VirtualHost>Once deployed behind your reverse proxy or VPN, test:
- Web Dashboard: Navigate to your domain or Tailscale/NetBird IP in browser.
-
Interactive Terminal (Backtick or Slide-up): Verify that the bash/sh shell connects immediately over WebSocket (
wss://). -
File Uploads: Drag and drop large files to ensure the proxy's
client_max_body_sizeis not rejecting uploads. - Mobile Navigation: Test on mobile browsers (Vivaldi, Chrome, Firefox) to confirm the dynamic viewport sits comfortably above mobile bottom bars.
Brum — Multi-Pane Web Environment (File Commander/Manager)
Creator & Lab: Bolt J Woofson @ Woofsons Lab (www.arf.ac) • MIT License