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>
12 KiB
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)
- DNS: add
CNAME video.BASE → HOST. Keep the old record until step 7. - 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 touchesmediamtx.yml; other hosts need no MediaMTX restart.) - Authentik: Applications → Providers →
Jellyfin→ Edit → redirect URI → the new host → Update. - Jellyfin: Dashboard → General → Branding → disclaimer form action → new host → Save. Dashboard → Plugins → Vanguard Metadata → Public URL → new host → Save.
- If the label changed (
watch→video), editabout/index.html(sub('watch')→sub('video')) — commit, push,sudo vanguard-deploy pull. (.env APEX_REDIRECTtoo if the bare domain pointed at it:./configure.py --full.) - Private window:
https://video.BASE/→ Discord → in. The gatewayhttps://HOST/links to the new name. - 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_hostand 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.htmlif the label changed. Everyone re-logs in. - git: Authentik Gitea provider redirect;
./registerGiteaRunner.sh; server clone remote +~/.ssh/config.vanguard; dev remote;switchToClone.shdefault. - live, bot: only the compose env (automatic) and
about/index.htmlif the label changed. - main (HOST):
mediamtx.ymlchanges →docker compose restart mediamtxbetween 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.shdefault 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).
- DNS on the new domain:
A HOST2 → IP, CNAMEsfiles,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. - Discord developer portal → OAuth2 → add redirect
https://auth.NEW/source/oauth/callback/discord/(keep the old one until step 9). - Server, between streams:
./configure.py --full→ new main hostname; the eight sub-hostnames default to the new base (Enter); bare domain;y. Thendocker compose restart mediamtx(webrtcAdditionalHosts changed). All sites answer on the new names within a minute (certificates). - 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 URLhttps://auth.NEW, cookie domainNEW - Providers →
Jellyfin→ redirecthttps://watch.NEW/sso/OID/redirect/authentik - Providers →
Gitea→ redirecthttps://git.NEW/user/oauth2/authentik/callback
- Outposts → Embedded Outpost →
- Private window:
https://auth.NEW/→ Discord login works (the redirect from step 2 is used). - Jellyfin: SSO plugin OID endpoint
https://auth.NEW/application/o/jellyfin/; Branding disclaimer form actionhttps://watch.NEW/sso/OID/start/authentik; Vanguard plugin Public URL + Authentik URL. Test the SSO start URL. - 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.gitand edit~/.ssh/config.vanguard(Host line); dev box:git remote set-url origin …. Testsudo vanguard-deploy pull. - Repo defaults:
switchToClone.sh(REPO_SSH),deployLive.sh(HOST) — commit, push, pull. - 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.
- DNS: CNAMEs
media,files,clips,sync→ the box (keepovh1for ssh; it is no longer a web host). - Dev box: pull/upload the repo (
configure.py,about/,addCommunityMediaServer.sh, docs). - Server, between streams:
./configure.py --full→ main hostnamemedia.BASE; Enter for the sub-hostnames (defaultsfiles.,clips.,sync., …); bare domain redirect →https://media.BASE/;y. Thendocker compose restart mediamtx(webrtcAdditionalHosts is nowmedia.) and./deployLive.sh(portal build picks up nothing new, but confirms/srv/liveis served onlive.). - 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). - Discord: re-pin
https://media.BASE/(members),https://clips.BASE/(gamers),https://files.BASE/(editors). - Old
ovh1bookmarks 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.
- DNS:
CNAME(orA) for the new name → the box; check it resolves before continuing. - Add the role to
configure.py: awrite_caddyblock, a<ROLE>_REQUIRE_GROUPdefault inwrite_env, the prompt infull(), the positional in--hosts, and the line inshow(). ./configure.py --hosts …with every hostname including the new one.- Verify the marker landed:
grep -c "vanguard:<role>" Caddyfile→ 1. Thencurl -sI https://NEW/→ 302. - Add it to
addCommunityMediaServer.shso 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"