How to set up a free dynamic hostname with SSL cert using Google Domains

Jeremy Gale
8 min readJun 6, 2018

--

Do you ever access your home computer remotely? For example:

  • SSHing into your home computer
  • Accessing a webserver you run at home
  • Accessing a Jenkins CI server you run at home
  • Accessing the web UI of a BitTorrent client
  • Accessing the web UI of Home Theatre PC media center software

Assuming you have a standard consumer internet plan, your home IP address changes fairly often. This guide will help you set up a free dynamic hostname (e.g. macmini.customdomain.com) that will be kept up-to-date automatically, and can even have an automatically updated SSL certificate so you can access it securely.

Goals

  • Set up a free dynamic hostname (e.g. macmini.customdomain.com) that will be automatically updated.
  • Set up a free SSL certificate from Let’s Encrypt that you can use to access web interfaces running on that computer dynamically.
  • Have that SSL cert be automatically renewed so it never expires.

Prerequisites

  • You have an always-on computer running at home. This guide is going to assume macOS, but you should be able to adapt it easily for Linux. We will use cron jobs to automate Dynamic DNS updates and SSL certificate renewals.
  • You are comfortable updating your router port forwarding settings and using a UNIX terminal.
  • You own a custom domain name (e.g. customdomain.com) that is hosted by Google Domains. See below.

Google Domains

There are many services that offer dynamic DNS hostnames and software to update your dynamic IP address, such as DynDNS or No-IP. I previously used a free No-IP account for this, but got tired of needing to verify my domain every few weeks.

I looked for a better solution, and found Google Domains. It offers free Dynamic DNS hosting, as well as some other highly desirable features like free email forwarding. (I wrote another guide on How to setup a custom domain for your Gmail address.)

If you are registering a new domain, it’s fairly straightforward to do. Transferring your domain to Google Domains is beyond the scope of this article, but here are Google’s instructions for transferring your domain.

Let’s get started.

1. Set up the Dynamic DNS in Google Domains

  1. Log into your Google Domains account
  2. Click the DNS icon for your custom domain
  3. Scroll down to Synthetic Records then Dynamic DNS
  4. Enter the hostname you want to use for your domain, e.g. macmini. Click Save
Enter your Dynamic DNS host name then click Save

5. Obtain your credentials, you’ll need them for the next step. To do this, expand the arrow beside Dynamic DNS and then click View Credentials. Make note of your Username and Password.

2. Set up a script to update the Dynamic DNS hostname

Setting up the dynamic hostname is easy, there isn’t much to it. It’s just an A record that points to your IP address with a short time-to-live so it can be updated frequently. The real magic is in having a script that updates that IP Address automatically.

Google Domains uses the dyndns2 protocol, so you you can use any readily available software that updates it automatically, such as DDclient or INADYN. However, Google Domains has a simple API. We are simply going to use a tiny script to update our Dynamic DNS hostname and run it with cron. See the Using the API to update your Dynamic DNS record documentation for a reference.

  1. Click the Download ZIP link to download this simple script from GitHub. All this script does is obtain your public IP address, then call the Google Domains API to update your dynamic hostname. The whole thing is duplicated here for posterity:
#!/bin/bash

### Google Domains provides an API to update a DNS
### "Synthetic record". This script updates a record with
### the script-runner's public IP address, as resolved using a DNS
### lookup.
###
### Google Dynamic DNS: https://support.google.com/domains/answer/6147083
### Synthetic Records: https://support.google.com/domains/answer/6069273

USERNAME=""
PASSWORD=""
HOSTNAME="macmini.customdomain.com"

# Resolve current public IP
IP=$( dig +short myip.opendns.com @resolver1.opendns.com )
# Update Google DNS Record
URL="https://${USERNAME}:${PASSWORD}@domains.google.com/nic/update?hostname=${HOSTNAME}&myip=${IP}"
curl -s $URL

2. Save it somewhere on your computer and make note of the path, e.g. /Users/<yourusername>/bin/google-domains-dynamic-dns-update.sh

3. Modify the script with the Username and Password that were obtained in the previous step, and substitue your Dynamic DNS hostname.

4. In a Terminal, make the script executable and run it:

$ chmod +x google-domains-dynamic-dns-update.sh$ ./google-domains-dynamic-dns-update.sh
good 1.2.3.4
$ ./google-domains-dynamic-dns-update.sh
nochg 1.2.3.4

Where 1.2.3.4 is your public IP address. If you run it again, you’ll see the “nochg” (no change) indication. Awesome! You can confirm on Google Domains that the API call worked and the proper IP address is shown in the A record.

Now we will set up cron to run that script periodically so your dynamic hostname is always kept up to date. We will use a simple text editor callednano to edit the cron jobs:

$ EDITOR=nano crontab -e

Now enter the following, then press Ctrl+O and Ctrl+X to save and exit.

0 * * * * /Users/<yourusername>/bin/google-domains-dynamic-dns-update.sh

