Mastering Nginx, Guide with Docker Examples

Milad Fahmy
6 min readOct 6, 2024

--

Generated By AI

Introduction

Nginx is a multi-purpose web server, reverse proxy, and load balancer that powers a huge portion of the internet. Its low memory usage, speed, and ability to scale make it an excellent choice for modern web applications.

This guide will not only help you understand Nginx, but also show you how to integrate it with Docker to streamline deployment and management of your Nginx configurations.

Table of Contents

  1. Introduction to Nginx and Its Role
  2. Key Concepts of Nginx (Nginx as a Web Server, Nginx as a Reverse Proxy, Nginx Load Balancing and Nginx Caching)
  3. Installing and Setting Up Nginx with Docker
  4. Serving Static Content in Nginx (Detailed Example)
  5. Reverse Proxying Multiple Applications with Nginx
  6. Advanced Load Balancing Strategies in Nginx
  7. Nginx Caching for Performance (Detailed Example)
  8. Nginx Security: SSL Termination, Rate Limiting, and More
  9. Monitoring and Logging Nginx with Docker
  10. Advanced Nginx Configurations for Real-World Applications
  11. Conclusion

1. Introduction to Nginx

What is Nginx?

Nginx is known for its high-performance capabilities. Its lightweight, event-driven architecture is designed to handle many thousands of connections at once without bogging down the server, making it an ideal choice for high-traffic sites.

Nginx is widely used in different roles:

  • Web server: Nginx is an excellent web server for serving static files such as HTML, CSS, JS, and images.
  • Reverse Proxy: It forwards client requests to backend services, acting as an intermediary for services behind firewalls.
  • Load Balancer: Nginx can distribute incoming traffic across multiple backend servers to ensure optimal performance and redundancy.
  • HTTP Cache: It caches responses from upstream servers, reducing latency and load.

2. Key Concepts of Nginx

Nginx as a Web Server

Web Servers are used to deliver content to a user’s browser. Nginx excels at this, especially for static files (HTML, CSS, JS, etc.).

Example of Nginx as a Web Server:

In a basic configuration file (nginx.conf), serving static files might look like this:

server {
listen 80;
server_name example.com;

location / {
root /var/www/html;
index index.html;
}
}

This tells Nginx to listen on port 80 and serve the files located in /var/www/html.

Nginx as a Reverse Proxy

In reverse proxy mode, Nginx forwards requests to backend servers (e.g., Node.js, Python, or Ruby applications), enabling multiple services to run behind one public-facing server.

Example of Nginx as a Reverse Proxy:

server {
listen 80;
server_name example.com;

location /app1 {
proxy_pass http://127.0.0.1:3000;
}

location /app2 {
proxy_pass http://127.0.0.1:4000;
}
}

In this setup:

  • Requests to example.com/app1 will be forwarded to a backend server running on port 3000.
  • Requests to example.com/app2 will go to port 4000.

This is useful for microservices where you have multiple applications running on different ports.

Nginx Load Balancing

Load Balancing allows Nginx to distribute traffic across multiple backend servers, improving redundancy and performance.

Example of Load Balancing:

upstream backend {
server 192.168.1.100;
server 192.168.1.101;
server 192.168.1.102;
}

server {
listen 80;

location / {
proxy_pass http://backend;
}
}

Here, incoming traffic is distributed evenly between the three servers in the upstream block.

Nginx supports various load-balancing methods:

  • Round Robin :(default): Traffic is distributed evenly across all servers.
  • Least Connections: Requests are sent to the server with the least active connections.
  • IP Hash: Traffic from each client is always routed to the same backend server based on the client’s IP.

Nginx Caching

Caching in Nginx can improve performance by storing copies of frequently accessed content.

Example of Simple Nginx Caching:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m;
proxy_cache_key "$scheme$request_method$host$request_uri";

server {
listen 80;

location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
}
}

This config caches valid 200 and 302 responses for 10 minutes, and 404 responses for 1 minute, reducing the load on the backend servers.

3. Installing and Setting Up Nginx with Docker

Docker allows us to run Nginx in isolated containers, making deployment easy and repeatable.

Step 1: Install Docker

  • On Linux, install Docker using:
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

Step 2: Run Nginx in Docker

To quickly get Nginx up and running:

docker pull nginx
docker run --name my-nginx -p 8080:80 -d nginx

This starts an Nginx container and maps port 80 of the container to port 8080 of your machine. You can access the default Nginx welcome page by visiting http://localhost:8080.

4. Serving Static Content in Nginx

To serve your own static files using Nginx with Docker, follow these steps:

  1. Create a directory for your HTML files:
