LXC Dev Environments on Proxmox Replace Docker Desktop

Replace Docker Desktop with a Proxmox LXC dev container running Docker CE. VS Code Remote SSH connects in seconds and build times drop on NVMe-backed storage.

Proxmox Pulse Proxmox Pulse
9 min read
lxc docker dev-environment vscode-remote docker-compose
Holographic LXC container cubes replacing a fading Docker whale in a glowing server room.

If you're running Docker Desktop on macOS or Windows and watching your fans spin up every time you start a container, there is a better way. Move your development environment into a Proxmox LXC container, connect VS Code or JetBrains over SSH, and your laptop becomes a thin client. Build times drop, disk I/O stops bottlenecking on virtualized file systems, and you get an environment any teammate can replicate from a single pct clone command.

Key Takeaways

  • Docker Desktop replacement: An LXC container on Proxmox running Docker CE gives you full dev tooling without Docker Desktop's VM overhead or licensing requirements.
  • Performance: On NVMe-backed Proxmox VE 9.1, compile times run 2–3× faster than through Docker Desktop's Linux VM translation layer on macOS.
  • Remote IDE support: VS Code Remote SSH and JetBrains Gateway connect directly to LXC containers — IntelliSense, debugger, and terminal all run on the server.
  • Container privilege: Docker-in-LXC needs either a privileged container or nesting=1,keyctl=1 feature flags — both approaches are covered below.
  • Clone for teammates: pct clone 200 201 --full gives a new developer an identical environment in under two minutes.

Why Docker Desktop Gets Painful at Scale

Docker Desktop on macOS and Windows does not run containers natively. It wraps a lightweight Linux VM and proxies all container activity through it. That proxy has real costs:

  • File system translation: Bind-mounting your macOS ~/projects folder into a container goes through a translation layer. On a project with 50,000 node_modules files, npm install can take 3× longer than the same operation on native Linux.
  • Memory overhead: The Docker Desktop VM itself consumes 2–4 GB of RAM before you run a single container.
  • Licensing: Since April 2022, Docker Desktop requires a paid subscription for businesses with more than 250 employees or over $10M in revenue.

Moving your dev environment to Proxmox LXC sidesteps all three. Your container runs on bare Linux with direct NVMe access, and you pay nothing extra beyond your existing Proxmox setup. If you're still debating whether to move workloads off bare metal entirely, running everything on Proxmox covers the broader case for hypervisor-first homelabs.

How to Create a Dev Container on Proxmox

Start with a fresh Ubuntu 24.04 LXC. Either use the web UI or run this directly on the Proxmox host:

pct create 200 local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \
  --hostname devbox \
  --cores 4 \
  --memory 4096 \
  --swap 2048 \
  --rootfs local-lvm:50 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \
  --unprivileged 0 \
  --features nesting=1,keyctl=1

Key decisions in that command:

  • --unprivileged 0 creates a privileged container. Docker-in-LXC works in unprivileged containers on Proxmox VE 9.1 with kernel 6.8+, but you will hit cgroup v2 permission walls with certain images. Privileged is the pragmatic choice for a personal dev box.
  • nesting=1 is required for Docker to create its own network namespaces inside the LXC.
  • keyctl=1 lets tools like BuildKit use kernel keyrings for layer caching.
  • 50 GB rootfs is a starting point — Docker build cache grows faster than you expect.

Start the container and enter it:

pct start 200
pct exec 200 -- bash

Set Up SSH Access

Inside the container, install OpenSSH and add your public key:

apt update && apt install -y openssh-server curl
mkdir -p /root/.ssh
echo "ssh-ed25519 AAAA...your-public-key-here" >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
systemctl enable --now ssh

Check the container's IP:

ip a show eth0

From your laptop, verify the connection:

ssh root@192.168.1.200

If you get a shell without a password prompt, you're done with this step.

Install Docker CE Inside the LXC Container

Avoid the docker.io package from Ubuntu's repos — it lags behind upstream by several minor versions. Use the official Docker CE repository:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable" \
  > /etc/apt/sources.list.d/docker.list
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Enable Docker and run a smoke test:

systemctl enable --now docker
docker run --rm hello-world

If hello-world completes successfully, Docker is fully functional inside your LXC. This is Docker CE 27.x running on Proxmox VE 9.1 with kernel 6.8 — cgroups v2 is active by default and Docker handles it cleanly with the nesting feature flag.

Common failure mode: if you see failed to create shim task: OCI runtime create failed, your container is running unprivileged without the right AppArmor profile. Fix it by switching to privileged mode:

pct stop 200
pct set 200 --unprivileged 0
pct start 200

Connect VS Code Remote SSH to Your Dev Container

VS Code's Remote SSH extension runs the extension host, terminal, debugger, and IntelliSense directly on the Proxmox LXC — your laptop only renders the UI. Install the Remote - SSH extension, then add this to your local ~/.ssh/config:

