---
title: "Pull request previews on Google Cloud"
description: "Run each pull request's stagelet on its own Compute Engine instance in your Google Cloud project. See what stagely setup creates and the roles it needs."
url: https://stagely.dev/docs/setup/cloud/google-cloud
---

Stagely gives each GitHub pull request a stagelet: a private, running copy of your app. On Google Cloud, each stagelet runs on its own Compute Engine instance in your project. You run `stagely setup gcp` once. After that, the customer agent creates an instance when a pull request deploys, and deletes it when the stagelet ends.

## What setup creates

Setup applies a Terraform module with OpenTofu or Terraform. It creates these resources in the region and zone that you choose:

| Resource                     | Details                                                                                                                                                  |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Network                      | `<environment>-stagely`, in custom mode, with one subnetwork, `10.42.0.0/20`                                                                             |
| Agent host                   | Instance of type `e2-small`, Ubuntu 24.04                                                                                                                |
| Gateway host                 | Instance of type `e2-small`, Ubuntu 24.04, with a static external address                                                                                |
| Firewall rules               | Rules on network tags: one set for the agent host, one for the gateway host, and one for stagelet machines and build workers                             |
| Artifact Registry repository | A Docker repository in the region, with the ID in `-registry`                                                                                            |
| Service accounts             | `<environment>-push` can push to the repository and pull from it. `<environment>-pull` can only pull from it. Your service account can impersonate both. |

The hosts get setup's SSH key for root, and they block the project-wide SSH keys.

## Credentials

Setup needs a service account key in `GOOGLE_APPLICATION_CREDENTIALS`, or in the file that `-credentials` names. The service account needs these roles in the project:

- Compute Admin (`roles/compute.admin`)
- Artifact Registry Administrator (`roles/artifactregistry.admin`)
- Service Account Admin (`roles/iam.serviceAccountAdmin`)

The project needs these APIs turned on: Compute Engine, Artifact Registry, IAM, and IAM Service Account Credentials.

The key stays on your computer and on the agent host. On the agent host, it is in `/etc/stagely/stagely-agent.env`, which only root can read. Machines never get the key.

## Stagelet machines and build workers

- The agent creates one instance for each stagelet, in the zone in `-zone`. Its type is `e2-medium`. Setup has no flag to change this type.
- The agent keeps two build workers, also of type `e2-medium`. They stay when stagelets come and go.
- Each instance starts from Ubuntu 24.04, and cloud-init installs Docker at the first boot. With `-golden-image`, instances start from an image that already has Docker. The `stagely` repository has the Packer template for this image.
- Each instance joins the environment's subnetwork. The agent connects to it over SSH, and accepts only the host key that it gave the instance.
- The agent names its machines `stagely-<environment>-...`, so several environments can share one project and zone.

## Registry

Build workers push images to the Artifact Registry repository. Before each build and each start, the agent impersonates one of the two service accounts and gets a token that lasts one hour:

- A build worker gets a token of the push account.
- A stagelet machine gets a token of the pull account.

A token works only with the repository. Your service account key never goes to a machine.

## Isolation

- Stagelet machines and build workers accept connections only from instances with the agent's or the gateway's network tag.
- The network has no rule that lets in its own address range. So a stagelet does not accept connections from another stagelet, and it cannot reach the agent host.
- The agent host accepts only SSH, and only from your `-operator-cidr` ranges.
- The gateway host accepts ports 80 and 443 from anywhere, and SSH from your ranges.
- On each instance, containers cannot open new connections to the metadata server at `169.254.169.254`, except on port 53. The metadata server is also the instance's DNS server.

## Run setup

```sh
export GOOGLE_APPLICATION_CREDENTIALS=key.json
stagely login
stagely setup gcp \
  -environment production \
  -region us-central1 \
  -zone us-central1-a \
  -stagelet-domain stagelets.example.com \
  -registry stagely \
  -operator-cidr 203.0.113.7/32 \
  -binaries bin/linux-amd64 \
  -acme-email ops@example.com
```

| Flag            | Meaning                                                                                |
| --------------- | -------------------------------------------------------------------------------------- |
| `-region`       | Region of the network, the address and the repository, required                        |
| `-zone`         | Zone in the region for the hosts and stagelet machines, required                       |
| `-registry`     | ID of the Artifact Registry Docker repository that setup creates, required             |
| `-project`      | Project ID. The default is the project of the service account key.                     |
| `-credentials`  | Service account key file. The default is the file in `GOOGLE_APPLICATION_CREDENTIALS`. |
| `-golden-image` | Image for stagelet machines and build workers, built from the golden image template    |

Setup also takes the [flags that every cloud takes](https://stagely.dev/docs/setup/cloud.md#flags-every-cloud-takes). At the end, it prints the gateway's static address. [Point DNS at the gateway](https://stagely.dev/docs/setup/cloud.md#point-dns-at-the-gateway) with an A record.

## After setup

1. [Add `.stagely.yml`](https://stagely.dev/docs/app/stagely-yml.md) to your repository.
2. [Add config values and secrets](https://stagely.dev/docs/setup/config.md).
3. Read the [Security model](https://stagely.dev/docs/security.md) before you add real secrets.
