{"id":1440,"date":"2016-06-24T17:15:10","date_gmt":"2016-06-24T14:15:10","guid":{"rendered":"https:\/\/www.systemcodegeeks.com\/?p=1440"},"modified":"2016-06-20T19:36:46","modified_gmt":"2016-06-20T16:36:46","slug":"nginx-reverse-proxy-docker-swarm-clusters","status":"publish","type":"post","link":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/","title":{"rendered":"NGINX as a Reverse Proxy for Docker Swarm Clusters"},"content":{"rendered":"<p>Spawning services across multiple Docker engines is a very cool thing, but those services need to connect each other and be found by public-facing nodes in order to be routed to users. A way to achieve that is to use NGINX as a reverse proxy by defining one or more public-facing nodes. These nodes are going to have NGINX configured to proxy request to each container exposing your service.<\/p>\n<p>In this post, we are going to see how to use NGINX as a reverse proxy for load-balancing containerized HTTP applications running in a Swarm cluster. We\u2019ll also look at how to automate the service discovery (<em>a.k.a.<\/em>, auto-add new containers running the same service) to the NGINX configuration using <a href=\"https:\/\/github.com\/ehazlett\/interlock\">ehazlett\/interlock<\/a>.<\/p>\n<h2>Prerequisites<\/h2>\n<p>To follow this post and execute all the examples, you will need the following:<\/p>\n<ul>\n<li><strong>Docker Machine &gt;= 0.7.0<\/strong>: to provision Docker engines. You can obtain Docker Machine <a href=\"https:\/\/github.com\/docker\/machine\/releases\">here<\/a>.<\/li>\n<li><strong>Docker Compose &gt;= 1.7.1<\/strong>: to orchestrate the application\u2019s services.<\/li>\n<li><strong>Docker client &gt;= 1.11.1<\/strong>: for talking with the Swarm manager. You can obtain the Docker client <a href=\"https:\/\/github.com\/docker\/docker\/releases\/latest\">here<\/a>.<\/li>\n<li><strong>Digital Ocean API Token<\/strong>: to allow docker-machine to create machines on which to provision its engines. You can generate your token <a href=\"https:\/\/cloud.digitalocean.com\/settings\/api\/tokens\/new\">here<\/a>.<\/li>\n<\/ul>\n<h3>Creating the Swarm cluster<\/h3>\n<p>To begin, we need a Swarm cluster with these characteristics:<\/p>\n<ul>\n<li>At least one public-facing node to host the NGINX proxy. Multiple nodes can be created and balanced using DNS.<\/li>\n<li>At least one node to host the Swarm manager. Swarm has built-in HA, which is not needed for this tutorial. Implementing it is left as an exercise for the reader; see <a href=\"https:\/\/docs.docker.com\/swarm\/multi-manager-setup\/\">here<\/a>.<\/li>\n<li>At least one node to host the key\/value datastore. Here I used Consul. As for the Swarm manager, you might want to have at least three nodes for this in production. This kind of node is not in the Swarm cluster.<\/li>\n<\/ul>\n<p>To make this step easier, I created a script that creates all the required nodes on Digital Ocean.<\/p>\n<pre class=\"brush:php\">#!\/bin\/bash\r\n\r\n# nodes to create configuration\r\npublic_nodes=\"public01\"\r\nnodes=\"node01 node02 node03\"\r\n\r\n# Create the KV node using consul\r\ndocker-machine create \\\r\n    -d digitalocean \\\r\n    --digitalocean-access-token=$DO_ACCESS_TOKEN \\\r\n    consul\r\n\r\ndocker-machine ssh consul docker run -d \\\r\n    -p \"8500:8500\" \\\r\n    -h \"consul\" \\\r\n    progrium\/consul -server -bootstrap\r\n\r\nKV_IP=$(docker-machine ip consul)\r\nKV_ADDR=\"consul:\/\/${KV_IP}:8500\"\r\n\r\n# Create the Swarm Manager\r\necho \"Create swarm manager\"\r\ndocker-machine create \\\r\n    -d digitalocean \\\r\n    --digitalocean-access-token=$DO_ACCESS_TOKEN \\\r\n    --swarm --swarm-master \\\r\n    --swarm-discovery=$KV_ADDR \\\r\n    --engine-opt=\"cluster-store=${KV_ADDR}\" \\\r\n    --engine-opt=\"cluster-advertise=eth0:2376\" \\\r\n    manager\r\n\r\n# Create Public facing Swarm nodes\r\nfor node in $public_nodes; do\r\n    (\r\n    echo \"Creating ${node}\"\r\n\r\n    docker-machine create \\\r\n        -d digitalocean \\\r\n        --digitalocean-size \"4gb\" \\\r\n        --engine-label public=yes \\\r\n        --digitalocean-access-token=$DO_ACCESS_TOKEN \\\r\n        --swarm \\\r\n        --swarm-discovery=$KV_ADDR \\\r\n        --engine-opt=\"cluster-store=${KV_ADDR}\" \\\r\n        --engine-opt=\"cluster-advertise=eth0:2376\" \\\r\n        $node\r\n    ) &amp;\r\ndone\r\nwait\r\n\r\n# Create other Swarm nodes\r\nfor node in $nodes; do\r\n    (\r\n    echo \"Creating ${node}\"\r\n\r\n    docker-machine create \\\r\n        -d digitalocean \\\r\n        --digitalocean-size \"2gb\" \\\r\n        --engine-label public=no \\\r\n        --digitalocean-access-token=$DO_ACCESS_TOKEN \\\r\n        --swarm \\\r\n        --swarm-discovery=$KV_ADDR \\\r\n        --engine-opt=\"cluster-store=${KV_ADDR}\" \\\r\n        --engine-opt=\"cluster-advertise=eth0:2376\" \\\r\n        $node\r\n    ) &amp;\r\ndone\r\nwait\r\n\r\n# Print Cluster Information\r\necho \"\"\r\necho \"CLUSTER INFORMATION\"\r\necho \"Consul UI: http:\/\/${KV_IP}:8500\"\r\necho \"Environment variables to connect trough docker cli\"\r\ndocker-machine env --swarm manager<\/pre>\n<p>Just copy the script to a file named <code>create-swarm-cluster.sh<\/code> and give execution permissions with <code>chmod +x create-swarm-cluster.sh<\/code>. To execute the script, you will need to give it the previously generated Digital Ocean API token.<\/p>\n<pre class=\"brush:php\">export DO_ACCESS_TOKEN=&lt;your-digitalocean-api-token&gt;\r\n.\/create-swarm-cluster.sh<\/pre>\n<p>This is how our cluster looks:<\/p>\n<p><a href=\"http:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/06\/cluster.png\"><img decoding=\"async\" class=\"aligncenter wp-image-1446 size-large\" src=\"http:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/06\/cluster-1024x588.png\" alt=\"cluster\" width=\"620\" height=\"356\" srcset=\"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/06\/cluster-1024x588.png 1024w, https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/06\/cluster-300x172.png 300w, https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/06\/cluster-768x441.png 768w, https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/06\/cluster.png 1126w\" sizes=\"(max-width: 620px) 100vw, 620px\" \/><\/a><\/p>\n<p>Now that we have our cluster, we have to export the right environment variables to connect to it using our local Docker client. To do that:<\/p>\n<pre class=\"brush:php\">eval $(docker-machine env --swarm manager)<\/pre>\n<p>To verify that you are connected to the Swarm cluster:<\/p>\n<pre class=\"brush:php\">docker info | grep \"Server Version:\"<\/pre>\n<p>That should output something like:<\/p>\n<pre class=\"brush:php\">Server Version: swarm\/1.2.3<\/pre>\n<h2>Running Your Application into the Cluster<\/h2>\n<p>Now that our Swarm cluster is ready, we just need to start our application. For this purpose, I chose the super cool <a href=\"https:\/\/github.com\/docker\/example-voting-app\">Cats vs Dogs Voting Demo Application<\/a>.<\/p>\n<p>The application consists of three parts:<\/p>\n<ul>\n<li>The Voting Application, where you actually choose between cats and dogs<\/li>\n<li>The Result Application<\/li>\n<li>The worker, in charge of persisting votes in the Postgres database<\/li>\n<\/ul>\n<p>For dependencies, it has Postgres and Redis databases.<\/p>\n<p>In order to run our application, we\u2019re going to need a <code>docker-compose.yml<\/code> file that will start an instance of each microservice and the dependencies.<\/p>\n<pre class=\"brush:php\">version: \"2\"\r\n\r\nservices:\r\n  voting-app:\r\n    image: docker\/example-voting-app-voting-app:latest\r\n    ports:\r\n      - \"80\"\r\n    links:\r\n      - redis\r\n    networks:\r\n      - front-tier\r\n      - back-tier\r\n\r\n  result-app:\r\n    image: docker\/example-voting-app-result-app:latest\r\n    ports:\r\n      - \"80\"\r\n    links:\r\n      - db\r\n    networks:\r\n      - front-tier\r\n      - back-tier\r\n\r\n  worker:\r\n    image: docker\/example-voting-app-worker:latest\r\n    networks:\r\n      - back-tier\r\n\r\n  redis:\r\n    image: redis:alpine\r\n    ports: [\"6379\"]\r\n    networks:\r\n      - back-tier\r\n\r\n  db:\r\n    image: postgres:9.5\r\n    volumes:\r\n      - \"db-data:\/var\/lib\/postgresql\/data\"\r\n    networks:\r\n      - back-tier\r\n\r\nvolumes:\r\n  db-data:\r\n\r\nnetworks:\r\n  front-tier:\r\n  back-tier:<\/pre>\n<p>If you start it, you should obtain something like this:<\/p>\n<pre class=\"brush:php\">CONTAINER ID        IMAGE                                         COMMAND                  CREATED             STATUS              PORTS                                    NAMES\r\n266c4ec6c51d        docker\/example-voting-app-result-app:latest   \"node server.js\"         14 seconds ago      Up 10 seconds       104.236.XXX.XXX:32768-&gt;80\/tcp            node01\/nginxreverseproxy_result-app_1\r\n8cefe6ad38b9        docker\/example-voting-app-voting-app:latest   \"python app.py\"          14 seconds ago      Up 11 seconds       104.236.XXX.XXX:32769-&gt;80\/tcp             node02\/nginxreverseproxy_voting-app_1\r\ne04fa43c9909        redis:alpine                                  \"docker-entrypoint.sh\"   17 seconds ago      Up 14 seconds       104.236.XXX.XXX:32768-&gt;6379\/tcp           node02\/nginxreverseproxy_redis_1\r\n8e802ff973aa        postgres:9.5                                  \"\/docker-entrypoint.s\"   17 seconds ago      Up 14 seconds       5432\/tcp                                 node01\/nginxreverseproxy_db_1\r\ne434f6a9ff9c        docker\/example-voting-app-worker:latest       \"java -jar target\/wor\"   17 seconds ago      Up 15 seconds                                                public01\/nginxreverseproxy_worker_1<\/pre>\n<p>But hang on. We\u2019re not going to start <code>docker-compose.yml<\/code> because it\u2019s not suitable for a cluster. In fact:<\/p>\n<ul>\n<li>We don\u2019t have an entry point or a defined set of entry points which point to our DNS. If you look at the above output, you should note that things were scheduled without any specific constraint.<\/li>\n<li>Our Postgres database has a mounted volume bound to the node on which the container is running. But what happens if the container is rescheduled on another node?<\/li>\n<li>Front-end applications should be on the 80 or 443 ports, not on casual ones.<\/li>\n<li>If you scale web applications with <code>docker-compose scale<\/code>, those are not load balanced.<\/li>\n<\/ul>\n<p>!New Call-to-action<\/p>\n<p>So, one thing at a time: To solve the problem of the single entry point for our DNS servers, we are going to need an automated way to register our services into a proxy. In our case, we\u2019ll use NGINX and <a href=\"https:\/\/github.com\/ehazlett\/interlock\">ehazlett\/interlock<\/a> for this purpose.<\/p>\n<p>With Interlock, each time that a service is added or scaled, it will be added into the pool of the NGINX <code>proxy_pass<\/code> so that NGINX can route and balance request to the right containers. In this way, the single entry point for the HTTP requests made to the cluster will be the NGINX container that\u2019s bound to the <code>public01<\/code> node using the constraint: <code>constraint:node==public01<\/code>. This also solves the problem that, when scaling containers using <code>docker-compose scale<\/code>, requests across containers are balanced. You can always start more public nodes and balance them using DNS balancing.<\/p>\n<p>For the Postgres database, the only thing we can do here is to bind it to a specific node so that we can be sure that it is not rescheduled on another machine.<\/p>\n<p>Obviously this will increase the chances of failure \u2014 it\u2019s creating a single point of failure on the cluster. However, there\u2019s a way to run stateful services like databases in production by allowing your volumes to follow your containers. It\u2019s called Flocker, and unfortunately it was not suitable for this post, but you can learn more <a href=\"https:\/\/clusterhq.com\/flocker\/introduction\/\">here<\/a>.<\/p>\n<p>To set up this interlock, you will need this <code>docker-compose.yml<\/code>:<\/p>\n<pre class=\"brush:php\">interlock:\r\n    image: ehazlett\/interlock:master\r\n    command: -D run -c \/etc\/interlock\/config.toml\r\n    tty: true\r\n    ports:\r\n        - 8080\r\n    environment:\r\n        INTERLOCK_CONFIG: |\r\n            ListenAddr = \":8080\"\r\n            DockerURL = \"${SWARM_HOST}\"\r\n            TLSCACert = \"\/etc\/docker\/ca.pem\"\r\n            TLSCert = \"\/etc\/docker\/server.pem\"\r\n            TLSKey = \"\/etc\/docker\/server-key.pem\"\r\n            [[Extensions]]\r\n            Name = \"nginx\"\r\n            ConfigPath = \"\/etc\/nginx\/nginx.conf\"\r\n            PidPath = \"\/var\/run\/nginx.pid\"\r\n            TemplatePath = \"\"\r\n            MaxConn = 1024\r\n            Port = 80\r\n    volumes:\r\n        - \/etc\/docker:\/etc\/docker:ro\r\n\r\nnginx:\r\n    image: nginx:latest\r\n    entrypoint: nginx\r\n    command: -g \"daemon off;\" -c \/etc\/nginx\/nginx.conf\r\n    ports:\r\n        - 80:80\r\n    labels:\r\n        - \"interlock.ext.name=nginx\"\r\n    environment:\r\n        - \"constraint:node==public01<\/pre>\n<p>As you can see, we\u2019re starting an interlock container that can connect to the Swarm cluster and updates the <code>\/etc\/nginx\/nginx.conf<\/code> each time it\u2019s needed. Note that the NGINX container is bound to the <code>public01<\/code> node, so all our HTTP services will be accessible trough that node.<\/p>\n<p>To start this on your cluster:<\/p>\n<pre class=\"brush:php\">eval $(docker-machine env --swarm manager)\r\nexport SWARM_HOST=tcp:\/\/$(docker-machine ip manager):2376\r\ndocker-compose up -d<\/pre>\n<p>Now that our cluster is ready, we can change our application\u2019s <code>docker-compose.yml<\/code> to reflect our thoughts:<\/p>\n<pre class=\"brush:php\">version: \"2\"\r\n\r\nservices:\r\n  voting-app:\r\n    hostname: voting.local\r\n    image: docker\/example-voting-app-voting-app:latest\r\n    ports:\r\n      - \"80\"\r\n    links:\r\n      - redis\r\n    networks:\r\n      - front-tier\r\n      - back-tier\r\n    labels:\r\n      - \"interlock.hostname=voting\"\r\n      - \"interlock.domain=local\"\r\n\r\n  result-app:\r\n    hostname: result.local\r\n    image: docker\/example-voting-app-result-app:latest\r\n    ports:\r\n      - \"80\"\r\n    links:\r\n      - db\r\n    networks:\r\n      - front-tier\r\n      - back-tier\r\n    labels:\r\n      - \"interlock.hostname=result\"\r\n      - \"interlock.domain=local\"\r\n\r\n  worker:\r\n    image: docker\/example-voting-app-worker:latest\r\n    networks:\r\n      - back-tier\r\n\r\n  redis:\r\n    image: redis:alpine\r\n    ports: [\"6379\"]\r\n    networks:\r\n      - back-tier\r\n\r\n  db:\r\n    image: postgres:9.5\r\n    volumes:\r\n      - \"db-data:\/var\/lib\/postgresql\/data\"\r\n    networks:\r\n      - back-tier\r\n    environment:\r\n      - \"constraint:node==node01\"\r\n\r\nvolumes:\r\n  db-data:\r\n\r\nnetworks:\r\n  front-tier:\r\n  back-tier:<\/pre>\n<p>A few things are different now:<\/p>\n<ul>\n<li>The voting and result apps now have the <code>hostname<\/code> and the interlock\u2019s hostname and domain labels that are used by interlock to configure NGINX.<\/li>\n<li>The Postgres database now is bound to the <code>node01<\/code>.<\/li>\n<\/ul>\n<p>The last thing to do is to add the IP address of the <code>public01<\/code> node to your DNS records. For simplicity, you can add it to your local host\u2019s file. You can obtain the right host\u2019s line with this command:<\/p>\n<pre class=\"brush:php\">echo $(docker-machine ip public01) voting.local result.local<\/pre>\n<p>Now you can just run the applications with a <code>docker-compose up<\/code> and point your browser to <a href=\"http:\/\/voting.local\">http:\/\/voting.local<\/a> to choose your favorite pet! (Pro tip: Cats are the right choice.)<\/p>\n<h2>Conclusion<\/h2>\n<p>In this post, we achieved a few things in a relatively simple way by using just the official tools provided by Docker. The coolest achievement was that our entire cluster is now exposed as a single Docker daemon by the Swarm manager which also matches the definition of cluster you can find <a href=\"https:\/\/en.wikipedia.org\/wiki\/Computer_cluster\">on Wikipedia<\/a>:<\/p>\n<blockquote><p>A computer cluster consists of a set of loosely or tightly connected computers that work together so that, in many respects, they can be viewed as a single system.<\/p><\/blockquote>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td><span class=\"reference\">Reference: <\/span><\/td>\n<td><a href=\"https:\/\/blog.codeship.com\/nginx-reverse-proxy-docker-swarm-clusters\/\">NGINX as a Reverse Proxy for Docker Swarm Clusters<\/a> from our <a href=\"http:\/\/www.systemcodegeeks.com\/join-us\/scg\/\">SCG partner<\/a> Lorenzo Fontana at the <a href=\"http:\/\/blog.codeship.com\/\">Codeship Blog<\/a> blog.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Spawning services across multiple Docker engines is a very cool thing, but those services need to connect each other and be found by public-facing nodes in order to be routed to users. A way to achieve that is to use NGINX as a reverse proxy by defining one or more public-facing nodes. These nodes are &hellip;<\/p>\n","protected":false},"author":30,"featured_media":390,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[25],"tags":[42],"class_list":["post-1440","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-nginx","tag-docker"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>NGINX as a Reverse Proxy for Docker Swarm Clusters - System Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"Spawning services across multiple Docker engines is a very cool thing, but those services need to connect each other and be found by public-facing nodes\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"NGINX as a Reverse Proxy for Docker Swarm Clusters - System Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"Spawning services across multiple Docker engines is a very cool thing, but those services need to connect each other and be found by public-facing nodes\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/\" \/>\n<meta property=\"og:site_name\" content=\"System Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/systemcodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2016-06-24T14:15:10+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Lorenzo Fontana\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@systemcodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@systemcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lorenzo Fontana\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/\"},\"author\":{\"name\":\"Lorenzo Fontana\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/#\/schema\/person\/6bf501dc351e23902fa5ce76e8d9ae15\"},\"headline\":\"NGINX as a Reverse Proxy for Docker Swarm Clusters\",\"datePublished\":\"2016-06-24T14:15:10+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/\"},\"wordCount\":1144,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\",\"keywords\":[\"Docker\"],\"articleSection\":[\"NGINX\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/\",\"url\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/\",\"name\":\"NGINX as a Reverse Proxy for Docker Swarm Clusters - System Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\",\"datePublished\":\"2016-06-24T14:15:10+00:00\",\"description\":\"Spawning services across multiple Docker engines is a very cool thing, but those services need to connect each other and be found by public-facing nodes\",\"breadcrumb\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#primaryimage\",\"url\":\"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\",\"contentUrl\":\"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.systemcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Web Servers\",\"item\":\"https:\/\/www.systemcodegeeks.com\/category\/web-servers\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"NGINX\",\"item\":\"https:\/\/www.systemcodegeeks.com\/category\/web-servers\/nginx\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"NGINX as a Reverse Proxy for Docker Swarm Clusters\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/#website\",\"url\":\"https:\/\/www.systemcodegeeks.com\/\",\"name\":\"System Code Geeks\",\"description\":\"Operating System Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.systemcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.systemcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.systemcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/systemcodegeeks\",\"https:\/\/x.com\/systemcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/#\/schema\/person\/6bf501dc351e23902fa5ce76e8d9ae15\",\"name\":\"Lorenzo Fontana\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.systemcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/77998050e0fdf5690e39484755e1adbaee5e4bffc412e55bd0894f0b171ed5c9?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/77998050e0fdf5690e39484755e1adbaee5e4bffc412e55bd0894f0b171ed5c9?s=96&d=mm&r=g\",\"caption\":\"Lorenzo Fontana\"},\"description\":\"Lorenzo Fontana is a DevOps Expert at Kiratech.\",\"url\":\"https:\/\/www.systemcodegeeks.com\/author\/lorenzo-fontana\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"NGINX as a Reverse Proxy for Docker Swarm Clusters - System Code Geeks - 2026","description":"Spawning services across multiple Docker engines is a very cool thing, but those services need to connect each other and be found by public-facing nodes","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/","og_locale":"en_US","og_type":"article","og_title":"NGINX as a Reverse Proxy for Docker Swarm Clusters - System Code Geeks - 2026","og_description":"Spawning services across multiple Docker engines is a very cool thing, but those services need to connect each other and be found by public-facing nodes","og_url":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/","og_site_name":"System Code Geeks","article_publisher":"https:\/\/www.facebook.com\/systemcodegeeks","article_published_time":"2016-06-24T14:15:10+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","type":"image\/jpeg"}],"author":"Lorenzo Fontana","twitter_card":"summary_large_image","twitter_creator":"@systemcodegeeks","twitter_site":"@systemcodegeeks","twitter_misc":{"Written by":"Lorenzo Fontana","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#article","isPartOf":{"@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/"},"author":{"name":"Lorenzo Fontana","@id":"https:\/\/www.systemcodegeeks.com\/#\/schema\/person\/6bf501dc351e23902fa5ce76e8d9ae15"},"headline":"NGINX as a Reverse Proxy for Docker Swarm Clusters","datePublished":"2016-06-24T14:15:10+00:00","mainEntityOfPage":{"@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/"},"wordCount":1144,"commentCount":0,"publisher":{"@id":"https:\/\/www.systemcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#primaryimage"},"thumbnailUrl":"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","keywords":["Docker"],"articleSection":["NGINX"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/","url":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/","name":"NGINX as a Reverse Proxy for Docker Swarm Clusters - System Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.systemcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#primaryimage"},"image":{"@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#primaryimage"},"thumbnailUrl":"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","datePublished":"2016-06-24T14:15:10+00:00","description":"Spawning services across multiple Docker engines is a very cool thing, but those services need to connect each other and be found by public-facing nodes","breadcrumb":{"@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#primaryimage","url":"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","contentUrl":"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.systemcodegeeks.com\/web-servers\/nginx\/nginx-reverse-proxy-docker-swarm-clusters\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.systemcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Web Servers","item":"https:\/\/www.systemcodegeeks.com\/category\/web-servers\/"},{"@type":"ListItem","position":3,"name":"NGINX","item":"https:\/\/www.systemcodegeeks.com\/category\/web-servers\/nginx\/"},{"@type":"ListItem","position":4,"name":"NGINX as a Reverse Proxy for Docker Swarm Clusters"}]},{"@type":"WebSite","@id":"https:\/\/www.systemcodegeeks.com\/#website","url":"https:\/\/www.systemcodegeeks.com\/","name":"System Code Geeks","description":"Operating System Developers Resource Center","publisher":{"@id":"https:\/\/www.systemcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.systemcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.systemcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.systemcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.systemcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.systemcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.systemcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/systemcodegeeks","https:\/\/x.com\/systemcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.systemcodegeeks.com\/#\/schema\/person\/6bf501dc351e23902fa5ce76e8d9ae15","name":"Lorenzo Fontana","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.systemcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/77998050e0fdf5690e39484755e1adbaee5e4bffc412e55bd0894f0b171ed5c9?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/77998050e0fdf5690e39484755e1adbaee5e4bffc412e55bd0894f0b171ed5c9?s=96&d=mm&r=g","caption":"Lorenzo Fontana"},"description":"Lorenzo Fontana is a DevOps Expert at Kiratech.","url":"https:\/\/www.systemcodegeeks.com\/author\/lorenzo-fontana\/"}]}},"_links":{"self":[{"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/posts\/1440","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/users\/30"}],"replies":[{"embeddable":true,"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/comments?post=1440"}],"version-history":[{"count":0,"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/posts\/1440\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/media\/390"}],"wp:attachment":[{"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/media?parent=1440"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/categories?post=1440"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.systemcodegeeks.com\/wp-json\/wp\/v2\/tags?post=1440"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}