Search
Varnish Helm Chart

Using VCL routes for multi-host deployments

Introduction

server.vcls.routes is a simple way to serve multiple virtual hosts from a single Varnish Enterprise deployment, each with its own VCL. The Helm chart automatically generates a router VCL that dispatches incoming requests to the correct per-host VCL based on the Host header.

This is an alternative to managing VCL labels manually through server.cmdfileConfig. See also Using CLI command file for multi-tenant deployment for the manual approach.

Note: server.vcls.routes cannot be used together with server.vclConfig, server.vclConfigs, server.vclConfigFile, server.cmdfileConfig, or server.agent.enabled.

Configuring routes

Each entry in server.vcls.routes must set vclContent with a complete VCL program and, optionally, a list of hostnames that should be dispatched to it. An optional name field controls the VCL label name; if omitted, the label is derived from the first hostname.

The following example serves two hosts, each pointing at a different backend:

server:
  vcls:
    routes:
      - name: www
        hostnames:
          - www.example.com
        vclContent: |
          vcl 4.1;

          backend default {
            .host = "10.0.0.10";
            .port = "80";
          }

      - name: api
        hostnames:
          - api.example.com
        vclContent: |
          vcl 4.1;

          backend default {
            .host = "10.0.0.20";
            .port = "8080";
          }

          sub vcl_recv {
            return (pass);
          }

Port numbers in the Host header are ignored during matching, so a request for www.example.com:8080 still routes to the www VCL.

Adding a catch-all route

A route without hostnames acts as a catch-all for any request that does not match an earlier route. The catch-all must be the last entry in the list.

A catch-all can be used as a readiness/liveness probe, a redirect, or anything else which might not have a known host-header.

If no catch-all is defined, the chart automatically adds a return(synth(404, "No matching route")) as a fallback.

The following example adds a catch-all that returns OK for a health check, and a 301 redirect for all unknown hostnames:

server:
  readinessProbe:
    httpGet:
      path: "/health"
  livenessProbe:
    httpGet:
      path: "/health"
  vcls:
    routes:
      - name: www
        hostnames:
          - www.example.com
        vclContent: |
          vcl 4.1;

          backend default {
            .host = "10.0.0.10";
            .port = "80";
          }

      - name: api
        hostnames:
          - api.example.com
        vclContent: |
          vcl 4.1;

          backend default {
            .host = "10.0.0.20";
            .port = "8080";
          }

          sub vcl_recv {
            return (pass);
          }

      # No hostnames → catch-all; must be last
      - name: unknown
        vclContent: |
          vcl 4.1;

          backend default none;

          sub vcl_recv {
            if (req.url == "/health") {
              return (synth(200));
            }
            return (synth(301));
          }
          
          sub vcl_synth {
            if (resp.status == 301) {
              set resp.http.location = "https://www.example.com";
            }
          }

Sharing VCL with includes

server.vcls.includes is a map of filename to VCL content. Each entry is mounted as a file under /etc/varnish/vcls/ and can be included by any route VCL, either with the full, absolute path, or a path relative to /etc/varnish.

Subdirectories are supported: a key of backends/shared.vcl is mounted at /etc/varnish/vcls/backends/shared.vcl.

The following example factors out a common backend definition into a shared include:

server:
  vcls:
    includes:
      backends/origin.vcl: |
        backend origin {
          .host = "10.0.0.10";
          .port = "80";
        }

    routes:
      - name: www
        hostnames:
          - www.example.com
        vclContent: |
          vcl 4.1;

          include "vcls/backends/origin.vcl";

          sub vcl_recv {
            return (hash);
          }

          sub vcl_backend_response {
            set beresp.ttl = 60s;
          }

      - name: api
        hostnames:
          - api.example.com
        vclContent: |
          vcl 4.1;

          include "vcls/backends/origin.vcl";

          sub vcl_recv {
            return (pass);
          }

Using routes with clustering

server.vcls.routes works transparently with cluster.enabled. When clustering is enabled, the chart generates a cluster-aware router that joins the cluster and then dispatches to the per-host VCLs. No additional configuration is required.

cluster:
  enabled: true

server:
  replicas: 4
  vcls:
    routes:
      - name: www
        hostnames:
          - www.example.com
        vclContent: |
          vcl 4.1;

          backend default {
            .host = "10.0.0.10";
            .port = "80";
          }

      - name: api
        hostnames:
          - api.example.com
        vclContent: |
          vcl 4.1;

          backend default {
            .host = "10.0.0.20";
            .port = "8080";
          }

          sub vcl_recv {
            return (pass);
          }

®Varnish Software, Wallingatan 12, 111 60 Stockholm, Organization nr. 556805-6203