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
> Heads up: when following this guide on IPv4-only servers (which is totally fine if one knows what we are 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).
## Requirements
- Virtual private server (VPS) or dedicated server running Debian 10 (buster)
- Computer running macOS Mojave or Catalina
- Phone running iOS 12 or 13
## Guide
#### Step 1: create SSH key pair used to setup server
> For increased security, protect private key using strong passphrase.
When asked for file in which to save key, enter `vpn-server`.
```console
$ cd ~/.ssh
$ 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
If server uses password authentication, run the following and type in password.
```shell
ssh root@185.193.126.203
```
If server uses public key authentication (using the key pair from [step 1](#step-1-create-ssh-key-pair-used-to-setup-server)), run the following and type in passphrase.
```shell
ssh root@185.193.126.203 -i ~/.ssh/vpn-server
```
#### Step 3: add SSH public key to `authorized_keys`
> This step is required only if server was configured without public key authentication.
> When copy/pasting commands that start with `cat << "EOF"`, select all lines (from `cat << "EOF"` to `EOF`) at once as they are part of the same (single) command
On Mac, run:
```shell
echo "cat << \"EOF\" > ~/.ssh/authorized_keys
$(cat ~/.ssh/vpn-server.pub)
EOF"
```
On server, paste output from macOS command and press <kbd>enter</kbd>.
On server, confirm the output from `cat ~/.ssh/authorized_keys` matches the output from `cat ~/.ssh/vpn-server.pub` on macOS.
#### Step 4: create `vpn-server-admin` user
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager). For all other fields, press <kbd>enter</kbd>. Then press <kbd>y</kbd>.
```shell
adduser vpn-server-admin
```
#### Step 5: copy root’s `authorized_keys` file over to vpn-server-admin’s home folder.
When asked to save current IPv4 or IPv6 rules, answer `Yes`.
```shell
apt install -y iptables-persistent
```
#### Step 16: configure iptables
Replace `eth0` (if needed) and `fdc7:da04:1ee6::/64` with first subnet of [step 14](#step-14-generate-random-ipv6-ula) (to display available interfaces, run `ip a`).
```shell
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
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
iptables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -o eth0 -m policy --pol ipsec --dir out -j ACCEPT
#### Step 27: copy/paste the content of `ca.crt`, `vpn-server.key` and `vpn-server.crt` to server and make private key root-only.
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>
On Mac: run `cat vpn-server.key`
On server: run `vi /etc/ipsec.d/private/vpn-server.key`, press <kbd>i</kbd>, paste output from previous step in the window and press <kbd>shift+z+z</kbd>
On Mac: run `cat vpn-server.crt`
On server: run `vi /etc/ipsec.d/certs/vpn-server.crt`, press <kbd>i</kbd>, paste output from previous step in the window and press <kbd>shift+z+z</kbd>
On server: run `chmod -R 600 /etc/ipsec.d/private`
#### Step 28: start strongSwan
```shell
systemctl restart strongswan
```
#### Step 29: configure sysctl
**Backup and override `/etc/sysctl.conf`**
```shell
cp /etc/sysctl.conf /etc/sysctl.conf.backup
```
If the server is IPv4-only, run:
```shell
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.send_redirects = 0/net.ipv4.conf.all.send_redirects = 0/' /etc/sysctl.conf
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
```
If the server is dual stack (IPv4 + IPv6) run:
```shell
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
sed -i -E 's/#net.ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding=1/' /etc/sysctl.conf
```
**Reload sysctl**
```shell
sysctl -p
```
#### Step 30: create VPN profiles for iOS and macOS using [Apple Configurator 2](https://support.apple.com/apple-configurator)
Open "Apple Configurator 2", then click "File", then "New Profile".