Problem
When containerd is configured to use a registry mirror, it appends a ?ns=<registry> query parameter to the request URL. For example:
GET /v2/library/nginx/manifests/latest?ns=docker.io
This ns parameter tells the mirror which upstream registry the request is intended for.
Currently, dfdaemon's proxy only reads the X-Dragonfly-Registry header to determine the upstream registry. If that header is missing, it falls back to config.proxy.registry_mirror.addr, which is a single static value.
This creates a significant limitation: it is impossible to use a single containerd _default/hosts.toml catch-all configuration to route all registries through dfdaemon. Instead, each registry (docker.io, ghcr.io, gcr.io, etc.) needs its own hosts.toml file with the X-Dragonfly-Registry header explicitly set. This is cumbersome to maintain and doesn't scale well.
Example of the current workaround
Each registry requires its own hosts.toml:
# /etc/containerd/certs.d/docker.io/hosts.toml
[host."http://127.0.0.1:4001"]
capabilities = ["pull", "resolve"]
[host."http://127.0.0.1:4001".header]
X-Dragonfly-Registry = ["https://index.docker.io"]
# /etc/containerd/certs.d/ghcr.io/hosts.toml
[host."http://127.0.0.1:4001"]
capabilities = ["pull", "resolve"]
[host."http://127.0.0.1:4001".header]
X-Dragonfly-Registry = ["https://ghcr.io"]
Desired behavior
A single _default/hosts.toml should be sufficient:
# /etc/containerd/certs.d/_default/hosts.toml
[host."http://127.0.0.1:4001"]
capabilities = ["pull", "resolve"]
Dfdaemon should automatically infer the upstream registry from the ns query parameter.
Proposed Solution
In dragonfly-client/src/proxy/mod.rs, in the make_registry_mirror_request() function (or the equivalent location where the upstream registry is resolved), add a fallback:
- Check for the
X-Dragonfly-Registry header (existing behavior).
- If the header is missing, extract the
ns query parameter from the request URI.
- Use the
ns value as the upstream registry (prepending https:// if needed).
- Fall back to
config.proxy.registry_mirror.addr only if neither the header nor the ns parameter is present.
Pseudocode
let registry = if let Some(header) = request.headers().get("X-Dragonfly-Registry") {
header.to_str()?.to_string()
} else if let Some(ns) = extract_query_param(request.uri(), "ns") {
format!("https://{}", ns)
} else {
config.proxy.registry_mirror.addr.clone()
};
Why This Matters
- Simpler containerd configuration: One
_default/hosts.toml instead of N per-registry files
- Dynamic registry support: New registries work automatically without config changes
- Alignment with containerd conventions: The
ns parameter is a standard part of containerd's mirror protocol and other registry mirrors already use it
- Backward compatible: The
X-Dragonfly-Registry header still takes priority; this only adds a new fallback
Problem
When containerd is configured to use a registry mirror, it appends a
?ns=<registry>query parameter to the request URL. For example:This
nsparameter tells the mirror which upstream registry the request is intended for.Currently, dfdaemon's proxy only reads the
X-Dragonfly-Registryheader to determine the upstream registry. If that header is missing, it falls back toconfig.proxy.registry_mirror.addr, which is a single static value.This creates a significant limitation: it is impossible to use a single containerd
_default/hosts.tomlcatch-all configuration to route all registries through dfdaemon. Instead, each registry (docker.io, ghcr.io, gcr.io, etc.) needs its ownhosts.tomlfile with theX-Dragonfly-Registryheader explicitly set. This is cumbersome to maintain and doesn't scale well.Example of the current workaround
Each registry requires its own hosts.toml:
Desired behavior
A single
_default/hosts.tomlshould be sufficient:Dfdaemon should automatically infer the upstream registry from the
nsquery parameter.Proposed Solution
In
dragonfly-client/src/proxy/mod.rs, in themake_registry_mirror_request()function (or the equivalent location where the upstream registry is resolved), add a fallback:X-Dragonfly-Registryheader (existing behavior).nsquery parameter from the request URI.nsvalue as the upstream registry (prependinghttps://if needed).config.proxy.registry_mirror.addronly if neither the header nor thensparameter is present.Pseudocode
Why This Matters
_default/hosts.tomlinstead of N per-registry filesnsparameter is a standard part of containerd's mirror protocol and other registry mirrors already use itX-Dragonfly-Registryheader still takes priority; this only adds a new fallback