In my last post I wrote about how Tailscale and Cloudflare Tunnel let me reach my homelab from anywhere without a static IP or open ports. A few people asked the obvious question: what is actually running at home?
This post is the answer. It's the full story of turning a small Minisforum MS-A2 from a Windows 11 PC into a Proxmox server that runs my production, testing and miscellaneous apps 24/7. I'll start where most guides skip: the BIOS. Then the install, the networking decisions, and how I carved up the machine into three virtual machines.
It's a long one. Grab a coffee.
Why a mini PC, and why the MS-A2
For years my apps lived on shared hosting, then on a VPS. That works, but every new project meant another monthly bill, and I always felt like I was renting a tiny slice of someone else's computer.
I wanted something that was:
- Small and quiet, because it sits in my room, not a server rack.
- Powerful enough for several VMs, so I could separate production from testing properly.
- Low on power, because it runs all day and night.
- A normal x86 PC, so I could install whatever I want on it.
The Minisforum MS-A2 ticked all of those. Mine has:
| Part | What I have |
|---|---|
| CPU | AMD Ryzen, 16 cores |
| RAM | 32 GB |
| Storage | 1 TB NVMe (there are three M.2 slots, so room to grow) |
| Network | 2 × 2.5G Ethernet, 2 × 10G SFP+ |
That network section is a big part of why people use this machine for homelabs. Two 10G SFP+ ports on a box this size is unusual. I don't use them yet, but it's nice to know the machine won't be the bottleneck later.
It came with Windows 11 Pro. I didn't need Windows on it at all, so the plan was simple: wipe it and install Proxmox.
What is Proxmox, quickly
Proxmox VE is a free, open-source platform for running virtual machines and containers. You install it directly on the hardware (it's Debian Linux underneath), and then you manage everything from a web interface on port 8006.
Instead of one big server doing everything, you get many smaller, isolated machines. If I break my testing VM, production doesn't care. If I want to try something risky, I take a snapshot first and roll back in seconds. That's the whole appeal.
Step 1: Making the bootable USB
I downloaded the Proxmox VE ISO and used Rufus on Windows to write it to a pendrive.
Two things confused me here, so they might confuse you too:
Rufus asks about "ISO mode" or "DD mode". For Proxmox, choose DD mode. It looks like a warning, but it's the correct and recommended option for the Proxmox ISO. ISO mode can produce a USB that doesn't boot properly.
Afterwards, Windows shows the USB as two drives. That's normal too. One is the main data partition and one is a small EFI boot partition. Windows may offer to format one of them. Don't.
Step 2: The BIOS settings (the part most guides rush)
Before installing anything, I went into the BIOS. On the MS-A2 you get there by pressing DEL while it powers on (and F7 brings up the one-time boot menu).
This is the part I'd tell anyone to slow down on. A few settings here decide whether your VMs run at all, and a couple of them make a real difference for a server that's meant to be always on.
Virtualization: SVM Mode → Enabled
This is the most important one. SVM is AMD's hardware virtualization (the AMD version of Intel's VT-x). Without it, Proxmox installs fine, but your VMs either won't start or will run painfully slowly.
You'll usually find it under Advanced → CPU configuration or inside AMD CBS.
IOMMU → Enabled
IOMMU lets the system hand a real physical device (like a GPU, a network card or a disk controller) directly to a VM. This is called PCIe passthrough.
I don't use passthrough today. But turning it on now costs nothing, and it saves me a trip back into the BIOS if I ever want to give a VM its own network card or GPU.
Secure Boot → Disabled
Secure Boot only lets signed bootloaders start. Proxmox can work with Secure Boot, but it's a common source of "why won't my USB boot?" problems. For a home server I didn't need it, so I turned it off to keep the install simple.
Ac Loss Control → Always On
This is the one I'm happiest I found.
By default, if the power goes out, the MS-A2 stays off when the power comes back. That's fine for a desktop. It's terrible for a server. If there's a blackout while I'm at uni, all my apps would be down until I got home and pressed the button.
The setting that fixes this is called Ac Loss Control, and on the MS-A2 it was hidden a few levels deep:
Advanced → AMD CBS → FCH Common Options → Ac Power Loss Options → Ac Loss Control
Set it to Always On. Now when power returns, the machine boots by itself, Proxmox starts, and the VMs I've marked as "start at boot" come up on their own. No button pressing.
UMA Frame Buffer Size → 2G down to 1G
This one is easy to miss. The MS-A2 uses the CPU's built-in graphics, and integrated graphics don't have their own memory. They borrow some of your system RAM. The amount they reserve is the UMA Frame Buffer Size.
Mine was set to 2 GB. On a server with no monitor attached most of the time, that's 2 GB of RAM just sitting there doing nothing.
I wanted to drop it to 512 MB, but the lowest option available was 1G. So 1 GB it is. That gave me back 1 GB of RAM for VMs, which matters when you're splitting 32 GB three ways.
This is also why Proxmox showed only about 29.7 GB usable instead of a clean 32. Some RAM is reserved for graphics and the firmware, and you never get it back.
My BIOS checklist
| Setting | Value | Why |
|---|---|---|
| SVM Mode | Enabled | VMs need hardware virtualization |
| IOMMU | Enabled | Allows PCIe passthrough later |
| Secure Boot | Disabled | Avoids USB / bootloader problems |
| Ac Loss Control | Always On | Boots itself after a power cut |
| UMA Frame Buffer Size | 1G (from 2G) | Gives RAM back to the VMs |
Save with F4 (or Save & Exit), and the machine reboots.
Step 3: Installing Proxmox
With the USB plugged in, I opened the boot menu and picked the entry that said UEFI: [my USB name], not Windows Boot Manager.
Then I chose Install Proxmox VE (Graphical). If you ever get a black screen here, reboot and pick the Terminal UI installer instead. It does the same thing with a simpler interface.
The installer asks for a few things:
Target disk. I picked my 1 TB NVMe, which wiped Windows completely. If you have more than one drive in the MS-A2, check the size and model carefully here. There's no undo.
Filesystem. With a single drive, I went with ext4. It's simple and light. ZFS is great, especially in a mirror with two identical drives, but it likes to use a lot of RAM for caching, and I wanted that RAM for my VMs.
Location and time zone. Australia, Australia/Sydney.
Root password and email. Write the password down somewhere safe. You'll need it to log into the web interface.
Network. This is where I had to think the most, so it gets its own section.
Step 4: The networking decisions
Proxmox needs a cable, not Wi-Fi
When I started, I didn't even have an Ethernet cable, and I wondered if I could just use Wi-Fi.
Short answer: not really. The installation itself doesn't need any network. But for running Proxmox, you want wired Ethernet. Proxmox's installer and web interface don't set up Wi-Fi, and more importantly, Wi-Fi can't properly bridge VM traffic onto your home network. Each VM needs to appear as its own device on the network, and Wi-Fi isn't designed to carry traffic for multiple machines like that. You end up with NAT and port-forwarding workarounds that aren't worth it.
So I installed it with the network details filled in, and plugged in a cable afterwards.
The bottleneck I didn't expect
My router is at the other end of the house, so the server is wired by Ethernet into a Wi-Fi repeater, not directly into the router.
It works, but when I ran speed tests from the server, I got around 26 Mbps. My internet plan is faster than that. The problem isn't the NBN, it's the Wi-Fi hop between the repeater and the router. For a blog and some APIs it's fine, but it's on my list to fix with a proper wired run (or powerline/MoCA) later.
Lesson: an Ethernet cable into a repeater is still Wi-Fi underneath.
Static IP vs DHCP
The installer asks for an IP address. The classic advice is to set a static IP outside your router's DHCP range, so the server always lives at the same address. I did that first.
Then I thought about the future. If I move house or change router, a static IP from my old network won't work on the new one, and the server becomes unreachable until I plug in a monitor and fix it. And I didn't want to depend on a DHCP reservation in the router either, because I don't always have access to the router admin page.
Since I access everything through Tailscale anyway (more on that below), the local IP doesn't really matter to me. So I switched the Proxmox bridge to DHCP:
# /etc/network/interfaces (the bridge part)
auto vmbr0
iface vmbr0 inet dhcp
bridge-ports <your-nic-name>
bridge-stp off
bridge-fd 0
There's one catch. Proxmox expects its hostname to resolve to its current IP in /etc/hosts. If DHCP hands out a different IP, that entry goes stale and Proxmox services can complain. So I added a small hook that updates /etc/hosts whenever DHCP gives the server an address. A simplified version looks like this:
#!/bin/sh
# /etc/dhcp/dhclient-exit-hooks.d/update-hosts
case "$reason" in
BOUND|RENEW|REBIND|REBOOT)
sed -i "s/^.*[[:space:]]pve\.home\.lan.*$/${new_ip_address} pve.home.lan pve/" /etc/hosts
;;
esac
Now I can plug the server into any network and it just works. No router login needed.
Step 5: First login, then locking it down
After the install finished and I removed the USB, the screen showed a URL like https://<ip>:8006. I opened it from my laptop, clicked past the self-signed certificate warning, and logged in as root with the Linux PAM realm.
That was the last time I used the local IP.
Tailscale on the Proxmox host
The first thing I installed was Tailscale, so I could reach Proxmox from anywhere. I covered how Tailscale works in my previous post, so I'll keep it short here:
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up
Then I used Tailscale Serve to put the Proxmox web UI behind a proper HTTPS address on my tailnet, so I get a real certificate and no browser warnings:
tailscale serve --bg https+insecure://localhost:8006
Now I open Proxmox using a pve.<my-tailnet>.ts.net address from my laptop or phone, wherever I am.
Making Proxmox reachable only through Tailscale
This was a deliberate choice. I didn't want the Proxmox admin page reachable by anything on my home network, only by my own devices on Tailscale.
The Proxmox web server (pveproxy) can be told which address to listen on. Setting it to localhost means only Tailscale Serve, running on the same machine, can reach it:
# /etc/default/pveproxy
LISTEN_IP="127.0.0.1"
systemctl restart pveproxy
I did the same idea for SSH, only allowing connections that come from Tailscale's address range (100.64.0.0/10). Anyone on my home Wi-Fi who tries the local IP gets nothing.
Be careful with this. Lock-down steps like these can lock you out too. I did each change with Tailscale already working and tested, and I kept a monitor and keyboard nearby just in case.
Two-factor on root
Finally, I turned on 2FA (TOTP) for the root account in the Proxmox web UI. Even through Tailscale, the admin account of the whole server deserves a second factor.
Step 6: Planning the VMs
Now the fun part. I wanted three VMs:
- prod: the apps real people use, like this blog.
- test: my UAT environment, where changes go before production.
- misc: side projects, experiments and small tools that don't belong in either.
Splitting the RAM
With about 29.7 GB usable, I couldn't just give everyone 10 GB. Proxmox itself needs some memory too. My first plan was 12 / 8 / 8, which adds up to 28 GB and leaves almost nothing for the host. So I adjusted:
| VM | ID | CPU cores | RAM | Disk |
|---|---|---|---|---|
| prod | 100 | 8 | 12 GB | 300 GB |
| test | 101 | 4 | 6 GB | 100 GB |
| misc | 102 | 4 | 8 GB | 200 GB |
That's 26 GB for VMs, leaving a few GB of breathing room for Proxmox.
Production gets the most, because that's what people actually see. Testing gets the least RAM, because it only needs to prove that things work, not handle real traffic.
You might notice the cores add up to exactly 16. CPU is more forgiving than RAM: VMs share CPU time, so you can even give out more virtual cores than you physically have, and it's fine as long as they aren't all busy at once. RAM doesn't work that way. If you hand out more RAM than you have, things get slow or crash. So I'm strict with RAM and relaxed with CPU.
The OS
All three VMs run Ubuntu Server 24.04 LTS. It's stable, it's supported for years, and everything I use (.NET, Docker, databases, cloudflared) has good support for it.
Step 7: Hardening every VM the same way
I treated each VM as if it were a server on the public internet, even though none of them are directly exposed. Every one got exactly the same steps, which made it easy to remember and easy to repeat.
1. QEMU guest agent. This lets Proxmox talk to the VM properly: shut it down cleanly, see its IP address, and take consistent snapshots.
sudo apt install qemu-guest-agent
sudo systemctl enable --now qemu-guest-agent
(You also tick "QEMU Guest Agent" in the VM's Options in Proxmox.)
2. Tailscale, with key expiry turned off. Each VM joined my tailnet. By default Tailscale device keys expire and need re-authentication. That's good for laptops, but for a server it would mean my VMs randomly disappear one day. So I disabled key expiry for the servers in the Tailscale admin console.
3. SSH keys only. Password login is turned off. Only my SSH keys work.
# /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes
4. UFW firewall: Tailscale only. The firewall blocks everything incoming, except traffic that arrives through the Tailscale interface.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow in on tailscale0
sudo ufw enable
This works perfectly with Cloudflare Tunnel later, because cloudflared makes an outbound connection and talks to the app on localhost. Nothing needs to come in through the firewall.
5. Automatic security updates. I don't want to remember to patch three servers every week.
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
6. A "hardened" snapshot. Once a VM was set up and locked down, I took a snapshot called hardened in Proxmox, without saving RAM state. This is my clean starting point. If I ever mess a VM up badly, I can roll back to a known-good, already-secured state in seconds.
qm snapshot 100 hardened --vmstate 0
That snapshot has already made me braver. I try things now that I wouldn't have tried on a VPS.
Step 8: Can it really run 24/7?
Before trusting it with anything real, I checked temperatures with lm-sensors:
sudo apt install lm-sensors
sensors
CPU, NVMe and RAM temperatures were all in normal ranges, even with all three VMs running. The MS-A2 is widely used for always-on homelabs, and so far mine has been happy sitting in a corner doing its thing.
How it all fits together
Here's the whole picture:
Minisforum MS-A2 (Proxmox VE)
BIOS: SVM on, IOMMU on, auto power-on, 1G iGPU
Host: DHCP + hosts hook, Tailscale only, root 2FA
---------------------------------------------------
| prod (100) | test (101) | misc (102) |
| 8c / 12 GB | 4c / 6 GB | 4c / 8 GB |
| cloudflared | cloudflared | side apps |
| Tailscale, UFW | Tailscale,UFW | Tailscale,UFW|
---------------------------------------------------
| |
Cloudflare Tunnel Tailscale (me, from anywhere)
(public apps) (Proxmox, SSH, admin)
Public apps reach the world through Cloudflare Tunnel. Everything admin-related stays on Tailscale. No ports are open on my router, and the server doesn't care which network it's plugged into.
What I'd do differently
A few honest notes, in case you're about to do the same:
- Check the BIOS first, before you install anything. Especially the power-loss setting. You only find out you needed it after the first blackout.
- Plan the network for the house you'll live in next, not just this one. Avoiding a hard dependency on the router was the best decision I made.
- Get the cabling right early. My Wi-Fi repeater hop is the slowest part of the whole setup, and no amount of CPU fixes that.
- Leave RAM headroom for the host. It's tempting to hand everything to VMs. Don't.
- Snapshot after hardening. It turns every risky experiment into a cheap one.
What's next
Right now, my UAT environment is moving from my old VPS onto the test VM, and production apps are following. I deploy with GitHub Actions, so the next post will probably be about how those pipelines reach VMs that have no public SSH at all.
If you're thinking about a homelab, a mini PC like the MS-A2 is a great place to start. It's small, quiet, and powerful enough to run a proper production / testing split, which is exactly the habit you want to build as a developer anyway.
Are you running Proxmox at home? What hardware are you using, and how did you split your VMs? Let me know in the comments.
Comments (0)
🔑 Log in to comment Sign in with your email to like, save and join the discussion.
No comments yet. Be the first!