Stop by Stop

DevOps line

Nginx reverse proxy

Every visitor meets one mailroom first, so it can open the envelopes, hand out brochures and share letters between desks.

Words to know

Stops explain each step. The film plays the whole ride.

Explain it
Route
Two department desksYouPosting lettersMailroomSorts the postBrochure rackPictures, pagesDesk 1Answers lettersDesk 2Answers letters
  • A letter going in
  • Stuck waiting
  • A reply coming back
  • Something went wrong
Stop 1 of 9

A letter reaches the mailroom

You post a letter asking for the company logo. Every letter reaches one place first, the mailroom, so that is where we start.

Next stop: The mailroom opens the envelope

All stops

The everyday version

A company mailroom works the same way. Every part of Nginx has a twin in the building.

  • Youis the Browser

    Post letters and wait for the replies.

  • The mailroomis the Nginx

    Opens the envelopes, hands out brochures itself and shares real questions between the desks.

  • The brochure rackis the Static files

    Holds pictures and pages that never change, ready to hand out.

  • Desk 1is the App server 1

    Reads each letter it is given and writes the answer.

  • Desk 2is the App server 2

    An identical desk, so the mailroom always has a spare.

  • A closed deskis a 502 or 504 error

    The mailroom finds every desk dark, or gets tired of waiting. Either way, you get a note instead of a reply.

Interview questions

Say the short answer first. Go deeper only if they ask.

What is a reverse proxy, and how is it different from a forward proxy?
Short answer

A forward proxy acts for clients. A reverse proxy acts for servers.

If they dig deeper

RFC 9110 calls a reverse proxy a gateway: it acts as the origin server for the outbound connection and forwards requests inward. Clients only ever talk to it, so TLS, load balancing and static files can live in one place.

Answer that loses points

“A reverse proxy and a forward proxy are the same thing.”

Why put Nginx in front of Uvicorn?
Short answer

It ends TLS, serves static files, buffers slow clients and shares the load.

If they dig deeper

Uvicorn’s docs say a proxy in front “may not be necessary, but is recommended for additional resilience”. Nginx buffers requests and responses by default (proxy_request_buffering and proxy_buffering are on), so slow clients do not tie up an app worker.

Answer that loses points

“Because Uvicorn cannot serve HTTP.”

How does Nginx choose between app servers?
Short answer

Round-robin by default: each request goes to the next server in turn.

If they dig deeper

The default is weighted round-robin (weight=1 each). least_conn picks the server with the fewest active connections, ip_hash keeps a client on one server, and weight favours bigger machines. Plain round-robin ignores how busy a server is.

Answer that loses points

“Round-robin sends traffic to the least busy server.”

How does the app learn the real client IP and scheme?
Short answer

Nginx has to pass them in headers such as X-Forwarded-For and X-Forwarded-Proto.

If they dig deeper

Nginx adds neither by default. Set proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; and proxy_set_header X-Forwarded-Proto $scheme;. Uvicorn only trusts them from IPs in --forwarded-allow-ips (default 127.0.0.1 and ::1), so trust just your proxy.

Answer that loses points

“request.client.host is always the user.”

What do nginx -t and nginx -s reload do?
Short answer

nginx -t checks the config. nginx -s reload applies it without a restart.

If they dig deeper

On reload the master process checks the new config and tries to apply it. If that fails, nginx keeps running with the old config. If it works, nginx starts new workers and asks the old ones to shut down gracefully. Run nginx -t first.

Answer that loses points

“Edit the file and it applies automatically.”

What happens when an app server fails or is slow?
Short answer

By default nginx tries the next server on an error or a timeout.

If they dig deeper

The default is proxy_next_upstream error timeout. Failures count toward max_fails (1) within fail_timeout (10s), and a failed server is skipped meanwhile. If no server answers, you get 502 or 504. Open-source nginx has passive checks only; active health checks need NGINX Plus.

Answer that loses points

“Nginx probes every app server in the background.”

What must you add to proxy WebSockets?
Short answer

Pass the Upgrade and Connection headers explicitly.

If they dig deeper

They are hop-by-hop headers, so nginx does not forward them unless told: proxy_set_header Upgrade $http_upgrade; and proxy_set_header Connection "upgrade";. Before 1.29.7 you also needed proxy_http_version 1.1;. An idle WebSocket closes after 60 seconds unless you raise proxy_read_timeout or send pings.

Answer that loses points

“WebSockets work through nginx with no extra config.”

Cheat-sheet

Commands you will actually type.

nginx -t && nginx -s reload

Check the config first, then reload it gracefully.

upstream backend { server 127.0.0.1:8001; server 127.0.0.1:8002; }

A pool of two app servers, shared round-robin by default.

location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }

Forward to the pool, keep the original host, and pass the client IP along.

listen 443 ssl; ssl_certificate /etc/ssl/site.crt; ssl_certificate_key /etc/ssl/site.key;

Terminate TLS: decrypt HTTPS here and talk plain HTTP to the pool.

return 301 https://$host$request_uri;

In the port 80 server block: redirect plain HTTP to HTTPS.

location /static/ { root /var/www; expires 30d; }

Serve /var/www/static/... straight from disk, with a 30 day cache lifetime.

proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";

Let WebSockets through (before nginx 1.29.7, also add proxy_http_version 1.1;).

tail -f /var/log/nginx/error.log

Watch errors live. A 502 or 504 usually leaves a clue here.

Sources