Gaming industry under DDoS attack. Get DDoS protection now. Start onboarding
  1. Home
  2. Developers
  3. How to Nginx Reverse Proxy with Docker Compose

How to Nginx Reverse Proxy with Docker Compose

  • By Gcore
  • March 31, 2023
  • 4 min read
How to Nginx Reverse Proxy with Docker Compose

While developing a web application, a common method of calling the application from a local machine is through http://localhost:x ports, which essentially means that we are required to expose several ports to access different modules of the application. In the article below, we will go through the method of using Reverse Proxy to call an application and the benefits of using it.

Why do we need Reverse Proxy?

The most prominent reason of using Reverse Proxy is to avoid changing ports everytime you try to access different modules of the application through the same URL. Through Reverse Proxy we can reach Frontend, Backend or other services without changing port through a single domain. Other important reasons of using Reverse Proxy is to mask services behind a proxy and avoid dealing with CORS issues.

# Without Reverse Proxy# Domain Name: http://mydomain.com# Mysql wordpress: http://mydomain.com:10088# Angular app: http://mydomain.com:7787# Backend: https://mydomain:9876
# With Reverse Proxy# Domain Name: http://mydomain.com# Mysql wordpress: http://mydomain.com/db# Angular app: http://mydomain.com/ang# Backend: https://mydomain/wp

Prerequisites

  • Docker Compose on Linux
  • iptables should be enabled. Note that Docker uses iptables to access incoming connections.

Building docker-compose.yml

For the reference of this article, let us create a WordPress-MySQL server with Nginx in one service. Start by creating the docker container, along with defining ports, base image, container name and service names.

version: '2'services:  whilefly_wp:    container_name: production_wp    image: nginx:latest    volumes:      - "/home/xx/Desktop/cust/xx/html:/var/www/html"      - "/home/xx/Desktop/cust/xx/Docker/logs:/logs"      - "/home/xx/Desktop/cust/xx/Docker/database:/docker-entrypoint-initdb.d"      - "xx_db_data:/var/lib/mysql"    user: root    restart: always    ports:      - "8081:80"    environment:      MYSQL_ROOT_PASSWORD: 'xxxxx'      MYSQL_DATABASE: 'production_db'      MYSQL_USER: 'production_admin'      MYSQL_PASSWORD: 'xxxxxx'        nginx:    image: nginx:latest    container_name: production_nginx    volumes:      - /home/xx/Desktop/cust/xx/Docker/nginx/reverse_proxy.conf:/etc/nginx/conf.d/default.conf      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.pem:/etc/nginx/cert/star_xx_com.pem      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.key:/etc/nginx/cert/star_xx_com.key      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.crt:/etc/nginx/cert/star_xx_com.crt    ports:      - 8080:8080      - 443:443    links:     - whilefly_wpvolumes:  xx_db_data:

Let’s explain the setup in steps.

  1. services command defines the service you will build in Docker.
version: '2'services:  running_wp:     nginx:
  1. As shown below, the running_wp service uses nginx:latest as the base image. You can also use your own custom image for MySQL and WordPress. Next is to assign a container name, for instance currently production_wp is used below. Copy the local files under volume section to the given directory while building this docker image. It is important to assign Ports which are to be used for accessibility within or outside of the application. As shown below, we have mapped 8081 host to 80 port for container.
version: '2'services:  running_wp:    container_name: production_wp    image: boraozkan/nginx:latest    volumes:      - "/home/xx/Desktop/cust/xx/html:/var/www/html"      - "/home/xx/Desktop/cust/xx/Docker/logs:/logs"      - "/home/xx/Desktop/cust/xx/Docker/database:/docker-entrypoint-initdb.d"      - "xx_db_data:/var/lib/mysql"    user: root    restart: always    ports:      - "8081:80"    environment:      MYSQL_ROOT_PASSWORD: 'xxxxx'      MYSQL_DATABASE: 'production_db'      MYSQL_USER: 'production_admin'      MYSQL_PASSWORD: 'xxxxxx'
  1. Assign necessary access credentials with environment command.
environment:      MYSQL_ROOT_PASSWORD: 'xxxxx'      MYSQL_DATABASE: 'production_db'      MYSQL_USER: 'production_admin'      MYSQL_PASSWORD: 'xxxxxx'
  1. Assign the base image and container name. Base image will create Nginx on the first run. You can also add encrypted SSL files through https://letsencrypt.org/, it is free.
version: '2'  nginx:    image: nginx:latest    container_name: production_nginx    volumes:      - /home/xx/Desktop/cust/xx/Docker/nginx/reverse_proxy.conf:/etc/nginx/conf.d/default.conf      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.pem:/etc/nginx/cert/star_xx_com.pem      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.key:/etc/nginx/cert/star_xx_com.key      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.crt:/etc/nginx/cert/star_xx_com.crt    ports:      - 8080:8080      - 443:443    links:     - running_wpvolumes:  xx_db_data:
  1. Add Nginx configuration file under conf.d path – this is the default directory for virtual host descriptions.
/home/xx/Desktop/cust/xx/Docker/nginx/reverse_proxy.conf:/etc/nginx/conf.d/default.conf
  1. As shown below there are two parts of this config file. First one shows the server side defining which port will be listened by the Nginx Container (8080 and 443). Secondly, the forward traffic would be directed to port 8081 – this is the port of production container for reaching.
