Opengram

Reverse Proxy

Put Opengram behind a reverse proxy for HTTPS termination with Caddy or nginx.

If you are not using Tailscale for HTTPS, a reverse proxy is the standard way to terminate TLS in front of Opengram.

Caddy

Caddy is the simplest option because it handles HTTPS certificates automatically:

Caddyfile
opengram.example.com {
  reverse_proxy 127.0.0.1:3000
}

That is the entire configuration. Caddy will obtain and renew a Let's Encrypt certificate, handle TLS termination, and proxy all traffic to Opengram. SSE streaming works without any additional configuration.

nginx

For nginx, a minimal configuration looks like this:

/etc/nginx/sites-available/opengram
server {
  listen 80;
  server_name opengram.example.com;
  return 301 https://$host$request_uri;
}

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

  ssl_certificate     /path/to/cert.pem;
  ssl_certificate_key /path/to/key.pem;

  client_max_body_size 50m;  # Match Opengram's maxUploadBytes

  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_buffering off;  # Required for SSE
  }
}

Trust proxy headers

When Opengram runs behind a reverse proxy, it needs to trust forwarded IP headers so that rate limiting uses the real client IP instead of the proxy's IP. The trusted headers are X-Forwarded-For, X-Real-IP, and CF-Connecting-IP (Cloudflare).

Set the following environment variable:

OPENGRAM_TRUST_PROXY_HEADERS=true

Add this to your opengram.env file or pass it as a Docker environment variable. Without this setting, all requests will appear to come from 127.0.0.1 and rate limiting will not work correctly.

SSE streaming

Opengram uses Server-Sent Events (SSE) for real-time message streaming. Reverse proxies must not buffer these responses, or users will see messages arrive in delayed chunks instead of streaming smoothly.

  • Caddy -- handles SSE correctly by default with no additional configuration.
  • nginx -- requires proxy_buffering off; inside the location block as shown above. Opengram also sends an X-Accel-Buffering: no header on SSE responses, but setting the directive explicitly is recommended as a safeguard.

Public base URL

After setting up your reverse proxy, configure Opengram to know its public URL. In your opengram.config.json, set:

{
  "server": {
    "publicBaseUrl": "https://opengram.example.com"
  }
}

Or use the environment variable instead:

OPENGRAM_PUBLIC_BASE_URL=https://opengram.example.com

This URL is used for generating links in push notifications and other features that need to reference the server externally. Restart Opengram after making this change.

On this page