For a long time, my homelab had a dirty secret: I couldn't access it remotely.
Well, that's not entirely true. I used to have a solution — Google Remote Desktop into my main PC, then SSH from there into my servers using XShell. It worked, but it was clunky, dependent on my desktop being on and reachable, and felt like the wrong answer. When I eventually rebuilt my PC, I never bothered to set it up again.
So for a while, if I wasn't home, I wasn't in my homelab. For a network I'd put real effort into building — pfSense firewall, Pi-hole, Unbound, a dedicated Docker host, a storage server — that felt like a gap worth closing.
The solution turned out to be Tailscale. Getting it fully working took a detour I didn't expect.
Why Tailscale
I'd heard about Tailscale for a while before actually setting it up. The pitch is simple: install it on your devices, and they form a secure mesh VPN — no port forwarding, no dynamic DNS headaches, no managing certificates. Each device gets a stable Tailscale IP that works anywhere.
What sold me was installing it on my pfSense router (fireclaw in my homelab, following a Horizon Zero Dawn naming convention I use throughout). Installing Tailscale at the router level means every device on my local network is reachable through Tailscale — not just the ones with the client installed. One install, whole network covered.
After setting it up, I could reach my services from my phone or laptop from anywhere. Portainer, Uptime Kuma, Nginx Proxy Manager, BookStack — all accessible as if I was sitting at home. For a homelab that had been effectively offline to me whenever I left the house, this was a big deal.
The SSH Problem
With Tailscale on pfSense working well for web-based services, the next thing I wanted was SSH access to my servers — specifically minerva (Docker host) and zero-dawn (storage server).
This is where things got interesting.
When I tried to SSH directly into minerva from my laptop (hephaestus) over Tailscale, it would time out. Connection refused. Couldn't be reached. This was confusing — Tailscale was working fine for everything else, both hephaestus and fireclaw had Tailscale installed and connected, so why couldn't I reach minerva?
The suspected culprit: a routing loop. Traffic from hephaestus was hitting Tailscale, routing through fireclaw, and somewhere in the handoff between Tailscale and the local network it was getting lost — likely looping back into pfSense without finding its way to minerva. Firewall rules and routing tables on pfSense can get opinionated about traffic that arrives and leaves on the same interface.
The obvious fix was to install Tailscale directly on minerva, giving it its own Tailscale IP that hephaestus could reach directly without routing through pfSense at all. I tried it. SSH worked.
But something else broke.
One Fix, One New Problem
Installing Tailscale directly on minerva interfered with how its Docker containers were being reached. The details got murky fast — container networking, Tailscale's network interface, and pfSense all have opinions about routing, and they weren't agreeing. Services that had been working fine were suddenly unreachable.
At this point I had two options: dig into the networking conflict and try to resolve it, or find a different path to SSH that didn't require touching minerva's network config.
I chose the workaround.
WeTTY: Browser-Based SSH in a Docker Container
The insight was simple: I could already reach Docker containers on minerva through Tailscale without any issues. What if one of those containers was the SSH client?
WeTTY (Web TTY) is a Docker container that runs a terminal emulator in the browser. You access it over HTTP/HTTPS, and from inside it you can SSH into other machines on the same network. Since WeTTY and minerva are on the same local network, an SSH connection from WeTTY to minerva is just local traffic — no Tailscale routing involved, no pfSense interference.
The flow became:
- Connect to Tailscale on hephaestus (or just have it running in the background)
- Open a browser, navigate to the WeTTY container via its Tailscale-accessible address
- SSH into minerva from WeTTY
It's one extra hop, but it's invisible in practice. From my laptop, opening a browser and navigating to WeTTY feels no different than opening a terminal — and I get a full SSH session into minerva from anywhere in the world.
What the Setup Looks Like Now
- Tailscale on fireclaw (pfSense) — whole network reachable remotely
- WeTTY in Docker on minerva — browser-based SSH terminal, accessible via Tailscale
- Tailscale on hephaestus — laptop connects to the mesh from anywhere
From my phone I can check Uptime Kuma, manage containers in Portainer, and browse my BookStack wiki. From my laptop I can do all of that plus SSH into minerva via WeTTY for anything that needs a terminal.
It's not a perfect architecture. Ideally I'd resolve the routing conflict properly and SSH directly into minerva. But it works reliably, it's low maintenance, and it solved the actual problem: I can now manage my homelab from anywhere without being tethered to my desk at home.
The Takeaway
Sometimes the clean solution creates new problems, and the workaround is the right answer — at least for now. Homelab work is iterative. The goal isn't a perfect network on paper, it's a network that actually does what you need it to do.
Tailscale made remote access trivially easy. WeTTY filled the one gap Tailscale's pfSense integration left open. Together they gave me something I should have had a long time ago.
Running a similar setup or hit the same pfSense routing issue? I'd love to hear how you solved it in the comments.
Top comments (0)