Troubleshooting

Fixes for the common problems when running Checky — the container won't start, no emails, sign-in or passkey errors, live updates, SSO and imports.

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, or uses 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:65532 it.

No emails arrive

  • The first log line says email: console? Then SMTP_URL isn’t set — emails are only logged.
  • Check the log for SMTP errors (authentication, TLS). Port 465 needs smtps://, port 587 smtp://.
  • Delivered but in spam: set up SPF, DKIM and DMARC for the EMAIL_FROM domain.
  • 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_DOMAIN must be set before the reminder is sent (the Reply-To address is in the email).
  • Docker: INBOUND_WEBHOOK_SECRET set, and the provider posts to /api/v1/inbound/email with 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_URL must be exactly the URL in the browser (scheme, host, port, no trailing slash).
  • Passkeys fail — passkeys need https:// (or localhost) and are bound to the host of BASE_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_SECRET changed.
  • One-tap links say “invalid” — APP_SECRET changed, 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 reach cloudflare-dns.com, set DNS_OVER_HTTPS_URL.
  • “Domain already taken” — another organization verified it.
  • Internal IdP rejected — set SSO_ALLOW_PRIVATE_IDP=true and add its origin to TRUSTED_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).

Stuck? We help with installations: contact us