Host devbox
  HostName 192.168.1.200
  User root
  IdentityFile ~/.ssh/id_ed25519
  ForwardAgent yes

In VS Code: Ctrl+Shift+PRemote-SSH: Connect to Host → select devbox. On first connect, VS Code installs its server component on the LXC (about 30 seconds) and then you're editing files directly inside the container with full language tooling.

JetBrains Gateway

JetBrains users get an identical experience through JetBrains Gateway. Add your SSH connection details, select which IDE to install remotely (IntelliJ, GoLand, PyCharm), and the full IDE backend runs on the LXC. On a container with 4 cores and 6 GB RAM, GoLand finishes indexing a 200k-line Go project in roughly 45 seconds — comparable to a local install on a modern laptop.

How to Handle Code Sync Between Your Laptop and the LXC

Three approaches, each with a different tradeoff:

Method Latency Setup Complexity Best For
Git only None Minimal Clean workflows, CI parity
NFS mount ~0.5ms on LAN Moderate Live editing from macOS/Windows
SSHFS ~1–2ms on LAN Low Quick access, no server config

Git is the cleanest option. Clone your repo inside the LXC, work there, push when done. You get the same environment as CI and there is no sync layer to break.

NFS makes sense when multiple people need live access to the same directory. Inside the LXC:

apt install -y nfs-kernel-server
echo "/root/projects 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
exportfs -ra

Mount on macOS:

mkdir -p ~/mnt/devbox
sudo mount -t nfs 192.168.1.200:/root/projects ~/mnt/devbox

SSHFS is the zero-config fallback. On macOS with macFUSE installed:

sshfs root@192.168.1.200:/root/projects ~/mnt/devbox -o follow_symlinks

Port Forwarding and Networking in Your Dev LXC

Because you're using vmbr0 with DHCP, the LXC gets a real LAN IP and any ports your containers expose are directly reachable from your network:

docker run -d -p 3000:3000 --name my-app my-app-image

Hit http://192.168.1.200:3000 from any machine on your LAN. No Docker Desktop port forwarding quirks, no extra NAT translation layer.

For remote access from outside your home network, a Cloudflare Tunnel on Proxmox gives you secure zero-trust access without opening any firewall ports — it works even on CGNAT connections where port forwarding is not an option.

If Docker Compose containers can reach each other but not the internet, Docker's default bridge network (172.17.0.0/16) likely conflicts with an existing LAN route. Adjust the address pool in /etc/docker/daemon.json:

{
  "default-address-pools": [
    {"base": "10.20.0.0/16", "size": 24}
  ]
}

Restart Docker after editing:

systemctl restart docker

How to Clone the Environment for Your Team

Once your devbox is working, giving a teammate an identical environment takes two minutes on the Proxmox host:

pct stop 200
pct clone 200 201 --full --hostname devbox-alice
pct set 201 --net0 name=eth0,bridge=vmbr0,ip=dhcp
pct start 201

Alice gets the same Docker CE version, the same system packages, the same shell config. Hand her the LXC IP and your SSH config template, and she's productive immediately. No "it works on my machine" because everyone's machine is the same machine.

For the Docker-in-LXC security model and a deeper look at when to choose privileged vs unprivileged containers on a shared cluster, running Docker inside LXC containers on Proxmox covers the privilege tradeoffs in detail.

Resource Limits and Sizing

A reasonable single-developer starting point:

pct set 200 --cores 4 --memory 6144 --swap 4096

For heavy builds — Rust, C++, large monorepos — go to 8 cores and 8 GB. LXC overhead is minimal; you're running near bare-metal performance for compute.

To prevent one devbox from starving others on a shared Proxmox host:

pct set 200 --cpulimit 4 --cpuunits 1024

--cpulimit is a hard core cap; --cpuunits sets the relative scheduling weight when the host is under load.

One gotcha that will catch you eventually: Docker build cache grows silently inside /var/lib/docker and can fill a 50 GB rootfs within days of aggressive image building. Either schedule a periodic docker system prune -af, or add a dedicated volume at container creation time:

pct set 200 --mp0 local-lvm:100,mp=/var/lib/docker

Stop and restart the container after adding the mount point. The inotify subsystem inside LXC also deserves a mention: tools like Vite, nodemon, and Air (Go live reload) fire inotify events natively — no polling, no 200–500ms delays like you sometimes see with Docker Desktop on macOS.

Conclusion

Replacing Docker Desktop with a Proxmox LXC dev environment is a one-afternoon project that pays off immediately in build speed, environment consistency, and team onboarding time. You end up with a container you can SSH into from any device, clone for any teammate, and resize without reinstalling anything. The natural next step is securing remote access: set up a Cloudflare Tunnel on Proxmox so your devbox is reachable from anywhere without exposing SSH to the public internet.

Share
Proxmox Pulse

Written by

Proxmox Pulse

Sysadmin-driven guides for getting the most out of Proxmox VE in production and homelab environments.

Related Articles

View all →