Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new option ADD_NO_CACHE_HEADER on requests to registry server #265

Merged
merged 1 commit into from
Sep 12, 2022

Conversation

Joxit
Copy link
Owner

@Joxit Joxit commented Sep 7, 2022

Background

I'm facing some issues with registry server cache control (see #260 (comment))

The docker registry UI is built on top of the registry server API v2 and it implements some HTTP specs incorrectly. This time I'm talking about cache control and ETag.

As I speak, when you are requesting a resource such as a tag manifest (e.g. /v2/nginx/manifests/1.23) and your browser cache control is activated, you will get a ETag in the response. When you use this ETag in If-None-Match header, you will receive 304 even if your headers and the body have changed.

# Will return 200 OK
curl -I 'http://127.0.0.1:5000/v2/nginx/manifests/1.23' -H 'Accept: application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.imaget.list.v2+json'

# Take the value in the ETag and replace the If-None-Match bellow
# This will return 304 Not Modified
curl -I 'http://127.0.0.1:5000/v2/nginx/manifests/1.23' -H 'Accept: application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.imaget.list.v2+json' -H 'If-None-Match: "sha256:b95a99feebf7797479e0c5eb5ec0bdfa5d9f504bc94da550c2f58e839ea6914f"'

# Remove the value application/vnd.oci.imaget.list.v2+json from Accept will still return 304 Not Modified...
curl -I 'http://127.0.0.1:5000/v2/nginx/manifests/1.23' -H 'Accept: application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json' -H 'If-None-Match: "sha256:b95a99feebf7797479e0c5eb5ec0bdfa5d9f504bc94da550c2f58e839ea6914f"'

How to fix it ?

This issue will be appear on multi-arch images only. With this PR you can add an option ADD_NO_CACHE_HEADER=true on your registry UI and you must add Cache-Control in your registry server Access-Control-Allow-Headers configuration.

http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
    Access-Control-Allow-Origin: ['*']
    Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
    # This line bellow 
    Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control']
    Access-Control-Expose-Headers: ['Docker-Content-Digest']

Try this PR with this image

docker pull joxit/docker-registry-ui:feat-no-cache

@loliee
Copy link

loliee commented Sep 8, 2022

Hi,

I tried the new image and I still have the problem.

A curl example:

curl -u xxx:xxx -I 'https://myregistry.example/v2/nginx/manifests/1.23' -H 'Accept: application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.imaget.list.v2+json'
HTTP/2 200
server: nginx
date: Thu, 08 Sep 2022 10:06:13 GMT
content-type: application/vnd.docker.distribution.manifest.v2+json
content-length: 1570
access-control-allow-credentials: true
access-control-allow-headers: Authorization
access-control-allow-headers: Accept
access-control-allow-headers: Cache-Control
access-control-allow-methods: HEAD
access-control-allow-methods: GET
access-control-allow-methods: OPTIONS
access-control-allow-methods: DELETE
access-control-allow-origin: *
access-control-expose-headers: Docker-Content-Digest
docker-content-digest: sha256:f26fbadb0acab4a21ecb4e337a326907e61fbec36c9a9b52e725669d99ed1261
docker-distribution-api-version: registry/2.0
etag: "sha256:f26fbadb0acab4a21ecb4e337a326907e61fbec36c9a9b52e725669d99ed1261"
x-content-type-options: nosniff

I can see an HXR request on https://myregistry.example/v2/nginx/blobs/undefined that return a 404 when I am on the https://myregistry.example/ui/#!/taglist/nginx.

@Joxit
Copy link
Owner Author

Joxit commented Sep 11, 2022

Your browser sent the request on https://myregistry.example/v2/nginx/manifests/1.23 with the header If-None-Match ?

Can you sent me the result of Copy As Curl for the request https://myregistry.example/v2/nginx/manifests/1.23 with the result when failing ? (you will need to remove the header Authorization)

@loliee
Copy link

loliee commented Sep 12, 2022

Yes the browser sent the request with the If-None-Match header.

curl 'https://myregistry.example/v2/nginx/manifests/1.23' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:104.0) Gecko/20100101 Firefox/104.0' -H 'Accept: application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate, br' -H 'Cache-Control: no-cache' -H 'DNT: 1' -H 'Authorization: Basic XXX' -H 'Connection: keep-alive' -H 'Referer: https://myregistry.example/ui/' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin' -H 'Sec-GPC: 1' -H 'If-None-Match: "sha256:691eecfa41f219b32acea5a3561a8d8691d8320e5a00e1cb4574de5827e077a7"' -H 'TE: trailers'

Response headers (304):

HTTP/2 304 Not Modified
server: nginx
date: Mon, 12 Sep 2022 07:20:19 GMT
access-control-allow-credentials: true
access-control-allow-headers: Authorization
access-control-allow-headers: Accept
access-control-allow-headers: Cache-Control
access-control-allow-methods: HEAD
access-control-allow-methods: GET
access-control-allow-methods: OPTIONS
access-control-allow-methods: DELETE
access-control-allow-origin: *
access-control-expose-headers: Docker-Content-Digest
docker-distribution-api-version: registry/2.0
x-content-type-options: nosniff
X-Firefox-Spdy: h2

Response body:

