addCommunityMediaServer.sh asks for the diag hostname, DNS-checks it and passes it to --hosts, so a rebuild sets it up like every other host instead of leaving it to be discovered missing. HOSTNAME-CHANGE.md gains §D, adding a new host, which is where the hour went: --apply is stateless and reads hostnames back out of the Caddyfile, so it silently omits a role that is not already there and the name ends up with no certificate. README and the Phase 13 checklist now point at --full or --hosts instead of --apply, and the plan's risks section carries the same warning plus the path-prefix cascade. LOGGING.md collects the four traps this produced so none of them is rediscovered. FRESH-INSTALL gains an ordered §7b and appendix M for the diag host, including that running without a webhook is correct rather than half-configured; the old Afterwards section is relettered N. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
154 lines
12 KiB
Markdown
154 lines
12 KiB
Markdown
# Changing hostnames safely
|
|
|
|
Two cases: renaming one subdomain (e.g. `watch.BASE` → `video.BASE`), and moving the whole stack to a new base
|
|
domain. Both are mostly `configure.py --full` plus a known list of places outside the repo that hold the name.
|
|
Do it between streams: the main host is MediaMTX's WebRTC advertised host, so a main-host change needs a
|
|
MediaMTX restart.
|
|
|
|
Roles: `main` (gateway page at `/`), `files` (copyparty), `clips`, `sync`, `live` (portal + `/dock/`, `/dock/clock/`,
|
|
`/dump`, `/me`, `/time`), `auth`, `watch`, `git`, `bot`. Ours: `media.`, `files.`, `clips.`, `sync.`, `live.`, … under
|
|
`dumpstervigilantes.rip`.
|
|
|
|
## Where hostnames live
|
|
|
|
### Generated on the server by `configure.py` (regenerated by `--full`, nothing to edit by hand)
|
|
| Place | Holds |
|
|
|---|---|
|
|
| `Caddyfile` | every site block — the source of truth `configure.py` reads back (`# vanguard:<role>` markers) |
|
|
| `.env` | `MAIN_HOST`, `FILES_HOST`, `CLIPS_HOST`, `SYNC_HOST`, `DIAG_HOST`, `WATCH_HOST`, `GIT_HOST`, `BOT_HOST`, `LIVE_HOST`, `APEX_HOST`, `APEX_REDIRECT` |
|
|
| `mediamtx.yml` | `webrtcAdditionalHosts: [MAIN_HOST]` (needs a MediaMTX restart to take effect) |
|
|
| `docker-compose.yml` → container env | Jellyfin `PublishedServerUrl` (WATCH), Gitea `DOMAIN/ROOT_URL/SSH_DOMAIN` (GIT), bot `WEB_PUBLIC_URL` (BOT), MediaMTX `LIVE_HOST` (text of the "is live" post), act_runner `GITEA_INSTANCE_URL` (GIT). `compose up -d` in the apply recreates the affected containers (seconds each) |
|
|
| Caddy TLS | certificates for new names are fetched automatically; old ones linger harmlessly |
|
|
|
|
### Pages in the repo that derive sibling hosts from the browser's location (label names hard-coded)
|
|
| File | Assumes |
|
|
|---|---|
|
|
| `about/index.html` | `files.`, `clips.`, `sync.`, `live.`, `auth.`, `watch.`, `git.`, `bot.` + the parent of the current host |
|
|
| `dock/index.html` | `auth.` (sign-out), ingest host prefilled from the current host (`live.`; any name of the box works for RTMP/SRT) |
|
|
| `switchToClone.sh`, `deployLive.sh` | defaults for `git.dumpstervigilantes.rip` / `media.dumpstervigilantes.rip` (override by env/arg, or edit) |
|
|
| `README.md`, `FRESH-INSTALL.md` | examples only |
|
|
Renaming a *label* (e.g. `watch` → `video`) means editing the first two; changing only the domain does not.
|
|
|
|
### Outside the repo — must be changed by hand
|
|
| System | Setting | Which host |
|
|
|---|---|---|
|
|
| DNS | A record + CNAMEs | all |
|
|
| Discord developer portal | OAuth2 redirect `https://AUTH/source/oauth/callback/discord/` | auth |
|
|
| Authentik | Embedded Outpost `authentik_host` | auth |
|
|
| Authentik | `Vanguard sites` proxy provider: authentication URL (auth) and **cookie domain** (base) | auth, base |
|
|
| Authentik | `Jellyfin` provider redirect URI `https://WATCH/sso/OID/redirect/authentik` | watch |
|
|
| Authentik | `Gitea` provider redirect URI `https://GIT/user/oauth2/authentik/callback` | git |
|
|
| Jellyfin | SSO-Auth plugin: OID endpoint `https://AUTH/application/o/jellyfin/` | auth |
|
|
| Jellyfin | Branding login disclaimer (the form action contains the watch host) | watch |
|
|
| Jellyfin | Vanguard Metadata plugin: Public URL, Authentik URL | watch, auth |
|
|
| Gitea | Authentication source `authentik`: discovery URL `https://AUTH/application/o/gitea/.well-known/openid-configuration` | auth |
|
|
| Gitea runner | registered with the instance URL → `./registerGiteaRunner.sh` again | git |
|
|
| Server clone | `git remote set-url origin ssh://git@GIT:2222/techy/Media-Server-Setup.git`; `~/.ssh/config.vanguard` Host line | git |
|
|
| Dev box | `git remote set-url origin …` | git |
|
|
| Gitea, the bot repo | nothing for a rename; `VANGUARD_DEPLOY_HOST` only if it was set to an address | — |
|
|
| Streamers' OBS | dock URL (Custom Browser Docks), dock Settings → ingest host (re-save), clock browser source URL (dock → Timecode band → "Add band + clock source" again), any manual RTMP/SRT configs (copy from the dock) | live |
|
|
| Jellyfin apps on phones/TVs | server address | watch |
|
|
| Bookmarks, Discord pinned links | main (gateway), clips, files, watch, live | all |
|
|
Not affected: Syncthing pairings (device IDs), MariaDB, stream tokens, the Gitea webhook (gateway IP), Authentik users/groups/policies.
|
|
|
|
## A. Renaming one subdomain (example: `watch.BASE` → `video.BASE`)
|
|
|
|
1. DNS: add `CNAME video.BASE → HOST`. Keep the old record until step 7.
|
|
2. Server, between streams: `./configure.py --full` → Enter keeps every value; type the new name at the
|
|
"Jellyfin hostname" prompt; `y`. Caddy reloads (new block, old gone), Jellyfin is recreated with the new
|
|
published URL. `curl -sI https://video.BASE/ | head -1` → 200/302 once the certificate is issued.
|
|
(Only the *main* host touches `mediamtx.yml`; other hosts need no MediaMTX restart.)
|
|
3. Authentik: Applications → Providers → `Jellyfin` → Edit → redirect URI → the new host → Update.
|
|
4. Jellyfin: Dashboard → General → Branding → disclaimer form action → new host → Save.
|
|
Dashboard → Plugins → Vanguard Metadata → Public URL → new host → Save.
|
|
5. If the *label* changed (`watch`→`video`), edit `about/index.html` (`sub('watch')` → `sub('video')`) — commit, push,
|
|
`sudo vanguard-deploy pull`. (`.env APEX_REDIRECT` too if the bare domain pointed at it: `./configure.py --full`.)
|
|
6. Private window: `https://video.BASE/` → Discord → in. The gateway `https://HOST/` links to the new name.
|
|
7. Remove the old DNS record. Tell members with Jellyfin apps to update the server address.
|
|
|
|
Per-host extras when it is a different host:
|
|
- **auth**: Discord portal redirect; Authentik outpost `authentik_host` and the proxy provider's authentication URL;
|
|
Jellyfin SSO plugin OID endpoint; Vanguard plugin Authentik URL; Gitea auth source discovery URL;
|
|
`dock/index.html` + `about/index.html` if the label changed. Everyone re-logs in.
|
|
- **git**: Authentik Gitea provider redirect; `./registerGiteaRunner.sh`; server clone remote + `~/.ssh/config.vanguard`;
|
|
dev remote; `switchToClone.sh` default.
|
|
- **live**, **bot**: only the compose env (automatic) and `about/index.html` if the label changed.
|
|
- **main (HOST)**: `mediamtx.yml` changes → `docker compose restart mediamtx` between streams; every streamer
|
|
re-adds the dock URL, re-saves Settings (ingest host), and re-runs "Add band + clock source"; manual RTMP/SRT
|
|
configs are re-copied from the dock; `deployLive.sh` default host.
|
|
|
|
## B. Changing the base domain (everything at once)
|
|
|
|
Plan a maintenance window: Caddy, Jellyfin, Gitea, the bot and MediaMTX all restart, and every member logs in again
|
|
(the Authentik session cookie is bound to the base domain).
|
|
|
|
1. DNS on the new domain: `A HOST2 → IP`, CNAMEs `files`, `clips`, `sync`, `live`, `auth`, `watch`, `git`, `bot` → `HOST2` (optional bare domain A).
|
|
Verify they resolve before continuing. Leave the old domain's records in place for now.
|
|
2. Discord developer portal → OAuth2 → add redirect `https://auth.NEW/source/oauth/callback/discord/` (keep the old one until step 9).
|
|
3. Server, between streams: `./configure.py --full` → new main hostname; the eight sub-hostnames default to the new
|
|
base (Enter); bare domain; `y`. Then `docker compose restart mediamtx` (webrtcAdditionalHosts changed).
|
|
All sites answer on the new names within a minute (certificates).
|
|
4. Authentik (log in at the NEW auth host with akadmin — Discord login is broken until step 5 is done):
|
|
- Outposts → Embedded Outpost → `authentik_host: https://auth.NEW`
|
|
- Providers → `Vanguard sites` → authentication URL `https://auth.NEW`, **cookie domain `NEW`**
|
|
- Providers → `Jellyfin` → redirect `https://watch.NEW/sso/OID/redirect/authentik`
|
|
- Providers → `Gitea` → redirect `https://git.NEW/user/oauth2/authentik/callback`
|
|
5. Private window: `https://auth.NEW/` → Discord login works (the redirect from step 2 is used).
|
|
6. Jellyfin: SSO plugin OID endpoint `https://auth.NEW/application/o/jellyfin/`; Branding disclaimer form action
|
|
`https://watch.NEW/sso/OID/start/authentik`; Vanguard plugin Public URL + Authentik URL. Test the SSO start URL.
|
|
7. Gitea: auth source discovery URL `https://auth.NEW/application/o/gitea/.well-known/openid-configuration`;
|
|
`./registerGiteaRunner.sh`; server: `cd ~/vanguard-stream && git remote set-url origin ssh://git@git.NEW:2222/techy/Media-Server-Setup.git`
|
|
and edit `~/.ssh/config.vanguard` (Host line); dev box: `git remote set-url origin …`. Test `sudo vanguard-deploy pull`.
|
|
8. Repo defaults: `switchToClone.sh` (REPO_SSH), `deployLive.sh` (HOST) — commit, push, pull.
|
|
9. Streamers: re-add the dock at `https://live.NEW/dock/`, re-save Settings, "Add band + clock source" again.
|
|
Members: `https://HOST2/`; Jellyfin apps → new server address. Remove the old Discord redirect and the old DNS.
|
|
|
|
## C. Splitting the single main host into media / files / clips / sync (done 2026-11-01)
|
|
|
|
Before: one main host (`ovh1.BASE`) served copyparty at `/`, `/about/`, `/clips/`, `/sync/`, `/dock/`, `/dump`, `/time`.
|
|
After: `media.BASE` = gateway at `/`; `files.BASE` = copyparty; `clips.BASE`; `sync.BASE`; `live.BASE` gains `/dock/`,
|
|
`/dock/clock/`, `/dump`, `/me`, `/time`, `/whoami`. `/time` is only on `live` because the two pages that fetch it
|
|
(the clock source and Go Live) are same-origin there. Authentik needs nothing: the domain-level provider covers every
|
|
name under BASE, the outpost host (`auth.`) is unchanged.
|
|
|
|
1. DNS: CNAMEs `media`, `files`, `clips`, `sync` → the box (keep `ovh1` for ssh; it is no longer a web host).
|
|
2. Dev box: pull/upload the repo (`configure.py`, `about/`, `addCommunityMediaServer.sh`, docs).
|
|
3. Server, between streams: `./configure.py --full` → main hostname `media.BASE`; Enter for the sub-hostnames
|
|
(defaults `files.`, `clips.`, `sync.`, …); bare domain redirect → `https://media.BASE/`; `y`.
|
|
Then `docker compose restart mediamtx` (webrtcAdditionalHosts is now `media.`) and `./deployLive.sh` (portal
|
|
build picks up nothing new, but confirms `/srv/live` is served on `live.`).
|
|
4. Streamers: OBS → Custom Browser Docks → replace the dock URL with `https://live.BASE/dock/`; dock Settings →
|
|
save; Timecode band → "Add band + clock source" again (the clock browser source URL moved).
|
|
5. Discord: re-pin `https://media.BASE/` (members), `https://clips.BASE/` (gamers), `https://files.BASE/` (editors).
|
|
6. Old `ovh1` bookmarks stop working (no Caddy block, TLS fails) — point people at the gateway.
|
|
|
|
## D. Adding a NEW host
|
|
|
|
**`./configure.py --apply` cannot do this, and will not complain.** It is stateless by design: it reads the
|
|
hostnames back out of the `Caddyfile` (`# vanguard:<role>` markers), so a role that is not in there yet has no
|
|
value to write and the site is simply left out. The containers come up, Caddy reloads, and the new name has no
|
|
site block and therefore no certificate — which presents as an SSL handshake error, not as an error from the
|
|
apply. This cost an hour on 2026-11-03 when `diag.` was added.
|
|
|
|
Introduce a new host with **`--full`** (asks for every hostname, defaults from the current config) or with
|
|
**`--hosts`**, which is the non-interactive form and takes them positionally:
|
|
|
|
./configure.py --hosts AUTH WATCH GIT BOT LIVE FILES SYNC CLIPS DIAG # "" leaves one unset
|
|
|
|
After that, `--apply` maintains it like any other host, because the marker is now in the file.
|
|
|
|
1. DNS: `CNAME` (or `A`) for the new name → the box; check it resolves before continuing.
|
|
2. Add the role to `configure.py`: a `write_caddy` block, a `<ROLE>_REQUIRE_GROUP` default in `write_env`,
|
|
the prompt in `full()`, the positional in `--hosts`, and the line in `show()`.
|
|
3. `./configure.py --hosts …` with every hostname including the new one.
|
|
4. Verify the marker landed: `grep -c "vanguard:<role>" Caddyfile` → 1. Then `curl -sI https://NEW/` → 302.
|
|
5. Add it to `addCommunityMediaServer.sh` so a rebuild asks for it too.
|
|
|
|
## Checklist after any change
|
|
dev$ for h in HOST files.BASE clips.BASE sync.BASE live.BASE diag.BASE auth.BASE watch.BASE git.BASE bot.BASE; do printf '%-26s ' $h; curl -s -o /dev/null -m 10 -w '%{http_code}\n' https://$h/; done
|
|
https://HOST/whoami → your identity (gate works on the new name)
|
|
https://watch.BASE/sso/OID/start/authentik → Jellyfin SSO round trip
|
|
https://git.BASE/user/login → "Sign in with authentik" round trip
|
|
dock → Go Live → journalctl -u dumpd | grep mtx-auth → allow publish
|
|
live.BASE → a window appears for the test stream, chip "webrtc"
|