Logo

dev-resources.site

for different kinds of informations.

Auto OpenVPN reconnect and killswitch for VPNs with dynamic IPs

Published at
10/2/2021
Categories
openvpn
vpn
security
linux
Author
nullabletype
Categories
4 categories in total
openvpn
open
vpn
open
security
open
linux
open
Author
12 person written this
nullabletype
open
Auto OpenVPN reconnect and killswitch for VPNs with dynamic IPs

The Problem

If you’re like me and run a home Linux server, you may wish to add some extra security in the form of a VPN connection to ensure traffic is encrypted. In my case, I use a Raspberry Pi to backup things like RAW images from my camera to an off-site location. The extra security gives me a little peace of mind, especially as the server generally uses a cellular connection.

I’ve been using UFW to work as a killswitch and only allow traffic via the VPN connection, but one issue I've had is with my trusted VPN provider is that they regularly rotate IP addresses. UFW uses iptables under the hood, meaning it can only be configured to use IP addresses explicitly and not a domain name. This has left my backup machine without an internet connection fairly frequently.

The Solution

Just to set this straight from the start, I’m no UNIX genius. I spend most of my time working with Windows machines and use Linux more as a hobbyist. That been said, I’ve written my fair share of code/scripts.

My solution is pretty simple; when disconnects happen:

  1. fetch a fresh list of IP’s from my internal DNS server.
  2. Update UFW .
  3. Update the OpenVPNconnection file and reconnect.

I thought I’d share my approach, as I failed finding any other solution online so this may be of help to others.

The first part is fetching the list of domains. To do this, I use dig.

ipoutput=$(dig $1 +short)

if [ -z “$ipoutput” ]; then  
  echo “No ips found for $1”  
  exit 1  
fi

echo “Found ips $ipoutput”

readarray -t ips <<<”$ipoutput”
Enter fullscreen mode Exit fullscreen mode

This gives me a nice list of IP address for the specified domain.

Now I know the correct ip addresses, I need to make use of them. The first job is to update UFW. I decided to use a template file so I can set it up as I want for each machine. This may not be the most elegant solution, but its pretty flexible.

ufwoutput=’’

for i in “${ips[@]}”  
do  
  :  
  ufwoutput+=$”### tuple ### allow udp any $i any 0.0.0.0\\/0 out\\n”  
  ufwoutput+=$”-A ufw-user-output -p udp -d $i -j ACCEPT\\n\\n”  
done

if test -f “$dir_path/user.rules.tmp”; then  
  echo “Deleting tmp file…”  
  rm “$dir_path/user.rules.tmp”  
fi

cp “$dir_path/user.rules.template” “$dir_path/user.rules.tmp”

sed -i -e “s/\[content\]/${ufwoutput}/g” “$dir_path/user.rules.tmp” “$dir_path/user.rules.tmp”

mv “$dir_path/user.rules.tmp” /etc/ufw/user.rules

echo “Reloading ufw”  
ufw reload
Enter fullscreen mode Exit fullscreen mode

The script builds up a string containing the correct formatted lines for the user.rules file for UFW, creates a new copy of the template, replaces [content] in the file using sed then moves the file into the correct place (for ubuntu). The final thing to do is ufw reload to reload the user.rules file.

That’s UFW taken care of, time for OpenVPN using a similar method

openvpnoutput=’’

for i in “${ips[@]}”  
do  
:  
  openvpnoutput+=$”remote $i 1198\\n”  
done

if test -f “$dir_path/openvpn.ovpn.tmp”; then  
  echo “Deleting tmp file…”  
  rm “$dir_path/openvpn.ovpn.tmp”  
fi

cp “$dir_path/openvpn.ovpn.template” “$dir_path/openvpn.ovpn.tmp”

sed -i -e “s/\[content\]/${openvpnoutput}/g” “$dir_path/openvpn.ovpn.tmp” “$dir_path/openvpn.ovpn.tmp”

