Start with the log: docker compose logs --tail 100 checky (Cloudflare: Worker → Logs, or wrangler tail),
and curl -s <BASE_URL>/health.
The container doesn’t start
Invalid configuration:followed by a list — fix the named variables in.env. Typical:BETTER_AUTH_SECRET: required in production, a secret shorter than 32 characters, oruses a published example value; generate a random one(you copied an example secret).- Port already in use — set
CHECKY_PORT=3001(or another free port) in.env. - Permission denied on
/data— the image runs as uid 65532. If you mount a host directory instead of the named volume,chown -R 65532:65532it.
No emails arrive
- The first log line says
email: console? ThenSMTP_URLisn’t set — emails are only logged. - Check the log for SMTP errors (authentication, TLS). Port 465 needs
smtps://, port 587smtp://. - Delivered but in spam: set up SPF, DKIM and DMARC for the
EMAIL_FROMdomain. - Reminders follow each person’s notification preference (all, due only, deadline only, none) and are not sent during absences and public holidays.
Replies don’t answer the check-in
EMAIL_REPLY_DOMAINmust be set before the reminder is sent (the Reply-To address is in the email).- Docker:
INBOUND_WEBHOOK_SECRETset, and the provider posts to/api/v1/inbound/emailwith the secret.401= wrong secret,404= the webhook is disabled (no secret configured). - Replies are accepted until seven days after the deadline, once per check-in.
Sign-in problems
- Redirected to the wrong address or cookies don’t stick —
BASE_URLmust be exactly the URL in the browser (scheme, host, port, no trailing slash). - Passkeys fail — passkeys need
https://(orlocalhost) and are bound to the host ofBASE_URL. After changing the domain, people register new passkeys. - “Sign-up is not allowed” — on a self-hosted install only the first account is free; others need an invitation or a verified email domain with auto-join.
- Everyone was signed out —
BETTER_AUTH_SECRETchanged. - One-tap links say “invalid” —
APP_SECRETchanged, or the link is older than allowed.
Live updates don’t appear
The dashboard updates through Server-Sent Events on /api/v1/events. Behind a proxy, disable buffering:
Caddy flush_interval -1, nginx proxy_buffering off;. Reloading the page always shows the current state.
Rate limiting looks wrong behind a proxy
Without TRUST_PROXY=true, all requests seem to come from the proxy’s address and share one limit. Set
TRUST_PROXY=true (and CLIENT_IP_HEADERS if your proxy uses another header).
SSO and domains
- Domain verification fails — the TXT record isn’t visible yet (DNS can take hours). Check with
dig TXT _checky-verification.example.com. If your server can’t reachcloudflare-dns.com, setDNS_OVER_HTTPS_URL. - “Domain already taken” — another organization verified it.
- Internal IdP rejected — set
SSO_ALLOW_PRIVATE_IDP=trueand add its origin toTRUSTED_ORIGINS. - SSO stopped working after moving — update the redirect/ACS URLs at the IdP and re-enter client secrets if the export had no passphrase.
Public holidays don’t import
The holiday import calls Nager.Date (HOLIDAYS_API_URL). On a server without internet access, run your own
Nager.Date instance and point the variable at it, or enter holidays as absences.
Import refused
import.version_unsupported— the file comes from a newer Checky; upgrade the target first.- A self-hosted install only accepts an import while it is still empty — start with a fresh volume.
Still stuck?
Write to [email protected] with the version (/health), how you run Checky and the relevant log lines (remove
secrets first).