I moved a home VPN box from Wi-Fi to Ethernet and its “permanent” address changed the same evening. Nothing on the router was broken. The reservation had been matching the wireless adapter, and that adapter was no longer in the path.

There is a second half to the same misconception. Fixing the LAN address does nothing for the address your friends connect to, and it has nothing to do with the private pool the VPN hands to clients. Three addresses, three separate failure modes, and only one of them is a reservation’s job.

A reservation matches a client, not a device

In DHCPv4 the reservation is keyed on the client’s hardware address; in DHCPv6 it is keyed on a DUID the client is expected to keep. The hostname field is a label for humans. What the router actually compares is the identifier that arrives in the request.

Read the entry as a conditional: when this identifier asks, hand it this address. Renewals keep the same lease while the match holds, and a reboot just asks again. When the identifier changes, the request misses the reservation and the client takes whatever the dynamic pool offers. No error, no warning, just a different address.

OpenWrt shows the shape plainly. One config host block in /etc/config/dhcp ties a name, a MAC and an address together, and the static lease documentation covers how that entry interacts with the pool. Other routers hide the same three fields behind different labels.

Where the match quietly falls through

Swapping hardware is the common case. Change the NIC, or move the machine between Ethernet and Wi-Fi, and the address the router sees changes with it. The old reservation stays in the list, still looking correct.

A reinstall is the second case, and it bites hardest on IPv6. A fresh install can generate a new DUID while the old IPv4 lease is still valid, so the v4 address survives for a while and the v6 entry stops applying without any visible edit.

Third is a pinned client identifier. Several DHCP clients let you set an identifier string instead of using the MAC. If an upgrade or a config rewrite drops that setting, the match disappears even though the machine did not move.

Fourth is duplication: a stale block and a new block for the same host. The server answers with whichever rule matches, often the pool address you were trying to avoid. Delete the stale entry instead of adding a second one.

Host-side configuration and what it costs

Setting the address on the host removes the matching question entirely. The interface comes up with that address whether or not DHCP answers, which is what you want from a machine that has to be reachable after a router reboot.

The cost is ownership. You now supply the prefix, the gateway and the resolvers, and you must keep the address outside the dynamic pool yourself. On Ubuntu with netplan, /etc/netplan/01-vpn.yaml carries it:

network:
  version: 2
  ethernets:
    eth0:
      dhcp4: false
      addresses: [192.168.50.10/24]
      routes:
        - to: default
          via: 192.168.50.1
      nameservers:
        addresses: [192.168.50.1]

NetworkManager users reach the same state with nmcli con mod "Wired connection 1" ipv4.method manual ipv4.addresses 192.168.50.10/24 ipv4.gateway 192.168.50.1, then nmcli con up "Wired connection 1". Apply netplan with netplan try on the first attempt rather than netplan apply; a mistyped gateway takes the box off the network and leaves you reaching for a console.

Keep a matching reservation anyway. It is not redundant. The entry records the address on the router side and stops the DHCP server from handing that address to a guest device if someone widens the pool later.

A stable LAN address is not a public endpoint

Point the port forward at 192.168.50.10 and the rule survives every LAN-side change. It does not give you a stable internet address. Your public IP belongs to the ISP and can move on a reconnect or a modem swap, which is what dynamic DNS is for.

Behind carrier-grade NAT there is no public IPv4 to forward at all, and no reservation creates one. Check the router’s WAN page before anything else: if the address sits in a shared range, inbound forwarding cannot work no matter how clean the reservation is.

The third address is the tunnel pool, often something like 10.8.0.0/24. Those addresses exist only inside the tunnel and never appear on the LAN. Confusing them with the server’s LAN address is how a port ends up forwarded to a client that is online only while it is connected.

Check the path in the order it breaks

Start on the router. Compare the lease table entry against the reservation’s target; if the server took a pool address, the identifier is wrong, and ip link show on the host gives you the value to compare.

Then the host. ip -4 addr show eth0 should report the expected address and prefix. A second address on the same interface usually means DHCP is still running next to your static configuration.

Then the forward. Confirm the destination still equals the address you just verified, and confirm something is listening with ss -lntp. A forward aimed at a closed port looks exactly like a broken forward from outside.

Finish from outside, on a phone with Wi-Fi off. That one test separates “the local address is wrong” from “public reachability is broken”, the two problems this setup keeps mixing together.

Write the three addresses down, LAN, public and tunnel pool, and note which system owns each. When a connection fails next month you will know which one to inspect instead of changing all three at once.

Qillqakuna t'inkisqa