Put a reconnect command in the sleep hook and the problem looks solved. It is solved only if the hook runs after the network exists, as an identity the client recognises, through a path the client actually implements. Most failures after resume are one of those three, and none of them appears as an error in the hook itself. The hook returns success either way.

A script that exits zero has told you nothing about whether a tunnel came back.

The Hook Runs, and Then What?

#!/bin/sh
case "$1" in
  pre)
    vpn-client disconnect
    ;;
  post)
    vpn-client connect
    ;;
esac

Each event invokes the hook twice, ahead of and behind the transition, handing it the phase and the event name. It runs as root with a minimal environment, so absolute paths are necessary and no desktop session variable should be expected. Both invocations returning quickly says only that the script ran. Whether the profile came up afterwards is a separate observation and needs its own evidence in the log.

Treat the phase argument as part of the design. A reconnect attempt in the pre phase happens while the machine is about to lose everything, and it cannot succeed.

Root, Minimal Environment, Wrong User

Should the client keep its login token per user, running the hook as root leaves it with nothing to present. Check the state under the identity the hook actually uses, not the one you tested from a desktop terminal. Some builds also leave a daemon holding the interface after a disconnect, so a reconnect lands in a stale state, and clearing the process first restores it at the cost of an unclean shutdown. Neither behaviour is visible if you only test the happy path.

Write the hook with absolute paths, keep it owned by root and executable, and log what it did. Without that log the next investigation starts from zero.

Autoconnect Is Not the VPN Path

NetworkManager offers two activation mechanisms: an autoconnect flag on the profile, and secondary connections that start when a primary profile activates. Native device types implement the first; VPN plugins have historically implemented only the second, so ticking autoconnect on an OpenVPN profile can have no effect at all. Inspect both properties, then attach the VPN as a secondary of the Wi-Fi or Ethernet profile instead.

[Unit]
PartOf=NetworkManager.service
Requires=NetworkManager-wait-online.service
After=NetworkManager-wait-online.service

A WireGuard interface managed by a systemd unit needs that drop-in rather than a hook, ordered after the network is online.

Wait for the Network, With a Ceiling

timer=1
while ! ping -c1 -n -w1 203.0.113.1 >/dev/null; do
  sleep 1; timer=$((timer+1))
  [ $timer -ge 300 ] && exit 0
done
nmcli connection up "work-vpn"

On resume the tunnel may be asked for while Wi-Fi is still reassociating, which makes any fixed sleep a guess. Wait for a reachable address, then bring the profile up, and cap the wait so a hook cannot hold the resume path open indefinitely. Prefer the profile name over a numeric index, and if the correct profile varies by network, have the healthy tunnel record its choice to a file beforehand.

Guard against restart storms too, by counting attempts and stopping. A watchdog that reacts to every failed probe turns one outage into a loop.

Suspend once, then read the journal for the hook's own output. That is the only test that proves the ordering.

مۇناسىۋەتلىك ماقالىلەر