> Raw Markdown twin (generated at build time from the source Markdown). Rendered page: https://docs.gatellm.io/en/practices/production-checklist · Doc index: https://docs.gatellm.io/en/llms.txt


# Production checklist

Before moving from single-node trial to production, go through this checklist item by item. Each item gives "why" and "where to configure", and can be checked off.

## Image version

- [ ] Pin an **immutable version tag** `vX.Y.Z`, **not `latest`** — a floating tag makes restarts/scaling pull a different version, so failures can't be reproduced and there's no determinable rollback target.
- [ ] For absolute immutability, pin further to `@sha256:<digest>`.
- [ ] Record the currently deployed version number for cross-referencing release notes, troubleshooting, and rollback.

> The official image is multi-arch (`linux/amd64` + `linux/arm64`) and auto-resolves by host architecture. For tag semantics, architecture support, and how to pin, see [image tags and architectures](/en/reference/image-tags-and-arch.md).

## Startup and probes

- [ ] `/health` returning 200 means alive.
- [ ] The external load balancer health check points to `/ready` (returns 503 when the database is unreachable, the gateway is draining, or the ingress spool volume is hung — used for canary removal / zero-downtime restart / automatic removal of hung volumes).
- [ ] `HOST` is set to `0.0.0.0` so it can be reached via port mapping inside a container (`127.0.0.1` is local-only).

## Credentials and encryption keys

- [ ] The built-in admin account `protoflux`'s initial password has been changed (Console → Console users).
- [ ] `ENCRYPTION_KEY` is injected from an environment variable, **not** hardcoded into the image or compose plaintext.
- [ ] `ENCRYPTION_KEY` is **backed up**: losing it = encrypted data (access keys, upstream API keys) permanently unreadable.
- [ ] In multi-instance, all instances use the **same** `ENCRYPTION_KEY`.

::: danger ENCRYPTION_KEY loss is irreversible
Without this key, the access keys and upstream API keys in the database cannot be decrypted. Be sure to back it up separately, not only in the deployment environment.
:::

## Console exposure

- [ ] `CONSOLE_ALLOW_REMOTE` defaults to `true` (the image allows remote Console access by default). When tightening, set it to `false` and **combine with a reverse proxy + access control** (firewall / IP allowlist / VPN) — don't expose it bare.
- [ ] Login brute-force protection is active (default: 5 failures bans for 300 seconds).
- [ ] SSO enterprise login (if needed) is configured; see [Configure SSO enterprise login](/en/howto/configure-sso.md).

## Storage and multi-instance

- [ ] Single-node uses SQLite, with an absolute file path (e.g. `/var/lib/protoflux/stats.sqlite`) mounted on a persistent volume.
- [ ] Multi-instance uses PostgreSQL (shared stats and config, 30s cross-instance sync) + Redis (shared session/rate limit/IP ban/log broadcast). See [Environment variable configuration reference](/en/reference/configuration.md) for the fields.
- [ ] PostgreSQL version **17+**: log tables (`request_logs` / `openai_message_store`) are partitioned daily by RANGE and their primary keys are `IDENTITY` columns; IDENTITY columns on partitioned tables are supported only from PG17 (earlier versions fail at table creation).
- [ ] Multi-instance **must configure Redis**, otherwise session/rate limit/IP ban degrade to per-instance independence, and ban thresholds are effectively meaningless. See [Achieve high availability](/en/usecases/high-availability.md#multi-instance-shared-state).

## Logs and disk

- [ ] `LOG_RETENTION_DAYS` is set per compliance needs (e.g. 30/90 days).
- [ ] `LOG_MAX_BODY_SIZE_MB` is set as needed (default 25 MB; set 0 to not capture the body, but you lose content traces).
- [ ] `LOG_STREAM_BODY_MAX_DISK_MB` controls streaming body disk usage.
- [ ] In multi-instance, the Live logs SSE stream aggregates logs from all instances; see [Logs viewer](/en/console/logs-viewer.md).

## Rate limiting and banning

- [ ] `RATE_LIMIT_*` is configured per key/IP/upstream with RPM, concurrency, and TPM caps. See [Audit and security configuration](/en/reference/audit-and-security-config.md) for the fields.
- [ ] In multi-instance, rate limiting goes through shared Redis, otherwise it is per-instance independent and thresholds are diluted.

## Backup and restore

- [ ] The database (SQLite file / PostgreSQL) is backed up regularly.
- [ ] `ENCRYPTION_KEY` is backed up separately (see above).
- [ ] The container's environment-variable list (compose / task definition) is under version control.
- [ ] A restore process has been verified once (backing up without verifying is as good as no backup).

## FAQ

**Q: Can a single node go to production directly?**
Small scale is fine, but you lose high availability and horizontal scaling. When scale grows or high availability is required, move to multi-instance + PostgreSQL + Redis.

**Q: Forgot the admin password?**
Set `RESET_ADMIN=<new password>` and restart to reset (**takes effect once only**). To reset again: set `RESET_ADMIN` to a new value and restart again. After a successful reset, remove the environment variable and restart to avoid a warning on every restart. See the FAQ in [Docker single-node walkthrough](/en/quickstart/docker-single-node.md).

**Next**: [Achieve high availability](/en/usecases/high-availability.md) for disaster recovery; [Audit and security configuration](/en/reference/audit-and-security-config.md) for security fields; [Meet compliance and audit requirements](/en/usecases/compliance-audit.md) for compliance.
