Recently, I explored the WireGuard VPN solution and was pleasantly surprised by its user-friendly setup. Setting up a VPN server with a sleek graphical interface took just a few commands. Given that I use strongSwan at my workplace, I envisioned having a similar graphical interface for it. A quick Google search revealed that such a project already exists: StrongMan—a graphical web UI designed for strongSwan. Excited to try it out, I encountered some difficulties getting it to run smoothly on my Ubuntu 22.04 host. In this write-up, I’ll share with you the process I went through to get it up and running.


Install strongSwan

First, update your local package cache using apt:

sudo apt update

Then install the software by typing:

sudo apt install strongswan strongswan-pki strongswan-swanctl -y
  • strongswan-pki package comes with a utility called pki to generate a Certificate Authority and server certificates.
  • strongswan-swanctl package comes with the Versatile IKE Control Interface (VICI) plugin

strongMan connects to the IKE daemon via VICI protocol, so you need to make sure that the VICI plugin is loaded:

sudo ipsec listplugins | grep -i vici

You should have an output as below:

vici:
    CUSTOM:vici

Install the dependencies

Install python:

sudo apt install python3-pip -y

Install virtualenv:

sudo python3 -m pip install virtualenv

Make alias for python:

sudo ln -s /usr/bin/python3 /usr/bin/python

Install strongMan

Run the following commands to install strongMan:

git clone https://github.com/strongswan/strongMan.git
cd strongMan
sudo ./setup.py install

If things went smoothly, you will get an output as below:

Start strongMan installation
        - Virtualenv
        - Requirements
        - Database migration
                Delete strongMan/db.sqlite3
[Errno 2] No such file or directory: '/root/strongMan/strongMan/db.sqlite3'
        - Static files

Please be aware that the [Errno 2] No such file or directory: '/home/ubuntu/strongMan/strongMan/db.sqlite3' message in the preceding output is not a critical error; think of it more like a log entry. There’s no need to worry. Initially, it might seem confusing—I fell for it myself the first time, thinking there was an issue. However, it’s just a benign notification, and everything is actually functioning properly.

Set the environment to production

Replace strongMan.settings.local by strongMan.settings.production in the run.py file. Otherwise, you might get a Invalid HTTP_POST header error.

Invalid HTTP_POST header

You can use your fav code editor or simply do it from the command line using:

sed -i 's/strongMan.settings.local/strongMan.settings.production/g' run.py

Configuration loader

To guarantee data consistency between strongMan and strongSwan, we need to make sure that the configuration loader script will be executed on the startup of strongSwan.

Put the following line into “strongswan-starter.service”. Replace “pathTostrongMan” with the path, where you installed strongMan.

ExecStartPost=/pathTostrongMan/configloader.py

Sample of the /lib/systemd/system/strongswan-starter.service file:

[Unit]
Description=strongSwan IPsec IKEv1/IKEv2 daemon using ipsec.conf
After=network-online.target

[Service]
ExecStart=/usr/sbin/ipsec start --nofork
ExecReload=/usr/sbin/ipsec reload
Restart=on-abnormal
ExecStartPost=/root/strongMan/configloader.py

[Install]
WantedBy=multi-user.target

Reload for changes to take effect:

sudo systemctl daemon-reload
sudo systemctl restart strongswan-starter.service

Add a systemd service

If you want to run strongMan permanently in the background, you can install strongMan as a systemd service.

sudo ./setup.py add-service

Check if it’s working:

sudo systemctl status strongMan

You might get an output as below:

