Skip to content

Instantly share code, notes, and snippets.

@schrockwell
Created August 21, 2012 12:52
Show Gist options
  • Save schrockwell/3415112 to your computer and use it in GitHub Desktop.
Save schrockwell/3415112 to your computer and use it in GitHub Desktop.
Linode dynamic DNS updater v0.0.3
#! /usr/bin/env ruby
#
# Linode dynamic DNS updater
# Version 0.0.3
# August 21, 2012
#
# By Rockwell Schrock
# [email protected]
# https://gist.github.com/3415112
#
# This Ruby script updates a Linode DNS listing with your public IP
# address. Think of it as a personalized dynamic DNS service. Throw
# it in a crontab or a system init script for +1 effectiveness.
#
# You only have to set two constants:
#
# RedirectDomain: This is the fully-qualified domain you wish to
# forward, of the form "[subdomain].[domain].[tld]". The script
# will automatically figure out the Linode DomainID and ResourceID
# for you! If the subdomain A record does not yet exist, it will be
# created. Nifty, huh?
#
# APIKey: This is the Linode developer API key from the 'my profile'
# link at the top-right of the Linode Manager. Mmm, copypasta.
#
# Enjoy!
require 'uri'
require 'net/http'
require 'net/https'
require 'json'
RedirectDomain = '[SUBDOMAIN.EXAMPLE.COM]'
APIKey = '[LINODE API KEY]'
PublicIPURL = 'http://icanhazip.com/'
APIURL = 'https://api.linode.com/?api_key=%s&api_action=%s'
def execute(action, params)
url = APIURL % [APIKey, action]
param_strings = params.map { |param, value| "#{param}=#{URI.escape(value)}" }
url << '&' << param_strings * '&'
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
JSON.parse(response.body)
end
# Figure out the subdomain
subdomain_name = RedirectDomain.split('.')[0]
domain_name = RedirectDomain.split('.')[1..2] * '.'
# Get the public IP
public_ip = Net::HTTP.get(URI(PublicIPURL)).chomp
# First find the domain ID
response = execute('domain.list', {})
response['DATA'].each do |domain|
if domain['DOMAIN'].downcase == domain_name.downcase
@domain_id = domain['DOMAINID'].to_s
break
end
end
raise "Domain #{domain_name} not found" unless @domain_id
# Now get the resource ID, and create it if not already there
response = execute('domain.resource.list', { :DomainID => @domain_id })
response['DATA'].each do |resource|
if resource['TYPE'].downcase == 'a' and resource['NAME'].downcase == subdomain_name.downcase
@resource_id = resource['RESOURCEID'].to_s
@old_ip = resource['TARGET']
break
end
end
if @resource_id
if @old_ip == public_ip
puts "Subdomain '#{subdomain_name}' found, no update needed"
else
puts "Subdomain '#{subdomain_name}' found, updating..."
response = execute('domain.resource.update', { :DomainID => @domain_id, :ResourceID => @resource_id, :Target => public_ip })
end
else
puts "Subdomain '#{subdomain_name}' not found, creating..."
response = execute('domain.resource.create', { :DomainID => @domain_id, :Type => 'A', :Name => subdomain_name, :Target => public_ip })
end
puts "Updated #{RedirectDomain} to #{public_ip}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment