This guide describes production-safe reverse proxy patterns for Infram, including complete TLS configuration and WebSocket forwarding requirements.
- Infram reachable on
http://127.0.0.1:6989 - Reverse proxy with WebSocket support
- Correct
TRUST_PROXYsetting in Infram runtime - Certificate and private key available on the proxy host
Your proxy configuration must:
- forward
Host,X-Forwarded-For, andX-Forwarded-Proto - support
UpgradeandConnectionheaders for WebSockets - allow long-lived connections for terminal/session streams
- terminate TLS with a valid certificate chain
Set TRUST_PROXY according to your topology:
TRUST_PROXY=1for one trusted proxy hopTRUST_PROXY=<n>for multiple trusted hopsTRUST_PROXY=<cidr-or-ip-list>for explicit trust boundariesTRUST_PROXY=falsewhen no reverse proxy is used
Warning
Incorrect TRUST_PROXY values can produce wrong client IP attribution in audit and session records.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name infram.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name infram.example.com;
ssl_certificate /etc/letsencrypt/live/infram.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/infram.example.com/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://127.0.0.1:6989;
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 $connection_upgrade;
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
}Enable modules:
sudo a2enmod ssl proxy proxy_http proxy_wstunnel headers rewriteVirtual host:
<VirtualHost *:80>
ServerName infram.example.com
Redirect permanent / https://infram.example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName infram.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/infram.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/infram.example.com/privkey.pem
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) ws://127.0.0.1:6989/$1 [P,L]
ProxyPass / http://127.0.0.1:6989/
ProxyPassReverse / http://127.0.0.1:6989/
ProxyTimeout 86400
</VirtualHost>Caddy automatically provisions certificates when DNS and inbound access are correct:
infram.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:6989
}services:
infram:
image: swissmakers/infram:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.infram.rule=Host(`infram.example.com`)"
- "traefik.http.routers.infram.entrypoints=websecure"
- "traefik.http.routers.infram.tls=true"
- "traefik.http.routers.infram.tls.certresolver=letsencrypt"
- "traefik.http.services.infram.loadbalancer.server.port=6989"- Use full certificate chain (
fullchain.pem) forssl_certificate/SSLCertificateFile - Restrict private key permissions (
chmod 600) - Automate renewal (for example
certbot renew) - Reload proxy service after renewal
- Open
https://infram.example.comand inspect certificate validity. - Login and open an interactive terminal session.
- Confirm session remains stable for long-running commands.
- Validate audit events include the real client IP.
- Confirm HTTP requests are redirected to HTTPS.
- WebSocket disconnects: verify upgrade headers and long timeout settings.
- Wrong source IP in audit logs: re-check
TRUST_PROXYvalue. - TLS errors: verify cert/key paths and file permissions on the proxy host.
- Redirect loops: ensure backend protocol is HTTP when TLS terminates at proxy.