Deploy an API gateway with the api-gateway template
Coming from another cloud?
▸AWS·API Gateway
This Quake AI feature maps to AWS’s API Gateway.
▸Google Cloud·API Gateway
This Quake AI feature maps to Google Cloud’s API Gateway.
Deploy an API gateway with the api-gateway template
Stand up an Apache APISIX API gateway on one Quake AI instance using the validated OpenTofu template api-gateway. You apply the template, launch two private backends on the same subnet, verify starter routes through the gateway floating IP, add rate limiting and key authentication, point a domain at the gateway, and lock each backend security group to the gateway.
The gateway holds the only public floating IP. The backend services stay on the private subnet with no addresses on the internet. You operate the gateway and backends yourself; this is a regional API front door you run, not a managed global edge gateway.
Monthly cost estimate
Pricing calculator ↗Sized as a custom package on shared vCPU.
Monthly total for the required template above. Use the configurator below to add optional pieces and see the total update.
What each resource is for
Gateway
s1a.medium · 4 shared vCPU, 4 GiB RAM, 0.5 Gbps
2× s1a.small
s1a.small · 2 shared vCPU, 2 GiB RAM, 0.5 Gbps
Compute shown per role at custom-package rates ($29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM). The headline above is the billed total: the cheaper of a named plan and the custom package, plus add-ons.
Included in baseline
s1a.medium
4 shared vCPU, 4 GiB RAM, 0.5 Gbps
s1a.small
2 shared vCPU, 2 GiB RAM, 0.5 Gbps
s1a.small
2 shared vCPU, 2 GiB RAM, 0.5 Gbps
Compute + RAM rate basis
8 vCPU + 8 GiB RAM at $29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM (regular). Totals apply the flat −$5/mo package promotion.
Block storage (40 GiB)
40 GiB at $0.08/GiB/mo
Public IP (included)
1 included with the custom package
Package promotional discount
Flat −$5.00/mo on the custom package (same promotion as named plans).
Included at no charge
These line items are zero on Quake AI. Many other providers meter them separately.
Data transfer (inbound and outbound)
Unlimited data transfer on every plan; Quake AI does not meter per-GB egress.
AWS, GCP, and Azure meter outbound transfer per GB. DigitalOcean and Hetzner include an allowance on compute plans, then charge overage.
Learn morePrivate networking
Private networks, subnets, Neutron routers, and security groups are included with the plan.
VPC objects are usually free to create elsewhere, but NAT gateways bill hourly plus per-GB processed. Quake AI uses router SNAT with no separate NAT line item.
Control-plane API requests
OpenStack API calls for provisioning and management are included.
Some managed services on other clouds meter API calls or charge for premium control-plane features.
Pricing data last validated: . For current rates, check quake.ai/pricing.
Prerequisites#
You need:
- OpenTofu 1.6.0 or later (or Terraform 1.6.0 or later) installed locally.
- Your OpenStack credentials sourced into the shell (
source openrc.sh). See the OpenStack CLI guide. - An SSH keypair that already exists in your project. Record its name for the
key_namevariable. - A copy of the
api-gatewaytemplate directory from the template reference page. - A domain you can point at the gateway floating IP when you reach the TLS step.
Step 1: Apply the gateway template#
Copy the template's example variables file and set key_name. Keep the default upstream_services unless you plan different private addresses:
cp terraform.tfvars.example terraform.tfvarskey_name = "YOUR_KEY_NAME"Initialize, preview, and apply:
tofu init
tofu plan
tofu applyOpenTofu provisions a private network, router, security group, data volume, gateway instance, and floating IP. cloud-init installs Docker, starts etcd on localhost, starts APISIX, generates an admin API key, and seeds starter routes to 10.42.0.10 and 10.42.0.11.
Record the outputs:
tofu output floating_ip
tofu output private_ip
tofu output gateway_url
tofu output admin_hintWait three to five minutes for cloud-init to finish before you test the gateway.
Step 2: Launch two private backends on the gateway network#
The template creates network api-gateway-net and subnet api-gateway-subnet. Launch two small backend instances at 10.42.0.10 and 10.42.0.11 with no floating IPs.
- Create a security group for the backends:
openstack security group create api-backends-sg \
--description "Private API backends; ingress from gateway only after step 8"Allow SSH from your workstation while you configure the backends:
openstack security group rule create \
--protocol tcp --dst-port 22 --remote-ip YOUR_IP/32 api-backends-sg- Resolve the subnet ID:
SUBNET_ID=$(openstack subnet list -f value -c ID -c Name | awk '/api-gateway-subnet/ {print $1}')- Write cloud-init that serves distinct responses on port 8080 for each backend:
cat > backend-a-cloud-init.yaml <<'EOF'
#cloud-config
package_update: true
packages:
- nginx
runcmd:
- |
echo 'service-a ok' > /var/www/html/index.html
printf '%s\n' 'server {' ' listen 8080;' ' root /var/www/html;' '}' > /etc/nginx/sites-available/default
systemctl restart nginx
EOF
cat > backend-b-cloud-init.yaml <<'EOF'
#cloud-config
package_update: true
packages:
- nginx
runcmd:
- |
echo 'service-b ok' > /var/www/html/index.html
printf '%s\n' 'server {' ' listen 8080;' ' root /var/www/html;' '}' > /etc/nginx/sites-available/default
systemctl restart nginx
EOF- Create ports and launch the instances:
openstack port create \
--network api-gateway-net \
--fixed-ip subnet=$SUBNET_ID,ip-address=10.42.0.10 \
--security-group api-backends-sg \
service-a-port
openstack port create \
--network api-gateway-net \
--fixed-ip subnet=$SUBNET_ID,ip-address=10.42.0.11 \
--security-group api-backends-sg \
service-b-port
openstack server create \
--flavor s1a.small \
--image Ubuntu-24.04 \
--key-name YOUR_KEY_NAME \
--port service-a-port \
--user-data backend-a-cloud-init.yaml \
service-a
openstack server create \
--flavor s1a.small \
--image Ubuntu-24.04 \
--key-name YOUR_KEY_NAME \
--port service-b-port \
--user-data backend-b-cloud-init.yaml \
service-bWait until both instances report ACTIVE.
Step 3: Verify starter routes through the gateway#
From your workstation, request each seeded route over HTTP on the gateway floating IP:
curl -s http://YOUR_FLOATING_IP/service-a/
curl -s http://YOUR_FLOATING_IP/service-b/The responses should show service-a ok and service-b ok. Traffic flows client to gateway floating IP to APISIX to the private backend.
If either route returns 502, cloud-init may still be running on the gateway or a backend. Retry after a minute. SSH to the gateway and run docker compose -f /opt/gateway/docker-compose.yml ps to confirm APISIX and etcd are up.
Step 4: Open the Admin API and read the admin key#
Port 9180 is not open in the gateway security group. Open an SSH tunnel from your workstation:
ssh -L 9180:127.0.0.1:9180 ubuntu@YOUR_FLOATING_IPIn another terminal on the same workstation, read the admin key from the gateway host:
ssh ubuntu@YOUR_FLOATING_IP 'sudo grep admin_key /root/gateway-admin-credentials'Export it for the Admin API calls in the next steps:
export ADMIN_KEY="PASTE_ADMIN_KEY_HERE"Confirm the Admin API answers through the tunnel:
curl -s -H "X-API-KEY: $ADMIN_KEY" http://127.0.0.1:9180/apisix/admin/routes | head -c 200Step 5: Add key authentication#
Create a consumer with an API key APISIX checks on every request:
curl -s -X PUT http://127.0.0.1:9180/apisix/admin/consumers/demo \
-H "X-API-KEY: $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"username": "demo",
"plugins": {
"key-auth": {
"key": "demo-api-key"
}
}
}'Enable the key-auth plugin on both routes:
for ROUTE in service-a service-b; do
curl -s -X PATCH "http://127.0.0.1:9180/apisix/admin/routes/$ROUTE" \
-H "X-API-KEY: $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"plugins":{"key-auth":{}}}'
doneVerify an unauthenticated request is rejected:
curl -s -o /dev/null -w "%{http_code}\n" http://YOUR_FLOATING_IP/service-a/The status code should be 401. A request with the API key should pass:
curl -s -H "apikey: demo-api-key" http://YOUR_FLOATING_IP/service-a/The response body should show service-a ok.
Step 6: Add a rate limit#
Attach APISIX limit-count to both routes. This example allows two requests per 60 seconds per client IP, then returns 429:
for ROUTE in service-a service-b; do
curl -s -X PATCH "http://127.0.0.1:9180/apisix/admin/routes/$ROUTE" \
-H "X-API-KEY: $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"plugins": {
"key-auth": {},
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 429,
"key": "remote_addr"
}
}
}'
doneSend three authenticated requests in quick succession:
for i in 1 2 3; do
curl -s -o /dev/null -w "request $i: %{http_code}\n" \
-H "apikey: demo-api-key" http://YOUR_FLOATING_IP/service-a/
doneThe first two requests should return 200; the third should return 429.
Step 7: Point a domain at the gateway#
- Create a DNS A record for your domain (for example
api.example.com) pointing atYOUR_FLOATING_IP. Follow How to point a domain at a Quake AI resource. Wait until it resolves:
dig +short api.example.com- Terminate TLS at the gateway. The template serves HTTP on port 80 by default. For a production domain, add an SSL listener and certificate through the Admin API or place a TLS-terminating reverse proxy in front of APISIX. For this walkthrough, continue testing over HTTP on the floating IP until you configure HTTPS for your domain.
For certificate background, see How to issue and auto-renew a TLS certificate with Let's Encrypt.
Step 8: Lock the backend security groups to the gateway#
Restrict each backend so it accepts application traffic only from the gateway security group api-gateway-sg:
openstack security group rule create \
--protocol tcp \
--dst-port 8080 \
--remote-group api-gateway-sg \
api-backends-sgList the backend rules and confirm port 8080 allows only the gateway group:
openstack security group rule list api-backends-sg -f tableThe backends have no floating IPs, so they are not reachable directly from the internet. Only the gateway can forward traffic to them on the private subnet.
Verify authenticated traffic still passes:
curl -s -H "apikey: demo-api-key" http://YOUR_FLOATING_IP/service-b/The response should show service-b ok.
What you built#
- Applied the
api-gatewaytemplate to provision a private network, gateway security group, data volume, APISIX host with etcd, and floating IP - Launched two private backends at
10.42.0.10and10.42.0.11with no public addresses - Verified starter routes through the gateway floating IP
- Added key authentication so unauthenticated requests return
401 - Added rate limiting so excess requests return
429 - Locked the backend security group so application traffic accepts only the gateway as its source
Scope of this deployment#
This gateway runs in one region on a VM you operate. It is a regional API front door, not a global edge network: Quake AI has no anycast and no global PoPs. For model routing to LLM backends instead of your own services, see the sibling inference gateway deployment.
The walkthrough adds two small backend instances; those VMs are not part of the OpenTofu template. Size the gateway with the template defaults; scale backends independently for your services.
Next steps#
- API gateway template: parameters, ports, and resource map
- Inference gateway deployment: the LLM-routing sibling with the same edge shape
- Edge WAF template: add L7 attack filtering in front of the same private-backend shape
- Security hardening checklist: audit security groups and floating IP usage
Clean up#
When you no longer need the deployment, destroy the OpenTofu stack and delete the backend resources you created in step 2:
tofu destroy
openstack server delete service-a service-b
openstack port delete service-a-port service-b-port
openstack security group delete api-backends-sgRemove any DNS A record you pointed at the gateway floating IP.
See Also
Terraform and OpenTofu on Quake AI
Prerequisite
Networks
Prerequisite
Authoring IaC templates for Quake AI
Shares: Volumes, Security Groups
Deploy a regional edge cache with the edge-cache template
Shares: Volumes, Security Groups
Deploy edge functions with the edge-functions template
Shares: Volumes, Security Groups