How To Host Static Website On Google App Engine

Why I choose App Engine for Static Web Hosting

I wanted a setup without DevOps, so hosting on EC2 or DigitalOcean is out (not to mentioned the need to integrate CDN after that).

I wanted to try [Google Cloud Storage](null), but SSL support comes with additional service and cost.

S3 + Cloudfare seems popular, but the task of setting up both things seems daunting.

App Engine seems fairly simple and free for low traffic site (static files shouldn't count towards instance cost, only need to pay for bandwidth). Static files seem to be distributed on multiple nodes with good performance (whether they are edge-cache nodes is debatable). If I ever need to write some server-side code, it could be easily done.

App Engine Limitation

Prerequisite

Create a project on Google Cloud Platform.

  • Remember your Project ID

Create an App Engine app

  • Language: Python (pick a language you are familar with, though it doesn't matter for static website)
  • Region: us-central (depending on your audience)
  • Don't have to proceed with the Quickstart Tutorial.

Create App Engine

Install Google Cloud SDK

Download the latest Google Cloud SDK

Extract the package (e.g. tar -zxf google-cloud-sdk*.tar.gz)

Run install script to add SDK rools to your path

./google-cloud-sdk/install.sh# OutputModify profile to update your $PATH and enable shell commandcompletion? [Y]Enter a path to an rc file to update, or leave blank to use[ENTER]

Initialize the SDK (enter your Google credential and select Project ID)

./google-cloud-sdk/bin/gcloud init# You can respond "n" to the followingAPI [compute-component.googleapis.com] not enabled on project[793702336627]. Would you like to enable and retry?  (Y/n)?

Create App Engine project files

Create a directory for your app engine project.

mkdir hello-world-appcd hello-world-app

Create an app.yaml file.

runtime: python27api_version: 1threadsafe: truehandlers:- url: /robots.txt  static_files: www/robots.txt  upload: www/robots.txt  secure: always# file with extensions (longer cache period)- url: /(.*\.(css|js|woff|woff2|ico|png|jpg))  static_files: www/\1  upload: www/(.*)  expiration: "14d"  secure: always# file with extensions- url: /(.*\..*)  static_files: www/\1  upload: www/(.*)  secure: always# assume file without extensions use index.html- url: /(.*)/  static_files: www/\1/index.html  upload: www/(.*)/index.html  secure: always- url: /  static_files: www/index.html  upload: www/index.html  secure: always

NOTE: To use secure: always, remember to enable managed SSL certificates for your website.

Create www directory

mkdir wwwcd www

Create index.html in www

<html>  <head>    <title>Hello World</title>    <link rel="stylesheet" type="text/css" href="/css/style.css">  </head>  <body>    <h1>Hello World</h1>    <p class="red">I am Red</a>    </p>  </body></html>

Create css directory in www

mkdir csscd css

Create style.css in www/css

.red {  color: #FF0000;}

Project files directory structure

hello-world-app
├── app.yaml
└── www
    ├── css
    │   └── style.css
    └── index.html

Deploy the app and make sure the source and Project ID is correct

Deployment

Deploy local files to App Engine server.

gcloud app deploy -v 1# outputServices to deploy:descriptor:      [/hello-world-app/app.yaml]source:          [/hello-world-app]target project:  [hello-world-project-id]target service:  [default]target version:  [1]target url:      [https://hello-world-project-id.appspot.com]Do you want to continue (Y/n)?  Y

Launch brower to preview the website

gcloud app browse -v 1

I prefer to include version (-v 1), else a new version will be created for every upload.

Static cache expiration

When you make changes to the files and refresh the page the second time, you might notice the page still serve the old content. All static contents are cached (default 10-minute expiration time) once downloaded, with no way to clear the cache (clearing browser cache and re-deploying a new version won't clear the cache) until it expires.

You can change cache duration by changing default_expiration or expiration in app.yaml.

For development purpose, you can add a caching busting query string to the end of the url (e.g. https://hello-world-project-id.appspot.com?r=1)

Refer to static cache expiration.

Web Server Performance

Google App Engine server performance is exceptionally good accross multiple countries.

Bitcatcha Result

LocationResponse Times
US (W)1 ms
US (E)3 ms
London25 ms
Singapore12 ms
Sao Paulo52 ms
Bangalore93 ms
Sydney335 ms
Japan70 ms

Bitchacha Result

Pagespeed Insights Result

Your server responded quickly.

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.