mv “$dir_path/openvpn.ovpn.tmp” “openvpn.ovpn”
Enter fullscreen mode Exit fullscreen mode

This works in a similar way to the UFW code, replacing a [content] placeholder in the .opvn template file.

So that’s all the code to update UFW and OpenVPN. The next thing to do is to manage the connection. I do this via a simple script called from a cron job.

function getStatus () {  
  echo “Attempting to get device status…”  
  ip address show | grep $1 && return 1  
  return 0  
}
Enter fullscreen mode Exit fullscreen mode

This is a pretty straightforward function. grep the output from ip address show to see if the OpenVPN connection is live. Return either 1for success or 0for failure.

The last thing to do is to check the result and connect if required.

getStatus $device  
if [[ $? == 0 ]]; then  
  echo “openvpn is not connected!”  
  echo “Reconnecting!”

  #Update config  
  updateIps $domain &> $dir_path/renew.out &disown

  openvpn — config “$dir_path/openvpn.ovpn” &>$dir_path/out.out &disown  
else  
  echo “openvpn is connected!”  
fi
Enter fullscreen mode Exit fullscreen mode

If the output from getStatus is 0, then it will call to update the IP addresses and trigger a new OpenVPN connection with &disown to not wait for the connection to exit.

Now that’s all in place, all that’s needed to run the script automatically is a cron job to check as frequently as you wish.

*/1 * * * * cd /home/account/openvpn && ./auto-connect.sh “my.vpn.domain” “tun0” > out.out
Enter fullscreen mode Exit fullscreen mode

If this is useful to you, rather than having to copy & paste the code I’ve wrapped all this up into a single script available on GitHub.

Wrap Up

As I say, I’m no Linux sysadmin but this script solves a problem for me and has been working well for the last few months. If anyone has any suggestions for improvements or comments I’d love to hear them. Even better, fork the repo on GitHub and pop in a merge request ❤

openvpn Article's
30 articles in total
Favicon
Fixing OpenVPN Connection Issues in Ubuntu 24.04
Favicon
AWS Verified Access preview non-review!
Favicon
How to Install a Private OpenVPN Server on Ubuntu 22.04
Favicon
Building an Ephemeral VPN Solution
Favicon
OpenVPN configuration for Tunnelbear in Windows
Favicon
Cómo montar una VPN rápido y sin complicaciones donde quieras
Favicon
AT1 has changed IP
Favicon
DE2 migration
Favicon
OpenVPN + SSO via OAUTH2
Favicon
New servers in Germany and Poland
Favicon
FR1 migration
Favicon
JP1 has changed datacenter
Favicon
Changing IP of LV1
Favicon
New Telegram contact
Favicon
Compiling OpenVPN in an Ubuntu 14.04 Chroot
Favicon
Why you should not use WireGuard
Favicon
Configurando o OpenVPN 2.4.7 no Ubuntu 23.04
Favicon
Local port forwarding using shadowsocks-rust + openvpn over shadowsocks
Favicon
Fixing OpenVPN3 bug in Arch
Favicon
Version 1 Terraform AWS OpenVPN Ephemeral Released!
Favicon
Connect to an OpenVPN server running on Synology DSM 7
Favicon
Configure OpenVPN server on Synology DSM 7
Favicon
How To Set Up an OpenVPN Server on Linux Server (Ubuntu)
Favicon
OpenVPN Server: Assigning Static IP Addresses Via A Script
Favicon
Install VPN (OpenVPN) Server on AWS EC2 Instance (Ubuntu)
Favicon
Open Vpn
Favicon
How to connect to the NETGEAR BR500 router using OpenVPN-GUI on Windows
Favicon
Installing and auto connecting to OpenVPN at startup on Gnome/Linux
Favicon
Auto OpenVPN reconnect and killswitch for VPNs with dynamic IPs
Favicon
Site to Site VPN for Google Kubernetes Engine

Featured ones: