Skip to content
IaC Templates

Edge cache

Template · Updated Jul 2026
Validated Jul 2026

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, 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. 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.

Alternate engines#

This template leads with Varnish (explicit VCL, PURGE support, file-backed storage on the data volume). Nginx with 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#

ParameterDescriptionDefault
key_nameSSH keypair name (must already exist)No default
flavor_nameInstance size (Varnish runs on 2 vCPU / 2 GiB)s1a.small
image_nameOperating system imageUbuntu-24.04
app_nameDisplay name prefix for resourcesedge-cache
varnish_versionVarnish container image tag7.6
caddy_versionCaddy image tag when domain is set2-alpine
domainPublic domain for automatic HTTPS; empty serves HTTP on the floating IP""
upstream_hostPrivate IP of the origin instance10.42.0.10
upstream_portTCP port the origin listens on8080
cache_sizeVarnish file store size in GiB on the data volume2
volume_sizeBlock volume size in GiB, mounted at /data10
external_networkExternal network for floating IP allocationPublicStatic
private_cidrCIDR for the private subnet10.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#

PortPurpose
22Host SSH for administration
80HTTP (Varnish when domain is empty; ACME challenges when domain is set)
443HTTPS 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 when you need TLS termination without caching, or with Front with a CDN when you need geographic edge.

Estimated cost#

Monthly cost estimate

Pricing calculator ↗

Sized as a custom package on shared vCPU.

Starting template$13.90/mo

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

$16.50/mo

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

$16.50

Compute + RAM rate basis

2 vCPU + 2 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

$2.40

Public IP (included)

1 included with the custom package

$0.00

Package promotional discount

Flat −$5.00/mo on the custom package (same promotion as named plans).

$-5.00

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 more
$0.00

Private 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.

$0.00

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.

$0.00

Pricing data last validated: . For current rates, check quake.ai/pricing.

Template source#

This is a validated OpenTofu template.

8 files. Download the zip or expand to copy any file.Download edge-cache.zip
Show source (8 files)
main.tfHCL
locals {
  caddy_site = var.domain != "" ? var.domain : ":80"
}

data "openstack_images_image_v2" "os" {
  name        = var.image_name
  most_recent = true
}

data "openstack_networking_network_v2" "external" {
  name = var.external_network
}

resource "openstack_networking_network_v2" "private" {
  name           = "${var.app_name}-net"
  admin_state_up = true
}

resource "openstack_networking_subnet_v2" "private" {
  name            = "${var.app_name}-subnet"
  network_id      = openstack_networking_network_v2.private.id
  cidr            = var.private_cidr
  ip_version      = 4
  dns_nameservers = ["1.1.1.1", "8.8.8.8"]
}

resource "openstack_networking_router_v2" "main" {
  name                = "${var.app_name}-router"
  external_network_id = data.openstack_networking_network_v2.external.id
}

resource "openstack_networking_router_interface_v2" "private" {
  router_id = openstack_networking_router_v2.main.id
  subnet_id = openstack_networking_subnet_v2.private.id
}

resource "openstack_networking_secgroup_v2" "cache" {
  name        = "${var.app_name}-sg"
  description = "SSH and HTTP/HTTPS for the regional edge cache"
}

resource "openstack_networking_secgroup_rule_v2" "ssh" {
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  port_range_min    = 22
  port_range_max    = 22
  remote_ip_prefix  = "0.0.0.0/0"
  security_group_id = openstack_networking_secgroup_v2.cache.id
}

resource "openstack_networking_secgroup_rule_v2" "http" {
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  port_range_min    = 80
  port_range_max    = 80
  remote_ip_prefix  = "0.0.0.0/0"
  security_group_id = openstack_networking_secgroup_v2.cache.id
}

resource "openstack_networking_secgroup_rule_v2" "https" {
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  port_range_min    = 443
  port_range_max    = 443
  remote_ip_prefix  = "0.0.0.0/0"
  security_group_id = openstack_networking_secgroup_v2.cache.id
}

resource "openstack_networking_port_v2" "cache" {
  name               = "${var.app_name}-port"
  network_id         = openstack_networking_network_v2.private.id
  security_group_ids = [openstack_networking_secgroup_v2.cache.id]

  fixed_ip {
    subnet_id = openstack_networking_subnet_v2.private.id
  }

  depends_on = [openstack_networking_router_interface_v2.private]
}

resource "openstack_blockstorage_volume_v3" "data" {
  name = "${var.app_name}-data"
  size = var.volume_size
}

resource "openstack_compute_instance_v2" "cache" {
  name        = var.app_name
  flavor_name = var.flavor_name
  key_pair    = var.key_name

  user_data = var.domain != "" ? templatefile("${path.module}/cloud-init/cache-https.yaml.tftpl", {
    caddy_site     = local.caddy_site
    caddy_version  = var.caddy_version
    varnish_version = var.varnish_version
    upstream_host  = var.upstream_host
    upstream_port  = var.upstream_port
    cache_size     = var.cache_size
  }) : templatefile("${path.module}/cloud-init/cache-http.yaml.tftpl", {
    varnish_version = var.varnish_version
    upstream_host   = var.upstream_host
    upstream_port   = var.upstream_port
    cache_size      = var.cache_size
  })

  block_device {
    uuid                  = data.openstack_images_image_v2.os.id
    source_type           = "image"
    destination_type      = "volume"
    volume_size           = 20
    boot_index            = 0
    delete_on_termination = true
  }

  network {
    port = openstack_networking_port_v2.cache.id
  }
}

resource "openstack_compute_volume_attach_v2" "data" {
  instance_id = openstack_compute_instance_v2.cache.id
  volume_id   = openstack_blockstorage_volume_v3.data.id
}

resource "openstack_networking_floatingip_v2" "cache" {
  pool = var.external_network
}

resource "openstack_networking_floatingip_associate_v2" "cache" {
  floating_ip = openstack_networking_floatingip_v2.cache.address
  port_id     = openstack_networking_port_v2.cache.id
}
variables.tfHCL
variable "key_name" {
  description = "SSH keypair name (must already exist in your project)"
  type        = string
}

variable "flavor_name" {
  description = "Instance size. Varnish is memory-bound: 2 vCPU and 2 GiB RAM handle a modest cacheable origin. Raise the flavor when you increase cache_size or serve high request rates."
  type        = string
  default     = "s1a.small"
}

variable "image_name" {
  description = "Operating system image. cloud-init targets a Debian-family distribution; Ubuntu 24.04 is the recommended base."
  type        = string
  default     = "Ubuntu-24.04"
}

variable "app_name" {
  description = "Display name prefix for compute and network resources"
  type        = string
  default     = "edge-cache"
}

variable "varnish_version" {
  description = "Varnish container image tag. The default 7.6 tracks the current Varnish Cache 7 release; pin a specific tag for reproducible rebuilds."
  type        = string
  default     = "7.6"
}

variable "caddy_version" {
  description = "Caddy container image tag used for automatic HTTPS when domain is set. Ignored when domain is empty."
  type        = string
  default     = "2-alpine"
}

variable "domain" {
  description = "Public domain for the cache front door. When set, Caddy obtains a Let's Encrypt certificate and terminates TLS before Varnish. Point the domain's DNS A record at the floating IP before traffic arrives. Leave empty to serve plain HTTP on port 80 at the floating IP."
  type        = string
  default     = ""
}

variable "upstream_host" {
  description = "Private IP address of the origin instance Varnish fetches from on cache miss. The origin stays on the private subnet with no floating IP; lock its security group to accept traffic only from this cache instance's private IP."
  type        = string
  default     = "10.42.0.10"
}

variable "upstream_port" {
  description = "TCP port the origin listens on within the private network"
  type        = number
  default     = 8080
}

variable "cache_size" {
  description = "Varnish cache storage size in GiB on the data volume. The value maps to the file-backed cache at /data/varnish/cache."
  type        = number
  default     = 2
}

variable "volume_size" {
  description = "Block volume size in GiB for Varnish cache files and TLS state. Must be at least cache_size plus headroom for Caddy certificates when domain is set."
  type        = number
  default     = 10
}

variable "external_network" {
  description = "Shared external network for router gateway and floating IPs; defaults to PublicStatic (persisted FIP / production pattern). Override with PublicEphemeral for ephemeral demos."
  type        = string
  default     = "PublicStatic"
}

variable "private_cidr" {
  description = "CIDR for the private tenant network the cache lives in"
  type        = string
  default     = "10.42.0.0/24"
}
outputs.tfHCL
output "instance_id" {
  description = "ID of the compute instance running the edge cache"
  value       = openstack_compute_instance_v2.cache.id
}

output "floating_ip" {
  description = "Public floating IP address of the edge cache"
  value       = openstack_networking_floatingip_v2.cache.address
}

output "private_ip" {
  description = "Private IP address of the cache on the tenant network"
  value       = openstack_compute_instance_v2.cache.access_ip_v4
}

output "cache_url" {
  description = "URL for the cache front door. HTTPS on the domain when set, otherwise HTTP on the floating IP. Point DNS at the floating IP before relying on automatic TLS."
  value       = var.domain != "" ? "https://${var.domain}" : "http://${openstack_networking_floatingip_v2.cache.address}"
}
versions.tfHCL
terraform {
  required_version = ">= 1.6.0"

  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "~> 2.0"
    }
  }
}

provider "openstack" {}
terraform.tfvars.exampleHCL
# Required: SSH keypair must already exist in your project
key_name = "YOUR_KEY_NAME"

# Origin on the private subnet (no floating IP). Lock its security group to the
# cache private IP after apply.
# upstream_host = "10.42.0.10"
# upstream_port = 8080

# Recommended: set a domain so Caddy obtains a Let's Encrypt certificate in front
# of Varnish. Point its DNS A record at the floating IP from the outputs.
# domain = "cache.example.com"

# cache_size = 2
# varnish_version = "7.6"
# caddy_version = "2-alpine"
# flavor_name = "s1a.small"
# image_name = "Ubuntu-24.04"
# app_name = "edge-cache"
# volume_size = 10
# external_network = "PublicStatic"
# private_cidr = "10.42.0.0/24"
cloud-init/cache-http.yaml.tftpl
#cloud-config
package_update: true
packages:
  - ca-certificates
  - curl
write_files:
  - path: /opt/edge-cache/default.vcl
    permissions: "0644"
    content: |
      vcl 4.1;

      backend origin {
          .host = "${upstream_host}";
          .port = "${upstream_port}";
      }

      acl purge {
          "localhost";
          "127.0.0.1";
          "::1";
      }

      sub vcl_recv {
          if (req.method == "PURGE") {
              if (!client.ip ~ purge) {
                  return (synth(405, "PURGE not allowed from this address"));
              }
              return (purge);
          }
          if (req.method != "GET" && req.method != "HEAD") {
              return (pass);
          }
      }

      sub vcl_backend_response {
          if (beresp.http.Cache-Control ~ "(private|no-cache|no-store)") {
              set beresp.ttl = 0s;
              set beresp.uncacheable = true;
              return (deliver);
          }
          if (beresp.http.Cache-Control ~ "max-age=([0-9]+)") {
              set beresp.ttl = std.duration(regsub(beresp.http.Cache-Control, ".*max-age=([0-9]+).*", "\\1") + "s", 3600s);
              return (deliver);
          }
          if (beresp.http.Expires || beresp.http.Last-Modified || beresp.http.ETag) {
              set beresp.ttl = 3600s;
              return (deliver);
          }
          set beresp.ttl = 0s;
          set beresp.uncacheable = true;
      }
  - path: /opt/edge-cache/docker-compose.yml
    permissions: "0644"
    content: |
      services:
        varnish:
          image: varnish:${varnish_version}
          restart: unless-stopped
          ports:
            - "80:80"
          volumes:
            - /opt/edge-cache/default.vcl:/etc/varnish/default.vcl:ro
            - /data/varnish:/var/lib/varnish
          command:
            - varnishd
            - -F
            - -f
            - /etc/varnish/default.vcl
            - -a
            - :80
            - -s
            - file,/var/lib/varnish/cache,${cache_size}G
runcmd:
  - |
    set -e
    DEV=/dev/sdb
    for i in $(seq 1 30); do [ -b "$DEV" ] && break; sleep 5; done
    if ! blkid "$DEV" >/dev/null 2>&1; then mkfs.ext4 -F -L cachedata "$DEV"; fi
    mkdir -p /data/varnish /data/caddy /data/caddy-config
    mount "$DEV" /data
    grep -q "$DEV" /etc/fstab || echo "$DEV /data ext4 defaults,nofail 0 2" >> /etc/fstab
    curl -fsSL https://get.docker.com | sh
    cd /opt/edge-cache
    docker compose up -d
cloud-init/cache-https.yaml.tftpl
#cloud-config
package_update: true
packages:
  - ca-certificates
  - curl
write_files:
  - path: /opt/edge-cache/default.vcl
    permissions: "0644"
    content: |
      vcl 4.1;

      backend origin {
          .host = "${upstream_host}";
          .port = "${upstream_port}";
      }

      acl purge {
          "localhost";
          "127.0.0.1";
          "::1";
      }

      sub vcl_recv {
          if (req.method == "PURGE") {
              if (!client.ip ~ purge) {
                  return (synth(405, "PURGE not allowed from this address"));
              }
              return (purge);
          }
          if (req.method != "GET" && req.method != "HEAD") {
              return (pass);
          }
      }

      sub vcl_backend_response {
          if (beresp.http.Cache-Control ~ "(private|no-cache|no-store)") {
              set beresp.ttl = 0s;
              set beresp.uncacheable = true;
              return (deliver);
          }
          if (beresp.http.Cache-Control ~ "max-age=([0-9]+)") {
              set beresp.ttl = std.duration(regsub(beresp.http.Cache-Control, ".*max-age=([0-9]+).*", "\\1") + "s", 3600s);
              return (deliver);
          }
          if (beresp.http.Expires || beresp.http.Last-Modified || beresp.http.ETag) {
              set beresp.ttl = 3600s;
              return (deliver);
          }
          set beresp.ttl = 0s;
          set beresp.uncacheable = true;
      }
  - path: /opt/edge-cache/Caddyfile
    permissions: "0644"
    content: |
      ${caddy_site} {
          reverse_proxy varnish:6081
      }
  - path: /opt/edge-cache/docker-compose.yml
    permissions: "0644"
    content: |
      services:
        varnish:
          image: varnish:${varnish_version}
          restart: unless-stopped
          expose:
            - "6081"
          volumes:
            - /opt/edge-cache/default.vcl:/etc/varnish/default.vcl:ro
            - /data/varnish:/var/lib/varnish
          command:
            - varnishd
            - -F
            - -f
            - /etc/varnish/default.vcl
            - -a
            - :6081
            - -s
            - file,/var/lib/varnish/cache,${cache_size}G
        caddy:
          image: caddy:${caddy_version}
          restart: unless-stopped
          ports:
            - "80:80"
            - "443:443"
          volumes:
            - /opt/edge-cache/Caddyfile:/etc/caddy/Caddyfile:ro
            - /data/caddy:/data
            - /data/caddy-config:/config
          depends_on:
            - varnish
runcmd:
  - |
    set -e
    DEV=/dev/sdb
    for i in $(seq 1 30); do [ -b "$DEV" ] && break; sleep 5; done
    if ! blkid "$DEV" >/dev/null 2>&1; then mkfs.ext4 -F -L cachedata "$DEV"; fi
    mkdir -p /data/varnish /data/caddy /data/caddy-config
    mount "$DEV" /data
    grep -q "$DEV" /etc/fstab || echo "$DEV /data ext4 defaults,nofail 0 2" >> /etc/fstab
    curl -fsSL https://get.docker.com | sh
    cd /opt/edge-cache
    docker compose up -d
README.mdMarkdown
# Edge cache

