Skip to content

Chapter 7 of 8

Access Control, Rate Limiting, and Logging

Access control in nginx starts with the simple allow and deny directives, which act as an ACL matched against the client IP. A typical block permits an internal subnet and rejects everyone else: allow 10.0.0.0/8; deny all;. Denied requests receive a 403 Forbidden. For stronger authentication, HTTP Basic Auth uses auth_basic "Restricted"; alongside auth_basic_user_file /etc/nginx/.htpasswd;, with the password file generated by htpasswd -c /etc/nginx/.htpasswd alice. These primitives compose well with location matching, so you can lock down /admin while leaving the rest of the site open.

Rate limiting protects backends from abuse and is implemented as a two-step pattern. First declare a shared memory zone that counts requests keyed by some identifier, usually $binary_remote_addr: limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;. Then apply it inside a location with limit_req zone=one burst=20 nodelay;. burst is the queue size — how many requests may pile up — and nodelay tells nginx to serve queued requests immediately instead of spacing them out at the configured rate. A similar primitive, limit_conn, restricts concurrent connections per key (typically the client IP), which is the right tool for capping WebSocket or download-heavy clients. To protect a login endpoint specifically, combine a per-minute zone with a tight location match: limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m; inside location = /login { limit_req zone=login burst=10 nodelay; ... }.

Logging gives you visibility into traffic and behaviour. The default access log format is "combined": $remote_addr - $remote_user [\(time_local] "\)request" $status $body_bytes_sent "\(http_referer" "\)http_user_agent". For more detail you can define a custom log_format that adds timing variables: $request_time measures total request processing time, while $upstream_response_time, $upstream_connect_time, and $upstream_header_time expose where latency is being spent — particularly useful when a backend is the bottleneck. To reduce syscall overhead on busy servers, open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2; keeps file descriptors warm for frequently written log files. The error_log directive, default level error, captures runtime warnings and errors; raise it to info or debug when troubleshooting. Because debug is extremely noisy, pair it with debug_connection 1.2.3.4; to restrict verbose output to a single client IP, which lets you debug one request end-to-end without flooding your disks.

All chapters
  1. 1Nginx Fundamentals and Process Model
  2. 2Core Configuration Directives and Performance Knobs
  3. 3HTTP Routing: Servers, Locations, and Rewrites
  4. 4Reverse Proxying, Upstreams, and Backend Protocols
  5. 5Caching and Compression
  6. 6TLS, SSL, and Connection Hardening
  7. 7Access Control, Rate Limiting, and Logging
  8. 8Advanced Routing, Variables, and Security Headers

Drill it

Reading is not remembering. These come from the Nginx Configuration Essentials deck:

Q

What does nginx stand for?

engine x — a high-performance open-source HTTP server, reverse proxy, and IMAP/POP3 mail proxy originally written by Igor Sysoev and first released in 2004...

Q

What is nginx's primary process model?

A single master process that reads configuration, manages sockets, and spawns worker processes (default count = CPU cores). Workers handle all incoming connecti...

Q

How do you reload nginx configuration without dropping connections?

Send SIGHUP to the master process (or run nginx -s reload). The master re-reads config, spawns new workers with the new config, and gracefully shuts down old wo...

Q

What is the difference between <code>nginx -s stop</code> and <code>nginx -s quit</code>?

stop sends SIGTERM to workers and forces them to exit immediately, closing open connections. quit sends SIGQUIT, which lets workers finish serving current reque...