0

Lab 9 — Web Server & Reverse Proxy

1. Mục tiêu

Ở các lab trước, chúng ta đã đi qua:

Ảnh Minh hoạ
Screenshot 2026-08-06 at 15.56.23.png image.png Screenshot 2026-08-06 at 15.56.23.png

Trong thực tế, client thường không truy cập trực tiếp application.

Ảnh Minh hoạ
Screenshot 2026-08-06 at 15.56.23.png image.png Screenshot 2026-08-06 at 15.56.23.png

Sau lab này, bạn sẽ:

  • Hiểu Web Server là gì.
  • Hiểu Reverse Proxy là gì.
  • Cài đặt và cấu hình Nginx.
  • Serve static file bằng Nginx.
  • Forward request từ Nginx tới Backend.
  • Hiểu proxy_pass.
  • Biết cách debug Nginx.
  • Hiểu mô hình thường gặp trong production.

2. Web Server là gì?

Web Server là phần mềm nhận HTTP request và trả HTTP response.

Ví dụ:

Ảnh Minh hoạ
Screenshot 2026-08-06 at 15.56.23.png image.png Screenshot 2026-08-06 at 15.56.23.png

Các Web Server phổ biến:

Nginx
Apache
Caddy

Trong lab này sử dụng Nginx.


3. Nginx có thể làm gì?

Nginx không chỉ serve HTML.

Nó thường được sử dụng để:

Nginx
 ├── Static Web Server
 ├── Reverse Proxy
 ├── Load Balancer
 ├── TLS/HTTPS Termination
 └── HTTP Gateway

Trong production, một kiến trúc rất phổ biến là:

Internet
    │
    ▼
 Nginx
    │
    ▼
Backend

4. Reverse Proxy là gì?

Đây là khái niệm quan trọng nhất của lab.

Giả sử Backend chạy:

127.0.0.1:8080

Client không truy cập trực tiếp:

http://server:8080

Thay vào đó:

Client
   │
   │ :80
   ▼
Nginx
   │
   │ :8080
   ▼
Backend

Nginx nhận request rồi forward request tới Backend.

Đó gọi là:

Reverse Proxy


5. Reverse Proxy khác Forward Proxy thế nào?

Forward Proxy

Proxy đại diện cho Client:

Client
   │
   ▼
Forward Proxy
   │
   ▼
Internet

Reverse Proxy

Proxy đại diện cho Server:

Client
   │
   ▼
Reverse Proxy
   │
   ▼
Backend

Trong DevOps, bạn sẽ gặp Reverse Proxy thường xuyên hơn.


6. Tại sao cần Reverse Proxy?

Nếu expose trực tiếp:

Internet
   │
   ▼
Spring Boot :8080

thì application phải xử lý trực tiếp traffic từ Internet.

Một mô hình tốt hơn:

Internet
   │
   ▼
Nginx :443
   │
   ▼
Spring Boot :8080

Nginx có thể đảm nhiệm:

  • HTTPS.
  • Routing.
  • Access log.
  • Rate limiting.
  • Load balancing.
  • Security headers.
  • Static files.

Backend chỉ cần tập trung xử lý business logic.


7. Cài Nginx

Trên Ubuntu:

sudo apt update
sudo apt install nginx

Kiểm tra:

nginx -v

Ví dụ:

nginx version: nginx/1.24.x

Kiểm tra service:

sudo systemctl status nginx

8. Kiểm tra Nginx

Mở browser:

http://SERVER_IP

Hoặc:

curl http://localhost

Nếu thành công, bạn sẽ nhận HTML mặc định của Nginx.

Kiểm tra port:

sudo ss -lntp | grep nginx

Thông thường:

0.0.0.0:80

Nginx đang listen trên HTTP port 80.


9. Nginx Configuration

Các file quan trọng thường nằm ở:

/etc/nginx/

Kiểm tra:

ls /etc/nginx

Bạn sẽ thường gặp:

nginx.conf
sites-available/
sites-enabled/
conf.d/

10. nginx.conf

File chính:

/etc/nginx/nginx.conf

Xem:

sudo cat /etc/nginx/nginx.conf

Bạn có thể thấy:

