Homelab Rebuild Part 11: The Way In From Outside

What this is about Link to heading

After part 10 the segmentation stands. Every device sits in its network, and between the networks only what I allowed gets through. What’s missing is the way in from outside โ€” so that in someone else’s wifi I don’t have to rely on the operator knowing what they’re doing.

WireGuard is the obvious choice: a few lines of configuration, one UDP port, no certificate management. The interesting part isn’t the setup, it’s the question that comes before it.

A VPN client is just another device on a network. Which one?

That’s why this comes only now. Before parts 9 and 10 I’d have had no answer beyond “the main network, like everything else” โ€” and that is exactly what I set out to get rid of.

The question I got stuck on Link to heading

Three clients: my laptop, my phone, and an access for a family member. For two of them the answer came quickly โ€” both only need the way out to the internet, no access inward.

The laptop is where I got stuck. It feels like it belongs in my trusted VLAN; that’s where it lives at home, after all. And still it didn’t sit right.

The reason, which I could only phrase properly while writing this: the laptop in the living room and the laptop on hotel wifi are not the same device. Physically yes, in terms of trust no. Between those two states lie two weeks on foreign networks, an airport, and the possibility of it going missing. If the tunnel carries the same rights as the cable at home, then it is the shortcut past everything part 10 built.

There’s a technical argument on top: a VPN client gets an address from the tunnel, but no VLAN tag. Actually placing it in an existing VLAN would need bridging. Pretending via rules is possible โ€” but then you maintain two rule sets that will certainly drift apart.

So the tunnel gets its own network, 10.0.60.0/24, deliberately outside the VLAN numbering, because it isn’t a VLAN on the switch. And rights aren’t granted per network but per tunnel address:

Client Address Access inward
Phone 10.0.60.4 none
Family member 10.0.60.2 none
Laptop 10.0.60.3 firewall, virtualisation host, access point

That works because the tunnel address is bound to a key. Unlike a MAC it can’t simply be claimed โ€” and that is exactly what you have to get right during setup, more on which below.

The endpoint: an address that changes every couple of years Link to heading

My connection has a fixed address, but only semi-fixed โ€” every one or two years it changes. Rare enough to forget, frequent enough that all client profiles eventually point nowhere.

I already had a solution for this, and it was a good example of how homemade fixes age. A script on the router called a URL on my web server with its own address as a parameter. A second script fished it out of the Apache log with grep and wrote it into a text file.

Two problems with that, and only one of them was on my radar:

It hadn’t worked at all since the rebuild. The script read the address off sfp-wan on the access point. Since that box went from router back to switch, that port is the trunk to the firewall and carries no public address. The script kept running, it just found nothing.

And a text file doesn’t help WireGuard. The client holds an Endpoint, which is resolved when the connection is established. What you need is an A record that changes โ€” then clients re-resolve by themselves after a failed handshake. A file containing the right address has to be read by a human and copied into three profiles.

The replacement was unspectacular: the os-ddclient plugin on the firewall, an API token at the DNS provider, a subdomain record with a short TTL. The firewall knows its own public address, so the whole detour via logfile and third-party server falls away.

The lesson: the homemade fix wasn’t the problem, the problem was that it broke silently. A script that finds nothing and still exits with status 0 never reports in.

One field, two meanings Link to heading

Before the mistakes, the one concept you have to have understood.

The same AllowedIPs field means, on the server side, which source address is accepted from a given key, and on the client side, which traffic is sent through the tunnel.

The most common stumbling block in WireGuard, and it goes by the same name in both configurations.

On the firewall, AllowedIPs is the binding of key to address. With 10.0.60.4/32 in there, WireGuard accepts from that key only packets carrying exactly that source address. Enter a whole network generously and one peer could impersonate another โ€” and every rule resting on a single tunnel IP becomes worthless.

In the client profile the same field means something entirely different, namely which traffic the client sends through the tunnel. 0.0.0.0/0 means everything. That’s the full tunnel, and it’s what I want here, because the whole point is not having to trust someone else’s wifi.

You can configure both sides correctly without knowing the difference. Right up until you start building per-client rules โ€” at which point their effectiveness hangs on the server side of that field.

What went wrong Link to heading

Four things, and three of them had the same symptom.

The switch that exists twice Link to heading

