strongSwan VPN Between Two VMs

A Pleasant Discovery

In the course of technological events arising from the labor of one's job, frequently the occasion occurs that one finds oneself either forestalled by uncertainty and variability in setting up an unfamiliar system/tool or confused by the complexity of such system/tool and its unwholesome documentation or both. (The appreciable frequency of this scenario being one of the reasons why filtering on flat task lists for job candidates often proves so foolhardy even as it is defended as the safe choice. Rather, Aristotle I think would advise not to look upon a person's resume, but at what that person will do next.)

Not as frequently as one would desire, the new system/tool purporting to fix/fulfill one's professional requirement proves pleasantly well-designed. VPN technology is naturally complex as it must interact with multiple functional areas within both networking and cryptography. This is all the more reason to enjoy using strongSwan, which handles the native complexity of the problem space with competence and composure and without arbitrary constructs that obscure intent and inflict intellectual discontent. Much like git with the version control of files, strongSwan seems to anticipate the next level of your thought progress by providing the right features in the right timeplace that behave exactly how you would expect them.

Not being yet enough awesome, strongSwan also provides excellent config documentation and an expansive suite of fully-documented test cases. Even the page on analyzing traffic is loaded with excellent information, which rewards close reading.

So many tutorials amongst the Greater Intarwebz I found consisted mostly of manically crunching together a pile of configs until the author's ends were produced, the resulting glut of info dumped into a blog post marking the achievement of the bonus goal of communal erudition making no distinction or cognition of which configs were effective and which were deceptive.

While dutifully working through the RTFM procedure (obligatory XKCD), I was not only pleased at the virtue signaled by DuckDuckGo being hardcoded in as their site-specific search tool, but also found this gem while searching the mailing list:

You're having no success because you're trying ramdom[sic] shit from the Internet. About 99,999% of the strongSwan related information on third party sites is wither well ng or of questinable quality[sic]. Don't get your information from any place but the project's website.

Kind regards


Great tonic for erstwhile tedium with hipstergrammer cargo cult explanations. Let's hope this post doesn't fall into the bottom \(\frac{99999}{100000}\) (yes, gratuitous MathJax) of strongSwan info.


I considered writing this post in SaltStack rather than plain command line, since if you're serious about what you're doing, you would not be deploying new systems without some kind of audit/control like salt or one of its inferior peers. I decided to favor the salt-illiterate.


The following assumes you are going to run two Ubuntu 16.04 VMs and will install the strongSwan version packaged for that platform (currently 5.3.5-1ubuntu3.5).


This is a worked reproduction of strongSwan's IKEv1 PSK testcase. I chose it because I need to site-to-site connect to a 3rd party, who uses this config profile. I chose to setup two strongSwan VMs so that I can more easily learn VPN technology generally and strongSwan specifically while controlling all the variables.


