Restarting a VPN client on pfSense through the CLI (SSH)

I recently had some issues with a flaky VPN service. I wanted to make a little script I could run on a different machine that would restart the VPN connection, should it break. This particular VPN connection included a DNS service for the remote .local-domain, which I decided to use for testing, but you could in theory use any valid connection test.

Either way, pulling the correct function names and options from /usr/local/www/status_services.php – following the reference to /etc/inc/service-utils.inc – I came up with this script:

#!/usr/bin/env bash
if ! nslookup -timeout=2 remote.server.local >/dev/null 2>&1; then
    echo "VPN not OK - restarting"
    ssh my.pfsense.ip /usr/local/bin/php -q <<-EOF
        <?php
            include('service-utils.inc');
            service_control_restart("openvpn", array('vpnmode' => 'client', 'id' => '3'));
        ?>
    EOF
fi

This will connect to my pfSense box using passwordless SSH login from a trusted machine, and restart the VPN connection.

The client ID was obtained from the restart link in the pfSense web interface:

vpnid

UPDATE

I ended up finding the browser VPN ID too hackish, and made a script that looks up the ID in the pfSense config instead. Might also be useful for adapting to future issues. Here: http://www.dhampir.no/stuff/bash/pfsense-vpnreset

37 Comments

  • Muhammad says:

    i was workingon this all day. pfsense channel on freenode was useless. thanks!

  • sorin says:

    Sadly this doesn’t work with pfsense 2.4.1 because the password file is overridden by pfsense on connect.

    You can find more information on https://redmine.pfsense.org/issues/8122 — maybe you found another workaround for this. I am really interested about finding a way to automate the connection.

    • bolt says:

      I don’t use one-time passwords with OpenVPN on pfSense, sorry. But I currently have 4 VPN clients running with usernames, passwords and client certificates, and those still work fine in 2.4.1 🙂

  • EDER MASCULINO GOMES says:

    ola

  • stefano says:

    Thanks a lot for your solution.
    I’m noob and i don’t know how to use and put this script… can you help me?
    I have a big problem that sometimes my VPN Gateway going offline and my connection drops… then i wont tu run a script every x minutes to ping and host and check if connection works or restart OpenVPN service that solve the problem.
    For run periodically i think that cron can solve the problem. but i don’t know how to begin.
    regards

    • bolt says:

      What you’d need is a simple crontab line to run a script:
      */5 * * * * /root/bin/my_vpn_ping_test

      Containing something like:
      #!/bin/bash
      ip="1.2.3.4" # your test IP here
      pfsense="10.0.0.1"
      vpnname="Work-VPN"
      if ! ping -c 1 -w 10 "$ip"; then
      /root/bin/pfsense-vpnreset "$pfsense" "$vpnname"
      fi

      Extend as required.

      • STefano says:

        Thanks a lot for your reply, in pfsense variable what ip i need to put? is there also a way to check if cron run my script like a log?

        • bolt says:

          The pfsense variable is the IP or hostname of your pfSense machine, to which you’ve hopefully already set up automatic login. I.e. you should be able to do ssh root@pfsenseip without specifying a password. This is done via the .ssh/authorized_keys file as on any Linux-style system.

          If you want to log your output, simply modify your crontab line to do so:
          */5 * * * * /root/bin/my_vpn_ping_test >>/var/log/vpn_test.log 2>&1

          ..or similar. Or have the script do it internally. And add any additional debug information or timestamps as desired. Or pipe output to the “logger” command to use your system’s built-in logging capabilities. Your options are limitless 🙂

          • Stefano says:

            Bolt really thanks a lot for all your essential help!!! 😀
            If is possible i want to use cron installed in my pfsense to do this.
            if is possibile i want to do this:
            Use cron installed inside pfsense and print to log if vpn is working or not inside the log of pfsense itself.

          • Stefano says:

            I think that i have solved part of my problem, using this:
            >>/var/log/vpn_test.log 2>&1

            now i have the log so i know that cron work properly, there i a way to print time and day?

            If i run the script inside pfsense i need to do this?
            The pfsense variable is the IP or hostname of your pfSense machine, to which you’ve hopefully already set up automatic login. I.e. you should be able to do ssh root@pfsenseip without specifying a password. This is done via the .ssh/authorized_keys file as on any Linux-style system.

          • bolt says:

            If you run the script inside of pfSense, you don’t need any SSH stuff. Also, pfSense does not come with Bash by default. You can install it though.
            Without the SSH part, you can shorten the script down to just the PHP section. Perhaps like this: https://blog.dhampir.no/wp-content/uploads/2019/01/stefano-vpnreset.sh
            I added simple date printing in the PHP 🙂

          • Stefano says:

            Really thanks a lot!!
            Where i can put this file? and how i can use the file? is there also a way to send an email if the vpn is offline?

          • bolt says:

            You put it on your pfSense machine. Using curl to download it or scp or something to transfer it over.
            Then you make it executable (chmod +x filename) and get your crontab to run it.
            As for the email and using pfSense’s internal logging capabilities, this is something I have not investigated, as I run my script on a machine where all those features are available through different means. Perhaps try the pfSense forums?

          • Stefano says:

            Sorry what kind of command i need to put inside the Cron?

          • bolt says:

            Put whatever you use to run it. The crontab manpage is useful to figure out the numbers. The last script I linked you to is PHP. To run that every 5 minutes, do something like:
            */5 * * * * /usr/local/bin/php -q /root/script/path/here >/root/vpnscript.log 2>&1

      • Stefano says:

        Thanks a lot!! Tomorrow I will try!! I really appreciate you awesome support!!
        I have also try to send some messages in PFSens forum but no one help me.. 🙁
        Regards
        Stefano

        • Stefano says:

          Bolt really thanks a lot!!
          Now i’M out of home but when I come back I will try!! 🙂

  • lamalo says:

    “This will connect to my pfSense box using keyless login from a trusted machine,…”

    What do you mean by this?

    How would i do this with a connected windows server my pfsense firewall is connected with? this means a non-joined pfsense?

    is it possible?

    • bolt says:

      Sure, you can do this from a Windows machine, but both the old script on this page, as well as the new one referenced in the “update” section are Bash scripts, so you’d have to get Bash running on Windows, something there are plenty of solutions for. Cygwin comes to mind.

      That being said, you could also rewrite this into PowerShell, or run just the php section of the updated script on pfSense itself. Check out the thread where I discuss this option with Stefano for a reference.

      When it comes to keyless login, that’s actually misleading. It should say “passwordless”, using unencrypted public/private keys. This is only viable if you fully trust both machines and use that key only for that particular purpose on that particular machine. Always encrypt your SSH keys.

      You didn’t provide a valid email address, so you won’t be notified of this reply. Perhaps consider doing so next time. I’m not in the spam business 🙂

      • lamalo says:

        Hi Bolt,

        Firstly, thanks for your reply and your blog. I have scanned it and it seems to be a little goldmine for System Admins! Greatly appreciated. If I would have the time, I’d also do something similar. Perhaps I still need to further automate my work tasks so that I can 🙂

        My ideal solution indeed would be indeed to run a scheduled task on my Windows server to check a remote IP and launch the ‘VPN Reset’ script if it’s down (+ check after ofc).

        I need to opt for this approach as the firewall on my other side of the IPsec tunnel, doesn’t support VPN-CLI commands to be ran from a FTP connection.

        So I’m focusing on implementing this via PowerShell.

        However, if we’re needed to encrypt plain text passwords or will be having plain text pw’s in a config sort of file, I would need to stop looking due to GDPR and internal policies.

        Maybe I should focus on how to connect ‘keyless’ to a connected pfSense and continue my job.

        • bolt says:

          Hey again 🙂

          It’s not keyless, as much as it is passwordless. I updated the article to reflect this. Thanks for pointing it out!

          All that involves is a pregenerated public/private key combination for SSH login, where the private key is not encrypted, so that the automated script can use it without requiring user input. There are many tutorials available on how to generate the keys for SSH, and where to put them. Here’s one of them.

          Once you have that, you can use any command line SSH client to connect to pfSense from your script. plink from the PuTTY bundle is one. Or the OpenSSH client.

          • lamalo says:

            i still failed to get this working.

            i can’t install bash on my pfsense due to security reasons.

            what i’m doing is the following:

            create file with the script of your latest link in /usr/local/bin/ as the name pfsense-vpnreset.

            when i save and run it using the following command:
            /usr/local/bin/pfsense-vpnreset: Permission denied.

            I fix this by running the following:
            chmod +rx /usr/local/bin/pfsense-vpnreset

            hereafter i get the error:
            function: not found.

            what am i doing wrong?

          • bolt says:

            “function” is a Bash keyword. You need to be running it with Bash.

  • K. Callis says:

    I have tried to put your script to use, but I have been having some issues. I use airvpn, and I decided to make use of a Multi VPN WAN connection. On the dashboard, I can see the remote and virtual IP address from the provider, so can I use any of those addresses to feed back to the script?

    I am really interested in getting this working, because many times a day, I find that my connections drop randomly, and would like to restart them automatically.

    • bolt says:

      The latest script at the bottom of the article uses the VPN name to determine which one to restart.

      If you want to go by IP instead, that’s certainly possible, but you’d have to alter the script to look those up. Try inspecting the current version and see if you can figure it out. I’m sure others would be interested 🙂

  • gktje says:

    doesnt work in 2.5.1? do you confirm?

    • bolt says:

      I don’t run 2.5 yet due to a bug that’s fixed in 2.5.2, so waiting for the official release of that. It would probably be helpful if you posted your error message and what you’ve tried to resolve the issue, however.

      • gktje says:

        the methods of ikedisconnect and connect are different.
        so your script does match id with vpnname but it doesn’t disconnect / connect them since the methods used in status_ipsec.php have changed.

        if you install a blank 2.5.1 and investigate /usr/local/www status_ipsec.php you’ll understand what i’m trying to say.

        I have been trying to correct it but haven’t managed to do so (probably cause i suck in php) 🙁

      • gktje says:

        what version are you running btw? i’m looking for the latest compatible version of the script that also lets me install CRON package (not possible in 2.4.?)

        • bolt says:

          Currently on 2.4.5
          I don’t recall installing Cron on this. It may have been standard in at least some earlier versions. Are you sure you don’t have it?
          Also, you can install any package you want, but you may need to add a repo for them.

          • gktje says:

            2.4.3 didn’t let me install cron package on the pfsense 🙁 hence why i upgraded to 2.5.2

          • bolt says:

            How did it not let you? Did you try adding the FreeBSD repository? Are you sure it’s not already there?

  • Harshad Kakatkar says:

    thanks to the original script — I have reused for different purpose as required by one of my customer.

    https://gist.github.com/HarshadkCon/1bcfbbc8ba2b0b6c3696f71bee745a00

    Sharing with everyone if needed.

  • zedug says:

    updated Harshad’s script for use with pfSense 2.6.0

    https://gist.github.com/zedug/b21b820a3b8cb57b262e34b6f2b507da

  • QuitpfS says:

    It would be great if you make this script for IPSec, in version 2.6, thanks in advance

  • abdulkareemqaasim891@gmail.com says:

    I want to join bin moha
    mmad

Leave a Reply to K. Callis Cancel reply

Your email address will not be published. Required fields are marked *