Quickstart: GCP (Compute Engine)
For: Platform engineers deploying Axemere Gateway on GCP. Detail page for Cloud Deployment — see also AWS and Azure.
Axemere Gateway sits between your applications and AI providers (OpenAI, Anthropic, etc.), enforcing policies, tracking attribution, and recording every request. This guide deploys the gateway as a binary on a GCP Compute Engine VM with Cloud SQL PostgreSQL.
Table of Contents
Prerequisites
- Google Cloud SDK (
gcloud) configured with a project and credentials that can create Compute Engine VMs, Cloud SQL instances, VPCs, service accounts, and Secret Manager secrets - A GCP project with billing enabled
curlandjqfor testing (installed on the VM in Step 3)- An OpenAI or Anthropic API key to store as a credential. You can skip this and test with a policy denial instead.
Architecture
The gateway runs as a systemd service on the VM. Cloud SQL is accessible over a private VPC IP; no public database endpoint is exposed.
Steps
Step 1: Provision the VPC and Cloud SQL Instance
Create a VPC with private service access so Cloud SQL uses an internal IP:
PROJECT_ID="your-gcp-project-id" REGION="us-central1" ZONE="us-central1-a" gcloud config set project $PROJECT_ID # Create a dedicated VPC gcloud compute networks create axemere-vpc \ --subnet-mode=custom \ --project=$PROJECT_ID # Create a subnet gcloud compute networks subnets create axemere-subnet \ --network=axemere-vpc \ --region=$REGION \ --range=10.0.0.0/24 \ --project=$PROJECT_ID # Enable Private Service Access for Cloud SQL gcloud compute addresses create google-managed-services-axemere \ --global \ --purpose=VPC_PEERING \ --prefix-length=16 \ --network=axemere-vpc \ --project=$PROJECT_ID gcloud services vpc-peerings connect \ --service=servicenetworking.googleapis.com \ --ranges=google-managed-services-axemere \ --network=axemere-vpc \ --project=$PROJECT_ID
Create the Cloud SQL instance (private IP only):
DB_PASSWORD=$(openssl rand -hex 24) echo "DB password: $DB_PASSWORD" # save this gcloud sql instances create axemere-db \ --database-version=POSTGRES_15 \ --tier=db-g1-small \ --region=$REGION \ --network=axemere-vpc \ --no-assign-ip \ --project=$PROJECT_ID gcloud sql databases create mvgc_gateway \ --instance=axemere-db \ --project=$PROJECT_ID gcloud sql users set-password postgres \ --instance=axemere-db \ --password="$DB_PASSWORD" \ --project=$PROJECT_ID
Get the private IP:
DB_IP=$(gcloud sql instances describe axemere-db \ --project=$PROJECT_ID \ --format='value(ipAddresses[0].ipAddress)') echo "Cloud SQL private IP: $DB_IP"
Step 2: Create the Compute Engine VM
Create a service account for the VM with minimal permissions:
gcloud iam service-accounts create axemere-gateway \ --display-name="Axemere Gateway" \ --project=$PROJECT_ID # Grant access to Secret Manager (for reading credentials) gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:axemere-gateway@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/secretmanager.secretAccessor"
Create the VM on the same VPC:
gcloud compute instances create axemere-gateway \ --project=$PROJECT_ID \ --zone=$ZONE \ --machine-type=e2-medium \ --network=axemere-vpc \ --subnet=axemere-subnet \ --no-address \ --service-account="axemere-gateway@${PROJECT_ID}.iam.gserviceaccount.com" \ --scopes=cloud-platform \ --image-family=debian-12 \ --image-project=debian-cloud \ --boot-disk-size=20GB \ --tags=axemere-gateway
Add a firewall rule to allow inbound traffic on port 7080 from within the VPC:
gcloud compute firewall-rules create axemere-gateway-internal \ --network=axemere-vpc \ --allow=tcp:7080 \ --source-ranges=10.0.0.0/24 \ --target-tags=axemere-gateway \ --project=$PROJECT_ID
For SSH access, add your IP to a firewall rule on port 22, or use
gcloud compute sshvia IAP:gcloud compute ssh axemere-gateway --tunnel-through-iap --zone=$ZONE
Step 3: Install the Gateway Binary
SSH into the VM and install the gateway:
gcloud compute ssh axemere-gateway --tunnel-through-iap --zone=$ZONE
On the VM:
# Install the Axemere APT repository curl -fsSL https://raw.githubusercontent.com/Axemere-LLC/mvgc-apt/main/gpg.key \ | sudo gpg --dearmor -o /etc/apt/keyrings/mvgc.gpg echo "deb [signed-by=/etc/apt/keyrings/mvgc.gpg arch=$(dpkg --print-architecture)] \ https://raw.githubusercontent.com/Axemere-LLC/mvgc-apt/main stable main" \ | sudo tee /etc/apt/sources.list.d/mvgc.list sudo apt update && sudo apt install -y mvgc-gateway jq
Verify the install:
mvgc-gateway --version
Step 4: Store Secrets in Secret Manager
From your local machine (not the VM), store the admin token and database password in GCP Secret Manager:
ADMIN_TOKEN=$(openssl rand -hex 32) # Admin token echo -n "$ADMIN_TOKEN" | gcloud secrets create axemere-admin-token \ --data-file=- --project=$PROJECT_ID # Database URL echo -n "postgres://postgres:${DB_PASSWORD}@${DB_IP}:5432/mvgc_gateway?sslmode=disable" \ | gcloud secrets create axemere-db-url \ --data-file=- --project=$PROJECT_ID # AI provider key (optional — skip if testing with policy denial) echo -n "sk-..." | gcloud secrets create axemere-openai-key \ --data-file=- --project=$PROJECT_ID
Step 5: Configure and Start the Gateway
On the VM, create a startup script that reads secrets from Secret Manager at boot:
sudo mkdir -p /etc/mvgc sudo tee /etc/mvgc/env-from-secrets.sh << 'EOF' #!/bin/bash # Reads secrets from GCP Secret Manager and exports them as env vars. # Run as root at service start. export_secret() { local name="$1" local var="$2" local val val=$(gcloud secrets versions access latest --secret="$name" 2>/dev/null) if [ -n "$val" ]; then export "$var"="$val" fi } export_secret axemere-db-url DATABASE_URL export_secret axemere-admin-token MVGC_ADMIN_TOKEN export_secret axemere-openai-key OPENAI_API_KEY EOF sudo chmod 700 /etc/mvgc/env-from-secrets.sh
Create the systemd unit:
sudo tee /etc/systemd/system/mvgc-gateway.service << 'EOF' [Unit] Description=Axemere Gateway After=network-online.target Wants=network-online.target [Service] Type=simple EnvironmentFile=-/etc/mvgc/mvgc.env ExecStartPre=/bin/bash /etc/mvgc/env-from-secrets.sh ExecStart=/usr/bin/mvgc-gateway Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now mvgc-gateway
Check status:
sudo systemctl status mvgc-gateway sudo journalctl -u mvgc-gateway -f
Step 6: Verify the Deployment
From within the VPC (or via port-forward through IAP):
# If testing locally via IAP tunnel: gcloud compute start-iap-tunnel axemere-gateway 7080 --local-host-port=localhost:7080 --zone=$ZONE & curl -s http://localhost:7080/healthz | jq .
Expected response:
{"status":"ok", "version":"...", "node_id":"...", ...}
Step 7: Register a Workload and Send Your First Request
Export your admin token (from Secret Manager):
export MVGC_ADMIN_TOKEN=$(gcloud secrets versions access latest --secret=axemere-admin-token) GATEWAY_URL="http://localhost:7080" # adjust to your VM's internal IP if calling from another VM
Register a workload:
curl -s -X PUT "${GATEWAY_URL}/v1/admin/workloads" \ -H "MVGC-Admin-Token: $MVGC_ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "workload_id": "wl-quickstart", "org_id": "org-quickstart", "name": "Quickstart Workload", "default_attribution": { "project_id": "proj-quickstart" }, "allowed_connection_types": ["direct_api"] }' | jq .
Submit a request (or test a policy denial without a key):
# Option A: with an OpenAI key stored in the gateway curl -s -X POST "${GATEWAY_URL}/v1/actions:execute" \ -H "Content-Type: application/json" \ -d '{ "schema": "mvgc.action_request.v2", "org_id": "org-quickstart", "workload_id": "wl-quickstart", "action": { "type": "ai.infer", "method": "POST", "target_host": "api.openai.com", "target_path": "/v1/chat/completions", "params": { "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Say hello in one sentence."}], "max_tokens": 50 } }, "attribution": { "project_id": "proj-quickstart" } }' | jq . # Option B: test a policy denial (no key needed) curl -s -X POST "${GATEWAY_URL}/v1/actions:execute" \ -H "Content-Type: application/json" \ -d '{ "schema": "mvgc.action_request.v2", "org_id": "org-quickstart", "workload_id": "wl-quickstart", "action": { "type": "ai.infer", "method": "POST", "target_host": "api.example-blocked.com", "params": {"model": "test"} }, "attribution": { "project_id": "proj-quickstart" } }' | jq .
Production Considerations
- Cloud SQL tier. The example uses
db-g1-small. Usedb-n1-standard-4or larger for production workloads. Enable high availability in the Cloud SQL settings. - VM sizing.
e2-mediumhandles light traffic. Usen2-standard-4for sustained load. - Load balancing. For external access or multiple VMs, put an internal GCP Load Balancer in front. Use a managed SSL certificate for TLS termination.
- Secret rotation. Rotate
axemere-admin-tokenand provider keys in Secret Manager. The gateway reads secrets at startup; restart the service after rotation. - IAP for SSH. Use Identity-Aware Proxy (
--tunnel-through-iap) instead of opening port 22 to the internet. No external IP is required on the VM. - VPC firewall. Keep the gateway port (7080) restricted to internal VPC ranges. Only expose it externally via a load balancer with TLS.
- Connecting to the control plane. To manage this gateway from
console.axemere.ai, see the Self-Hosted + CP Connected guide.
Next Steps
| Task | Where to look |
|---|---|
| Configure credentials and policies | Configuration Reference |
| Connect to the Axemere control plane | CP Connected Onboarding |
| Set up monitoring and observability | Telemetry and Observability |
| Integrate your application | Developer Integration Guide |
| Use the managed gateway service | Managed Gateway Guide |
Cleanup
# Stop and remove the gateway service (on the VM) sudo systemctl stop mvgc-gateway sudo systemctl disable mvgc-gateway # From your local machine: gcloud compute instances delete axemere-gateway --zone=$ZONE --project=$PROJECT_ID gcloud sql instances delete axemere-db --project=$PROJECT_ID gcloud secrets delete axemere-admin-token --project=$PROJECT_ID gcloud secrets delete axemere-db-url --project=$PROJECT_ID gcloud secrets delete axemere-openai-key --project=$PROJECT_ID gcloud compute networks delete axemere-vpc --project=$PROJECT_ID