WireGuard Keepalive 1.0.1 (FreeBSD Jail Edition)


WireGuard Keepalive 1.0.1 (FreeBSD Jail Edition)
“Keep your WireGuard VPN connection alive in a jail!”

Don’t you wish you could just leave your WireGuard connection unattended in your jail?

Sadly, not everything is in your control, such as…

:confused: …sometimes your VPN service provider might face an issue on their end.

:frowning_face: …sometimes your connection goes down for whatever reason.

:cry: …sometimes it’s been a while since the last successful handshake.

This simple script (combined with a cron job that runs every 10 minutes in your jail) will automatically restart your WireGuard connection if something goes wrong in your absence. It should work with any WireGuard VPN provider that can be natively used in FreeBSD or Linux, such as Mullvad, Proton, Azire, Air, etc.


  1. You have a working WireGuard VPN with valid config files.
  2. You are only using a single active WireGuard connection. (This does not work with multiple simultaneous Wireguard connections.)
  3. You have configured and enabled the wireguard service and desired interface in /etc/rc.conf
  4. You create a cron job under the root user. (See the included example.)

Everything is done in the jail. Nothing is done on the TrueNAS host.

Contents of /root/.bin/wg-keepalive.sh


# WireGuard Keepalive, FreeBSD Jail Edition

# wg-keepalive.sh
# Version: 1.0.1

# Checks if the interface is inactive or hasn't had a successful handshake since 10 minutes.
# Restarts the wireguard service if *either* of the above are true.

# This assumes only a *single* active WireGuard connection.
# It does not work for *multiple* active connections.

# Events are logged under /var/log/wg-keepalive-events.log
# This script should be placed under /root/.bin/wg-keepalive.sh
# You *must* have your WireGuard VPN configured.
# You *must* have the WireGuard service and desired tunnel enabled in /etc/rc.conf

# A complimentary cron job must exist for the root user.
# Here is an example cron job entry that checks every 10 minutes:
# */10 * * * * /root/.bin/wg-keepalive.sh



# Check if WireGuard interface is active

if [ -z "$WGINTERFACE" ]
        # Activate wireguard interface and log it
        echo -e "`date +%Y-%m-%d-%H-%M`: Restarting WireGuard service. Interface was not active.\n" >> /var/log/wg-keepalive-events.log
        service wireguard restart
        exit 1

# Compare the current time (in seconds) to the latest handshake
LATESTHANDSHAKE=$(echo "`date +%s` - `wg show all latest-handshakes | cut -f3`" | bc)

# Check if latest handshake is longer than 10 minutes (600 seconds)
if [ "$LATESTHANDSHAKE" -gt 600 ]
        # If longer than 10 minutes, restart the WireGuard service and log it
        echo -e "`date +%Y-%m-%d-%H-%M`: Restarting WireGuard service. No handshake since $LATESTHANDSHAKE seconds ago.\n" >> /var/log/wg-keepalive-events.log
        service wireguard restart
        exit 1
        # If shorter than 10 minutes, do nothing and exit
        exit 0

### SCRIPT END ###

An example of a cron job that automatically runs this script every 10 minutes:

root user's crontab
*/10 * * * * /root/.bin/wg-keepalive.sh

This is a sample of what the logfile /var/log/wg-keepalive-events.log contains after logging some events:

2023-11-08-04-00: Restarting wireguard service. No handshake since 766 seconds ago.

2023-11-08-05-00: Restarting wireguard service. Interface was not active.

2023-11-08-06-00: Restarting wireguard service. Interface was not active.

Currently tested and used on TrueNAS Core 13.0-U6.1 in a FreeBSD 13.2-RELEASE-p11 jail, as of April 3, 2024.

* Even though this was made for FreeBSD, it is possible to modify it to work under Linux.

** This is independent of and unrelated to the “PersistentKeepalive” option in a WireGuard .conf file.