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

  • 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

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.

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

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.

  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
$ 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
$ EDITOR=nano crontab -e
0 * * * * /Users/<yourusername>/bin/google-domains-dynamic-dns-update.sh
$ crontab -l

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

  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)"
$ brew install certbot
Forward port 80 to 8080
Forward port 443 to 8443
$ 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
$ 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

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.)
--------------------------------------------------------------------
$ 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

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jeremy Gale

Jeremy Gale

95 Followers

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