If you are using PowerDNS for round robin on multiple websites, you can set it up so that it will return only the records for sites that are up. I set up a Ruby daemon to monitor sites and connect to the PowerDNS MySQL table used by PowerDNS on Rails. You can use any language or system you like. It just needs to be able to access your PowerDNS database.
First add the following line to /etc/powerdns/pdns.conf:
gmysql-any-query=select content,ttl,prio,type,domain_id,name from records where name='%s' and (prio<>-1 or prio is null)
Thats the trickiest part. If you mess up on the sql query, PowerDNS may not return any results for your domain.
Then restart pdns. I use CentOS so I type
service pdns restart
Now you just need a daemon to monitor your websites. Something like the following might work for you:
#!/usr/bin/env ruby
require 'net/http'
require 'rubygems'
require 'activerecord'
SITE_ADDRESSES = %w( www.yourdomain.com www.example.com )
SITE_THAT_IS_ALWAYS_UP = "" # some well known site that is always up
class Record < ActiveRecord::Base
ActiveRecord::Base.establish_connection(:adapter => "mysql",
:encoding => "utf8", :database => "powerdns_production",
:username => "your_mysql_username", :password => "your_secret_password_here",
:host => "ns1.your_isp.com")
set_inheritance_column :ruby_type
end
$running = true
def signal_trap_exit(signal_name)
puts "#{Time.now} received #{signal_name} signal"
$running = false
end
our_exit_signals = ["TERM", "INT", "KILL", "HUP"]
for exit_signal_name in our_exit_signals
Signal.trap(exit_signal_name, "signal_trap_exit('#{exit_signal_name}')")
end
def check_internet
begin
Timeout::timeout(5) do
Net::HTTP.get_response(SITE_THAT_IS_ALWAYS_UP, "/", 80) do |response|
return response.code.match(/2|3\d{2}/)
end
end
rescue => e
puts "#{Time.now} Error connecting to internet: #{e}"
return false
end
end
def get_site_ip_addresses
begin
Record.find(:all, :conditions => ["type = ? and name in (?)", "A", SITE_ADDRESSES])
rescue => e
puts "#{Time.now} Error finding all records: #{e}"
return []
end
end
def make_inactive(ip_record)
Record.update_all("prio=-1", "name='#{ip_record.name}' and content='#{ip_record.content}'")
end
def make_active(ip_record)
Record.update_all("prio=1", "name='#{ip_record.name}' and content='#{ip_record.content}'")
end
while($running) do
get_site_ip_addresses.each do |ip_address|
begin
Timeout::timeout(5) do
Net::HTTP.get_response(ip_address.content.to_s, "/", 80) do |response|
puts "#{Time.now} Response code for #{ip_address.content.to_s}: #{response.code}"
make_active(ip_address) if ip_address.prio == -1
end
end
rescue => e
puts "#{Time.now} Error connecting to #{ip_address.content.to_s}: #{e}"
if check_internet
make_inactive(ip_address) unless ip_address.prio == -1
end
end
end
sleep 15 if $running
end