The application answers on its tunnel address, and the address you documented for it goes nowhere. Nothing in the OpenVPN log complains, the peer shows connected, and the hub lists exactly one client. The gap is that a second address on a client is two separate facts: the host must own it, and the hub must know which peer owns it. Handle one without the other and traffic either dies at the hub or arrives with no route home.

The alias is local, the ownership is remote

A tunnel address is negotiated, so both ends learn it during the handshake. An extra service address is not negotiated at all, which is why adding it changes nothing on the hub by itself. The client can own the address immediately and the server will still send that traffic to its default path or drop it. Two records have to be created, in two different places.

On the client, the address belongs to the host, and loopback is the natural home for a service identity that should never appear on a physical link. On the hub, the peer-to-prefix mapping is a separate declaration that only the server reads. Neither record implies the other.

Keep the two ranges distinct in your notes as well. Addresses in an example are documentation values, and overlapping them with a real LAN is the quickest way to make a working setup look broken.

Add the address on the client, persistently

Place the service address on loopback with a host prefix, so the host treats it as local input rather than as a subnet to reach. ip address add 10.66.0.10/32 dev lo does that for one address, and repeating the command for a second address models two services.

Run that as a one-off test, then move it into whatever owns the host's network configuration, because a runtime addition disappears on reboot and duplicates accumulate across reconnects. A systemd unit ordered after the network is one option, and a distribution network manager is another. Whichever you pick, the address must exist before the application binds, or the service comes up on the wrong socket. Verify with ip address show dev lo after a reboot rather than after the manual command.

Binding is a separate decision from addressing. An application that listens on every address accepts traffic on interfaces you never intended, so point it at the specific service address. Local input policy then has something precise to match.

Claim it in the CCD file the hub actually reads

On the server, the ownership declaration goes in the per-client file selected by the authenticated common name, inside the directory named by client-config-dir. The line is iroute 10.66.0.10 255.255.255.255, one per address, and it tells the server which peer should receive traffic for that destination.

Two details break this quietly. The filename must match the name the server really uses, which differs when username-as-common-name is in play. And iroute only takes effect in TUN mode with a client configuration directory configured, so the same line does nothing in a bridged deployment. Add lines to the existing file rather than replacing it, since it may already carry a fixed address or push options. The OpenVPN 2.6 reference documents both the directory and the ownership directive.

The hub's own kernel also needs a path to those destinations so locally generated traffic enters the tunnel process. route 10.66.0.10 255.255.255.255 in the server configuration covers traffic the server originates, while other clients need push "route 10.66.0.10 255.255.255.255" to learn the destination themselves.

Routing and authorization stay separate. A pushed route tells a client where to send packets and grants nothing; the service still has to accept the caller on its own terms.

Check input policy and the reply path

A packet addressed to the alias arrives at the owning host as local input, so the question is whether the local firewall permits that source and port. Allow the specific service port from the VPN source range instead of opening the whole address.

Replies need a route back to the caller. For a caller inside the normal tunnel pool that path already exists, because the tunnel device carries it. A caller behind another routed network needs that network's return route as well, and this is where asymmetric setups lose packets.

Watch for a second listener on the same port bound to a different address, because the kernel delivers to whichever socket matches and the results look random. Check with ss -lntp and confirm the bound address is the service alias. Source NAT is not required here, and adding it hides the caller identity your logs depend on.

Test addresses and ownership separately

Test in two steps. First confirm the owning host can reach the service on its alias from itself, which separates bind and firewall problems from routing. Then test from a real VPN caller using the application's own authentication. When the first passes and the second fails, the missing piece is on the hub side.

Check the failure modes that outlive a connection too: the alias stays assigned when the tunnel is down, and the hub keeps its route when the peer is absent. Neither object alone proves the service is reachable, which is why the two-step test beats a single ping from a laptop.

Makomi ya ndenge moko