Skip to content
EN

Reverse Proxy

Use this page if you run Varin behind Nginx, Nginx Proxy Manager, Caddy, Cloudflare, or another reverse proxy.

  1. Confirm Varin works directly first.
  2. Open http://<server-ip>:3000 or your custom port from the same network.
  3. Only add the reverse proxy after the direct connection works.
  • WebSocket:
    • /api/dictation/ws
    • /api/terminal/ws
    • /api/varin/realtime-proxy/ws
  • SSE without buffering:
    • /api/notifications/stream
    • /api/varin/events
    • /api/threads/observe
    • /api/varin/realtime-proxy/sse
  • Large request bodies for attachments and file operations
  • Long-lived read timeouts for live streams and terminal sessions
  • Enable WebSocket proxying.
  • Disable buffering on SSE routes.
  • Disable gzip on the proxy if Varin is already compressing responses.
  • Keep compression enabled in only one layer.
  • Forward normal proxy headers such as Host, X-Forwarded-For, and X-Forwarded-Proto.
  • Increase body size limits if users upload files.
  • Varin reachable directly on LAN
  • WebSockets enabled in the proxy
  • SSE routes have buffering off
  • gzip off on the proxy host, or proxy compression disabled another way
  • client_max_body_size large enough for attachments
  • proxy_read_timeout long enough for streams
Show example config
client_max_body_size 50M;
client_body_buffer_size 50M;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Connection "";
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 X-Forwarded-Host $host;
gzip off;
location ~ ^/api/(varin/realtime-proxy|terminal|dictation)/ws$ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header 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_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location ~ ^/api/(threads/observe|notifications/stream|varin/(events|realtime-proxy/sse))$ {
proxy_pass http://127.0.0.1:3000;
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 Accept "text/event-stream";
proxy_set_header Cache-Control "no-cache";
proxy_buffering off;
proxy_cache off;
gzip off;
add_header X-Accel-Buffering "no" always;
add_header Cache-Control "no-cache, no-transform" always;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location /api {
proxy_pass http://127.0.0.1:3000;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location / {
proxy_pass http://127.0.0.1:3000;
}

Enable Websockets Support in Nginx Proxy Manager. Use the buffering, request-size and timeout directives from the Nginx example above in the host’s Advanced configuration; keep the same current WebSocket and SSE paths.

  • Check authentication and forwarding for POST /api/threads/* requests.
  • Check that GET /api/threads/observe streams SSE without buffering or caching.

Notifications or live status do not update

Section titled “Notifications or live status do not update”
  • one of the SSE routes is buffered or cached
  • X-Accel-Buffering "no" is missing
  • client_max_body_size is too small

Everything works locally, but breaks only behind the proxy

Section titled “Everything works locally, but breaks only behind the proxy”
  • the proxy is compressing and buffering live traffic
  • the proxy is missing WebSocket support
Show example config
reverse_proxy 127.0.0.1:3000 {
# WebSocket support is automatic in Caddy
# Flush SSE responses immediately
flush_interval -1
# Pass through Host and proxy headers
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
# Increase timeouts for long-lived streams
transport http {
read_timeout 3600s
write_timeout 3600s
}
}

Caddy handles WebSocket upgrades automatically — no extra configuration needed. The flush_interval -1 directive ensures SSE chunks are forwarded immediately without buffering.

If you place a CDN (such as Cloudflare) in front of your reverse proxy, be aware of double compression:

  • Varin compresses HTTP responses with gzip (threshold 1 KB).
  • Cloudflare and other CDNs also compress responses by default.
  • This can cause double-compressed responses or incorrect Content-Encoding headers.

To avoid this, disable compression at one layer:

  • Cloudflare: Rules → Compression → disable (or use “Passthrough” mode).
  • Nginx: gzip off (already shown in the examples above).
  • Caddy: Caddy does not re-compress by default if the upstream already sends compressed content.

SSE streaming routes are excluded from compression by Varin, but the CDN may still buffer them. Check your CDN documentation for how to disable buffering on SSE paths.