A client connects to one of several OpenVPN servers and then needs a small service that runs on that node: a status page, a metrics endpoint, a backup agent. Giving every node the same private service address makes the client's configuration identical regardless of which server it landed on. That convenience is real, and it is also easy to over-read: the shared address tells you which node you reached, not that anything is redundant.

Why the same address on every node works

Each node owns the address locally and answers for it, so a client that reaches it through its current tunnel gets the service on the far end of that tunnel. Nothing is coordinated between nodes, and no traffic crosses from one node to another.

The address is a local label, repeated rather than replicated. Each node answers only for itself, and none of them forwards traffic for the address on another node's behalf. That is what keeps one client configuration valid while the servers stay independent. It is also why the design needs no coordination between the nodes.

That is why the same configuration works on every server without a routing protocol between them. It is also why the design says nothing about health: the address exists on an unhealthy node exactly as it does on a healthy one, because it is bound to the host rather than to the service being useful.

Assign it to loopback, not to the tunnel

Putting the address on a loopback interface decouples it from the lifetime of any tunnel device, so a reconnect or a configuration reload does not remove it. The address exists as long as the host does.

An address on lo is not a filter. The service still has to listen on it, and the host firewall still evaluates the real incoming path, which arrives on the tunnel interface. Anyone who assumes loopback means local-only ends up either blocking legitimate clients or exposing something they did not intend.

Persist the assignment through the host's network configuration rather than re-adding it from a hook. A setup hook will not fire on a node where no tunnel came up, and the service address should not depend on tunnel activity. Put the address in the interface configuration your distribution owns, then reboot once and check it. A reboot is the only test that survives a later configuration change.

ip address show dev lo | grep 10.250.0.1
ip address add 10.250.0.1/32 dev lo

Push one route and mean one destination

The client needs a host route for the address, offered by the server it connects to. Because every server offers the same destination, the profile does not change when the client moves.

Verify what the client installed before blaming the service.

ip route get 10.250.0.1

For an HTTP service, give the address a name and a certificate for that name. The shared IP is not an identity, and it does not remove TLS verification, nor does it justify copying one private key to every node. A name that resolves to the shared address keeps the certificate story ordinary and lets you keep a per-node identity if you need one.

What the shared address cannot do

It does not provide failover. If the selected node dies, the address dies with it, and the client has to reconnect somewhere else.

It does not migrate a live TCP session, because a new connection terminates at a different host with no knowledge of the old one.

It does not choose a healthy node, balance load, or synchronize data between nodes. Each of those is a separate mechanism with its own failure modes, and pretending the addressing trick covers them is how a simple design acquires an undeserved reputation for resilience. If two tunnels are active at once, the meaning of the destination becomes ambiguous, so keep the one-active-tunnel assumption explicit.

Keep the service identity with the name

Write down what the address means: it reaches the service on the node the client is currently connected to. That single sentence prevents most of the misunderstanding this pattern attracts.

Then document the pieces together: the address, the interface it lives on, the route the server pushes, and the name and certificate the service presents. Four small facts that a future reader can verify, in the order they will check them.

If the requirement is a stable destination for a node-local service, the pattern fits and costs almost nothing.

If the requirement is availability, move up a layer: a load balancer, a service name with health checks, or an orchestration system that already knows how to replace a node.

Deciding that early keeps the shared address what it is, a convenient label, instead of a component quietly expected to do work it was never designed for.

Amanqephe ahlobene