Proxmox cluster in Docker. Learn, test, break, and repeat.
- Fast iteration — Spin up, tear down, repeat in seconds
- Cluster simulation — Test live migration, clustering, and multi-node management
- Automation testing — Validate Terraform, Ansible, or scripts
- Shared storage — Mount ISOs, backups, and disk images across all nodes
- Dual-Stack Networking — IPv4 and IPv6 support with pre-configured NAT bridges
- KVM & LXC ready — Virtual machines and containers work out of the box
- Central management — Optional Proxmox Datacenter Manager container included
- ARM64 support — Proxmox VE on your favorite ARM platform, powered by PXVIRT
- Modern Linux host with kernel 6.8+
- Docker Engine (version 27+ recommended)
- Intel VT-x / AMD-V enabled
- macOS: Use OrbStack instead of Docker Desktop
- Windows 11 with Docker Desktop (WSL2):
- WSL kernel version 6.6+ (
wsl --version) - Nested virtualization enabled in WSL Settings
- WSL kernel version 6.6+ (
Important
For ARM64 platforms:
Do not config DHCP when create LXC, config IP inside the LXC instead (e.g. dhclient eth0)
For latest ARM64 LXC template, visit: https://images.linuxcontainers.org/images/
Standalone node with docker run:
Tip
Remove --detach if you want an interactive console, to escape, hold CTRL then press P + Q
Run docker attach pve-1 to reattach later if needed
For full hardware devices access, use --privileged flag
docker run --detach -it --name pve-1 --hostname pve-1 \
-p 2222:22 -p 3128:3128 -p 8006:8006 \
--restart unless-stopped \
--cgroupns=private --cap-add ALL \
--security-opt seccomp=unconfined \
--security-opt apparmor=unconfined \
--security-opt systempaths=unconfined \
--device-cgroup-rule "a *:* rwm" \
-v /dev/vfio:/dev/vfio \
-v /usr/lib/modules:/usr/lib/modules:ro \
-v /sys/kernel/security:/sys/kernel/security \
-v ./VM-Backup:/var/lib/vz/dump \
-v ./ISOs:/var/lib/vz/template/iso \
--env PASSWORD=123 \
ghcr.io/longqt-sea/proxmox-veReplace ./ISOs with the path to your ISO folder.
Default root password: 123
Access the web UI at https://localhost:8006/ (accept the self-signed cert).
Important
If on ARM64 platforms, remove the pdm: section because the PDM image is amd64-only.
Deploy 3-node cluster using Docker Compose:
-
Create a project directory and cd into it:
mkdir pve_cluster; cd pve_cluster -
Create a
compose.ymlfile in thepve_clusterdirectory with the following content:
# Common option
x-service: &systemd
restart: unless-stopped
stdin_open: true
tty: true
cgroup: private
device_cgroup_rules:
- "a *:* rwm"
cap_add:
- ALL
security_opt:
- seccomp=unconfined
- apparmor=unconfined
- systempaths=unconfined
x-pve-service: &pve-systemd
<<: *systemd
image: ghcr.io/longqt-sea/proxmox-ve
volumes:
- /usr/lib/modules:/usr/lib/modules:ro # Required for loading kernel modules
- /sys/kernel/security:/sys/kernel/security # Optional, needed for LXC
- ./VM-Backup:/var/lib/vz/dump # Shared storage for VM/LXC backups
- ./ISOs:/var/lib/vz/template/iso # Shared storage for ISO files
# Set default root password
x-env: &password
PASSWORD: "123"
services:
# First node
pve-1:
container_name: pve-1
hostname: pve-1
<<: *pve-systemd
environment:
<<: *password
networks:
dual_stack:
ipv4_address: 10.0.99.1
ipv6_address: fd00::1
# Port mapping only required for Docker Desktop or remote access from other machines.
ports:
- "2222:22"
- "3128:3128"
- "8006:8006" # First node container port 8006 maps to host port 8006
# Second node
pve-2:
container_name: pve-2
hostname: pve-2
<<: *pve-systemd
environment:
<<: *password
networks:
dual_stack:
ipv4_address: 10.0.99.2
ipv6_address: fd00::2
# Port mapping only required for Docker Desktop or remote access from other machines.
ports:
- "2223:22"
- "3129:3128"
- "8007:8006" # Second node container port 8006 maps to host port 8007
# Third node
pve-3:
container_name: pve-3
hostname: pve-3
<<: *pve-systemd
environment:
<<: *password
networks:
dual_stack:
ipv4_address: 10.0.99.3
ipv6_address: fd00::3
# Port mapping only required for Docker Desktop or remote access from other machines.
ports:
- "2224:22"
- "3130:3128"
- "8008:8006" # Third node container port 8006 maps to host port 8008
# Optional: Proxmox Datacenter Manager
pdm:
image: ghcr.io/longqt-sea/proxmox-datacenter-manager
container_name: pdm
hostname: pdm
<<: *systemd
environment:
<<: *password
cap_add:
- SYS_ADMIN
- NET_ADMIN
security_opt:
- seccomp=unconfined
- apparmor=unconfined
networks:
dual_stack:
ipv4_address: 10.0.99.4
ipv6_address: fd00::4
ports:
- "2225:22"
- "8443:8443"
# Dual-stack network for this cluster
networks:
dual_stack:
enable_ipv6: true
ipam:
config:
- subnet: 10.0.99.0/24
gateway: 10.0.99.99
- subnet: fd00::/64
gateway: fd00::99Bring it up:
docker compose up -d
Default root password: 123
Tip
Access nodes like this to avoid authentication conflicts ("invalid PVE ticket 401"):
| Environment | How to access nodes | Example |
|---|---|---|
| Docker Engine (Linux) | Access nodes directly via container IPs | https://[fd00::1]:8006https://[fd00::2]:8006https://[fd00::3]:8006 |
| Docker Desktop (Windows) | Use different loopback address | https://127.0.0.1:8006https://127.0.0.2:8007https://127.0.0.3:8008 |
| OrbStack (macOS) | Use separate browser profile for each node | Multiple Chrome profileOr different browser |
Note
To create the cluster, go to System → Network on pve-1 node, edit eth0 interface as shown in the image below.
Next, go to Datacenter → Cluster → Create Cluster and copy Join Information.
On other nodes, go to Datacenter → Cluster → Join Cluster, paste the copied Join Information, enter root password.
Nodes can reach each other over hostname or IP address:
| hostname | IPv4 | IPv6 |
|---|---|---|
| pve-1 | 10.0.99.1 | fd00::1 |
| pve-2 | 10.0.99.2 | fd00::2 |
| pve-3 | 10.0.99.3 | fd00::3 |
| pdm | 10.0.99.4 | fd00::4 |
To tear down the cluster:
docker compose down -t 0
| Port | Purpose |
|---|---|
| 8006 | Proxmox VE Web UI |
| 3128 | SPICE proxy |
| 22 | OpenSSH |
| 8443 | Proxmox Datacenter Manager Web UI |
| Host Path | Container Path | Purpose |
|---|---|---|
| ./VM-Backup | /var/lib/vz/dump | VM backups |
| ./ISOs | /var/lib/vz/template/iso | ISO images |
vmbr1- NAT network for VM and LXC, works out of the boxvmbr2- Empty bridge, configure it yourself, maybe with macvlan, veth or passthrough a physical NIC
Note
When running with podman, make sure to run as root or with sudo, rootless Podman does not work even with --privileged.
Warning
Use the --privileged flag with caution. A privileged container can do almost everything the Linux host can do.
Proxmox HA requires hardware watchdog fencing, which cannot work in containers:
- Linux
/dev/watchdogcan only be used by one process at a time - Containers cannot fence (forcibly reboot) each other
- VMs added to HA will stay stuck in "queued" state
For HA learning, use bare-metal or nested VMs instead.
This project is licensed under the GPLv3 or later (see LICENSE file).
This project is provided “as‑is”, without any warranty, for educational and research purposes. In no event shall the authors or contributors be liable for any direct, indirect, incidental, special, or consequential damages arising from use of the project, even if advised of the possibility of such damages.
All product names, trademarks, and registered trademarks are property of their respective owners. All company, product, and service names used in this repository are for identification purposes only.
