Skip to content

Reverse proxy setup

Run rChat behind Caddy, nginx, or HAProxy. The reverse proxy terminates TLS 1.3 and forwards plain WebSocket traffic to rChat on a local port.


  • Automatic HTTPS — Caddy and certbot handle certificates for you
  • Multiple services — Run rChat alongside a website or other apps on the same host
  • Load balancing — Distribute connections across multiple rChat backends
  • Security hardening — WAF rules, rate limiting, and access controls at the edge

When running behind a reverse proxy, disable TLS in rChat and bind to localhost:

[server]
bind_addr = "127.0.0.1:8443"

The proxy listens on port 443 and forwards to 127.0.0.1:8443.


Caddy is the easiest option — it handles TLS automatically via Let’s Encrypt.

Terminal window
sudo apt install caddy

Create /etc/caddy/Caddyfile:

chat.example.com {
tls {
protocols tls1.3
}
reverse_proxy 127.0.0.1:8443
}

The protocols tls1.3 directive ensures only TLS 1.3 is offered to clients.

Terminal window
sudo systemctl reload caddy

Terminal window
sudo apt install nginx

Create /etc/nginx/sites-available/rchat:

upstream rchat_backend {
server 127.0.0.1:8443;
keepalive 1000;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl http2;
server_name chat.example.com;
ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
ssl_protocols TLSv1.3;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
ssl_prefer_server_ciphers off;
location / {
proxy_pass http://rchat_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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_read_timeout 86400;
proxy_send_timeout 86400;
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name chat.example.com;
return 301 https://$server_name$request_uri;
}

Enable the site:

Terminal window
sudo ln -s /etc/nginx/sites-available/rchat /etc/nginx/sites-enabled/rchat
sudo nginx -t
sudo systemctl reload nginx
Terminal window
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d chat.example.com

Terminal window
sudo apt install haproxy

Edit /etc/haproxy/haproxy.cfg:

global
maxconn 100000
ssl-default-bind-options ssl-min-ver TLSv1.3
ssl-default-bind-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
defaults
mode http
timeout connect 5s
timeout client 300s
timeout server 300s
option httpchk
frontend rchat_frontend
bind *:443 ssl crt /etc/letsencrypt/live/chat.example.com/fullchain.pem alpn h2,http/1.1
# Enforce TLS 1.3 only
bind *:443 ssl crt /etc/letsencrypt/live/chat.example.com/fullchain.pem ssl-min-ver TLSv1.3
# WebSocket upgrade
acl is_websocket hdr(Upgrade) -i websocket
acl is_connection_upgrade hdr_beg(Connection) -i upgrade
use_backend rchat_backend
backend rchat_backend
server rchat_local 127.0.0.1:8443 check
# WebSocket support
option httpchk GET /
# Redirect HTTP to HTTPS
frontend http_redirect
bind *:80
redirect scheme https code 301 if !{ ssl_fc }

Reload:

Terminal window
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl reload haproxy

All three proxies must pass these headers for WebSocket upgrades to work:

HeaderValuePurpose
UpgradewebsocketInitiates WebSocket upgrade
ConnectionupgradeMaintains upgrade connection
Hostoriginal hostRequired for virtual hosting
X-Forwarded-Forclient IPPreserves client address
X-Forwarded-ProtohttpsTells rChat the request was secure

All proxies can check whether rChat is healthy before sending traffic:

Terminal window
curl -f http://127.0.0.1:8443/health

If rChat returns HTTP 200, it is ready. If it returns anything else or refuses the connection, the proxy should try another backend or return a 503.