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

    CRON job for failover on pfSense

    Scheduled Pinned Locked Moved Off-Topic & Non-Support Discussion
    1 Posts 1 Posters 486 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.
    • B
      border
      last edited by

      Hi,

      I wrote a small script for webserver failover that I run as a CRON job on the pfSense system. The script checks if a remote website is running and in case it is down, a local backup server is started and DNS settings are adjusted. When the remote server is running again, the local server is shutdown (after a timeout based on the TTL of the remote server in order to allow DNS propagation).

      My question is: (a) am I not overloading the pfSense system (Netgate SG-3100) by running this script in CRON, (b) does this have a negative effect on the security of the gateway?

      While the script works fine, I have set CRON to only run it every 15 minutes (higher frequency would be nice though).

      For anybody interested in the script, I include it in the post.

      regards.

      <?php
      
      // requirements: an account on DNS server to change A records, a backup server with SSH access, keyless login to backup server, the correct firewall and proxy settings for providing access to the backup server
      
      //
      // params
      //
      $hosts    = array('mydomain.com','www.mydomain.com','my.mydomain.com');	// the URL's to be redirected
      $svr_ip   = '192.168.1.10';												// the IP address of the backup server
      $svr_mac  = 'e8:2c:b3:fc:3d:1b';										// the Mac address of the backup server
      $port     = 22; 														// the ssh port of the backup server
      $rsa_dir  = '/root/.ssh';												// the key location on pfSense system
      $ssh_user = 'user2';													// the user account on backup server
      $rem_svr  = 'remote.mydomain.com';										// the URL to monitor
      $rem_port = 443;														// the service port on the remote server
      $dns_usr  = 'user1';													// the user account on DNS server
      $dns_pwd  = 'mypasswd';													// the password on DNS server
      $dns_svr  = 'https://eurodyndns.org/update/';							// the URL of the DNS update service
      $dns_ttl  = 15;															// the TTL of the domain
      $status   = '/root/failover.on';										// the file indicating the status
      $ip_svr   = 'http://checkip.dyndns.com/';								// URL to obtain external IP address
      $reboot   = '/sbin/shutdown';											// shutdown command on backup server
      //
      // check is site in online
      //
      if(!$socket =@ fsockopen($rem_svr, $rem_port, $errno, $errstr, 30)) {
      	//
      	// check if site is already in offline mode
      	//
      	if (!file_exists($status)) {
      		//
      		// wake backup server
      		//
      		$wake = new WakeOnLan;
      		$wake->WakeUp($svr_mac,$svr_ip);
      		//
      		// update DNS server
      		//
              $ext = file_get_contents($ip_svr);
              preg_match('/\b(?:\d{1,3}\.){3}\d{1,3}\b/', $ext, $m);
              $addr = $m[0];
      		$up = new UpdateDNS;
      		foreach ($hosts as $host) {
      			$up->update($addr,$host,$dns_usr,$dns_pwd,$dns_svr);
      		}
      		date_default_timezone_set("Europe/Brussels");
      		file_put_contents($status,time());
      	}
      } else {
      	if (file_exists($status)) {
      		//
      		// site recovered: get address of the site (in case it has changed)
      		//
                      $addr = gethostbyname($rem_svr);
                      //
                      // update DNS server
                      //
                      $up = new UpdateDNS;
                      foreach ($hosts as $host) {
                              $up->update($addr,$host,$dns_usr,$dns_pwd, $dns_svr);
                      }
      		//
      		// remove failover flag
      		//
      		unlink($status);
      		//
      		// shutdown backup server
      		//
      		$conn = ssh2_connect($svr_ip, $port, array('hostkey'=>'ssh-rsa'));
      		if (ssh2_auth_pubkey_file($conn, $ssh_user, $rsa_dir.'/id_rsa.pub', $rsa_dir.'/id_rsa')) {
      		        $res = ssh2_exec($conn, 'sudo '.$reboot."+".(2*$dns_ttl));
      		}
      	}
      }
      class UpdateDNS {
      	public static function update($addr,$fqdn,$user,$pwd,$dns_svr) {
      		$ch = curl_init();
      		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 
      		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);   
              curl_setopt($ch, CURLOPT_TIMEOUT, 120); 
      		curl_setopt($ch, CURLOPT_USERPWD, $user.':'.$pwd);
              curl_setopt($ch, CURLOPT_URL, $dns_svr . '?hostname=' . $fqdn . '&myip=' . $addr);
      		$res = curl_exec($ch);
      		curl_close($ch);
      	}
      }
      class WakeOnLAN
      {
          public static function wakeUp($macAddressHexadecimal, $broadcastAddress)
          {
              $macAddressHexadecimal = str_replace(':', '', $macAddressHexadecimal);
              if (!ctype_xdigit($macAddressHexadecimal)) {
                  throw new \Exception('Mac address invalid, only 0-9 and a-f are allowed');
              }
              $macAddressBinary = pack('H12', $macAddressHexadecimal);
              $magicPacket = str_repeat(chr(0xff), 6).str_repeat($macAddressBinary, 16);
              if (!$fp = fsockopen('udp://' . $broadcastAddress, 7, $errno, $errstr, 2)) {
                  throw new \Exception("Cannot open UDP socket: {$errstr}", $errno);
              }
              fputs($fp, $magicPacket);
              fclose($fp);
          }
      }
      
      ?>
      
      1 Reply Last reply Reply Quote 0
      • First post
        Last post
      Copyright 2025 Rubicon Communications LLC (Netgate). All rights reserved.