This will run the script every hour. The article Schedule jobs with crontab on Mac OS X also has a good introduction if cron is new to you. Your IP address is unlikely to change every hour, but Google can handle your overwhelming DDoS attack. ;)

Sanity check that your job exists by running:

$ crontab -l

Boom! Now you have a script that will always update your Dynamic DNS hostname every hour. Easy as pie! If you don’t need an SSL certificate, you can stop here.

3. Obtain a free SSL Cert from Let’s Encrypt

Let’s Encrypt is a wonderful project that offers free SSL certs to everyone to make the web a safer place. We want to obtain an SSL certificate for our dynamic DNS hostname, e.g. macmini.customdomain.com

You’ll need to install certbot. Here are the certbot docs for macOS. I found these to be a bit obtuse, so I’ll walk you through it.

This assumes you are not running a web server on standard ports. We will be setting up our router to forward standard HTTP/HTTPS ports through to your always-on computer. This is needed for the Let’s Encrypt challenge to verify that you own the domain.

I prefer not to run as root, since it’s easier to set everything up.

  1. Install Homebrew if you don’t already have it installed:
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

2. Install certbot

$ brew install certbot

3. Set up your router to forward ports 80 and 443 to your always-on computer. These are used when Let’s Encrypt issues a challenge to your Dynamic DNS hostname to verify that you own it. You must use these ports externally. Since I don’t want to run the certbot challenge webserver on ports that require root, I am redirecting them to port 8080 and 8443 internally. This will be different on every router, but here’s what it looks like for me:

Forward port 80 to 8080
Forward port 443 to 8443

4. Create a certbot config file so we don’t need to run as root:

$ mkdir ~/letsencrypt
$ mkdir ~/.config/letsencrypt
$ nano ~/.config/letsencrypt/cli.ini
# Enter the following, substituting <username> with your username
config-dir=/Users/<username>/letsencrypt/config
work-dir=/Users/<username>/letsencrypt/work
logs-dir=/Users/<username>/letsencrypt/logs

Press Ctrl+O and Ctrl+X to save and exit.

4. Run this command to create your cert, substituting macmini.customdomain.com with your Dynamic DNS hostname. This will briefly run a web server. Let’s Encrypt will issue a challenge to your domain name to make sure you own it, then generate your cert if it succeeds.

$ certbot certonly --standalone -d macmini.customdomain.com --http-01-port 8080 --tls-sni-01-port 8443Saving debug log to /Users/<username>/letsencrypt/logs/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for macmini.customdomain.com
Waiting for verification...
Cleaning up challenges
Non-standard path(s), might not work with crontab installed by your operating system package manager
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/Users/<username>/letsencrypt/config/live/macmini.customdomain.com/fullchain.pem
Your key file has been saved at:
/Users/<username>/letsencrypt/config/live/macmini.customdomain.com/privkey.pem
Your cert will expire on 2018-08-28. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

The first time, you will probably need to agree to some terms, enter your email address, etc.

Great, now you have an SSL cert! Google the instructions of your particular webserver/application to find out how to configure it with an SSL cert. You probably want to leave the certs in this folder and symlink them into your server software, so that they can be automatically renewed.

4. Setup a cron job to automatically renew your SSL cert

Let’s Encrypt certs expire after 90 days, so you’ll want to set up a cron job to renew them automatically. If your previous command works, certbot will set up config files so that renewal works the same way. Let’s test it out like so:

  1. Run the cert renewal dry-run command:
$ certbot renew --dry-run
Saving debug log to /Users/<username>/certbot/logs/letsencrypt.log
--------------------------------------------------------------------
Processing /Users/<username>/letsencrypt/config/renewal/macmini.customdomain.com.conf
--------------------------------------------------------------------
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator standalone, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for macmini.customdomain.com
Waiting for verification...
Cleaning up challenges
--------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/Users/<username>/letsencrypt/config/live/macmini.customdomain.com/fullchain.pem
--------------------------------------------------------------------
--------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/Users/<username>/letsencrypt/config/live/macmini.customdomain.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
--------------------------------------------------------------------

Nice, the renewal should work smoothly.

2. Set up a cron job to automatically run the renewal script. According to the docs, they would like you make your renewal requests at most twice per day, at random times. I was having trouble getting their python command for randomization work, so I decided to run it once a day at a random time of the night, say 4:18 am. Pick something else for yours. :) Also note, it’s important to provide the full paths to the commands to run because root may not have the same $PATH as your user does.

$ EDITOR=nano crontab -e# Modify like so: Now you should have two lines:0 * * * * /Users/<yourusername>/bin/google-domains-dynamic-dns-update.sh
18 4 * * * /usr/local/bin/certbot renew

Press Ctrl+O and Ctrl+X to save and exit.

Note: You may want to look into certbot’s --post-hook command-line option if you need to do something like copy/symlink your certs to some other directory, or restart your web server.

You’re all done! Now you have a DNS hostname that will always be pointing to your home computer, and an SSL cert for that hostname that is continually renewed!

--

--

Jeremy Gale

Mobile Dev Lead @ Solium. Foodie. Flames fan. App developer. Human being.