# Production deployment The production shape is Docker Compose (PostgreSQL + FastAPI) behind the host Caddy instance. Caddy owns HTTPS and serves the Vue build from `/srv/keychain/web`; the API is only published on `127.0.0.1:8799`. The deployment secret file lives outside Git at `/etc/keychain/keychain.env` with mode `0600`. It must contain a random URL-safe `KEYCHAIN_DB_PASSWORD` and may contain `KEYCHAIN_EXTENSION_ID` after the unpacked extension receives its stable ID. ```sh install -d -m 0750 /etc/keychain openssl rand -hex 32 install -m 0600 /dev/null /etc/keychain/keychain.env # Put KEYCHAIN_DB_PASSWORD= in the file. npm ci VITE_API_URL=/api VITE_DEMO_MODE=false npm run build --workspace=@keychain/web install -d -m 0755 /srv/keychain/web cp -a apps/web/dist/. /srv/keychain/web/ docker compose --env-file /etc/keychain/keychain.env -f deploy/docker-compose.prod.yml up -d --build ``` Append `deploy/Caddyfile.keychain` as a new block to `/etc/caddy/Caddyfile`, validate, then restart Caddy. Existing Caddy blocks must remain unchanged. Verify: ```sh curl -fsS https://keychain.agent.snw.su/api/health docker compose --env-file /etc/keychain/keychain.env -f deploy/docker-compose.prod.yml ps ``` For rollback, restore the previous `/srv/keychain/web` contents and redeploy the previous Git commit. Do not remove the named `keychain-postgres` volume.