Single compute instance running [Varnish Cache](https://varnish-cache.org), an open-source HTTP accelerator, on infrastructure you control. Varnish sits on a floating IP in front of a private origin and stores cacheable responses on a block volume you operate.


**Network class:** production — `external_network` defaults to `PublicStatic` for persisted floating IPs and multi-tier stacks; override with `PublicEphemeral` for ephemeral demos.

The instance provisions a private network, a floating IP, and a block volume mounted at `/data` so cache files and TLS state live on a resizable volume rather than the boot disk. cloud-init installs Docker, writes a VCL file that honors `Cache-Control` from the origin, and starts Varnish on first boot. When `domain` is set, Caddy terminates TLS in front of Varnish.

## Slug decision

This template earns its own slug (`edge-cache`) 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.

## Where this fits

This is the regional cache half of a CDN: it absorbs origin load for cacheable GET and HEAD responses within one Quake AI region. It does not replace a global PoP network. For geographic distribution and volumetric DDoS absorption, [front the origin with a third-party CDN](/docs/network/how-to/front-with-cdn).

## Prerequisites

- OpenTofu >= 1.6.0 or Terraform >= 1.6.0
- Quake AI account with OpenStack credentials
- An existing SSH keypair in your project (the value of `key_name` must match that keypair)
- An origin instance on the private network that sends appropriate `Cache-Control` headers

## Resource baseline

Varnish is memory- and disk-bound. The default `s1a.small` flavor (2 shared vCPU, 2 GiB RAM) handles a modest cacheable origin. The boot disk is 20 GiB; cache files live on the separate data volume (`volume_size`, default 10 GiB). Set `cache_size` (default 2 GiB) to the Varnish file store size on that volume.

## Usage

1. Clone or copy this template directory
2. Copy `terraform.tfvars.example` to `terraform.tfvars` and set `key_name`, `upstream_host`, and `upstream_port` (and `domain` if you have one)
3. Source your OpenStack credentials: `source openrc.sh`
4. Initialize: `tofu init`
5. Preview: `tofu plan`
6. Apply: `tofu apply`

cloud-init takes a few minutes on first boot to install Docker, mount the data volume, and start Varnish. The cache then answers on `cache_url` from the outputs.

## 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 (SSH in and run `curl -X PURGE http://127.0.0.1/path`). Remote purge is blocked by the VCL ACL; extend the ACL in the VCL file if your workflow needs purge from a trusted admin host.

## Domain and TLS

With `domain` set and its DNS A record pointed at `floating_ip`, Caddy obtains a Let's Encrypt certificate automatically and proxies HTTPS traffic to Varnish on port 6081. With `domain` empty, Varnish serves plain HTTP on port 80 at the floating IP.

## Alternate engines

[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](/resources/iac-templates/edge-reverse-proxy) template and want a lighter cache layer without a dedicated Varnish VM. Varnish leads here because it exposes explicit purge and TTL policy in VCL.

## Outputs

| Output | Description |
| --- | --- |
| `floating_ip` | Public floating IP of the cache |
| `private_ip` | Private IP of the cache on the tenant network |
| `cache_url` | HTTPS on the domain when set, otherwise HTTP on the floating IP |
| `instance_id` | Compute instance ID |

## Validation

This template passes `tofu validate` in CI. That check confirms the OpenTofu configuration is well-formed against the provider schema; it does not run `tofu apply` against a live account.

Recorded command:

```bash
cd iac/templates/edge-cache && tofu init -backend=false && tofu validate
```
Resources, parameters, and variables
Provisions
Parameterized by
Variables
  • key_namerequired
  • flavor_name="s1a.small"
  • image_name="Ubuntu-24.04"
  • app_name="edge-cache"
  • varnish_version="7.6"
  • caddy_version="2-alpine"
  • domain=""
  • upstream_host="10.42.0.10"
  • upstream_port=8080
  • cache_size=2
  • volume_size=10
  • external_network="PublicStatic"
  • private_cidr="10.42.0.0/24"

Customize this pattern#

See also#

Usage Guidelines

The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.

For the full policy, see Usage Guidelines.

Last validated: 07.07.2026

Was this page helpful?