Cloud · · 4 min read

Hosting a Web App on Google Cloud Using Compute Engine

A hands-on guide to deploying your own Node.js app on Google Cloud Compute Engine using managed instance groups, load balancers, and Cloud CDN.

Google Cloud Compute Engine
Photo by BoliviaInteligente / Unsplash

Introduction

Google Cloud offers several ways to host web applications — from fully managed services like App Engine and Cloud Run to infrastructure-level tools like Compute Engine. In this post, I’ll walk you through deploying a sample Node.js app (from my GitHub repo) on Compute Engine, using Google Cloud Shell, managed instance groups, load balancers, autoscaling, and Cloud CDN.

This guide uses my own minimal app. It’s a hands-on tutorial designed for developers or DevOps engineers looking to learn Google Cloud from the ground up.

If you're interested in a fully managed, container-based approach, check out my previous post: Deploying Your Website on Cloud Run.

What You’ll Learn

By the end of this guide, you’ll know how to:

Prerequisites

Step 1: Activate Cloud Shell

Click the Activate Cloud Shell button in the GCP Console. Cloud Shell gives you a pre-configured virtual machine with the gcloud CLI already installed.

Set your region and zone (you can change them later if needed):

gcloud config set compute/zone us-east4-b
gcloud config set compute/region us-east4

Step 2: Enable Compute Engine API

gcloud services enable compute.googleapis.com

Step 3: Create a Cloud Storage Bucket

This bucket will hold your startup script and application code:

gsutil mb gs://sample-app-$DEVSHELL_PROJECT_ID

Step 4: Clone Your GitHub Repo

Clone your app from GitHub:

git clone https://github.com/niiiixd/sampla-app.git
cd sampla-app

Remove any node_modules to keep the upload lightweight:

rm -rf node_modules

Upload the source code to the bucket:

gsutil -m cp -r . gs://sample-app-$DEVSHELL_PROJECT_ID/

Step 5: Create the Startup Script

Create a file called startup-script.sh:

nano startup-script.sh

Paste the following:

#!/bin/bash

apt-get update
apt-get install -y ca-certificates git build-essential supervisor curl

curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
apt-get install -y nodejs

mkdir -p /opt/app
gsutil -m cp -r gs://sample-app-<YOUR_PROJECT_ID>/* /opt/app/
cd /opt/app
npm install

cat >/etc/supervisor/conf.d/node-app.conf <<EOF
[program:nodeapp]
directory=/opt/app
command=npm start
autostart=true
autorestart=true
stderr_logfile=syslog
stdout_logfile=syslog
user=root
EOF

supervisorctl reread
supervisorctl update

Replace <YOUR_PROJECT_ID> with your actual project ID.

Then upload it:

gsutil cp startup-script.sh gs://sample-app-$DEVSHELL_PROJECT_ID

Step 6: Create Compute Engine VM

Deploy the first VM (this will serve both frontend and backend for simplicity):

gcloud compute instances create sample-instance \
  --zone=$ZONE \
  --machine-type=e2-standard-2 \
  --metadata=startup-script-url=https://storage.googleapis.com/sample-app-$DEVSHELL_PROJECT_ID/startup-script.sh \
  --tags=http-server

Step 7: Create a Firewall Rule

Allow access to port 3000:

gcloud compute firewall-rules create allow-http3000 \
  --allow tcp:3000 \
  --target-tags=http-server

Step 8: Get External IP and Test App

gcloud compute instances list

Open http://[EXTERNAL_IP]:3000 in your browser — you should see:

Hello, world!
This is Sample app version 3🚀

Step 9: Create an Instance Template and Managed Instance Group

Stop the VM:

gcloud compute instances stop sample-instance --zone=$ZONE

Create a template from it:

gcloud compute instance-templates create sample-template \
  --source-instance=sample-instance \
  --source-instance-zone=$ZONE

Create a Managed Instance Group:

gcloud compute instance-groups managed create sample-mig \
  --zone=$ZONE \
  --base-instance-name sample \
  --size 2 \
  --template sample-template

Step 10: Set Up Load Balancer and Health Checks

Create a health check:

gcloud compute http-health-checks create sample-health-check \
  --port 3000 \
  --request-path /

Create a backend service:

gcloud compute backend-services create sample-backend \
  --http-health-checks sample-health-check \
  --port-name http \
  --global

Add your MIG to the backend:

gcloud compute backend-services add-backend sample-backend \
  --instance-group sample-mig \
  --instance-group-zone=$ZONE \
  --global

Create a URL map and target proxy:

gcloud compute url-maps create sample-map --default-service sample-backend
gcloud compute target-http-proxies create sample-proxy --url-map=sample-map

Reserve an IP and set up forwarding:

gcloud compute forwarding-rules create sample-http-rule \
  --global \
  --target-http-proxy=sample-proxy \
  --ports=80

Check the external IP:

gcloud compute forwarding-rules list --global

Step 11: Enable Autoscaling and CDN

Enable autoscaling:

gcloud compute instance-groups managed set-autoscaling sample-mig \
  --zone=$ZONE \
  --max-num-replicas 3 \
  --target-load-balancing-utilization 0.6

Enable CDN:

gcloud compute backend-services update sample-backend --enable-cdn --global

Step 12: Push Code Updates

Make a change in app.js, then repeat the following:

gsutil -m cp -r . gs://sample-app-$DEVSHELL_PROJECT_ID/

Then roll out changes:

gcloud compute instance-groups managed rolling-action replace sample-mig \
  --zone=$ZONE \
  --max-unavailable=100%

Step 13: Simulate Failure (Optional)

SSH into one instance and stop the app:

gcloud compute ssh [INSTANCE_NAME] --zone=$ZONE
sudo supervisorctl stop nodeapp
exit

Then monitor:

watch -n 2 gcloud compute operations list \
--filter='operationType~compute.instances.repair.*'

Your MIG should automatically recreate the unhealthy instance.

Conclusion

Congratulations! 🎉 You just deployed, scaled, load-balanced, autohealed, and updated a Node.js app using Google Compute Engine.

You’ve now touched some of the most important GCP building blocks for production-grade deployments.


Subscribe for More

If you found this tutorial useful, consider subscribing to NotSoStatic for more deep-dive DevOps and cloud engineering guides.

Read next