From c6b28b8307d1ec0f825b6fa1071a82eb6c24ce61 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 5 Sep 2026 19:28:48 +0000 Subject: [PATCH] docs(docs): add the Production checklist page and point the copies at it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase-2 documentation restructure — another additive "new page", and the home the audit said the security-hardening list never had. The list (auth on, encryption key, HTTPS, trust-proxy) was copied across the README, deployment, authentication, privacy, SECURITY.md and the Docker Hub page, with no single source. - Add apps/docs/production-checklist.md (Operate, 585 words): the ordered "before you expose it" steps, a "what Piwi already does for you" section (non-root container, scrypt hashing, hashed API keys, rate limiting, env-secret handling, AES-256-GCM, forward-only migrations), and the optional share-links/retention notes. The secret-generation one-liner is the shared snippet include, not another literal copy. - Point the two most prominent copies at it: deployment's "Security" section keeps its heading (privacy deep-links the anchor) and the non-root fact but drops the duplicated bullets; the README's "before you expose it" keeps its teaser bullets and adds a link. Authentication's "Security considerations" keeps only its auth-specific facts (scrypt, rate limiting, trust-proxy) and links the checklist for the generic steps. - Add a "Production checklist" entry to the "Running your instance" sidebar. No existing page URL or heading anchor changes (deployment#security stays). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01GKdmqq1BRUPeH5BxSPV5Jj --- README.md | 3 ++ apps/docs/.vitepress/config.mts | 1 + apps/docs/authentication.md | 9 ++---- apps/docs/deployment.md | 9 +----- apps/docs/production-checklist.md | 46 +++++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 apps/docs/production-checklist.md diff --git a/README.md b/README.md index dcd69c3da..a6b7ba4c6 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,9 @@ and not fine on a network. Three things to set before anyone else can reach it: Generate a value for either secret with `node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"`. +The full list — including the trust-proxy flag, backups and version pinning — is the +[production checklist](https://piwitests.dev/production-checklist). + Found a vulnerability? Please report it privately via the [security policy](./SECURITY.md). ## A quick tour diff --git a/apps/docs/.vitepress/config.mts b/apps/docs/.vitepress/config.mts index 37487d4f9..a9c18f23e 100644 --- a/apps/docs/.vitepress/config.mts +++ b/apps/docs/.vitepress/config.mts @@ -140,6 +140,7 @@ export default defineConfig({ text: 'Running your instance', items: [ { text: 'Deployment', link: '/deployment' }, + { text: 'Production checklist', link: '/production-checklist' }, { text: 'Upgrading', link: '/upgrading' }, { text: 'Configuration reference', link: '/configuration' }, { text: 'Configuration generator', link: '/configuration/generator' }, diff --git a/apps/docs/authentication.md b/apps/docs/authentication.md index f4305be3b..33649ad39 100644 --- a/apps/docs/authentication.md +++ b/apps/docs/authentication.md @@ -312,13 +312,10 @@ The reporter automatically calls `/api/auth/login` before each upload and uses t ## Security considerations -- Always use HTTPS in production. -- Use strong, unique passwords. -- Set `PIWI_SECRET_KEY` (generate with `node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"`, or `openssl rand -hex 32`) to encrypt AI API keys and SCM tokens at rest in the database. This is recommended even when authentication is disabled. -- Set `PIWI_AUTH_SECRET` (same generator) for session cookie encryption — required when `PIWI_AUTH_ENABLED=true`. -- Passwords are hashed using scrypt with per-password salts. +Everything to set before you expose an instance — HTTPS, `PIWI_SECRET_KEY`, `PIWI_AUTH_SECRET` and the trust-proxy flag — is the [production checklist](./production-checklist). What authentication adds on top of that: + +- Passwords are hashed using scrypt with per-password salts; use strong, unique passwords. - Login, initial setup, and password-reset endpoints are rate-limited per client address — failed logins also per account — and throttled requests get a `429` with a `Retry-After` header. Behind a reverse proxy, set `PIWI_TRUST_PROXY` so those per-address limits see real client addresses; see the [configuration reference](./configuration#authentication). -- Never use the default secrets in production. ## Disabling authentication diff --git a/apps/docs/deployment.md b/apps/docs/deployment.md index c4a6edd89..4d94eb635 100644 --- a/apps/docs/deployment.md +++ b/apps/docs/deployment.md @@ -444,14 +444,7 @@ Piwi is a single Node.js process and runs comfortably on small machines: ## Security -The container runs as a non-root user (`nodejs:nodejs`, UID/GID 1001). - -Security best practices: - -- Always use HTTPS in production -- Mount `.data/` on a persistent volume -- Set a strong `PIWI_SECRET_KEY` (`node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"`, or `openssl rand -hex 32`) to encrypt secrets at rest -- Set a strong `PIWI_AUTH_SECRET` and enable authentication for multi-user deployments +The container runs as a non-root user (`nodejs:nodejs`, UID/GID 1001). Everything to set before you put an instance on a shared address — authentication, the encryption key, HTTPS, the trust-proxy flag, backups and version pinning — is the [production checklist](./production-checklist). ## Troubleshooting diff --git a/apps/docs/production-checklist.md b/apps/docs/production-checklist.md new file mode 100644 index 000000000..98b365b74 --- /dev/null +++ b/apps/docs/production-checklist.md @@ -0,0 +1,46 @@ +--- +title: Production checklist +lang: en-US +--- + +# Production checklist + +A fresh Piwi instance starts as an **open dashboard with authentication off** — right for localhost, wrong for a network. This is the one page that lists what to set before anyone else can reach it. Work down it before you put an instance on a shared address; the detail links go to the pages that explain each step. + +## Before you expose it + +1. **Turn authentication on.** Set `PIWI_AUTH_ENABLED=true` and a strong `PIWI_AUTH_SECRET` (session-cookie signing key). The server refuses to start with auth enabled and no secret, so this can't half-apply. See [Authentication](./authentication). +2. **Set the encryption key.** Set `PIWI_SECRET_KEY` so the credentials you store in the dashboard — AI API keys, SCM tokens, webhook secrets — are encrypted with **your** key. Unset, Piwi falls back to a development key published in this repository, which is no protection at all. Generate either secret with: + + <<< @/snippets/secret.sh{bash} + +3. **Terminate TLS.** Always put the dashboard behind an HTTPS reverse proxy. Mind the two things a proxy gets wrong by default: **upload size** (trace and report uploads reach hundreds of MB) and **SSE buffering** (live runs and browser notifications use long-lived `text/event-stream` responses that must not be buffered). See [Deployment → Reverse proxy (HTTPS)](./deployment#reverse-proxy-https). +4. **Tell Piwi it's behind a proxy.** Set `PIWI_TRUST_PROXY=true` so the per-client rate limits on the auth endpoints key on the real client address from `X-Forwarded-For` instead of pooling every request into the proxy's one address. Leave it off when clients connect directly — see the [configuration reference](./configuration#authentication). +5. **Persist and back up the data.** Mount `/app/.data` (or your configured database and storage paths) on a persistent volume, and set up a backup before you accumulate history you care about. See [Deployment → Backups](./deployment#backups). +6. **Pin a version.** Running `latest` lets an unattended `docker pull` move you across a breaking change. Pin an exact tag and bump it deliberately — migrations are forward-only, so the rollback path is *restore a backup*, not "pull the old tag." See [Upgrading](./upgrading). + +Never leave the built-in development secrets in place on a real deployment. + +## What Piwi already does for you + +The defaults are conservative, so the checklist above is short. Without any extra work: + +- The container runs as a **non-root** user (`nodejs`, UID/GID 1001). +- Passwords are hashed with **scrypt** and per-password salts; login, initial-setup and password-reset endpoints are **rate-limited** per client address (and failed logins per account), returning `429` with `Retry-After`. +- **API keys** are stored only as SHA-256 hashes and shown once, at creation — a leaked database yields no usable key. +- Secrets supplied by **environment variable** are never written to the database and never returned by the API; the settings UI shows them read-only with a lock badge. +- Stored credentials are encrypted with **AES-256-GCM** once `PIWI_SECRET_KEY` is set. +- Database **migrations are forward-only** and run on startup; a failed migration stops the server rather than serving a half-migrated schema. + +## Optional, and worth a thought + +- **Public share links** are off by default (`PIWI_SHARE_LINKS_ENABLED`). If you turn them on, know that anyone with the link sees the execution or cluster without signing in — see [Share links](./share-links). +- **Retention.** Automatic pruning is opt-in; set `PIWI_RETENTION_DAYS` to cap how much run history you keep. See [Storage → Data retention](./storage#data-retention). + +## Related + +- [Authentication](./authentication) — roles, OAuth, API keys +- [Deployment](./deployment) — the reverse proxy, backups and the full install +- [Privacy & data flow](./privacy) — what is stored, and secrets at rest +- [Configuration reference](./configuration) — every `PIWI_*` variable +- [Security policy](https://github.com/PiwiTests/platform/blob/main/SECURITY.md) — reporting a vulnerability