124 lines
9.4 KiB
Markdown
124 lines
9.4 KiB
Markdown
# Fresh install — from an empty OVH box to a working stack with the deploy pipeline
|
||
|
||
Everything in order. Scripted steps are commands; manual steps are click lists. `HOST` = your main hostname
|
||
(ours: `ovh1.dumpstervigilantes.rip`), `BASE` = the parent domain. Detailed background for each part is in
|
||
README.md (section numbers given).
|
||
|
||
## 0. Before touching the server
|
||
- DNS: `A` record for `HOST` → the server IP; `CNAME`s `auth`, `watch`, `git`, `bot`, `live` → `HOST`.
|
||
Optional: the bare domain `A` → server IP (it redirects to the watch site or `/about/`).
|
||
- Discord developer portal → New Application (one app serves Authentik login, the Jellyfin plugin's bot and the
|
||
Discord bot):
|
||
- OAuth2 → Redirects: `https://auth.BASE/source/oauth/callback/discord/` (the last segment is the Authentik
|
||
source slug — keep them identical). Copy Client ID + Client Secret.
|
||
- Bot → Reset Token (copy it); enable **Server Members** intent; OAuth2 URL generator: scope `bot`, permissions
|
||
View Channels + Send Messages + Embed Links + Attach Files → invite it to the server.
|
||
- Discord → User Settings → Advanced → Developer Mode on; right-click the server → Copy Server ID; Server
|
||
Settings → Roles → Copy Role ID for each role you will map to a group.
|
||
- If this is a **rebuild**, have the backups ready: `.env`, `/srv/appdata`, `/srv/media`, `/etc/vanguard/clip-quotas.json`.
|
||
Restoring `.env` + `/srv/appdata` makes sections 5–7 unnecessary (that state lives there).
|
||
|
||
## 1. OS (README §1)
|
||
OVH manager → Reinstall → Debian 13, custom partitioning, distribution kernel. RAID 1:
|
||
`/boot` 1 GB ext4 · `/` 250 GB ext4 · swap 8 GB per disk · `/srv` rest xfs. Add your SSH key. You get the `debian` user with sudo.
|
||
|
||
## 2. Code onto the box
|
||
Fresh box has no deploy key yet, so copy the repo in:
|
||
|
||
scp -r vanguard-stream debian@HOST:~/ # from a machine that has the repo (or git clone over https with a token)
|
||
|
||
## 3. Host install (README §2, §4)
|
||
|
||
ssh debian@HOST
|
||
cd ~/vanguard-stream && sudo bash install.sh
|
||
|
||
Packages, Docker, timezone (Eastern), uid 1000, `/srv` folders, host scripts and timers, sysctl, live-portal
|
||
build, **firewall** (keep this session open; test a new ssh in a second terminal). Log out and back in once (docker group).
|
||
|
||
## 4. Configure + start (README §3)
|
||
|
||
cd ~/vanguard-stream && ./configure.py --full
|
||
|
||
Asks: main hostname; `auth`/`watch`/`git`/`bot`/`live` hostnames (defaults); bare domain (optional) and where it
|
||
redirects; Discord bot token + server ID (optional now, needed for the plugin feed); "is live" webhook (optional).
|
||
Generates `.env` with every secret, the configs, starts all containers, waits, then runs the post-start fixups
|
||
(Syncthing GUI auth off, Gitea admin user, Jellyfin plugin). `./configure.py --show` prints every credential
|
||
you will need below (akadmin password, Gitea admin, MariaDB, bot DB).
|
||
|
||
Check: `docker compose ps` → all `Up`; `https://auth.BASE/`, `https://watch.BASE/`, `https://git.BASE/`,
|
||
`https://HOST/` answer with certificates (Caddy fetches them itself, give it a minute).
|
||
|
||
## 5. Authentik (README §5c, §5g) — manual, ~20 minutes
|
||
Log in at `https://auth.BASE/` as `akadmin` with `AUTHENTIK_BOOTSTRAP_PASSWORD` from `.env` (change it: user menu → settings).
|
||
1. Directory → Federation & Social login → Create → **Discord OAuth Source**: name `Discord`, slug `discord`,
|
||
consumer key/secret = the Discord app's Client ID/Secret, scopes `guilds guilds.members.read`, user matching
|
||
"link on unique identifier", flows default-source-authentication / default-source-enrollment.
|
||
2. Flows & Stages → Stages → `default-authentication-identification` → Sources: add Discord, tick "Show sources'
|
||
labels". (No Discord button appears until this is done.)
|
||
3. Flows & Stages → Stages → `default-source-enrollment-write` → User type **Internal**, user path `users`.
|
||
4. Directory → Groups: `streamers`, `editors`, `media-admins`, `admins`, `bot-users`, `git-users`, `git-admins`.
|
||
Nesting: `admins` parent `authentik Admins`; `authentik Admins` parent `git-admins` (admins inherit everything).
|
||
5. Customization → Policies → Create Expression Policy ×2 from the repo:
|
||
`discord-guild-member` (`authentik/discord-guild-policy.py`, set your server ID) and
|
||
`discord-roles-to-groups` (`authentik/discord-roles-to-groups.py`, set server ID + role-id→group table).
|
||
Tick "Execution logging" on both.
|
||
6. Flows & Stages → Flows → `default-source-enrollment` and `default-source-authentication`: bind both policies
|
||
(guild first), **Policy engine mode: all**.
|
||
7. Applications → Outposts → edit "authentik Embedded Outpost" → config `authentik_host: https://auth.BASE`.
|
||
8. Applications → Create with provider → `Vanguard sites`: **Proxy Provider**, implicit consent,
|
||
**Forward auth (domain level)**, authentication URL `https://auth.BASE`, cookie domain `BASE`,
|
||
invalidation flow `default-provider-invalidation-flow`. Edit the Embedded Outpost → add the application.
|
||
9. Applications → Create with provider → `Jellyfin`: OAuth2/OpenID, implicit consent, Confidential, redirect
|
||
`https://watch.BASE/sso/OID/redirect/authentik`, default signing cert, scopes `openid email profile`. Keep ID + secret.
|
||
10. Applications → Create with provider → `Gitea` (slug `gitea`): OAuth2/OpenID, same settings, redirect
|
||
`https://git.BASE/user/oauth2/authentik/callback`. Bind groups `git-users` + `git-admins` on the application.
|
||
11. Test in a private window: `https://auth.BASE/` → Discord → your user exists and is Internal. Add yourself to
|
||
`admins` (and `streamers`, `media-admins` as needed) or give yourself the Discord roles; sign out and back in.
|
||
`https://HOST/whoami` shows your groups.
|
||
|
||
## 6. Jellyfin (README §5c) — manual, ~10 minutes
|
||
`https://watch.BASE/` → wizard: admin user; libraries `/media/streams` and `/media/clips` as **Shows** with
|
||
metadata downloaders = only "Vanguard Metadata" (Series/Season/Episode), image fetchers Vanguard Metadata
|
||
(Series) + Screen Grabber (Episode), real-time monitoring on; `/media/finals` as Home Videos, fetchers off.
|
||
Dashboard → Playback → Transcoding: hardware acceleration none. Dashboard → Plugins: Vanguard Metadata is
|
||
installed → its page: Discord bot token + server ID, feed channel ID, public URL `https://watch.BASE`.
|
||
Plugins → Repositories → add `https://raw.githubusercontent.com/9p4/jellyfin-plugin-sso/manifest-release/manifest.json`
|
||
→ Catalog → SSO Authentication → install → `docker compose restart jellyfin`. Plugins → SSO-Auth → add OID provider
|
||
`authentik`: endpoint `https://auth.BASE/application/o/jellyfin/`, client ID/secret, roles claim `groups`,
|
||
admin roles `admins`, enabled folders = the 3 libraries, Scheme Override `https`, Port Override EMPTY, Save.
|
||
Dashboard → General → Branding: paste `jellyfin/branding-disclaimer.html` (set the hostname) and `jellyfin/branding.css`.
|
||
Test: `https://watch.BASE/sso/OID/start/authentik`. Scheduled Tasks → run "Vanguard: snapshot Discord events",
|
||
"roll seasons", "enforce playback policy" once.
|
||
|
||
## 7. Gitea (README §5e) — manual, ~10 minutes
|
||
Log in at `https://git.BASE/` as `GITEA_ADMIN_USER` / `GITEA_ADMIN_PASSWORD` from `.env`.
|
||
1. Site Administration → Identity & Access → Authentication Sources → Add: OAuth2, name `authentik`, OpenID
|
||
Connect, client ID/secret from step 5.10, discovery URL
|
||
`https://auth.BASE/application/o/gitea/.well-known/openid-configuration`, Skip local 2FA, group claim
|
||
`groups`, administrator group `git-admins`.
|
||
2. Create the repo `techy/Media-Server-Setup` (empty) and push this repo to it from your dev box:
|
||
`git remote add origin ssh://git@git.BASE:2222/techy/Media-Server-Setup.git && git push -u origin main`
|
||
(your SSH key under Settings → SSH keys).
|
||
3. Runner: `./registerGiteaRunner.sh` on the server → Site Administration → Actions → Runners shows it idle.
|
||
|
||
## 8. Pipeline (README "Deployment")
|
||
1. On the server: `./switchToClone.sh key` → add the printed key as a read-only **Deploy Key** on the repo
|
||
→ `./switchToClone.sh clone` (keeps `.env`, generated configs, plugin zips) → `./configure.py --apply`.
|
||
2. Gitea → repo → Settings → Webhooks → Add → Gitea: URL `http://<docker gateway>:8081/deploy`
|
||
(`docker network inspect vanguard-stream_default -f '{{(index .IPAM.Config 0).Gateway}}'`), secret =
|
||
`DEPLOY_WEBHOOK_SECRET` from `.env`, push events, branch `main`. Test delivery → 202 "auto-deploy disabled".
|
||
3. Manual deploys from now on: push, then `sudo vanguard-deploy pull` on the server. When trusted:
|
||
`DEPLOY_AUTO=1` in `.env` → `./configure.py --apply`; CI: `git mv .gitea/draft-workflows/ci.yml .gitea/workflows/ci.yml`.
|
||
|
||
## 9. Streamers, gamers, editors (README §5, §5a, §6)
|
||
- Streamers: OBS → WebSocket server on; Docks → Custom Browser Dock `https://HOST/dock/` → Discord login →
|
||
Settings: OBS WebSocket password; Timecode band → "Add band + clock source" (not streaming). Then title → Go Live.
|
||
- Gamers: `https://HOST/clips/` → paste their Syncthing Device ID → accept device + folder on their PC (Send Only).
|
||
Syncthing UI (`https://HOST/sync/`, media-admins): Actions → Settings → Connections → incoming rate limit 12500 KiB/s.
|
||
- Everyone: `https://HOST/about/`.
|
||
|
||
## 10. Afterwards
|
||
- Pin `AUTHENTIK_TAG` in `.env` to the running version. Rotate any secret that was ever pasted into chat.
|
||
- Back up `.env`, `/srv/appdata`, `/srv/media` (home archive puller: README §7).
|
||
- `STATUS.md` = what runs and what is unfinished; `check.sh` before any commit.
|