Using Google Cloud Run to host static website on Google Cloud Storage (for free)

When you’re getting older and older you don’t want to maintain one server more to host few sites and blogs like this one, monitor if lets encrypt certificate renewed even on old outdated sites and so on… at least this is true for me :) And I decided to move it to some full-managed platform. For the first look Google Cloud storage was good enough solution, but after creating bucket, and going throw complete tutorial I understand that enabling https will be nor easy (using load balancer and so on) neither cheap (it’s $0.025 per first 5 rules per hour => $18 per month).

Just used Google Cloud Run for few APIs and it’s payed just for used time/CPU/RAM, but in case of not very active website even Free Tier is enough to host some websites absolutely for free.

After reading of documentation it looks just very simple, you even do not need to provide credentials manually inside Cloud Run (fully managed) container instances when using the GCP client libraries!

P.S.: if you just want to you final code to deploy you own container please visit github.com/kanocz/gclwebgcs.

First we need to listen on port provided by PORT env variable:


http.ListenAndServe(”:” + os.Getenv(“PORT”), nil)

Via GCS env we’ll specify Google Cloud Storage bucket name (need to be in the same project!):


ctx : = context.Background()
client, err := storage.NewClient(ctx)
bucket = client.Bucket(os.Getenv(“GCS”))

And reading object to send:


obj := bucket.Object(r.URL.Path[1:]) // strip first “/”
objAttrs, err := obj.Attrs(ctx)
obj = obj.ReadCompressed(true) // we don’t want to decompress and compress it again for transfer
// copy headers
w.Header().Set(“Content-Type”, objAttrs.ContentType)
w.Header().Set(“Content-Encoding”, objAttrs.ContentEncoding)
w.Header().Set(“Content-Length”, strconv.Itoa(int(objAttrs.Size)))
w.Header().Set(“Content-Disposition”, objAttrs.ContentDisposition)
w.Header().Set(“Cache-Control”, objAttrs.CacheControl)
w.Header().Set(“ETag”, objAttrs.Etag)
// and send data
reader, err := obj.NewReader(ctx)
io.Copy(w, reader)

Really for serving website we also require server index, handle not found errors and so on, but it’s also not so complicated.

Don’t forget to create go.mod to help Google Cloud Build :)

Than deployment to container registry it just

gcloud builds submit --tag gcr.io/project1/gclwebgcs

(please replace project1 with your project name) and create/update service using

gcloud beta run deploy --image gcr.io/project1/gclwebgcs \
  --platform managed --set-env-vars=GCS=GCSbucketName serviceName

Don’t forget upload files to GCSbucketName in the same project and assign domain name to new service, ssl certificate will be provided and managed automatically!

That’s all :)