Russell Seymour
Russell Seymour

Reputation: 1423

How to login to a Docker Registry that has an HTTP prefix set?

I have setup my own Docker Registry, but I did not want it on the root URL so when I created the service I used the REGISTRY_HTTP_PREFIX environment variable and set it to /registry/, thus the URL to the registry is https://tools.example.com/registry. This is being proxied by Nginx which has Basic Auth setup on it.

I tested access to the registry using a Browser and I was able to get it to show that there are no repositories by going to http://tools.example.com/registry/v2/_catalog:

enter image description here

This led me to think that it was workoing. However when I try to login to the registry using the Docker command line, I get the Basic Auth challenge but then it fails to login because the URL is incorrect, e.g.

docker login -u russells -p xxxxxxxx https://tools.example.com/registry/
Error response from daemon: login attempt to https://tools.example.com/v2/ failed with status: 404 Not Found

As can be seen from the error, the prefix is not being added properly. SO how can I login to the registry so I can push images. Is there an environment variable or something that I am missing to make the docker login work properly?

Update - 2017-08-12 2253 BST

I Have been playing around with the configuration a bit, but I am still not getting very far.

As requested here are my configuration files.

nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    keepalive_timeout  65;

    upstream docker-registry {
        server registry:5000;
    }

    map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
        '' 'registry/2.0';
    }

    server {
        listen 15000;
        server_name tools.example.com;

        # disable any limits to avoid HTTP 413 for large image uploads
        client_max_body_size 0;

        # required to avoid HTTP 411
        chunked_transfer_encoding on;

        location /registry/ {

            # Do not allow connections from docker 1.5. and earlier
            # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
            if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$") {
                return 404;
            }

            auth_basic "Docker Registry";
            auth_basic_user_file /etc/nginx/.htpasswd;

            add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;

            proxy_pass                      http://docker-registry/registry/;
            proxy_set_header    Host        $http_host;
            proxy_set_header    X-Real-IP   $remote_addr;
            proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header    X-Forwarded-Proto $scheme;
            proxy_read_timeout              900;

        }
    }
}

My Docker Registry service is deployed as registry and is running on the default port of 5000. Looking at this now I think I have got things confused. I do not need the registry to answer on the prefix itself, just Nginx.

For example if I leave the location set to / then I can login, but if I change this to /registry/ then I am not able to. I am beginning to think that the two are conflicting each other.

Registry

I have not set a configuration for the Registry other than the one environment variable - REGISTRY_HTTP_PREFIX, which maybe surplus to requirements in this setup.

Update - 2017-08-15 1100 BST

In order to test the prefix for the registry I created a registry container with the following configuration file:

version: 0.1
auth:
  htpasswd:
    realm: Docker Registry
    path: /auth/etc/htpasswd
storage:
  filesystem:
    rootdirectory: /var/lib/registry
    maxthreads: 100
http:
  addr: 0.0.0.0:5000
  prefix: /registry/
  tls:
    certificate: /auth/ssl/certs/registry.cert
    key: /auth/ssl/private/registry.key

As this is using self signed certificates I updated my Docker engine by placing the certificate in /etc/docker/certs.d/host-lin-01:5000.

I then created the container with the following command:

docker run -it --rm -p 5000:5000 --name registry_test -v ~/workspaces/docker/registry/etc/registry.yml:/etc/docker/registry/config.yml -v ~/workspaces/docker/registry:/auth registry:2

If I try and login to the registry with the command:

docker login -u russells -p xxxxxx https://host-lin-01:5000/registry

I get the following error:

Error response from daemon: login attempt to https://host-lin-01:5000/v2/ failed with status: 404 Not Found

Now if I remove the perfix: /registry/ line from the registry yaml file and restart the container and then login all is well:

docker login -u russells -p xxxxxx https://turtle-host-03:5000/
Login Succeeded

What is strange, however, is that the login works for any prefix I put on the end of the login URL, e.g.

docker login -u russells -p xxxxxx https://turtle-host-03:5000/registry/fred/34
Login Succeeded

I do not understand this. I must be misunderstanding what the prefix setting does.

Upvotes: 10

Views: 8619

Answers (2)

BMitch
BMitch

Reputation: 264821

The prefix setting in the distribution project was added for environments behind a proxy that would map the path to a hostname. It is not intended to be directly accessed from the Docker CLI. All of the endpoints in the OCI spec start at /v2 without the option to change that setting.

The docker login is most likely stripping off the repository provided on the command, since they manage logins as a registry level, not at a repository level:

$ docker login --help

Usage:  docker login [OPTIONS] [SERVER]

Authenticate to a registry.
Defaults to Docker Hub if no server is specified.

Options:
  -p, --password string   Password
      --password-stdin    Take the password from stdin
  -u, --username string   Username

Upvotes: 1

Tarun Lalwani
Tarun Lalwani

Reputation: 146630

You issue is the application of your Basic Auth. So you have Nginx with Basic Auth which is backed by a plain registry.

You are able to authenticate urls and see the _catalog blank json, and that make you feel it is working. But technically what is happening is that your Nginx is asking for username/password, which gets it and then passes is on to you docker registry. Which in turn has no authentication.

Now when you use docker login you are expecting a authenticated registry but you have a authenticated nginx and non-authenticated registry. So you need to ditch the below lines of code from your nginx config

auth_basic "Docker Registry";
auth_basic_user_file /etc/nginx/.htpasswd;

Also when launching your registry you need to define the below environment variables

  REGISTRY_AUTH: htpasswd
  REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
  REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm

Make sure you map /auth/htpasswd from your host to the registry container. Do this and the setup should work. Also make sure to setup the server certificates in your docker client system

Optional Changes

Next part of this answer is optional as such. Since you are using Nginx and Registry both. I would suggest you ditch the REGISTRY_HTTP_PREFIX from your registry and change the proxy_pass to

proxy_pass http://docker-registry/;

Upvotes: 0

Related Questions