Netgate Discussion Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search
    • Register
    • Login

    Restarting OpenVPN

    Scheduled Pinned Locked Moved OpenVPN
    29 Posts 5 Posters 19.8k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C
      cyboc
      last edited by

      I would like to automatically restart OpenVPN every night by using cron.

      What command should I use to restart OpenVPN? I saw an old post that says to use this command:

      echo "" | php -q
      

      From what I can tell, it seems to work. Is this the best command to use? Or is there a better way?

      1 Reply Last reply Reply Quote 0
      • jimpJ
        jimp Rebel Alliance Developer Netgate
        last edited by

        Why would you want to do that?

        That command should do it, and is probably the easiest way to accomplish that, but still seems like an odd thing to do.

        Remember: Upvote with the šŸ‘ button for any user/post you find to be helpful, informative, or deserving of recognition!

        Need help fast? Netgate Global Support!

        Do not Chat/PM for help!

        1 Reply Last reply Reply Quote 0
        • C
          cyboc
          last edited by

          Hi Jimp,

          That's a good question. I hope the following answer makes sense.

          Our main office has two internet connections. One is very fast and the other is relatively slow and is meant as a backup connection.

          Our satellite offices' VPN tunnels are configured to always connect to the fast connection first, then the slow one if the fast one is down.

          Sometimes in the middle of the night, our fast connection goes down for a minute or two. During that time, the satellite offices' VPN tunnels automatically switch over to the slow connection. Sometimes we discover this days later when a user complains that the VPN has been slow for several days. Then we have to manually restart the tunnels to get them to use the fast connection again.

          If we automatically restart the tunnels every night, then the longest someone would be on the slow connection would be 24 hours.

          If you have a better idea for automatically switching the tunnels back to the fast connection, I'm all ears.

          1 Reply Last reply Reply Quote 0
          • B
            Briantist
            last edited by

            OpenVPN has a network interface of some kind that can be used to control it. I am 99% sure that pfSense uses this feature for itself to check on status and just generally control it, because when I tried to add the options to make it listen on the IP and port I wanted, all the pfSense built-in stuff broke.

            I would love to know what IP/port it's set to listen to by default in pfSense, because I want to do something similar (basically, I want to stop the VPN when certain conditions are met, and start it again on other conditions). Jim, do you know?

            1 Reply Last reply Reply Quote 0
            • jimpJ
              jimp Rebel Alliance Developer Netgate
              last edited by

              Yeah I suppose that might be needed there. I don't think there is a way to make that happen inside of OpenVPN. Some Googling suggests that others do this (on other platforms) by shutting down the other server processes when they want to, so you're probably doing about the best you can.

              Remember: Upvote with the šŸ‘ button for any user/post you find to be helpful, informative, or deserving of recognition!

              Need help fast? Netgate Global Support!

              Do not Chat/PM for help!

              1 Reply Last reply Reply Quote 0
              • jimpJ
                jimp Rebel Alliance Developer Netgate
                last edited by

                @Briantist:

                OpenVPN has a network interface of some kind that can be used to control it. I am 99% sure that pfSense uses this feature for itself to check on status and just generally control it, because when I tried to add the options to make it listen on the IP and port I wanted, all the pfSense built-in stuff broke.

                I would love to know what IP/port it's set to listen to by default in pfSense, because I want to do something similar (basically, I want to stop the VPN when certain conditions are met, and start it again on other conditions). Jim, do you know?

                It doesn't listen on a port like that, we use a unix socket (/var/etc/openvpn/<something>.sock)</something>

                Remember: Upvote with the šŸ‘ button for any user/post you find to be helpful, informative, or deserving of recognition!

                Need help fast? Netgate Global Support!

                Do not Chat/PM for help!

                1 Reply Last reply Reply Quote 0
                • C
                  cyboc
                  last edited by

                  @jimp:

                  Yeah I suppose that might be needed there. I don't think there is a way to make that happen inside of OpenVPN. Some Googling suggests that others do this (on other platforms) by shutting down the other server processes when they want to, so you're probably doing about the best you can.

                  Yup, I googled around too, hoping that OpenVPN had a built-in feature to restart the tunnels periodically. It seems the answer is "no". Pity. I can't be the only person in the world who needs that feature.Ā  :-[

                  1 Reply Last reply Reply Quote 0
                  • B
                    Briantist
                    last edited by

                    I should still be able to use that then as long as I'm controlling it from pfSense then, as opposed to an outside machine, right? I'm thinking I would install NRPE, and use a cron job to run one of the NRPE scripts, and send control commands to OpenVPN based on the results. Any thoughts? Thanks for the quick response.

                    1 Reply Last reply Reply Quote 0
                    • jimpJ
                      jimp Rebel Alliance Developer Netgate
                      last edited by

                      @cyboc:

                      @jimp:

                      Yeah I suppose that might be needed there. I don't think there is a way to make that happen inside of OpenVPN. Some Googling suggests that others do this (on other platforms) by shutting down the other server processes when they want to, so you're probably doing about the best you can.

                      Yup, I googled around too, hoping that OpenVPN had a built-in feature to restart the tunnels periodically. It seems the answer is "no". Pity. I can't be the only person in the world who needs that feature.Ā  :-[
                      [/quote]

                      Yeah, it seems like it would be a nice feature, but in reality that would involve the client periodically retrying the server connection on its own, potentially disrupting the tunnel there. Favoring stability over speed is usually a good choice, but it would be nice to have the option.

                      Remember: Upvote with the šŸ‘ button for any user/post you find to be helpful, informative, or deserving of recognition!

                      Need help fast? Netgate Global Support!

                      Do not Chat/PM for help!

                      1 Reply Last reply Reply Quote 0
                      • jimpJ
                        jimp Rebel Alliance Developer Netgate
                        last edited by

                        @Briantist:

                        I should still be able to use that then as long as I'm controlling it from pfSense then, as opposed to an outside machine, right? I'm thinking I would install NRPE, and use a cron job to run one of the NRPE scripts, and send control commands to OpenVPN based on the results. Any thoughts? Thanks for the quick response.

                        Probably best to split that off into its own thread.

                        Remember: Upvote with the šŸ‘ button for any user/post you find to be helpful, informative, or deserving of recognition!

                        Need help fast? Netgate Global Support!

                        Do not Chat/PM for help!

                        1 Reply Last reply Reply Quote 0
                        • B
                          Briantist
                          last edited by

                          @cyboc:

                          @jimp:

                          Yeah I suppose that might be needed there. I don't think there is a way to make that happen inside of OpenVPN. Some Googling suggests that others do this (on other platforms) by shutting down the other server processes when they want to, so you're probably doing about the best you can.

                          Yup, I googled around too, hoping that OpenVPN had a built-in feature to restart the tunnels periodically. It seems the answer is "no". Pity. I can't be the only person in the world who needs that feature.Ā  :-[
                          [/quote]
                          I found a way. You have to know which VPN server you're using (pfSense seems to assign them sequential numbers, server1, server2, etc.).

                          Then in cron you can use this:

                          
                          nc -U /var/etc/openvpn/serverX.sock %signal SUGHUP%exit%
                          
                          

                          The X in serverX.sock is the server number I referenced above. The exit is probably not necessary, at least that's what it seems in my testing, but I put it in anyway (the OpenVPN management interface only supports one connection at a time, so the OpenVPN status page in the web GUI is inoperable while you are connected).

                          HTH

                          1 Reply Last reply Reply Quote 0
                          • C
                            cyboc
                            last edited by

                            Hi Brian,

                            Thanks for the tip.

                            After thinking more about the requirements, I have refined them a bit. Instead of restarting the VPN client every night, I am going to restart the VPN whenever I detect that it is connected to the VPN server's secondary (slow) IP address instead of the primary (fast) IP address.

                            The primary IP address is specified by the Server host or address setting on the VPN client config screen (i.e. in the server_addr setting in the pfSense XML config file). The secondary IP address is specified by the remote setting inside the Advanced setting on the VPN client config screen (i.e. in the custom_options setting in the pfSense XML config file).

                            Here is a hackish, unfinished, unpolished PHP script that I am currently working on for this purpose. Please don't flame saying the code sucks. I know it sucks. It's not done yet. So far it seems to work okay in my testing.

                            require_once('config.inc');
                            include('openvpn.inc');
                            
                            // Read in all of the OpenVPN client configs.
                            global $config;
                            if (!is_array($config['openvpn']['openvpn-client']))
                            {
                            Ā  return;
                            }
                            
                            // Find client config for London VPN server
                            $found_config = false;
                            $name = "London";
                            foreach ($config['openvpn']['openvpn-client'] as & $settings)
                            {
                            Ā  if (stripos($settings['description'], $name) !== false)
                            Ā  {
                            Ā  Ā   $found_config = true;
                            Ā  Ā   break;
                            Ā  }
                            }
                            
                            // If client config not found, exit.
                            if (!$found_config)
                            {
                            Ā  echo "Did not find client VPN config for \"$name\".\n";
                            Ā  exit;
                            }
                            
                            // Print the client config.
                            echo "vpnid: {$settings['vpnid']}\n";
                            echo "description: {$settings['description']}\n";
                            echo "server_addr: {$settings['server_addr']}\n";Ā   
                            echo "custom_options: {$settings['custom_options']}\n";
                            
                            // Resolve the configured host name to an IP address.
                            // This is the VPN server's primary IP.
                            $ip = gethostbyname($settings['server_addr']);
                            echo "VPN server primary IP: $ip\n";
                            
                            // Tokenize the custom_options to get the VPN 
                            // server's secondary IP.
                            $tok = strtok($settings['custom_options'], " \n\t;");
                            while ($tok !== false) {
                            Ā  if (strcasecmp($tok, 'remote') == 0)
                            Ā  {
                            Ā  Ā  $tok = strtok(" \n\t;");
                            Ā  Ā  if ($tok !== false)
                            Ā  Ā  {
                            Ā  Ā  Ā  $ip_secondary = gethostbyname($tok);
                            Ā  Ā  Ā  echo "VPN server secondary IP: $ip_secondary\n";Ā  Ā  
                            Ā  Ā  }
                            Ā  }
                            Ā  $tok = strtok(" \n\t;");
                            }
                            
                            // Find the status for the VPN client.
                            $found_status = false;
                            $clients = openvpn_get_active_clients();
                            foreach ($clients as $client) 
                            {
                            Ā  if (stripos($client['name'], $name) !== false)
                            Ā  {
                            Ā  Ā  $found_status = true;
                            Ā  Ā  break;
                            Ā  }
                            }
                            
                            // If client status not found, exit.
                            if (!$found_config)
                            {
                            Ā  echo "Did not find VPN client status for \"$name\".\n";
                            Ā  exit;
                            }
                            
                            // Print the client status
                            echo "name: {$client['name']}\n";
                            echo "mgmt: {$client['mgmt']}\n";
                            echo "status: {$client['status']}\n";
                            echo "remote_host: {$client['remote_host']}";
                            
                            // See if the client is connected to a secondary IP.
                            // Note: $client['remote_host'] has trailing white space that
                            // we must trim before comparing to $ip
                            $remote_host = rtrim($client['remote_host']);
                            if ($client['status'] == 'up' && $remote_host !== $ip)
                            {
                            Ā  echo "The VPN client is connected to the server's secondary IP.\n";
                            }
                            else 
                            {
                            Ā  echo "The VPN client is NOT connected to the server's secondary IP.\n";
                            Ā  echo "NOT restarting VPN.\n";
                            Ā  exit;
                            }
                            
                            // If we got this far, we will want to restart the VPN client
                            // so it connects to primary IP instead of secondary IP.
                            
                            // Before trying to connect to primary IP, we have to make sure
                            // we can ping it. If we can't ping it, there's no sense in
                            // trying to connect to it. Furthermore, that is probably
                            // the reason why the client is currently connected to the 
                            // secondary IP.
                            exec("ping -t 10 -o $ip", $output, $return_var);
                            echo "ping return_var: $return_var\n";
                            
                            // A return value of 0 means at least one ping was replied to.
                            // In other words, the IP address is up and we should be
                            // able to restart to VPN to connect to it.
                            if ($return_var == 0)
                            {
                            Ā  echo "Restarting VPN.\n";
                            Ā  openvpn_restart('client', $settings);
                            Ā  echo "Finished restarting VPN.\n";
                            }
                            ?>
                            

                            As you can see, the script makes use of the handy config variables in config.inc and the handy functions in openvpn.inc. Rather than hard-coding the client vpnid number in my script, I scan all of the client configs for a description containing 'London'; that will be the client that connects to our London server.

                            When finished, I will store this script somewhere in the pfSense filesystem (any suggestions as to an appropriate directory to store it in?). Then I will call it periodically with cron, perhaps once per hour.

                            HTH

                            1 Reply Last reply Reply Quote 0
                            • B
                              Briantist
                              last edited by

                              Neat! For my purposes, I am actually doing more than just restarting, and I considered using PHP but I was really looking for something that didn't rely on external files. Basically, I want to be able to restore a config backup and not have to restore any random files to get this working again. I don't like that I am hard coding the server number, but I'm okay with it for now.

                              I looked into the add-on package that lets you enter PHP code in the web gui (PHP Service) and runs it every second, but it was buggy and didn't work right, so I promptly uninstalled it. Please post your final solution; I'm interested, even if it's just to run the PHP via cron.

                              1 Reply Last reply Reply Quote 0
                              • C
                                cyboc
                                last edited by

                                I haven't tried it yet but I think the Shellcmd package might let you echo some PHP code to a file in /tmp on system startup. Then you should be able to call that script from cron. This should allow you to store the script (somewhat indirectly) inside the exported config file. Again, I haven't tried this yet but it seems like it could do the job.

                                1 Reply Last reply Reply Quote 0
                                • C
                                  cyboc
                                  last edited by

                                  Meh. I tried Shellcmd. The GUI for it only lets you enter one line. Not really convenient for what I wanted to do.

                                  1 Reply Last reply Reply Quote 0
                                  • C
                                    cyboc
                                    last edited by

                                    Brian,

                                    I am running the embedded version of pfSense. I just tried storing my custom script in /scripts. Then I rebooted. Low and behold, after rebooting, my script was still in /scripts. I expected that it would have been wiped out by a reboot but I was wrong. That's good. Now I can store my script there. It's not quite the same as storing it in the XML config file but at least I can keep all my scripts in one place.

                                    1 Reply Last reply Reply Quote 0
                                    • B
                                      Briantist
                                      last edited by

                                      Yeah the embedded version won't delete your files on you. You might have some trouble writing things if you don't mount the filesystem as RW first, but anyway that's not what I was worried about. I am doing something that will be used at multiple locations, and I just don't want to have backup additional files with the config that I would then have to put back in place in the event of a restore.

                                      From what I could tell there is no way to do multiple lines with echo in the bourne shell, so you would need to install bash (another dependency I don't want). It just happens that cron does have a way to send mult-line input (the % character) so that helped me out there.

                                      1 Reply Last reply Reply Quote 0
                                      • C
                                        cyboc
                                        last edited by

                                        /scripts already seems to be mounted writeable. I did not have to do a remount-rw. :)

                                        1 Reply Last reply Reply Quote 0
                                        • C
                                          cyboc
                                          last edited by

                                          Brian,

                                          I have revised the code a bit. For example, I now write some messages to the system log by calling the logger command. I ran this script once per hour last night using cron. It seems to work fine so far. Still requires more testing. For example, I will have to pull the plug on our primary internet connection to force the VPN client to switchover to the secondary IP (i.e. backup connection). Then I will have to verify that this script forces the connection back to the primary IP.

                                          Here's the current version of the script:

                                          #!/usr/local/bin/php -f
                                          require_once('config.inc');
                                          include('openvpn.inc');
                                          
                                          // Read in all of the OpenVPN client configs.
                                          global $config;
                                          if (!is_array($config['openvpn']['openvpn-client']))
                                          {
                                          Ā  return;
                                          }
                                          
                                          // Find client config for London VPN server
                                          $found_config = false;
                                          $name = "London";
                                          foreach ($config['openvpn']['openvpn-client'] as & $settings)
                                          {
                                          Ā  if (stripos($settings['description'], $name) !== false)
                                          Ā  {
                                          Ā  Ā   $found_config = true;
                                          Ā  Ā   break;
                                          Ā  }
                                          }
                                          
                                          // If client config not found, exit.
                                          if (!$found_config)
                                          {
                                          Ā  echo "Did not find client VPN config for \"$name\".\n";
                                          Ā  exit;
                                          }
                                          
                                          // Print the client config.
                                          echo "vpnid: {$settings['vpnid']}\n";
                                          echo "description: {$settings['description']}\n";
                                          echo "server_addr: {$settings['server_addr']}\n";Ā   
                                          echo "custom_options: {$settings['custom_options']}\n";
                                          
                                          // Resolve the configured host name to an IP address.
                                          // This is the VPN server's primary IP.
                                          $ip = gethostbyname($settings['server_addr']);
                                          echo "VPN server primary IP: $ip\n";
                                          
                                          // Tokenize the custom_options to get the VPN 
                                          // server's secondary IP.
                                          $tok = strtok($settings['custom_options'], " \n\t;");
                                          while ($tok !== false) {
                                          Ā  if (strcasecmp($tok, 'remote') == 0)
                                          Ā  {
                                          Ā  Ā  $tok = strtok(" \n\t;");
                                          Ā  Ā  if ($tok !== false)
                                          Ā  Ā  {
                                          Ā  Ā  Ā  $ip_secondary = gethostbyname($tok);
                                          Ā  Ā  Ā  echo "VPN server secondary IP: $ip_secondary\n";Ā  Ā  
                                          Ā  Ā  }
                                          Ā  }
                                          Ā  $tok = strtok(" \n\t;");
                                          }
                                          
                                          // Find the status for the VPN client.
                                          $found_status = false;
                                          $clients = openvpn_get_active_clients();
                                          foreach ($clients as $client) 
                                          {
                                          Ā  if (stripos($client['name'], $name) !== false)
                                          Ā  {
                                          Ā  Ā  $found_status = true;
                                          Ā  Ā  break;
                                          Ā  }
                                          }
                                          
                                          // If client status not found, exit.
                                          if (!$found_config)
                                          {
                                          Ā  echo "Did not find VPN client status for \"$name\".\n";
                                          Ā  exit;
                                          }
                                          
                                          // Print the client status
                                          echo "name: {$client['name']}\n";
                                          echo "mgmt: {$client['mgmt']}\n";
                                          echo "status: {$client['status']}\n";
                                          echo "remote_host: {$client['remote_host']}";
                                          
                                          // See if the client is connected to a secondary IP.
                                          // Note: $client['remote_host'] has trailing white space that
                                          // we must trim before comparing to $ip
                                          $remote_host = rtrim($client['remote_host']);
                                          if ($client['status'] == 'up' && $remote_host == $ip)
                                          {
                                          Ā  $msg = "The $name VPN client is connected to $ip (VPN server primary IP). Not restarting client.\n";
                                          Ā  echo $msg;
                                          Ā  exec("logger '$msg'");
                                          Ā  exit;
                                          }
                                          else if ($client['status'] == 'up')
                                          {
                                          Ā  $msg = "The $name VPN client is connected to $ip (VPN server secondary IP).\n";
                                          Ā  echo $msg;
                                          Ā  exec("logger '$msg'");
                                          }
                                          else
                                          {
                                          Ā  $msg = "The $name VPN client is not connected. Current status is {$client['status']}.\n";
                                          Ā  echo $msg;
                                          Ā  exec("logger '$msg'");
                                          Ā  exit;
                                          }
                                          
                                          // If we got this far, we will want to restart the VPN client
                                          // so it connects to primary IP instead of secondary IP.
                                          
                                          // Before trying to connect to primary IP, we have to make sure
                                          // we can ping it. If we can't ping it, there's no sense in
                                          // trying to connect to it. Furthermore, that is probably
                                          // the reason why the client is currently connected to the 
                                          // secondary IP.
                                          exec("ping -t 10 -o $ip", $output, $return_var);
                                          echo "ping return_var: $return_var\n";
                                          
                                          // A return value of 0 means at least one ping was replied to.
                                          // In other words, the IP address is up and we should be
                                          // able to restart to VPN to connect to it.
                                          if ($return_var == 0)
                                          {
                                          Ā  $msg = "VPN server primary IP is up. Restarting $name VPN client.\n";
                                          Ā  echo $msg;
                                          Ā  exec("logger '$msg'");
                                          Ā  openvpn_restart('client', $settings);
                                          Ā  $msg = "Finished restarting $name VPN client.\n";
                                          Ā  echo $msg;
                                          Ā  exec("logger '$msg'");
                                          }
                                          else
                                          {
                                          Ā  $msg = "VPN server primary IP is down. Not restarting $name VPN client.\n";
                                          Ā  echo $msg;
                                          Ā  exec("logger '$msg'");
                                          }
                                          ?>
                                          
                                          1 Reply Last reply Reply Quote 0
                                          • GruensFroeschliG
                                            GruensFroeschli
                                            last edited by

                                            Having just read this thread i something think you're shooting on sparrows with cannons. (Writing scripts, changing php).

                                            Is it not feasible to have 2 OpenVPN tunnels up with two different tranfer subnets.
                                            Each VPN tunnel on it's own WAN.

                                            When both tunnels are up a failover-pool forces all traffic to the fast connection.
                                            Should it go down, the backup connection will be used.
                                            If the connection comes back up everything switches to the fast connection again.

                                            Should asymetric routing occur (for whatever reasons) traffic could even be NATed into the tunnel to ensure the answer comes back the same tunnel.

                                            We do what we must, because we can.

                                            Asking questions the smart way: http://www.catb.org/esr/faqs/smart-questions.html

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Copyright 2025 Rubicon Communications LLC (Netgate). All rights reserved.