IPSec Site to Site VPN With Dynamic IPs With Openswan
In this tutorial we will setup a site to site ipsec vpn with strongswan and we will enable each server to discover the other vpn server via dynamic dns. We will also append to our config the ability of roadwarriors so that you will be able to connect to your homelab from any mobile or laptop device from any remote source.
Some background
Me and one of my friends decided to build a site to site vpn with strongswan so that our homelabs could be reachable to each other over private networks.
One challenge that I thought of is that both of our internet providers don’t support static ip addressing, so each vpn server needs to know where to connect to whenever the ip address changes.
What we will be doing
We will setup strongswan vpn on both servers and allow the private LAN ranges to be reachable for both sides. As I have a domain hosted on cloudflare, I will be using cloudflare’s api to update the A record of each sides dns whenever the IP changes.
Environment
On my side, which I will be referring to as Side-A:
123
Public DNS Name: side-a.example.com
Private Range: 192.168.0.0/24
VPN Server IP: 192.168.0.2
On my friend’s side, which I will be referring to as Side-B:
123
Public DNS Name: side-b.example.com
Private Range: 192.168.1.0/24
VPN Server IP: 192.168.1.2
Cloudflare Dynamic DNS
You don’t need to use Cloudflare, theres services such as dyndns.com, no-ip.com. But for this tutorial I will be using cloudflare to utilize my own domain.
First we need to create a API Token, head over to your dashboard: dash.cloudflare.com, head over to “my profile”, select “API Tokens”, then allow “Read Zones” and “Edit DNS”, then select “Create Token”. Keep the returned token value in a safe place.
Install the pre-requirements:
1
$ apt install python python-dev python-pip make curl build-essential -y
Get the source and install:
123
$ git clone https://github.com/LINKIWI/cloudflare-ddns-client.git
$ cd cloudflare-ddns-client
$ make install
We will now configure the cloudflare dynamic dns client, this will be done on both sides, but will only demonstrate for side-a:
12345678
$ cloudflare-ddns --configure
Use API token or API key to authenticate?
Choose [T]oken or [K]ey: T
Enter the API token you created at https://dash.cloudflare.com/profile/api-tokens.
Required permissions are READ Account.Access: Organizations, Identity Providers, and Groups; READ Zone.Zone; EDIT Zone.DNS
CloudFlare API token: [redacted]
Enter the domains for which you would like to automatically update the DNS records, delimited by a single comma.
Comma-delimited domains: side-a.example.com
Testing it out to ensure the A record can be updated:
123456
$ cloudflare-ddns --update-now
Found external IPv4: "1.x.x.x"
Listing all zones.
Finding all DNS records.
Updating the A record (ID x) of (sub)domain side-a.example.com (ID x) to 1.x.x.x.
DNS record updated successfully!
We can run this command from above in a cron, but I will use a bash script to only run when the public ip changed: /opt/scripts/detect_ip_change.sh:
12345678
#!/bin/bash
set -ex
MY_DDNS_HOST="side-a.example.com"
if [ $(dig ${MY_DDNS_HOST} +short) == $(curl -s icanhazip.com) ];
then exit 0;
else /usr/local/bin/cloudflare-ddns --update-now;
fi
Make the file executable: chmod +x /opt/scripts/detect_ip_change.sh then edit your cronjobs: crontab -e and add the script:
1
* * * * * /opt/scripts/detect_ip_change.sh
This will keep your DNS updated, this needs to be done on both sides, if you want to use dynamic dns.
Port Forwarding
We will need to forward UDP traffic from the router to the VPN server, on both sides:
$ ip route add 192.168.1.0/24 via 192.168.0.2 dev eth0
We want to persist the iptables and static route across reboots, so edit the /etc/rc.local file, if it’s not there create it with the following values:
12345
#!/bin/bash
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.0.0/24 -j MASQUERADE
iptables -A FORWARD -s 192.168.1.0/24 -d 192.168.0.0/24 -j ACCEPT
ip route add 192.168.1.0/24 via 192.168.0.2 dev eth0
exit 0
If you created the file, make sure to apply executable permissions:
$ ip route add 192.168.0.0/24 via 192.168.1.2 dev eth0
We want to persist the iptables and static route across reboots, so edit the /etc/rc.local file, if it’s not there create it with the following values:
12345
#!/bin/bash
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -d 192.168.1.0/24 -j MASQUERADE
iptables -A FORWARD -s 192.168.0.0/24 -d 192.168.1.0/24 -j ACCEPT
ip route add 192.168.0.0/24 via 192.168.1.2 dev eth0
exit 0
If you created the file, make sure to apply executable permissions:
From side-a (192.168.0.2) ping the gateway on side-b (192.168.1.1):
123
$ $ ping -c2 192.168.1.1
PING 10.3.96.2 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=62 time=11.9 ms
If you want to be able to reach the private range of the other side of the vpn from any device on your network, you should add a static route on your router to inform your default gateway where to route traffic to.
In this case on side-a (192.168.0.0/24) we want to inform our default gateway to route (192.168.1.0/24) to the VPN as it knows to route that destination over the VPN.
This step is optional, but since we can access each others homelabs, we thought it would be nice to be able to access the resources from mobile devices or laptops when we are on remote locations.
We made it that each VPN owner will connect to its own endpoint (for roadwarriors), so side-a (which will be me) will connect to its own dns endpoint to connect when away from home..
I will only demonstrate how to append your config to add the ability for a roadwarrion vpn connection, append to the /etc/ipsec.conf:
Connecting your VPN Client, I will be using my Laptop, with the following details:
1234567
VPN Type: IKEv2
Description: Home VPN
Server: side-a.example.com
Remote ID: side-a.roadwarrior
Local ID: my-laptop
User Authentication: None
Secret: MySuperSecureSecret123
Thank You
In this tutorial I demonstrated how to setup a site to site ipsec vpn between 2 sides that consists of internet connections that has dynamic ip’s and also appending roadwarrior config so that you can connect to your homelab from anywhere in the world.