{
	"manifests": [
		{
			"digest": "sha256:f26fbadb0acab4a21ecb4e337a326907e61fbec36c9a9b52e725669d99ed1261",
			"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
			"platform": {
				"architecture": "amd64",
				"os": "linux"
			},
			"size": 1570
		},
		{
			"digest": "sha256:df0d884bcf2e51ad370f16bcbe6d4cef68fd8057b63da89b77c228a680e7ed8a",
			"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
			"platform": {
				"architecture": "arm",
				"os": "linux",
				"variant": "v5"
			},
			"size": 1570
		},
		{
			"digest": "sha256:ef2ad3781f412ae3052ef56f5938be93fef49d4204ecb36af2cec4d443ad9895",
			"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
			"platform": {
				"architecture": "arm",
				"os": "linux",
				"variant": "v7"
			},
			"size": 1570
		},
		{
			"digest": "sha256:f5bee9654d19467f16c259fb577c4a28c082f8008914befd30805f803fa56e99",
			"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
			"platform": {
				"architecture": "arm64",
				"os": "linux",
				"variant": "v8"
			},
			"size": 1570
		},
		{
			"digest": "sha256:d830cc525721daa5769bf9876db421987aefeff16c5074edc0c6b9061f8ff359",
			"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
			"platform": {
				"architecture": "386",
				"os": "linux"
			},
			"size": 1570
		},
		{
			"digest": "sha256:3e7402f0eb053ffd769097c9c726b39b0318e3f5a2538e7b63779714e646de93",
			"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
			"platform": {
				"architecture": "mips64le",
				"os": "linux"
			},
			"size": 1570
		},
		{
			"digest": "sha256:f1d915d7215a80b1a294ec8e9005a4b7984e650e06cb9b52f57e830576245c74",
			"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
			"platform": {
				"architecture": "ppc64le",
				"os": "linux"
			},
			"size": 1570
		},
		{
			"digest": "sha256:ead4adf366b0333e5f7e10f32b2b7814b3ea39807db3c3ac029d4404140da5b0",
			"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
			"platform": {
				"architecture": "s390x",
				"os": "linux"
			},
			"size": 1570
		}
	],
	"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
	"schemaVersion": 2
}

A screenshot of my browser console on https://myregistry.example/ui/#!/taglist/nginx:

Screen Shot 2022-09-12 at 9 01 46 AM

@Joxit
Copy link
Owner Author

Joxit commented Sep 12, 2022

Okay, thank you for your response 😄

What's your configuration for the docker registry ui (the docker-compose) ? Did you add the environment variable ADD_NO_CACHE_HEADER and set the value to true ?

@loliee
Copy link

loliee commented Sep 12, 2022

Yes, here my config:

  registry-ui:
    container_name: registry-ui
    restart: always
    image: joxit/docker-registry-ui:feat-no-cache
    environment:
      REGISTRY_TITLE: XXX private Docker registry
      REGISTRY_URL: https://myregistry.example
      NGINX_PROXY_PASS_URL: https://myregistry.example
      ADD_NO_CACHE_HEADER: "true"
      DELETE_IMAGES: "true"
      SINGLE_REGISTRY: "true"
      SHOW_CONTENT_DIGEST: "true"

[EDIT]

And the registry container was re-recreated, cf. docker inspect:

        "Config": {
            "Hostname": "c11156482aa8",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "REGISTRY_TITLE=XXX private Docker registry",
                "REGISTRY_URL=https://myregistry.example",
                "NGINX_PROXY_PASS_URL=https://myregistry.example",
                "ADD_NO_CACHE_HEADER=true",
                "DELETE_IMAGES=true",
                "SINGLE_REGISTRY=true",
                "SHOW_CONTENT_DIGEST=true",
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.23.1",
                "NJS_VERSION=0.7.6",
                "PKG_RELEASE=1",
                "NGINX_PROXY_HEADER_Host=$http_host",
                "NGINX_LISTEN_PORT=80",
                "SHOW_CATALOG_NB_TAGS=false"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Image": "joxit/docker-registry-ui:feat-no-cache",
            "Volumes": null,
            "WorkingDir": "/usr/share/nginx/html",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],

@Joxit
Copy link
Owner Author

Joxit commented Sep 12, 2022

I try your configuration and it works..... on Chrome but not Firefox 😭
When I add the Cache-Control header on Crhome, this remove the If-None-Match header
But on Firefox it adds both Cache-Control: no-cache and If-None-Match... Thanks now I can reproduce the issue, I will see what I can do now...
I may change the option 🤷

@loliee
Copy link

loliee commented Sep 12, 2022

I am glad you can reproduce the issue.
I confirm it works well on Chrome.

BTW Thanks for this project !

@Joxit
Copy link
Owner Author

Joxit commented Sep 12, 2022

It's a pleasure 😄 I needed this for my work too 😄

I pushed a new version (Image id 38a12e511868) please do a docker pull and recreate your container.
I added no-store, seems to work on Firefox now, can you check this ? 😄

@loliee
Copy link

loliee commented Sep 12, 2022

It works 🙌 👍

Well done !

@Joxit
Copy link
Owner Author

Joxit commented Sep 12, 2022

Yeah! Thanks! 😁 I will publish this tonight with the documentations

…e-Control` header on requests to registry server

This requires a change in your registry server configuration
@Joxit Joxit merged commit 34fd13d into main Sep 12, 2022
@Joxit Joxit deleted the feat/no-cache branch September 12, 2022 16:29
@Joxit
Copy link
Owner Author

Joxit commented Sep 12, 2022

I've renamed the option, it will be USE_CONTROL_CACHE_HEADER in release 2.3.0

@Joxit Joxit added this to the 2.3.0 milestone Sep 12, 2022
@Joxit
Copy link
Owner Author

Joxit commented Sep 18, 2022

Hi @loliee, thank you again for your help. I added you in my contributors list 😄

@gavinw6662
Copy link

I will need to grab a copy of 2.3.0 and then apply the same changes here.

Thanks a bunch for the help.

I was always able to just 'forget' about the problem since I don't use my registry all that much. Eventually, the problem would fix itself (for me). But now it sounds like I don't have to worry about it.

@gavinw6662
Copy link

I finally got around to working on this on my home network and I can confirm that this solution works. I no longer have this issue while using firefox (or any browser).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants