107 lines
4.9 KiB
Markdown
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.
|