Skip to content

Instantly share code, notes, and snippets.

@cmdruid
Last active November 23, 2022 21:11
Show Gist options
  • Save cmdruid/4556564 to your computer and use it in GitHub Desktop.
Save cmdruid/4556564 to your computer and use it in GitHub Desktop.
This is my Ruby DNS Updater script. If you are using an .htaccess file to forward a domain or subdomain to your server's dynamic IP address, this script will make sure that .htaccess file stays updated with your server's current address. This script is an alternative to using services like Dynamic DNS or No-IP. This script uses SFTP and the 'net…
# This is my Ruby DNS Updater script. If you are using an .htaccess
# file to forward a domain or subdomain to your server's dynamic IP
# address, this script will make sure that file stays updated with
# your server's current address. This script is an alternative to
# using services like Dynamic DNS.
# This script uses SFTP and the 'net-sftp' gem to connect to your
# hosting via a secure connection. You must add all your relevant
# information below in order for this script to work.
# Make sure the three files (rubydns_updater.rb, rubydns_methods.rb,
# config.yml) are in the same directory. Run 'ruby rubydns_updater.rb'
# to execute the script. You can use cron to run this script every so
# often on a schedule.
# In order for this script to work, you need to have the forwarding
# configurations already setup in your .htaccess file. An example:
# # Ruby DNS Updater
# RewriteCond %{HTTP_HOST} ^subdomain.yourdomain.com [NC]
# RewriteRule ^(.*)$ 12.34.56.78$1 [L,R=301]
# This is my first ruby script, so there's still a lot of room for
# improvement. The script works for me, but there might be some
# bugs for you. Make sure to backup your .htaccess file before using
# this script!! If you have any suggestions, please let me know via
# e-mail at: suggestions@karmadragon.me. Thank you!
host: yourdoman.com # Your host's FTP/SFTP address
user: ftp_username # Your username
pass: ftp_password # Your password
file_path: /home/public/.htaccess # path to your .htacces file
# Your .htaccess file might have multiple IP addresses listed, which
# makes it hard to locate the one we need to check. To make sure we
# are checking the right address, you need to place a unique header
# above the forwarding rules for your server. The script will look
# for this header in your .htaccess file and use it as a reference
# when checking your address. An example would be "# Ruby DNS Updater"
# Leave out any "#" pound signs below, or it will break the script!
entry_header: Ruby DNS Updater
# The best way to update your .htaccess file is to save the changes
# to disk before uploading them to your host. This specifies the
# file path used for temporarily saving these changes. By default,
# this file is saved in the same local directory as the script.
temp_file: rdutemp
# We need an external website to give us our public IP. Some websites
# offer this service for free. The default site listed below should
# work, but if that service ever becomes unreliable, you can specify
# another site to use. Depending on the website, you might have to
# modify the 'publicAddress' method in the 'rubydns_methods.rb' file
# in order to parse the correct address out of the website data.
lookup_url: http://remote-ip.herokuapp.com
require 'net/sftp' # The gem net-sftp must be installed
require 'net/http'
# Finds the current WAN IP of the machine and aborts if not present
def publicAddress(website)
public_ip = Net::HTTP.get(URI website)
if public_ip != nil
return public_ip
else
Kernel::raise("Public address not detected! Maybe you are in a test environment?")
# pubic_ip = '12.34.56.78' # If in a testing environment, use this line (and comment out the above line) to set a fake IP
end
end
# Connects to host and downloads file into array, aborts if not present
def fileDownload(host, user, pass, path)
Net::SFTP.start(host, user, :password => pass) do |sftp|
a = []
s = sftp.download!(path)
s != nil ? s.each_line {|line| a.push line} : Kernel::raise("File download returned nil!")
puts "Reading settings from host..."
return a
end
end
# Parses file contents for header and returns IP, aborts if not present
def retrieveAddress(array, header)
i = array.index{|s| s.include?(header)}
i != nil ? i = i + 2 : Kernel::raise("Header not found in file!")
ip = array[i]
return ip[/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/]
end
# Write changes to a local file
def changeAddress(array, old_address, new_address, tempfile)
array != nil ? nil : Kernel::raise("Array is not supposed to equal nil!")
s = array.join.gsub(old_address, new_address)
File.exist?(tempfile) ? File.delete(tempfile) : nil
File.open(tempfile, 'w') {|f| f.write(s)}
puts "Changes saved and awaiting upload..."
end
# Upload temporary file to server
def fileUpload (host, user, pass, path, tempfile)
File.exist?(tempfile) ? nil : Kernel::raise("Cannot write to server, local file does not exist!")
Net::SFTP.start(host, user, :password => pass) {|sftp| sftp.upload!(tempfile, path)}
puts "Uploaded new settings to host!"
end
# This is my Ruby DNS Updater script. If you are using an .htaccess
# file to forward a domain or subdomain to your server's dynamic IP
# address, this script will make sure that file stays updated with
# your server's current address. This script is an alternative to
# using services like Dynamic DNS.
# This script uses SFTP and the 'net-sftp' gem to connect to your
# hosting via a secure connection. You must add your FTP login
# information to the config.yml file in order for this script to
# work.
# Make sure the three files (rubydns_updater.rb, rubydns_methods.rb,
# config.yml) are in the same directory. Run 'ruby rubydns_updater.rb'
# to execute the script. You can use cron to run this script every so
# often on a schedule.
# This is my first ruby script, so there's still a lot of room for
# improvement. The script works for me, but there might be some
# bugs for you. Make sure to backup your .htaccess file before using
# this script!!
# If you have any suggestions, please let me know via e-mail at
# suggestions@karmadragon.me. Thank you!
# List of things to do:
# * Add better error checking for the config file
# * Make better use of 'rescue' and improve error handling
# * Add an 'ensure' method to close the rdutmp file after write
# * Add an 'ensure' method to close the SFTP sessions
# * Add a method for generating the proper forwarding rules for
# you (if they don't exist) and appending it to your .htaccess.
require 'yaml'
require_relative 'rubydns_methods'
# Loads our configuration file
File.exist?('config.yml') ? nil : Process::abort("Couldn't read config.yml! Aborting!")
settings = YAML::load_file "config.yml"
puts "Configuration loaded!"
reCheck = false
loopCheck = 0
while reCheck == false && loopCheck < 2
# Download the file and set the addresses to values
fileArray = fileDownload(settings['host'], settings['user'], settings['pass'], settings['file_path'])
public_address = publicAddress(settings['lookup_url'])
forward_address = retrieveAddress(fileArray, settings['rules_header'])
# Compare the addresses to see if they match. If not, update new address to server.
if public_address != forward_address && public_address != nil && forward_address != nil
puts "Forwarding address #{forward_address} doesn't match server! (#{public_address})"
changeAddress(fileArray, forward_address, public_address, settings['temp_file'])
fileUpload(settings['host'], settings['user'], settings['pass'], settings['file_path'], settings['temp_file'])
puts loopCheck < 2 ? "Verifying the changes..." : "Unable to verify! Please check your forwarding settings!"
loopCheck += 1
elsif forward_address == public_address && forward_address != nil
puts "Forwarding address matches server with #{forward_address}! We're good!"
reCheck = true
else
# If this message gets triggered, one of the addresses returned nil, which is bad
puts "Something went wrong! Detected forwarding address (#{forward_address}) and public address (#{public_address})!"
recheck = true
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment