Vấn đềMọi thứ hoạt động bình thường khi proxy_pass của bạn trỏ đến một URL tĩnh. Tuy nhiên, ngay khi bạn đưa vào một biến để làm cho upstream của mình trở nên linh hoạt (dynamic), Nginx có thể gặp lỗi. Bạn sẽ thấy trang web của mình trả về lỗi 502 và các bản ghi log sẽ đầy rẫy những phàn nàn về việc thiếu resolver.
Kiểm tra các bản ghi log lỗi tại /var/log/nginx/error.log. Bạn có thể sẽ thấy một mục như sau:
2023/10/27 10:45:01 [error] 12345#0: *1 no resolver defined to resolve "api.example.com", client: 1.2.3.4, server: example.com, request: "GET / HTTP/1.1", upstream: "http://api.example.com/"
Cấu hình lỗi điển hìnhVấn đề này thường xuất hiện trong các khối cấu hình có dạng như sau:
location / {
set $backend_host "api.example.com";
proxy_pass http://$backend_host;
}
Tại sao Nginx bị lỗi khi thực thiNginx xử lý việc phân giải DNS theo cách khác nhau tùy thuộc vào cách bạn viết chỉ thị proxy_pass.
- Phân giải tĩnh: Khi bạn sử dụng
proxy_pass http://api.example.com;, Nginx sẽ phân giải tên miền đúng một lần duy nhất trong quá trình khởi động hoặc reload. Nó sẽ lưu cache địa chỉ IP đó mãi mãi cho đến lần reload tiếp theo.- Phân giải động: Sử dụng một biến nhưproxy_pass http://$variable;sẽ thay đổi các quy tắc. Vì biến có thể thay đổi cho mỗi yêu cầu riêng biệt, Nginx phải phân giải tên miền tại thời điểm thực thi (runtime).Vấn đề nằm ở chỗ: Nginx không tự động sử dụng file/etc/resolv.confcủa hệ thống cho các lần tra cứu runtime này. Nó yêu cầu bạn phải xác định rõ ràng một DNS server bằng cách sử dụng chỉ thịresolver. Nếu không có nó, Nginx sẽ không có cách nào để chuyển đổi chuỗi tên miền đó thành địa chỉ IP.
Cách khắc phục: Thêm chỉ thị ResolverĐể khắc phục điều này, bạn phải cho Nginx biết DNS server nào cần tin cậy. Bạn có thể đặt chỉ thị này trong khối http, server hoặc location.
Lựa chọn 1: Sử dụng các Public DNS ServerNếu máy chủ của bạn cần kết nối tới các endpoint công cộng, Google hoặc Cloudflare là những lựa chọn đáng tin cậy. Thêm đoạn sau vào khối server của bạn:
server {
listen 80;
server_name example.com;
# Sử dụng DNS của Google và Cloudflare
resolver 8.8.8.8 1.1.1.1 valid=30s;
location / {
set $upstream_endpoint "api.example.com";
proxy_pass http://$upstream_endpoint;
}
}
Lựa chọn 2: Sử dụng DNS nội bộ/CloudTrong môi trường cloud, bạn nên sử dụng resolver của VPC nội bộ. Trên AWS, giá trị này luôn là địa chỉ cơ sở của dải mạng VPC cộng thêm hai. Đối với mạng 10.0.0.0/16, resolver của bạn sẽ là 10.0.0.2. Trên các hệ thống Ubuntu hiện đại sử dụng systemd-resolved, hãy sử dụng stub nội bộ:
# Cho systemd-resolved nội bộ
resolver 127.0.0.53 valid=10s;
# Cho AWS VPC (ví dụ)
resolver 10.0.0.2 valid=10s;
Lựa chọn 3: Vô hiệu hóa IPv6Nếu mạng của bạn không hỗ trợ IPv6, Nginx có thể lãng phí thời gian cố gắng phân giải các bản ghi AAAA. Bạn có thể ép nó chỉ sử dụng IPv4 để tăng tốc độ:
resolver 8.8.8.8 ipv6=off;
Áp dụng các thay đổiĐừng bao giờ restart Nginx mà không kiểm tra cấu hình trước. Một lỗi đánh máy nhỏ cũng có thể làm sập toàn bộ trang web của bạn.
- Kiểm tra cú pháp:
sudo nginx -tTìm dòng chữsyntax is oktrong kết quả trả về.- Reload một cách an toàn (Gracefully):sudo systemctl reload nginx- **Theo dõi kết quả:**Xem log trong thời gian thực khi bạn truy cập ứng dụng:tail -f /var/log/nginx/error.log## Mẹo từ chuyên gia- Lưu ý về TTL: Các backend động như AWS Load Balancer thường xuyên thay đổi IP. Hãy thiết lậpvalid=10shoặc30sđể đảm bảo Nginx không giữ các địa chỉ IP cũ (stale).- Tính dự phòng: Luôn liệt kê ít nhất hai DNS server. Nếu một cái bị lỗi, proxy của bạn sẽ không bị gián đoạn.- Phạm vi toàn cục: Nếu bạn sử dụng các biến động trên nhiều trang web, hãy đặtresolvertrong khối http của filenginx.confđể tránh việc phải lặp lại cấu hình.

