Looking for the simple installation?
The installer downloads both components, creates your configuration, and starts VoltVault for you.
Use the installerRecommended setup
Start with Docker Compose
If you do not have both VoltVault ZIP files yet, download them first. Then choose your computer, install the required tools, and follow the numbered Docker steps. Each check tells you when it is safe to continue.
Use the complete Docker bundle manually
For a first installation, extract the combined ZIP into a new folder and open Terminal in the extracted voltvault directory. It contains the root compose.yaml and both component folders. Windows users can use the PowerShell installer to create the configuration, then manage Docker Compose directly.
On Mac or Linux, generate the root configuration only if it does not already exist:
if [ -e .env ]; then echo 'Existing .env kept; check its port and address before continuing.' else umask 077 session_secret=$(openssl rand -hex 32) credential_key=$(openssl rand -hex 32) printf 'SESSION_SECRET=%s\nDEVICE_CREDENTIAL_KEY=%s\nAPP_BIND_ADDRESS=127.0.0.1\nAPP_PORT=8080\n' "$session_secret" "$credential_key" > .env unset session_secret credential_key fi docker compose -p voltvault up -d --build --wait --wait-timeout 300 curl --fail http://127.0.0.1:8080/api/ready
Use the browser address matching your root configuration and create the administrator account. Existing installations need a backup before replacing application files. Do not reuse the project name voltvault on a Docker host where another installation already uses it.
Maintain an installer installation
For version changes, use Upgrade VoltVault. Official installer and older full-stack Docker deployments can upgrade with one command and automatic verified backups.
These commands apply to the new installer, whose default folder is ~/voltvault and browser port is 8080. The older instructions below use a different directory layout and a directly published API.
To stop, start, or inspect your installation, open Terminal or PowerShell in the installation folder and run:
docker compose -p voltvault stop docker compose -p voltvault start docker compose -p voltvault logs --tail=100
Your database and uploads remain in persistent Docker volumes. Keep the root .env protected; the credential key is required to read stored printer access codes. Keep an off-machine copy of this file as well as your database and upload backups.
Before changing application versions, create and download a verified database backup from Settings → Backups. For a complete offline copy, stop the server and copy both data volumes into a new, empty backup folder:
docker compose -p voltvault stop voltvault-server docker compose -p voltvault cp voltvault-server:/data/. ./backup-data/ docker compose -p voltvault cp voltvault-server:/uploads/. ./backup-uploads/ docker compose -p voltvault start voltvault-server
Use a new backup destination every time. Check that both copy commands succeeded and move the backups off the host. If a copy fails, restart the server before troubleshooting.
After a successful automated upgrade, the updater manages a protected .voltvault-updater/active.json Compose configuration. Run maintenance commands from the existing Compose directory with docker compose -p YOUR_PROJECT -f .voltvault-updater/active.json, followed by stop, start, or logs --tail=100. Use the project name shown by Docker for older deployments. Keep this file and updater metadata with your backups. Installer-managed deployments can rerun the current installer for LAN or port changes. Manual deployments should keep managing their own configuration. Do not delete volumes or replace secret keys during an update.
1. Prepare your platform
Docker Compose is the recommended path on every platform. Use the matching section below, then continue to extract the downloads. Native Node.js service installation is supported on Linux and documented separately.
macOS (Apple Silicon)arm64
Confirm the processor, install Homebrew if needed, then install the native Apple Silicon builds of Docker Desktop and Caddy:
test "$(uname -m)" = "arm64" || { echo "This is not an Apple Silicon Mac"; exit 1; }
if ! command -v brew >/dev/null 2>&1; then
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
eval "$(/opt/homebrew/bin/brew shellenv)"
brew install --cask docker
brew install caddy
open -a Docker
until docker info >/dev/null 2>&1; do sleep 2; done
docker version
docker compose version
caddy versionIf an Intel-only container tool later requires it, install Rosetta with softwareupdate --install-rosetta --agree-to-license. VoltVault’s supplied images support ARM64 directly.
macOS (Intel)x86_64
Confirm the processor, install Homebrew if needed, then install the Intel builds selected for this Mac:
test "$(uname -m)" = "x86_64" || { echo "This is not an Intel Mac"; exit 1; }
if ! command -v brew >/dev/null 2>&1; then
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
eval "$(/usr/local/bin/brew shellenv)"
brew install --cask docker
brew install caddy
open -a Docker
until docker info >/dev/null 2>&1; do sleep 2; done
docker version
docker compose version
caddy versionDocker supports the current and two previous major macOS releases. Use the official Mac requirements to confirm an older Intel Mac is still supported.
Windows 10 or 11WSL 2
Use Docker Desktop with its WSL 2 backend. First download Docker Desktop Installer.exe, then open PowerShell as Administrator:
wsl --install -d Ubuntu-24.04
wsl --update
Start-Process "$HOME\Downloads\Docker Desktop Installer.exe" -Wait -ArgumentList 'install','--user'
Start-Process "$env:LOCALAPPDATA\Programs\DockerDesktop\Docker Desktop.exe"
wsl --version
do { Start-Sleep -Seconds 2 } until (docker info 2>$null)
docker version
docker compose versionIn Docker Desktop, open Settings → General and enable Use the WSL 2 based engine. Then open Settings → Resources → WSL Integration, enable Ubuntu 24.04, and select Apply & restart. Open the Ubuntu terminal and install the remaining tools:
sudo apt update sudo apt install -y unzip rsync caddy docker info caddy version
Run all remaining Linux-style commands inside the Ubuntu terminal, not PowerShell.
Ubuntu22.04 / 24.04 / 26.04
Add Docker’s official Ubuntu repository, install Compose and the deployment tools, then give the current user Docker access:
sudo apt update
sudo apt install -y ca-certificates curl unzip rsync caddy
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
. /etc/os-release
docker_suite="${UBUNTU_CODENAME:-$VERSION_CODENAME}"
docker_arch="$(dpkg --print-architecture)"
printf 'Types: deb\nURIs: https://download.docker.com/linux/ubuntu\nSuites: %s\nComponents: stable\nArchitectures: %s\nSigned-By: /etc/apt/keyrings/docker.asc\n' "$docker_suite" "$docker_arch" | sudo tee /etc/apt/sources.list.d/docker.sources
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker caddy
sudo usermod -aG docker "$USER"Sign out and back in once, then verify with docker run --rm hello-world, docker compose version, and caddy version.
Debian12 / 13
Add Docker’s official Debian repository, install Compose and the deployment tools, then give the current user Docker access:
sudo apt update sudo apt install -y ca-certificates curl unzip rsync caddy sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc . /etc/os-release docker_suite="$VERSION_CODENAME" docker_arch="$(dpkg --print-architecture)" printf 'Types: deb\nURIs: https://download.docker.com/linux/debian\nSuites: %s\nComponents: stable\nArchitectures: %s\nSigned-By: /etc/apt/keyrings/docker.asc\n' "$docker_suite" "$docker_arch" | sudo tee /etc/apt/sources.list.d/docker.sources sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl enable --now docker caddy sudo usermod -aG docker "$USER"
Sign out and back in once, then verify with docker run --rm hello-world, docker compose version, and caddy version.
Fedora or RHELdnf
Use the command matching the distribution to add Docker’s repository, then install and start the services:
. /etc/os-release if [ "$ID" = "fedora" ]; then sudo dnf -y install dnf5-plugins curl unzip rsync sudo dnf config-manager addrepo --from-repofile https://download.docker.com/linux/fedora/docker-ce.repo else sudo dnf -y install dnf-plugins-core curl unzip rsync sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo fi sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo dnf copr enable -y @caddy/caddy sudo dnf install -y caddy sudo systemctl enable --now docker caddy sudo usermod -aG docker "$USER"
Sign out and back in once, then verify with docker run --rm hello-world, docker compose version, and caddy version. Docker’s supported RHEL releases are listed in its RHEL guide.
Arch Linuxpacman
Install the distribution packages, enable both services, and give the current user Docker access:
sudo pacman -Syu --needed docker docker-compose caddy unzip rsync sudo systemctl enable --now docker caddy sudo usermod -aG docker "$USER"
Sign out and back in once, then verify with docker run --rm hello-world, docker compose version, and caddy version. See the Arch Docker guide for host-specific storage and networking options.
2. Extract the downloads
macOS or Linux
Open Terminal in the folder containing both ZIP files:
mkdir -p voltvault-self-hosted mv voltvault-server-2.0.7.zip voltvault-web-client-2.0.7.zip voltvault-self-hosted/ cd voltvault-self-hosted unzip voltvault-server-2.0.7.zip unzip voltvault-web-client-2.0.7.zip
Windows
Run this in PowerShell. It moves the files from Downloads into the Ubuntu WSL filesystem and extracts them there:
wsl bash -lc 'mkdir -p ~/voltvault-self-hosted' wsl bash -lc "cp /mnt/c/Users/$env:USERNAME/Downloads/voltvault-server-2.0.7.zip ~/voltvault-self-hosted/" wsl bash -lc "cp /mnt/c/Users/$env:USERNAME/Downloads/voltvault-web-client-2.0.7.zip ~/voltvault-self-hosted/" wsl bash -lc 'cd ~/voltvault-self-hosted && unzip voltvault-server-2.0.7.zip && unzip voltvault-web-client-2.0.7.zip' wsl
At the Ubuntu prompt, run cd ~/voltvault-self-hosted.
3. Create secrets and configuration
Enter the server directory, copy the example, generate both secrets, insert them, protect the file, and confirm no placeholder remains:
cd voltvault-server
cp .env.example .env
session_secret="$(openssl rand -hex 32)"
credential_key="$(openssl rand -hex 32)"
awk -v session="$session_secret" -v device="$credential_key" 'BEGIN { FS=OFS="=" } $1=="SESSION_SECRET" {$2=session} $1=="DEVICE_CREDENTIAL_KEY" {$2=device} {print}' .env > .env.new
mv .env.new .env
chmod 600 .env
unset session_secret credential_key
grep -E '^(AUTH_MODE|APP_BIND_ADDRESS|COOKIE_SECURE|HOST)=' .env
if grep -q 'replace-with' .env; then echo 'ERROR: placeholder secret remains'; exit 1; fi| Variable | Safe starting value |
|---|---|
AUTH_MODE | required |
COOKIE_SECURE | false for private HTTP; true when the public-facing origin uses HTTPS |
HOST | 0.0.0.0 in Docker; 127.0.0.1 for a native server behind a local reverse proxy |
APP_BIND_ADDRESS | 127.0.0.1 for Docker until another trusted LAN device must connect |
.env. Keep a protected off-machine copy of DEVICE_CREDENTIAL_KEY; changing it makes saved printer access codes unreadable.Docker Compose deployment
Verify the platform tools
Run these commands after completing your platform section. All three must succeed before deployment:
docker version docker compose version caddy version
Check the server configuration
Complete the shared configuration above, then verify the container paths and bind address:
grep -E '^(DATABASE_PATH|UPLOAD_DIR|APP_BIND_ADDRESS|APP_PORT)=' .env
Confirm the output includes
DATABASE_PATH=/data/inventory.sqlite,UPLOAD_DIR=/uploads, andAPP_BIND_ADDRESS=127.0.0.1.Build and start
docker compose up -d --build docker compose ps
Verify readiness
curl --fail http://127.0.0.1:3000/api/ready
Continue only when the response reports
readyand the database check isok.Confirm persistence
docker volume ls --filter name=voltvault docker compose exec -T voltvault-server test -f /data/inventory.sqlite docker compose exec -T voltvault-server test -d /uploads
All three commands must succeed. Rebuilding keeps these volumes. Do not use
docker compose down -vduring normal maintenance.
Native Node.js deployment
Install prerequisites for your Linux distribution
Ubuntu or Debian
sudo apt update sudo apt install -y ca-certificates curl git python3 build-essential rsync unzip caddy curl -fsSL https://deb.nodesource.com/setup_22.x -o /tmp/nodesource_setup.sh sudo -E bash /tmp/nodesource_setup.sh sudo apt install -y nodejs
Fedora
sudo dnf install -y dnf5-plugins curl git python3 gcc-c++ make rsync sudo dnf copr enable -y @caddy/caddy sudo dnf install -y caddy curl -fsSL https://rpm.nodesource.com/setup_22.x -o /tmp/nodesource_setup.sh sudo bash /tmp/nodesource_setup.sh sudo dnf install -y nodejs
RHEL
sudo dnf install -y dnf-plugins-core curl git python3 gcc-c++ make rsync sudo dnf copr enable -y @caddy/caddy sudo dnf install -y caddy curl -fsSL https://rpm.nodesource.com/setup_22.x -o /tmp/nodesource_setup.sh sudo bash /tmp/nodesource_setup.sh sudo dnf install -y nodejs
Arch Linux
sudo pacman -Syu --needed nodejs npm base-devel python git rsync caddy unzip
Verify the required versions:
node --version npm --version git --version python3 --version make --version c++ --version rsync --version caddy version
Stop if Node reports a major version below 22.
Install and build
npm ci npm run build
Set native filesystem paths
Update
.env, create the persistent directories, and verify the values:sed -i.bak 's|^DATABASE_PATH=.*|DATABASE_PATH=./data/inventory.sqlite|' .env sed -i.bak 's|^UPLOAD_DIR=.*|UPLOAD_DIR=./uploads|' .env sed -i.bak 's|^HOST=.*|HOST=127.0.0.1|' .env sed -i.bak 's|^PORT=.*|PORT=3000|' .env mkdir -p data/backups uploads chmod 700 data data/backups uploads grep -E '^(PORT|HOST|DATABASE_PATH|UPLOAD_DIR)=' .env
Test the production process
Load
.env, start the server, verify readiness in another terminal, then stop it with Control+C:set -a . ./.env set +a npm start # Run in a second terminal: curl --fail http://127.0.0.1:3000/api/ready
Install the Linux service
From the built server directory, create the service account, copy the checkout, set ownership, confirm the Node path, and install the unit:
sudo useradd --system --home-dir /opt/voltvault-server --shell /usr/sbin/nologin voltvault sudo mkdir -p /opt/voltvault-server sudo rsync -a --exclude .git ./ /opt/voltvault-server/ sudo chown -R voltvault:voltvault /opt/voltvault-server command -v node grep '^ExecStart=' deploy/voltvault-server.service sudo cp deploy/voltvault-server.service /etc/systemd/system/voltvault-server.service sudo systemctl daemon-reload sudo systemctl enable --now voltvault-server sudo systemctl status --no-pager voltvault-server curl --fail http://127.0.0.1:3000/api/ready
If
command -v nodeis not/usr/bin/node, editExecStartin the unit before copying it.Verify after reboot
During a maintenance window, reboot and run the same checks:
sudo reboot # After reconnecting: sudo systemctl is-active voltvault-server curl --fail http://127.0.0.1:3000/api/ready sudo journalctl -u voltvault-server -n 50 --no-pager
Deploy the web client for either path
Build the client
Enter the client directory and create its same-origin environment file:
cd ../voltvault-web-client cp .env.example .env printf 'VITE_API_BASE_URL=\n' > .env
On the native Node.js path, build with the installed runtime:
npm ci npm run typecheck npm run build test -f dist/index.html
On the Docker-only path, build in a temporary Node.js container instead:
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/app" -w /app node:22-bookworm sh -lc 'npm ci && npm run typecheck && npm run build' test -f dist/index.html
Publish the built files
Use the command for the host running Caddy.
macOS
web_root="$HOME/.local/share/voltvault/www" mkdir -p "$web_root" rsync -a --delete dist/ "$web_root/"
Linux or Windows WSL
sudo install -d -m 755 /srv/voltvault-web sudo rsync -a --delete dist/ /srv/voltvault-web/ sudo find /srv/voltvault-web -type d -exec chmod 755 {} \; sudo find /srv/voltvault-web -type f -exec chmod 644 {} \;Configure one origin
Use the command for the host running Caddy.
macOS
config_dir="$HOME/.local/share/voltvault" web_root="$config_dir/www" sed "s|/srv/voltvault-web|$web_root|" ../voltvault-server/deploy/Caddyfile.example > "$config_dir/Caddyfile" caddy validate --config "$config_dir/Caddyfile" sudo "$(command -v caddy)" start --config "$config_dir/Caddyfile" grep -q 'voltvault.local' /etc/hosts || echo '127.0.0.1 voltvault.local' | sudo tee -a /etc/hosts sudo dscacheutil -flushcache curl --fail http://voltvault.local/ curl --fail http://voltvault.local/api/ready
Linux or Windows WSL
sudo cp ../voltvault-server/deploy/Caddyfile.example /etc/caddy/Caddyfile sudo caddy validate --config /etc/caddy/Caddyfile sudo systemctl enable --now caddy sudo systemctl reload caddy grep -q 'voltvault.local' /etc/hosts || echo '127.0.0.1 voltvault.local' | sudo tee -a /etc/hosts curl --fail --resolve voltvault.local:80:127.0.0.1 http://voltvault.local/ curl --fail --resolve voltvault.local:80:127.0.0.1 http://voltvault.local/api/ready
Windows browser name resolution
Run PowerShell as Administrator after Caddy is running in WSL:
Add-Content -Path "$env:WINDIR\System32\drivers\etc\hosts" -Value "`n127.0.0.1 voltvault.local" ipconfig /flushdns Invoke-WebRequest http://voltvault.local/api/ready
For other devices, point local DNS for
voltvault.localto the server’s private IP.Create the administrator
Open
http://voltvault.local/, select Create administrator, enter a unique password of at least 12 characters, submit the form, sign out, and sign back in. Public registration remains unavailable.
LAN and HTTPS decisions
Confirm the API is listening only on loopback. Use lsof -nP -iTCP:3000 -sTCP:LISTEN on macOS or ss -lntp | grep ':3000' on Linux and WSL. The listener should show 127.0.0.1:3000.
Do not port-forward the API or printer ports. When one trusted reverse proxy terminates HTTPS, update the server environment and restart it:
cd "$(dirname "$PWD")/voltvault-server" sed -i.bak 's/^COOKIE_SECURE=.*/COOKIE_SECURE=true/' .env sed -i.bak 's/^TRUST_PROXY=.*/TRUST_PROXY=true/' .env docker compose up -d # Native Linux service instead of Docker: sudo cp .env /opt/voltvault-server/.env sudo chown voltvault:voltvault /opt/voltvault-server/.env sudo systemctl restart voltvault-server
Optional local printers
- Reserve each supported printer’s IP address in the router.
- Enable LAN-only Developer Mode and record the exact serial number, IP address, and access code.
- In VoltVault, open 3D printers and pair one printer at a time.
- Verify telemetry. Test Stop only on a disposable print.
Local Bambu Lab protocols are unsupported and firmware-sensitive. Bambu Studio remains responsible for slicing and print submission.
Backups and upgrades
Using the official installer or full-stack Docker Compose? The one-command updater handles backups and upgrades for you. The following instructions are for deployments you maintain manually.
Before every upgrade, open Settings → Backups, select Create backup, wait for the verified result, then select Download and copy the file off the server.
For Docker, also copy the persistent data and uploads to a dated host directory before rebuilding:
cd "$(dirname "$PWD")/voltvault-server" backup_dir="./host-backups/$(date +%Y%m%d-%H%M%S)" mkdir -p "$backup_dir/data" "$backup_dir/uploads" docker compose stop voltvault-server docker compose cp voltvault-server:/data/. "$backup_dir/data/" docker compose cp voltvault-server:/uploads/. "$backup_dir/uploads/" docker compose start voltvault-server docker compose up -d --build curl --fail http://127.0.0.1:3000/api/ready docker compose ps
For a native service, back up, replace the application files, rebuild, restart, and verify:
cd "$(dirname "$PWD")/voltvault-server" backup_dir="/var/backups/voltvault/$(date +%Y%m%d-%H%M%S)" sudo install -d -m 700 "$backup_dir" sudo systemctl stop voltvault-server sudo cp -a /opt/voltvault-server/data /opt/voltvault-server/uploads "$backup_dir/" sudo rsync -a --delete --exclude .git --exclude .env --exclude data --exclude uploads ./ /opt/voltvault-server/ sudo chown -R voltvault:voltvault /opt/voltvault-server sudo -u voltvault npm --prefix /opt/voltvault-server ci sudo -u voltvault npm --prefix /opt/voltvault-server run build sudo systemctl start voltvault-server curl --fail http://127.0.0.1:3000/api/ready sudo systemctl status --no-pager voltvault-server
Migrations run automatically and create a verified pre-migration database copy when existing application tables are present.
Troubleshooting
| Problem | Run |
|---|---|
| Docker container is unhealthy | docker compose logs --tail=200 voltvault-serverdocker compose psdf -h |
| Native service will not start | sudo journalctl -u voltvault-server -n 200 --no-pagercommand -v nodesudo -u voltvault test -w /opt/voltvault-server/data |
| Client loads but API fails | curl --fail http://127.0.0.1:3000/api/readysudo caddy validate --config /etc/caddy/Caddyfilesudo journalctl -u caddy -n 100 --no-pager |
| Login repeats | curl -I http://voltvault.local/; confirm every visit uses the same hostname and protocol, then clear stale cookies. |
| Database is locked | pgrep -af 'dist/index.js'docker ps --filter name=voltvault-server; exactly one server process should use the database. |