5.6 KiB
Tower-side transcribe worker — deploy notes
Target host: EndeavourOS tower (Arch base), RTX 3080. Runs the
second-brain transcribe-worker daemon under systemd. Reaches the
petalbrain Postgres over WireGuard at db.wg.herbylab.dev:5432.
This worker only does pull + transcribe for VIDEO sources. Articles and all extraction/embedding stay on the dev side.
1. System packages
# Build / runtime tooling.
sudo pacman -S --needed base-devel git ffmpeg python uv
# NVIDIA — driver, CUDA, cuDNN. faster-whisper / CTranslate2 needs cuDNN
# at runtime; missing-symbol errors at first transcribe are usually a
# cuDNN install gap. Use whichever driver/cuda channel matches your
# Arch derivative; on stock EndeavourOS the AUR/community packages work:
sudo pacman -S --needed nvidia nvidia-utils cuda cudnn
# Confirm the GPU is visible.
nvidia-smi
yt-dlp comes in via the Python project (uv sync step below), so the
distro yt-dlp is optional. Leave it off the host unless you want it on
your CLI PATH.
2. Project checkout + venv
sudo mkdir -p /opt/projects/homelab
sudo chown trucktrav:trucktrav /opt/projects/homelab
cd /opt/projects/homelab
git clone gitea-pbs-trucktrav:petal-power/second-brain.git
cd second-brain
# Install the runtime deps + the `tower` extra (faster-whisper / CTranslate2).
# The dev side does NOT install --extra tower; only the tower needs it.
uv sync --extra tower
faster-whisper will pull a couple hundred MB of CUDA wheels. First-run
model download (~3 GB for large-v3) lands under ~/.cache/huggingface/
the first time the worker transcribes; pre-warm it if you want:
uv run python -c "from faster_whisper import WhisperModel; WhisperModel('large-v3', device='cuda', compute_type='float16')"
3. WireGuard
The worker assumes the tunnel is already configured and that
wg-quick@wg-lan.service brings it up at boot. Topology:
| Peer | WG IP |
|---|---|
| hub (herbydev) | 10.99.0.1 |
| tower | 10.99.0.3 |
db.wg.herbylab.dev resolves to 10.99.0.1. Confirm connectivity from
the tower:
ping -c2 db.wg.herbylab.dev
nc -vz db.wg.herbylab.dev 5432
Tunnel setup itself is out of scope for this README — that's configured separately as part of Travis's infra.
4. EnvironmentFile
sudo install -m 0600 -o root -g root \
deploy/tower/second-brain-transcribe.env.example \
/etc/default/second-brain-transcribe
sudo $EDITOR /etc/default/second-brain-transcribe # paste the lovebug password
The lovebug password lives in /opt/backups/postgres-consolidation/credentials.env
on the dev host. Copy it across through whatever channel you trust
(personal Bitwarden, scp over WG, etc.) — do not commit it.
5. systemd unit
sudo install -m 0644 deploy/tower/second-brain-transcribe.service \
/etc/systemd/system/second-brain-transcribe.service
sudo systemctl daemon-reload
sudo systemctl enable --now second-brain-transcribe.service
The unit declares After= + Wants= on wg-quick@wg-lan.service, so
the worker starts after the tunnel comes up at boot. If the tunnel
disappears mid-run the worker keeps polling and logs DB-unreachable
warnings; it doesn't crash-loop.
Day-to-day commands
# What's it doing right now?
systemctl status second-brain-transcribe.service
journalctl -u second-brain-transcribe.service -f
# Pause without uninstalling — toggle from the dashboard at
# https://brain.herbylab.dev/settings (or whichever host).
# Or stop the unit:
sudo systemctl stop second-brain-transcribe.service
# Pick up code updates:
cd /opt/projects/homelab/second-brain
git pull
uv sync --extra tower
sudo systemctl restart second-brain-transcribe.service
6. Validation — what to confirm once WG is live
These can only be verified on the tower itself:
- WG reachability.
nc -vz db.wg.herbylab.dev 5432succeeds. - DB auth.
uv run alembic currentreturns the latest revision id. - GPU large-v3 path. With a short test video queued via
second-brain add <url>on the dev side, runuv run second-brain transcribe-worker --onceon the tower. Watchjournalctl— first run pulls the model from HuggingFace (slow), subsequent runs are fast. The source row should end up inTRANSCRIBEDwithtranscript_textpopulated andclaimed_bycleared. - Race safety smoke test. Run two
--onceinvocations in parallel against an empty queue, then with one PENDING video. Only one should claim it; the other should see no work. - Settings round-trip. Flip
transcription_enabledoff on the dashboard; within one poll cycle (~15s) the worker logstranscription_enabled=false — sleeping. Flip back on, the next PENDING video gets picked up.
Follow-ups (out of scope for this round)
- Media + subtitles directory currently lives on the tower's local
disk (under
~/.local/share/second-brain/). Move to a NAS mount later so the dev side can compile/inspect the SRTs without a cross-machine fetch. Open question on the right mount point + cred flow — see the project'spostgres-migration-planning.mdfor the related vault-location decision Travis still owes. - Tower-side observability. No metrics endpoint yet; journald is
the only signal. A
/api/worker-statusheartbeat the dashboard could read would be nice once two workers exist. - GPU concurrency > 1.
transcription_max_concurrent_gpu_jobsexists inpipeline_settingsbut the worker only runs one job at a time. Scale-out would need a per-job semaphore (or just running N worker instances with distinctSECOND_BRAIN_WORKER_IDs).