mkdir -p ~/nginx-html
echo "<h1>Welcome to My Site</h1>" > ~/nginx-html/index.html

2. Start the Nginx container and mount your files to /usr/share/nginx/html in the container:

docker run --name static-nginx -p 8080:80 -v ~/nginx-html:/usr/share/nginx/html:ro -d nginx

Now, when you visit http://localhost:8080, you should see the "Welcome to My Site" page.

5. Reverse Proxying Multiple Applications with Nginx

If you have two services running, say a Node.js application on port 3000 and a Python Flask app on port 4000, you can use Nginx as a reverse proxy to expose both services under the same domain.

Configuration:

server {
listen 80;

location /node {
proxy_pass http://localhost:3000;
}

location /flask {
proxy_pass http://localhost:4000;
}
}

Requests to /node will be routed to your Node.js app, while requests to /flask will be sent to the Flask application.

Running this setup in Docker:

  1. Start your Node.js and Flask applications in Docker containers.
  2. Create the Nginx configuration file on your local machine.
  3. Start the Nginx container with the config file mounted:
docker run --name reverse-proxy-nginx -p 8080:80 -v ~/nginx-conf:/etc/nginx/nginx.conf:ro -d nginx

6. Advanced Load Balancing Strategies in Nginx

Least Connections: Distribute traffic based on the number of active connections each server has.

upstream backend {
least_conn;
server 192.168.1.100;
server 192.168.1.101;
}

IP Hash: Ensure that requests from a specific client always go to the same backend server.

upstream backend {
ip_hash;
server 192.168.1.100;
server 192.168.1.101;
}

Nginx also supports Sticky Sessions, which keep a user’s session on the same server by using cookies or session identifiers.

7. Nginx Caching for Performance

Nginx can be used as a caching layer to reduce the load on your backend services. Here’s how to enable simple caching:

  1. Define the cache zone in the nginx.conf:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;

2. Enable caching in a specific location:

server {
listen 80;

location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
}
}

8. Nginx Security: SSL Termination, Rate Limiting, and More

Security is crucial for any web service. Nginx provides features like SSL termination, HTTP rate limiting, and content security policies.

Enabling SSL with Let’s Encrypt (via Docker)

  1. Pull the Certbot Docker image:
docker pull certbot/certbot

2. Use Certbot to obtain an SSL certificate for your domain:

docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
certbot/certbot certonly --standalone -d yourdomain.com

3. Configure Nginx to use SSL:

server {
listen 443 ssl;
server_name yourdomain.com;

ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

location / {
proxy_pass http://backend;
}
}

Enabling Rate Limiting to Thwart DDoS Attacks

To prevent abuse and limit the number of requests per second:

http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;

server {
location / {
limit_req zone=mylimit burst=5 nodelay;
proxy_pass http://backend;
}
}
}

This configuration limits each IP address to one request per second.

9. Monitoring and Logging Nginx with Docker

Nginx provides real-time logs that can be analyzed for security, performance, or debugging purposes. To view logs from a running Nginx container:

docker logs my-nginx

For more advanced monitoring, Nginx can be integrated with tools like Prometheus and Grafana to visualize performance metrics such as requests per second, latency, and error rates.

10. Advanced Nginx Configurations for Real-World Applications

HTTP/2 and Gzip Compression

HTTP/2 allows multiplexing and header compression, which speeds up website loading.

To enable HTTP/2 and Gzip compression:

server {
listen 443 ssl http2;
server_name yourdomain.com;

ssl_certificate /etc/ssl/certs/ssl-bundle.crt;
ssl_certificate_key /etc/ssl/private/ssl-cert.key;

gzip on;
gzip_types text/plain text/css application/json application/javascript;
}

Buffering and Timeouts for Optimized Performance

http {
client_max_body_size 100M;
send_timeout 60s;
client_body_buffer_size 128k;
proxy_buffering on;
proxy_buffers 8 16k;
}

These settings control the maximum upload size, timeouts, and how responses are buffered.

11. Conclusion

Nginx is a powerful tool that can be used in various capacities, from serving static content to balancing traffic and enhancing security. With Docker, you can easily spin up Nginx instances, manage configurations, and integrate them into a broader system architecture.

By mastering Nginx, you gain control over traffic, performance, and security, making it an essential skill for modern web infrastructure management.

--

--

Milad Fahmy
Milad Fahmy

Written by Milad Fahmy

I’m a JS Champion, I wrote about software engineering. I’m currently developing various open-source projects (like: https://encrypt-rsa.js.org)

No responses yet