# Edge cache

Source: https://docs.quake.ai/resources/iac-templates/edge-cache
Markdown: https://docs.quake.ai/resources/iac-templates/edge-cache.md

---

# Edge cache

This pattern composes Compute, Network, and Block Storage into a regional HTTP cache on infrastructure you control.

## What this template does

Provisions a single instance running [Varnish Cache](https://varnish-cache.org), an open-source HTTP accelerator, that caches GET and HEAD responses from a private origin on a floating IP:

- Compute instance that runs Varnish in Docker, sized for a modest cacheable origin (2 vCPU and 2 GiB RAM by default)
- Private network, subnet, router, port, and security group; a floating IP on the cache only
- A block volume mounted at `/data`, so cache files and TLS state live on a volume you can grow rather than on the boot disk
- cloud-init installs Docker, writes a VCL file that honors origin `Cache-Control` headers, and starts Varnish on first boot
- When `domain` is set, Caddy terminates TLS in front of Varnish and obtains a Let's Encrypt certificate automatically

The origin stays on the private subnet with no floating IP of its own. You set `upstream_host` and `upstream_port` to the private address of the origin, then lock the origin security group to accept traffic only from the cache.

## Slug decision

This template has its own slug rather than folding into [Edge reverse proxy](/resources/iac-templates/edge-reverse-proxy). Cache storage sizing, purge semantics, and `Cache-Control` policy are a distinct appliance from TLS termination alone.

## Honest scope

This cache runs in one region on a VM you operate. It is a regional HTTP accelerator, 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](/docs/network/how-to/front-with-cdn).

## Alternate engines

This template leads with Varnish (explicit VCL, `PURGE` support, file-backed storage on the data volume). [Nginx with `proxy_cache`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache) fits when you already run Nginx on the edge reverse proxy template and want a lighter cache layer without a dedicated cache VM.

## Parameters

| Parameter | Description | Default |
| --- | --- | --- |
| `key_name` | SSH keypair name (must already exist) | No default |
| `flavor_name` | Instance size (Varnish runs on 2 vCPU / 2 GiB) | `s1a.small` |
| `image_name` | Operating system image | `Ubuntu-24.04` |
| `app_name` | Display name prefix for resources | `edge-cache` |
| `varnish_version` | Varnish container image tag | `7.6` |
| `caddy_version` | Caddy image tag when `domain` is set | `2-alpine` |
| `domain` | Public domain for automatic HTTPS; empty serves HTTP on the floating IP | `""` |
| `upstream_host` | Private IP of the origin instance | `10.42.0.10` |
| `upstream_port` | TCP port the origin listens on | `8080` |
| `cache_size` | Varnish file store size in GiB on the data volume | `2` |
| `volume_size` | Block volume size in GiB, mounted at `/data` | `10` |
| `external_network` | External network for floating IP allocation | `PublicStatic` |
| `private_cidr` | CIDR for the private subnet | `10.42.0.0/24` |

## Cache behavior and purge

Varnish caches GET and HEAD responses when the origin allows it:

- Honors `Cache-Control: private`, `no-cache`, and `no-store` (pass-through, no store)
- Uses `max-age` from `Cache-Control` when present
- Falls back to a one-hour TTL when the origin sends `Expires`, `Last-Modified`, or `ETag` without an explicit deny

Purge a cached object with the HTTP `PURGE` method from localhost on the instance (for example `curl -X PURGE http://127.0.0.1/path` over SSH). Remote purge is blocked by the default VCL ACL.

## Ports and access

| Port | Purpose |
| --- | --- |
| 22 | Host SSH for administration |
| 80 | HTTP (Varnish when `domain` is empty; ACME challenges when `domain` is set) |
| 443 | HTTPS when `domain` is set and Caddy has obtained a certificate |

## When to use this pattern

Run a regional HTTP cache in front of a private origin so cacheable static assets and API responses absorb repeat traffic without hitting the origin on every request. Pair it with [Edge reverse proxy](/resources/iac-templates/edge-reverse-proxy) when you need TLS termination without caching, or with [Front with a CDN](/docs/network/how-to/front-with-cdn) when you need geographic edge.

## Estimated cost

<PricingCompanion
  components={[
    { kind: "template", slug: "edge-cache", required: true },
  ]}
/>

## Template source

This is a [validated OpenTofu template](/docs/platform/validation#how-infrastructure-templates-are-checked).

<TemplateSource slug="edge-cache" />

<TemplateResourceMap template="edge-cache" format="opentofu" />

## Customize this pattern

- [Customize a template's image and flavor](/docs/automation/how-to/customize-template-image-flavor)
- [Add a block volume to a template](/docs/automation/how-to/add-volume-to-template)
- [Parameterize a template with a tfvars file](/docs/automation/how-to/parameterize-template-tfvars)

## See also

- [Edge reverse proxy](/resources/iac-templates/edge-reverse-proxy)
- [Edge WAF template](/resources/iac-templates/edge-waf)
- [Front with a CDN](/docs/network/how-to/front-with-cdn)
