How to Deploy NGINX Reverse Proxy on Docker

Introduction

A reverse proxy intercepts incoming requests and directs them to the appropriate server. Not only does this speed up performance, it also strengthens server security.

The easiest way to set up and manage reverse proxies is to use Nginx and Docker. This guide sets up two sample web services inside Docker containers and a Nginx reverse proxy for those services.

In this tutorial, you will learn how to set up a reverse proxy on Docker for two sample web servers.

Deploy Nginx reverse proxy on Docker.

Prerequisites

  • A user account with sudo privileges
  • A command line/terminal window (Ctrl-Alt-T)
  • Docker installed on your system
  • Docker Compose installed on your system
  • A registered domain name with an SSL Certificate associated with it

Why Do You Need Reverse Proxy?

While the standard proxy server protects the clients, the reverse proxy protects the server.

A reverse proxy is a type of proxy set up behind the private network’s firewall. Its primary role is to intercept traffic and direct a request to the appropriate server on the backend.

The main reasons for using a reverse proxy are to improve security and performance. If you have services running on multiple pods, you can redirect all requests coming into the network to go through a number of specified ports.

Additionally, reverse proxies can also handle SSL encryption, caching, and compressing data.

Step 1: Create a Sample Web Service

1. Start by creating a new directory for the first sample web service. In this tutorial, we create a directory example1, but you can use a name of your choice.

mkdir example1

2. Move into that directory:

cd example1

3. Create a docker-compose YAML configuration file for the first container to define the service. Use a text editor of your choice (in this example, we use Nano).

sudo nano docker-compose.yml

4. Then, add the following content into the .yaml file:

version: '2'
services:
 app:
  image: nginx
  volumes:
   - .:/usr/share/nginx/html
  ports:
   - "80"

The docker-compose file specifies this is an app service that uses the nginx image. It mounts the root of example1 from the Docker host to /usr/share/nginx/html/. Finally, the configuration exposes the service on port 80.

The docker-compose.yml file varies depending on the service you want to run. The configuration above is specific to the web service we create for this tutorial.

Note: Since this is a sample service, we did not include the version number of the nginx image. However, in a production environment, make sure to specify the version as well.

4. Save and exit the file.

5. While inside the same example1 directory, create an index file for the web service:

sudo nano index.html

6. Add a few simple lines to appear on the sample web page:

<!DOCTYPE html>
<html>
<head>
<title>Website 1</title>
</head>
<body>
<h1>Hello! This is the first sample website.</h1>
</body>
</html>

7. Save and close the file.

8. Build the newly created service using the docker-compose command:

sudo docker-compose build

If you are using a prebuilt image, as in this example, the output responds with app uses an image, skipping.

Output showing "app uses an image, skipping".

9. Next, start the container with:

sudo docker-compose up -d
Start a container for the first web service using docker-compose.

Step 2: Create a Second Sample Web Service

Create a second sample web service by following the same process.

Make sure to return to the home directory if you are still in example1. To do so, run cd in the terminal window.

1. Create a new directory where you will store the docker-compose and index file for the second website. We will name this directory example2.

mkdir example2

2. Move into example2 by running:

cd example2

3. Create a docker-compose file:

sudo nano docker-compose.yml

4. Define the service using the same specifications as in Step 1. Add the following content to the file:

version: '2'
services:
 app:
  image: nginx
  volumes:
   - .:/usr/share/nginx/html
  ports:
   - "80"

5. Save and exit the file.

6. Then, create an index file for the second web service by running:

sudo nano index.html

7. Add content to the file:

<!DOCTYPE html>
<html>
<head>
<title>Website 2</title>
</head>
<body>
<h1>Hello! This is the second sample website.</h1>
</body>
</html>

8. Save the changes and exit the file.

9. Build the second service and start the container by running the commands:

sudo docker-compose build
sudo docker-compose up -d
Run a web service inside a Docker container.

Step 3: List Containers

To verify the containers for both services are up and running, list all containers with the command:

docker ps -a

You should see containers for both web services listed in the output.

List all Docker containers to verify you have to two containers with web services.

Step 4: Set up Reverse Proxy

Next, you need to set up and configure a reverse proxy container. This requires creating multiple files and subdirectories, which should all be stored inside the proxy directory.

Therefore, the first step is to create and navigate into the proxy directory. To do so, run the commands:

mkdir proxy
cd proxy

Configure the Dockerfile

1. Once inside the proxy directory, create a Dockerfile for a new custom image:

sudo nano Dockerfile

2. The file should contain the following:

FROM nginx

COPY ./default.conf /etc/nginx/conf.d/default.conf

COPY ./backend-not-found.html /var/www/html/backend-not-found.html

COPY ./includes/ /etc/nginx/includes/

COPY ./ssl/ /etc/ssl/certs/nginx/

The Dockerfile is based on the nginx image. It also copies a number of files from the local machine:

  • the default configuration for the proxy service
  • an HTML error response
  • proxy and SSL configurations and certificates

3. Save and exit the Dockerfile.

Configure the backend-not-found File

Create an index file for a not found response:

sudo nano backend-not-found.html

Add the content:

<html>
<head><title>Proxy Backend Not Found</title></head>
<body>
<h2>Proxy Backend Not Found</h2>
</body>
</html>

3. Save the changes and close the file.

Configure the default.conf File

1. Create the default.conf file inside the proxy directory:

sudo nano default.conf

2. Add the content:

# web service1 config.
server {
listen 80;
listen 443 ssl http2;
server_name example1.test;

# Path for SSL config/key/certificate
ssl_certificate /etc/ssl/certs/nginx/example1.crt;
ssl_certificate_key /etc/ssl/certs/nginx/example1.key;
include /etc/nginx/includes/ssl.conf;

location / {
include /etc/nginx/includes/proxy.conf;
proxy_pass http://example_app_1;
}

access_log off;
error_log /var/log/nginx/error.log error;
}

# web service2 config.
server {
listen 80;
listen 443 ssl http2;
server_name example2.test;

# Path for SSL config/key/certificate
ssl_certificate /etc/ssl/certs/nginx/example2.crt;
ssl_certificate_key /etc/ssl/certs/nginx/example2.key;
include /etc/nginx/includes/ssl.conf;

location / {
include /etc/nginx/includes/proxy.conf;
proxy_pass http://example2_app_1;
}

access_log off;
error_log /var/log/nginx/error.log error;
}

# Default
server {
listen 80 default_server;

server_name _;
root /var/www/html;

charset UTF-8;

error_page 404 /backend-not-found.html;
location = /backend-not-found.html {
allow all;
}
location / {
return 404;
}

access_log off;
log_not_found off;
error_log /var/log/nginx/error.log error;
}

The configuration consists of two web services – example1.test and example2.test. Both server components listen to port 80 and direct Nginx to the appropriate SSL certificate.

Configure the docker-compose.yml File

1. Create a new docker-compose.yml file for the proxy service:

sudo nano docker-compose.yml

2. Copy and paste the following content into the file:

version: '2'
services:
proxy:
build: ./
networks:
- example1
- example2
ports:
- 80:80
- 443:443

networks:
example1:
external:
name: example1_default
example2:
external:
name: example2_default

In this file, you connect the proxy and the external networks (the web services example1 and example2). Also, ports 80/443 of the proxy service are bound to ports 80/443 of the Docker host.

Generate Keys and Certificates

1. Start by creating a subdirectory (ssl) inside the proxy folder:

mkdir ssl

2. Navigate into the ssl subdirectory with:

cd ssl

3. Next, run each touch command listed below to create the required files:

touch example1.crt
touch example1.key
touch example2.crt
touch example2.key

4. Then, use OpenSSL to generate keys and certificates for your web services. For the first web service (example1), run the command:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout example1.key -out example1.crt

The command generates a 2048 bit RSA private key and stores it into the example1.key file.

Generate keys and certificates for your web services before starting up NGINX reverse proxy.

You will also be asked to provide some information that is incorporated into the certificate request. You can leave some of the fields blank.

5. Repeat the process to generate keys and certificates for the second web service (example2). Type in the following command in the terminal window:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout example2.key -out example2.crt

This generates a 2048 bit RSA private key for example2 and saves it in the example2.key file.

Edit the Proxy and SSL Configuration

1. Exit out of the ssl subdirectory and back into proxy. To do so, use the command:

cd ..

2. Then, create a new subdirectory under the name includes:

mkdir includes

3. Navigate into includes and create the files proxy.conf and ssl.conf:

cd includes
touch proxy.conf
touch ssl.conf

4. Next, open the proxy.conf file:

sudo nano proxy.conf

5. Add the following configuration:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_intercept_errors on;

6. Save and exit proxy.conf.

7. Open the ssl.conf file:

sudo nano ssl.conf

8. Paste the following lines in the file:

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-
ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-
SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-
GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-
AES128-SHAECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-
SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:
DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-
DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:
AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-
CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;

Edit the hosts File

1. Return to the proxy directory:

cd

2. Open the /etc/hosts file:

sudo nano etc/hosts

3. Add the following lines to map the hostnames of the web services to the private IP address of the Docker hosts:

10.0.2.15 example1.test
10.0.2.15 example2.test

4. Save the changes and close the file.

Note: If you don’t know your host’s IP address, refer to How to Find Or Check Your IP Address In Linux.

Step 5: Start Reverse Proxy

1. With the configuration files in place, use the docker-compose command to build the container:

sudo docker-compose build
Build reverse proxy container.

2. Then, run the container:

sudo docker-compose up -d
Run a reverse proxy container.

3. Verify you know have three containers – two web services and one reverse proxy container:

sudo docker ps -a
Verify you have two web services and a reverse proxy container.

Step 6: Check Whether Reverse Proxy is Working

Use the curl command to check whether the web services and the reverse proxy are working properly. Each domain should respond with the appropriate output.

1. Run the following command to check the first web service:

sudo curl example1.test

The output responds with the HTML created for example1.test.

2. Then, verify the second web service is working with the reverse proxy with:

sudo curl example2.test

The output responds with the example2.test HTML.

Conclusion

This tutorial showed you how to use Docker to set up two sample web services and an Nginx reverse proxy for them.

If you want to learn more about Nginx reverse proxy outside the Docker environment, take a look at How To Set Up & Use NGINX As A Reverse Proxy.

Was this article helpful?
YesNo
Sofija Simic
Sofija Simic is an experienced Technical Writer. Alongside her educational background in teaching and writing, she has had a lifelong passion for information technology. She is committed to unscrambling confusing IT concepts and streamlining intricate software installations.
Next you should read
How to Install Nvidia Drivers on Ubuntu 20.04
March 23, 2021

Ubuntu 20.04 comes with an open-source Nouveau GPU driver out of the box. This driver does not always take...
Read more
Bare Metal Cloud Portal Quick Start Guide
March 23, 2021

Follow the sections in this Bare Metal Cloud Portal guide to learn how to navigate through the portal. This...
Read more
How to Deploy a Bare Metal Cloud Server
March 23, 2021

This article shows how to deploy a new Bare Metal Cloud server in nine simple steps. Follow the instructions...
Read more
How to Use the vmstat Command
March 18, 2021

The vmstat command is a Linux monitoring utility used to see various system statistics and to diagnose...
Read more