Compare commits

..

2 Commits

Author SHA1 Message Date
357bb61b65 MediaMTX: write webrtcAdditionalHosts into the generated config (env-based value left it empty and MediaMTX refused to start)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 00:48:27 -05:00
b2869c3740 Generated configs out of the repo: *.example.* templates only; configure.py refuses to apply over CHANGEME placeholders
A deploy copied mediamtx.yml (template) over the server's generated file and the next apply
wiped all streamers. Generated files are now gitignored so scp -r cannot clobber them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 00:32:30 -05:00
8 changed files with 27 additions and 9 deletions

5
.gitignore vendored
View File

@@ -5,3 +5,8 @@ __pycache__/
bot/app/__pycache__/ bot/app/__pycache__/
*.pyc *.pyc
streamers.json streamers.json
# generated by configure.py on the server — never commit or scp these
mediamtx.yml
copyparty.conf
Caddyfile
dump-users.txt

View File

@@ -35,6 +35,12 @@ works from ~/vanguard-stream without sudo.
## 3. Configure (domain, admin, streamers, editors) ## 3. Configure (domain, admin, streamers, editors)
> `mediamtx.yml`, `copyparty.conf`, `Caddyfile`, `dump-users.txt` and `.env` are **generated on the server**
> by `configure.py` and gitignored. The `*.example.*` files in the repo are reference only. **Never copy them
> to the server**: doing so once replaced the live streamer passwords with `CHANGEME` and the next apply
> wiped the streamers. To update the server, copy scripts (`configure.py`, `bin/`, `docker-compose.yml`, …)
> and re-run `./configure.py`.
cd ~/vanguard-stream cd ~/vanguard-stream
./configure.py --full # first time: asks everything, then applies ./configure.py --full # first time: asks everything, then applies
./configure.py # later: add/remove/reset streamers and editors, then apply ./configure.py # later: add/remove/reset streamers and editors, then apply

View File

@@ -6,12 +6,13 @@
# The Authentik groups must already exist (Directory -> Groups). Role IDs: Discord Developer Mode -> # The Authentik groups must already exist (Directory -> Groups). Role IDs: Discord Developer Mode ->
# Server Settings -> Roles -> right-click a role -> Copy Role ID. # Server Settings -> Roles -> right-click a role -> Copy Role ID.
GUILD_ID = "000000000000000000" # <- your Discord server ID GUILD_ID = "1387203044084551690" # <- your Discord server ID
ROLE_TO_GROUP = { # <- Discord role id : Authentik group name ROLE_TO_GROUP = { # <- Discord role id : Authentik group name
"111111111111111111": "bot-users", "1387239222070612110": "bot-users",
"222222222222222222": "streamers", "1515901670943490129": "bot-users",
"333333333333333333": "editors", # "222222222222222222": "streamers",
"444444444444444444": "admins", # "333333333333333333": "editors",
# "444444444444444444": "admins",
} }
from authentik.core.models import Group from authentik.core.models import Group

View File

