Skip to content

Checklist

Go through the list before the first release to production and after larger changes of the infrastructure.

  • CI_ENVIRONMENT = production, debug toolbar gone, no error details on an error page.
  • Document root is public/; .env, writable/ not reachable.
  • HTTPS only, HSTS at the web server, app.baseURL with https://, cookie.secure = true.
  • Config\App::$proxyIPs set when behind a proxy; the audit log shows real client IPs.
  • app.CSPEnabled = true, response headers checked in the browser (CSP, frame-ancestors 'none', nosniff, HSTS).
  • Global csrf (except api/* with the API, sso/*/callback with SAML), secureheaders and Shield’s auth-rates filter active (php spark filter:check GET admin, php spark filter:check GET login).
  • New encryption.key and own anvil.auditKey for production, kept in a secret store and backed up; no secret in the repository.
  • composer install --no-dev, migrate --all, anvil:publish done; anvil:workflow:check passes.
  • Cron for anvil:tick, anvil:prune, anvil:audit:verify (and anvil:api:review), queue worker running.
  • Real cache handler; shared cache, sessions and file storage with several servers.
  • Virus scanner configured and reachable, upload limits in php.ini match $fileMaxSize.
  • logger.threshold = 5, logs forwarded, alerts on security events.
  • Database user restricted on the audit tables; backup and restore tested.
  • Administrator password changed, two-factor required (anvil.mfaRequired = true) or panels restricted to single sign-on; Config\Anvil::$shieldGroupFallback = false once roles are maintained in Anvil.