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.routescannot be used together withserver.vclConfig,server.vclConfigs,server.vclConfigFile,server.cmdfileConfig, orserver.agent.enabled.
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.
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";
}
}
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);
}
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);
}