Released: 2026-10-22
Varnish version: 6.0.18r6
Artifact Firewall version: 0.8.0
varnish.vcls loads your own VCL programs next to the generated ones. Each has a name, the path of its main VCL file, optional include_paths, and routes that match a host glob, a path glob, or both. The root VCL checks these routes in the order listed, before it routes to a registry, so a VCL can take a path on a registry’s host, and default: true sends a VCL the requests that match nothing else. The .vcl files under the main file’s directory and under each include path are loaded with it, so it can include them by relative path or by name, and it can also include the VCL shipped with Varnish, such as devicedetect.vcl. Edits to those files take effect on the next reload, by SIGHUP or a change to the config files. A file included by absolute path is read in place, so a reload misses an edit to it. Each VCL is loaded under the label label_<name>, so extra_root_vcl can route to it on anything else in the request. It requires the VCL editing feature, and without it the configuration is refused.routes accept ecosystems, a list of package ecosystems (for example [npm, oci]). On its own, an ecosystems route sends those requests to the registry when the Host header matches no registry’s name or glob, before falling back to the default registry. Together with glob in the same route, both must match, and such a route is checked after registry names but before routes with only a glob. The ecosystem is classified the way the registry itself classifies a request, by Accept, User-Agent and then URL, so a client that identifies itself by neither header is routed only when its URL is distinctive. An ecosystem, or an ecosystem with a given glob, can be routed to only one registry.virtual_registry.extra_root_vcl includes your own VCL files at the top of the root VCL, which receives every request before it is routed to a registry. Their subroutines run before the built-in ones, in the order listed, so they can answer or rewrite a request for every registry at once. Like a registry’s extra_vcl, it requires the VCL editing feature, and without it the files are ignored.firewall.remote_address and firewall.remote_api_address send the registries that set enable_firewall to an Artifact Firewall running outside the Supervisor, instead of starting the embedded one. Set them together, as host:port, to the firewall’s proxy address and its api_address. They cannot be combined with firewall.address. The remote firewall must run with deployment: integrated. To have its ruleset reloads purge cached manifests, point its webhook at the Supervisor’s /purgez with method PURGE and header Cache-Tags: resource_manifest, and add its address to virtual_registry.purge.allow.remote_auth.password_file takes the password from a file instead of an environment variable. Varnish reads the file on each injected request, so a password that is rotated on disk, such as an Amazon ECR token that a Kubernetes Secret refreshes, takes effect without a reload. The Varnish worker process must be able to read the file.remote_auth without a username, password_env or password_file injects an Amazon ECR authorization token on a registry whose remote is an <account>.dkr.ecr.<region>.amazonaws.com host, so a private ECR remote no longer needs a token rotated in by hand. The Supervisor requests the token in that region with its own AWS credentials (environment, web identity, or instance or task role), which need ecr:GetAuthorizationToken, and renews it at half its 12-hour lifetime./api/), file downloads (/resolve/) and the Xet protocol that large model and dataset files transfer over, both against huggingface.co directly and through a JFrog Artifactory HuggingFaceML repository, with Artifactory’s Xet setting on or off. Through Artifactory, a client sets HF_ENDPOINT to Orca with the repository’s /artifactory/api/huggingfaceml/<repo> path./readyz answers 503 once the Supervisor starts shutting down, so a load balancer stops sending new traffic while Varnish drains during shutdown_delay. /healthz keeps answering 200 until Varnish exits. Varnish defaults shutdown_delay to 0 and exits at once, so set varnish.params.shutdown_delay to at least the load balancer’s probe interval times its failure threshold. Keep shutdown_delay plus 15 seconds under the unit’s TimeoutStopSec, which is 90 seconds unless the unit sets it.docker pull failing with 503 Backend fetch failed when the client connects over HTTPS and the remote url is plain http://. A remote that builds links to itself from the client’s X-Forwarded-Proto, such as a self-hosted Artifactory, advertised its token realm as https:// on its plain HTTP port, and Varnish fetched the token from there with TLS. A link to the host and port of a configured remote is now fetched with the scheme of that remote’s url.remote_auth credential, or under its auth_policy: ignore with a client’s own credential, being served from the cache through another virtual registry, which may have no access to it. Content-addressed objects in a virtual registry with remote_auth or auth_policy: ignore are now cached per virtual registry, so each is fetched from the remote once more after the upgrade. They are still keyed without the credential, so rotating password_env keeps them. With the sup-auth addon, content-addressed objects fetched anonymously are fetched once more too, so that a persistent store stops serving the ones that an earlier version cached through such a virtual registry.remote_auth on an OCI registry without a token endpoint, such as Amazon ECR or registry:2 with htpasswd. Such a registry asks for Basic auth on /v2/ itself, but the credential was attached only to the token request, so a pull failed with no basic auth credentials. It now goes on every OCI request that carries no bearer token. A Docker client sends its own login only after a challenge, so under if_anonymous a registry that accepts Basic auth on /v2/ no longer challenges it, and the client pulls as the configured account.unknown blob after a layer was deleted from the remote. The OCI blob HEAD existence check was cached for good, so the client skipped uploading a layer the registry no longer held. It is now cached as a manifest, so it is revalidated against the remote on every request, or cached for manifest_ttl when that is set. Like a manifest, it self-routes in a cluster only when manifest_ttl is at least 1s.GET on an upload session was cached as if it were a blob, so a client resuming an interrupted push read the offset from the first answer rather than the remote’s current one. Upload sessions now always go to the remote.