{{announcement.body}}
{{announcement.title}}

How to NGINX Reverse Proxy with Docker Compose

DZone 's Guide to

How to NGINX Reverse Proxy with Docker Compose

Take a look at how to use NGINX reverse proxy with Docker Compose to expose multiple services without changing ports.

· Cloud Zone ·
Free Resource

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 obvious reason for using Reverse Proxy is to avoid changing ports every time 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. Another important reason for using Reverse Proxy is to mask services behind a proxy and avoid dealing with CORS issues.

Plain Text
 






Plain Text
 




xxxxxxxxxx
1


 
1
# With Reverse Proxy 
2
# Domain Name: http://mydomain.com 
3
# Mysql wordpress: http://mydomain.com/db 
4
# Angular app: http://mydomain.com/ang 
5
# 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 reference for 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.

Shell
 




xxxxxxxxxx
1
37


 
1
version: '2'
2
 
          
3
services:
4
  whilefly_wp:
5
    container_name: production_wp
6
    image: nginx:latest
7
    volumes:
8
      - "/home/xx/Desktop/cust/xx/html:/var/www/html"
9
      - "/home/xx/Desktop/cust/xx/Docker/logs:/logs"
10
      - "/home/xx/Desktop/cust/xx/Docker/database:/docker-entrypoint-initdb.d"
11
      - "xx_db_data:/var/lib/mysql"
12
    user: root
13
    restart: always
14
    ports:
15
      - "8081:80"
16
    environment:
17
      MYSQL_ROOT_PASSWORD: 'xxxxx'
18
      MYSQL_DATABASE: 'production_db'
19
      MYSQL_USER: 'production_admin'
20
      MYSQL_PASSWORD: 'xxxxxx'
21
      
22
  nginx:
23
    image: nginx:latest
24
    container_name: production_nginx
25
    volumes:
26
      - /home/xx/Desktop/cust/xx/Docker/nginx/reverse_proxy.conf:/etc/nginx/conf.d/default.conf
27
      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.pem:/etc/nginx/cert/star_xx_com.pem
28
      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.key:/etc/nginx/cert/star_xx_com.key
29
      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.crt:/etc/nginx/cert/star_xx_com.crt
30
    ports:
31
      - 8080:8080
32
      - 443:443
33
    links:
34
     - whilefly_wp
35
 
          
36
volumes:
37
  xx_db_data:



Let's explain the setup in steps.

  1. services command defines the service you will build in Docker.
Shell
 






2. 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. 

Shell
 




xxxxxxxxxx
1
19


 
1
version: '2'
2
services:
3
  running_wp:
4
    container_name: production_wp
5
    image: boraozkan/nginx:latest
6
    volumes:
7
      - "/home/xx/Desktop/cust/xx/html:/var/www/html"
8
      - "/home/xx/Desktop/cust/xx/Docker/logs:/logs"
9
      - "/home/xx/Desktop/cust/xx/Docker/database:/docker-entrypoint-initdb.d"
10
      - "xx_db_data:/var/lib/mysql"
11
    user: root
12
    restart: always
13
    ports:
14
      - "8081:80"
15
    environment:
16
      MYSQL_ROOT_PASSWORD: 'xxxxx'
17
      MYSQL_DATABASE: 'production_db'
18
      MYSQL_USER: 'production_admin'
19
      MYSQL_PASSWORD: 'xxxxxx'


3. Assign necessary access credentials with the environment command. 

Shell
 




xxxxxxxxxx
1


 
1
environment:
2
      MYSQL_ROOT_PASSWORD: 'xxxxx'
3
      MYSQL_DATABASE: 'production_db'
4
      MYSQL_USER: 'production_admin'
5
      MYSQL_PASSWORD: 'xxxxxx'


4. Assign the base image and container name. The base image will create NGINX on the first run. You can also add encrypted SSL files through https://letsencrypt.org/; it is free.

Shell
 




xxxxxxxxxx
1
17


 
1
version: '2'
2
  nginx:
3
    image: nginx:latest
4
    container_name: production_nginx
5
    volumes:
6
      - /home/xx/Desktop/cust/xx/Docker/nginx/reverse_proxy.conf:/etc/nginx/conf.d/default.conf
7
      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.pem:/etc/nginx/cert/star_xx_com.pem
