Skip to content

Hardening Checklist

A checklist for operators of public Doable instances (SaaS-style, anonymous signups). For private/team deployments most of these are optional.

Operating system

  • [ ] OS fully patched (unattended-upgrades enabled).
  • [ ] Non-root user for application processes (Docker does this; for bare-metal, run doable.service as a dedicated user).
  • [ ] SSH: key-only login, root login disabled, fail2ban watching.
  • [ ] UFW: deny incoming except 22, 80, 443.
  • [ ] Time sync (systemd-timesyncd or chrony) — JWT validation needs accurate clocks.
  • [ ] Swap configured (Doable's installer does 2 GB by default).

Network

  • [ ] All app services bound to 127.0.0.1 — verify with ss -tlnp.
  • [ ] One TLS-terminating proxy (nginx/Caddy) is the only publicly reachable port besides SSH.
  • [ ] HSTS header enabled in the proxy (Strict-Transport-Security: max-age=63072000; includeSubDomains; preload).
  • [ ] HTTP/2 enabled; HTTP/3 if your proxy supports it.
  • [ ] Rate limits at the proxy on /auth/* (much stricter than other routes).
  • [ ] Egress firewall — block outbound to RFC1918, link-local, and metadata IPs (169.254.169.254).
  • [ ] Optional: WAF in front (Cloudflare proxied, or AWS WAF) for L7 abuse.

Secrets

  • [ ] JWT_SECRET, ENCRYPTION_KEY, INTERNAL_SECRET are unique 32-byte random hex strings.
  • [ ] .env and docker/.env chmod 600, owned by the app user.
  • [ ] Backups encrypt these env files separately (don't restore secrets to a new host without rotating).
  • [ ] No NEXT_PUBLIC_* variable contains a secret (audited at build time).

Database

  • [ ] PostgreSQL bound to 127.0.0.1.
  • [ ] Database user has access only to the doable database; not a superuser.
  • [ ] Daily pg_dump to off-host storage; encrypt at rest.
  • [ ] Connection limits sized so DATABASE_POOL_SIZE × replicas + admin_overhead < max_connections.

AI sandbox

  • [ ] Default policies kept strict (DEFAULT_DANGEROUS_COMMANDS not weakened).
  • [ ] URL allow-list reviewed — remove any "fetch from anywhere" overrides for public workspaces.
  • [ ] dovault resource limits set: memoryMax: 150M, cpuQuota: 30%, tasksMax: 32.
  • [ ] Process isolator backend = nsjail or systemd (not direct) on Linux.
  • [ ] Per-workspace credit caps configured to prevent runaway AI spend.

Account abuse

  • [ ] Email verification required on signup (/auth/signup endpoint behavior).
  • [ ] Strict password policy (≥ 8 chars; bcrypt cost ≥ 12).
  • [ ] Rate limits on signup, login, password reset (already configured by default — verify in services/api/src/index.ts).
  • [ ] Captcha on signup if you see automated abuse (not built in — wire up Turnstile or hCaptcha).
  • [ ] Disposable-email block list if needed.

Outbound abuse from user projects

  • [ ] Each project's Vite dev server runs jailed (default).
  • [ ] User project fetch() calls go through your egress firewall.
  • [ ] Published sites (SITES_DIR/*) are static-only; no server-side execution.

Updates

  • [ ] Subscribe to the Doable repo's Security Advisories.
  • [ ] Run pnpm audit (or your favorite vulnerability scanner) periodically; rebuild containers.
  • [ ] Test upgrades on a staging instance before production.

Observability

  • [ ] Centralize logs (journalctl → Loki / CloudWatch / Datadog).
  • [ ] Alert on: 5xx rate, auth failures spike, audit-log denies spike, disk usage, AI provider errors.
  • [ ] Periodically review Workspace Settings → Audit for suspicious tool-call patterns.

Incident response

  • [ ] Documented playbook for rotating secrets in an emergency.
  • [ ] Documented playbook for revoking a workspace / user.
  • [ ] Recent backup tested for restore (don't trust untested backups).
  • [ ] Out-of-band contact info for Stripe, AI providers, and your DNS provider.

Compliance hooks (if applicable)

  • [ ] Data retention policy for chat history & audit log.
  • [ ] DPA in place with the AI provider.
  • [ ] DSAR process — exporting and deleting a user's data.

If you check off this list, you're well past the security level of most commercial AI app builders.