How to run multiple Docker projects under port 80 using an off-the-shelf local Reverse Proxy

How to run multiple Docker projects under port 80 using an off-the-shelf local Reverse Proxy

You might have had to run two or more Docker projects on a local machine at some point. This is a common task for developers if you have multiple projects or you are using a microservices architecture.

However, working with multiple Docker projects, you might have encountered some issues:

  • Containers (nginx/apache) from different projects can conflict because they all try to use the standard HTTP port (80 or 443 for HTTPS). Only one container can listen to a port at a time.
  • Difficulties with external integrations or with the project itself can arise if it is not on port 80/443. For example, you might need to access it via http://wp-yoda.local:8080/.
    In these cases, changes may need to be made to the project’s code for it to work correctly or to coordinate with the support team.
  • A WordPress Multisite setup will not run on any port other than 80/443, meaning you can’t run more than 2 WordPress Multisite instances locally on Docker.

The solution to these problems is the use of a local Reverse Proxy, which allows receiving requests on port 80 and redirecting them to the corresponding Docker containers running on different ports. This not only solves the port conflict issue but also enables the use of custom local URLs for accessing projects without additional problems, adding convenience to the workflow.

In this article, I will explore how a local Reverse Proxy in Go, which I wrote to handle two or more Docker projects on port 80, works. You will learn how to easily and efficiently manage access to multiple containers using a single standard port, and how to eliminate the need for additional configuration of each project to work in such an environment.

How is it work

How to run multiple Docker projects under port 80 using an off-the-shelf local Reverse Proxy - diagram.
The diagram of how Local Reverse Proxy works.
  • Client is you.
  • hosts file is a file that contains all the desired local domains, which should be directed to the IP address 127.0.0.1. Your local DNS.
  • Reverse Proxy listens on port 80 and proxies requests to Docker containers based on specific rules, which are described in services.json (more on this later).
  • Target Server (Docker App) – this is our Docker project. There can be multiple such projects, as many as you need to run simultaneously.
    The main task is to specify different ports for different Docker projects in Apache or Nginx.

About ports:
In the context of computer networks, if one process (container) is “listening” to or receiving data on a specific port, another process cannot use the same port on the same interface for listening or receiving data. This prevents conflicts and ensures that data intended for a particular application or service is correctly routed to it.

0.1.1 version of Local Reverse Proxy works only on port 80, 443 port is not supported on this version.

From ‘request’ to ‘response’

  1. When you enter a request in the browser, such as http://example.local, the OS routing initially finds the domain’s corresponding IP in the /etc/hosts file.
  2. Then, a request is made to this IP – 127.0.0.1 and port 80 with the domain example.local in the header.
  3. Port 80 is already being listened to by our Reverse Proxy, and it receives this request.
  4. Next, the Local Reverse Proxy extracts the domain from the request and searches for it in the services.json file, which contains an object with a list of domains and where to proxy them:
    • "Domain": "Address to a docker container"
    • "example.local": "http://localhost:8080"
{
  "pbnwp.loc": "http://localhost:8080",
  "*.local": "http://localhost:8090"
}

You can also use wildcards, such as *.local. This would mean to proxy all requests to *.local domains to the http://localhost:8090 container.
  1. And our Docker application, which, for example, has Nginx exposed on port 8080, receives this request from our Local Reverse Proxy at http://localhost:8080. Inside, the container thinks it’s operating on port 80.
  2. After that, the Docker application handles the request and sends a response to the Local Reverse Proxy.
  3. Local Reverse Proxy in turn returns the response to a client.

Your main task will be to configure an external port for nginx/apache in your Docker project that is different from 80 and does not conflict with the port of another Docker project. You can use ports such as 8080, 8090, etc.

Step-by-Step Guide on Setting Up and Running a Local Reverse Proxy

For a step-by-step guide on how to launch and configure a local Reverse Proxy, including the full steps for setting up Local Reverse Proxy and Docker projects, you can refer to the project’s GitHub repository.

Practical application

In our projects, we use this solution in the team to work with two Docker projects under port 80 simultaneously, without additional configurations and script rewrites.

Among the conveniences: we no longer need to stop one Docker project and start another to check something on the other project. This, in turn, has reduced the number of errors during development and increased comfort when working with projects. There’s no need to remember which ports the projects are on, as they are now always directly accessible by domain. Also, we connect a 3rd Docker project when we need to run a microservice.

Among the significant advantages, it’s worth noting that to add a new domain, you don’t need to recompile the application. It’s enough to simply add a new domain in services.json, as well as in the hosts file, and you can immediately start making requests. This is possible because the services.json file is read at runtime.

You can also use Nginx as a local Reverse Proxy. However, it will require configuration and restarting, which in our case turned out to be inconvenient.

Leave a Reply

Your email address will not be published. Required fields are marked *