Skip to content

Environment variables

This is the full reference for self-hosted instances. Start with the small .env example in the Docker guide; add other settings only when you need them.

Production startup requires a secret, the Quipthread URL, allowed publisher origins, and a sign-in provider. Email sign-in also requires an SMTP host and sender address.

Variable Default Description
JWT_SECRET — Required. Secret key used to sign session tokens. Generate with openssl rand -hex 32.
Variable Default Description
PORT 8080 TCP port the HTTP server listens on.
BASE_URL http://localhost:8080 Public origin of Quipthread, such as https://comments.example.com. OAuth callbacks append /auth/github/callback or /auth/google/callback; do not put that path in BASE_URL.
TRUST_PROXY false Trust forwarded client IP headers. Set to true behind Caddy or another trusted proxy, and prevent direct access to the app port.
LOG_FORMAT text Set to json for structured logs.
LOG_LEVEL info Set to debug for debug logs.
Variable Default Description
DATABASE_URL ./data/comments.db Path to the local SQLite database file. Docker Compose defaults to /data/db.sqlite in its persistent volume. Self-hosted mode rejects remote libsql://, http://, and https:// URLs before opening a driver.
Variable Default Description
GITHUB_CLIENT_ID — GitHub OAuth app client ID.
GITHUB_CLIENT_SECRET — GitHub OAuth app client secret.
GOOGLE_CLIENT_ID — Google OAuth client ID.
GOOGLE_CLIENT_SECRET — Google OAuth client secret.

See OAuth Setup for how to create these credentials.

Variable Default Description
EMAIL_AUTH_ENABLED false Set to true to enable email+password registration and login.
SMTP_HOST — SMTP server hostname.
SMTP_PORT 587 SMTP server port.
SMTP_USER — SMTP authentication username.
SMTP_PASS — SMTP authentication password.
SMTP_FROM — Sender address for all outgoing email.
EMAIL_PROVIDER SMTP Delivery path. Empty uses SMTP; cloudflare sends authentication email and notification digests over the Cloudflare Email Sending REST API; postmark and sendgrid send notification digests over their HTTP APIs while authentication email falls back to SMTP; ses uses SMTP. An unknown value fails at startup.
EMAIL_REPLY_TO — Optional Reply-To for Cloudflare authentication and notification email. Only EMAIL_PROVIDER=cloudflare sets it; SMTP, Postmark, SendGrid, and SES ignore it. When empty, replies go to SMTP_FROM; no address is hardcoded.
CLOUDFLARE_API_TOKEN — Cloudflare API token with email sending permission. Required when EMAIL_PROVIDER=cloudflare; distinct from any Turso token.
CLOUDFLARE_ACCOUNT_ID — Cloudflare account that owns the sending domain. Required when EMAIL_PROVIDER=cloudflare.

See Email Authentication for details.

The sender selection is compiled into every build, so it is available self-hosted, but the supported self-hosted configuration is SMTP. The Cloudflare Email Sending path is the managed-cloud default: when EMAIL_PROVIDER=cloudflare is set, SMTP_FROM is the sender and its domain must be onboarded to Email Sending, and SMTP_HOST is not required because delivery is over HTTPS.

Variable Default Description
ALLOWED_ORIGINS — Required in production. Comma-separated publisher origins, such as https://example.com,https://www.example.com. Include scheme and port where needed; paths and wildcards are rejected. BASE_URL is accepted separately for dashboard requests.
Variable Default Description
RATE_LIMIT_COMMENTS 5/10m Rate limit for comment submissions. Format: count/duration where duration uses Go time syntax (e.g. 10m, 1h). 5/10m means 5 requests per 10 minutes per IP.
RATE_LIMIT_AUTH 10/5m Rate limit for auth endpoints. Same format as above.
Variable Default Description
SPAM_MAX_LINKS 3 Maximum number of links (hrefs or bare URLs) allowed in a comment before it is auto-rejected as spam.

Self-hosted builds support SMTP email notifications. Configure the SMTP_* settings above.

Variable Default Description
NOTIFY_BATCH_SIZE 5 Number of pending comments to accumulate before sending a notification.
NOTIFY_COOLDOWN_HOURS 24 Legacy (inactive). Parsed for compatibility but read nowhere at runtime. Self-hosted dispatch uses 5 minutes; cloud dispatch uses the site interval or a 5-minute default. Setting this variable has no effect.
NOTIFY_EMAIL_TO — Fallback notification recipient email address, used when the site owner has no email address on their account.

See Notifications for delivery settings and channel availability.

Variable Default Description
TURNSTILE_SITE_KEY — Cloudflare Turnstile site key. Served to the embed widget to render the challenge.
TURNSTILE_SECRET_KEY — Cloudflare Turnstile secret key. Used for server-side token verification.

Both variables must be set to enable Turnstile bot protection from the environment. Keys saved on the dashboard’s Account page take priority over these variables, so you can also leave both unset and configure Turnstile there.

These variables are read by the Docker entrypoint, not by the Go backend:

Variable Default Description
LITESTREAM_REPLICA_URL — Replica URL. A nonempty value enables restore-on-startup and continuous replication with the packaged Litestream v0.3.14.
LITESTREAM_ACCESS_KEY_ID — Access key for the replica bucket.
LITESTREAM_SECRET_ACCESS_KEY — Secret key for the replica bucket.

See Backups and restore for setup and restore behavior.

Self-hosted builds use local SQLite and do not include managed billing or tenant provisioning. Leave CLOUD_MODE unset or false; setting it to true does not convert a self-hosted image into the managed platform. Turso and Stripe credentials are not needed for self-hosting.

Process environment variables take priority. The backend then loads ../.env and .env without overwriting values already set. Docker Compose passes .env through env_file. Keep one configuration source per deployment to avoid conflicting values.