● strongMan.service - strongMan gunicorn service
     Loaded: loaded (/etc/systemd/system/strongMan.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2023-11-18 11:29:54 UTC; 8s ago
   Main PID: 28150 (python)
      Tasks: 8 (limit: 2309)
     Memory: 211.1M
        CPU: 2.680s
     CGroup: /system.slice/strongMan.service
             ├─28150 /root/strongMan/env/bin/python run.py
             ├─28152 /root/strongMan/env/bin/python /root/strongMan/env/bin/gunicorn --workers 6 --bind 0.0.0.0:1515 --env DJANGO_SETTINGS_MODULE=strongMan.s>
             ├─28153 /root/strongMan/env/bin/python /root/strongMan/env/bin/gunicorn --workers 6 --bind 0.0.0.0:1515 --env DJANGO_SETTINGS_MODULE=strongMan.s>
             ├─28154 /root/strongMan/env/bin/python /root/strongMan/env/bin/gunicorn --workers 6 --bind 0.0.0.0:1515 --env DJANGO_SETTINGS_MODULE=strongMan.s>
             ├─28155 /root/strongMan/env/bin/python /root/strongMan/env/bin/gunicorn --workers 6 --bind 0.0.0.0:1515 --env DJANGO_SETTINGS_MODULE=strongMan.s>
             ├─28156 /root/strongMan/env/bin/python /root/strongMan/env/bin/gunicorn --workers 6 --bind 0.0.0.0:1515 --env DJANGO_SETTINGS_MODULE=strongMan.s>
             ├─28157 /root/strongMan/env/bin/python /root/strongMan/env/bin/gunicorn --workers 6 --bind 0.0.0.0:1515 --env DJANGO_SETTINGS_MODULE=strongMan.s>
             └─28158 /root/strongMan/env/bin/python /root/strongMan/env/bin/gunicorn --workers 6 --bind 0.0.0.0:1515 --env DJANGO_SETTINGS_MODULE=strongMan.s>

Nov 18 11:29:54 strongman systemd[1]: Started strongMan gunicorn service.
Nov 18 11:29:55 strongman python[28152]: [2023-11-18 11:29:55 +0000] [28152] [INFO] Starting gunicorn 20.0.4
Nov 18 11:29:55 strongman python[28152]: [2023-11-18 11:29:55 +0000] [28152] [INFO] Listening at: http://0.0.0.0:1515 (28152)
Nov 18 11:29:55 strongman python[28152]: [2023-11-18 11:29:55 +0000] [28152] [INFO] Using worker: sync
Nov 18 11:29:55 strongman python[28153]: [2023-11-18 11:29:55 +0000] [28153] [INFO] Booting worker with pid: 28153
Nov 18 11:29:55 strongman python[28154]: [2023-11-18 11:29:55 +0000] [28154] [INFO] Booting worker with pid: 28154
Nov 18 11:29:55 strongman python[28155]: [2023-11-18 11:29:55 +0000] [28155] [INFO] Booting worker with pid: 28155
Nov 18 11:29:55 strongman python[28156]: [2023-11-18 11:29:55 +0000] [28156] [INFO] Booting worker with pid: 28156
Nov 18 11:29:55 strongman python[28157]: [2023-11-18 11:29:55 +0000] [28157] [INFO] Booting worker with pid: 28157
Nov 18 11:29:55 strongman python[28158]: [2023-11-18 11:29:55 +0000] [28158] [INFO] Booting worker with pid: 28158

You now have strongMan service listening on http://your-server-IP:1515. Likewise, you can now log in to the web UI with:

  • Username: John
  • Password: Lennon@1940

strongMan login page

That’s it!


Bonus

If you’re a fan of Ansible and embrace the concept of Infrastructure as Code, I have a playbook ready to effortlessly automate the entire installation process for you.

- name: Install strongMan
  hosts: all
  tasks:
    - name: Update cache
      become: true
      ansible.builtin.apt:
        update_cache: true

    - name: Install strongswan
      become: true
      ansible.builtin.apt:
        name:
          - strongswan
          - strongswan-pki
          - strongswan-swanctl
        state: present

    - name: Install python3 and virtualenv
      become: true
      ansible.builtin.apt:
        name:
          - python3
          - python3-virtualenv
          - python3-pip
        state: present

    - name: Create a symbolic link
      become: true
      ansible.builtin.file:
        src: /usr/bin/python3
        dest: /usr/bin/python
        state: link

    - name: Clone strongMan repo
      ansible.builtin.git:
        repo: 'https://github.com/strongswan/strongMan.git'
        dest: "/strongMan"
        force: true

    - name: Install strongMan
      become: true
      ansible.builtin.command:
        cmd: sudo ./setup.py install
        chdir: "/strongMan"

    - name: Set the environment to production
      ansible.builtin.replace:
        path: "/strongMan/run.py"
        regexp: 'strongMan\.settings\.local'
        replace: 'strongMan.settings.production'

    - name: Configuration loader
      become: true
      ansible.builtin.lineinfile:
        path: /lib/systemd/system/strongswan-starter.service
        insertafter: '^Restart=on-abnormal\n'
        line: 'ExecStartPost=/strongMan/configloader.py'
      notify: Restart strongswan-starter service
    
    - name: Add strongMan service
      become: true
      ansible.builtin.command:
        cmd: sudo ./setup.py add-service
        chdir: "/strongMan"
      notify: Restart strongMan service

  handlers:
    - name: Restart strongswan-starter service
      become: true
      ansible.builtin.systemd_service:
        state: restarted
        daemon_reload: true
        name: strongswan-starter.service

    - name: Restart strongMan service
      become: true
      ansible.builtin.systemd_service:
        state: restarted
        daemon_reload: true
        name: strongMan.service

What’s next?

Now that you have strongMan installed, take a look at this article of mine to learn how to set up an IKEv2 Point-to-Site VPN with it.


Thank you for reading this article all the way to the end! I hope you found the information and insights shared here to be valuable and interesting. Get in touch with me on LinkedIn

I appreciate your support and look forward to sharing more content with you in the future. Until next time!

References