Two OpenVPN processes run on a Pi that both admits roaming users and reaches an upstream provider, and they share almost nothing beyond the hardware. One listens for inbound tunnels while the other dials out. Each reads its own directory, and each has its own failure mode. Restarting the wrong one is the most common way a "client fix" ends up bouncing the listener instead.

Match the unit name to the directory it loads

Upstream 2.6 ships two template units, [email protected] and [email protected]. The server template starts in /etc/openvpn/server and loads %i.conf from there. The client template starts in /etc/openvpn/client. An instance named roaming can exist in both places at once, as a server and as a client, with two unrelated configurations and no link between them beyond the string.

Ask systemd instead of the filesystem, because packagers add drop-ins that can change the working directory or the arguments the binary receives.

systemctl list-units --type=service 'openvpn-*@*'
systemctl cat [email protected]
systemctl show -p WorkingDirectory -p ExecStart [email protected]

The first command lists every instantiated unit, including the ones that failed and stayed loaded. The second prints the unit file together with any override. The third is the fastest way to see the two facts that decide the question: the directory the process starts in, and the configuration path it was handed.

Decide by packet direction, not by interface name

A server instance owns a listening socket and accepts connections. Its encrypted transport is local input and local output on the Pi, while the traffic it forwards for users follows the forwarding path and answers to a different set of rules. A client instance owns no listener in that sense: it dials a peer, so its encrypted transport is local output toward the underlay.

That difference tells you where a rule belongs. A rule matching an interface inside a forward chain only permits traffic that routing already selected; it never selects the route. When a roaming user's packets leave through the wrong path, the chain to inspect is forward, not output.

Look at sockets before theorising. A server bound to udp/1194 shows a listening socket. The client shows an association to the provider's address and nothing listening at all.

ss -lunp | grep openvpn
ss -unp state established '( dport = :1194 or sport = :1194 )'

One instance's default route can capture the other's replies

A redirect-gateway pushed by the upstream client installs a default route that competes with everything else on the box, including the replies the server sends to roaming users. OpenVPN carves out an exception for its own peer address so the tunnel stays reachable, but that exception says nothing about a phone sitting on a hotel network.

The symptom is usually asymmetric. The handshake completes, the client reports connected, and traffic dies after the first reply packet. Source-based policy routing, or a packet mark set on the server instance with --mark, keeps the two flows apart; neither is a complete rule set by itself, and both need valid routes in whichever table they select.

Test the local decision rather than the tunnel state, since the kernel picks the source and interface before OpenVPN sees the packet.

ip route get 203.0.113.44
ip rule show

Restart one role and prove the other survived

Order matters when both roles depend on the same underlay. Restart the client first if the upstream route has to exist before user traffic can be forwarded, and restart the server first when you are only changing its listener or its pool. Either way, confirm both units afterwards, because a failed restart can leave the other role running against stale state.

Write the stop condition down before the change: does losing the upstream tunnel block roaming users, or fall back to the Pi's own uplink? DNS and IPv6 need an explicit answer as well, since a pushed resolver often outlives the route that made it useful.

systemctl restart [email protected]
systemctl is-active [email protected]
journalctl -u [email protected] -n 20 --no-pager

Accept the change only when three things hold at once: a new inbound connection completes, a forwarded application reaches its destination through the intended exit, and both processes still report their expected peer. If one of the three fails, you changed the wrong instance or the wrong route, and the next step is to re-read the unit rather than to restart anything else.

Artaigilean co-cheangailte