If you are having network trouble after trying the advice on our network requirements page, you can try some of these suggestions to narrow down where the problem lies.
Basic tests
Depending on where your problem lies you will need to try some different techniques. This section starts with a few fundamental things to check.
Pull an image without authentication
To ensure you can access our registry with
docker pull cgr.dev/chainguard/glibc-dynamic:latest
latest: Pulling from chainguard/glibc-dynamic
21bb9c404e1e: Pull complete
8f719a88a247: Pull complete
cccc0d3c4986: Pull complete
e3962a60631a: Pull complete
6141addca33d: Pull complete
Digest: sha256:4fd32c47d5d83cb2bc5045f6d2a76458fb3a68c148ddc32841e452df5afe0279
Status: Downloaded newer image for cgr.dev/chainguard/glibc-dynamic:latestThe SHAs will change as we release new versions of the image. But this is a very small image you can pull to prove that you can successfully connect to our repository.
It does not need authentication BUT if you have previously run chainctl auth configure-docker then it will try to authenticate. If authentication is your problem you can remove the credential helper from ~/.docker/config.json:
{
"auths": {},
"credHelpers": {
"cgr.dev": "cgr"
}
}If you are using a Mac and you are getting an error like [{"code":"UNAUTHORIZED","message":"Authentication required"}] then you may need to open the Keychain Access app and search for Docker credentials and delete them.
What does this prove?
You can make a TLS connection to cgr.dev and access the relevant endpoints to pull an image.
Authenticate
Next you need to try authenticating.
A basic login:
chainctl auth loginIf this fails we can disable some of the login with a few options (and also see debug output):
chainctl auth login --log-level=debug --sts-http1-downgrade --validate=falseIf your connection is failing at a low level that won't help. The next steps start at lower levels and build up.
TLS certificates
To check you are seeing our certificates:
openssl s_client -connect issuer.enforce.dev:443
Connecting to 34.117.0.114
CONNECTED(00000005)
depth=2 C=US, O=Google Trust Services LLC, CN=GTS Root R1
verify return:1
depth=1 C=US, O=Google Trust Services, CN=WR3
verify return:1
depth=0 CN=*.enforce.dev
verify return:1
---
Certificate chain
0 s:CN=*.enforce.dev
i:C=US, O=Google Trust Services, CN=WR3
a:PKEY: RSA, 2048 (bit); sigalg: sha256WithRSAEncryption
v:NotBefore: Feb 8 18:43:29 2026 GMT; NotAfter: May 9 19:39:24 2026 GMT
1 s:C=US, O=Google Trust Services, CN=WR3
i:C=US, O=Google Trust Services LLC, CN=GTS Root R1
a:PKEY: RSA, 2048 (bit); sigalg: sha256WithRSAEncryption
v:NotBefore: Dec 13 09:00:00 2023 GMT; NotAfter: Feb 20 14:00:00 2029 GMT
2 s:C=US, O=Google Trust Services LLC, CN=GTS Root R1
i:C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
a:PKEY: RSA, 4096 (bit); sigalg: sha256WithRSAEncryption
v:NotBefore: Jun 19 00:00:42 2020 GMT; NotAfter: Jan 28 00:00:42 2028 GMT
....If you see other certificates/authorities then your connection is probably going via a network proxy.
If there are any self-signed certificates, that will cause problems.
What does this prove?
You can connect to the server and exchange certificates to establish an encrypted channel.
HTTP/2
This connection is made with http/2. A check to ensure http/2 is working would look like:
curl --http2 https://issuer.enforce.dev
Not FoundThere is no content at the root location which is why it says "Not Found".
What does this prove?
You established an http/2 connection properly.
GRPC
The login process uses GRPC protocol. This is not straightforward to test with curl/openssl. However, it can be done. If the above tests were successful then the second login command with options will probably be working. If so, you can then get a token:
chainctl auth token --audience console-api.enforce.devYou should get a JWT token back. Assuming you get a token, you can try to simulate the GRPC login process with it. First, you need to create a blob of "null" data which GRPC requires. Then send it with curl:
echo -n '0000000000' | xxd -r -p - frame.bin
curl -X POST https://issuer.enforce.dev/chainguard.platform.auth.Auth/Validate \
-H "Authorization: Bearer $(chainctl auth token --audience console-api.enforce.dev)" \
-H "Content-Type: application/grpc" -H "TE: trailers" -v -H "user-agent: chainctl" \
--http2 --data-binary @frame.bin --raw -H "grpc-accept-encoding: gzip" -o /dev/nullThe result will include all the http headers and so on. But at the end, you should see something like:
} [5 bytes data]
* upload completely sent off: 5 bytes
100 5 0 0 100 5 0 24 --:--:-- --:--:-- --:--:-- 24< HTTP/2 200
< content-type: application/grpc
< trailer: Grpc-Status
< trailer: Grpc-Message
< trailer: Grpc-Status-Details-Bin
< date: Fri, 06 Mar 2026 11:38:02 GMT
< server: Google Frontend
< traceparent: 00-3df30c4027d543ad58a367d828083e2f-9403132e190491c3-00
< x-cloud-trace-context: 3df30c4027d543ad58a367d828083e2f/10665389431252619715
< via: 1.1 google
< alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
<
{ [11790 bytes data]
< grpc-status: 0
{ [0 bytes data]
100 11795 0 11790 100 5 10393 4 0:00:01 0:00:01 --:--:-- 10392
What does this prove?
This command will simulate a GRPC request to validate a recently generated token.
This is the final step of the login process. If this is successful and the output matches, then hopefully everything is working. Maybe you found a new way it can break!
Accessing packages
If you are having trouble downloading packages, this is much easier to debug.
The apk command will first download an index file and then from the index decide which files to download for the package.
docker run -it chainguard/wolfi-base
904ab4e77490:/# apk update
fetch https://apk.cgr.dev/chainguard/aarch64/APKINDEX.tar.gz
[https://apk.cgr.dev/chainguard]
OK: 164595 distinct packages availableThis is a standard http download and you can take the URL to the APKINDEX and download it anywhere. These repositories have no authentication restrictions. (You can use curl or wget to download the file)
wget https://apk.cgr.dev/chainguard/aarch64/APKINDEX.tar.gz
--2026-03-20 15:15:58-- https://apk.cgr.dev/chainguard/aarch64/APKINDEX.tar.gz
Resolving apk.cgr.dev (apk.cgr.dev)... 34.107.162.32
Connecting to apk.cgr.dev (apk.cgr.dev)|34.107.162.32|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 13381027 (13M) [application/gzip]
Saving to: ‘APKINDEX.tar.gz‘
APKINDEX.tar.gz 100%[========================>] 12.76M 13.6MB/s in 0.9s
2026-03-20 15:15:59 (13.6 MB/s) - ‘APKINDEX.tar.gz’ saved [13381027/13381027]
virtualapk
The virtualapk address is the same but the SHAs in the URL allow us to track which images are adding which packages. The first part identifies your customer org, the second part: the image.
You don't need to specify the image.
eg both of these URLs work:
https://virtualapk.cgr.dev/deadbeefc0ffeedeadbeefc0ffeedeadbeefc0ff/chainguard/aarch64/APKINDEX.tar.gz
https://virtualapk.cgr.dev/deadbeefc0ffeedeadbeefc0ffeedeadbeefc0ff/sha256:c0ffee123c0ffee123c0ffee123c0ffee123c0ffee123c0ffee123c0ffee1234/chainguard/aarch64/APKINDEX.tar.gzBut your networking team may consider the virtualapk sub-domain separately from the apk sub-domain.
If you can download the APKINDEX file you should be able to download any other package from the repository.
What next?
If you can complete these tests successfully then your network is setup to let you login and use chainctl and pull images.
If you are failing with one of these tests you probably need to call your own network team.
If you are still having some sort of problem, please raise a ticket, including any of the previous test results you think might be relevant.
Comments
0 comments
Article is closed for comments.