Creating Your First Google Cloud VM: Compute Engine Step by Step
This guide walks you through creating a Compute Engine VM in Google Cloud from scratch. You will enable the API, create a VM with gcloud, SSH in, install nginx, open firewall rules, test from a browser, and clean up safely when you are done. Both the gcloud CLI path and the Cloud Console path are covered.
Compute Engine VM in simple terms
A virtual machine is a rented computer running in one of Google’s data centres. You choose the number of CPUs, the amount of memory, the disk size, the operating system, and the network settings. Google manages the physical host. You manage everything inside the machine.
Think of Compute Engine like renting a dedicated office room. You get four walls, a power outlet, and a key. What furniture you put in, how you organise it, and whether you leave the lights on overnight is entirely up to you. Cloud Run, by contrast, is more like renting a desk in a coworking space — everything is already set up, someone else handles the building, and you just show up and work.
Unlike Cloud Run, where Google handles the server entirely and you just deploy code, Compute Engine gives you a full Linux or Windows machine you can SSH into and configure however you need. That flexibility comes with more responsibility: you are accountable for OS updates, security hardening, and making sure the VM is stopped or deleted when you are not using it.
Billing runs per second with a one-minute minimum. A stopped VM ends compute charges, but its attached disk continues to bill until you delete it. See Compute Engine Overview for the full billing breakdown including sustained use discounts and committed use discounts.
When to use Compute Engine
Compute Engine is the right choice when:
- You need full OS-level access and the ability to SSH directly into the machine
- Your software has specific kernel requirements or system dependencies that cannot be containerised
- You are running a database, a background daemon, or another stateful service that manages its own storage
- You are migrating an on-premises workload to GCP without rewriting it
- You need to install custom system packages or configure kernel parameters
- You need Windows Server or a licensed OS that serverless platforms do not provide
If your workload is a stateless web app or API that runs in a container, Cloud Run is simpler and often cheaper. It scales to zero, includes HTTPS automatically, and requires no OS management. Read Cloud Run vs Compute Engine before committing to a VM.
What you need before you start
A GCP project. If you do not have one, create one in the Cloud Console. See GCP Projects for how projects work and why every resource lives inside one.
Billing enabled. Compute Engine requires a linked billing account. Even if you are on the free tier, billing must be configured before you can run a VM. See Billing.
The Compute Engine API enabled. Disabled by default in new projects. Covered in Step 1 below.
gcloud CLI installed and authenticated. See gcloud CLI for setup instructions if you have not done this yet.
How creating a VM works in GCP
Before running any commands, it helps to understand what you are actually configuring. Every Compute Engine VM is defined by six decisions:
Region and zone: the physical location where the VM runs. Once created, a VM cannot move zones. Pick a region and zone close to your users to minimise latency.
Machine type: the vCPU and memory allocation.
e2-medium(2 vCPUs, 4 GB RAM) is a sensible starting point for development. Read Machine Types Explained before committing to a shape for production.Boot disk and OS image: the operating system and disk the VM boots from. Debian 12 and Ubuntu LTS are the most common choices for Linux VMs. See VM Images for a breakdown of available images and how image families keep your OS automatically patched.
Network and VPC: the VPC network the VM connects to. New projects get a default VPC automatically.
External IP: whether the VM gets a public IP address. Without one, the VM is reachable only from within your VPC or via IAP tunnelling. Read Private vs Public IP Addresses to understand the tradeoffs.
Service account: the identity the VM uses to call GCP APIs. For development, the default service account with
—scopes=cloud-platformis convenient but overly broad. Production VMs should use a dedicated service account with least-privilege roles.
When you create the VM, GCP provisions the machine, attaches the boot disk, assigns an IP address, and applies firewall rules. The VM becomes reachable via SSH within about 30 seconds. Firewall rules are separate from the VM itself. SSH access and web traffic require different rules and neither is automatically open.
Option 1: Create a VM with gcloud
Step 1: Confirm your project and enable the API
# Confirm you are working in the correct project
gcloud config get-value project
# Enable the Compute Engine API (only needed once per project)
gcloud services enable compute.googleapis.comIf the API is already enabled, the enable command is harmless. If you are unsure how API enablement works in GCP, see Enabling APIs in GCP.
Step 2: Create the VM
gcloud compute instances create my-app-server \
--project=YOUR_PROJECT_ID \
--zone=europe-west2-a \
--machine-type=e2-medium \
--image-family=debian-12 \
--image-project=debian-cloud \
--boot-disk-size=20GB \
--boot-disk-type=pd-balanced \
--tags=http-server \
--scopes=cloud-platformWhat each flag does:
—zone: the zone where the VM runs. Pick one close to your users. See Regions and Zones.—machine-type: vCPU and memory.e2-mediumgives 2 vCPUs and 4 GB RAM for around $25/month. Read Machine Types Explained before choosing a type for production.—image-family=debian-12: the OS image family. Using a family name rather than a pinned version means you always get the latest patched build. See VM Images.—boot-disk-size=20GB: 20 GB is a practical minimum for a Linux VM. The disk persists after the VM stops and continues billing. See Persistent Disks.—tags=http-server: a network tag used to target firewall rules. You will reference this tag in Step 6.—scopes=cloud-platform: grants the VM access to GCP APIs within the permissions of the attached service account. Convenient for development; use a dedicated least-privilege service account in production.
Step 3: Verify the VM started
# List all VMs in the project
gcloud compute instances list
# Get the external IP address
gcloud compute instances describe my-app-server \
--zone=europe-west2-a \
--format="get(networkInterfaces[0].accessConfigs[0].natIP)"The status column should show RUNNING. Note the external IP. You
will use it in Step 7 to test the web server from a browser. If no IP appears,
the VM was created without one. See
Private vs Public IP Addresses.
Step 4: SSH into the VM
# SSH using gcloud — handles key management automatically
gcloud compute ssh my-app-server --zone=europe-west2-a
# Run a single command without opening an interactive session
gcloud compute ssh my-app-server \
--zone=europe-west2-a \
--command="uname -a"On first use, gcloud generates an SSH key pair and uploads the public key to the VM’s metadata. Subsequent connections reuse the same key. You do not need to manage SSH keys manually for development use.
For production VMs, use OS Login to tie SSH access to Google Cloud IAM. Revoking access becomes removing an IAM role rather than tracking down key files. See OS Login Explained and SSH Access in Compute Engine for the full picture.
Step 5: Install a web server
Once you are inside the VM via SSH, install nginx and confirm it is running:
# Update package lists and install nginx
sudo apt-get update && sudo apt-get install -y nginx
# Start nginx and enable it to start automatically on reboot
sudo systemctl start nginx
sudo systemctl enable nginx
# Confirm nginx is active
sudo systemctl status nginxThe status output should show active (running). nginx is now
serving on port 80 inside the VM, but you cannot reach it from the internet
yet. The GCP firewall blocks all inbound web traffic by default. That is what
Step 6 fixes.
Type exit to leave the SSH session and return to your local
terminal before continuing.
Step 6: Open firewall rules for web traffic
GCP blocks all inbound traffic by default except SSH. You must create an explicit firewall rule to allow web traffic. Rules target VMs using network tags. See Firewall Rules Explained for how tags and rules work together.
Think of a network tag like a wristband at an event. The firewall rule is
the door policy: “anyone wearing the http-server wristband can
enter on port 80.” Adding the tag to a VM puts the wristband on it.
Removing the tag takes it off. The door policy itself never changes. This
is why two VMs in the same project can have completely different firewall
behaviour even though they share the same rules.
# Allow HTTP traffic (port 80) for VMs tagged with http-server
gcloud compute firewall-rules create allow-http \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:80 \
--target-tags=http-server \
--source-ranges=0.0.0.0/0
# Confirm the VM has the correct tag
gcloud compute instances describe my-app-server \
--zone=europe-west2-a \
--format="value(tags.items)"The tag on the VM (http-server) and the tag in the firewall rule
(—target-tags=http-server) must match exactly. A mismatch means
traffic is blocked silently with no error message.
To revoke web access without deleting the rule, remove the tag from the VM. The rule stays in place but only applies to VMs that carry the matching tag.
Step 7: Test the VM from your browser
# Retrieve the external IP if you have not already
gcloud compute instances describe my-app-server \
--zone=europe-west2-a \
--format="get(networkInterfaces[0].accessConfigs[0].natIP)"Open http://YOUR_EXTERNAL_IP in a browser. You should see the
default nginx welcome page: “Welcome to nginx!”
If the page does not load, check the following in order:
- Confirm the VM is running:
gcloud compute instances list - Confirm nginx is active: SSH in and run
sudo systemctl status nginx - Confirm the firewall rule exists:
gcloud compute firewall-rules list - Confirm the VM has the
http-servertag: check the describe output above - Confirm you are using
http://nothttps://. TLS is not configured yet
Step 8: Stop or delete the VM when you are done
# Stop the VM — compute billing stops; disk billing continues
gcloud compute instances stop my-app-server --zone=europe-west2-a
# Restart a stopped VM
gcloud compute instances start my-app-server --zone=europe-west2-a
# Delete the VM and permanently destroy the boot disk
gcloud compute instances delete my-app-server \
--zone=europe-west2-a \
--delete-disks=boot—delete-disks=boot permanently deletes the boot disk and all
data on it. There is no undo. Take a
snapshot before deleting
if you might need the disk contents later. See also
Cleaning Up Unused Resources
to avoid ongoing charges from forgotten VMs and disks.
Option 2: Create a VM in the Google Cloud Console
If you prefer a graphical interface, you can create a VM entirely in the Cloud Console without installing gcloud.
Open the Cloud Console and navigate to Compute Engine > VM instances.
Click Create instance.
Set a name for the VM. Names must be lowercase and may use hyphens but not underscores.
Choose a Region and Zone. See Regions and Zones if you are unsure which to pick.
Under Machine configuration, select a machine type.
e2-mediumis a reasonable default for learning. See Machine Types Explained to understand the families and tradeoffs.Under Boot disk, click Change to choose an OS image. Debian 12 or Ubuntu 24.04 LTS are reliable starting points. See VM Images.
Under Firewall, tick Allow HTTP traffic if you want to serve web content. This adds the
http-servernetwork tag and creates a matching firewall rule automatically.Click Create. The VM appears in the instances list within about 30 seconds.
Click SSH in the instances list to open an in-browser terminal connected to your VM. No local SSH client or key management required.
The Console is useful for exploration and one-off VMs. For repeatable or automated VM creation, gcloud or Terraform is more reliable and reviewable.
Common beginner mistakes
Not enabling the Compute Engine API first. Attempting to create a VM without enabling the API returns a confusing permission error. Run
gcloud services enable compute.googleapis.combefore any other compute command.No billing account linked to the project. Compute Engine refuses to provision VMs in a project without billing enabled, even during a free trial. Confirm your billing setup at Billing before starting.
Picking a zone far from your users. Zones in distant regions add noticeable latency. Choose a region close to where most traffic will originate, and remember you cannot move a VM between zones after creation.
Confusing SSH access with web traffic. SSH on port 22 is allowed by default on the default VPC. Web traffic on ports 80 and 443 is blocked until you create an explicit firewall rule. Being able to SSH does not mean your web server is reachable from the internet.
Missing or mismatched firewall tag. The tag on the VM and the
—target-tagsin the firewall rule must match exactly.http-serverandhttpserverare treated as different tags. Confirm the tag withgcloud compute instances describeif traffic is not flowing.Forgetting the VM needs an external IP to serve internet traffic. If the VM has no external IP, it cannot receive traffic from the internet regardless of firewall rules. See Private vs Public IP Addresses.
Assuming stopped and deleted mean the same thing. A stopped VM ends compute billing but the boot disk continues to accrue storage charges. Delete the disk explicitly if you want to stop paying for storage entirely.
Leaving test VMs running and forgetting them. A forgotten
e2-mediumVM costs roughly $25/month. Set a billing alert or schedule automatic shutdowns. See Compute Engine Cost Optimisation.
Compute Engine vs Cloud Run
Beginners often wonder whether to start with a VM or Cloud Run. The table below covers the key practical differences.
| Factor | Compute Engine | Cloud Run |
|---|---|---|
| Infrastructure management | You manage the OS, patches, and software | Google manages the runtime entirely |
| SSH access | Yes, with full terminal access to the machine | No. You deploy a container image, not a server |
| Deployment model | Install software directly on the VM | Build a container image and deploy it |
| Scaling | Manual or via Managed Instance Groups | Automatic, including scale to zero |
| Idle cost | Bills while running, even with no traffic | No cost when idle. Scales to zero automatically |
| Best fit | OS-level control, stateful apps, legacy software | Stateless web apps, APIs, event-driven workloads |
For a first stateless web app or API, Cloud Run is usually the better default. Use Compute Engine when you genuinely need VM-level control that Cloud Run cannot provide. For a thorough side-by-side breakdown, read Cloud Run vs Compute Engine and Serverless vs Virtual Machines.
Summary
- Enable the Compute Engine API and confirm your project before creating any resources
- Key creation flags:
—zone,—machine-type,—image-family,—tags,—boot-disk-size gcloud compute sshmanages SSH key generation and upload automatically- Firewall rules target VMs by network tag. The tag on the VM must match the tag in the rule exactly
- Stopping a VM halts compute billing. Deleting the boot disk removes storage billing
- For stateless web apps, Cloud Run is simpler. Use Compute Engine when you need OS-level control
Frequently asked questions
What do I need before creating a Compute Engine VM?
A GCP project with billing enabled and the Compute Engine API enabled. The API is off by default in new projects — run gcloud services enable compute.googleapis.com before creating your first VM. You also need the gcloud CLI installed and authenticated. Even during a free trial, running VMs consume credits, so confirm your billing setup before starting.
Do I need a public IP address to access my VM?
Not always. You can SSH into a VM without a public IP using Identity-Aware Proxy tunnelling, which routes traffic through Google infrastructure without exposing the VM to the internet. However, if the VM needs to serve web traffic from the internet, it requires an external IP address. By default, a new VM gets an ephemeral external IP unless you explicitly disable it at creation time.
Why can I SSH into the VM but not open my website in a browser?
SSH uses port 22, which GCP allows by default on the default VPC network. Web traffic on port 80 is blocked until you create an explicit firewall rule permitting it. Add --tags=http-server when creating the VM, then create a firewall rule with --target-tags=http-server and --rules=tcp:80. The tag on the VM and the tag in the firewall rule must match exactly — a mismatch means traffic continues to be blocked with no error message.
What is the difference between stopping and deleting a VM?
Stopping a VM halts the instance and ends compute billing, but the boot disk and any attached data disks remain and continue to incur storage charges. Deleting a VM removes the instance permanently. If you pass --delete-disks=boot, the boot disk is also destroyed. For a temporary pause, stop the VM. For full cleanup after an experiment, delete the VM and its disks.
Should beginners use Compute Engine or Cloud Run first?
For most beginners building a web app or API, Cloud Run is the better starting point. It handles scaling, HTTPS, and infrastructure automatically. Use Compute Engine when you genuinely need OS-level control, direct SSH access, custom system packages, or a workload that cannot run in a container.