Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

Reading Time: 6 minutes
Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

Sometimes, developing a full-stack application is not the end of the journey for a web developer. Let us take a case scenario whereby, you have a backend, a frontend, and also a database. For such a setup, we would like to make it easy to replicate our application in different environments let’s say development, staging, and production. It will be painful trying to configure each environment and each layer of the application separately. This is where multi-container docker comes in.

In this blog, we will cover:

  • Multi-Container Docker with Docker Compose
  • What Is a Reverse Proxy & Why to Use?
  • Nginx as a Reverse Proxy
  • Hands-On
  • Conclusion

Multi-Container Docker with Docker Compose

In Docker, you can have multiple containers running on the same host, each providing a different service. But managing these different containers manually can be complex. This is where Docker Compose comes into the picture. Docker Compose is a tool for creating and managing Docker applications that run in many containers. In our case, we have three layers in our application; the frontend, the backend, and the database. We can treat these as Docker Compose services.

Docker Compose uses YAML files to configure application services. This means you can define how services are built, what ports they expose, and how they are linked together in a clear, concise file, typically named docker-compose.yml. You can even go further and define the networking for your multiple containers.

What Is a Reverse Proxy & Why to Use?

A reverse proxy acts as an intermediary (proxy) between a user (client) submitting a request to that proxy and that proxy submitting requests and retrieving results from other servers.

A reverse proxy is a proxy server positioned behind a private network’s firewall that safeguards the server rather than the clients. Its main function is to intercept incoming traffic and route requests to the relevant server on the backend. The key purposes of using a reverse proxy are to enhance security and performance. By directing all network requests through specified ports, it becomes possible to manage services running on multiple pods. Furthermore, reverse proxies can handle SSL encryption, data caching, and compression.

Nginx as a Reverse Proxy

We will use Nginx as a reverse proxy server and also as a load balancer. A reverse proxy server is a server that handles requests from clients on behalf of a group of backend servers. It receives client requests, does some processing, and forwards them to the appropriate server within the internal network. When the backend server responds, the reverse proxy server sends the response back to the client.

Nginx can also introduce load-balancing capabilities as well as SSL termination which will also be covered in this blog.

Hands-On

The code used in this blog is found at https://github.com/workfall/workfall-chatgpt-be and https://github.com/workfall/workfall-chatgpt-fe for the backend and frontend respectively.

Architecture

Our application will be a multi-container architecture with each Docker Compose service describing a single layer of the application. The application will have Nginx as an API gateway and reverse proxy. Nginx will also carry out SSL termination. The backend repository will host all the logic. 

Both the backend and the frontend app will be containerized separately and then the images pulled in the docker-compose.yml from a docker registry; in this case Docker Hub. We shall use GitHub Actions to build and push the docker images to Docker Hub.

Folder Structure

Backend

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

The Nginx configurations hold the configs for the Nginx reverse proxy/API gateway.

.github/workflows/main.yml(1):

Note: All GitHub secrets should be added to your repository under the settings tab. The pipelines will not work if the secrets are missing. In a previous blog, we tackled how to obtain the Docker username and Docker Access Token. 

In this workflow, we are building the backend application/API and pushing the image to Docker Hub.

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx


.github/workflows/main.yml(2):

In this job, we are copying the nginx configuration and the docker-compose.yml to the server and at the same time deploying the application using docker-compose. Docker Compose will create the necessary resources such as volumes and networks to spin up our multi-container application.

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

.github/workflows/main.yml(3):

nginx/nginx.conf(1):

In this case, we are using Nginx as a reverse proxy and also as an API gateway. We shall also carry out SSL termination. Make sure that the SSL certificates are available on the server in the directory specified by the docker-compose.yml.

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

nginx/nginx.conf(2):

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

Dockerfile:

This Dockerfile creates an image for our backend application.

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

docker-compose.yml(1):

This file describes configs for our services i.e. containers that will run to make up our multi-container application. We expose the required ports, declare environment variables, define restart policy, networks, and also start-up order using the depends_on key.

For example, we tell the frontend app to wait for the API to start. If the API fails to start, the frontend app will not start. 

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

docker-compose.yml(2):

In this case, we used an example of how we can start a database service and it is important to not always persist the database to a volume on the server disk. Containers are volatile and you will lose your data if an error occurs or if a new container is created.

Frontend

.github/workflows/main.yml(1):

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

.github/workflows/main.yml(2):

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

.github/workflows/main.yml(3):

Dockerfile:

Reverse Proxy Mastery: Deploying a Full-Stack Application with Multi-Container Docker and Nginx

nginx/nginx.conf:

Conclusion

In this blog, we have demonstrated how using Docker Compose in conjunction with Nginx as a reverse proxy can greatly simplify the deployment and management of multi-container applications. Docker Compose allows you to define and configure multiple services, such as web servers, databases, and backend services, in a single YAML file, making it easier to orchestrate and scale your application.

Nginx acts as an intermediary between clients and backend servers, enabling load balancing, caching, SSL termination, and other advanced features. It helps distribute client requests across multiple backend servers, improving scalability and ensuring high availability.

Additionally, Docker Compose’s ability to define and manage the configuration of your multi-container application simplifies deployment and eliminates potential configuration discrepancies across different environments. With a single command, you can bring up your entire application stack, including Nginx as the reverse proxy, and have it ready to serve client requests. We will come up with more such use cases in our upcoming blogs.

Meanwhile…

If you are a Full-stack enthusiast and want to explore more about the above topics, here are a few of our blogs for your reference:

Stay tuned to get all the updates about our upcoming blogs on the cloud and the latest technologies.

Keep Exploring -> Keep Learning -> Keep Mastering


At Workfall, we strive to provide the best tech and pay opportunities to kickass coders around the world. If you’re looking to work with global clients, build cutting-edge products, and make big bucks doing so, give it a shot at workfall.com/partner today!

Back To Top