Reverse Proxy
The container listens on plain HTTP on port 8080. For anything beyond localhost (e.g., a LAN or the internet) you should put it behind a reverse proxy that terminates TLS and forwards to the container. The examples here assume your container is reachable at romm:8080 (by container name on a Docker network) or 192.168.1.100:8080 (by IP on the LAN).
Caddy
Dead-simple, auto-HTTPS via Let's Encrypt:
romm.mysite.com {
encode zstd gzip
header {
Strict-Transport-Security "max-age=31536000;"
X-XSS-Protection "1; mode=block"
X-Frame-Options "SAMEORIGIN"
X-Robots-Tag "noindex, nofollow"
-Server
-X-Powered-By
}
reverse_proxy romm:8080
}
If you just want HTTP on the LAN:
Nginx
HTTP only
server {
listen 80 default_server;
server_name romm.mysite.com;
client_max_body_size 0;
location / {
proxy_pass http://romm:8080;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
HTTPS with HSTS
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name romm.mysite.com;
ssl_certificate /etc/ssl/romm/fullchain.pem;
ssl_certificate_key /etc/ssl/romm/privkey.pem;
client_max_body_size 0;
location / {
proxy_pass http://romm:8080;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
server_tokens off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
}
}
client_max_body_size 0
Required so large ROM uploads aren't rejected by nginx before they reach RomM.
Traefik
Dynamic configuration file
http:
routers:
romm:
entryPoints:
- websecure
rule: "Host(`romm.mysite.com`)"
middlewares:
- default-headers
- https-redirectscheme
tls:
certResolver: letsencrypt
service: romm
services:
romm:
loadBalancer:
servers:
- url: "http://192.168.1.100:8080"
passHostHeader: true
Docker Compose labels
Add these to the romm service in your docker-compose.yml:
labels:
- "traefik.enable=true"
- "traefik.http.services.romm.loadbalancer.server.port=8080"
- "traefik.http.routers.romm.rule=Host(`romm.mysite.com`)"
- "traefik.http.routers.romm.entrypoints=websecure"
- "traefik.http.routers.romm.tls=true"
- "traefik.http.routers.romm.tls.certresolver=letsencrypt"
Nginx Proxy Manager
Items marked ❗ are important. RomM won't work right without them.
Details
- Domain Names:
romm.mysite.com - Scheme:
http - Forward Hostname/IP: container hostname or LAN IP (e.g.
192.168.1.100) - Forward Port:
8080 - Cache Assets:
off - Block Common Exploits:
on - Websockets Support:
on❗ - Access List: as needed
SSL
- SSL Certificate: Request a new SSL Certificate
- Force SSL:
on - HTTP/2 Support:
on - HSTS Enabled:
on(after you've confirmed TLS works) - Email Address for Let's Encrypt: your address
- I Agree to the TOS:
on
Custom nginx configuration ❗
Without that line, large downloads (bulk ROM zips, multi-disc games) will fail on NPM because nginx tries to buffer them to disk.
| Details | SSL | Advanced |
|---|---|---|
Set ROMM_BASE_URL behind HTTPS
Once you're proxying through HTTPS, set ROMM_BASE_URL in the container's environment so generated links (QR codes, invite links, OIDC redirects) use the public URL:
If you're also using OIDC, update OIDC_REDIRECT_URI to match (see OIDC Setup).