You’ve heard it before: a container is not a sandbox. We even wrote an article about it. Sharing the host kernel is a security compromise, period. For most homelab services, it’s a risk we accept. But what about that sketchy Discord bot you want to run? Or a publicly exposed service you don’t fully trust?
The standard answer is a full KVM virtual machine. It’s isolated, secure, and has decades of hardening behind it. It also eats 1-2 GiB of RAM just to idle and takes a solid 30 seconds to boot. It’s total overkill for running a single Go binary.
There’s a better middle ground: microVMs. Specifically, using Amazon’s Firecracker VMM directly within Proxmox VE. This gives you the kernel-level isolation of a VM with the resource footprint and speed closer to a container. The problem has always been that setting this up is a nightmare of custom kernels, TAP devices, and arcane tooling.
It turns out there’s an easier way, hidden in plain sight within modern LXC tooling. Let’s get it running.
Why Bother? KVM vs LXC vs MicroVM
Let’s get the taxonomy straight.
- KVM (Full VM): Proxmox’s bread and butter. Full hardware emulation via QEMU. Massively flexible, hugely resource-intensive. Your Windows Server VM lives here.
- LXC (Container): Proxmox’s other specialty. Shares the host kernel, using cgroups and namespaces for isolation. Lightweight, fast, but not a strong security boundary. Your trusted internal services live here.
- MicroVM (Firecracker): A KVM-based, minimalist VMM. It boots a real, separate Linux kernel but virtualizes only the bare minimum required. No BIOS, no PCI bus, just a serial console, a network device, and a block device. This is where your untrusted, single-purpose apps should live.
The goal is to run a Firecracker microVM with the same ease as an LXC container, right from the Proxmox host’s shell.
The “Easy Way” with LXC’s Firecracker Backend
Recent versions of lxc (the userspace tools that power Proxmox’s LXC integration) include an experimental backend that can use Firecracker as the virtualization provider instead of kernel namespaces. It’s not exposed in the Proxmox GUI, which is probably for the best. It requires a bit of manual configuration, but it’s surprisingly straightforward.
This approach gives you a workflow that feels very similar to managing standard LXC containers, but with a real hardware-virtualized boundary.
Step 1 — Prepare the Proxmox Host
First, SSH into your Proxmox node. You’ll need to install the firecracker binary and some LXC tooling that might not be present by default.
# Update package lists
apt update
# Install firecracker and lxc-utils
apt install firecracker lxc-utils -y
# Verify firecracker is installed
firecracker --version
You also need a kernel image for your guests. Firecracker doesn’t have a BIOS to boot a standard ISO. It needs a direct path to an uncompressed kernel vmlinuz file. You can compile your own, but the easiest way is to steal one from an existing Linux distribution.
Let’s grab the latest Alpine kernel, which is small and perfect for this.
# Create a directory to store guest kernels
mkdir -p /opt/microvm/kernels
# Go to the directory
cd /opt/microvm/kernels
# Download the Alpine vmlinuz file (check for the latest version)
# Example for Alpine 3.18
wget http://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/alpine-virt-3.18.2-x86_64.iso
# Mount the ISO to extract the kernel
mount -o loop,ro alpine-virt-3.18.2-x86_64.iso /mnt
cp /mnt/boot/vmlinuz-virt ./vmlinuz-alpine-3.18
umount /mnt
# Clean up
rm alpine-virt-3.18.2-x86_64.iso
Now you have a guest kernel ready at /opt/microvm/kernels/vmlinuz-alpine-3.18.
Step 2 — Create the MicroVM Configuration
This is the secret sauce. We’ll create an LXC configuration file that instructs it to use the firecracker driver.
Create a file named ~/firecracker.conf.
# Use the lxc-firecracker driver
lxc.virt.type = firecracker
# Path to the Firecracker binary
lxc.virt.firecracker.path = /usr/bin/firecracker
# Path to the guest kernel
lxc.virt.kernel = /opt/microvm/kernels/vmlinuz-alpine-3.18
# Network Configuration
lxc.net.0.type = veth
lxc.net.0.link = vmbr0
lxc.net.0.flags = up
lxc.net.0.name = eth0
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx # CHANGE THIS
CRITICAL: You must change the lxc.net.0.hwaddr to a unique MAC address. Mash your keyboard for the last three octets if you have to, just make it unique on your network. This config bridges the microVM’s network interface directly to your Proxmox vmbr0, so it will get an IP from your DHCP server just like any other VM or container.
Step 3 — Create and Launch the MicroVM
We’ll use standard lxc-create to build the root filesystem and then launch it with our custom config. We’ll create an Alpine-based microVM named mvm-test01.
# Create the container using the Alpine template
# This only creates the rootfs, we'll apply our config at launch
lxc-create -n mvm-test01 -t alpine
# Start the microVM using our Firecracker configuration
lxc-start -n mvm-test01 -f ~/firecracker.conf --logpriority=INFO --logfile=/tmp/mvm-test01.log
You won’t see much output. Check the log file for progress. If it hangs, it’s almost always a networking or kernel path issue. A successful boot log will end with Firecracker reporting a successful exit after you stop the VM.
Step 4 — Access and Manage
How do you get a shell? lxc-attach works just like it does with regular containers.
# Attach to the running microVM
lxc-attach -n mvm-test01
# You should get a shell inside the Alpine guest
/ # uname -a
Linux mvm-test01 6.1.27-0-virt #1-Alpine ...
/ # ip a
...
eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
inet 192.168.1.123/24 ...
...
/ # exit
Notice the kernel version. It’s the Alpine kernel we downloaded, not your Proxmox host’s kernel. That’s the proof of isolation.
To stop it, use lxc-stop.
lxc-stop -n mvm-test01
The boot and shutdown speeds are absurd. We’re talking hundreds of milliseconds. The idle RAM usage is around 5-10 MiB. You could run dozens of these on a modest Proxmox host without breaking a sweat.
Reality Check: The Gotchas
This isn’t a perfect replacement for a KVM. Be aware of the limitations.
- Storage is Primitive: By default,
lxc-createjust makes a directory on the host’s filesystem. This is fine, but it’s not as robust as a ZFS volume or LVM-thin backing. You can get fancy and create a loopback block device for the rootfs, but that adds complexity. - No Proxmox GUI Integration: This is a command-line-only affair. The microVM won’t show up in your Proxmox dashboard. You’re managing it like a classic Linux service. You could write a simple systemd unit file to manage it.
- Minimalism is a Double-Edged Sword: Firecracker emulates almost nothing. You can’t pass through USB devices or GPUs. You get one network card and one block device. This is great for security but limits what you can run. It’s designed for server-side Linux applications, and nothing else.
- Debugging is Painful: When things go wrong, the log file is your only friend. The feedback loop is less interactive than booting a KVM with a full console. Double-check your config paths and network settings before you start.
Despite these points, for isolating a single application, this method is a fantastic tool for the homelab security toolbox. It provides a meaningful security upgrade over a simple container without demanding the resources of a full virtual machine.
What’s Next
Now that you have a handle on running isolated workloads, it’s time to put them to work.
[discussion]
Comments are powered by Giscus — backed by GitHub Discussions. Sign in with GitHub to join the conversation.