Installing the Mixer Web UI

mixer_web is the LiveView control interface for shiloh-mixer. It talks to the mixer over a local control-plane socket (UDP 19997) and exposes a web UI on port 8889 with per-channel faders, mutes, bus assignment, and scene management.

The app is a Phoenix 1.8 application with LiveView. It is intended for LAN use — no authentication by default.

Prerequisites

  • Elixir ≥ 1.15 and Erlang/OTP (managed by mise on this server — see note below)
  • Node.js (for asset compilation; only needed at build time)

NOTE: On the Shiloh servers, Elixir/Erlang are managed by mise and are not on $PATH by default. Prefix all mix and iex commands with mise exec --. For example: mise exec -- mix deps.get.

Install Elixir with mise if not already present:

mise install elixir@1.18
mise use elixir@1.18

Or install system-wide on Debian/Ubuntu:

sudo apt install elixir erlang

1. Get dependencies

cd ~/shiloh-broadcaster/server/mixer_web
mise exec -- mix deps.get

2. Compile assets (development)

mise exec -- mix assets.setup   # downloads esbuild + tailwind
mise exec -- mix assets.build   # compiles JS + CSS

3. Generate a secret key base

Required for production. Generate and save it somewhere secure (e.g. a drop-in systemd config):

mise exec -- mix phx.gen.secret
# → prints a 64-byte hex string, e.g.:
#   AbcDef1234...

4. Configuration

The app is configured via environment variables at runtime. The relevant variables are:

Variable Default Description
PORT 8889 HTTP listen port
PHX_HOST localhost Hostname used in URL generation
PHX_SERVER (unset) Set to true to start the HTTP server
SECRET_KEY_BASE (required in prod) 64-byte secret from mix phx.gen.secret

The mixer endpoint defaults are set in config/config.exs. To override at runtime without touching the config file, set the environment variables before starting the server.

5. Development run

cd ~/shiloh-broadcaster/server/mixer_web
PORT=8889 mise exec -- mix phx.server

The UI is available at http://localhost:8889. LiveReload is active in dev mode — edits to .ex/.heex files reload automatically.

6. Production run (release)

For a long-lived production deployment, build a Mix release:

cd ~/shiloh-broadcaster/server/mixer_web
MIX_ENV=prod mise exec -- mix assets.deploy
MIX_ENV=prod mise exec -- mix release

The release is assembled at _build/prod/rel/mixer_web/. Copy it to the target location:

cp -r _build/prod/rel/mixer_web ~/mixer_web

Run it:

PHX_SERVER=true \
PHX_HOST=stg-srv001.bq.shilohbv.com \
PORT=8889 \
SECRET_KEY_BASE="<your-secret>" \
~/mixer_web/bin/mixer_web start

7. systemd user unit

The repo ships server/systemd/mixer_web.service. The unit expects the release at ~/mixer_web/bin/mixer_web.

The SECRET_KEY_BASE is kept out of the unit file in a drop-in to avoid committing secrets:

mkdir -p ~/.config/systemd/user/mixer_web.service.d
cat > ~/.config/systemd/user/mixer_web.service.d/secret.conf << 'EOF'
[Service]
Environment=SECRET_KEY_BASE=<paste-your-secret-here>
EOF
chmod 600 ~/.config/systemd/user/mixer_web.service.d/secret.conf

Install the main unit:

cp ~/shiloh-broadcaster/server/systemd/mixer_web.service \
   ~/.config/systemd/user/mixer_web.service

The unit file (for reference):

[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

[Install]
WantedBy=default.target

NOTE: SuccessExitStatus=143 maps SIGTERM (exit code 143) to a clean shutdown so the Restart=on-failure policy only fires on actual crashes, not on systemctl stop.

Enable and start:

systemctl --user daemon-reload
systemctl --user enable mixer_web.service
systemctl --user start  mixer_web.service
systemctl --user status mixer_web.service

The UI is intentionally not PartOf=shiloh-mixer.service — it stays running across mixer restarts and LiveView reconnects automatically once the mixer is back.

Troubleshooting

Symptom Likely cause
SECRET_KEY_BASE is missing Production mode without the env var — add the drop-in unit
cannot connect to mixer Check that the mixer is running on localhost (mixer address is compiled-in as 127.0.0.1:19997)
Assets return 404 Run mix assets.deploy and mix phx.digest before building the release
LiveView socket disconnects Origin mismatch; check_origin: false in runtime.exs disables this check on LAN