DocsMore
Running the hub on a Mac (launchd)
For a Mac that should run the hub all the time. It builds the single-file hub executable (web UI inside), installs it under one folder, runs it as a launchd service, and backs up its databases every night. Nothing here is specific to one site: a site's names, ports and paths live in an env file you keep outside the repository.
Deploy#
./deploy-dev.sh --dry-run # print every step, change nothing
./deploy-dev.sh # build, install, load the services, health-check
./deploy-dev.sh --restart-only
./deploy-dev.sh --rollback # put the previous binary back
deploy-prod.sh is the same script for a second instance (prod.env). Both call deploy/macos/hub-deploy.sh ENV.
Needs bun, curl and sqlite3 (the last two ship with macOS) on the Mac doing the deploy.
The instance env file#
hub-deploy.sh sources ENV.env from $YARRIX_INSTANCE_DIR, else private/instance/ in the checkout (or in the main
checkout when you run from a git worktree). YARRIX_INSTANCE_ENV names a file directly. Keep it out of version control.
LABEL=io.example.yarrix # launchd label; the backup job is "$LABEL.backup"
PREFIX=$HOME/yarrix # bin/ config/ data/ logs/ backups/ live here
APP_PORT=7791 # loopback port the hub listens on (not the 7790 default if that is taken)
PUBLIC_URL=https://hub.example.ts.net:7790
TAILNET_HOST=hub.example.ts.net # optional: enables the https health check and the serve check
TAILNET_PORT=7790
REQUIRED_HOST=hub # optional: refuse to deploy anywhere else
BACKUP_KEEP_DAYS=14 # optional
BACKUP_HOUR=3 # optional, local time; the job runs at HH:15
DC_LIB=/path/to/deploy-common.sh # optional: a shared deploy library for the lock, restart and health helpers
No secrets go in this file or in the plist. The hub reads them through ${env:NAME} / ${file:path} references in
its config (configuration.md).
On first start the hub writes a starter yarrix.yaml into $PREFIX/config and logs the first-run setup address (in
$PREFIX/logs/hub.log) that creates the first admin when you enter it on the hub's /setup page.
HTTPS with Tailscale#
The hub listens on loopback only. tailscale serve puts HTTPS (a real certificate) in front of it, reachable only
from your tailnet:
tailscale serve --bg --https=7790 http://127.0.0.1:7791 # public port 7790 -> hub on 7791
tailscale serve status
Set PUBLIC_URL to https://<machine>.<tailnet>.ts.net:7790 so setup and sign-in links carry that address. To sign
people in with their tailnet identity, add { type: tailscale, mode: headers } to auth.providers
(auth.md): the hub trusts the Tailscale-User-Login header only from loopback, which is where
tailscale serve connects from. The deploy script checks that the serve door exists and prints this command when it
does not; it never runs it for you.
Backups#
deploy/macos/backup-hub-data.sh DATA_DIR BACKUP_DIR [CONFIG_DIR] copies every *.db in the data directory with
SQLite's online backup (consistent while the hub runs), integrity-checks each copy, copies the config directory, and
prunes folders older than YARRIX_BACKUP_KEEP_DAYS. A deploy installs it with a launchd job ($LABEL.backup) that runs
daily. Run it by hand any time:
$PREFIX/bin/backup-hub-data.sh $PREFIX/data $PREFIX/backups $PREFIX/config
To restore: stop the hub (launchctl bootout gui/$(id -u)/$LABEL), copy the .db files from a hub-<timestamp>
folder over the same names in $PREFIX/data, delete any *.db-wal and *.db-shm beside them, start the hub
(launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/$LABEL.plist). Copy the backups folder to another machine as
well: a backup on the same disk does not survive the disk.
This is separate from the hub's own self_monitor.db_backup (a VACUUM INTO copy it makes and checks itself); the
nightly job is the one that also covers the config directory and is driven from outside the hub process.