Saturday, September 12, 2009

Running a Web Server on a dynamic IP address

Modern broadband internet speeds make it easy to host your own development/test web server. But the dynamic IP address supplied by most ISPs requires some extra steps to maintain the pointer from the web to your server.

Handling dynamic IP is relatively easy with a DNS service that can handle dynamic IP updates. There are many services available, and I recently moved all my domains to EveryDNS based on their features and straightforward service.

DNS setup

I wanted to keep my existing hosted services and also point sub-domain names to my own development/test server. So I set up the main sites as primary domains (steps 1,3 in image below) pointing to various hosted services:

    
mydomain.com, 'A' record to IP of professional hosting service
mail.mydomain.com, 'CNAME' record to ghs.google.com

and then some dynamic domains (steps 1,2,3 in image below) as sub-domains pointing to the test server:
    
abc.mydomain.com, 'A' record to IP of my-server
xyz.mydomain.com, 'A' record to IP of my-server

dyndomain
Note the DNS names that EveryDns give you, you’ll need to go to your registrar and point your domain name to these name servers (all 4 of them, nice!).

Allow a few minutes or so for this info to filter through the servers, and you should be able to browse to your site.

Updating the dynamic IP

To keep EveryDns automatically updated with your server IP address you call a special page on their website; they check the source of your request and update their records accordingly. There are a few update clients available that do this for you (and some routers provide built in support), but I wanted a bit more control and it was fun to roll my own using powershell.

In summary this script gets your current IP address, compares it to the last IP address update, and if different does a new update:

$getUrl = "http://whatismyip.com/automation/n09230945.asp"
$setUrl = "http://dyn.everydns.net/index.php?ver=0.1"
$user = "your-username"
$pass = "your-password"
$log = "path-to-log-file"
$update = "path-to-cache-file"
$timestamp = (Get-Date).ToString("yyyy.MM.dd HH:mm:ss")

# check

$ip = (new-object System.Net.WebClient).DownloadString($getUrl)
if ($error) {
Add-Content $log "[$timestamp] FAIL** Get ip failed with: $error"
exit
}
if ((Test-Path $update) -and ($ip -eq (Get-Content $update))) {
exit # nothing to do
}

# update

$webclient = new-object System.Net.WebClient
$webclient.Credentials = new-object System.Net.NetworkCredential($user, $pass)
$result = $webclient.DownloadString($setUrl)

# verify

if ($error) {
Add-Content $log "[$timestamp] FAIL** Update id failed with: $error"
exit
}
$code = [Regex]::Match($result, "Exit code: (\d+)").Groups[1].Value
if ($code -eq 0) {
Set-Content $update $ip -Force
Add-Content $log "[$timestamp] UPDATE Set ip: $ip"
}
else {
Add-Content $log "[$timestamp] FAIL** Received exit code: $code"
}

To automate the running of the script, create a new task in Windows Task Scheduler; I chose to Trigger the task at startup and repeat every 5 minutes, and Action start program Powershell with arguments -command "& 'path-to-my-powershell-script-file' " (mind the quotes, single inside double).

Its well worth the effort to be able to spin up new test/demo sites at will.

No comments:

Post a Comment