Advanced installation

Manage every part of your installation

Manual Docker deployment, native Linux services, and maintenance guidance for existing installations. New installations can use the one-command installer.

Looking for the simple installation?

The installer downloads both components, creates your configuration, and starts VoltVault for you.

Use the installer
Protect existing data. Before replacing or upgrading an installation, create and download a verified backup. Never delete a live database or named Docker volume as part of a routine update.

Recommended 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 version

If 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 version

Docker 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 version

In 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
VariableSafe starting value
AUTH_MODErequired
COOKIE_SECUREfalse for private HTTP; true when the public-facing origin uses HTTPS
HOST0.0.0.0 in Docker; 127.0.0.1 for a native server behind a local reverse proxy
APP_BIND_ADDRESS127.0.0.1 for Docker until another trusted LAN device must connect
Never commit .env. Keep a protected off-machine copy of DEVICE_CREDENTIAL_KEY; changing it makes saved printer access codes unreadable.

Docker Compose deployment

  1. 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
  2. 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, and APP_BIND_ADDRESS=127.0.0.1.

  3. Build and start

    docker compose up -d --build
    docker compose ps
  4. Verify readiness

    curl --fail http://127.0.0.1:3000/api/ready

    Continue only when the response reports ready and the database check is ok.

  5. 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 -v during normal maintenance.

Native Node.js deployment

  1. 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.

  2. Install and build

    npm ci
    npm run build
  3. 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
  4. 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
  5. 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 node is not /usr/bin/node, edit ExecStart in the unit before copying it.

  6. 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

  1. 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
  2. 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 {} \;
  3. 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.local to the server’s private IP.

  4. 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

  1. Reserve each supported printer’s IP address in the router.
  2. Enable LAN-only Developer Mode and record the exact serial number, IP address, and access code.
  3. In VoltVault, open 3D printers and pair one printer at a time.
  4. 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

ProblemRun
Docker container is unhealthydocker compose logs --tail=200 voltvault-server
docker compose ps
df -h
Native service will not startsudo journalctl -u voltvault-server -n 200 --no-pager
command -v node
sudo -u voltvault test -w /opt/voltvault-server/data
Client loads but API failscurl --fail http://127.0.0.1:3000/api/ready
sudo caddy validate --config /etc/caddy/Caddyfile
sudo journalctl -u caddy -n 100 --no-pager
Login repeatscurl -I http://voltvault.local/; confirm every visit uses the same hostname and protocol, then clear stale cookies.
Database is lockedpgrep -af 'dist/index.js'
docker ps --filter name=voltvault-server; exactly one server process should use the database.