Reverse proxy, TLS and OAuth callbacks
6. Reverse proxy and TLS
The server speaks plain HTTP and has no TLS listener. Terminate TLS at Caddy,
Nginx, Traefik or Cloudflare. FRONTEND_URL must be the public HTTPS origin,
with no path prefix: the app assumes it owns /, /public/v1, /mcp,
/oauth, /.well-known and /uploads.
6.1 Caddy
social.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:5000 {
flush_interval -1
header_up X-Forwarded-Proto {scheme}
}
}
Caddy obtains and renews certificates automatically and appends the client
address to X-Forwarded-For, so set TRUSTED_PROXY_HOPS=1 when Rustiz is
reachable only through Caddy.
flush_interval -1 disables response buffering, which matters for
subscriptions/listen and long MCP responses.
6.2 Nginx
server {
listen 443 ssl http2;
server_name social.example.com;
ssl_certificate /etc/letsencrypt/live/social.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/social.example.com/privkey.pem;
client_max_body_size 1024m;
location / {
proxy_pass http://127.0.0.1:5000;
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_request_buffering off;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
$proxy_add_x_forwarded_for appends the peer address; one Nginx hop means
TRUSTED_PROXY_HOPS=1. If Nginx is itself behind Cloudflare, see §6.3.
6.3 Cloudflare
- Use SSL/TLS → Full (strict) with a Cloudflare Origin Certificate or a valid public certificate on the origin.
- Cloudflare’s proxy has a 100-second origin response timeout on most plans.
Normal API calls and most MCP tool calls fit, but a long-lived
subscriptions/listenstream may be cut. Options: give MCP a DNS-only hostname, keep the stream short and let the client reconnect, or use an Enterprise plan with a longer timeout. - Cloudflare’s request-body limit depends on plan (commonly 100 MB). Set
MAX_UPLOAD_MBand the origin proxy limit to match; otherwise large video uploads fail at the edge before reaching Rustiz. - Do not enable “Under Attack” or a challenge on
/mcp; agents cannot solve it. Use a WAF skip rule for/mcp,/oauth/*and/.well-known/*if needed. - With Cloudflare → Nginx → Rustiz there are two appended XFF entries. Set
TRUSTED_PROXY_HOPS=2and firewall the origin so it is reachable only from Cloudflare. With Cloudflare connecting directly to Rustiz,1is correct. The limiter does not verify the peer address; the hop count is only safe when the origin cannot be reached directly.
6.4 OAuth callback URLs
Every provider’s redirect URI is built as:
{FRONTEND_URL}/integrations/social/{identifier}
FRONTEND_URL is trimmed of trailing slashes, so register the URI without
a trailing slash unless the provider’s table explicitly shows one. The exact
paths and exception cases are in the master provider table;
the important ones:
tiktok-businessends with/(.../tiktok-business/); the platform requires it and the token exchange sends the same value.mastodon-customreuses/integrations/social/mastodon.xuses/integrations/social/x, unlessX_URLoverrides the base.threads,slack,vk,tiktok,tiktok-businessandinstagram-standalonewrap the URI ashttps://redirectmeto.com/<FRONTEND_URL>/...whenFRONTEND_URLdoes not contain the substringhttps. In production this should never happen; use HTTPS.facebook,instagram,pinterest,reddit,linkedin,youtube,gmb,tumblr,twitch,discord,dribbble,whopandmeweare registered directly; several of them refuse plainhttp://redirects even on localhost.
The callback route is GET /integrations/social/{provider}. It reads code
and state from the query, consumes the one-time state row, exchanges the
code and stores the channel (access tokens in plain text; customFields
credentials and custom-instance client data encrypted). OAuth state lives for
one hour; Telegram/Moltbook connection ids also one hour; Farcaster signers 30
minutes. A second use of the same state fails with
This connection link expired, please start again.
The server does not render a dashboard. The callback renders a minimal HTML “Channel connected” / “Could not connect the channel” page.
6.5 Local OAuth without a public server
rustiz channels connect <provider> and rustiz mcp can receive the platform
callback themselves, but only when FRONTEND_URL is plain HTTP on
localhost or 127.0.0.1. They bind 127.0.0.1:<port> and wait. If the
port is already in use by another rustiz using the same database, the command
warns and waits for that process to finish the login.
If FRONTEND_URL is a public HTTPS URL or a non-loopback host, the CLI cannot
receive the callback; it prints the login URL and tells you the server must
handle it.