# Deployment Two independent targets, both built from `main`. Same pattern as TranslationUI: separate GitHub Actions workflows, neither edits the other. | | HF Space | DO droplet | |---|---|---| | Workflow | `.github/workflows/deploy.yml` | `.github/workflows/deploy-do.yml` | | Triggers | `workflow_dispatch` + nightly (00:00 UTC, skipped if unchanged) | Same | | Target | `huggingface.co/spaces/GarchenArchive/ArchiveAI-TTS` | The droplet shared with TranslationUI, via SSH | | Image registry | N/A | DO Container Registry, repo `garchen-archive/archiveai-tts` | | Public URL | The Space's own URL | `https://archiveai-tts.64-225-26-230.nip.io` | | Access control | HF's private-Space account whitelist | Google OAuth via oauth2-proxy, shared with TranslationUI | ## Sharing a droplet with TranslationUI Both apps are CPU-only and lightweight enough to coexist on one droplet: - **Same droplet, separate containers**: `translationui-pilot` on internal port `7860`, `archiveai-tts-pilot` on `7861`, both bound to `127.0.0.1` only. - **Same Caddy instance**, routing by hostname. A second site block was added to the existing `/etc/caddy/Caddyfile` for `archiveai-tts.64-225-26-230.nip.io`, reverse-proxying to `127.0.0.1:7861`. - **Same oauth2-proxy, same Google OAuth app, same allowlist**: one login covers both apps. This required widening oauth2-proxy's cookie scope — `OAUTH2_PROXY_COOKIE_DOMAINS` and `OAUTH2_PROXY_WHITELIST_DOMAINS` were both set to `.64-225-26-230.nip.io` so the session cookie set on one subdomain is valid on the other. `nip.io` is on the Public Suffix List at the `nip.io` level, not per-IP, so `.64-225-26-230.nip.io` is a valid single-site cookie scope; it does not leak across other unrelated nip.io users. - **Same Volume, separate subdirectory**: TranslationUI's SQLite file lives at the volume root; TTS's project files live under `tts/` on the same volume, mounted into its container at `/data` (a different container path than TranslationUI's, same physical disk). - **Same DO Project** ("HF Migration"), same isolation-token approach as the rest of this migration. ## CI/CD (`deploy-do.yml`) Same shape as TranslationUI's: build → push to `registry.digitalocean.com/garchen-archive/archiveai-tts` → SSH in → pull, stop/remove the old container, start the new one with: - `-p 127.0.0.1:7861:7860` - `-v /mnt/hfmigration_translationui_data/tts:/data` - `-e TTS_DATA_DIR=/data` - `--env-file /root/archiveai-tts.env` (holds `ELEVENLABS_API_KEY`, `GEMINI_API_KEY`, `HF_TOKEN`, `API_TOKEN`, and `BACKBLAZE_KEY_ID` / `BACKBLAZE_APPLICATION_KEY`; never passed through CI logs or command args) > **Adding a variable to `/root/archiveai-tts.env` is not enough on its own.** > Docker reads `--env-file` only when the container is *created*, so an edited > env file reaches the app only on the next deploy that runs `docker run` — > `docker restart` will not do it. The nightly schedule will not do it either > unless `main` moved: `check-for-changes` skips the run when the current > commit's image tag already exists in the registry. After editing the env > file, either dispatch `deploy-do.yml` manually or recreate the container by > hand with the flags above. Reuses the same `DO_CI_TOKEN`/`DO_SSH_PRIVATE_KEY` credential values as TranslationUI, added as this repo's own GitHub Actions secrets. A registry-scoped token isn't tied to a specific app, but GitHub secrets are per-repo, so it is added twice. ## Manual deploy / debugging ```bash ssh -i root@ docker ps --filter name=archiveai-tts-pilot docker logs archiveai-tts-pilot --tail 50 ```