Projects Blog

NearlyFreeSpeech.NET as a dynamic DNS provider

Dynamic DNS services provide great value to people who wish to host their own services at home or any place without a static IP address. Providers include DynDNS and No-Ip. However, for free they only give you a subdomain of their own site (e.g. MySite.no-ip.org). They will, however, host your domain’s DNS services but if you are like me, you already have your own domain and DNS hosting that probably came with your web host.

I use NearlyFreeSpeech to host my website and DNS and I wanted to use that DNS service to give my home servers a name on the internet. NearlyFreeSpeech has an API(requires login) which you can use to make changes to your account in creative ways. I have only seen one other article about this topic that used perl and some CPAN modules (here). I created a method for using PHP and curl instead so I didn’t need to install anything extra. Here’s how you do it:

  1. Register for an API key for your NearlyFreeSpeech.net account. Fill out a support request and they will send you one.
  2. Login to your NFS SSH account and open a text editor
    nano /home/public/dynamicdns.php

    Copy and paste the following into your text editor and save:

    <?php
    require_once("NFSN/API/Manager.php");
    
    //CONFIGURE THIS STUFF
    $strLogin = "MYUSERNAME";
    $strAPIKey = "MYAPIKEY";
    $subdomain = "MYSUBDOMAIN";  //Example: home , work , grandma
    $domain = "MYDOMAIN";  //Example: google.com , mydomain.com , school.org
    
    $bDebug = false;
    $api = new APIManager($strLogin, $strAPIKey, $bDebug);
    $dns = $api->NewDNS($domain);
    $entries = $dns->ListRRs($subdomain);
    $old = "";
    $new = $_SERVER['REMOTE_ADDR'];
    
    $entries = split(",", $entries);
    $old = split(":", $entries[2]);
    $old = str_replace("\"", "", $old[1]);
    
    //Check that the script has your IP address
    if ($new != "")
    {
        //Remove the old DNS entry for the subdomain if it exists
        if ($old != "")
        {
            $dns->RemoveRR($subdomain, "A", $old);
        }
    
        //Add new subdomain DNS entry
        $dns->AddRR($subdomain, "A", $new);
        print "$new\nSuccess";
    }
    else
    {
        print "$new\nFailed";
    }
    ?>
    
  3. Edit the variables near the top to match your situation. strLogin should be the username that you use to login to the NFS.NET website and not the one you use to SSH into your hosted site. strAPIkey should be the API key that you received from support in the first step. Subdomain should be the name you want your subdomain to be. Domain should be the domain you are having hosted by NFS (in my case, arrington.me). Save the file.
  4. Test it. Navigate to your site using your web browser (http://mydomain.com/dynamicdns.php). If all goes well, you should see your current public IP address and the word “Success.” You will be able to see your IP address as a new “A” resource record in your account on NearlyFreeSpeech.Net.

Securing the Script

So now you have a script that works, right? Great! But we don’t want just anybody to access it and change the IP address and potentially create a MITM attack. We can use Apache’s basic authentication to force you to enter a username and password before the script will be run.

  1. Where you saved your dynamicdns.php script, create a .htaccess file.
    nano /home/public/.htaccess
    Add the following:

    AuthUserFile /PATH/TO/.HTPASSWD
    AuthType Basic
    AuthName "dns"
    
      Require valid-user
    
    
  2. We now want to create a .htpasswd file to store our user credentials. I stored mine in my /home/protected/ directory. Because NFS.NET does some weird gymnastics to show protect users and alias file paths, you will need to use the full path that Apache uses to find your .htpasswd file. Login to your NFS.NET account and click on “Sites” and then the “Short Name” for the site you are setting this up on. Towards the bottom you will find “Apache Site Root.” It will look like /d6/sitename/
  3. Open .htaccess file that we created above and edit the AuthUserFile line to reflect your apache site root discovery. Example: AuthUserFile /d6/sitename/protected/.htpasswd
  4. To create your .htpasswd file, you will need a username and password you want to use to protect your script. Use whatever you want for these but I recommend using a VERY strong password because it IS accessible via the internet and because you will not need to remember it if you automate the process (described below). You can use GRC’s Ultra High Security Passwords page to generate a very high quality password. You may even consider using it to generate a username too! You may want to copy it to a text editor temporarily while we configure some stuff.
  5. While SSHed into your NFS.NET site, run the following command, replacing MYUSERNAME with the username you chose:
    htpasswd -c -s /home/protected/.htpasswd MYUSERNAME
    It will prompt you for your new password twice. You may want to copy and paste in the password you saved from GRC’s website. It will create the file and add the user credentials to it. It will also hash the password using SHA which should be sufficient for this use and if you used a very long password. Your .htaccess file will look something like this:

    MYUSERNAME:{SHA}A95sVwv+JL/DKMzXyka3bq2vQzQ=
  6. Visit your website again (http://mydomain.com/dynamicdns.php). It should prompt you for your credentials. Try inputting something that would fail to test that the authentication is working properly. Then test the correct credentials you used above. You should get the same page as before with your IP address and the word “Success.”

Automating the Process; Final Thoughts

Your dynamic IP address from your ISP is never guaranteed to be the same. To set up automatic renewal, I set up curl to hit the script every so often via cron on my Linux servers or on my DD-WRT router. You can use a line like this for cron:

30 5 * * * root "curl http://mydomain.com/dynamicdns.php --user MYUSERNAME:MYPASSWORD"

This will make the NFS.NET web server run your new script at 5:30am every day. For information about how to use cron, see my resources section.

This is the best solution I have found for having my own, (very) inexpensive DNS hosting and domain with dynamic DNS for my hosts. Typically, I would set up a new script for each host that I wanted to give a subdomain (e.g. office.php for office.mydomain.com, grandma.php for grandma.mydomain.com, etc). In theory, you could set up a single script to manage all of these by passing your intended subdomain as a POST parameter with curl.

It should be noted that if you are not using SSL for your web hosting (NFS.NET does not offer this currently), your password and username can be intercepted when passing over the network. This is not intended to be a super secure solution, just a simple and inexpensive one. If security is a concern, you may consider using the perl and CPAN method linked above.

Resources


Categorised as: Networking


10 Comments

  1. Therese says:

    Fantastic how-to!

    Just a quick note though: I was unable to get it to run successfully on my domain until I removed “!–” after the opening tag (NewDNS($domain);” to “$dns = $api->NewDNS($domain);” in line 1 of the script. I also removed any comments from the script for good luck. 😉

    Thanks again for the great guide, I’m planning to put this to good use!

  2. Therese says:

    That was meant to read :

    removed “!–” after the opening tag, and changed “$dns = $api—>NewDNS($domain);” to “$dns = $api->NewDNS($domain);”

  3. sam says:

    Thanks for the helpful script! Worked really well. There is still one bug: there are two extra hyphens on line 12.

  4. Adam says:

    Awesome! Thanks for this! NFS just rolled out an initial SSL implementation that allows you to either piggyback on their cert for .nfshost.com or to use your own cert for your own domain. I don’t have my own cert so I used the piggyback option and it caused the script to output localhost (127.0.0.1) instead. I’m not too concerned about security so I won’t bother with SSL but I thought I’d share the info.

    • Adam says:

      Oops, greater than and less than got eaten. Should read “…piggyback on their cert for <mysite>.nfshost.com…”

    • josh says:

      Thanks for the info! I have moved on from NFS to a VPS so I wont be able to test this. 🙁

    • Tim says:

      Adam, I’m also using the piggyback option and I got it working by changing…

      $new = $_SERVER[‘REMOTE_ADDR’];

      … to …

      $new = split(‘,’,$_SERVER[‘HTTP_X_FORWARDED_FOR’])[0];

      Thanks Josh for the jump-start, I thought I was going to have to write this from scratch!

      -Tim

  5. Jason says:

    Thanks for this great how to, it’s great! I have one question however. I’m utilizing AsusWRT which passes the WAN IP from the firmware to the script. Is there an easy modification that I can do that the dynamicdns.php script can use that IP that it passed to it as the IP instead auto-detecting it? I’m not sure how to modify the script and I’m new to this.

    Thanks again for the script and information!

Leave a Reply

Your email address will not be published. Required fields are marked *