2020-08-05 17:14:30 -04:00
<!--
Title: How to self-host a hardened strongSwan IKEv2/IPsec VPN server for iOS and macOS
Description: Learn how to self-host a hardened strongSwan IKEv2/IPsec VPN server for iOS and macOS.
Author: Sun Knudsen < https: / / github . com / sunknudsen >
Contributors: Sun Knudsen < https: / / github . com / sunknudsen >
Publication date: 2020-07-31T12:39:56.680Z
-->
# How to self-host a hardened strongSwan IKEv2/IPsec VPN server for iOS and macOS
2020-08-10 19:36:08 -04:00
> Heads up: when following this guide on IPv4-only servers (which is totally fine if one knows what one is doing), it’ s likely IPv6 traffic will leak on iOS when clients are connected to carriers or ISPs running dual stack (IPv4 + IPv6) infrastructure. Leaks can be mitigated on iOS (cellular-only) and on macOS by following this [guide](../how-to-disable-ipv6-on-ios-cellular-only-and-macos-and-why-it-s-a-big-deal-for-privacy).
2020-08-05 17:14:30 -04:00
## Requirements
2020-08-10 19:36:08 -04:00
- Virtual private server (VPS) or dedicated server running Debian 10 (buster) with public IPv4 address
2020-08-05 17:14:30 -04:00
- Computer running macOS Mojave or Catalina
- Phone running iOS 12 or 13
2020-08-10 19:36:08 -04:00
## Caveats
- When copy/pasting commands that start with `$` , strip out `$` as this character is not part of the command
- When copy/pasting commands that start with `cat << "EOF"` , select all lines at once (from `cat << "EOF"` to `EOF` inclusively) as they are part of the same (single) command
2020-08-05 17:14:30 -04:00
## Guide
2020-08-16 09:26:06 -04:00
### Step 1: create SSH key pair
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
For increased security, protect private key using strong passphrase.
2020-08-05 17:14:30 -04:00
When asked for file in which to save key, enter `vpn-server` .
2020-08-16 09:26:06 -04:00
Use `vpn-server.pub` public key when setting up server.
2020-08-05 17:14:30 -04:00
```console
2020-08-14 15:23:58 -04:00
$ mkdir -p ~/.ssh
2020-08-05 17:14:30 -04:00
$ cd ~/.ssh
2020-08-14 15:23:58 -04:00
2020-08-05 17:14:30 -04:00
$ ssh-keygen -t rsa -C "vpn-server"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/sunknudsen/.ssh/id_rsa): vpn-server
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in vpn-server.
Your public key has been saved in vpn-server.pub.
The key fingerprint is:
SHA256:4On7WymZIcM5p8SbsybwJpaFIUrnTUMf/1fdAhI1WPY vpn-server
The key's randomart image is:
+---[RSA 3072]----+
| .== |
| . . o..o |
| . o o . .E o|
|.... * = . ..o|
|o.ooo % S . .. |
|. o..+ O + o . |
| = * + o . |
| + + .+ o |
| . o oo.o. |
+----[SHA256]-----+
2020-08-16 09:26:06 -04:00
$ cat vpn-server.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCu4k9OcJlatGgUoo41m18Hekv+nSHq1w7qcuAuOZWLI8y5aYkLzyEgyp7EibB0rcmwiZfwx/RDb5zAvlr9KGsOWOYJ/gRIf4AwK1PdBPDo8jaa02J/H585NHV7T7XJ7Ycl/LeJh+oDXGs4OOspiFM/7NuleqCA0sSuJEnnuuTZsIDAlJwtWIJTM8lg4nWCQx2xAGkRyx4eNHE2vmlg+xHu3PbHg9kpSIaBWpx0WsysypyaB77+pkid6kYzxPXexoxFm4FnkoY7PZGb97wl4FwW1EK/yo9rnwbtEq5ny96JEHqeJdxeBGHYrsAoRro4jPWYXvdXZV2s27NYC6S3yHsJdaLfyfJXyTaygOyyaf39GcwqfJZpmVYwVyfZ2Go6ec9R/dFbKEA4Ue7aeCkDskSTiMuUZjYjfhezpa4Y0Jiy+lDZFVSv3tsBYu7Nxq0erZ2ygRJAXUMvvyFICJQGUhblRGXAOwYUt72CSUM0ZMsr84aOWsyzRwVQXzxETuDgnXk= vpn-server
2020-08-05 17:14:30 -04:00
```
2020-08-10 19:36:08 -04:00
### Step 2: log in to server as root
2020-08-05 17:14:30 -04:00
Replace `185.193.126.203` with IP of server.
If server uses password authentication, run the following and type in password.
```shell
ssh root@185 .193.126.203
```
2020-08-16 09:26:06 -04:00
If server uses public key authentication, run the following and type in passphrase.
2020-08-05 17:14:30 -04:00
```shell
ssh root@185 .193.126.203 -i ~/.ssh/vpn-server
```
2020-08-10 19:36:08 -04:00
### Step 3: add SSH public key to `authorized_keys`
2020-08-05 17:14:30 -04:00
2020-08-16 09:26:06 -04:00
> This step is only required if server was configured without SSH public key.
2020-08-05 17:14:30 -04:00
On Mac, run:
```shell
echo "cat < < \"EOF \" > ~/.ssh/authorized_keys
$(cat ~/.ssh/vpn-server.pub)
EOF"
```
2020-08-05 19:34:55 -04:00
On server, paste output from Mac command and press < kbd > enter< / kbd > .
2020-08-05 17:14:30 -04:00
```shell
2020-08-11 07:16:17 -04:00
mkdir -p ~/.ssh
2020-08-05 17:14:30 -04:00
cat < < "EOF" > ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCu4k9OcJlatGgUoo41m18Hekv+nSHq1w7qcuAuOZWLI8y5aYkLzyEgyp7EibB0rcmwiZfwx/RDb5zAvlr9KGsOWOYJ/gRIf4AwK1PdBPDo8jaa02J/H585NHV7T7XJ7Ycl/LeJh+oDXGs4OOspiFM/7NuleqCA0sSuJEnnuuTZsIDAlJwtWIJTM8lg4nWCQx2xAGkRyx4eNHE2vmlg+xHu3PbHg9kpSIaBWpx0WsysypyaB77+pkid6kYzxPXexoxFm4FnkoY7PZGb97wl4FwW1EK/yo9rnwbtEq5ny96JEHqeJdxeBGHYrsAoRro4jPWYXvdXZV2s27NYC6S3yHsJdaLfyfJXyTaygOyyaf39GcwqfJZpmVYwVyfZ2Go6ec9R/dFbKEA4Ue7aeCkDskSTiMuUZjYjfhezpa4Y0Jiy+lDZFVSv3tsBYu7Nxq0erZ2ygRJAXUMvvyFICJQGUhblRGXAOwYUt72CSUM0ZMsr84aOWsyzRwVQXzxETuDgnXk= vpn-server
EOF
```
2020-08-10 19:36:08 -04:00
On server, confirm output from `cat ~/.ssh/authorized_keys` matches output from `cat ~/.ssh/vpn-server.pub` on Mac.
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
### Step 4: create `vpn-server-admin` user
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager). All other fields are optional, press < kbd > enter</ kbd > to skip them and then press < kbd > Y</ kbd > .
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
```console
$ adduser vpn-server-admin
Adding user `vpn-server-admin' ...
Adding new group `vpn-server-admin' (1000) ...
Adding new user `vpn-server-admin' (1000) with group ` vpn-server-admin' ...
Creating home directory `/home/vpn-server-admin' ...
Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for vpn-server-admin
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] Y
```
### Step 5: copy root’ s `authorized_keys` file to vpn-server-admin’ s home folder
2020-08-05 17:14:30 -04:00
```shell
mkdir /home/vpn-server-admin/.ssh
cp /root/.ssh/authorized_keys /home/vpn-server-admin/.ssh/authorized_keys
chown -R vpn-server-admin:vpn-server-admin /home/vpn-server-admin/.ssh
```
2020-08-10 19:36:08 -04:00
### Step 6: set root password
2020-08-05 17:14:30 -04:00
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager).
```shell
passwd
```
2020-08-10 19:36:08 -04:00
### Step 7: log out
2020-08-05 17:14:30 -04:00
```shell
exit
```
2020-08-10 19:36:08 -04:00
### Step 8: log in as `vpn-server-admin`
2020-08-05 17:14:30 -04:00
Replace `185.193.126.203` with IP of server.
```shell
ssh vpn-server-admin@185 .193.126.203 -i .ssh/vpn-server
```
2020-08-10 19:36:08 -04:00
### Step 9: switch to root
2020-08-05 17:14:30 -04:00
When asked, enter root password.
```shell
su -
```
2020-08-10 19:36:08 -04:00
### Step 10: update SSH config to disable root login and password authentication and restart SSH
2020-08-05 17:14:30 -04:00
```shell
sed -i -E 's/(#)?PermitRootLogin (prohibit-password|yes)/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i -E 's/(#)?PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh
```
2020-08-10 19:36:08 -04:00
### Step 11: update apt index files and upgrade packages
2020-08-05 17:14:30 -04:00
2020-08-11 07:16:17 -04:00
#### Update apt index files
2020-08-05 17:14:30 -04:00
```shell
apt update
2020-08-11 07:16:17 -04:00
```
#### Upgrade packages
```shell
2020-08-05 17:14:30 -04:00
apt upgrade -y
```
2020-08-11 07:16:17 -04:00
### Step 12: install and configure Vim
#### Install Vim
2020-08-05 17:14:30 -04:00
```shell
apt install -y vim
2020-08-11 07:16:17 -04:00
```
#### Configure Vim
```shell
2020-08-05 17:14:30 -04:00
cat < < "EOF" > ~/.vimrc
set encoding=UTF-8
set termencoding=UTF-8
set nocompatible
set backspace=indent,eol,start
set autoindent
set tabstop=2
set shiftwidth=2
set expandtab
set smarttab
set ruler
set paste
syntax on
EOF
```
2020-08-10 19:36:08 -04:00
### Step 13: set timezone (the following is for Montreal time)
2020-08-05 17:14:30 -04:00
See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for available timezones.
```shell
timedatectl set-timezone America/Montreal
```
2020-08-10 19:36:08 -04:00
### Step 14: detect network interface and save to environment variables
```console
$ ip -4 route | grep "default" | awk '{print "STRONGSWAN_INTERFACE="$5}' | tee -a ~/.bashrc
STRONGSWAN_INTERFACE=eth0
$ source ~/.bashrc
```
### Step 15: install cURL and Python, generate random IPv6 ULA and save to environment variables
2020-08-05 17:14:30 -04:00
2020-08-11 07:16:17 -04:00
#### Install cURL and Python
```shell
apt install -y curl python
```
#### Generate random IPv6 ULA and save to environment variables
2020-08-05 17:14:30 -04:00
Shout out to [Andrew Ho ](https://gist.github.com/andrewlkho/31341da4f5953b8d977aab368e6280a8 ) for `ulagen.py` .
2020-08-11 13:13:36 -04:00
The following commands downloads and runs [ulagen.py ](./ulagen.py ) (advanced users may wish to download [ulagen.py.sig ](./ulagen.py.sig ) and verify signature using my [PGP public key ](https://sunknudsen.com/sunknudsen.asc ) before running script).
2020-08-05 17:14:30 -04:00
```console
2020-08-10 19:36:08 -04:00
$ curl -s https://sunknudsen.com/static/media/privacy-guides/how-to-self-host-a-hardened-strongswan-ikev2-ipsec-vpn-server-for-ios-and-macos/ulagen.py | python | grep "First subnet:" | awk '{print "STRONGSWAN_IPV6_ULA="$3}' | tee -a ~/.bashrc
STRONGSWAN_IPV6_ULA=fdcb:f7a1:38ec::/64
$ source ~/.bashrc
2020-08-05 17:14:30 -04:00
```
2020-08-10 19:36:08 -04:00
### Step 16: install iptables-persistent
2020-08-05 17:14:30 -04:00
When asked to save current IPv4 or IPv6 rules, answer `Yes` .
```shell
apt install -y iptables-persistent
```
2020-08-10 19:36:08 -04:00
### Step 17: configure iptables
2020-08-05 17:14:30 -04:00
```shell
2020-08-10 19:36:08 -04:00
iptables -N SSH_BRUTE_FORCE_MITIGATION
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --set
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --update --seconds 300 --hitcount 10 -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[ssh-brute-force-mitigation]: "
2020-08-11 07:16:17 -04:00
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --update --seconds 300 --hitcount 10 -j DROP
2020-08-10 19:36:08 -04:00
iptables -A SSH_BRUTE_FORCE_MITIGATION -j ACCEPT
2020-08-05 17:14:30 -04:00
iptables -A INPUT -i lo -j ACCEPT
2020-08-10 19:36:08 -04:00
iptables -A INPUT -p tcp --dport 22 --syn -m conntrack --ctstate NEW -j SSH_BRUTE_FORCE_MITIGATION
2020-08-05 17:14:30 -04:00
iptables -A INPUT -p udp --dport 500 -j ACCEPT
iptables -A INPUT -p udp --dport 4500 -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -s 10.0.2.0/24 -m policy --dir in --pol ipsec --proto esp -j ACCEPT
iptables -A FORWARD -d 10.0.2.0/24 -m policy --dir out --pol ipsec --proto esp -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
2020-08-05 19:34:55 -04:00
iptables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
2020-08-05 17:14:30 -04:00
iptables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
2020-08-10 19:36:08 -04:00
iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -o $STRONGSWAN_INTERFACE -m policy --pol ipsec --dir out -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -o $STRONGSWAN_INTERFACE -j MASQUERADE
2020-08-05 17:14:30 -04:00
iptables -t mangle -A FORWARD -m policy --pol ipsec --dir in -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1280
iptables -t mangle -A FORWARD -m policy --pol ipsec --dir out -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1280
iptables -P FORWARD DROP
iptables -P INPUT DROP
iptables -P OUTPUT DROP
```
If the server is IPv4-only, run:
```shell
ip6tables -P FORWARD DROP
ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
```
If the server is dual stack (IPv4 + IPv6) run:
```shell
ip6tables -A INPUT -i lo -j ACCEPT
2020-08-10 19:36:08 -04:00
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type redirect -m hl --hl-eq 255 -j ACCEPT
2020-08-05 17:14:30 -04:00
ip6tables -A INPUT -p udp --dport 500 -j ACCEPT
ip6tables -A INPUT -p udp --dport 4500 -j ACCEPT
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
2020-08-10 19:36:08 -04:00
ip6tables -A FORWARD -s $STRONGSWAN_IPV6_ULA -m policy --dir in --pol ipsec --proto esp -j ACCEPT
ip6tables -A FORWARD -d $STRONGSWAN_IPV6_ULA -m policy --dir out --pol ipsec --proto esp -j ACCEPT
2020-08-05 17:14:30 -04:00
ip6tables -A OUTPUT -o lo -j ACCEPT
2020-08-10 19:36:08 -04:00
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type neighbour-solicitation -m hl --hl-eq 255 -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT
2020-08-05 17:14:30 -04:00
ip6tables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
2020-08-05 19:34:55 -04:00
ip6tables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
2020-08-05 17:14:30 -04:00
ip6tables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
2020-08-10 19:36:08 -04:00
ip6tables -t nat -A POSTROUTING -s $STRONGSWAN_IPV6_ULA -o $STRONGSWAN_INTERFACE -m policy --pol ipsec --dir out -j ACCEPT
ip6tables -t nat -A POSTROUTING -s $STRONGSWAN_IPV6_ULA -o $STRONGSWAN_INTERFACE -j MASQUERADE
2020-08-05 17:14:30 -04:00
ip6tables -t mangle -A FORWARD -m policy --pol ipsec --dir in -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1280
ip6tables -t mangle -A FORWARD -m policy --pol ipsec --dir out -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1280
ip6tables -P FORWARD DROP
ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
```
2020-08-10 19:36:08 -04:00
### Step 18: log out and log in to confirm iptables didn’ t block SSH
#### Log out
2020-08-05 17:14:30 -04:00
```shell
exit
exit
```
2020-08-10 19:36:08 -04:00
#### Log in
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
Replace `185.193.126.203` with IP of server.
2020-08-05 17:14:30 -04:00
```shell
2020-08-10 19:36:08 -04:00
ssh vpn-server-admin@185 .193.126.203 -i .ssh/vpn-server
2020-08-05 17:14:30 -04:00
```
2020-08-10 19:36:08 -04:00
#### Switch to root
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
When asked, enter root password.
2020-08-05 17:14:30 -04:00
```shell
2020-08-10 19:36:08 -04:00
su -
2020-08-05 17:14:30 -04:00
```
2020-08-10 19:36:08 -04:00
### Step 19: make iptables rules persistent
2020-08-05 17:14:30 -04:00
```shell
2020-08-10 19:36:08 -04:00
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6
2020-08-05 17:14:30 -04:00
```
2020-08-10 19:36:08 -04:00
### Step 20: add and enable dummy network interface
2020-08-05 17:14:30 -04:00
2020-08-05 20:38:20 -04:00
If server is configured to use `/etc/network/interfaces` , run:
2020-08-05 17:14:30 -04:00
```shell
cp /etc/network/interfaces /etc/network/interfaces.backup
cat < < "EOF" >> /etc/network/interfaces
auto strongswan0
iface strongswan0 inet static
address 10.0.2.1/24
pre-up ip link add strongswan0 type dummy
EOF
2020-08-05 19:34:55 -04:00
ifup strongswan0
2020-08-05 17:14:30 -04:00
```
2020-08-05 20:38:20 -04:00
If server is configured to use systemd-networkd, run:
```shell
cat < < "EOF" >> /etc/systemd/network/10-strongswan0.netdev
[NetDev]
Name=strongswan0
Kind=dummy
EOF
cat < < "EOF" >> /etc/systemd/network/20-strongswan0.network
[Match]
Name=strongswan0
[Network]
Address=10.0.2.1/24
EOF
2020-08-10 19:36:08 -04:00
systemctl restart systemd-networkd
2020-08-05 20:38:20 -04:00
```
2020-08-10 19:36:08 -04:00
### Step 21: install, configure and restart dnsmasq
#### Install dnsmasq
Please ignore systemd port conflict error (if present).
2020-08-05 17:14:30 -04:00
```shell
apt install -y dnsmasq
```
2020-08-10 19:36:08 -04:00
#### Configure dnsmasq
2020-08-05 17:14:30 -04:00
```shell
cat < < "EOF" > /etc/dnsmasq.d/01-dhcp-strongswan.conf
interface=strongswan0
dhcp-range=10.0.2.10,10.0.2.254,255.255.255.0
port=0
EOF
```
2020-08-10 19:36:08 -04:00
#### Restart dnsmasq
2020-08-05 17:14:30 -04:00
```shell
systemctl restart dnsmasq
```
2020-08-10 19:36:08 -04:00
### Step 22: install strongSwan
2020-08-05 17:14:30 -04:00
If you are shown an "Old runlevel management superseded" warning, answer `Ok` .
```shell
apt install -y strongswan libcharon-extra-plugins
```
2020-08-10 19:36:08 -04:00
### Step 23: configure strongSwan
2020-08-11 07:16:17 -04:00
#### Find server’ s DNS nameserver(s)
Depending on the server’ s configuration, DNS nameserver(s) can be found using one of the following commands (ignore nameservers starting with `127` ).
2020-08-10 19:36:08 -04:00
2020-08-11 07:16:17 -04:00
Fist, run:
```console
$ cat /etc/resolv.conf | grep "nameserver" | awk '{print $2}'
93.95.224.28
93.95.224.29
```
If that doesn’ t output valid nameserver(s), run:
```console
$ cat /etc/network/interfaces | grep "dns-nameservers" | awk '{$1="";$0=$0;} NF=NF'
93.95.224.28 93.95.224.29
```
If that doesn’ t output valid nameserver(s), run:
```console
$ systemd-resolve --status | grep "DNS Servers" | awk '{print $3}'
95.215.19.53
```
#### Set DNS nameserver(s)
Replace `95.215.19.53` with server’ s DNS nameserver(s).
Separate nameservers using commas with no leading spaces (example: `93.95.224.28,93.95.224.29` ).
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
```shell
2020-08-11 07:16:17 -04:00
STRONGSWAN_DNS_NAMESERVERS=95.215.19.53
2020-08-10 19:36:08 -04:00
```
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
#### Backup and override `/etc/ipsec.conf`
2020-08-05 17:14:30 -04:00
```shell
cp /etc/ipsec.conf /etc/ipsec.conf.backup
```
If the server is IPv4-only, run:
```shell
2020-08-10 19:36:08 -04:00
cat < < EOF > /etc/ipsec.conf
2020-08-05 17:14:30 -04:00
config setup
charondebug="ike 1, knl 1, cfg 1"
conn ikev2
auto=add
compress=no
type=tunnel
keyexchange=ikev2
fragmentation=yes
forceencaps=yes
ike=aes256gcm16-prfsha512-ecp384!
esp=aes256gcm16-ecp384!
dpdaction=clear
dpddelay=300s
rekey=no
left=%any
leftid=vpn-server.com
2020-08-10 19:36:08 -04:00
leftcert=server.crt
2020-08-05 17:14:30 -04:00
leftsendcert=always
2020-08-05 19:51:52 -04:00
leftsubnet=0.0.0.0/0
2020-08-05 17:14:30 -04:00
right=%any
rightid=%any
rightauth=eap-tls
2020-08-11 07:16:17 -04:00
rightdns=$STRONGSWAN_DNS_NAMESERVERS
2020-08-05 17:14:30 -04:00
rightsourceip=%dhcp
rightsendcert=never
eap_identity=%identity
EOF
```
If the server is dual stack (IPv4 + IPv6) run:
```shell
2020-08-10 19:36:08 -04:00
cat < < EOF > /etc/ipsec.conf
2020-08-05 17:14:30 -04:00
config setup
charondebug="ike 1, knl 1, cfg 1"
conn ikev2
auto=add
compress=no
type=tunnel
keyexchange=ikev2
fragmentation=yes
forceencaps=yes
ike=aes256gcm16-prfsha512-ecp384!
esp=aes256gcm16-ecp384!
dpdaction=clear
dpddelay=300s
rekey=no
left=%any
leftid=vpn-server.com
2020-08-10 19:36:08 -04:00
leftcert=server.crt
2020-08-05 17:14:30 -04:00
leftsendcert=always
2020-08-05 19:51:52 -04:00
leftsubnet=0.0.0.0/0,::/0
2020-08-05 17:14:30 -04:00
right=%any
rightid=%any
rightauth=eap-tls
2020-08-11 07:16:17 -04:00
rightdns=$STRONGSWAN_DNS_NAMESERVERS
2020-08-10 19:36:08 -04:00
rightsourceip=%dhcp,$STRONGSWAN_IPV6_ULA
2020-08-05 17:14:30 -04:00
rightsendcert=never
eap_identity=%identity
EOF
```
2020-08-10 19:36:08 -04:00
#### Backup and override `/etc/ipsec.secrets`
2020-08-05 17:14:30 -04:00
```shell
cp /etc/ipsec.secrets /etc/ipsec.secrets.backup
cat < < "EOF" > /etc/ipsec.secrets
2020-08-10 19:36:08 -04:00
: RSA server.key
2020-08-05 17:14:30 -04:00
EOF
```
2020-08-10 19:36:08 -04:00
#### Backup and override `/etc/strongswan.d/charon-logging.conf`
2020-08-05 17:14:30 -04:00
```shell
cp /etc/strongswan.d/charon-logging.conf /etc/strongswan.d/charon-logging.conf.backup
cat < < "EOF" > /etc/strongswan.d/charon-logging.conf
charon {
filelog {
charon {
default = 1
}
}
syslog {
auth {
default = 1
}
}
}
EOF
```
2020-08-10 19:36:08 -04:00
#### Backup and override `/etc/strongswan.d/charon/dhcp.conf`
2020-08-05 17:14:30 -04:00
```shell
cp /etc/strongswan.d/charon/dhcp.conf /etc/strongswan.d/charon/dhcp.conf.backup
cat < < "EOF" > /etc/strongswan.d/charon/dhcp.conf
dhcp {
force_server_address = yes
identity_lease = yes
2020-08-05 19:34:55 -04:00
interface = strongswan0
2020-08-05 17:14:30 -04:00
load = yes
server = 10.0.2.1
}
EOF
```
2020-08-10 19:36:08 -04:00
#### Disable unused plugins
2020-08-05 17:14:30 -04:00
```shell
cd /etc/strongswan.d/charon
2020-08-05 20:38:20 -04:00
sed -i 's/load = yes/load = no/' ./*.conf
sed -i 's/load = no/load = yes/' ./eap-tls.conf ./aes.conf ./dhcp.conf ./farp.conf ./gcm.conf ./hmac.conf ./kernel-netlink.conf ./nonce.conf ./openssl.conf ./pem.conf ./pgp.conf ./pkcs12.conf ./pkcs7.conf ./pkcs8.conf ./pubkey.conf ./random.conf ./revocation.conf ./sha2.conf ./socket-default.conf ./stroke.conf ./x509.conf
2020-08-10 19:36:08 -04:00
cd
2020-08-05 20:38:20 -04:00
```
2020-08-10 19:36:08 -04:00
#### Backup and edit `/lib/systemd/system/strongswan.service`
2020-08-05 20:38:20 -04:00
```shell
cp /lib/systemd/system/strongswan.service /lib/systemd/system/strongswan.service.backup
sed -i 's/After=network-online.target/After=dnsmasq.service/' /lib/systemd/system/strongswan.service
2020-08-10 19:36:08 -04:00
systemctl daemon-reload
```
### Step 24: create `strongswan-certs` folder
> For security reasons, steps 24 to 28 are done on Mac vs server.
```shell
mkdir ~/Desktop/strongswan-certs
cd ~/Desktop/strongswan-certs
2020-08-05 17:14:30 -04:00
```
2020-08-10 19:36:08 -04:00
### Step 25: create OpenSSL config file
#### Set client common name
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
Each client is configured using a unique common name ending with `@vpn-server.com` .
2020-08-05 17:14:30 -04:00
```shell
2020-08-10 19:36:08 -04:00
STRONGSWAN_CLIENT_COMMON_NAME=john@vpn -server.com
2020-08-05 17:14:30 -04:00
```
2020-08-10 19:36:08 -04:00
#### Create OpenSSL config file
2020-08-05 17:14:30 -04:00
```shell
2020-08-10 19:36:08 -04:00
cat < < EOF > openssl.cnf
2020-08-05 17:14:30 -04:00
[ req ]
distinguished_name = req_distinguished_name
attributes = req_attributes
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
2020-08-10 19:36:08 -04:00
countryName_default = US
2020-08-05 17:14:30 -04:00
0.organizationName = Organization Name (eg, company)
2020-08-10 19:36:08 -04:00
0.organizationName_default = Self-hosted strongSwan VPN
2020-08-05 17:14:30 -04:00
commonName = Common Name (eg, fully qualified host name)
commonName_max = 64
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
[ ca ]
subjectKeyIdentifier = hash
basicConstraints = critical, CA:true
keyUsage = critical, cRLSign, keyCertSign
[ server ]
authorityKeyIdentifier = keyid
2020-08-10 19:36:08 -04:00
subjectAltName = DNS:vpn-server.com
2020-08-05 17:14:30 -04:00
extendedKeyUsage = serverAuth, 1.3.6.1.5.5.8.2.2
[ client ]
authorityKeyIdentifier = keyid
2020-08-10 19:36:08 -04:00
subjectAltName = email:$STRONGSWAN_CLIENT_COMMON_NAME
2020-08-05 17:14:30 -04:00
extendedKeyUsage = serverAuth, 1.3.6.1.5.5.8.2.2
EOF
```
2020-08-10 19:36:08 -04:00
### Step 26: generate certificate authority cert
2020-08-05 17:14:30 -04:00
```console
$ openssl genrsa -out ca.key 4096
Generating RSA private key, 4096 bit long modulus
......................................++
........................................................................................................................................................................................................................................................................................++
e is 65537 (0x10001)
2020-08-10 19:36:08 -04:00
$ openssl req -x509 -new -nodes -config openssl.cnf -extensions ca -key ca.key -subj "/C=US/O=Self-hosted strongSwan VPN/CN=vpn-server.com" -days 3650 -out ca.crt
2020-08-05 17:14:30 -04:00
```
2020-08-10 19:36:08 -04:00
### Step 27: generate server cert
2020-08-05 17:14:30 -04:00
```console
2020-08-10 19:36:08 -04:00
$ openssl genrsa -out server.key 4096
2020-08-05 17:14:30 -04:00
Generating RSA private key, 4096 bit long modulus
.................................................................................................................................................................................................................................................++
................................................................................++
e is 65537 (0x10001)
2020-08-10 19:36:08 -04:00
$ openssl req -new -config openssl.cnf -extensions server -key server.key -subj "/C=US/O=Self-hosted strongSwan VPN/CN=vpn-server.com" -out server.csr
$ openssl x509 -req -extfile openssl.cnf -extensions server -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out server.crt
2020-08-05 17:14:30 -04:00
Signature ok
2020-08-10 19:36:08 -04:00
subject=/C=US/O=Self-hosted strongSwan VPN/CN=vpn-server.com
2020-08-05 17:14:30 -04:00
Getting CA Private Key
```
2020-08-10 19:36:08 -04:00
### Step 28: generate client cert
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
When asked for export password, use output from `openssl rand -base64 24` (and store password in password manager).
2020-08-05 17:14:30 -04:00
```console
2020-08-10 19:36:08 -04:00
$ openssl genrsa -out john.key 4096
2020-08-05 17:14:30 -04:00
Generating RSA private key, 4096 bit long modulus
.........++
............................................................................++
e is 65537 (0x10001)
2020-08-10 19:36:08 -04:00
$ openssl req -new -config openssl.cnf -extensions client -key john.key -subj "/C=US/O=Self-hosted strongSwan VPN/CN=$STRONGSWAN_CLIENT_COMMON_NAME" -out john.csr
$ openssl x509 -req -extfile openssl.cnf -extensions client -in john.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out john.crt
2020-08-05 17:14:30 -04:00
Signature ok
2020-08-10 19:36:08 -04:00
subject=/C=US/O=Self-hosted strongSwan VPN/CN=john@vpn -server.com
2020-08-05 17:14:30 -04:00
Getting CA Private Key
2020-08-10 19:36:08 -04:00
$ openssl pkcs12 -in john.crt -inkey john.key -certfile ca.crt -export -out john.p12
2020-08-05 17:14:30 -04:00
Enter Export Password:
Verifying - Enter Export Password:
```
2020-08-10 19:36:08 -04:00
### Step 29: copy/paste the content of `ca.crt`, `server.key` and `server.crt` to server and make private key root-only.
2020-08-05 17:14:30 -04:00
On Mac: run `cat ca.crt`
On server: run `vi /etc/ipsec.d/cacerts/ca.crt` , press < kbd > i</ kbd > , paste output from previous step in the window and press < kbd > shift+z+z</ kbd >
2020-08-10 19:36:08 -04:00
On Mac: run `cat server.key`
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
On server: run `vi /etc/ipsec.d/private/server.key` , press < kbd > i</ kbd > , paste output from previous step in the window and press < kbd > shift+z+z</ kbd >
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
On Mac: run `cat server.crt`
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
On server: run `vi /etc/ipsec.d/certs/server.crt` , press < kbd > i</ kbd > , paste output from previous step in the window and press < kbd > shift+z+z</ kbd >
2020-08-05 17:14:30 -04:00
On server: run `chmod -R 600 /etc/ipsec.d/private`
2020-08-10 19:36:08 -04:00
### Step 30: restart strongSwan
2020-08-05 17:14:30 -04:00
```shell
systemctl restart strongswan
```
2020-08-10 19:36:08 -04:00
### Step 31: configure sysctl
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
#### Backup and override `/etc/sysctl.conf`
2020-08-05 17:14:30 -04:00
```shell
cp /etc/sysctl.conf /etc/sysctl.conf.backup
2020-08-05 19:34:55 -04:00
sed -i -E 's/#net .ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sed -i -E 's/#net .ipv4.conf.all.accept_redirects = 0/net.ipv4.conf.all.accept_redirects = 0/' /etc/sysctl.conf
sed -i -E 's/#net .ipv4.conf.all.send_redirects = 0/net.ipv4.conf.all.send_redirects = 0/' /etc/sysctl.conf
2020-08-05 17:14:30 -04:00
```
If the server is IPv4-only, run:
```shell
cat < < "EOF" >> /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF
```
2020-08-10 19:36:08 -04:00
If the server is dual stack (IPv4 + IPv6) rune:
2020-08-05 17:14:30 -04:00
```shell
sed -i -E 's/#net .ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding=1/' /etc/sysctl.conf
```
2020-08-10 19:36:08 -04:00
#### Reload sysctl
2020-08-05 17:14:30 -04:00
```shell
sysctl -p
```
2020-08-10 19:36:08 -04:00
### Step 32: create VPN profile for iOS and macOS using [Apple Configurator 2](https://support.apple.com/apple-configurator)
> When configuring strongSwan using certs and dnsmasq, two devices cannot use the same provisioning profile simultaneously.
2020-08-05 17:14:30 -04:00
Open "Apple Configurator 2", then click "File", then "New Profile".
2020-08-05 19:34:55 -04:00
In "General", enter "Self-hosted strongSwan VPN" in "Name".
2020-08-05 17:14:30 -04:00

2020-08-10 19:36:08 -04:00
In "Certificates", click "Configure" and select "ca.crt". Then click "+" and select "john.p12". The password is the one from [step 28 ](#step-28-generate-client-cert ).
2020-08-05 17:14:30 -04:00

2020-08-05 19:34:55 -04:00
In "VPN", click "Configure" and enter the settings from the following screenshot (replace `185.193.126.203` with IP of server).
The "Child SA Params" are the same as "IKE SA Params".
2020-08-05 17:14:30 -04:00

2020-08-10 19:36:08 -04:00
Finally, click "File", then "Save", and save file as "john.mobileconfig".
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
### Step 33: add VPN profile to iPhone using Apple Configurator 2
2020-08-05 17:14:30 -04:00
2020-08-05 17:22:20 -04:00
Unlock iPhone, connect it to Mac using USB cable and open Apple Configurator 2.
2020-08-05 17:14:30 -04:00
2020-08-05 17:22:20 -04:00
In "All Devices", double-click on iPhone, then "Add", and finally "Profiles".
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
Select "john.mobileconfig" and follow instructions.
2020-08-05 17:14:30 -04:00
2020-08-05 19:34:55 -04:00
On iPhone, open "Settings", then "Profile Downloaded" and tap "Install"
2020-08-05 17:14:30 -04:00
2020-08-10 19:36:08 -04:00
### Step 34: add VPN profile to Mac
This step is super simple, simply double-click "john.mobileconfig" and follow instructions.
### Step 35: connect to VPN on iPhone or Mac
On iPhone, open "Settings", then enable "VPN".
On Mac, open "System Preferences", click "Network", then "Self-hosted strongSwan VPN" and finally "Connect" and enable "Show VPN status in menu bar".
2020-08-11 07:16:17 -04:00
### Step 36: test for leaks
Open Firefox and go to https://ipleak.net/.
Make sure listed IPv4, IPv6 (if server is dual stack) and DNS servers do not match the ones supplied by client ISP.
### Step 37: create additionnal provisioning profiles
2020-08-10 19:36:08 -04:00
Repeat steps [25 ](#step-25-create-openssl-config-file ), [28 ](#step-28-generate-client-cert ) and [32 ](#step-32-create-vpn-profile-for-ios-and-macos-using ).