Virtual Registry

Configuration for the Virtual Registry. A registry should have a name and must have a remote, all other parameters are optional.

Example:

virtual_registry:
  registries:
   - name: example
     remotes:
     - url: https://example.com

registries

Type: List

List of virtual registries.

name

virtual_registry:
  registries:
  - name: example

Type: String

Default: default

The registry name should be short, unique, and recognizable. It is used for subdomain routing, and metrics are segmented on registry name. A registry answers requests whose Host is its name, or starts with its name followed by . or :, so example answers example.registry.example.com but not registry.example.com.

default

virtual_registry:
  registries:
  - name: example
    default: true

Type: Boolean

Default: false

If set to true, all requests that don’t match any other registry subdomain will be handled by this registry. Only one registry, or one of the VCLs in varnish.vcls, can be the default.

No registry is the default unless it sets default: true, even when it is the only one. A request whose host matches no registry name or routes entry, and finds no default registry, gets a 404. Set default: true on a lone registry to have it answer whatever host clients use to reach it. The Supervisor logs a warning when the only registry has neither default: true nor any routes.

load_balancer

virtual_registry:
  registries:
  - name: example
    load_balancer: random

Type: String

Default: fallback

The load balancing policy to use when there are multiple remotes.

  • fallback: Use remotes in order of appearance. The first remote is selected first, then retries go down through the list.
  • random: Balance traffic to remotes evenly. A random remote is selected from the list and retries never pick the same backend twice for a given fetch.
  • hash: Pick the same remote for the same cache key. A consistent hashing algorithm is used to select a remote and retries pick new remotes in a consistent order.

retry_statuses

virtual_registry:
  registries:
  - name: example
    retry_statuses: [404, 429]

Type: List of Integers

Default: [404, 429]

Response statuses from a remote that make Orca retry the fetch against a remote it has not tried yet, so an artifact only one of several remotes holds is still served, and a remote that throttles a request is spent on one that does not. The client gets the response of the last remote asked.

Only applies to registries with more than one remote. These retries spend the same budget as the global varnish.params.max_retries, so raise that parameter for a registry with more remotes than it allows.

Valid values are 400-499, except 401 and 407, whose challenges have to reach the client instead of being retried. 5xx and 408 responses and failed connections are always retried regardless of this setting. Set to [] to keep the first remote’s response instead of retrying.

auth_ttl

Note: Orca Premium feature

virtual_registry:
  registries:
  - name: example
    auth_ttl: 3600

Type: Number

Default: 3600

The number of seconds to cache each users authorization per artifact. Setting this to 0 causes the users authorization to be checked against the remote registry on every request.

auth_policy

Note: Orca Premium feature

virtual_registry:
  registries:
  - name: example
    auth_policy: ignore

Type: String

Default: preflight

Authorization handling policy for the caller’s own credential:

  • preflight: Verify every request via a HEAD check before serving it, and share the cache only between requests that pass the same check. This is the existing default behavior.
  • ignore: Skip the preflight check and share cache with anonymous requests to this registry, while still forwarding Authorization unchanged to the backend. Useful for backends that already permit anonymous access, to avoid the extra round-trip.
  • drop: Strip Authorization before it ever reaches the backend.

Independent of remote_auth’s policy, which governs whether a separately configured shared credential gets injected. Not valid combined with drop, since Authorization is stripped before remote_auth.policy could apply.

auth_token_ttl

Note: Orca Premium feature

virtual_registry:
  registries:
  - name: example
    auth_token_ttl: 60

Type: Number

Default: 60

TTL in seconds for cached OCI auth tokens. Orca caches the token per credential and scope for this window and hands the same bearer token back, keeping the downstream authorization cache key stable so already-cached images keep serving while the upstream registry or its token endpoint is unreachable (the cached token and preflight are revived for up to 1 week in that case).

Set to 0 to disable and pass token requests straight through. Only meaningful when the Authentication feature is licensed.

default_ttl

virtual_registry:
  registries:
  - name: example
    default_ttl: 3600

Type: Number

Default: 120

The number of seconds to cache objects that are not otherwise covered by a specific cache policy or considered uncacheable.

Overrides the global varnish.params.default_ttl for this registry.

default_grace

virtual_registry:
  registries:
  - name: example
    default_grace: 3600

Type: Number

Default: 10

The number of seconds to grace objects that are not otherwise covered by a specific cache policy or considered uncacheable.

Overrides the global varnish.params.default_grace for this registry.

default_keep

virtual_registry:
  registries:
  - name: example
    default_keep: 3600

Type: Number

Default: 0

The number of seconds to keep stale objects that are not otherwise covered by a specific cache policy or considered uncacheable.

Overrides the global varnish.params.default_keep for this registry.

manifest_ttl

virtual_registry:
  registries:
  - name: example
    manifest_ttl: 60

