Deploy a regional edge cache with the edge-cache template
Deploy a regional edge cache with the edge-cache template
Stand up a Varnish Cache HTTP accelerator on one Quake AI instance using the validated OpenTofu template edge-cache. You apply the template, launch a private origin on the same subnet, confirm a cache miss reaches the origin and a repeat request is a cache hit, purge a path from localhost, lock the origin security group to the cache, and optionally point a domain for automatic TLS.
The cache holds the only public floating IP. The origin stays on the private subnet with no address on the internet. You operate both instances yourself; this is a regional HTTP cache you run, not a global PoP network.
Monthly cost estimate
Pricing calculator ↗Sized as a custom package on shared vCPU.
Partial estimate: 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
Cache
s1a.small · 2 shared vCPU, 2 GiB RAM, 0.5 Gbps
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.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
4 vCPU + 4 GiB RAM at $29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM (regular). Totals apply the flat −$5/mo package promotion.
Block storage (30 GiB)
30 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
edge-cachetemplate directory from the template reference page. - A domain you can point at the cache floating IP when you enable TLS (optional for the HTTP verification steps below).
Step 1: Apply the cache template#
Copy the template's example variables file and set key_name. Leave domain empty so Varnish serves plain HTTP on port 80 while you stand up the origin. Keep the default upstream_host and upstream_port unless you plan a different private address:
cp terraform.tfvars.example terraform.tfvarskey_name = "YOUR_KEY_NAME"
upstream_host = "10.42.0.10"
upstream_port = 8080Initialize, preview, and apply:
tofu init
tofu plan
tofu applyOpenTofu provisions a private network, router, security group, data volume, cache instance, and floating IP. cloud-init installs Docker, mounts the data volume at /data, writes a VCL file that honors origin Cache-Control headers, and starts Varnish on first boot.
Record the outputs:
tofu output floating_ip
tofu output private_ip
tofu output cache_urlWait two to three minutes for cloud-init to finish before you test the cache.
Step 2: Launch a private origin on the cache network#
The template creates network edge-cache-net and subnet edge-cache-subnet (names follow the default app_name). Launch a small origin instance on that subnet at the fixed address 10.42.0.10 with no floating IP.
- Create a security group for the origin:
openstack security group create app-origin-sg \
--description "Private app origin; ingress from cache only after step 6"Allow SSH from your workstation while you configure the origin:
openstack security group rule create \
--protocol tcp --dst-port 22 --remote-ip YOUR_IP/32 app-origin-sg- Create a port with the fixed private IP:
SUBNET_ID=$(openstack subnet list -f value -c ID -c Name | awk '/edge-cache-subnet/ {print $1}')
openstack port create \
--network edge-cache-net \
--fixed-ip subnet=$SUBNET_ID,ip-address=10.42.0.10 \
--security-group app-origin-sg \
app-origin-port- Write cloud-init that serves a cacheable test page on port 8080 with an explicit
Cache-Controlheader:
cat > origin-cloud-init.yaml <<'EOF'
#cloud-config
package_update: true
packages:
- nginx
runcmd:
- |
echo 'origin ok' > /var/www/html/index.html
printf '%s\n' \
'server {' \
' listen 8080;' \
' root /var/www/html;' \
' add_header Cache-Control "public, max-age=3600";' \
'}' > /etc/nginx/sites-available/default
systemctl restart nginx
EOF- Launch the origin instance on the port:
openstack server create \
--flavor s1a.small \
--image Ubuntu-24.04 \
--key-name YOUR_KEY_NAME \
--port app-origin-port \
--user-data origin-cloud-init.yaml \
app-originWait until the instance reports ACTIVE, then confirm the origin answers on the private subnet from the cache host:
ssh ubuntu@YOUR_FLOATING_IP 'curl -sI http://10.42.0.10:8080/ | tr -d "\r" | grep -i cache-control'The response should include Cache-Control: public, max-age=3600.
Step 3: Verify traffic through the cache#
From your workstation, request the cache floating IP over HTTP:
curl -s http://YOUR_FLOATING_IP/The response body should include origin ok. The request path is client to cache floating IP to Varnish to private origin.
If Varnish returns 503 or 502, cloud-init may still be running on the cache or origin. Wait and retry. SSH to the cache host and run docker compose -f /opt/edge-cache/docker-compose.yml ps to confirm Varnish is up.
Step 4: Confirm a cache miss, then a cache hit#
Varnish adds an Age header and an X-Varnish header on every response. On the first request for a URL, Age is 0 and X-Varnish carries one ID (a miss). On a repeat request while the object is still fresh, Age is greater than zero and X-Varnish carries two space-separated IDs (a hit).
Send two requests and inspect the headers:
curl -sI http://YOUR_FLOATING_IP/ | tr -d '\r' | grep -iE '^(age|x-varnish):'
curl -sI http://YOUR_FLOATING_IP/ | tr -d '\r' | grep -iE '^(age|x-varnish):'The first line should show Age: 0 (or a low value) and one X-Varnish ID. The second line should show a higher Age and two IDs in X-Varnish, which confirms Varnish served the response from its file-backed store at /data/varnish instead of contacting the origin again.
Step 5: Purge a cached path from localhost#
The default VCL allows PURGE only from localhost on the cache instance. SSH to the cache host and purge the root path:
ssh ubuntu@YOUR_FLOATING_IP 'curl -sI -X PURGE http://127.0.0.1/ | tr -d "\r" | head -5'The response status should be 200. A PURGE from your workstation is blocked:
curl -sI -X PURGE http://YOUR_FLOATING_IP/ | tr -d '\r' | grep -i '^HTTP'The status should be 405.
After the purge, the next client request is a miss again:
curl -sI http://YOUR_FLOATING_IP/ | tr -d '\r' | grep -iE '^(age|x-varnish):'Age should be 0 and X-Varnish should carry one ID.
Step 6: Lock the origin security group to the cache#
Restrict the origin so it accepts application traffic only from the cache security group edge-cache-sg. Remove any rule that opens the application port to 0.0.0.0/0 if you added one during testing.
openstack security group rule create \
--protocol tcp \
--dst-port 8080 \
--remote-group edge-cache-sg \
app-origin-sgList the origin rules and confirm port 8080 allows only the cache group:
openstack security group rule list app-origin-sg -f tableThe origin has no floating IP, so it is not reachable directly from the internet. Only the cache can forward traffic to it on the private subnet.
Verify cached traffic still passes through the cache:
curl -s http://YOUR_FLOATING_IP/The response should still include origin ok.
Step 7: Point a domain and enable HTTPS (optional)#
Skip this step if HTTP on the floating IP is enough for your test. To enable automatic TLS with Caddy in front of Varnish:
- Create a DNS A record for your domain (for example
cache.example.com) pointing atYOUR_FLOATING_IP. Follow How to point a domain at a Quake AI resource. Wait until it resolves:
dig +short cache.example.com- Set
domaininterraform.tfvarsand re-apply:
domain = "cache.example.com"tofu applycloud-init switches to the HTTPS branch: Caddy terminates TLS on ports 80 and 443 and forwards to Varnish on port 6081. Wait two to three minutes for Caddy to obtain a Let's Encrypt certificate.
- Confirm HTTPS end to end:
curl -sI https://cache.example.com/ | tr -d '\r' | grep -iE '^(HTTP|age|x-varnish):'The status should be 200 and repeat requests should still show cache hits via Age and X-Varnish.
For certificate background, see How to issue and auto-renew a TLS certificate with Let's Encrypt.
What you built#
- Applied the
edge-cachetemplate to provision a private network, cache security group, data volume, Varnish host, and floating IP - Launched a private origin on the same subnet at
10.42.0.10with cacheableCache-Controlheaders and no public address - Confirmed cache miss and cache hit behavior by inspecting
AgeandX-Varnishresponse headers - Purged a cached path with
PURGEfrom localhost on the cache instance - Locked the origin security group so application traffic accepts only the cache as its source
Scope of this deployment#
This cache runs in one region on a VM you operate. It stores cacheable HTTP responses on a block volume you size with cache_size and honors origin Cache-Control policy. It is not a global PoP network: Quake AI has no anycast, no global PoPs, and no first-party CDN. For geographic distribution and volumetric DDoS absorption at the network edge, front the origin with a third-party CDN.
The walkthrough adds a second small instance for the origin; that VM is not part of the OpenTofu template. Size the cache with the template defaults; scale the origin independently for your application.
Next steps#
- Edge cache template: parameters, VCL behavior, ports, and resource map
- Front with a CDN: cache static assets and absorb edge traffic geographically
- Edge reverse proxy template: TLS termination without a dedicated cache layer
- Edge WAF template: L7 inspection in front of a private origin
- 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 origin resources you created in step 2:
tofu destroy
openstack server delete app-origin
openstack port delete app-origin-port
openstack security group delete app-origin-sgRemove any DNS A record you pointed at the cache floating IP.
See Also
Terraform and OpenTofu on Quake AI
Prerequisite
Networks
Prerequisite
Authoring IaC templates for Quake AI
Shares: Volumes, Security Groups
Deploy an API gateway with the api-gateway template
Shares: Volumes, Security Groups
Deploy edge functions with the edge-functions template
Shares: Volumes, Security Groups