Joulenap runs beside Proxmox — not on the PVE host itself — as a tiny always-on container or service on the same LAN as your PBS. Pick the path that fits you.
Every step from scratch: create the container, install Docker, one command.
DOCKERAlready have Docker, or want to pre-edit config.
ADVANCEDRun it directly as a Python service under systemd.
Before you start: enable Wake-on-LAN on the PBS (a BIOS/UEFI setting, sometimes also ethtool -s <iface> wol g) and put Joulenap on the same LAN/subnet as the PBS — Wake-on-LAN can't cross routers. Keep the UI on your LAN/VPN.
The simplest reliable path: a small Debian LXC on your Proxmox host, Docker inside it, then one command. No files to download and no config to edit by hand — the container creates its own config and you finish in the browser.
In the Proxmox web UI, Create CT from a Debian 12 template: 1 core, 512 MB RAM, 2 GB disk. Bridge its network onto the same VLAN/subnet as your PBS — this is the setting that matters most.
Select the container → Options → Features → nesting, then start it. (Docker needs this inside an LXC.)
Open the container's Console (log in as root), then install Docker's official build:
# inside the LXC
apt update && apt install -y curl
curl -fsSL https://get.docker.com | sh
Seeing perl: warning: Setting locale failed? Fresh Debian LXCs ship without a generated locale — it's harmless and the install still succeeds. Silence it with update-locale LANG=C.UTF-8 (permanent, from the next login) and export LANG=C.UTF-8 LC_ALL=C.UTF-8 (takes effect in the current shell).
One command. Docker pulls the image from Docker Hub and the container seeds its own config on first boot:
mkdir -p /opt/joulenap/data docker run -d --name joulenap \ --restart unless-stopped \ --network host \ -e TZ=Etc/UTC \ -v /opt/joulenap/data:/app/data \ catubba/joulenap:latest
--network host lets it send the Wake-on-LAN broadcast; the single data folder holds config, history, logs and the SSH key. You'll pick your timezone on the first-run screen (pre-detected from your browser), so leave TZ as-is.
Browse to http://<container-ip>:8080 and continue at First run.
Use this if you already run Docker, or want to pre-edit config.yaml. There's no separate config file to create — it's seeded into ./data on first run.
mkdir -p joulenap && cd joulenap # grab just the compose file curl -fsSL -o docker-compose.yml \ https://raw.githubusercontent.com/Joulenap/joulenap/main/docker-compose.example.yml docker compose up -d # then open http://<host-ip>:8080
The example uses host networking and mounts one writable ./data directory. To pre-fill config, start it once so it seeds ./data/config.yaml, stop it, edit, and bring it back up.
For those who'd rather not use Docker — run Joulenap directly as a Python service. You need Python 3.12+, git, and Node.js 20+ (once, to build the web UI).
# 1. get the source mkdir -p /opt/joulenap && cd /opt/joulenap git clone https://github.com/Joulenap/joulenap.git cd joulenap # 2. build the web UI cd frontend && npm ci && npm run build && cd .. # 3. install the backend (editable — resolves the packaged README) python3 -m venv .venv .venv/bin/pip install -e ./backend mkdir -p /opt/joulenap/data
Then run it under systemd so it starts on boot — a unit file, the full walkthrough, and the update steps are in the repo's install guide.
Full native + systemd instructions, plus updating each method, live in docs/INSTALL.md.
Once the UI is up at http://<host>:8080 — the same for every install path:
A one-time registration. The timezone dropdown is pre-filled from your browser, so usually you just leave it — it sets the timezone your backup schedule runs in.
Under Settings → Setup. By default it uses API-token mode (you paste scoped tokens; nothing leaves your server). It walks through: connect to PVE → pick the PBS storage → confirm PBS → detect the PBS MAC → generate and install the poweroff SSH key.
Choose the time, pick which CTs/VMs to back up, set retention, and optionally wire up notifications. Use Run backup now to test the full wake → backup → power-off cycle. Everything else — backup mode, bandwidth limit, ports — lives in Settings → Advanced, which also embeds a full config.yaml editor in the browser (secrets are never sent to it).
Your config.yaml and data live in the mounted data/ directory, so they carry over across updates.