jChat LogojChat Docs
Production Deployment

Host Reverse Proxy & SSL (For Standalone)

Configure Nginx or Caddy on your Linux host to proxy traffic to your standalone JChat process.

Overview

When running JChat as a standalone Linux process on port 3000, you need a reverse proxy on the host to route public ports 80 and 443, provide SSL/TLS termination, and handle WebSocket upgrades.

Reverse Proxy Architecture & TLS Termination
┌─────────────────────────┐
│   Client Web / Mobile   │
└────────────┬────────────┘
             │ HTTPS / WSS (Ports 80 & 443)
             ▼
┌────────────────────────────────────────────────────────┐         ┌───────────────────────────┐
│             Reverse Proxy (Caddy / Nginx)              │  ─────▶│  Let's Encrypt / ZeroSSL  │
│             SSL / TLS Termination Gateway              │         │  Automatic ACME Renewal   │
└────────────────────────────┬───────────────────────────┘         └───────────────────────────┘
                             │
            ┌────────────────┴────────────────┐
            │ HTTP/1.1                        │ Upgrade: websocket
            │ (127.0.0.1:3000)                │ Connection: upgrade
            ▼                                 ▼
┌────────────────────────────┐   ┌────────────────────────────┐
│         JChat Core         │   │   Real-Time WS Gateway     │
│       (Bun + Elysia)       │   │  Persistent Socket Tunnel  │
└────────────────────────────┘   └────────────────────────────┘

Nginx Reverse Proxy

Real-time chat requires proper WebSocket upgrade headers (Upgrade and Connection).

Option A: Path Routing Mode (Single Domain)

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    client_max_body_size 50M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;

        # WebSocket Upgrade Headers
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Forwarded Client 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;

        proxy_read_timeout 86400;
        proxy_send_timeout 86400;
    }
}

Option B: Subdomain Routing Mode (Wildcard & Management Subdomain)

server {
    listen 80;
    server_name example.com *.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com *.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    client_max_body_size 50M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;

        # WebSocket Upgrade Headers
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Forwarded Client 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;

        proxy_read_timeout 86400;
        proxy_send_timeout 86400;
    }
}

Caddy Reverse Proxy

Caddy automatically provisions and renews SSL certificates from Let's Encrypt / ZeroSSL out of the box:

Path Routing Mode:

example.com {
    reverse_proxy 127.0.0.1:3000
}

Subdomain Routing Mode:

example.com, *.example.com {
    reverse_proxy 127.0.0.1:3000
}

Obtain SSL Certificates with Certbot (Nginx)

For single domain:

sudo certbot --nginx -d example.com

For wildcard subdomains (requires DNS-01 verification):

sudo certbot certonly --manual --preferred-challenges dns -d example.com -d "*.example.com"

On this page