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
- Limit of 10,000 files
- There is no storage cost if code and static files are less than 1 GB, else $0.026 per GB per month is charged.
- Each files must be less than 32MB.
- Free quota
- Google Cloud Storage: 5GB
- Code & Static Data Storage: 1GB
- Frontend Instances: 28h per Day
- Outgoing Bandwidth/egress: 1GB per Day
Prerequisite
Create a project on Google Cloud Platform.
- Remember your Project ID
- 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.
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
Location | Response Times |
---|---|
US (W) | 1 ms |
US (E) | 3 ms |
London | 25 ms |
Singapore | 12 ms |
Sao Paulo | 52 ms |
Bangalore | 93 ms |
Sydney | 335 ms |
Japan | 70 ms |
Pagespeed Insights Result
Your server responded quickly.