Systemd Units
All Shiloh Broadcaster services run as user-mode systemd units. No sudo is required for day-to-day operation.
Unit files
Units are installed to ~/.config/systemd/user/ by the install script:
~/.config/systemd/user/shiloh-mixer.service
~/.config/systemd/user/shiloh-web-relay.service
~/.config/systemd/user/mixer_web.service
~/.config/systemd/user/mixer_web.service.d/secret.conf # SECRET_KEY_BASE drop-in
Enable auto-start (survive login/logout)
By default, user systemd units only run while the user is logged in. To keep services running after you log out (required for a server):
# Allow the user's systemd session to persist without an active login
loginctl enable-linger $USER
# Enable the services to start at boot
systemctl --user enable shiloh-mixer shiloh-web-relay mixer_web
# Verify
loginctl show-user $USER | grep Linger
# → Linger=yes
Starting and stopping
# Start all at once
systemctl --user start shiloh-mixer shiloh-web-relay mixer_web
# Stop individual service
systemctl --user stop shiloh-web-relay
# Restart single service (safest during updates)
systemctl --user restart shiloh-mixer
# Check status
systemctl --user status shiloh-mixer
Dependency ordering
The units have explicit ordering:
PipeWire / WirePlumber (system audio stack)
└── shiloh-mixer (After= pipewire.service wireplumber.service)
└── shiloh-web-relay (After= shiloh-mixer.service)
└── mixer_web (After= shiloh-mixer.service, but PartOf= is intentionally absent
so the UI stays up across mixer restarts)
mixer_web is intentionally not a PartOf shiloh-mixer. The Phoenix LiveView UI reconnects automatically when the mixer comes back — keeping the UI alive lets operators see what is happening during a mixer restart.
Unit details
shiloh-mixer.service
[Unit]
Description=shiloh-mixer — Rust JACK mix bus + UDP broadcaster relay
After=pipewire.service wireplumber.service
Wants=pipewire.service wireplumber.service
[Service]
Type=simple
WorkingDirectory=%h/mixer
# pw-jack wraps the mixer so it uses PipeWire's JACK shim instead of native libjack.
# This makes PipeWire clients (Firefox, Desktop Audio) visible as JACK ports.
ExecStart=/usr/bin/pw-jack %h/mixer/shiloh-mixer-linux-x86_64 --config %h/mixer/shiloh-mixer.toml
Restart=on-failure
RestartSec=3
LimitRTPRIO=95
LimitMEMLOCK=infinity
Environment=XDG_RUNTIME_DIR=/run/user/1000
Environment=RUST_LOG=info
Environment=RUST_BACKTRACE=1
[Install]
WantedBy=default.target
Key points:
pw-jackwrapper — The mixer runs under PipeWire’s JACK compatibility layer. This makes all PipeWire clients (Firefox, Desktop Audio sink, etc.) visible as JACK ports. Withoutpw-jack, the mixer uses nativelibjackand cannot see PipeWire-only clients.LimitRTPRIO=95andLimitMEMLOCK=infinityallow the JACK RT callback thread to run at realtime priority. Without these, JACK will refuse to enable RT scheduling and xrun rates rise dramatically under load.XDG_RUNTIME_DIRmust be set explicitly because linger sessions don’t always inherit it from PAM. The install script hard-codes your UID — verify it matchesid -u.Restart=on-failurewithRestartSec=3means the mixer auto-recovers from crashes. Broadcaster and relay clients reconnect automatically.
mixer_web.service
[Unit]
Description=mixer_web — Phoenix LiveView mixer UI (port 8889)
After=network-online.target shiloh-mixer.service
Wants=network-online.target
[Service]
Type=simple
Environment=PHX_SERVER=true
Environment=PHX_HOST=stg-srv001.bq.shilohbv.com
Environment=PORT=8889
ExecStart=/home/shiloh/mixer_web/bin/mixer_web start
ExecStop=/home/shiloh/mixer_web/bin/mixer_web stop
Restart=on-failure
RestartSec=3
SuccessExitStatus=143
TimeoutStopSec=15
SuccessExitStatus=143maps SIGTERM (exit 143) to “clean shutdown” soRestart=on-failuredoes not re-trigger on graceful stop.TimeoutStopSec=15gives the Erlang VM 15 seconds to drain active WebSocket connections before systemd kills it.SECRET_KEY_BASEis in the drop-inmixer_web.service.d/secret.conf— not the main unit — so the unit file can be version-controlled without exposing secrets.
Editing a unit
# Open a drop-in (preferred — survives reinstall)
systemctl --user edit shiloh-mixer
# Or edit the file directly
nano ~/.config/systemd/user/shiloh-mixer.service
# Always reload after editing
systemctl --user daemon-reload
systemctl --user restart shiloh-mixer
Socket activation
Socket activation is not currently used. The mixer and web relay bind their own UDP/TCP sockets at startup. If you need to start the mixer on-demand (e.g. for a low-power server that should sleep), socket activation could be added for TCP 8889, but UDP socket activation is awkward — the mixer opens UDP 5005 itself and must be running continuously for relay reconnects to work.
Checking all Shiloh units at once
systemctl --user list-units 'shiloh-*' 'mixer_web*'