PiVPN writes a server configuration and a client profile, then exits; it never becomes the process that carries your traffic. So a failed handshake, a client dialing the wrong endpoint, or a service that comes back wrong after a reboot cannot be explained from the installer's menus. Those symptoms belong to whichever OpenVPN daemon is running now, the configuration that daemon actually loaded, and the log it was pointed at. Four read-only commands usually settle it, and none of them changes your certificates or keys.

The helper and the daemon are different objects

The confusion is easy to explain: one directory holds the file the helper generated, the file the daemon reads, and sometimes a stale copy of both. A helper is a provisioning script. It installs packages, writes unit files and prints a client profile, and then its job ends. What remains is a service-manager entry and a command line.

On a systemd host, start from the active unit instead of the directory listing. The name depends on packaging: Debian and Raspberry Pi OS images commonly expose a template instance such as openvpn-server@server, while older installs use openvpn@server. Ask the manager which one is running rather than guessing from a filename.

systemctl list-units --type=service --all | grep -i openvpn
systemctl cat openvpn-server@server

Read ExecStart= in that output. It names the executable and the options the manager actually launches, including any --config path; a configuration file sitting nearby that no command references is not part of the running tunnel.

Follow the configuration chain the daemon resolved

OpenVPN does not scan a directory for settings. It reads the file passed with --config, follows any config directives inside it, and then applies command-line options. The 2.6 manual describes that ordering, and it matters when two files disagree about the port, the device or the cipher.

Dump the effective invocation first, then look at the directives that decide identity and reachability. Both commands are read-only and safe on a live server, though the second prints paths you may not want in a public ticket.

systemctl show -p ExecStart --value openvpn-server@server
grep -E '^(config|dev|proto|port|local|log|log-append|status|ca|cert|key|tls-auth|tls-crypt)' /etc/openvpn/server/server.conf

A .ovpn file in a home directory is a client artifact. The server daemon never reads it, so editing that file to fix a server-side handshake failure accomplishes nothing.

Includes are the other trap. A config line pulls in a second file whose options are processed at that point, so a later single-value directive can override what the main file appears to say. If the visible file looks correct and the daemon still behaves differently, read the included file before changing anything.

Match the log to the process, not to the error you remember

Two logging destinations are common, and only one of them is the journal. With log-append set, the daemon writes to that file and the journal keeps little beyond startup lines. Without it, journalctl is the event source.

journalctl -u openvpn-server@server -n 80 --no-pager

Correlate one connection attempt with one time window. Note the client's endpoint, then read server events from the same seconds. A TLS handshake that never reaches the certificate exchange points at reachability or protocol mismatch, while an authentication rejection arrives after the tunnel parameters are already agreed.

An old log entry proves nothing about a profile you downloaded five minutes ago. Regenerate the client file, reconnect once, and read only the lines that appeared during that attempt.

Record the first specific failure rather than the final generic one. A bind error, an unanswered outer exchange, a certificate rejection and an account rejection each send you to a different layer, and a timeout at the end often hides the useful event above it.

Rebuilding the tunnel is not a diagnostic step

The tempting shortcut is to stand up a second, simpler tunnel: static key, no certificates, no additional authentication. It will often connect, and it proves only that two hosts can pass UDP or TCP between them. It says nothing about why the certificate-authenticated deployment fails, and it quietly replaces the security model you were asked to keep.

The same applies to disabling tls-auth or tls-crypt, loosening verify-x509-name, or dropping a second factor to get a green status. A tunnel that connects because verification was removed is a different system, not a repaired one.

Make one scoped change at the layer the log named, restart the same unit, and repeat the single connection attempt. That keeps the comparison honest, and it leaves a change you can revert.

What to hand to the next person

Write down four facts while you still have them: the OpenVPN version from openvpn --version, the unit that is active, the configuration chain with its includes, and the log window covering one attempt. Those four turn a vague complaint into a reproducible case.

Redact before you share. Private keys, auth-user-pass files, static key material and full client bundles do not belong in a ticket; option names and the shape of the chain are usually enough for a second pair of eyes.

If the chain is intact and the log still points at the network, the next step is the path between client and server rather than another installation. That is the one part of the story the helper never owned.

អត្ថបទពាក់ព័ន្ធ