Files

107 lines
4.9 KiB
Markdown

# mediabox-bootstrap
Everything the media box (`10.0.1.20`, hostname `mediabox`) needs after the
Ubuntu 24.04 autoinstall has laid down the base system.
The autoinstall USB is deliberately thin: sshd, a key, DHCP, Docker CE, `/srv`,
and a first-boot unit that clones **this** repo and runs `bootstrap.sh`. That
split exists so the interesting parts stay in git, reviewable and re-runnable,
instead of frozen onto a USB stick that nobody can diff.
Full context, decisions and the phase-by-phase runbook live in the workspace repo
at `projects/mediabox-linux/`.
---
## Layout
```
bootstrap.sh orchestrator — runs the stages, fails soft
scripts/
00-preflight.sh asserts hardware/BIOS state. Changes nothing.
10-secrets.sh idempotent ADD-ONLY seeder for /srv/secrets/stacks.env
20-cifs.sh the 6 NAS mounts, named exactly as the DB stores them
30-nvidia.sh NVIDIA 580 + container toolkit
40-shell-mcp.sh builds and starts the native shell-mcp
50-plex.sh Plex against the MIGRATED data dir. No claim token.
60-media-relocate.sh optional, post-soak: move the 337 GB preview cache
migration/ remap.sql, migrate-db.sh, gen-preferences.ps1, README.md
shell-mcp/ amd64 build of the MCP server (server.py, Dockerfile,
docker-compose.yml, pinned requirements.txt)
plex/docker-compose.yml Plex service definition
secrets/stacks.env.example placeholder master env
```
## Running it
```bash
sudo /srv/mediabox-bootstrap/bootstrap.sh # all stages
sudo /srv/mediabox-bootstrap/scripts/20-cifs.sh # one stage
sudo /srv/mediabox-bootstrap/scripts/20-cifs.sh --verify
```
Every stage is idempotent. Re-running is the normal way to use this, not an
emergency measure.
---
## Design rules
**Nothing may leave the box unreachable.** `sshd` is up before any of this runs
and no stage may compromise that. `bootstrap.sh` catches stage failures and
continues; the systemd unit declares `SuccessExitStatus=0 1` so a bad stage can
never wedge boot. There is no keyboard attached to this machine.
**Secrets never ride on removable media.** The CIFS credentials file is created
*empty* by the autoinstall and filled in post-boot over the MCP.
**No claim token, ever.** The migration preserves `MachineIdentifier`, so this
is the existing server rather than a new one. Claiming would discard shared
users and every client registration.
**One secrets file per host.** This box has its own `/srv/secrets/stacks.env`,
using the same `[OPERATOR]` / `[VALUES]` / `[MANIFEST]` tiering as arrsstack, but
it is not shared or mounted from anywhere. Canonical copies live in Vaultwarden.
**The seeder only ever adds.** `10-secrets.sh` will never overwrite an existing
key, change its value, or move it. If `KEY=` is present it is skipped entirely.
Verified against a pre-populated file: existing values, unrelated keys, the
operator tier and existing manifest lines all survive byte-for-byte, and a second
run is a no-op.
---
## Notes that will save you an evening
**shell-mcp was originally built on arm64.** It builds clean on amd64 — the whole
Python dependency tree resolves to prebuilt manylinux x86_64 wheels, so no
compiler is needed. Two real changes were required:
- **Dependencies are now pinned.** The original installed `mcp starlette uvicorn`
unpinned. `starlette` has since gone 1.x. Unpinned installs are tolerable in a
hand-run build and dangerous inside a first-boot script.
- **Port and description.** It listens on 8103 (not 8085) so NPM proxy host 42 can
simply be repointed, and the tool description says *media box*, not *arrsstack* —
otherwise every session starts with the wrong idea of which host it is touching.
**The GTX 1070 is Pascal, and NVIDIA branch 580 is the last one that supports it.**
There will be no 590 for this card. `30-nvidia.sh` installs 580 explicitly and pins
against newer branches. Never use `ubuntu-drivers autoinstall` here — it will
cheerfully install a branch that drops the card. And it must be the proprietary
module, not `-open`: the open kernel modules need Turing or newer.
**Secure Boot must stay off.** It is off today. A BIOS update resets ASUS defaults
and turns it back on, at which point the DKMS module needs interactive MOK
enrollment at a console this box does not have. `00-preflight.sh` checks for this.
**`nofail` on every CIFS mount is not optional.** Without it, an unreachable NAS
drops a headless box to an emergency shell waiting for a root password on a
keyboard that is not plugged in.
**`autoEmptyTrash` is the most dangerous default here.** The NAS account is
read-write. If a mount is missing when Plex scans, Plex sees an empty library and
will act on that. `50-plex.sh` disables it before any library is added.
**Plex's PUID/PGID must equal the CIFS `uid=`/`gid=`.** Both are `3000` (`media`).
If they ever drift, every file is permission-denied.