http {
    ...

    include /etc/nginx/sites-enabled/*;
}

Điều này có nghĩa Nginx sẽ load các configuration trong:

/etc/nginx/sites-enabled/

11. sites-available và sites-enabled

Một convention phổ biến:

sites-available/
        │
        │ configuration
        ▼
sites-enabled/
        │
        ▼
     Nginx

Ví dụ:

/etc/nginx/sites-available/myapp

Sau đó tạo symbolic link:

sudo ln -s \
/etc/nginx/sites-available/myapp \
/etc/nginx/sites-enabled/myapp

Có thể hiểu:

sites-available
      ↓
   Available

sites-enabled
      ↓
    Active

12. Tạo Static Website

Tạo thư mục:

sudo mkdir -p /var/www/lab9

Tạo HTML:

echo "Hello from Nginx" | sudo tee /var/www/lab9/index.html

Tạo config:

sudo nano /etc/nginx/sites-available/lab9

Nội dung:

server {
    listen 80;

    server_name _;

    root /var/www/lab9;
    index index.html;
}

13. Enable Website

Tạo symbolic link:

sudo ln -s \
/etc/nginx/sites-available/lab9 \
/etc/nginx/sites-enabled/lab9

Kiểm tra configuration:

sudo nginx -t

Nếu:

syntax is ok
test is successful

thì configuration hợp lệ.

Đây là command phải nhớ.

Trước khi reload Nginx:

sudo nginx -t

14. Reload Nginx

Sau khi configuration hợp lệ:

sudo systemctl reload nginx

Test:

curl http://localhost

Kết quả:

Hello from Nginx

15. Reload vs Restart

Đây là một kinh nghiệm thực tế quan trọng.

Reload

sudo systemctl reload nginx

Nginx đọc lại configuration mà không cần dừng service theo cách restart.

Thường dùng khi:

Thay đổi configuration

Restart

sudo systemctl restart nginx

Dừng rồi khởi động lại service.

Trong production:

Nếu chỉ thay đổi config, ưu tiên nginx -t rồi reload.


16. Nginx làm Reverse Proxy

Bây giờ chúng ta tạo Backend giả.

Chạy:

mkdir ~/backend
cd ~/backend
echo "Hello from Backend" > index.html
python3 -m http.server 8080

Kiểm tra:

curl http://localhost:8080

Kết quả:

Hello from Backend

Kiến trúc hiện tại:

Client
   │
   ├── :80 → Nginx
   │
   └── :8080 → Backend

17. Cấu hình Reverse Proxy

Sửa:

sudo nano /etc/nginx/sites-available/lab9

Dùng:

server {
    listen 80;

    server_name _;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

Kiểm tra:

sudo nginx -t

Sau đó:

sudo systemctl reload nginx

18. Test

Bây giờ:

curl http://localhost

Bạn nhận:

Hello from Backend

Nhưng request thực tế là:

Client
   │
   │ :80
   ▼
 Nginx
   │
   │ :8080
   ▼
 Backend

Client không cần biết Backend đang chạy port 8080.


19. proxy_pass là gì?

Dòng:

proxy_pass http://127.0.0.1:8080;

có nghĩa:

Khi request vào location này, Nginx chuyển request tới Backend ở 127.0.0.1:8080.

Ví dụ:

GET /
   │
   ▼
Nginx :80
   │
   ▼
127.0.0.1:8080

20. Routing theo Path

Đây là khả năng rất hữu ích của Reverse Proxy.

Ví dụ:

/api
   ↓
Backend :8080

/admin
   ↓
Admin App :3000

Nginx:

server {
    listen 80;

    location /api/ {
        proxy_pass http://127.0.0.1:8080;
    }

    location /admin/ {
        proxy_pass http://127.0.0.1:3000;
    }
}

Kiến trúc:

                 Nginx
                   │
          ┌────────┴────────┐
          │                 │
       /api             /admin
          │                 │
          ▼                 ▼
      Backend           Admin App
       :8080               :3000

Đây là một mô hình rất phổ biến.


21. Routing theo Domain

Bạn cũng có thể route dựa trên domain:

api.example.com
      ↓
Backend :8080

admin.example.com
      ↓
Admin :3000

Ví dụ:

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

và:

server {
    listen 80;
    server_name admin.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}

22. Forwarded Headers

Khi Nginx proxy request, Backend có thể không biết IP thật của Client nếu không cấu hình đúng.

Thường sử dụng:

location / {
    proxy_pass http://127.0.0.1:8080;

    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;
}

Các header quan trọng:

Host
X-Real-IP
X-Forwarded-For
X-Forwarded-Proto

Có thể hiểu:

Client
  │
  │ IP = 1.2.3.4
  ▼
Nginx
  │
  │ X-Real-IP: 1.2.3.4
  ▼
Backend

Backend có thể sử dụng thông tin này để biết request ban đầu đến từ đâu.


23. Tại sao X-Forwarded-For quan trọng?

Nếu không có reverse proxy:

Client
   ↓
Backend

Backend thấy:

Client IP

Nhưng khi có Nginx:

Client
   ↓
Nginx
   ↓
Backend

Backend có thể chỉ nhìn thấy:

Nginx IP

Vì vậy proxy cần truyền thông tin Client IP.

Đặc biệt quan trọng cho:

  • Access log.
  • Rate limiting.
  • Audit.
  • Security.
  • Application monitoring.

24. Nginx Logs

Đây là một trong những thứ bạn sẽ dùng rất nhiều khi troubleshooting.

Thông thường:

/var/log/nginx/access.log
/var/log/nginx/error.log

Xem access log:

sudo tail -f /var/log/nginx/access.log

Xem error log:

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

Sau đó:

curl http://localhost

Bạn sẽ thấy request xuất hiện trong access log.


25. Debug 502 Bad Gateway

Một lỗi cực kỳ quan trọng.

Giả sử:

Client
   ↓
Nginx
   ↓
Backend :8080

Backend chết:

Backend :8080
   X

Client:

curl http://localhost

có thể nhận:

502 Bad Gateway

Kiểm tra Backend:

curl http://localhost:8080

Nếu fail:

Backend ✗

Kiểm tra Nginx:

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

Bạn có thể thấy lỗi kiểu:

connect() failed

26. Debug theo tầng

Khi nhận:

502 Bad Gateway

đừng chỉ restart Nginx.

Kiểm tra:

1. Nginx đang chạy?
       ↓
2. Backend đang chạy?
       ↓
3. Backend listen port nào?
       ↓
4. Nginx proxy tới đúng port?
       ↓
5. Firewall có chặn?
       ↓
6. Backend có trả HTTP response?

Command:

sudo systemctl status nginx
sudo ss -lntp
curl http://localhost:8080
sudo nginx -t
sudo tail -f /var/log/nginx/error.log

27. Debug 404

Nếu:

GET /api/todos

trả:

404 Not Found

có thể do:

Nginx routing sai
Backend routing sai
Path bị thay đổi

Đừng mặc định rằng Backend bị lỗi.

Test trực tiếp:

curl http://localhost:8080/api/todos

Sau đó test qua Nginx:

curl http://localhost/api/todos

So sánh hai kết quả.


28. Một trick rất hữu ích

Khi debug Reverse Proxy, luôn test hai đường:

Direct Backend

curl http://127.0.0.1:8080

Through Nginx

curl http://localhost

Nếu:

Backend → OK
Nginx → FAIL

thì tập trung vào:

Nginx config
proxy_pass
location
headers
firewall

Nếu:

Backend → FAIL
Nginx → FAIL

thì xử lý Backend trước.


29. nginx -t trước khi reload

Đây là một thói quen nên hình thành:

sudo nginx -t

Nếu OK:

sudo systemctl reload nginx

Không nên:

sudo systemctl restart nginx

ngay sau mỗi lần sửa config mà chưa kiểm tra syntax.

Một typo trong config có thể khiến Nginx không reload được.


30. Firewall cho mô hình Reverse Proxy

Một kiến trúc tốt hơn:

Internet
   │
   ▼
Nginx :80/:443
   │
   ▼
Backend :8080

Nếu Backend và Nginx cùng server:

Internet
   │
   ├── 80  ✓
   ├── 443 ✓
   │
   └── 8080 ✗

Không cần expose 8080 ra Internet.

Backend chỉ cần:

127.0.0.1:8080

hoặc private network.

Đây là một nguyên tắc bảo mật quan trọng:

Chỉ expose những port thực sự cần public.


31. Mô hình production cơ bản

Một server có thể được triển khai:

                    Internet
                       │
                       │ HTTPS :443
                       ▼
                    Nginx
                       │
                 Reverse Proxy
                       │
                       ▼
                Spring Boot
                    :8080
                       │
                       ▼
                 PostgreSQL
                    :5432

Public:

443

Internal:

8080
5432

Đây là kiến trúc tốt hơn rất nhiều so với:

Internet
   │
   ├── 8080
   └── 5432

32. Challenge 1 — Tự tạo 502

Chạy Backend:

python3 -m http.server 8080

Test:

curl http://localhost

→ OK.

Bây giờ tắt Backend:

Ctrl + C

Test lại:

curl http://localhost

→ Có thể nhận 502 Bad Gateway.

Kiểm tra:

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

Bạn vừa mô phỏng một lỗi production rất phổ biến:

Nginx ✓
Backend ✗
       ↓
502

33. Challenge 2 — Sai Port

Backend chạy:

8080

Nhưng Nginx cấu hình:

proxy_pass http://127.0.0.1:8081;

Test:

curl http://localhost

Debug:

sudo ss -lntp

và:

curl http://127.0.0.1:8080

Sau đó kiểm tra:

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

Tìm nguyên nhân và sửa lại:

proxy_pass http://127.0.0.1:8080;

34. Challenge 3 — Path Routing

Tạo:

/api

forward tới:

8080

và:

/admin

forward tới:

3000

Sau đó test:

curl http://localhost/api
curl http://localhost/admin

Mục tiêu:

             Nginx
                │
       ┌────────┴────────┐
       │                 │
      /api             /admin
       │                 │
       ▼                 ▼
    :8080              :3000

35. Những command cần nhớ

Command Mục đích
nginx -v Kiểm tra version
sudo nginx -t Kiểm tra config
systemctl status nginx Kiểm tra service
systemctl reload nginx Reload config
systemctl restart nginx Restart
ss -lntp Kiểm tra listening ports
curl -v Debug HTTP
tail -f access.log Theo dõi request
tail -f error.log Theo dõi lỗi

36. Checklist

Sau Lab 9, bạn cần hiểu:

✓ Web Server là gì?
✓ Nginx là gì?
✓ Reverse Proxy là gì?
✓ Forward Proxy khác Reverse Proxy thế nào?
✓ proxy_pass dùng để làm gì?
✓ Nginx routing theo path thế nào?
✓ Nginx routing theo domain thế nào?
✓ 127.0.0.1 và 0.0.0.0 khác nhau thế nào?
✓ access.log dùng để làm gì?
✓ error.log dùng để làm gì?
✓ 502 Bad Gateway thường liên quan đến gì?
✓ nginx -t dùng để làm gì?
✓ reload khác restart thế nào?
✓ Vì sao Backend không nên public trực tiếp?

37. Kết quả cần đạt

Sau Lab 8:

Client
   ↓
 DNS
   ↓
Firewall
   ↓
Server
   ↓
 Port
   ↓
Application

Sau Lab 9, chúng ta có kiến trúc gần production hơn:

                    Client
                       │
                       │ HTTP/HTTPS
                       ▼
                     Nginx
                       │
                 Reverse Proxy
                       │
                       ▼
                  Application
                       │
                       ▼
                    Database

Quan trọng nhất, bạn phải hiểu được flow:

https://api.example.com
          │
          ▼
         DNS
          │
          ▼
       Server IP
          │
          ▼
     Firewall :443
          │
          ▼
       Nginx :443
          │
          ▼
   proxy_pass :8080
          │
          ▼
    Spring Boot

Đây là nền móng trực tiếp cho những kiến thức sau này như:

Docker
   ↓
Docker Compose
   ↓
Kubernetes Service
   ↓
Ingress
   ↓
Load Balancer
   ↓
Azure Application Gateway

Kinh nghiệm quan trọng nhất của Lab 9:

Khi gặp 502, đừng vội kết luận Nginx hỏng. Hãy kiểm tra Nginx → Backend → Port → Process theo từng tầng.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.