@@ -8,6 +8,8 @@
used by addCommunityMediaServer.sh) used by addCommunityMediaServer.sh)
Reads : Caddyfile (hostnames), mediamtx.yml (streamers), copyparty.conf (editors + admin), .env Reads : Caddyfile (hostnames), mediamtx.yml (streamers), copyparty.conf (editors + admin), .env
(these are GENERATED on the server and gitignored; *.example.* in the repo are reference only —
never scp them over the live ones: that is how streamers got wiped once)
Writes : Caddyfile, mediamtx.yml, copyparty.conf, dump-users.txt -> /etc/vanguard, .env (generated secrets + Writes : Caddyfile, mediamtx.yml, copyparty.conf, dump-users.txt -> /etc/vanguard, .env (generated secrets +
Discord bot token/guild), folders, restarts Discord bot token/guild), folders, restarts
Set VG_DRY=1 to write files only (no sudo / docker / folders). Set VG_DRY=1 to write files only (no sudo / docker / folders).
@@ -265,7 +267,7 @@ def write_env(watch_host, discord_token=None, discord_guild=None, git_host="", b
Path(".env").write_text("".join(f"{k}={v}\n" for k, v in env.items())) Path(".env").write_text("".join(f"{k}={v}\n" for k, v in env.items()))
os.chmod(".env", 0o600) os.chmod(".env", 0o600)
def write_mediamtx(streamers): def write_mediamtx(streamers, public_host=""):
users = "".join(f""" - user: {u} users = "".join(f""" - user: {u}
pass: {p} pass: {p}
permissions: permissions:
@@ -292,7 +294,7 @@ webrtcAddress: :8889
webrtcLocalUDPAddress: :8189 webrtcLocalUDPAddress: :8189
webrtcLocalTCPAddress: :8189 webrtcLocalTCPAddress: :8189
webrtcIPsFromInterfaces: no webrtcIPsFromInterfaces: no
# webrtcAdditionalHosts is set via env MTX_WEBRTCADDITIONALHOSTS (= the public hostname) in docker-compose.yml webrtcAdditionalHosts: [{public_host or "127.0.0.1"}] # public hostname browsers can reach for ICE (written by configure.py)
rtmp: yes rtmp: yes
rtmpAddress: :1935 rtmpAddress: :1935
@@ -398,9 +400,13 @@ def run(cmd, **kw):
return subprocess.call(cmd, **kw) return subprocess.call(cmd, **kw)
def apply(domain, admin_pw, streamers, editors, auth_host="", watch_host="", discord_token=None, discord_guild=None, git_host="", bot_host="", live_host="", live_webhook=None): def apply(domain, admin_pw, streamers, editors, auth_host="", watch_host="", discord_token=None, discord_guild=None, git_host="", bot_host="", live_host="", live_webhook=None):
if not streamers and Path("mediamtx.yml").exists() and "CHANGEME" in Path("mediamtx.yml").read_text():
print("\n!! mediamtx.yml contains CHANGEME placeholders — it looks like the repo template was copied over the")
print(" generated config. Applying now would leave NO streamers (OBS ingest and the dump button stop working).")
if not yes(" continue anyway?", False): print("aborted; add streamers first ([s] in the menu)"); sys.exit(1)
print("\n== writing configs") print("\n== writing configs")
write_env(watch_host, discord_token, discord_guild, git_host, bot_host, live_host, domain, live_webhook) write_env(watch_host, discord_token, discord_guild, git_host, bot_host, live_host, domain, live_webhook)
write_caddy(domain, auth_host, watch_host, git_host, bot_host, live_host); write_mediamtx(streamers); write_copyparty(admin_pw, editors); write_dump_users(admin_pw, streamers); write_streamers_json(streamers) write_caddy(domain, auth_host, watch_host, git_host, bot_host, live_host); write_mediamtx(streamers, domain); write_copyparty(admin_pw, editors); write_dump_users(admin_pw, streamers); write_streamers_json(streamers)
run(["sudo", "install", "-d", "-o", os.environ.get("SUDO_USER") or os.environ.get("USER") or "debian", "/srv/live"]) run(["sudo", "install", "-d", "-o", os.environ.get("SUDO_USER") or os.environ.get("USER") or "debian", "/srv/live"])
print("== app data folders") print("== app data folders")
run(["sudo", "install", "-d", "-o", "1000", "-g", "1000", "/srv/appdata/jellyfin/config", "/srv/appdata/jellyfin/cache", run(["sudo", "install", "-d", "-o", "1000", "-g", "1000", "/srv/appdata/jellyfin/config", "/srv/appdata/jellyfin/cache",

View File

@@ -17,7 +17,7 @@ webrtcAddress: :8889
webrtcLocalUDPAddress: :8189 webrtcLocalUDPAddress: :8189
webrtcLocalTCPAddress: :8189 webrtcLocalTCPAddress: :8189
webrtcIPsFromInterfaces: no webrtcIPsFromInterfaces: no
# webrtcAdditionalHosts is set via env MTX_WEBRTCADDITIONALHOSTS (= the public hostname) in docker-compose.yml webrtcAdditionalHosts: [media.example.com] # public hostname browsers can reach for ICE (configure.py fills this)
rtmp: yes rtmp: yes
rtmpAddress: :1935 rtmpAddress: :1935