Skip Navigation
Resources Blog Setting up a private Docker registry with authentication ...

Setting up a private Docker registry with authentication using Sonatype Nexus Repository and NGINX

This article shows how you can set up a private Docker registry with authentication and SSL using Sonatype Nexus Repository OSS.

Sonatype Nexus Repository OSS is a universal repository manager with support for all major package formats and types. It's a free solution for storing and sharing Docker images and other components like NuGet or NPM packages across the deployment pipeline while keeping your proprietary and third-party images private and secure.

I am using an Ubuntu Server 16.04 and Docker 1.12 to host the Sonatype Nexus Repository and NGINX containers.

Running Sonatype Nexus Repository container

First you have to build your own Sonatype Nexus Repository 3 Docker image and expose port 8081 and 5000. Sonatype Nexus Repository management UI will run on 8081 while Docker registry will run on 5000. This Docker image can be found on Docker Hub at stefanprodan/nexus.

Create a directory named "nexus" and add a Dockerfile with the following content:

FROM alpine:3.4

ENV NEXUS_VERSION="3.0.2-02" \
    NEXUS_DATA="/nexus-data" \
    JAVA_MIN_MEM="1200M" \
    JAVA_MAX_MEM="1200M" \
    JKS_PASSWORD="changeit"

RUN set -x \
    && apk --no-cache add \
        openjdk8-jre-base \
        openssl \
        su-exec \
    && mkdir "/opt" \
    && wget -qO - "https://download.sonatype.com/nexus/3/nexus-${NEXUS_VERSION}-unix.tar.gz" \
    | tar -zxC "/opt" \
    && adduser -S -h ${NEXUS_DATA} nexus \
	&& sed \
		-e "s|-Xms1200M|-Xms${JAVA_MIN_MEM}|g" \
		-e "s|-Xmx1200M|-Xmx${JAVA_MAX_MEM}|g" \
		-e "s|karaf.home=.|karaf.home=/opt/nexus-${NEXUS_VERSION}|g" \
		-e "s|karaf.base=.|karaf.base=/opt/nexus-${NEXUS_VERSION}|g" \
		-e "s|karaf.etc=etc|karaf.etc=/opt/nexus-${NEXUS_VERSION}/etc|g" \
		-e "s|java.util.logging.config.file=etc|java.util.logging.config.file=/opt/nexus-${NEXUS_VERSION}/etc|g" \
		-e "s|karaf.data=data|karaf.data=${NEXUS_DATA}|g" \
		-e "s|java.io.tmpdir=data/tmp|java.io.tmpdir=${NEXUS_DATA}/tmp|g" \
		-i "/opt/nexus-${NEXUS_VERSION}/bin/nexus.vmoptions" \
	&& mkdir -p "${NEXUS_DATA}" \
	&& chown -R nexus "${NEXUS_DATA}"

EXPOSE 8081 5000

WORKDIR "/opt/nexus-${NEXUS_VERSION}"

VOLUME ${NEXUS_DATA}

CMD ["su-exec", "nexus", "bin/nexus", "run"]

Next you need to create a dedicated Docker network for your registry:

docker network create intranet

Now you can build the Sonatype Nexus Repository image and run the container:

docker build -t nexus-img .

docker run -d --name nexus \
    -v /path/to/nexus-data:/nexus-data \
    --restart unless-stopped \
    --network intranet nexus-img

Replace /path/to/nexus-data with your own location.

Running NGINX as reverse proxy for Sonatype Nexus Repository

Create a directory named nginx and add a Dockerfile with the following content:

FROM nginx
COPY ./nginx.conf /etc/nginx/nginx.conf

In the same directory create the nginx.conf file with the following content:

worker_processes 2;

events { 
	worker_connections 1024; 
}

http {
	error_log /var/log/nginx/error.log warn;
	access_log  /dev/null;
	proxy_intercept_errors off;
	proxy_send_timeout 120;
	proxy_read_timeout 300;
	
	upstream nexus {
        server nexus:8081;
	}

	upstream registry {
        server nexus:5000;
	}

	server {
        listen 80;
        server_name nexus.demo.com;

        keepalive_timeout  5 5;
        proxy_buffering    off;

        # allow large uploads
        client_max_body_size 1G;

        location / {
		# redirect to docker registry
		if ($http_user_agent ~ docker ) {
			proxy_pass http://registry;
		}
		proxy_pass http://nexus;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

Replace nexus.demo.com with your own domain. The NGINX server detects if a call is made by the Docker client, based on user agent, and redirects that call to the Docker registry.

Build and run the NGINX container:

docker build -t nginx-img .

docker run -d --publish 80:80 --name nginx \
    --restart unless-stopped \
    --network intranet \
    nginx-img

Now you can access the Sonatype Nexus Repository UI by navigation to your sub-domain. The default credentials are admin / admin123, you should change them before proceeding with the setup. Sonatype Nexus Repository can be configured to support static or dynamic user and group definitions and can authenticate users against LDAP or Active Directory.

Navigate to the repository administration page and create a new repository by selecting the docker (hosted) recipe. In the repository connectors section, check Create an HTTP connector at specified port and insert 5000 as the port value.

At this point, the Docker registry is up and running, but you can't access it from a docker client because Docker requires the registry to run on SSL.

You can use Let's Encrypt certbot to generate a certificate for Sonatype Nexus Repository sub-domain or you can use Cloudflare to manage your domain and enable the free Flexible SSL option. Since certbot NGINX plug-in is still experimental, I opted for the Cloudflare certificate.

Once you've configured the certificate you can start using the private Docker registry by logging in with your Sonatype Nexus Repository credentials:

docker login nexus.demo.com

Sonatype Nexus Repository OSS is used by more than 100,000 development teams, if you need to run a self-hosted Docker registry you should consider using Sonatype Nexus Repository.

Picture of Stefan Prodan

Written by Stefan Prodan

Co-Founder of Veritech Solutions. Passionate about software architecture, domain driven design and DevOps. Loves programming in .NET, JS and Go.