Docs/apply note: MediaMTX does not hot-reload auth settings; restart between streams after auth changes
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -289,8 +289,9 @@ MediaMTX asks dumpd (`POST /mtx-auth` on 127.0.0.1:8081, reachable only from Doc
|
|||||||
connection. Reads/playback are allowed (viewers are gated by Caddy + Authentik). Publishing needs a token
|
connection. Reads/playback are allowed (viewers are gated by Caddy + Authentik). Publishing needs a token
|
||||||
minted by `GET /me/stream-token` behind Authentik for a member of `streamers`/`admins`/`media-admins`; dumpd
|
minted by `GET /me/stream-token` behind Authentik for a member of `streamers`/`admins`/`media-admins`; dumpd
|
||||||
checks the HMAC signature (`/etc/vanguard/stream-token.secret`, generated into `.env` as `STREAM_TOKEN_SECRET`),
|
checks the HMAC signature (`/etc/vanguard/stream-token.secret`, generated into `.env` as `STREAM_TOKEN_SECRET`),
|
||||||
the expiry, and that the path starts with that user's name. Changing this needs **no MediaMTX restart**:
|
the expiry, and that the path starts with that user's name. MediaMTX hot-reloads paths/recording settings
|
||||||
MediaMTX hot-reloads `mediamtx.yml`; `configure.py` reloads Caddy in place and only restarts copyparty.
|
but **not** the auth section: after changing auth, `docker compose restart mediamtx` between streams.
|
||||||
|
`configure.py` reloads Caddy in place and restarts only copyparty.
|
||||||
|
|
||||||
## Layout on the server
|
## Layout on the server
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ Source of truth: this repo, `techy/Media-Server-Setup` on the stack's own Gitea
|
|||||||
- Several videos inside one non-season folder = ONE Jellyfin episode with "versions". Streams are therefore published flat as `<Title>__<ts>.mp4` in the streamer's folder (plugin 0.1.3 parses the title from the name). Four or five helmet cams a night each get their own episode.
|
- Several videos inside one non-season folder = ONE Jellyfin episode with "versions". Streams are therefore published flat as `<Title>__<ts>.mp4` in the streamer's folder (plugin 0.1.3 parses the title from the name). Four or five helmet cams a night each get their own episode.
|
||||||
- The sweep's VFR check used a gawk-only function; Debian's mawk made it pass everything silently. Portable now.
|
- The sweep's VFR check used a gawk-only function; Debian's mawk made it pass everything silently. Portable now.
|
||||||
- A deploy block that is only half-run leaves old binaries in `/usr/local/bin`; `grep -c` the installed script before blaming logic.
|
- A deploy block that is only half-run leaves old binaries in `/usr/local/bin`; `grep -c` the installed script before blaming logic.
|
||||||
|
- MediaMTX hot-reloads `paths`/recording settings but NOT `authMethod`/auth settings: those need a container restart (between streams).
|
||||||
- MediaMTX stamps recording filenames in its container clock: without `TZ` it is UTC and the plugin reads names as Eastern (4 h off). `TZ=America/New_York` is set on the container.
|
- MediaMTX stamps recording filenames in its container clock: without `TZ` it is UTC and the plugin reads names as Eastern (4 h off). `TZ=America/New_York` is set on the container.
|
||||||
- MediaMTX 1.21 refuses to start without `webrtcAdditionalHosts` or `webrtcIPsFromInterfaces`; configure.py writes the public host in.
|
- MediaMTX 1.21 refuses to start without `webrtcAdditionalHosts` or `webrtcIPsFromInterfaces`; configure.py writes the public host in.
|
||||||
- Jellyfin honours provider-supplied season numbers on a Shows library (day seasons appeared). Next check: Monday 04:10 ET should fold them into a week season.
|
- Jellyfin honours provider-supplied season numbers on a Shows library (day seasons appeared). Next check: Monday 04:10 ET should fold them into a week season.
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ srtAddress: :8890
|
|||||||
# ---- auth -------------------------------------------------------------
|
# ---- auth -------------------------------------------------------------
|
||||||
# Publishing is authorised by dumpd (/mtx-auth) with short-lived tokens minted for Discord-authenticated
|
# Publishing is authorised by dumpd (/mtx-auth) with short-lived tokens minted for Discord-authenticated
|
||||||
# members of the streamers group. Reads are allowed; viewers are gated by Caddy + Authentik. No passwords.
|
# members of the streamers group. Reads are allowed; viewers are gated by Caddy + Authentik. No passwords.
|
||||||
# MediaMTX hot-reloads this file: changing auth needs no restart.
|
# NOTE: MediaMTX hot-reloads paths/recording settings but NOT the auth section — restart after auth changes.
|
||||||
authMethod: http
|
authMethod: http
|
||||||
authHTTPAddress: http://{auth_gw}:8081/mtx-auth
|
authHTTPAddress: http://{auth_gw}:8081/mtx-auth
|
||||||
authHTTPExclude:
|
authHTTPExclude:
|
||||||
@@ -469,7 +469,8 @@ def apply(domain, admin_pw, streamers, editors, auth_host="", watch_host="", dis
|
|||||||
run(dc + ["up", "-d", "--build"]) # recreates only services whose compose definition changed
|
run(dc + ["up", "-d", "--build"]) # recreates only services whose compose definition changed
|
||||||
run(dc + ["restart", "copyparty"]) # copyparty re-reads its config on start
|
run(dc + ["restart", "copyparty"]) # copyparty re-reads its config on start
|
||||||
run(dc + ["exec", "caddy", "caddy", "reload", "--config", "/etc/caddy/Caddyfile"]) # zero-downtime
|
run(dc + ["exec", "caddy", "caddy", "reload", "--config", "/etc/caddy/Caddyfile"]) # zero-downtime
|
||||||
print(" (mediamtx hot-reloads mediamtx.yml itself — live streams are not interrupted)")
|
print(" mediamtx: hot-reloads most of mediamtx.yml, but NOT auth changes. If you changed auth settings, run")
|
||||||
|
print(" docker compose restart mediamtx between streams (cuts a live recording).")
|
||||||
|
|
||||||
def show(domain, admin_pw, streamers, editors, auth_host="", watch_host="", git_host="", bot_host="", live_host=""):
|
def show(domain, admin_pw, streamers, editors, auth_host="", watch_host="", git_host="", bot_host="", live_host=""):
|
||||||
print(f"\n== domain : {domain or '(not set)'}")
|
print(f"\n== domain : {domain or '(not set)'}")
|
||||||
|
|||||||
@@ -216,7 +216,13 @@ $("signout").onclick = async e => {
|
|||||||
const auth = "https://" + location.hostname.replace(/^[^.]+\./, "auth.") + "/if/flow/default-invalidation-flow/?next=" + encodeURIComponent(location.origin + "/dock/");
|
const auth = "https://" + location.hostname.replace(/^[^.]+\./, "auth.") + "/if/flow/default-invalidation-flow/?next=" + encodeURIComponent(location.origin + "/dock/");
|
||||||
setTimeout(() => location.replace(auth), 400);
|
setTimeout(() => location.replace(auth), 400);
|
||||||
};
|
};
|
||||||
whoami(); renderPreview();
|
// On load: who am I, and mint a token right away so the preview and the manual section show real values.
|
||||||
|
(async () => {
|
||||||
|
await whoami();
|
||||||
|
try { await mint(); status("ready"); }
|
||||||
|
catch (e) { status(e.message, "bad"); $("m_tok").textContent = "— " + e.message; }
|
||||||
|
})();
|
||||||
|
renderPreview();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user