Logo AppDev24 Login / Sign Up
Sign Up
Have Login?
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Login
New Account?
Recovery
Go to Login
By continuing you indicate that you agree to Terms of Service and Privacy Policy of the site.
Docker

Docker Nginx Reverse Proxy

Updated on Aug 15, 2024

Are you looking to set up a Nginx container using Docker on your MacOS machine? Look no further! In this article, we'll walk you through the process of creating and configuring a Docker Nginx container, including setting nginx configuration as Reverse Proxy, API Gateway, http redirection & ssl/tls termination.

Create Self Signed Certificate

Pre-requisite: openssl must be installed in MacOS

openssl req -x509 -nodes -days 365 \
    -subj "/C=DE/ST=Berlin/L=Berlin/O=appdev24/OU=dev/CN=nginx.demo" \
    -newkey rsa:4096 -keyout selfsigned.key \
    -out selfsigned.crt

-subj switch option:

  • Country Name (2 letter code): DE
  • State or Province Name (full name): Berlin
  • Locality Name (city): Berlin
  • Organization Name (company): appdev24
  • Organizational Unit Name (department): dev
  • Common Name (server FQDN): nginx.demo

Update hosts file

sudo vi /etc/hosts

# Append the server entry
127.0.0.1	nginx.demo

Create Nginx configuration

nginx-reverseproxy.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    
    sendfile            on;
    keepalive_timeout   65;


    # HTTP Redirect
    server {
        listen          80 default_server;
        listen          [::]:80 default_server;
        server_name     _;
        return 301 https://$host$request_uri;
    }


    # Reverse Proxy
    upstream products {
        server host.docker.internal:5000;
    }

    upstream customers {
        server host.docker.internal:3000;
    }


    # SSL/TLS Termination
    server {
        listen 443 ssl;
        listen [::]:443 ssl;

        server_name     nginx.test;
        root            /usr/share/nginx/html;
        index           index.html;
        
        ssl_session_cache   shared:SSL:10m;
        ssl_session_timeout 4h;
        
        ssl_protocols               TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_ciphers                 HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers   off;

        ssl_certificate         /etc/ssl/certs/selfsigned.crt;
        ssl_certificate_key     /etc/ssl/private/selfsigned.key;

        # Proxy Microservices
        proxy_http_version 1.1;
        proxy_cache_bypass $http_upgrade;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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;

        location /api/products {
            proxy_pass http://products;
        }

        location /api/customers {
            proxy_pass http://customers;
        }

        # Basic Status Info
        location /stub_status {
            stub_status on;
        }
    }
}

Create Demo Python API Microservice

requirements.txt

flask

app.py

import json
from flask import Flask, jsonify

app = Flask(__name__)

products = [
    { 'id': 1, 'name': 'Cakes' },
    { 'id': 2, 'name': 'Cookies' },
    { 'id': 3, 'name': 'Chocolates' },
    { 'id': 4, 'name': 'Milk' },
    { 'id': 5, 'name': 'Coffee' },
    { 'id': 6, 'name': 'Soft Drinks' },
    { 'id': 7, 'name': 'Ice cream' }
]

@app.route('/api/products', methods=['GET'])
def get_products():
    return jsonify(products)

if __name__ == '__main__':
   app.run(debug=True)

Python-Dockerfile

# syntax=docker/dockerfile:1

FROM python:3.12.4-slim
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip3 install --no-cache-dir -r requirements.txt
COPY app.py .
CMD [ "python", "-m" , "flask", "run", "--host=0.0.0.0"]

Create Demo Nodejs API Microservice

package.json

{
  "name": "nginx-demo",
  "version": "1.0.0",
  "description": "nginx reverse proxy & API gateway demo",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/sarubhai/nginx-demo.git"
  },
  "keywords": [
    "Node.js",
    "Nginx Reverse Proxy",
    "Nginx API Gateway",
    "REST API"
  ],
  "author": "Saurav Mitra <saurav.karate@gmail.com>",
  "license": "ISC",
  "homepage": "https://appdev24.com/pages/44/docker-nginx-reverse-proxy",
  "dependencies": {
    "express": "^4.19.2"
  }
}

