Zero Open Ports: A Homelab with Proxmox + Cloudflare Tunnel
How I reach my homelab from anywhere with zero open ports on my router, what went wrong along the way, and the AWS concepts it helped me understand.
I work as an IT support analyst (level 2) and study Systems for Internet in Brazil. At work I deal with Windows Server, Hyper-V, monitoring and remote management every day. I wanted a place at home to practice those same tools without being afraid of breaking anything. The constraint: no money for a real server, and no open ports on my home router.
This is how I built it, what went wrong, and why the design reminded me of things I later studied in AWS.
The hardware: smaller than a book
- Dell OptiPlex 3040 Micro, a corporate mini PC from about ten years ago
- Intel Core i5-6500T: 4 cores, 35 W
- 16 GB DDR3L (the board maximum) and a 240 GB SATA SSD
- Wired network, no rack, no noise
On top of it runs Proxmox VE 9, a free hypervisor based on Debian. Today it hosts a few Linux containers and one VM: monitoring (Zabbix), a remote management server, an automation tool (n8n) and the container that matters most for this article,
cloudflared. With everything running, the machine uses around 30% of its RAM and the CPU stays almost idle.The problem: remote access without opening the door
The classic way to reach a home server from outside is port forwarding on the router. That means:
- exposing services directly to the internet, where bots scan every IP all day;
- depending on a public IP, which many home connections don't have (CGNAT);
- maintaining firewall rules on an ISP router that was never designed for this.
I didn't want any of that.
The solution: an outbound-only tunnel plus identity in front
Cloudflare Tunnel flips the direction of the connection. A small agent,
cloudflared, runs inside my network and opens an outbound connection to Cloudflare. When I open a hostname like panel.mydomain, the request goes to Cloudflare, travels through that existing tunnel and reaches the service inside my house. Nothing on the router listens for incoming traffic.1
2
3
4
5
6
7
8
9
Me (anywhere) ──► Cloudflare (DNS + Access + Tunnel)
│ outbound connection, started from inside
▼
cloudflared container (Proxmox)
│
├──► Proxmox web panel
├──► monitoring
├──► automation
└──► SSH to the host
A tunnel alone would just publish the services to the world. The second piece is Cloudflare Access (part of the free Zero Trust plan). Every hostname gets an Access application with one policy: only my e-mail is allowed. Before any request reaches Proxmox or the monitoring panel, I have to log in with a one-time code. Then the service's own login and TOTP 2FA apply. That's three layers, and none of them depends on the router.
The
cloudflared container is tiny: 1 core, 256 MB of RAM, 4 GB of disk.What went wrong (and what I learned)
1. I downloaded the wrong ISO. The Proxmox download page listed the ARM64 image first. It doesn't boot on an Intel CPU. Lesson: check the architecture and the SHA256 before writing the USB stick.
2. I pasted the tunnel token in the wrong shell. Proxmox gives you a shell on the host and inside each container. I ran the install command on the host and got
cloudflared: command not found. The fix was pct enter 100 to get into the container first. It sounds obvious, but it cost me some time.3. Order matters: Access first, route second. The moment you save a public hostname in the tunnel, it's live. If the Access application doesn't exist yet, the service is open to the internet for those minutes. My rule now: create the Access app before the route, always.
4. Free certificates cover one level only.
ssh.pve.mydomain doesn't get a valid certificate on the free plan; pve-ssh.mydomain does. Keep hostnames to one level.5. Self-signed origins need a hint. The Proxmox panel uses a self-signed certificate, so the route needs "No TLS Verify". It's fine here because that hop happens inside my own network, not over the internet.
6. Always test from outside. One
curl per hostname shows whether the protection is really there:1
2
curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" https://panel.mydomain
# 302 to the Access login page = protected
A few machine-to-machine endpoints can't go behind an interactive login (agents need to reach them directly). Those stay without Access on purpose and rely on the application's own authentication and 2FA. Writing those exceptions down was as important as the setup itself.
Why this felt familiar when I studied AWS
After building this, I took the AWS Academy Cloud Foundations course, and several ideas clicked:
- Default deny for inbound traffic. My router has no forwarding rules, just like a security group with no inbound rules: nothing gets in unless you allow it explicitly.
- Outbound-only connectivity. Resources in a private subnet reach the internet through a NAT gateway but can't be reached from outside. My containers live in the same spirit.
- No bastion, no open SSH port. AWS Systems Manager Session Manager lets you get a shell on an EC2 instance without opening port 22. Cloudflare Tunnel plus Access gives me SSH to my host the same way.
- Identity in front of the application. Checking who you are before the request reaches the app is the idea behind AWS Verified Access, and it's what Access does for my panels.
Different providers, same principle: reduce what's exposed, and put identity before the network.
Takeaways
- Modest hardware is not an excuse. A 35 W CPU and 16 GB of RAM handle a surprising amount of work.
- Zero open ports is achievable at home, and it costs nothing on the free plan.
- The order of operations is part of security. Protection first, publication second.
- Document every exception. An endpoint left open on purpose is a decision; one left open by accident is an incident.
Next in this series: how my homelab tells me when it goes down, even when the server that does the monitoring is the one that died.
How do you reach your homelab from outside: port forwarding, VPN or a tunnel?
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article