{"id":74,"date":"2017-03-29T16:54:29","date_gmt":"2017-03-29T08:54:29","guid":{"rendered":"http:\/\/www.jsjs.org\/?p=74"},"modified":"2017-03-29T16:54:29","modified_gmt":"2017-03-29T08:54:29","slug":"setting-up-a-docker-private-registry-with-authentication-using-nexus-and-nginx","status":"publish","type":"post","link":"https:\/\/blog.jsjs.org\/?p=74","title":{"rendered":"Setting up a Docker Private Registry with Authentication Using Nexus and Nginx"},"content":{"rendered":"<p>This article shows how you can set up a Docker Private Registry with authentication and SSL using Nexus Repository OSS.<\/p>\n<p>Nexus Repository OSS is a universal repository manager with support for all major package formats and types. It\u2019s 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.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-64170\" src=\"http:\/\/www.sonatype.org\/nexus\/content\/uploads\/2017\/03\/stefan1.png\" alt=\"stefan1\" width=\"520\" height=\"258\" \/><\/p>\n<p>I am using an Ubuntu Server 16.04 and Docker 1.12 to host the Nexus Repository and NGINX containers.<\/p>\n<h3 id=\"running-nexus-repository-container\">Running Nexus Repository container<\/h3>\n<p>First you have to build your own Nexus 3 docker image and expose port 8081 and 5000. Nexus management UI will run on 8081 while Docker Registry will run on 5000. This Docker image can be found on Docker Hub at <a href=\"https:\/\/hub.docker.com\/r\/stefanprodan\/nexus\/\">stefanprodan\/nexus<\/a>.<\/p>\n<p>Create a directory named nexus and add a Dockerfile with the following content:<\/p>\n<div class=\"language-sh highlighter-rouge\">\n<pre class=\"highlight\"><code>FROM alpine:3.4\n\nENV <span class=\"nv\">NEXUS_VERSION<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"3.0.2-02\"<\/span> <span class=\"se\">\\<\/span>\n    <span class=\"nv\">NEXUS_DATA<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"\/nexus-data\"<\/span> <span class=\"se\">\\<\/span>\n    <span class=\"nv\">JAVA_MIN_MEM<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"1200M\"<\/span> <span class=\"se\">\\<\/span>\n    <span class=\"nv\">JAVA_MAX_MEM<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"1200M\"<\/span> <span class=\"se\">\\<\/span>\n    <span class=\"nv\">JKS_PASSWORD<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"changeit\"<\/span>\n\nRUN <span class=\"nb\">set<\/span> -x <span class=\"se\">\\<\/span>\n    <span class=\"o\">&amp;&amp;<\/span> apk --no-cache add <span class=\"se\">\\<\/span>\n        openjdk8-jre-base <span class=\"se\">\\<\/span>\n        openssl <span class=\"se\">\\<\/span>\n        su-exec <span class=\"se\">\\<\/span>\n    <span class=\"o\">&amp;&amp;<\/span> mkdir <span class=\"s2\">\"\/opt\"<\/span> <span class=\"se\">\\<\/span>\n    <span class=\"o\">&amp;&amp;<\/span> wget -qO - <span class=\"s2\">\"https:\/\/download.sonatype.com\/nexus\/3\/nexus-<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_VERSION<\/span><span class=\"k\">}<\/span><span class=\"s2\">-unix.tar.gz\"<\/span> <span class=\"se\">\\<\/span>\n    | tar -zxC <span class=\"s2\">\"\/opt\"<\/span> <span class=\"se\">\\<\/span>\n    <span class=\"o\">&amp;&amp;<\/span> adduser -S -h <span class=\"k\">${<\/span><span class=\"nv\">NEXUS_DATA<\/span><span class=\"k\">}<\/span> nexus <span class=\"se\">\\<\/span>\n\t<span class=\"o\">&amp;&amp;<\/span> sed <span class=\"se\">\\<\/span>\n\t\t-e <span class=\"s2\">\"s|-Xms1200M|-Xms<\/span><span class=\"k\">${<\/span><span class=\"nv\">JAVA_MIN_MEM<\/span><span class=\"k\">}<\/span><span class=\"s2\">|g\"<\/span> <span class=\"se\">\\<\/span>\n\t\t-e <span class=\"s2\">\"s|-Xmx1200M|-Xmx<\/span><span class=\"k\">${<\/span><span class=\"nv\">JAVA_MAX_MEM<\/span><span class=\"k\">}<\/span><span class=\"s2\">|g\"<\/span> <span class=\"se\">\\<\/span>\n\t\t-e <span class=\"s2\">\"s|karaf.home=.|karaf.home=\/opt\/nexus-<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_VERSION<\/span><span class=\"k\">}<\/span><span class=\"s2\">|g\"<\/span> <span class=\"se\">\\<\/span>\n\t\t-e <span class=\"s2\">\"s|karaf.base=.|karaf.base=\/opt\/nexus-<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_VERSION<\/span><span class=\"k\">}<\/span><span class=\"s2\">|g\"<\/span> <span class=\"se\">\\<\/span>\n\t\t-e <span class=\"s2\">\"s|karaf.etc=etc|karaf.etc=\/opt\/nexus-<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_VERSION<\/span><span class=\"k\">}<\/span><span class=\"s2\">\/etc|g\"<\/span> <span class=\"se\">\\<\/span>\n\t\t-e <span class=\"s2\">\"s|java.util.logging.config.file=etc|java.util.logging.config.file=\/opt\/nexus-<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_VERSION<\/span><span class=\"k\">}<\/span><span class=\"s2\">\/etc|g\"<\/span> <span class=\"se\">\\<\/span>\n\t\t-e <span class=\"s2\">\"s|karaf.data=data|karaf.data=<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_DATA<\/span><span class=\"k\">}<\/span><span class=\"s2\">|g\"<\/span> <span class=\"se\">\\<\/span>\n\t\t-e <span class=\"s2\">\"s|java.io.tmpdir=data\/tmp|java.io.tmpdir=<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_DATA<\/span><span class=\"k\">}<\/span><span class=\"s2\">\/tmp|g\"<\/span> <span class=\"se\">\\<\/span>\n\t\t-i <span class=\"s2\">\"\/opt\/nexus-<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_VERSION<\/span><span class=\"k\">}<\/span><span class=\"s2\">\/bin\/nexus.vmoptions\"<\/span> <span class=\"se\">\\<\/span>\n\t<span class=\"o\">&amp;&amp;<\/span> mkdir -p <span class=\"s2\">\"<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_DATA<\/span><span class=\"k\">}<\/span><span class=\"s2\">\"<\/span> <span class=\"se\">\\<\/span>\n\t<span class=\"o\">&amp;&amp;<\/span> chown -R nexus <span class=\"s2\">\"<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_DATA<\/span><span class=\"k\">}<\/span><span class=\"s2\">\"<\/span>\n\nEXPOSE 8081 5000\n\nWORKDIR <span class=\"s2\">\"\/opt\/nexus-<\/span><span class=\"k\">${<\/span><span class=\"nv\">NEXUS_VERSION<\/span><span class=\"k\">}<\/span><span class=\"s2\">\"<\/span>\n\nVOLUME <span class=\"k\">${<\/span><span class=\"nv\">NEXUS_DATA<\/span><span class=\"k\">}<\/span>\n\nCMD <span class=\"o\">[<\/span><span class=\"s2\">\"su-exec\"<\/span>, <span class=\"s2\">\"nexus\"<\/span>, <span class=\"s2\">\"bin\/nexus\"<\/span>, <span class=\"s2\">\"run\"<\/span><span class=\"o\">]<\/span>\n<\/code><\/pre>\n<\/div>\n<p>Next you need to create a dedicated docker network for your registry:<\/p>\n<div class=\"language-sh highlighter-rouge\">\n<pre class=\"highlight\"><code>docker network create intranet\n<\/code><\/pre>\n<\/div>\n<p>Now you can build the nexus image and run the nexus container:<\/p>\n<div class=\"language-sh highlighter-rouge\">\n<pre class=\"highlight\"><code>docker build -t nexus-img .\n\ndocker run -d --name nexus <span class=\"se\">\\<\/span>\n    -v \/path\/to\/nexus-data:\/nexus-data <span class=\"se\">\\<\/span>\n    --restart unless-stopped <span class=\"se\">\\<\/span>\n    --network intranet nexus-img\n<\/code><\/pre>\n<\/div>\n<p>Replace <code class=\"highlighter-rouge\">\/path\/to\/nexus-data<\/code> with your own location.<\/p>\n<h3 id=\"running-nginx-as-reverse-proxy-for-nexus\">Running NGINX as reverse proxy for Nexus<\/h3>\n<p>Create a directory named nginx and add a Dockerfile with the following content:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>FROM nginx\nCOPY .\/nginx.conf \/etc\/nginx\/nginx.conf\n<\/code><\/pre>\n<\/div>\n<p>In the same directory create the nginx.conf file with the following content:<\/p>\n<div class=\"language-sh highlighter-rouge\">\n<pre class=\"highlight\"><code>worker_processes 2;\n\nevents <span class=\"o\">{<\/span>\n\tworker_connections 1024;\n<span class=\"o\">}<\/span>\n\nhttp <span class=\"o\">{<\/span>\n\terror_log \/var\/log\/nginx\/error.log warn;\n\taccess_log  \/dev\/null;\n\tproxy_intercept_errors off;\n\tproxy_send_timeout 120;\n\tproxy_read_timeout 300;\n\n\tupstream nexus <span class=\"o\">{<\/span>\n        server nexus:8081;\n\t<span class=\"o\">}<\/span>\n\n\tupstream registry <span class=\"o\">{<\/span>\n        server nexus:5000;\n\t<span class=\"o\">}<\/span>\n\n\tserver <span class=\"o\">{<\/span>\n        listen 80;\n        server_name nexus.demo.com;\n\n        keepalive_timeout  5 5;\n        proxy_buffering    off;\n\n        <span class=\"c\"># allow large uploads<\/span>\n        client_max_body_size 1G;\n\n        location \/ <span class=\"o\">{<\/span>\n\t\t<span class=\"c\"># redirect to docker registry<\/span>\n\t\t<span class=\"k\">if<\/span> <span class=\"o\">(<\/span><span class=\"nv\">$http_user_agent<\/span> ~ docker <span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n\t\t\tproxy_pass http:\/\/registry;\n\t\t<span class=\"o\">}<\/span>\n\t\tproxy_pass http:\/\/nexus;\n\t\tproxy_set_header Host <span class=\"nv\">$host<\/span>;\n\t\tproxy_set_header X-Real-IP <span class=\"nv\">$remote_addr<\/span>;\n\t\tproxy_set_header X-Forwarded-For <span class=\"nv\">$proxy_add_x_forwarded_for<\/span>;\n        <span class=\"o\">}<\/span>\n    <span class=\"o\">}<\/span>\n<span class=\"o\">}<\/span>\n\n<\/code><\/pre>\n<\/div>\n<p>Replace <code class=\"highlighter-rouge\">nexus.demo.com<\/code> 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.<\/p>\n<p>Build and run the NGINX container:<\/p>\n<div class=\"language-sh highlighter-rouge\">\n<pre class=\"highlight\"><code>docker build -t nginx-img .\n\ndocker run -d --publish 80:80 --name nginx <span class=\"se\">\\<\/span>\n    --restart unless-stopped <span class=\"se\">\\<\/span>\n    --network intranet <span class=\"se\">\\<\/span>\n    nginx-img\n<\/code><\/pre>\n<\/div>\n<p>Now you can access the Nexus UI by navigation to your nexus sub-domain. The default credentials are <code class=\"highlighter-rouge\">admin<\/code> \/ <code class=\"highlighter-rouge\">admin123<\/code>, you should change them before proceeding with the setup. Nexus can be configured to support static or dynamic user and group definitions and can authenticate users against LDAP or Active Directory.<\/p>\n<p>Navigate to the repository administration page and create a new repository by selecting the <strong><em>docker (hosted)<\/em><\/strong> recipe. In the repository connectors section, check <strong><em>Create an HTTP connector at specified port<\/em><\/strong> and insert <strong><em>5000<\/em><\/strong> as the port value. For a detailed walkthrough check the nexus documentation on <a href=\"https:\/\/books.sonatype.com\/nexus-book\/3.0\/reference\/docker.html?__hstc=239247836.89b4f0772be24f1c03525f0d50e3fc22.1490161869732.1490161869732.1490756181935.2&amp;__hssc=239247836.2.1490756181935&amp;__hsfp=1862577492\">Docker Registry<\/a>.<\/p>\n<p>At this point, the Docker Registry is up and running, but you can\u2019t access it from a docker client because Docker requires the registry to run on SSL.<\/p>\n<p>You can use letsencrypt <a href=\"https:\/\/github.com\/certbot\/certbot\">certbot<\/a> to generate a certificate for nexus 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.<\/p>\n<p>Once you\u2019ve configured the certificate you can start using the Docker Private Registry by logging in with your nexus credentials:<\/p>\n<div class=\"language-sh highlighter-rouge\">\n<pre class=\"highlight\"><code>docker login nexus.demo.com\n<\/code><\/pre>\n<\/div>\n<p><a href=\"https:\/\/www.sonatype.com\/nexus-repository-oss?__hstc=239247836.89b4f0772be24f1c03525f0d50e3fc22.1490161869732.1490161869732.1490756181935.2&amp;__hssc=239247836.2.1490756181935&amp;__hsfp=1862577492\">Nexus Repository OSS<\/a> is used by more than 100,000 development teams, if you need to run a self-hosted Docker Registry you should consider using Nexus.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article shows how you can set up a Docker Private Registry with authentication and SSL using Nexus Repository OSS. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-74","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/posts\/74","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=74"}],"version-history":[{"count":0,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/posts\/74\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=74"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=74"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=74"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}