Skip to content

Proxmox deployment

The whole difference between a Proxmox install and a workstation install is one fact: the container has no graphics card. Everything else follows from that, plus the usual care about a service that has to survive a logout. This covers only what differs from Setup.

An unprivileged LXC is the right shape: no kernel modules, no device passthrough, no Docker.

Template Debian 13 or Ubuntu 24.04
Cores 4 (2 works; builds are slower)
RAM 4 GB (2 GB runs, but next build is tight)
Disk 20 GB — node_modules and .next are ~2 GB
Unprivileged yes · Nesting: not needed
Network a static IP or a DHCP reservation — you will be typing it a lot
Terminal window
pct create 120 local:vztmpl/debian-13-standard_amd64.tar.zst \
--hostname erebros-t \
--cores 4 --memory 4096 --rootfs local-lvm:20 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--unprivileged 1 --features nesting=0 \
--onboot 1
pct start 120
pct enter 120

--onboot 1 matters: a container that does not start with the node is a service that vanishes after the next reboot of the host.

Debian’s own nodejs is far too old — node:sqlite will not be there.

Terminal window
apt update && apt install -y curl git ca-certificates
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
node --version # must be >= 22.22.0

Do not run this as root — Workflows has shell steps and the agent CLIs have file access.

Terminal window
adduser --disabled-password --gecos "" erebros
su - erebros
Terminal window
git clone <your-repository-url> ~/erebros-t
cd ~/erebros-t
npm install
npm run build
export EREBROS_FORCE_CLOUD=1

EREBROS_FORCE_CLOUD overrides the GPU probe entirely. Provider keys are now required, not optional: with no GPU and no key a capability has nowhere to run, and the Local / Cloud screen says so. Paste the keys in Settings → Secrets before deciding anything is broken. For finer control, leave it unset and set each capability on that screen instead.

5 · The service, and the part everybody gets wrong

Section titled “5 · The service, and the part everybody gets wrong”

~/.config/systemd/user/erebrost.service:

[Unit]
Description=Erebros-T
After=network.target
[Service]
Type=simple
WorkingDirectory=%h/erebros-t
Environment=NODE_ENV=production
Environment=PORT=3401
Environment=HOST=0.0.0.0
Environment=EREBROS_STATE_DIR=%h/.erebros-t
Environment=EREBROS_FORCE_CLOUD=1
Environment=EREBROS_MACHINE=proxmox
ExecStart=/usr/bin/npm start
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target

EREBROS_MACHINE is the name this machine signs its events with; “proxmox” beats a container hostname you will not recognise in six months.

Terminal window
systemctl --user daemon-reload
systemctl --user enable --now erebrost.service
exit # back to root
loginctl enable-linger erebros

Without lingering, the service dies when the SSH session closes. It will look perfect while you are testing and be gone the moment you disconnect. Verify it survives: disconnect entirely, reconnect, and su - erebros -c 'systemctl --user status erebros-t --no-pager'.

By default Teams binds 127.0.0.1 only — useless in a container. The unit above sets HOST=0.0.0.0; check it actually took:

Terminal window
ss -tlnp | grep 3401 # expect 0.0.0.0:3401, not 127.0.0.1:3401

Then from the LAN: http://<container-ip>:3401. Do not port-forward this to the internet. The PIN gate and the same-origin guard stop a browser on your own network acting on your behalf; they are not an authentication system. Remote access goes behind a VPN (WireGuard on the Proxmox host) or a reverse proxy that does real authentication.

Proxmox backs up the container, which covers everything; the piece that matters is small enough to copy on its own:

Terminal window
# from the host
pct exec 120 -- tar czf - -C /home/erebros/.erebros-t events \
> /var/lib/vz/dump/erebros-t-events-$(date +%F).tar.gz

Restoring is tar xzf into the same place and a restart; the index catches up on the first request. Keep identity.json — regenerating it means this machine signs future events as a different machine.

Terminal window
su - erebros
cd ~/erebros-t && git pull && npm install && npm run build
systemctl --user restart erebros-t

Take a Proxmox snapshot before a version you have not run before; rolling back a snapshot is instant.

Symptom Where to look
Nothing on :3401 systemctl --user status erebros-t, then journalctl --user -u erebros-t -n 100
Service vanishes after you log out loginctl show-user erebros | grep Linger — must be yes
Transcription takes minutes EREBROS_FORCE_CLOUD=1 is not set, or is set in your shell but not in the unit
“Neither path works yet” on a capability No GPU and no provider key. Paste a key.
App starts, every page errors node --version — below 22.22 the index import throws
Search finds nothing curl -X POST http://localhost:3401/api/events/verify rebuilds the index
Audit log says the chain is broken Somebody edited log.jsonl. Restore from backup; do not repair by hand.