ThorneLabs

Use Google App Engine and Python for Inexpensive Domain Redirects

• Updated January 10, 2019


This blog has existed under a few domain names: workingconfig.com, thornelaboratories.net, and, now, thornelabs.net. workingconfig.com didn’t exist for very long, and never had many - if any - backlinks to it; it didn’t make sense to keep those URLs alive. However, thornelaboratories.net did exist for a longer period of time, and it had URLs I wanted to keep alive.

I can easily host thornelaboratories.net and thornelabs.net from the same webserver on a single VM - I never needed more resources to serve static content.

The configuration redirects for thornelaboratories.net lived in its own VirtualHost when I ran Apache, and then its own Server Block when I migrated to nginx. This worked well, but I was managing the nginx configurations for thornelaboratories.net and thornelabs.net in the same git repository, and I wanted to separate the two domains even more; I wanted to host thornelaboratories.net somewhere else and not have to think about it any more, but I didn’t want to create another VM for it because it would be a waste of resources to redirect so little traffic. I wanted to host it somewhere new and different, and spend as little money as possible.

Then I found Max Laumeister’s blog post on how to use Google App Engine as a free redirect server. This was exactly what I was looking for, and, given how little traffic thornelaboratories.net redirects, hosting the redirect service on Google App Engine would easily fit within the limits of App Engine’s free tier.

Prerequisites

This post assumes the following:

  • You are familiar with Google Cloud Platform (GCP) and have already created a GCP Project
  • You have installed the Google Cloud SDK
  • You have authenticated the gcloud command against your Google Account

Create a GCP Project

If you have not yet created a GCP Project, follow these steps:

  1. Open a web browser, and create or log in to a Google Account
  2. Navigate to the GCP Console
  3. If this is your first GCP Project, you will be prompted to create a GCP Project. Each Google Account gets $300 in credit to use within 12 months towards GCP. You are required to enter a credit card to create a GCP Project, but it will not be charged until the $300 credit is consumed or 12 months expire.
  4. If this is a new GCP Project, you will need to enable the Compute Engine API by navigating to the Compute Engine section of the GCP Console and wait for initialization to complete

Install the Google Cloud SDK

If you have not yet installed the Google Cloud SDK, follow the instructions here.

Authenticate gcloud

Once you have created a GCP Project and installed the Google Cloud SDK, the last step is to authenticate the gcloud command to your Google Account. Open your terminal application and run the following command:

gcloud auth login

A web page will open in your web browser. Select your Google Account and give it permission to access GCP. Once completed, you will be authenticated and ready to move forward.

Create a Directory

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

mkdir ~/Development/domain-redirect/app_engine

Change into that directory:

cd ~/Development/domain-redirect/app_engine

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

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 Python.

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, Python will be used, and you can find all the available Python parameters here.

Create file app.yaml with the following contents:

runtime: python27
api_version: 1
threadsafe: yes

handlers:
- url: /.*
  script: main.app

Create main.py

Next, you need the Python application file.

Most of the following code comes from Max’s post, but I have made some modifications. I wanted to be very exact in what URLs I was redirecting; I did not want a catch-all redirect, so I removed the DEFAULT_URL variable and redirection code originally found in the else blocks in method get in the MainPage class. If you prefer to have a catch-all redirect, refer to the aforementioned code block in Max’s post.

For the following code to meet your needs, create file main.py, copy and paste the code below, and make the following modifications:

  • In the domain variable, change the value to match your domain name with the correct HTTP protocol.
  • In the urls dictionary, 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 old URL you want to keep alive. Then replace each value with just the path portion of the new URL you want to redirect to.

All redirects will be 301 redirects. This can be changed to a 302 redirect by changing self.redirect(url, permanent=True) in the code below to self.redirect(url, permanent=False).

import webapp2
import logging
from urlparse import urlparse

def get_redirect_url(url):
    scheme, netloc, path, params, query, fragment = urlparse(url)

    # Fix empty paths to be just '/' for consistency
    if path == '':
        path = '/'

    # Check if we have a mapping for this url
    if path in urls:
        # Return the value of the path key from the urls dictionary
        return urls[path]
    else:
        return False

class MainPage(webapp2.RequestHandler):
    def get(self):
        url = get_redirect_url(self.request.url)

        if url:
            # Concatenate the new domain with the redirect path
            url = domain + url
            # Redirect to the new URL with a 301 redirect
            self.redirect(url, permanent=True)
        else:
            self.error(404)
            self.response.write('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
            self.response.write('<title>404 Not Found</title>')
            self.response.write('<h1>Not Found</h1>')
            self.response.write('<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>')

app = webapp2.WSGIApplication([
    ('/.*', MainPage),
])

# The domain with protocol to redirect to
domain = "https://thornelabs.net"

# Path => URL to redirect to
urls = {
    '/': ('/'),
    '/index.html': ('/index.html'),
    '/post/example-post-1.html': ('/post/example-post-1.html'),
    '/post/example-post-2.html': ('/post/example-post-2.html'),
}

Deploy to App Engine

With app.yaml and main.py saved, 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 https://your-project-id.appspot.com. 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. After a few seconds, the application should be deployed.

Setup DNS

At this point, your application is deployed under URL https://your-project-id.appspot.com. Unless your website used that as its old domain name, you probably want to setup a custom domain that uses your actual old 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 to http://old-domain-example.com/post/example-post-1.html in your web browser and have it redirect to http://new-domain-example.com/post/example-post-1.html.

References

If you found this post useful and would like to help support this site - and get something for yourself - sign up for any of the services listed below through the provided affiliate links. I will receive a referral payment from any of the services you sign-up for.

Get faster shipping and more with Amazon Prime: About to order something from Amazon but want to get more value out of the money you would normally pay for shipping? Sign-up for a free 30-day trial of Amazon Prime to get free two-day shipping, access to thousands of movies and TV shows, and more.

Thanks for reading and take care.