I'm trying to deploy a generic registry instance (npm private registry + docker private registry) on an EC2 instance sitting behind an Elastic Load Balancer with nginx as a reverse proxy.
Doing so I want to be able to push npm packages and docker images respectively to registry.mydomain.org and docker.mydomain.org through https and with authentication.
To do so, I followed the following steps:
docker-compose.yml file with this configuration (I'm using verdaccio as npm private registry and registry:2 as docker registry:
version: '3'
services:
nginx:
image: nginx:alpine
container_name: nginx
restart: always
ports:
- "80:80"
volumes:
- ./nginx:/etc/nginx/conf.d/
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
links:
- verdaccio:verdaccio
- docker:docker
verdaccio:
image: verdaccio/verdaccio:latest
container_name: verdaccio
restart: always
ports:
- "4873:4873"
volumes:
- ./registry:/verdaccio/conf
- ./database/verdaccio:/verdaccio/storage
docker:
image: registry:2
container_name: docker
restart: always
ports:
- "5000:5000"
volumes:
- ./database/docker:/var/lib/registry
events {
worker_connections 1024;
}
http {
upstream docker-registry {
server docker:5000;
}
upstream npm-registry {
server verdaccio:4873;
}
## Set a variable to help us decide if we need to add the
## 'Docker-Distribution-Api-Version' header.
## The registry always sets this header.
## In the case of nginx performing auth, the header will be unset
## since nginx is auth-ing before proxying.
map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
'' 'registry/2.0';
}
# Healtcheck
server {
listen 80;
location /healthcheck {
access_log off;
return 200;
}
}
server {
# Server options
listen 80;
charset utf-8;
client_max_body_size 0;
server_name registry.mydomain.org;
# Proxy settings
location / {
access_log /var/log/nginx/verdaccio.log;
proxy_pass http://npm-registry;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_ssl_session_reuse off;
proxy_redirect off;
}
}
server {
# Server options
listen 80;
charset utf-8;
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
chunked_transfer_encoding on;
server_name docker.mydomain.org;
# Authentication
auth_basic "Registry realm";
auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
# Proxy settings
location / {
if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
return 404;
}
## If $docker_distribution_api_version is empty, the header will not be added.
## See the map directive above where this variable is defined.
add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;
access_log /var/log/nginx/docker.log;
proxy_pass http://docker-registry;
proxy_read_timeout 900;
}
}
}
nginx.htpasswd file with the encoded authentication infos.Now, the registry is perfectly working. So if I visit https://registry.mydomain.org I can see it and I can push npm packages to it through npm login --registry=https://registry.mydomain.org --scope=@myscope
Concerning the docker registry, however, while I can definitely log into it with docker login -u user -p password but when I am trying to push an image to it the docker client enters in an infinite loop and continues trying uploading the images (with no success).
On the server side, the docker registry's logs does not show an useful info about what is going on since all the requests end in 202 HTTP statuses.
Any hint about how to solve it?
I figured it out.
I was missing a proxy_set_header Host $host; in the nginx proxy configuration.
Doing this:
server {
# Server options
listen 80;
charset utf-8;
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
chunked_transfer_encoding on;
server_name docker.cubbit.net;
# Authentication
auth_basic "Registry realm";
auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
# Proxy settings
location / {
# 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;
}
## If $docker_distribution_api_version is empty, the header will not be added.
## See the map directive above where this variable is defined.
add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;
access_log /var/log/nginx/docker.log;
proxy_pass http://docker-registry;
proxy_set_header Host $host;
proxy_read_timeout 900;
}
}
It started working perfectly. Hope this can help someone. I spent two days on it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With