Docker Repository Reverse Proxy Strategies


Setting up a reverse proxy is one way to avoid Docker port scalability issues. This topic covers intended use cases and implementation steps for setting up a reverse proxy.

Intended Use Cases

Using a reverse proxy in front of Nexus Repository for Docker repositories is an option to consider for the following use cases:

  • Multiple connectors inside of Eclipse Jetty or Nexus Repository would cause performance issues
    • If more than 20 connectors are needed, you must use a reverse proxy
  • You need to limit the number of open ports for infrastructure or security reasons
  • Managing secure connectors/ports/hosts inside an external reverse proxy aligns with organizational goals and infrastructure

Note that Docker client expects secure connectivity (See our SSL documentation).

Implementation Overview

Once implemented as described in this topic, Nexus Repository listens at a non-https connector such as the default 8081.

You can add Docker repositories into Nexus Repository as normal, but do not configure them with any connector port values. 

In the simple example, the following Docker repository hierarchy would exist inside Nexus per project team:

  • docker-group-project
    • docker-hosted-project
    • docker-hub

Based on the host name or port of the request to a reverse proxy, the reverse proxy decides where to reverse proxy the request into Nexus Repository.

Port Mapping Example

In the following Docker push port mapping example, the reverse proxy would direct Docker push commands received at https://project.example.com:8086 to http://nexus.example.com:8081/repository/docker-hosted-project.

docker login project.example.com:8086
docker push project.example.com:8086

In the following Docker pull port mapping example, the reverse proxy would direct Docker pull commands received at https://project.example.com:8087 to http://nexus.example.com:8081/repository/docker-group-project.

docker login project.example.com:8087
docker pull project.example.com:8087

The following example Apache HTTP Server configuration port maps https://project.example.com:8087 to http://nexus.example.com:8081/repository/docker-repo.

Listen 8087 https

<VirtualHost *:8087>
  ServerName project.example.com
  ServerAdmin admin@example.com

  AllowEncodedSlashes NoDecode
  ProxyRequests Off
  ProxyPreserveHost On

  SSLEngine ON
  SSLCertificateFile "/path/to/ssl/server.crt"
  SSLCertificateKeyFile "/path/to/ssl/server.key"

  ProxyTimeout 300
  ProxyPass / http://nexus.example.com:8081/repository/docker-repo/ nocanon
  ProxyPassReverse / http://nexus.example.com:8081/repository/docker-repo/
  RequestHeader set X-Forwarded-Proto "https"
</VirtualHost>

Host Mapping Example

A wildcard TLS certificate is needed for the host name mapping scenario if you intend to have more than one project team specific host name.

In the following Docker push host mapping example, the reverse proxy would direct Docker push commands received at https://project-push.example.com to http://nexus.example.com:8081/repository/docker-hosted-project.

docker login project-push.example.com
docker push project-push.example.com

In the following Docker pull host mapping example, the reverse proxy would direct Docker pull commands recieved at https://project.example.com to http://nexus.example.com:8081/repository/docker-group-project.

docker login project.example.com
docker pull project.example.com

The following example Nginx configuration host maps https://project.example.com to http://nexus.example.com:8081/repository/docker-repo.

This Nginx host mapping example uses the same server for both Docker and regular Nexus Repository requests; it also uses location directives to proxy /v2 or /v1 requests to the Docker repository. Docker automatically adds these v1/v2 paths to the requests and does not require users to add them directly to the Docker commands.

http {

  proxy_send_timeout 120;
  proxy_read_timeout 300;
  proxy_buffering    off;
  proxy_request_buffering off;
  keepalive_timeout  5 5;
  tcp_nodelay        on;

  server {
   listen 443 ssl;
   server_name project.example.com

   ssl on; 
   ssl_certificate /path/to/ssl/server.crt;
   ssl_certificate_key /path/to/ssl/server.key;

   # Docker /v2 and /v1 (for search) requests
   location /v2 {
     proxy_set_header Host $host:$server_port;
     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 "https";
     proxy_pass http://nexus.example.com:8081/repository/docker-repo/$request_uri;
   }
   location /v1 {
     proxy_set_header Host $host:$server_port;
     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 "https";
     proxy_pass http://nexus.example.com:8081/repository/docker-repo/$request_uri;
  }

   # Regular Nexus requests
   location / {
     proxy_set_header Host $host:$server_port;
     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 "https";
     proxy_pass http://nexus.example.com:8081;
   }
 }}