Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions apps/docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand Down
9 changes: 3 additions & 6 deletions apps/docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
9 changes: 1 addition & 8 deletions apps/docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
46 changes: 46 additions & 0 deletions apps/docs/production-checklist.md
Original file line number Diff line number Diff line change
@@ -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
Loading