4.**`data/config.json` from `/admin` — highest precedence** (overrides env)
Official stance: prefer environment variables; `config.json` is **not** the recommended long-term method. Once admin saves `config.json`, those keys stop being changeable via `.env` until removed/edited in admin or the file.
| Public URL | Set `DOMAIN` e.g. `https://auth.wsvc.info` (no trailing slash) | Set in compose + `config.json` |
| SMTP | `587`+`starttls` or `465`+`force_tls` | Effective: **587/starttls** to mx2 (`465` unreachable from us2); `extra_hosts` pins A `194.163.160.244` |
| SMTP password | Same mailbox password as mailcow | Must match across `.env`, `config.json`, `.smtp-credentials`. **Admin/`config.json` wins** — stale admin password → SMTP `535` while `.env` still works |
| Database | `DATABASE_URL` for Postgres | Live: Postgres via compose `DATABASE_URL`; sqlite cold under `backups/sqlite-cold/` |
| Client IP behind proxy | Traefik → prefer `X-Forwarded-For` | `ip_header=X-Forwarded-For` in `config.json` |
| Admin | Argon2 `ADMIN_TOKEN` | On server only |
| Signups | Invite-only on public URL | `signups_allowed=false` |
## Agent checklist before edits
1. Read this page + [us2 host facts](../hosts/us2.wsvc.info.md).
2. On the server, compare `.env`, compose `environment`, and `/data/config.json` (including SMTP password fingerprint, not plaintext in chat/logs).
3. Change the layer that actually wins (often `config.json`); if rotating the mailbox password, update **all three** secret stores.
4. After recreating the `vaultwarden` container, restart Traefik if `auth.wsvc.info` 404s.
5. Do not commit secrets; do not copy passwords from Obsidian into this repo.
6. Verify SMTP with AUTH (not TCP-only) — [vaultwarden-health](../runbooks/vaultwarden-health.md) §5.