8
      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.key:/etc/nginx/cert/star_xx_com.key
9
      - /home/xx/Desktop/cust/xx/Docker/nginx/cert/star_xx_com.crt:/etc/nginx/cert/star_xx_com.crt
10
    ports:
11
      - 8080:8080
12
      - 443:443
13
    links:
14
     - running_wp
15
 
          
16
volumes:
17
  xx_db_data:


5. Add NGINX configuration file under conf.d path - this is the default directory for virtual host descriptions.

Plain Text
 




xxxxxxxxxx
1


1
/home/xx/Desktop/cust/xx/Docker/nginx/reverse_proxy.conf:/etc/nginx/conf.d/default.conf


6. 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. 

Shell
 




xxxxxxxxxx
1
27


 
1
# re-route everything to production_wp
2
 server {
3
  listen 8080;
4
  server_name production_wp;
5
  
6
  error_page 497 http://$host:80$request_uri;
7
 
          
8
  ssl on;
9
  ssl_certificate /etc/nginx/cert/star_xx_com.crt;
10
  ssl_certificate_key /etc/nginx/cert/star_xx_com.key;
11
 
          
12
  location /wp {
13
    proxy_pass          http://localhost:8081/wp;
14
     rewrite /wp(.*) /origin-d$1
15
            proxy_pass http://localhost:8081;
16
            proxy_redirect / /wp;
17
            sub_filter 'href="/' 'href="/wp'
18
    
19
  }  
20
}
21
 
          
22
# wordpress container via production_wp
23
 server {
24
  listen 443;
25
  server_name production_wp;
26
 
          
27
  error_page 497 http://$host:80$request_uri;


7. Enable secure HTTP with the ssl on command. 

Shell
 






8. 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.

Shell
 




xxxxxxxxxx
1


 
1
proxy_set_header    X-Forwarded-Host   $host; 
2
proxy_set_header    X-Forwarded-Server $host; 
3
proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for; 
4
proxy_set_header    X-Forwarded-Proto  $scheme; 
5
proxy_set_header    X-Real-IP          $remote_addr; 
6
proxy_set_header    Host               $host;


9. For Reverse Proxy as mentioned in the beginning, we will give a path for the Wordpress container in NGINX configuration. Let us say it is using http://localhost/wp to http://localhost:8081, which is an asymmetric path. 

Shell
 




xxxxxxxxxx
1


 
1
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' }


10. Now we can start our containers with the command below. Remember to be in same path with docker-compose.yaml while starting containers. 

Shell
 






11. The  docker-compose up  command is a shorthand form of  docker-compose build  and  docker-compose run 

Shell
 




xxxxxxxxxx
1
15


 
1
#docker-compose up -d
2
Pulling nginx (nginx:latest)...
3
2.1: Pulling from nginx:latest
4
b8f262c62ec6: Pulling fs layer
5
a98660e7def6: Pulling fs layer
6
4d75689ceb37: Pulling fs layer
7
639eb0368afa: Waiting
8
99e337926e9c: Waiting
9
431d44b3ce98: Waiting
10
beb665ea0e0e: Pulling fs layer
11
c98a22d85c62: Waiting
12
bf70d116f1d7: Waiting
13
97f2d71621e0: Waiting
14
ea02a46a87c8: Waiting
15
78fff17c3a50: Waiting


12. When complete, we should have two containers deployed, one of which we cannot access directly:

Shell
 




xxxxxxxxxx
1


1
$ docker ps
2
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                                      NAMES
3
9c327bb01a85       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_nginx
4
3823ce1f25d8        boraozkan/nginx:latest   "/usr/bin/supervisord"   8 minutes ago       Up 8 minutes        3306/tcp, 0.0.0.0:8081->80/tcp             production_wp


13. 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:

NGINX web application


14. 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:

Apache web application 

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:

Shell
 




xxxxxxxxxx
1


 
1
$ sudo iptables -t nat -L -n
2
 
          
3
...
4
Chain POSTROUTING (policy ACCEPT)
5
target     prot opt source               destination
6
MASQUERADE  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.

I hope you liked this post! More to come soon.

Until then, here are some more Kubernetes and Docker best practices for managing and deploying containers.

Topics:
cloud ,devops ,docker ,nginx ,ports ,reverse proxy ,tutorial

Published at DZone with permission of Sudip Sengupta . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}