This website is statically generated using the Zola static site generator (SSG) which is a fantastic, extremely fast tool written in Rust available on all major OSs. The workflow is:

  1. Write some markdown for a post
  2. Run zola serve to validate that it looks good, locally
  3. Run zola build
  4. Run gsutil -m rsync -r public/ gs://my-website-bucket

Here's a sample of the file listing in the bucket:

$ ls
about             # my 'About' page
even.js           # from my Zola theme
# [...]
minecraft-server  # this is a post that has a gallery in its directory
# [...]
processed_images  # images that are resized during generation by Zola
# [...]

As you can see, that's exactly what we would want in the root of a web server's serving directory for a domain. Google Storage has the ability to do this serving directly from a GS-provided URL. But, we (I) want to serve our site from our own domain. There's instructions on how to do this in Google's Cloud documentation but only for non-HTTPS and there's instructions for setting up an HTTPS Load Balancer. But not a guide on how to combine both, together.

Overview of steps:

  1. Create a storage bucket and upload a site there

  2. Configure the specialty pages

  3. Create a global serving IP address

  4. Create a load balancer for the storage bucket

    1. with your GS bucket as its backend
    2. with HTTPS as its frontend with a Google Managed cert
  5. Create an HTTP load balancer to bounce traffic from HTTP to HTTPS

First, Hosting a static website in the Cloud docs describes the process to get hosting via Cloud Storage via HTTP (not HTTPS). Go to this page and skip the step for CNAME (we're going to use a static IP). Also, obviously, you can't test this site yet, so skip that too. Do everything else on that page. After the steps on this page are done, you'll have a Google Storage bucket that is publicly viewable with the specialty serving pages configured. Note that the specialty serving options will not take effect until the load balancer is configured (you can see why this is in the case in the static web API doc).

Second, create a load balancer specifically for serving over HTTPS. Note that your SSL certificate will be issued to so keep this in mind; don't use the naked domain name in any of the configuration. The simplest Cloud doc for this talks about two GS backends; we only have one. Start with this doc: Setting up a load balancer with backend buckets.

When you create the static IP address, set it to global.

When you get to the step of configuring the load balancer:

  1. Set the backend to your only GS bucket
  2. For the host and path rules, set it to "simple" with no hosts and no paths configured pointing to your GS bucket (a single rule)
  3. For the frontend, attach it to the IP address that you created above in HTTPS mode and create a new Google-managed certificate for .

The certificate created here will take about 60 minutes to provision and is chained-up to Google's own Domain Validation CA. This is very similar to Let's Encrypt in that it is valid for 90 days but the certificate is automatically rotated for you as explained here.

Finish creating this "serving" load balancer.

Edit your DNS records for your domain to set an A record for www to the IP address that you allocated above.

Finally, configure another load balancer also attached to the same IP address for HTTP-to-HTTPS redirection (attached to the HTTP port 80). The documentation for this is inside of this larger article Setting up HTTP-to-HTTPS redirect. Follow the simple steps there.

That is, you'll have two load balancers: one for serving traffic from your GS bucket on HTTPS and one for serving HTTP-to-HTTP redirection.

That's it! After DNS replicates and you wait 60 minutes for the SSL certificate to provision, you should see your website serving off of . If you get 404, try directly accessing your page file name, directly (e.g. ) and check the specialty settings.

As a bonus, it's a good idea to redirect folks from the naked domain . Many DNS hosts provide a "synthetic record" to redirect @ via HTTP 301 to some domain. Set the redirect to .