Type: Number

TTL in seconds for manifest artifacts (such as an npm packument or a PyPI simple index). By default, mutable manifests are revalidated with the remote on every request; setting manifest_ttl caches them for a fixed window instead. Digest-pinned (immutable) manifests are unaffected.

package_ttl

virtual_registry:
  registries:
  - name: example
    package_ttl: 86400

Type: Number

TTL in seconds for package artifacts. Caps the built-in immutable lifetime of package downloads. Mutable packages that must revalidate are unaffected.

other_ttl

virtual_registry:
  registries:
  - name: example
    other_ttl: 300

Type: Number

TTL in seconds for artifacts that are not classified as a manifest or a package.

max_ttl

virtual_registry:
  registries:
  - name: example
    max_ttl: 604800

Type: Number

Maximum TTL in seconds for anything this registry caches, including the packages and version-pinned manifests that are otherwise cached for a hundred years. A longer TTL is lowered to max_ttl and the difference is added to the object’s keep, so once it expires the object is revalidated with a conditional request rather than downloaded again. Must be positive.

Content-addressed objects, which are named by a digest of their content (an OCI blob or digest-pinned manifest, a PyPI file or Cargo crate carrying a vs-sha256- segment, a Debian by-hash index), are exempt, since their content cannot change under the same name.

Within the registry’s default_grace after it expires, an object is still served while it is revalidated in the background, so set default_grace: 0 where the first request past max_ttl must already get the replacement.

Objects cached before max_ttl was set keep the TTL they were cached with. To apply it to them, purge the registry once with Cache-Tags: registry_<name>.

extra_vcl

Type: List

Note: Orca Premium feature

virtual_registry:
  registries:
  - name: example
    extra_vcl:
    - /etc/varnish-supervisor/example.vcl

Extra VCL to prepend to the configuration generated by the Virtual Registry. Extra VCLs are included in the order they appear in this list.

base_url

virtual_registry:
  registries:
  - name: example
    base_url: https://my-registry.example.com

Type: String

Base URL of the virtual registry. This is used when the registry needs to generate URLs that point back to itself (e.g., in manifests or redirect responses).

base_url can be set to http:// or https:// without a domain to determine the scheme used for the redirect. This can be useful when the Virtual Registry is placed behind a TLS terminating proxy, especially when preserve_subdomain is enabled for the Virtual Registry remote.

Overrides the global virtual_registry.base_url for this registry.

disable_cache

virtual_registry:
  registries:
  - name: example
    disable_cache: true

Type: Boolean

Default: false

Disable artifact caching for this registry. When enabled, requests are still proxied to the registry’s remotes, but responses are not cached and every request is fetched fresh from the remote. Caching is enabled by default.

readonly

virtual_registry:
  registries:
  - name: example
    readonly: true

Type: Boolean

Default: false

Whether this registry should be treated as read-only. When enabled, write operations (push, delete) are rejected.

enable_firewall

Note: Orca Premium feature

virtual_registry:
  registries:
  - name: example
    enable_firewall: true

Type: Boolean

Default: false

Enable the Artifact Firewall for this registry. When enabled, requests are evaluated against the configured firewall rules. Requires a top-level firewall configuration, and a license carrying the sup-firewall and sup-auth addons.

enable_cluster

Note: Orca Premium feature

virtual_registry:
  registries:
  - name: example
    enable_cluster: true

Type: Boolean

Default: false

Enable clustering for this registry. When enabled, cluster-wide request coalescing is enabled for package requests to this Virtual Registry. Requires a top-level cluster configuration, and a license carrying the sup-clustering and sup-auth addons.

Only package requests are coalesced between cluster nodes, manifest and preflight auth requests go directly to the remote.

preserve_manifest

virtual_registry:
  registries:
  - name: example
    preserve_manifest: true

Type: Boolean

Default: false

Preserve original manifests from the remote without inserting the base URL. When disabled, the registry rewrites manifest URLs to point through the virtual registry.

fast_304

virtual_registry:
  registries:
  - name: example
    fast_304: false

Type: Boolean

Default: true

When a remote answers a revalidation with 304 Not Modified, refresh the cached object in place instead of copying its body into a new object. This is what makes revalidating a large artifact cheap.

Refreshing in place keeps the headers the object already had and discards the ones the 304 carried. Set to false only for a remote whose 304 responses carry an updated Cache-Control or Vary that has to take effect.

cache_req_body_limit

virtual_registry:
  registries:
  - name: example
    cache_req_body_limit: 10MB

Type: String

Default: 10MB

Maximum request body size to buffer for cacheable POST requests (e.g. git-upload-pack). The value is a byte size such as 512KB, 10MB, or 1GB.

remote_auth

Note: Orca Premium feature

