DIY secure pseudo-DDNS setup using ssh

Here's a quick HOWTO for setting up your own secure pseudo-dynamic DNS (DDNS) server.

It's not a "real" DDNS service, i.e. you won't be able to use standard DNS tools or protocols to talk to the server, but it covers 98% of all functionality I expect from a service such as DynDNS or similar ones: It tells me the IP address of a certain box which doesn't have a static IP address (e.g. my home-server).

Requirements

You'll need:

  • A Linux box with dynamic IP address (dial-up modem/DSL), I'll call it homeserver from now on. This is the box whose public IP address I want to be able to find out.
  • A public Linux box with static IP address (or known DNS name) where you have a user account and ssh access. I'll call this box publicserver.

Setup

On the homeserver:

  • Add a non-root user account (e.g. user) just for the purpose of this mechanism: adduser user. The user doesn't need any special permissions.
  • Create an ssh key with an empty passphrase for the user: ssh-keygen -t rsa -b 4096. This is required as you'll want to run ssh commands via cronjob later.
  • Add a cronjob which runs a random command such as ls regularly (as user), e.g. once per 10 minutes:

    5,15,25,35,45,55 * * * * user ssh -x user@publicserver ls

    The command to run (e.g. ls) doesn't really matter at all, more on that later.

On the publicserver:

  • Add a non-root user account (e.g. also named user) just for the purpose of this mechanism: adduser user. The user doesn't need any special permissions.
  • Add the public ssh key (/home/user/.ssh/id_rsa.pub) of user@homeserver to the publicserver's /home/user/.ssh/authorized_keys, so that the homeserver user can login on the remote publicserver without password (i.e. non-interactively). We'll also limit which ssh commands this user can run using the command keyword in /home/user/.ssh/authorized_keys file:

    command="echo $SSH_CLIENT | cut -d \" \" -f 1 > /home/user/homeserverip.txt && chmod 644 /home/user/homeserverip.txt",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-rsa AAAAAAAAAA...AAAAAAA user@homeserver

    In the above example AAA...AAA is the public key, command specifies which command should be run if this user "logs in" via ssh, and we use some other options such as no-port-forwarding,no-X11-forwarding,no-agent-forwarding to minimize what this user can do via ssh.

So to summarize: the homeserver's user simply executes the above commands on the remote publicserver, which in turn abuses the $SSH_CLIENT environment variable which contains the public IP the ssh connection was coming from (which is exactly what we're looking for). We store that IP in the homeserverip.txt file, which will always contain the latest-known IP address of the homeserver (because of the cronjob).

Getting the current homeserver IP address

You can now retrieve the current IP address of your homeserver easily from anywhere (e.g. from your laptop when you're in another, possibly hostile network) in order to connect to your homeserver:

  $ ssh -x otheruser@publicserver cat /home/user/homeserverip.txt

To make this a bit more convenient you can add a shell alias (e.g. into ~/.bashrc):

  alias homeserverip='ssh -x otheruser@publicserver cat /home/user/homeserverip.txt'

Or, to conveniently login to your homeserver as johndoe:

  alias homeserverlogin='ssh -x johndoe@`ssh -x otheruser@publicserver cat /home/user/homeserverip.txt`'

Conclusion, advantages

This may not be the most elegant solution, and it has a number of drawbacks when compared to services such as DynDNS, but it's sufficient for me and it also has some advantages:

  • You're not dependent on the DDNS service provider. For instance DynDNS recently changed their policy to only allow one update per 28 days, which totally sucks. They then disabled the service completely until I updated my ddclient config and contacted them, i.e. I wasn't able to connect to my homeserver for quite a while, which also sucks.
  • The ssh-based solution is secure and encrypted, in contrast to some other DDNS services, which only allow unencrypted HTTP-based connections (yes, some do allow https/SSL connections).
  • This solution doesn't require in-depth DNS server config knowledge, neither does it require a DNS server you control. You only need a (non-root) ssh account on a public server (or virtual server).

Personally I'm currently using this mechanism for two things, more might follow:

  • Connect to my homeserver via ssh.
  • Get the homeserver's IP address so I can update my OpenVPN client config file on my laptop (I use my homeserver as OpenVPN server).

So far it works pretty nicely.

Update 2008-06-24: Various fixes and simplifications. SSH key must be password-less. Don't run cronjob once per minute, that's overkill.
Update 2008-07-02: Simplify setup by removing the need for extra scripts. Limit the commands the user can perform via ssh in the authorized_keys file. Make the RSA keys 4096 bits strong.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Hi You could also retrieve

Hi

You could also retrieve your IP address directly via:

ssh my.server.net 'echo $SSH_CLIENT' > myip.txt

The magic is done by the quotation marks :-)

cu

Not sure about this one

This misses the point. If my.server.net has a fixed IP, you don't need to do that. If it has a dynamic IP, it won't help.
-alex

Easier fix: IPv6

Faced that same problem for years. One other trick I used was to set up an ssh port forwarding, so I could get to my home machine by SSHing to the public machine on some other port.

But more recently I just put the home machine on IPv6, using:

apt-get install aiccu

and voila, it now has a stable IPv6 address, I can get to it from any other IPv6-enabled host, etc. Much easier and less painful.

ssh port forwarding

Nice, but how does the ssh port forwarding work? You still need to handle the case where your homeserver IP changes, no?

The IPv6 solution sounds interesting, though (currently) less flexible, as it requires IPv6 setups/hosts which are not widely used yet.

Uwe.

authorized_keys

You might also want to look into using command="/home/user/updateip",no-port-forwarding,no-X11-forwarding,no-agent-forwarding in your authorized_keys file to limit that passphrase-free key to running this script. The sshd man page describes the available options.

restricted ssh

Yep, thanks, that's probably a very good idea.

Another approach ...

To achieve this aim -- and get a whole lot more, try out the open source home server from www.Amahi.org. All the hard work has been done for you (for starters it provides DDNS and sets up OpenConnect) ... and there's a whole -- take a look!

Typo above ...

Meant to say OpenVPN, not OpenConnect :-)

DDNS

How does the DDNS solution work btw? Does it rely on DynDNS or a similar service or does it require access to an actual DNS server (on the "publicserver") which you control?

Ewww. Don't run the script

Ewww. Don't run the script every minute. Run it when the network interface comes up.

cronjob

Yeah, once per minute is a bit of an overkill, but running it when the interface comes up won't work in my case. The homeserver is not the one dialing out (PPPOE, DSL), instead it has a static 192.168.x.y IP (no DHCP) and its interface never goes down. There's an extra DSL router that does the dialing and renewing IP addresses and port-forwarding to the homeserver and all that stuff...

Uwe.