Depending on how you configure strongSwan, you and/or strongSwan could be editing iptables rules.

  1. Instantiate two Ubuntu 16.04 VMs on your favorite cloud/hypervisor. Name one moon and the other sun.

  2. Install the package on both VMs.

    (moon/sun) # apt update ; apt install strongswan
  3. Setup main config ipsec.conf.

    (moon) # mv /etc/ipsec.conf /etc/ipsec.conf.original
    (moon) # cat > /etc/ipsec.conf
    config setup
    conn %default
    conn MyVPN
        left=  # moon's normal IP addr
        leftfirewall=yes    # These two configs trigger the necessary iptables rules
        lefthostaccess=yes  # for moon<-->sun traffic from strongSwan's up/down script
        right=  # sun's normal IP addr
    (sun) # mv /etc/ipsec.conf /etc/ipsec.conf.original
    (sun) # cat > /etc/ipsec.conf
    config setup
    conn %default
    conn MyVPN
        left=  # Swap left/right
  4. Setup secret config ipsec.secrets.

    (moon/sun) # mv /etc/ipsec.secrets /etc/ipsec.secrets.original
    (moon/sun) # cat > /etc/ipsec.secrets
    : PSK TBTBidVXSOQ1bTF8R81gtjQb0T97KfDJ3D4avvM32RZ744d6miaAAFiazJPQgWu8Fw9rduirfy7nIzLxN4loxqrqrLwAJ5JodQbWuEk3koQ0DbeoOLRr1zIVcdJHJWZB
  5. Add the VPN IP addresses to moon and sun. Make sure the subnet (/16) matches what you've configured in ipsec.conf.

    (moon) # ip address add dev eth0
    (sun) # ip address add dev eth0
  6. Add iptables rules for esp, ah, and isakmp.

    (moon/sun) # iptables -A INPUT -i eth0 -p esp -j ACCEPT
    (moon/sun) # iptables -A INPUT -i eth0 -p ah -j ACCEPT
    (moon/sun) # iptables -A INPUT -i eth0 -p udp -m udp --dport isakmp -j ACCEPT
    (moon/sun) # iptables -A OUTPUT -o eth0 -p udp -m udp --dport isakmp -j ACCEPT
  7. Start the connection.

    (moon) # systemctl restart strongswan.service
    (moon) # ipsec statusall  # Ensure MyVPN is listed
    (moon) # ipsec up MyVPN
  8. Profit. An exercise for the reader: repeat the following from sun and replace with

    (moon) # ping -c 1
    PING ( 56(84) bytes of data.
    64 bytes from icmp_seq=1 ttl=64 time=180 ms
    --- ping statistics ---
    1 packets transmitted, 1 received, 0% packet loss, time 0ms
    rtt min/avg/max/mdev = 180.300/180.300/180.300/0.000 ms
    (moon) # telnet 22
    Connected to
    Escape character is '^]'.
    SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.4
    telnet> Connection closed.


This is obviously not a finished example: the IP addresses, iptables rules, and VPN connection are not saved across reboots; two random VMs connected by a VPN is not very useful for real work; the systems are flagrantly not salted. The purpose is to illustrate the minimum necessary to get from nothing to a successful VPN connection, or at least imbue enough comprehension to make reading strongSwan's test cases productive and provide a working starting place.

Getting Help

strongSwan has what might appear to be an overly punitive RTFM policy, but given the complexity of the problem space a comprehensively detailed report seems like a reasonable context prerequisite for assistance. The one minor annoyance with this situation is that strongSwan does not provide a tool to gather most/all of this info for you, which is why I wrote the following script. It assumes you're running with the deprecated stroke plugin on Ubuntu with Systemd and have charon logging setup.


If your Ubuntu VM has AppArmor enabled, you may need to place the following AppArmor config for charon logging to work:

(moon/sun) # cat > /etc/apparmor.d/local/usr.lib.ipsec.charon
/var/log/charon_debug.log w,
#!/usr/bin/env python3
from subprocess import run, Popen, PIPE
from datetime import datetime
import time
import shlex

def log(stmt):
    print('=== {} ==='.format(stmt))

conn = 'MyVPN'
pre_cmds = [
    'ipsec down {}'.format(conn),
    'rm -f /var/log/charon_debug.log',
    'systemctl restart strongswan.service',
for pre_cmd in pre_cmds:

start = datetime.utcnow()
cmds = [
    'ipsec up {}'.format(conn),
    'journalctl --all --priority 7 --since "{}" --unit strongswan.service'.format(start.isoformat(sep=' ')[:19]),
    'cat /var/log/charon_debug.log',
    'cat /etc/ipsec.conf',
    'ipsec statusall',
    'ip route show table all',
    'ip address show',
    'ping -c 5 -I',
with open('', 'w') as report:
    for cmd in cmds:
        proc = Popen(shlex.split(cmd), stdout=PIPE)
        report.write('\n### `{}`\n'.format(cmd))

The resulting file should give you all you need to ask for help on the mailing list or in the IRC channel.

Remember to paste responsibly.

Posted: | Source