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.
1 · The container
Section titled “1 · The container”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 |
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 1pct start 120pct 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.
2 · Node 22.22+, from NodeSource
Section titled “2 · Node 22.22+, from NodeSource”Debian’s own nodejs is far too old — node:sqlite will not be there.
apt update && apt install -y curl git ca-certificatescurl -fsSL https://deb.nodesource.com/setup_22.x | bash -apt install -y nodejsnode --version # must be >= 22.22.03 · A user to run it as
Section titled “3 · A user to run it as”Do not run this as root — Workflows has shell steps and the agent CLIs have file access.
adduser --disabled-password --gecos "" erebrossu - erebros4 · Install, and force cloud placement
Section titled “4 · Install, and force cloud placement”git clone <your-repository-url> ~/erebros-tcd ~/erebros-tnpm installnpm run buildexport EREBROS_FORCE_CLOUD=1EREBROS_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-TAfter=network.target
[Service]Type=simpleWorkingDirectory=%h/erebros-tEnvironment=NODE_ENV=productionEnvironment=PORT=3401Environment=HOST=0.0.0.0Environment=EREBROS_STATE_DIR=%h/.erebros-tEnvironment=EREBROS_FORCE_CLOUD=1Environment=EREBROS_MACHINE=proxmoxExecStart=/usr/bin/npm startRestart=on-failureRestartSec=5
[Install]WantedBy=default.targetEREBROS_MACHINE is the name this machine signs its events with; “proxmox” beats a
container hostname you will not recognise in six months.
systemctl --user daemon-reloadsystemctl --user enable --now erebrost.serviceexit # back to rootloginctl enable-linger erebrosWithout 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'.
6 · Reaching it
Section titled “6 · Reaching it”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:
ss -tlnp | grep 3401 # expect 0.0.0.0:3401, not 127.0.0.1:3401Then 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.
7 · Backups
Section titled “7 · Backups”Proxmox backs up the container, which covers everything; the piece that matters is small enough to copy on its own:
# from the hostpct exec 120 -- tar czf - -C /home/erebros/.erebros-t events \ > /var/lib/vz/dump/erebros-t-events-$(date +%F).tar.gzRestoring 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.
8 · Updating
Section titled “8 · Updating”su - erebroscd ~/erebros-t && git pull && npm install && npm run buildsystemctl --user restart erebros-tTake a Proxmox snapshot before a version you have not run before; rolling back a snapshot is instant.
9 · When something is wrong
Section titled “9 · When something is wrong”| 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. |