
Protecting an Nginx that publishes an application means closing what should not be reachable, limiting what is, then making visible what goes through: authentication on the administration area, refusal of hidden files and unneeded methods, rate limiting, security headers, JSON logs and counters. This lesson extends publishing with Nginx: it takes the protection steps of the training and writes them in Nginx syntax, and it lays down only the minimum for rate limiting and observation. Sizing the limits, full observation and diagnosis each have their own lesson, cited where it takes over.
What you will learn
The lesson goes from the most restrictive to the most informative: refuse, limit, announce, then observe.
- Authenticate access to an administration route.
- Refuse hidden files and unneeded write methods.
- Limit the rate with
limit_req. - Add security headers to responses.
- Produce JSON logs and expose
stub_statuslocally.
Prerequisites
This lesson assumes you know how to publish an application with Nginx.
- Publishing, forwarded headers and configuration validation: Publish an application with Nginx.
- The path of a request and what a proxy must not believe: Publish a web service.
- The basics of Nginx: Nginx: practical guide (in French).
How do you protect an administration route?
Require authentication on the route, and only expose it if it has to be exposed. An unprotected /admin route is among the paths that scanners try first. Nginx offers two mechanisms: auth_basic, which compares credentials with a file of hashed passwords, and auth_request, which delegates the decision to an authentication service through a subrequest.
location /admin { auth_basic "Administration"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://127.0.0.1:8080;}auth_basic is enough for a simple access, provided it goes through HTTPS: credentials travel encoded, not encrypted. auth_request fits when authentication is already handled by another service; the service answers 2xx to allow and 401 or 403 to refuse. The matching module is present in the official packages, but not in every build: check with nginx -V.
What should you refuse right away?
Refuse hidden files and the methods the application does not need. A file whose name starts with a dot (.git, .env) can contain secrets, and a proxy that serves it passes the leak on. A write method on a read-only application has no reason to get through.
location ~ /\. { deny all;}
if ($request_method !~ ^(GET|HEAD|POST)$) { return 405;}The first block answers 403 to any path containing a hidden file. The second refuses with 405 the methods that are not listed. Adapt the list to the application: a refusal that is too broad breaks normal requests, and that is precisely what you must check with curl after the change. The /\. pattern also blocks /.well-known/, where ACME authorities come to read the HTTP-01 challenge: if this server obtains its certificates through that challenge, add a location ^~ /.well-known/ that allows it, because the ^~ prefix is chosen before the regular expression.
How do you limit the request rate?
limit_req slows down or refuses clients that exceed a set rate, per address. It is set in two steps: limit_req_zone, at the http level, declares the memory zone, the counting key and the rate; limit_req, in a location, applies the zone with a burst tolerance.
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
server { location / { limit_req zone=api burst=20 nodelay; limit_req_status 429; proxy_pass http://127.0.0.1:8080; }}Here each address can send ten requests per second, with a burst of twenty accepted without delay; beyond that, Nginx answers 429. By default the refusal code is 503: limit_req_status makes it readable for clients and for logs. Behind another relay, the $binary_remote_addr key designates the relay's address, not the client's: the key must match what you actually want to limit.
This is the minimal case. The sizing of rate and burst, the limiting of simultaneous connections, the body size and the choice of a key that a client cannot forge are covered in Nginx limits.
Which security headers should you add?
Add headers that reduce the attack surface on the browser side, with the always parameter so that they also appear on error responses. Without always, Nginx adds the header only on success and redirection codes.
add_header X-Content-Type-Options "nosniff" always;add_header X-Frame-Options "DENY" always;add_header Referrer-Policy "no-referrer" always;add_header Strict-Transport-Security "max-age=31536000" always;One pitfall: add_header is not inherited from one level to the next as soon as a lower level declares one. If a location adds its own header, it loses those of the server. So check the headers actually received with curl -I, not the ones you believe you configured.
How do you observe Nginx?
Two sources are enough to start: a structured access log and the stub_status counters. A JSON log can be filtered and aggregated without text parsing, and the counters give the instantaneous load.
log_format json_acces escape=json '{"heure":"$time_iso8601","client":"$remote_addr",' '"methode":"$request_method","uri":"$uri","code":$status,' '"duree":$request_time}';
access_log /var/log/nginx/acces.json json_acces;
server { listen 127.0.0.1:8081; location /stub_status { stub_status; }}escape=json protects the format against special characters in an address. stub_status exposes only global counters: active connections, accepted and handled requests. It details neither response codes nor per-route times, which you must read in the log. Keep this access point on the local interface, as above: it reveals the traffic volume and has no reason to be reachable from outside.
This minimal case stops there. The timing fields that separate Nginx's slowness from the application's, the metrics exporter and the alerts are the subject of Observe Nginx. When a 403, 502 or 504 response appears anyway, the diagnostic approach is in Diagnose Nginx.
Practice: protect an application with Nginx
The lab starts from an Nginx that already publishes the application, but accepts administration requests without protection, serves hidden files and forwards methods the application does not need. It asks you to add the security headers, require the supplied credentials on /admin, refuse hidden files and block the unneeded write methods without breaking the application's normal requests. Validation is an automated check that verifies these refusals and that legitimate requests still work. Practice on observation (JSON log, stub_status, correlation with the upstream) takes place in the lesson Observe Nginx.
Key points
Protecting means refusing the superfluous, then proving the result with curl.
auth_basicorauth_requestprotect the administration area.- Refuse hidden files and unneeded methods.
limit_reqlimits per key, andlimit_req_statuschooses the code.add_header ... alwaysalso covers errors, but is not freely inherited.- A JSON log and a local
stub_statusmake Nginx observable.
Knowledge check
Knowledge check
Check what you have learned with this interactive quiz
How it works
- The timer starts when you click Start
- Multiple choice, true/false and short answer questions
- You can move between questions
- Detailed results are shown at the end
Starts the quiz and the timer
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: Nginx limits: limit_req, limit_conn and body size
A new full quiz with random questions
Work again only on the questions you missed