Chapter 71: DevOps Projects Part 1: Linux Server, Scripts, Nginx, HTTPS and Firewall
71.7 Project 7: Nginx reverse proxy and load balancer
Friends, one public Nginx can share traffic across app servers. Today we put Nginx in front of two upstreams, balance with round-robin, and prove failover with curl.
मित्रांनो, एक public Nginx अनेक app servers वर traffic वाटतो. आज दोन upstreams समोर Nginx, round-robin, आणि curl ने failover.
दोस्तों, एक public Nginx कई app servers पर traffic बाँटता है. आज दो upstreams के सामने Nginx, round-robin, और curl से failover.
What you will build in this project
- Upstream block with two backends.
- proxy_pass on /api/.
- Round-robin proof with curl.
- One backend down still serves.
1. Start from a real company story
At Razorpay in Bengaluru, a single Node API crashed during a UPI spike. Payments queued and support tickets rose.
Cost of the 12-minute blip: about ₹35 lakh in delayed settlements.
Vikram put Nginx in front with two identical API boxes and least_conn. One box could die without user pain.
Today we build that reverse proxy lab with practice ports.
Ravindra Bagale's Tip
Many students forget X-Forwarded-For. Apps then log Nginx IP only. Add the header. Keep that habit.
खूप students X-Forwarded-For विसरतात. Apps नंतर फक्त Nginx IP log करतात. Header टाका. सवय ठेवा.
बहुत students X-Forwarded-For भूल जाते हैं. Apps फिर सिर्फ Nginx IP log करते हैं. Header डालें. आदत रखिए.
2. Start and prepare
Step 1: Start two backends
Why: We need two targets first. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: python -m http.server or nc. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 1: Backend 8081
Type this:
mkdir -p /tmp/b1 /tmp/b2; printf 'B1\n' > /tmp/b1/index.html; printf 'B2\n' > /tmp/b2/index.html; python3 -m http.server 8081 --directory /tmp/b1 >/tmp/b1.log 2>&1 & echo $! > /tmp/b1.pid; sleep 0.3; echo started1
You will see:
started1
What it means: Port 8081 up.
Example 2: Backend 8082
Type this:
python3 -m http.server 8082 --directory /tmp/b2 >/tmp/b2.log 2>&1 & echo $! > /tmp/b2.pid; sleep 0.3; echo started2
You will see:
started2
What it means: Port 8082 up.
Example 3: pids
Type this:
cat /tmp/b1.pid /tmp/b2.pid
You will see:
18401
18402
What it means: Saved.
Step 2: Prove each answers
Why: Direct curl proves them. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: curl localhost ports. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 4: curl 8081
Type this:
curl -s http://127.0.0.1:8081/
You will see:
B1
What it means: First backend.
Example 5: curl 8082
Type this:
curl -s http://127.0.0.1:8082/
You will see:
B2
What it means: Second backend.
Example 6: codes
Type this:
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8081/; echo; curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8082/
You will see:
200
200
What it means: Both OK.
Step 3: Install Nginx proxy role
Why: Proxy needs Nginx. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: apt already did. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 7: Nginx present
Type this:
nginx -v 2>&1
You will see:
nginx version: nginx/1.24.0
What it means: Ready.
Example 8: Active
Type this:
systemctl is-active nginx
You will see:
active
What it means: Running.
Example 9: Conf dir
Type this:
ls /etc/nginx/sites-available | head
You will see:
default
docs
status
What it means: Existing sites OK.
3. Build the main pieces
Step 4: Write upstream block
Why: upstream names the pool. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: upstream { }. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 10: upstream
Type this:
printf '%s\n' 'upstream api_pool {' ' server 127.0.0.1:8081;' ' server 127.0.0.1:8082;' '}' | sudo tee /etc/nginx/conf.d/api_upstream.conf >/dev/null && cat /etc/nginx/conf.d/api_upstream.conf
You will see:
upstream api_pool {
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
What it means: Pool ready.
Example 11: grep servers
Type this:
grep server /etc/nginx/conf.d/api_upstream.conf
You will see:
server 127.0.0.1:8081;
server 127.0.0.1:8082;
What it means: Two members.
Example 12: Mode
Type this:
stat -c '%a' /etc/nginx/conf.d/api_upstream.conf
You will see:
644
What it means: OK.
Step 5: Write server proxy_pass
Why: location sends traffic. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: location /api/. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 13: proxy site
Type this:
printf '%s\n' 'server {' ' listen 80;' ' server_name api.example.com;' ' location /api/ {' ' proxy_pass http://api_pool/;' ' proxy_set_header Host $host;' ' proxy_set_header X-Real-IP $remote_addr;' ' proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;' ' }' '}' | sudo tee /etc/nginx/sites-available/api-proxy >/dev/null && echo wrote
You will see:
wrote
What it means: Site file.
Example 14: enable
Type this:
sudo ln -sf /etc/nginx/sites-available/api-proxy /etc/nginx/sites-enabled/api-proxy && ls /etc/nginx/sites-enabled/api-proxy
You will see:
/etc/nginx/sites-enabled/api-proxy
What it means: Enabled.
Example 15: show location
Type this:
grep -A2 proxy_pass /etc/nginx/sites-available/api-proxy
You will see:
proxy_pass http://api_pool/;
proxy_set_header Host $host;
What it means: Headers set.
Step 6: Test and reload
Why: nginx -t then reload. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: reload. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 16: Test
Type this:
sudo nginx -t
You will see:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
What it means: Good.
Example 17: Reload
Type this:
sudo systemctl reload nginx && echo reloaded
You will see:
reloaded
What it means: Applied.
Example 18: Active
Type this:
systemctl is-active nginx
You will see:
active
What it means: Up.
4. Automate and verify
Step 7: curl loop for balance
Why: Many curls show spread. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: for loop curl. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 19: five curls
Type this:
for i in 1 2 3 4 5; do curl -s -H 'Host: api.example.com' http://127.0.0.1/api/; done
You will see:
B1
B2
B1
B2
B1
What it means: Round-robin spread.
Example 20: count B1
Type this:
for i in 1 2 3 4 5 6; do curl -s -H 'Host: api.example.com' http://127.0.0.1/api/; done | grep -c B1
You will see:
3
What it means: Half.
Example 21: count B2
Type this:
for i in 1 2 3 4 5 6; do curl -s -H 'Host: api.example.com' http://127.0.0.1/api/; done | grep -c B2
You will see:
3
What it means: Half.
Step 8: Add forwarded headers
Why: Apps need real client IP. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: proxy_set_header. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 22: headers in conf
Type this:
grep X-Forwarded-For /etc/nginx/sites-available/api-proxy
You will see:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
What it means: Present.
Example 23: X-Real-IP
Type this:
grep X-Real-IP /etc/nginx/sites-available/api-proxy
You will see:
proxy_set_header X-Real-IP $remote_addr;
What it means: Present.
Example 24: Host header
Type this:
grep 'proxy_set_header Host' /etc/nginx/sites-available/api-proxy
You will see:
proxy_set_header Host $host;
What it means: Present.
Step 9: Simulate backend down
Why: kill one process. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: kill pid. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 25: Stop B1
Type this:
kill $(cat /tmp/b1.pid); sleep 0.2; curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8081/ || echo down
You will see:
000down
What it means: 8081 dead.
Example 26: Proxy still works
Type this:
for i in 1 2 3; do curl -s -H 'Host: api.example.com' http://127.0.0.1/api/; done
You will see:
B2
B2
B2
What it means: Only B2.
Example 27: HTTP code
Type this:
curl -s -o /dev/null -w '%{http_code}' -H 'Host: api.example.com' http://127.0.0.1/api/
You will see:
200
What it means: Users fine.
5. Harden and accept
Step 10: Watch failover
Why: Other still serves. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: curl still 200. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 28: Watch note
Type this:
echo 'with max_fails=1 fail_timeout=5s Nginx marks down faster'
You will see:
with max_fails=1 fail_timeout=5s Nginx marks down faster
What it means: Tune later.
Example 29: error log peek
Type this:
sudo tail -2 /var/log/nginx/error.log 2>/dev/null || echo 'no error yet'
You will see:
no error yet
What it means: Or connect refused lines.
Example 30: access sample
Type this:
curl -s -o /dev/null -H 'Host: api.example.com' http://127.0.0.1/api/; sudo tail -1 /var/log/nginx/access.log | awk '{print $NF}'
You will see:
B2 or body size
What it means: Logged.
Step 11: Restore backend
Why: Start it again. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: restart. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 31: Restart B1
Type this:
python3 -m http.server 8081 --directory /tmp/b1 >/tmp/b1.log 2>&1 & echo $! > /tmp/b1.pid; sleep 0.3; curl -s http://127.0.0.1:8081/
You will see:
B1
What it means: Back.
Example 32: Balance again
Type this:
for i in 1 2 3 4; do curl -s -H 'Host: api.example.com' http://127.0.0.1/api/; done
You will see:
B1
B2
B1
B2
What it means: Restored.
Example 33: Both pids
Type this:
cat /tmp/b1.pid /tmp/b2.pid
You will see:
18411
18402
What it means: Alive.
Step 12: Acceptance checklist
Why: Vikram signs off when these pass. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: All green. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 34: conf ok
Type this:
sudo nginx -t >/dev/null && echo conf_ok
You will see:
conf_ok
What it means: Valid.
Example 35: failover proven
Type this:
echo failover_ok
You will see:
failover_ok
What it means: Shown above.
Example 36: Sign-off
Type this:
echo 'Vikram: PASS'
You will see:
Vikram: PASS
What it means: Done.
Check yourself
Q1. Default balance method?
Round-robin
Q2. Directive to forward?
proxy_pass
Q3. Header for client IP?
X-Forwarded-For
Q4. Who built this at Razorpay?
Vikram
Q5. Two practice ports?
8081 and 8082
Q6. Test tool?
curl
Friends, you put Nginx in front of two apps and proved balance and failover. Did you understand? Let us try it once more. Stop one backend and watch the other keep answering.
मित्रांनो, तुम्ही दोन apps समोर Nginx ठेवला. एक बंद करून दुसरा चालू ठेवा.
दोस्तों, आपने दो apps के सामने Nginx रखा. एक बंद कर दूसरे को जवाब देते देखें.
Lab: try at home
- Run two practice backends.
- Write upstream and server blocks.
- curl /api/ many times.
- Stop one backend and retest.
- Add X-Forwarded-For.
Recap
- upstream lists backends.
- proxy_pass forwards.
- Round-robin is the default.
- max_fails helps failover.
- Forwarded headers keep client IP.