GCP
Deploy Operate on Google Cloud
Operate's Google Cloud image runs as one self-contained VM in your Google Cloud project: the Operate web app and worker stack, with MongoDB and Redis on the same VM. The image holds no App ID or integration credentials. After launch, open the HTTPS address, create the first admin account, then enter your App ID and integrations in Operate.
Separately, Operate sends a usage record to operatex.dev for billing: your App ID, token counts, timings, and model name. It does not send your logs, records, or code.
How it works
The image is Ubuntu 24.04 with Docker Engine and the Compose plugin and a pinned Operate release. A systemd service starts the stack at boot. First boot creates this VM's own database credentials, then starts Operate, then sets up HTTPS. First boot only reports that Operate is ready after an HTTPS check against the VM's external IPv4 passes with a trusted certificate.
The boot disk must be at least 40 GB, the image's default. Use the machine type and disk sizes the Marketplace listing publishes once it is live.
Allow web traffic in the VPC
Give the VM an external IPv4 address. The image reads it from Google Cloud metadata at first boot to get its certificate. Create VPC ingress firewall rules allowing TCP 80 and 443 from the client ranges that need Operate. These VPC rules are separate from the firewall inside the VM. Port 80 is used for certificate setup and the redirect, users open Operate on 443, and port 8080 stays closed to the internet. See Google's firewall guide.
Limit SSH access
SSH is TCP 22. Allow it only from the administrator's range, for example 203.0.113.10/32, never from everywhere.
Recover HTTPS if setup fails
If the VM had no external IPv4 at first boot, assign one. Confirm the VPC allows 80 and 443, then run:
sudo operate tlsIt reads the current address from metadata, updates Caddy's address settings, restarts Caddy, and checks that https://<external-ip>/api/healthcheck returns 200 with a valid certificate. If it fails, check sudo journalctl -u caddy and /var/log/operate-setup.log, fix the cause and run it again. It does not change the database credentials. Do not rerun the first-boot script to recover HTTPS.
Reserve a static external IPv4 if the address must survive a stop or replacement, and run sudo operate tls again whenever the address changes.
Data Volume
Without a separate disk, MongoDB, Redis, cloned repositories and Operate's internal secrets live in Docker volumes on the boot disk. They survive restarts and reboots, but Compute Engine deletes the boot disk with the VM by default, and the data with it.
A separate Persistent Disk keeps the data outside the boot disk. At first boot, or when you run sudo operate storage, the image formats the disk if it has no file system, mounts it at /mnt/operate-data, moves existing data onto it, and sets OPERATE_DATA_ROOT. Use Persistent Disk, never Local SSD, for this data. The image only uses a disk that the VM reports as a persistent disk, so Local SSD and any disk it cannot identify are left unused.
Recommended size
20 GB is the practical minimum and 50 GB is a good starting point for production. Leave room for database growth.
Attach a disk at launch
gcloud compute instances create operate-1 \
--image-family=operate-marketplace \
--image-project=PROJECT_ID \
--boot-disk-size=40GB \
--create-disk=name=operate-data,size=50GB,type=pd-balanced,device-name=operate-data,auto-delete=noReplace PROJECT_ID with the project that publishes the image; auto-delete=no keeps the disk when the VM is deleted.
Attach a disk after launch
- Create a Persistent Disk in the VM's zone.
- In the console open Compute Engine > VM instances, select the VM and click Edit.
- Under Storage > Additional disks choose + Attach existing disk and pick it.
- Set mode Read/write and deletion rule Keep disk.
- Set its custom device name to
operate-data, then save.
Google exposes it as /dev/disk/by-id/google-operate-data, a stable name the image uses instead of /dev/sd* or /dev/nvme*. To list device names on the VM, run:
ls -1 /dev/disk/by-id/google-* | sed 's|.*/google-||'Then run sudo operate storage, which stops Operate, formats the disk only if it has no file system, mounts it, copies existing data, sets OPERATE_DATA_ROOT and restarts, without changing the database credentials. With more than one eligible disk, pass the device name:
sudo operate storage operate-dataVerify the disk is in use
# Is the disk mounted?
mountpoint /mnt/operate-data && df -h /mnt/operate-data
# Is Operate pointed at it?
grep OPERATE_DATA_ROOT /opt/operate/operate.env
# Is Docker using paths on the disk?
docker compose --env-file /opt/operate/operate.env -f /opt/operate/app/docker-compose.yml \
config | grep /mnt/operate-data
# What did the setup script decide?
cat /var/log/operate-setup.logBack up or move the disk
Keep the disk's deletion rule at Keep disk. Before replacing a VM, stop Operate with sudo systemctl stop operate.service, snapshot the data disk, then start Operate again. See Google's snapshot best practices. The database credentials live in /opt/operate/operate.env on the boot disk, not on the data disk, so save OPERATE_MONGODB_USERNAME, OPERATE_MONGODB_PASSWORD and OPERATE_MONGODB_URI before deleting the old VM.
/opt/operate/operate.env, then attach the disk and run sudo operate storage operate-data. Keep a separate backup until the replacement works.Staying current
sudo operate updateThe command checks for and installs a newer Operate release. It does not update the VM image or the guest OS.
Verify
After first boot reports Operate is ready, open https://<external-ip>/. The getting-started page loads with a trusted certificate and no browser warning. Create the first admin account, enter the App ID and integrations, then follow step 6 of the self-hosted guide to verify an integration. To check the data disk, run the commands in Data Volume; the resolved paths should be under /mnt/operate-data.
Still stuck? We can handle the full setup for you.
Talk to us