Also download the package-lock.json file from https://github.com/sarubhai/nginx-demo/blob/main/package-lock.json

app.js

const express = require('express');
const app = express();

app.get("/api/customers", (req, res, next) => {
    const customers = [
        { id: 1, name: "John Doe", age: 30 },
        { id: 2, name: "Jane Smith", age: 25 },
        { id: 3, name: "Mike Johnson", age: 40 },
        { id: 4, name: "Jane Doe", age: 28 },
        { id: 5, name: "Micheal Page", age: 36 },
        { id: 6, name: "Peter Alter", age: 39 }
      ];
    res.json(customers);
});

app.listen(3000, () => {
    console.log("Server running on port 3000");
});

Nodejs-Dockerfile

# syntax=docker/dockerfile:1

FROM node:20.15.0-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY app.js .
EXPOSE 3000
CMD [ "node", "app.js" ]

Create Docker Compose file

reverseproxy-docker-compose.yml

version: '3.9'

services:
  nginx-reverseproxy:
    # Apple M1 Chip
    platform: linux/amd64
    image: nginx:latest
    container_name: nginx-reverseproxy
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./nginx-reverseproxy.conf:/etc/nginx/nginx.conf:ro
      - ./selfsigned.crt:/etc/ssl/certs/selfsigned.crt:ro
      - ./selfsigned.key:/etc/ssl/private/selfsigned.key:ro
    networks:
      - backend-network

  ms1-python-app:
    # Apple M1 Chip
    platform: linux/amd64
    build:
      context: .
      dockerfile: Python-Dockerfile
    container_name: ms1-python-app
    restart: always
    ports:
      - 5000:5000
    networks:
      - backend-network

  ms2-nodejs-app:
    # Apple M1 Chip
    platform: linux/amd64
    build:
      context: .
      dockerfile: Nodejs-Dockerfile
    container_name: ms2-nodejs-app
    restart: always
    ports:
      - 3000:3000
    networks:
      - backend-network

networks:
  backend-network:
    driver: bridge

Start the Container

Now that we have our configuration and Docker compose file set up, it's time to start the containers! Run the following command:

docker-compose -f reverseproxy-docker-compose.yml up -d --build

This will start the containers in detached mode, meaning they will run in the background.

Test Nginx Reverse Proxy Container

Once the container is running, we can test our webserver by browsing to https://nginx.demo/api/products & https://nginx.demo/api/customers

Optionally you can download the self signed certificate from
Chrome > Developer Tools > Security Tab > View Certificate
and import into MacOS System Keychain to Always Trust the self signed certificate and avoid the certificate warning.

Stop the Container

Finally, we can stop the containers by running the following command:

docker-compose -f loadbalancer-docker-compose.yml down

This will stop the containers and remove it from memory.

That's it! We've successfully created and configured a Docker Nginx container as a Reverse Proxy along with SSL/TLS Termination and HTTP Redirect. It also acts as an API Gateway for two backend API Services.

PrimeChess

PrimeChess.org

PrimeChess.org makes elite chess training accessible and affordable for everyone. For the past 6 years, we have offered free chess camps for kids in Singapore and India, and during that time, we also observed many average-rated coaches charging far too much for their services.

To change that, we assembled a team of top-rated coaches including International Masters (IM) or coaches with multiple IM or GM norms, to provide online classes starting from $50 per month (8 classes each month + 4 tournaments)

This affordability is only possible if we get more students. This is why it will be very helpful if you could please pass-on this message to others.

Exclucively For Indian Residents: 
Basic - ₹1500
Intermediate- ₹2000
Advanced - ₹2500

Top 10 Articles