# re-route everything to production_wp server {  listen 8080;  server_name production_wp;    error_page 497 http://$host:80$request_uri;  ssl on;  ssl_certificate /etc/nginx/cert/star_xx_com.crt;  ssl_certificate_key /etc/nginx/cert/star_xx_com.key;  location /wp {    proxy_pass          http://localhost:8081/wp;     rewrite /wp(.*) /origin-d$1            proxy_pass http://localhost:8081;            proxy_redirect / /wp;            sub_filter 'href="/' 'href="/wp'      }  }# wordpress container via production_wp server {  listen 443;  server_name production_wp;  error_page 497 http://$host:80$request_uri;
  1. Enable secure HTTP with the ssl on command.
ssl on;  ssl_certificate /etc/nginx/cert/star_xx_com.crt;  ssl_certificate_key /etc/nginx/cert/star_xx_com.key;
  1. To prefix headers for proxy connections, we can use the proxy_set_header directive which helps in redefining or appending fields to the request header passed through the proxied server.
proxy_set_header    X-Forwarded-Host   $host;proxy_set_header    X-Forwarded-Server $host;proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;proxy_set_header    X-Forwarded-Proto  $scheme;proxy_set_header    X-Real-IP          $remote_addr;proxy_set_header    Host               $host;
  1. For Reverse Proxy as mentioned in the beginning, we will give a path for the WordPress container in Nginx conf. Let us say it is using e.g.,
    http://localhost/wp
    to
    http://localhost:8081
    which is asymmetric path.
location /wp {proxy_pass          http://localhost:8081/wp;rewrite /wp(.*) /origin-d$1proxy_pass http://localhost:8081;proxy_redirect / /wp;sub_filter 'href="/' 'href="/wp'}
  1. Now we can start our containers with the command below. Remember to be in same path with docker-compose.yaml while starting containers.
docker-compose up -d 
  1. The docker-compose up command is a shorthand form of docker-compose build and docker-compose run.
#docker-compose up -dPulling nginx (nginx:latest)...2.1: Pulling from nginx:latestb8f262c62ec6: Pulling fs layera98660e7def6: Pulling fs layer4d75689ceb37: Pulling fs layer639eb0368afa: Waiting99e337926e9c: Waiting431d44b3ce98: Waitingbeb665ea0e0e: Pulling fs layerc98a22d85c62: Waitingbf70d116f1d7: Waiting97f2d71621e0: Waitingea02a46a87c8: Waiting78fff17c3a50: Waiting
  1. When complete, we should have two containers deployed, one of which we cannot access directly:
$ docker psCONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                                      NAMES9c327bb01a85       nginx:latest             "nginx -g 'daemon of…"   8 minutes ago       Up 8 minutes        0.0.0.0:8080->8080/tcp, 0.0.0.0:443->443/tcp   production_nginx3823ce1f25d8        boraozkan/nginx:latest   "/usr/bin/supervisord"   8 minutes ago       Up 8 minutes        3306/tcp, 0.0.0.0:8081->80/tcp             production_wp
  1. We can check our applications (one with Nginx and the other one with Apache).
    Navigate to
    http://localhost:8080
    , and this will hit Nginx Reverse Proxy which will in turn will load the Nginx web application:
  1. Also check with navigating to
    http://localhost:8081
    or
    http://localhost/wp
    , through the Nginx Reverse Proxy asymmetric path and the Apache web application will be loaded:

Troubleshooting

Once the services are up, try to connect your web application to the localhost link. If it is not answered, check your iptables table for correctness.

By default Docker containers can make connections to the outside world, but the outside world cannot connect to containers. Each outgoing connection will appear to originate from one of the host machine’s own IP addresses thanks to an iptables masquerading rule on the host machine that the Docker server creates when it starts:

$ sudo iptables -t nat -L -n...Chain POSTROUTING (policy ACCEPT)target     prot opt source               destinationMASQUERADE  all  --  172.17.0.0/16       0.0.0.0/0

Conclusion

This article is aimed to show how you can use Nginx with docker-compose easily. It also shows setting of Reverse Proxy configuration on containers. Using this will give you additional flexibility during deployment of a web application.

Explore Gcore Container as a Service

Related articles

What's the difference between multi-cloud and hybrid cloud?

Multi-cloud and hybrid cloud represent two distinct approaches to distributed computing architecture that build upon the foundation of cloud computing to help organizations improve their IT infrastructure.Multi-cloud environments involve us

What is multi-cloud? Strategy, benefits, and best practices

Multi-cloud is a cloud usage model where an organization utilizes public cloud services from two or more cloud service providers, often combining public, private, and hybrid clouds, as well as different service models, such as Infrastructur

What is cloud migration? Benefits, strategy, and best practices

Cloud migration is the process of transferring digital assets, such as data, applications, and IT resources, from on-premises data centers to cloud platforms, including public, private, hybrid, or multi-cloud environments. Organizations can

What is a private cloud? Benefits, use cases, and implementation

A private cloud is a cloud computing environment dedicated exclusively to a single organization, providing a single-tenant infrastructure that improves security, control, and customization compared to public clouds.Private cloud environment

What is a cloud GPU? Definition, types, and benefits

A cloud GPU is a remotely rented graphics processing unit hosted in a cloud provider's data center, accessible over the internet via APIs or virtual machines. These virtualized resources allow users to access powerful computing capabilities

What is cloud networking: benefits, components, and implementation strategies

Cloud networking is the use and management of network resources, including hardware and software, hosted on public or private cloud infrastructures rather than on-premises equipment. Over 90% of enterprises are expected to adopt cloud netwo

Subscribe to our newsletter

Get the latest industry trends, exclusive insights, and Gcore updates delivered straight to your inbox.