Every environment variable Checky reads, with defaults — the same names on Docker and Cloudflare Workers.
Checky is configured with environment variables. Docker reads them from .env next to docker-compose.yml
(keep it at mode 600); on Cloudflare they are Worker variables, secrets via wrangler secret put NAME.
Invalid values stop the server at start with a list of the problems.
In production (NODE_ENV=production, the Docker image’s default) Checky refuses secrets copied from example
files (values containing change-me or dev-only-insecure). Generate secrets with openssl rand -base64 48.
Required
| Variable |
Default |
Description |
BASE_URL |
http://localhost:3000 |
Public URL, https:// in production, no trailing slash. Links in emails, passkeys, OAuth and SSO callbacks use it. On Workers empty = the URL of the first request. |
BETTER_AUTH_SECRET |
— (required in production) |
≥ 32 characters. Signs sessions; rotating it signs everyone out. |
APP_SECRET |
BETTER_AUTH_SECRET |
≥ 32 characters. One-tap email links, reply addresses, encryption of SSO secrets. Rotating it invalidates open email links and requires re-entering SSO client secrets. |
Server and database (Docker)
| Variable |
Default |
Description |
NODE_ENV |
production in the image |
development, test or production. |
PORT / HOST |
3000 / 0.0.0.0 |
Listen address inside the container. |
DATABASE_URL |
/data/checky.db in the image |
SQLite file path or a libsql URL (DATABASE_AUTH_TOKEN for remote libsql). |
CHECKY_IMAGE |
ghcr.io/sonnenglas/checky:latest |
Compose only: the image to run. Pin x.y in production. |
CHECKY_PORT |
3000 |
Compose only: the port published on the host. |
TRUST_PROXY |
false |
Set true behind Caddy/Traefik/nginx: the client IP for rate limiting then comes from CLIENT_IP_HEADERS. Without it forwarding headers are ignored (clients can forge them). |
CLIENT_IP_HEADERS |
x-forwarded-for |
Headers your proxy writes with the client IP (right-most entry is used). |
TRUSTED_ORIGINS |
— |
Comma-separated extra origins allowed to call the auth endpoints. |
MULTI_ORG |
false |
true only for a hosted, multi-organization instance. |
Email
| Variable |
Default |
Description |
EMAIL_FROM |
Checky <checky@localhost> |
Sender, e.g. Checky <[email protected]>. The domain must be verified at your provider. |
SMTP_URL |
— |
smtps://user:[email protected]:465, or port 587 with smtp://… (STARTTLS). Docker only. |
EMAIL_TRANSPORT |
smtp if SMTP_URL is set, else console |
console only logs emails. On Workers: cloudflare (default with the binding) or console. |
EMAIL_REPLY_DOMAIN |
— |
Domain that receives reply+<token>@… replies. Empty = reply-to-answer off. |
INBOUND_WEBHOOK_SECRET |
— |
≥ 16 characters. Enables POST /api/v1/inbound/email (Mailgun, Postmark, SendGrid, generic). |
Details: Email setup.
Scheduler
| Variable |
Default |
Description |
SCHEDULER_ENABLED |
true |
In-process scheduler (Docker). Set false only if another process ticks. |
SCHEDULER_CRON |
* * * * * |
Cron pattern of the tick (create check-ins, mark missed, send reminders, deliver webhooks). |
Sign-in and SSO
| Variable |
Default |
Description |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
— |
Google sign-in. Redirect URI <BASE_URL>/api/auth/callback/google. |
MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRET |
— |
Microsoft sign-in. Redirect URI <BASE_URL>/api/auth/callback/microsoft. |
MICROSOFT_TENANT_ID |
common |
Your directory id: then Microsoft sign-ins are linked to existing accounts by email. |
SSO_ALLOW_PRIVATE_IDP |
false |
Allow an identity provider on http:// or a private address (internal Keycloak). Also add its origin to TRUSTED_ORIGINS. |
DNS_OVER_HTTPS_URL |
https://cloudflare-dns.com/dns-query |
DNS-over-HTTPS endpoint (JSON API) used to look up the TXT record when verifying an email domain. Point it at your own resolver if outbound DoH is blocked. |
Integrations
| Variable |
Default |
Description |
API_RATE_LIMIT |
600 |
REST API requests per minute per user / API key (0 = unlimited). |
OAUTH_CIMD |
true |
Accept OAuth Client ID Metadata Documents (ChatGPT/Claude), fetched with an SSRF-safe client. |
WEBHOOKS_ALLOW_PRIVATE |
false |
Allow webhook targets on http:// and private networks (self-host behind a firewall only). |
OPENAI_APPS_CHALLENGE |
— |
Domain verification token served at /.well-known/openai-apps-challenge. |
HOLIDAYS_API_URL |
https://date.nager.at |
Public-holiday source (Nager.Date-compatible API) for the holiday import. Point it at a self-hosted Nager.Date if your server can’t reach the internet. |
Licence and updates (self-host)
| Variable |
Default |
Description |
CHECKY_LICENSE_KEY |
— |
Your licence key from the checky.team account. Verified offline; nothing is sent anywhere. |
UPDATE_CHECK_URL |
https://checky.team/versions.json |
Release feed for the admins’ “update available” notice — a plain GET without any data about your instance. Empty = off. |
Backups (Docker + Litestream)
LITESTREAM_BUCKET, LITESTREAM_PATH (default checky), LITESTREAM_ENDPOINT, LITESTREAM_REGION,
LITESTREAM_ACCESS_KEY_ID, LITESTREAM_SECRET_ACCESS_KEY — see Backups and upgrades.
Hosted and demo only
PROVISIONING_SECRET, HOSTED_DOMAIN, HOSTED_RESERVED_SLUGS, HOSTED_FALLBACK_URL run a multi-tenant
instance (MULTI_ORG=true); DEMO_MODE and DEMO_RESET_HOUR run the public demo, which deletes all data
every night — never set them on a real instance.
Test only — never in production
| Variable |
Default |
Description |
ACCEPTANCE_MODE |
off |
Enables the clock override used by Checky’s release acceptance suite to simulate days and weeks. Off by default. |
ACCEPTANCE_SECRET |
— |
Shared secret the acceptance suite must present; the override stays disabled without it. |
These exist so every release can be tested end to end before it ships. Do not set them on an installation
with real data.