# Docker Service Deployment Standard (IT Pro Partner)

This reference documents the standard for deploying Docker services on ITP infrastructure.

## Directory Structure

```
~/docker/<service-name>/
├── docker-compose.yml   ← Pinned image tags (never :latest)
├── .env                 ← Secrets only (never in compose file)
├── data/                ← Persistent volumes on disk (backed up by S3)
├── CHANGELOG.md         ← Every config change documented
```

## Access: Tailscale-Only Standard

1. Deploy compose in `~/docker/<service>/`
2. Verify local: `curl -s http://localhost:<port>/`
3. Open UFW: `ufw allow <port>/tcp`
4. Enable Tailscale Serve for HTTPS: `tailscale serve --bg --https 443 --set-path / http://127.0.0.1:<port>`
5. Set the service's base URL to `https://<hostname>.tail<random>.ts.net`
6. Test from a Tailscale-connected device
7. Close UFW port: `ufw delete allow <port>/tcp`
8. Log: `bash ~/.hermes/scripts/changelog.sh "Networking" "Tailscale Serve for <service> at https://..."`

## Vaultwarden-Specific Notes

- DOMAIN env var must match the access URL exactly. Wrong protocol (http vs https) causes the web vault to hang on a spinner silently.
- Registration is disabled by default (`SIGNUPS_ALLOWED=false`). Enable it temporarily for first-user setup, then lock it.
- Admin panel at `/admin` uses the `ADMIN_TOKEN` from `.env`.
- Tailscale hostname with `0` vs `O` confusables: the Bitwarden mobile app may silently corrupt zero characters in the URL during text input. Fix: rename the Tailscale node before deploying: `tailscale set --hostname vaultwarden`. Then re-create Tailscale Serve (turn off, re-enable — it picks up the new hostname). No zeros, no letter-O confusion.
- Bitwarden app fails with "not a recognized Bitwarden server": always the DOMAIN/access-URL mismatch. Verify via `curl https://<url>/api/config` — the `identity` field must match exactly what the app connects to.

## Backup

- Compose files and .env are synced to S3 every 15 min via `hermes-live-sync`
- For data directories: same sync includes `~/docker/*/data/*`
- RPO: < 15 min for both config and data
