You have one Pi, one working outbound VPN profile, and two devices that should reach the internet through it. The question that decides the whole build is not which guide to follow but how much containment you need. A single port lets the Pi sit beside those devices on the router's LAN and act as an extra gateway; a second port lets you put them on a segment where the Pi is the only way out. Everything after that choice — DHCP, firewall scope, DNS, the outage case — follows from it.

What the two layouts actually differ in

Both designs route. The difference is who else is standing on the wire and what happens when your policy is wrong.

Layout A: Pi on the ISP LANLayout B: dedicated client port
CablingOne Ethernet port, existing switch portTwo interfaces: uplink plus a separate LAN port
Can a client bypass the Pi?Yes, by using the ISP router as its gatewayNo, unless the device has another radio or link
Who hands out addressesThe ISP router, with a per-client setting or a DHCP optionThe Pi, on its own LAN interface only
Blast radius of a mistakeAny LAN host, if a rule is too broadThe attached segment
Good fit forOne laptop, a console, a temporary test clientAppliances, always-on boxes, untrusted devices

Containment is the real axis. Layout A is advisory: a device that ignores your DHCP-supplied gateway and picks the router still works, unencrypted. Layout B is enforced by topology, because there is no other next hop to choose.

Layout A: the Pi as an extra gateway on the existing LAN

Assume the ISP router is 192.168.50.1, the Pi is 192.168.50.2, and the chosen clients point at the Pi. What matters is that two different packet flows share one cable. The client's inner packet arrives at the Pi and must leave through the tunnel; the Pi's own encrypted packet to the VPN peer must leave through the same cable to the router. They travel in opposite directions over the same interface and need different treatment.

Give the Pi its address through the installed network manager rather than an old interface-file recipe that fights it for the device. Then set the clients: a static gateway on one device, or a DHCP reservation that hands out 192.168.50.2 as router. Do not change the router's whole DHCP scope for two devices, and do not assume a client honours the option — verify it.

The weakness is structural rather than fixable. Any client on that segment can point at 192.168.50.1 and leave in the clear, and a device with a second interface or a cellular radio leaves your enforcement path entirely. If that sentence is unacceptable for the device in question, you already have your answer: use Layout B.

Layout B: a dedicated port fences the devices in

Here the Pi keeps 192.168.50.2 on the uplink with gateway 192.168.50.1, and takes 10.20.0.1/24 on a second interface for the attached devices. The Pi is now a router with two networks, and the attached segment has exactly one exit.

Check the range against everything else before you commit: the tunnel's own subnet, other site-to-site prefixes, and anything reachable through the VPN. A 10.20.0.0/24 that collides with a remote LAN produces the kind of half-working result that takes an evening to diagnose. If the second port is a USB adapter, confirm it is supported and pin its name in the network manager so a reorder after reboot does not move your LAN address.

Run the DHCP listener on that interface only. A server answering on the uplink competes with the ISP router and hands your segment's addresses to the rest of the house. Bind it to the LAN interface, restrict it to the declared range, and keep the Pi's own address off the pool.

Forwarding, translation and the fail-closed rule

Four things are often described as one and are not. Enabling forwarding (net.ipv4.ip_forward=1) only tells the kernel it may move packets between interfaces; it permits nothing by itself and guarantees no path. Selecting the egress is a routing decision. Permitting the packet is a forward-chain policy decision. Rewriting its source is a postrouting decision. A build that only does the first one produces a Pi that happily forwards client traffic out of the uplink.

Scope the permission to the sources you meant and the interface the traffic should use, and include the return path and the Pi's own required destinations. Then translate on the tunnel egress if the provider does not route your LAN prefix back to you. The nftables manual treats forwarding, local output and source translation as separate operations, which is the right mental model here.

The common failure is a broad masquerade rule on the physical interface. Traffic then reaches the internet through the ISP path while looking, from the client side, exactly like a working VPN. It proves nothing. Keep translation tied to the declared egress, and keep your rules in the firewall the host already uses instead of adding a competing ruleset that flushes a shared postrouting chain.

Then handle the absence of the tunnel. A client profile that installs a broad default route also means that when the tunnel drops, the ordinary default can come back and client traffic quietly returns to the uplink. Where cleartext fallback is not acceptable, the forward policy has to deny client-to-uplink traffic explicitly, in the state where the VPN route is gone. Write that as a reject rule, not as an assumption. The Pi's own encrypted transport to the VPN peer is a separate local-output flow and must stay permitted, or the tunnel can never come back.

DNS and IPv6 need their own answer

If clients use the Pi as resolver, they hit a local listener and the Pi originates a new query. That upstream query follows the Pi's own route, not the forwarding rule you wrote for clients, so a tunnel-only client path plus a resolver that egresses directly is a leak with no error message. Decide deliberately: a resolver reached over the tunnel, or a local one you accept as direct, and make the Pi's own output policy match that decision.

IPv6 is separate again. An IPv4 forward rule constrains nothing about IPv6, and router advertisements on the uplink can give the Pi, and through it the attached segment, a second default that bypasses your policy. Either give IPv6 its own protected path on the same principle, or restrict it explicitly on the client segment and say so.

Test the boundary before you trust it

Accept the design only after four separate checks, because the tempting single test — open a browser on one client — passes in several broken states.

Confirm one real client reaches the internet through the tunnel, then confirm the same client cannot reach the internet with the tunnel down. Confirm DNS resolution works and that the query leaves where you intended. Confirm the Pi's own transport still functions after a tunnel restart, and that recovery does not require a reboot. Finally, check a device you did not select: under Layout A it should keep working normally, and under Layout B it should not exist on that segment at all.

  • Two ports and a deny rule give enforcement; one port and a DHCP option give advice.
  • Translation on the wrong interface looks like success and is not.
  • The Pi's own traffic, DNS and IPv6 each need a decision, not an inference.

Allakkat attuumassuteqartut