Wednesday, June 7, 2017

Setting up HTTPS on App Engine With a Custom Domain

The Go programming language provides a great tool, go get, to fetch packages.  A common use case is to get a package that is hosted on Github:


go get -u github.com/abc/xyz
This works okay but requires your local source to also be under src/github.com/abc/xyz to keep the import paths consistent with users that got the package with get.  If GitHub goes away or the code need to move to another location then it could potentially break users.  A solution is to have your own custom domain that you tell get to fetch from but that tells the tool where the actual location is.

go get -u ninja.co/abc/xyz

Supporting this "vanity" import path was introduced in Go 1.4.  I recently decided to do this for my own projects so I set out to find the simplest and cheapest way to do this.  This required a custom domain, a web server for serving static pages and a SSL certificate to allow https.

I initially started with a GitHub page with custom domain, but there were two problems:  1) GitHub pages doesn't support SSL with custom domains so in order to use it with 'go get' requires using the -insecure flag; 2) GitHub will still answer the request at https but with it's own certificate even though it doesn't matches the custom domain and this breaks 'go get'.

My solution is to use Google App Engine Standard (free) for hosting and Let's Encrypt (free) for the SSL/TLS certificate.




Purchase a Domain


Start by purchasing a custom domain to use from a registrar such as Google Domains.

Set Up Google App Engine (GAE) With a Custom Domain


GAE Project


Go to http://appengine.google.com and create a new GAE project.  Normally, the next step is to install one of the supported programming language and download the SDK, but Google's Cloud Shell provides a completely ready environment that already have all the languages, packages and SDKs available.

I decided to use this and so will skip all the install instructions that's needed if you were to develop locally on your own machine.

Code on Cloud Shell


Inside Cloud Shell, create a directory with 2 files and a sub-directory called "letsencrypt" :

abc/app.yaml


abc/server.go

abc/letsencrypt/

app.yaml configures GAE by telling it that this project uses the Go runtime and there is a directory called "letsencrypt" which will hold static files which shouldn't be compiled.

server.go is the code that handles requests and returns the redirection and also serves any static files under letsencrypt.

Deploy to GAE

Once you have the above, deploy it with the gcloud tool that is already available in your Cloud Shell.

gcloud app deploy

Once deployed, test to make sure that it is serving requests correctly.

Enabling Custom Domain for Project


From the App Engine dashboard, go to Settings > Custom Domain and tell GAE to use a custom domain.  You'll need to add the IPs of GAE to your DNS so follow the instructions on the settings page.

Once you've updated the DNS, you should be able to access the project with your domain name.

The final step is to get an SSL/TLS certificate and register it with GAE so it supports https.

Generate a Free SSL Certificate from Let's Encrypt


Let's Encrypt provides free 3 months certificates (so remember to renew) and is completely free (including renewals).

The first step is to get the letsencrypt tool from GitHub:

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
sudo ./letsencrypt-auto -a manual certonly
To verify that you own the domain you're asking to get a certificate for require that a server at your domain respond to a challenge request from the command line tool.  Don't press ENTER yet. The tool will give you the name of the file (e.g. ZYX) and it must contain a specific value string (e.g. ZYX.CBA).

echo ZYX.CBA > letsencrypt/acme-challenge/ZYX
gcloud app deploy
Once deployed and you verified that going to the url serves the file with the right content, you can press ENTER to generate the certifcates and keys in /etc/letsencrypt/live/[domain]/...  You'll need to `sudo su -` to switch to root in order to see the certs and I suggest copying the file to your Cloud Shell home directory so it doesn't get wiped.

Convert the private key (privkey.pem) to RSA so GAE can read it:

openssl rsa -in privkey.pem -out rsa.pem
From the App Engine dashboard, go to Settings > SSL Certificates and copy the text of fullchain.pem into the first box for SSL certificates and copy the content of rsa.pem to the private key section.

You're done!  Now going to your URL with http://ninja.in should auto forward you to a valid https://ninja.in.