Use Google App Engine and Golang to Host a Static Website with Same Domain Redirects

Wednesday, March 8, 2017

There are several inexpensive ways to host a static website generated with a static site generator like Jekyll, Hugo, or Pelican:

This entire blog is statically generated using Jekyll. However, I am unable to use any of the options above, because, over the blog’s lifetime, I have changed domain names, changed URL schemes, and renamed posts, and I wanted to keep alive all of the old URLs.

I have been hosting this blog using Apache and, more recently, nginx on a single virtual machine, and the redirection features of either piece of software work just fine, but I was ready to host it somewhere new and different.

A previous post details how I redirect URLs from an old domain to a new domain using Google App Engine and Python, but now I needed a way to serve static content and redirect URLs from the same domain. That same domain redirection requirement is why I cannot simply use Google App Engine’s static content only feature (linked in the list above). However, I can use Google App Engine in combination with a simple Golang application to serve both static content and same domain redirects.

Why Google App Engine?

Before you dive into the rest of the post, perhaps you are wondering, why host a blog on Google App Engine? Here are my reasons why:

  • If your traffic fits within App Engine’s free tier of 28 instance hours and 1 GB of egress traffic per day, hosting the blog is practically free
  • Pushing updates is done with one command
  • Logging and monitoring are integrated using Stackdriver
  • Automatic up and down scaling based on traffic patterns
  • With a few clicks, web logs can easily be pushed to something like BigQuery for long term storage and adhoc analysis

Prerequisites and Authentication

This post assumes the following:

  • You are familiar with Google Cloud Platform and have already created a Google Cloud Project
  • You have installed the Google Cloud SDK. If you haven’t already installed it, follow the instructions here.

Finally, make sure gcloud is authenticated against Google Cloud Platform:

gcloud auth login

A web page will open in your web browser. Select and give permission to your Google account to access Google Cloud Platform, and you should be authenticated.

Create a Directory

Next, create a directory somewhere on your workstation to store your Google App Engine application:

mkdir ~/Sites/

Change into that directory:

cd ~/Sites/

The remainder of this post will assume you are working inside of this directory.

Additionally, create a directory inside of the app-engine directory called static:

mkdir ~/Sites/

You will revisit this directory later.

Create app.yaml

Google App Engine typically requires two files: app.yaml and an application file written in Python, Golang, Java, or PHP - in this case it’s going to be Golang.

app.yaml provides the necessary configuration to run your application. There are a lot of different parameters that can exist in app.yaml. Those parameters might differ based on the programming language used. For this post, Golang will be used, and you can find all the available Golang parameters here.

Create file app.yaml with the following contents:

runtime: go
api_version: go1

- url: /.*
  script: _go_app
  secure: always
  redirect_http_response_code: 301

Notice that secure: always has been set. This means the Golang application will always be served over HTTPS. If an end user navigates to the web application over HTTP, they will by default be 302 redirected to the HTTPS version. This is why redirect_http_response_code: 301 has also been set. I always want the web application to be served over HTTPS, and I do not want search engines interpreting the redirection from HTTP to HTTPS as a temporary redirect; it is a permanent redirect.

Create main.go

Next, you need the Golang application file.

For the following code to meet your needs, create file main.go, and, in the urls map, replace all of the key value pairs to match the redirects you need in place. Replace each key with just the path portion of the current domain’s old URL you want to keep alive. Then replace each value with the current domain’s exact new URL - domain and path - you want to redirect to. The if code block within the handler function has every redirect set to be a 301 permanent redirect; You more than likely want to keep it this way, but it can be changed if needed.

package main

import (

func init() {
    http.HandleFunc("/", handler)

func handler(w http.ResponseWriter, r *http.Request) {
    urls := map[string]string {
            "/example-post-1.html": "",
            "/example-post-2.html": "",
            "/example-post-3.html": "",

    if value, ok := urls[r.URL.Path]; ok {
        http.Redirect(w, r, value, 301)
    } else {
        http.ServeFile(w, r, "static/"+r.URL.Path)

Generate the Static Content

With app.yaml and main.go saved, the last piece is to generate your static content and store it in the static directory you created earlier.

How you do this entirely depends on what static site generator you are using.

If you are using Jekyll, you can configure the destination parameter in Jekyll’s _config.yml file to save your static content in any directory on your workstation. So, you could set the destionation parameter to ~/Sites/, and, everytime you run jekyll build, the static content will be saved in that directory.

Deploy to App Engine

With app.yaml, main.go, and your static content generated, you are ready to deploy your Google App Engine application.

Assuming gcloud is already pointed at the Google Cloud Project you want to deploy to, verify with gcloud config list project, run the following command:

gcloud app deploy

The command will output the appspot URL your application will be deployed to and ask if you want to continue. Typically, the appspot URL is This is also a useful self-check to make sure you are not deploying your application to the wrong Google Cloud Project. If everything looks okay, type Y and Enter to deploy your application. Depending on how large your static content is, your application should be deployed within about one minute.

Setup DNS

At this point, your application is deployed under URL Unless your website uses that as its domain name, you will probably want to setup a custom domain that uses your actual current domain name.

The App Engine section of the Google Cloud Console can be used to do this. Go here and follow the instructions to configure your custom domain.

Once that is complete and DNS has had time to propagate, you should be able to navigate in your web browser to one of your current domain’s old URLs, for example, and have it redirect to your current domain’s latest URL, for example

Pushing Updates

To push updates, make the necessary changes in your static site’s source directory, regenerate the static content, and redeploy to Google App Engine by changing into the ~/Sites/ directory and running gcloud app deploy.


A Surprising Feature of Golang that Colored Me Impressed

How to check if a map contains a key in go?

comments powered by Disqus