Instance created, three peers created, peers assigned to the instance, saved, applied. In the status view: nothing. wg show produced no output, the interface didn’t exist at all.

The reason was at the bottom of the same page: a global Enable WireGuard, independent of whether the instance itself is enabled. Two checkboxes with the same meaning on two levels, and I had ticked the upper one.

The interface that isn’t one Link to heading

Even after enabling it you can’t build a firewall rule. The tunnel exists, but not as an interface in the firewall’s sense โ€” for that it has to be assigned under Interfaces โ†’ Assignments. Only then does a tab appear under Firewall โ†’ Rules.

Two traps while assigning: the IPv4 configuration stays on None, because the tunnel address is managed by WireGuard itself โ€” enter it again here and you have two interfaces in the same subnet. And block private networks must stay off, because the tunnel carries nothing but private addresses.

The key I didn’t carry over Link to heading

The most interesting mistake, because it disguised itself as a network problem.

Phone connected over mobile data, DNS name resolved correctly, port was right. On the client: a few kilobytes sent, zero received. On the firewall, all three peers: zero received.

The capture on the WAN showed the packets arriving. The hit counter on the WAN rule was counting. And wg show stayed at zero.

The cause: I had carried over the clients’ public keys from the old configuration โ€” those were fine. What I hadn’t carried over was the server’s public key. It was generated fresh when the instance was created, while the client profiles still held the one from the old router.

So the phone was encrypting its handshake for a recipient that doesn’t exist. WireGuard couldn’t decrypt the packet and dropped it without comment โ€” no log, no counter, no error.

The rule in the wrong place Link to heading

And finally the mistake from part 10 in new clothing. I wanted to watch TV over the tunnel too; for that I run a small service that translates the IPTV multicast into an ordinary HTTP stream.

The rule for it existed and access was blocked anyway. It sat below the block rule against private networks โ€” and the target is a private address. Moved up, and it worked.

At least I saw it immediately, because the block rule logs. That’s the checkbox I set in part 10, paying off here for the first time.

The rule of thumb Link to heading

WireGuard stays silent for every failure alike. Wrong key, wrong endpoint, blocked packet, service not started โ€” the symptom is always that nothing happens. There is no “connection refused” and no error in the log.

That’s a design decision in the protocol, not sloppiness: WireGuard never replies to packets it can’t attribute. From outside the port looks closed, and a scanner learns nothing about what’s listening there.

For troubleshooting that means guessing doesn’t work, because every cause looks the same. You check from the outside in and see where the chain breaks.

Four checkpoints from the outside in: packet capture on the WAN, hit counter of the WAN rule, received bytes in wg show, and the latest handshake. Wherever the chain breaks names the cause.

Four steps, four possible causes. Mine broke between 2 and 3 โ€” the firewall was counting hits, WireGuard wasn’t.

That combination was exactly the key mistake: the packet filter sees the packet and lets it through, the service can’t decrypt it. Anyone working from “it doesn’t work” alone would probably keep fiddling with firewall rules at that point.

Where I stand now Link to heading

The tunnel runs, tested on the phone over mobile data. Full tunnel, DNS via my own firewall, IPTV working. The phone and the family member’s access reach the internet and nothing internal โ€” the same chain of four as in part 10, with one rule for a single host inserted in the middle.

From outside, exactly one UDP port is open, and it only answers packets carrying a valid signature.

Two things stay open:

The laptop. It gets set up tomorrow. Its rule currently sits wide, but with logging โ€” the same method as the receiver in part 10: do everything you’d typically do while travelling, then read the real targets and ports off the log and narrow it down. That’s more honest than guessing now which ports the management interfaces actually need.

The emergency access stays out. Besides its regular address, my access point has a recovery interface in its own subnet with no connection to the rest โ€” the way out after two lockouts back in part 3. It isn’t reachable over the tunnel, and it should stay that way. Which does mean: if I lock myself out, the VPN won’t help. That still takes a cable and being there in person.

And one side note for the record: my IPTV channel list still contains addresses from before the rebuild. Over the tunnel each of those entries runs into a timeout before the player tries the next one. Cleaning that up is pending.

Next step Link to heading

With the tunnel, the network side is together for now. What comes next is a different layer: identity. Right now every service has its own user management, and that scales about as well as a flat network.


Part of a series about rebuilding my home network. Status: September 2026. Questions, corrections and your own experiences are welcome in the comments.