title: docker-compose an app behind a reverse-proxy that can also access external services
body: <p>On a local server I started several instances of gunicorn each running a different web app on a unique port as a service to the rest of the internal network. Now I want to put each instance of gunicorn behind its own nginx reverse-proxy server for better load balancing. </p>
  
  <p>I decided to try to deploy each (nginx, gunicorn) pair in its own Docker container, exposing only its unique port to the outside world. I know that's easy enough with port-forwarding - for example "5555:80". However, each app also accesses external services, such as databases, that run on the same host independently of Docker. </p>
  
  <p>Through trial and error, I found that a Docker container can access an external service (e.g. MySQL, or MongoDB) only if I run it as "docker run --network=host ...". This has the effect letting the container share the the host network, but it also exposes any ports  gunicorn opens, which means that it leaves a way for a client to circumvent the reverse-proxy. While this is all running on a local server on a secure network, it doesn't seem like a good security practice, as it leaves the back-end open to denial-of-service attacks. </p>
  
  <p>So I guess I want the best of both worlds - I want each (proxy, gunicorn) pair to talk with one another over a private network that only they use, while I expose one port (e.g. "5555") to the network, and the web app running under gunicorn can still access other services on the same host. </p>
  
  <p>My nginx.conf would look something like this:</p>
  
  <pre><code>http {
      upstream app {
          server network1_app;
      }
  
      server {
          location / {
              proxy_pass  http://app;
          }
      }
  }
  </code></pre>
  
  <p>And my docker-compose.yml might look something like:</p>
  
  <pre><code>version: "3"
  services:
  
    proxy:
      image: nginx:alpine
      networks:
        - host
        - network1
      volumes:
        ./nginx.conf:/etc/nginx/nginx.conf:ro
  
    app:
      build: ./app
      networks:
        - network1
      ports: "5555:80" # Do I have to associate this with the "host" network somehow?
  
    networks:
      network1:
  </code></pre>
  
  <p>Then deploy this with </p>
  
  <pre><code>docker stack deploy network1 -c docker-compose.yml
  </code></pre>
  
  <p>Am I on the right path, or am I making it too complicated? Would it be more straightforward not to use Docker at all for this? Instead, I could create named sockets for this. </p>
  
  <p>I like using docker-compose if I can, because it encapsulates some of the details and makes management easier (if it works). It also leaves less surface for a security breach.</p>