virtual_registry:
  registries:
  - name: example
    auth_policy: ignore
    remote_auth:
      username: my-account
      password_env: REMOTE_AUTH_PASSWORD
      policy: if_anonymous

Type: Object

A shared credential that Orca can attach to outbound requests to the remote on the client’s behalf.

For an OCI (Docker/container) registry it targets the /token auth-token exchange, so that pulls through this registry count against the configured account’s rate limit instead of the upstream’s shared anonymous quota (for example, Docker Hub’s per-IP anonymous limit). It also goes on every other OCI request that carries no bearer token, for a registry without a token endpoint, such as Amazon ECR or registry:2 with htpasswd, which asks for Basic auth on /v2/ itself. A Docker client sends its own login only after a challenge, so under if_anonymous such a registry no longer challenges the client, which then pulls as the configured account. For every other package type it is attached to the content request itself.

Inactive until policy is set below. Not scope-aware: the credential is presented on every request it applies to, including one that turns out to carry a write scope, so give it read-only permissions upstream. Requires the Authentication feature to be licensed. Not valid combined with auth_policy: drop, since Authorization would already be stripped before this policy could apply.

A request the credential was injected into gets a cache entry of its own rather than a preflight, because what reaches the remote is not the caller’s own credential. That entry is shared by every caller the credential is injected for, and it is keyed without the credential, so rotating the password leaves the cached objects in place instead of invalidating them.

policy: always therefore skips the check that auth_policy: preflight would otherwise make, since no caller’s credential is left to verify. The Supervisor warns about the combination at startup. if_anonymous is unaffected, as it only fills in where the caller sent nothing of its own.

When the remote’s token endpoint lives on a different host than the registry (as with Docker Hub’s auth.docker.io), Orca adds that host to the allowed upstream hosts automatically, so there is no need to list it in redirects.extra_known_hosts as well.

On a registry whose remote is an Amazon ECR host, <account>.dkr.ecr.<region>.amazonaws.com, a remote_auth without username, password_env or password_file injects an ECR authorization token instead:

virtual_registry:
  registries:
  - name: ecr
    remotes:
    - url: https://123456789012.dkr.ecr.eu-west-1.amazonaws.com
    remote_auth:
      policy: if_anonymous

The Supervisor requests the token in that region with its own AWS credentials, which need ecr:GetAuthorizationToken and come from the environment, a web identity, or an instance or task role. It renews the token at half its 12-hour lifetime, and retries a failed request every minute. A token is valid in one region only, so a registry with remotes in two ECR regions is refused.

username

# (...)
    remote_auth:
      username: my-account

Type: String

Username to authenticate with, at the OCI token exchange or on the content request itself depending on the package type. Required, together with password_env or password_file, except for the Amazon ECR token above.

password_env

# (...)
    remote_auth:
      password_env: REMOTE_AUTH_PASSWORD

Type: String

Name of the environment variable holding the password paired with username. Read at request time, so the password itself never appears in the config file. Set this or password_file.

password_file

# (...)
    remote_auth:
      password_file: /run/secrets/remote-auth-password

Type: String

Absolute path of a file holding the password paired with username. Set this or password_env.

