nginx

nginx is a piece of software that sits in front of a web server. It is defined as "an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev".

I always struggled understanding the function that nginx fulfills, mostly because it fulfills many. I discussed about nginx with chatGPT and summarized the discussion below.

Reverse proxy

why "reverse"? A forward proxy generally works on behalf of the client making requests, while the reverse proxy generally works on behalf of the server receiving requests (hence the “reverse” in the name).

reverse_proxy.png

wikipedia

forward_proxy.png

wikipedia

Load Balancing: Nginx can distribute incoming traffic across multiple instances of your app, helping to balance the load and improve performance.

SSL Termination: Nginx can handle SSL/TLS encryption, offloading this task from your application server and simplifying certificate management.

Request Handling: Nginx can handle a large number of concurrent connections efficiently, serving static files directly and passing dynamic requests to the application server.

Performance

Caching: Nginx can cache responses, reducing the load on your application server and speeding up response times for repeated requests.

Static Content: Serving static content (e.g., images, CSS, JavaScript) directly from Nginx is faster and more efficient than serving it through your application server.

Security

privileged ports

Ports below 1024, such as port 80 (HTTP) and port 443 (HTTPS), are privileged ports.

On Unix-like operating systems, binding to these ports requires superuser privileges (the root user has unrestricted read and write privileges to all areas of the file system).

question: what does "binding" to a port mean?

Running a webserver (such as Uvicorn for Python) on these ports typically requires root or elevated permissions. nginx initially runs as a root process but then drops privileges, which allows you to handle traffic on these ports without running your application server as root.

nginx's process model consists of a master process and one or more worker processes:

  1. master process:

    • The Nginx master process starts with root privileges.

    • It reads the configuration files and binds to privileged ports (e.g., port 80 or 443).

    • The master process is responsible for managing the worker processes.

  2. worker Processes:

    • After the master process binds to the necessary ports, it spawns worker processes.

    • The worker processes handle the actual client requests and responses.

    • Nginx drops the root privileges for the worker processes, running them under a less-privileged user (often www-data or nginx).

Because nginx drops root privileges for worker processes, if an attacker compromises a worker process, they gain access only to the permissions of the unprivileged user, not root.

DDoS Mitigation

Nginx can help mitigate DDoS (Distributed Denial of Service) attacks by rate limiting and blocking malicious traffic before it reaches your application server.

Nginx mitigates DDoS attacks using rate limiting (number of connections within a time frame from a given client IP), connections limiting (number of simultaneous connections from a single client IP), blocking malicious IPs (from known blackilsts), dynamic banning (use fail2ban to ban IPs that exhibit malicious behaviors based on patterns in the access logs).

WAF (Web Application Firewall)

With appropriate modules, Nginx can act as a web

application firewall, adding an extra layer of security.

Example configuration

Here is what an nginx configuration file looks like:


http {

	# creates a rate limiting zone named `mylimit` with a memory space of 10MB and a rate of 1 request per second per client IP.

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

	

	# Define a connection limiting zone

	limit_conn_zone $binary_remote_addr zone=connlimit:10m;

	

	# list of upstream backend servers

	upstream fastapi_backend {

			# load balancing algo. ip_hash distributes requests based on the client's IP address. This ensures that requests from the same client are always sent to the same backend server.

			# other algos: least_conn, round robin (leave blank)

	    ip_hash;

	    server 192.168.1.2:8000;

	    server 192.168.1.3:8000;

	    server 192.168.1.4:8000;

	    

	    # health checks on backend servers to ensure that traffic is only sent to healthy servers.

	    # requires a module such as ngx_http_upstream_check_module.

	    check interval=3000 rise=2 fall=5 timeout=1000 type=http;

	}

	server {

	    listen 80;

	    server_name your_domain_or_ip;

	

	    location / {

		    # Apply rate limiting.

		    # allows a burst of up to 5 requests per client without delay.

		    # loading a web page may trigger multiple AJAX requests, modern browsers often open multiple connections to load resources (images, scripts, styles) simultaneously.

		    limit_req zone=mylimit burst=5 nodelay;

		    

			# limits each client IP to 10 simultaneous connections.

			limit_conn connlimit 10;

		

			# Block specific IP addresses

			deny 192.168.1.1;

			deny 203.0.113.0/24;

			

	        proxy_pass http://fastapi_backend;

	        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;

	    }

	}

}