Varnish reads the file on each injected request, so a password rotated on disk, such as a token that a Kubernetes Secret refreshes, takes effect without a reload. Trailing whitespace, such as the newline that echo writes, is dropped, and a missing or empty file sends the request on without the credential. The Varnish worker process has to be able to read the file, which means the vcache user when the Supervisor runs as root, or each injected request fails. The path cannot contain *, ?, [ or \.

policy

# (...)
    remote_auth:
      policy: if_anonymous

Type: String

Default: disabled

When to inject the configured credential:

  • disabled: Never inject. remote_auth has no effect.
  • if_anonymous: Inject only when the caller sent no credential of its own, leaving an existing one untouched.
  • always: Inject unconditionally, replacing whatever credential the caller sent. Skips the preflight check under auth_policy: preflight.

Not valid together with auth_policy: drop.

routes

virtual_registry:
  registries:
  - name: example
    routes:
    - glob: "*.example.com"
    - ecosystems: [npm, pypi]

Type: List

Additional routes to associate with this registry, which match a request on its Host header, its package ecosystem, or both. A request goes to the first registry that it matches, checked in this order:

  1. A registry whose name the Host header names.
  2. A route with both glob and ecosystems.
  3. A route with glob only.
  4. A route with ecosystems only.
  5. The default registry.

The routes of the VCLs in varnish.vcls are checked before all of these.

glob

virtual_registry:
  registries:
  - name: example
    routes:
    - glob: "*.example.com"

Type: String

Glob pattern to match against the Host header for routing requests to this registry. Together with ecosystems in the same route, the request has to match both.

ecosystems

virtual_registry:
  registries:
  - name: example
    routes:
    - ecosystems: [npm, oci]

Type: List of Strings

Package ecosystems to route to this registry. Valid values are the package types other than web and other.

A request is classified the way the registry itself classifies it, 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, and a configuration that routes it to two is refused.

remotes

virtual_registry:
  registries:
   - name: example
     remotes:
     - url: https://example.com

Type: List

List of remotes. See remotes configuration.

base_url

virtual_registry:
  base_url: https://my-registry.example.com

Type: String

Default base URL applied to every registry that does not set its own base_url. This is convenient when multiple registries share the same public hostname. A per-registry base_url takes precedence over this value. See the per-registry base_url for how the base URL is used, including scheme-only values.

redirects

virtual_registry:
  redirects:
    enabled: true
    signing:
      enabled: true
      key_env: REDIRECT_SIGNING_KEY

Configuration for the /redirectz endpoint. The Virtual Registry rewrites certain upstream URLs (for example Git LFS objects, Composer dist archives, and signed-blob redirects) so that they route back through itself via /redirectz, where the content can be cached.

enabled

virtual_registry:
  redirects:
    enabled: false

Type: Boolean

Default: true

Enable the /redirectz endpoint. When set to false, the endpoint is closed entirely and clients requesting it receive a 404 response.

signing

virtual_registry:
  redirects:
    signing:
      enabled: true
      key_env: REDIRECT_SIGNING_KEY

HMAC signing of /redirectz URLs. When enabled, the Virtual Registry appends a ;sig=... matrix parameter to the URLs it rewrites, and rejects requests to /redirectz whose signature is missing or invalid. This prevents clients from crafting arbitrary /redirectz URLs.

enabled

virtual_registry:
  redirects:
    signing:
      enabled: true

Type: Boolean

Default: false

Enable HMAC signing of /redirectz URLs.

key_env

virtual_registry:
  redirects:
    signing:
      key_env: REDIRECT_SIGNING_KEY

Type: String

Name of the environment variable that holds the HMAC signing key. Required when signing is enabled.

deny_unknown_hosts

virtual_registry:
  redirects:
    deny_unknown_hosts: true

Type: Boolean

Default: false

Restrict /redirectz upstream hosts and transparent redirect targets to each registry’s configured remotes plus any extra_known_hosts. When enabled, redirects to any other host are refused. When disabled, redirects to arbitrary hosts are followed.

extra_known_hosts

virtual_registry:
  redirects:
    extra_known_hosts:
    - cdn.example.com
    - downloads.example.org

Type: List

Additional hosts to allow /redirectz and transparent redirects to fetch from, beyond each registry’s configured remotes. Has no effect unless deny_unknown_hosts is enabled.

Does not apply to package_reroute, which only ever accepts a registry’s own remotes.

package_reroute

virtual_registry:
  package_reroute:
    enabled: true

Type: Object

The /package-reroute endpoint, a redirect target for a third-party forward proxy that intercepts outbound traffic to the public package registries, such as a Zscaler ZIA rule mirroring JFrog’s Package Traffic Controller.

Distinct from redirects, which covers /redirectz and the Virtual Registry’s own signed rewriting of URLs it handed out. A /package-reroute request carries no signature, since the redirect originates outside.

enabled

virtual_registry:
  package_reroute:
    enabled: true

Type: Boolean

Default: false

Enable the /package-reroute endpoint. The upstream host embedded in the ?url= parameter is resolved against every configured registry’s remotes, and the request re-enters that registry’s pipeline, so it is classified, cached and firewalled like any other.

The host has to be a remote of some registry already, and that allowlist has no override: extra_known_hosts does not extend it. The endpoint applies across every registry, with no per-registry opt-out. While disabled, a request to /package-reroute gets a 404.

purge

virtual_registry:
  purge:
    allow:
    - "10.0.0.0/8"

Type: Object

Configuration for the /purgez endpoint.

allow

virtual_registry:
  purge:
    allow:
    - "192.0.2.10"
    - "10.0.0.0/8"
    - "2001:db8::/32"

Type: List

Client addresses and CIDR ranges allowed to send PURGE /purgez, in addition to 127.0.0.1 and ::1, which are always allowed. IPv4 and IPv6 are both accepted, and an entry that is neither a valid address nor a valid CIDR range fails validation.

Anyone in these ranges can invalidate the cache, so keep them to the hosts that need it, such as a Varnish Broadcaster fanning a purge out to a cluster, or a webhook sender at the origin.

extra_root_vcl

Note: Orca Premium feature

virtual_registry:
  extra_root_vcl:
  - /etc/varnish-supervisor/root.vcl

Type: List

VCL files to include 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. A vcl_recv that returns also skips the built-in one, which answers the service endpoints such as /healthz.

To send a request to one of the VCLs in varnish.vcls on something other than its host and path, use return (vcl(label_<name>));.

Like a registry’s extra_vcl, it requires the sup-vclediting addon, and without it the files are ignored.


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