Dùng iptables NAT thay thế cho reverse proxy
Hôm rồi một khách hàng thông báo website của họ cứ chập chờn, lúc vào được, lúc lại không. Tôi vào kiểm tra thì thấy web-server của họ hoàn toàn ổn, duy một điều coi log lại không thấy kết nối nào đến được web-server cả. Loay hoay một hồi, khách hàng mới báo cho biết rằng họ có sử dụng một con squid làm reverse proxy đứng trước web-server, mục đích là để cache lại static content.
Tôi vào kiểm tra con squid này thì phát hiện trong log của nó phun ra khá nhiều lỗi. Google cho biết đây là những lỗi khá nghiêm trọng và cũng có đưa ra vài giải pháp, nhưng do tôi không có nhiều kinh nghiệm với squid thành ra loay hoay mãi mà vẫn không sao giải quyết được.
Tôi quyết định tạm thời stop con squid này lại, tìm một giải pháp thay thế. Ban đầu tôi định sử dụng Apache để làm reverse proxy do tôi có nhiều kinh nghiệm với thằng này. Tuy vậy, giải pháp này khá mất thời gian mà con reverse proxy này cũng sẽ bị "kết liễu" trong vài ngày tới, nên tôi quyết định sử dụng chức năng NAT của iptables để làm luôn cho gọn.
Thú thật là rất lâu rồi tôi không đụng đến iptables, nên tôi cũng mất gần 15' coi tài liệu mới nhớ lại cách làm. Tôi ghi lại ở đây để sau này có gặp sự cố tương tự thì có cách giải quyết nhanh:
iptables -t nat -A PREROUTING -p tcp --dport 80 -d 1.1.1.1 -i eth0 -j DNAT --to 2.2.2.2:80
iptables -t nat -A POSTROUTING -p tcp --dport 80 -o eth0 -j SNAT --to 1.1.1.1
Ghi chú:
- 1.1.1.1 là IP address của eth0 trên reverse proxy, 2.2.2.2 là IP address của eth0 trên web-server.
- 2 lệnh này được chạy trên reverse proxy và chúng chỉ "redirect" traffic đến cổng 80, nếu bạn cần redirect traffic đến các cổng khác như 443 chẳng hạn, bạn phải thêm vào các lệnh tương ứng.
- Lệnh số 1 có tác dụng chuyển destination IP address (hence DNAT) của tất cả TCP packet đến cổng 80 của IP 1.1.1.1 thành cổng 80 của IP 2.2.2.2. Lệnh này nằm ở chain PREROUTING, nghĩa là nó được apply trước giai đoạn routing.
- Lệnh số 2 có tác dụng chuyển source IP address (hence SNAT) của tất cả TCP packet đi ra bằng đường eth0 có destination port là 80 thành 1.1.1.1. Lệnh này nằm ở chain POSTROUTING, nghĩa là nó được apply sau giai đoạn routing.
Giải thích:
1. client 3.3.3.3 gửi một packet (src=3.3.3.3, dst=1.1.1.1) đến reverse proxy 1.1.1.1
2. Lệnh thứ nhất sẽ chuyển packet này thành (src=3.3.3.3, dst=2.2.2.2).
3. Lệnh thứ hai sẽ chuyển packet này thành (src=1.1.1.1, dst=2.2.2.2).
3. Sau khi web-server 2.2.2.2 nhận được packet này, nó sẽ tạo ra một packet (src=2.2.2.2, dst=1.1.1.1) và gửi lại cho reverse proxy 1.1.1.1.
4. reverse proxy 1.1.1.1 sẽ nhìn vào NAT table của lệnh thứ hai để chuyển packet này thành (src=2.2.2.2, dst=3.3.3.3)
5. reverse proxy 1.1.1.1 tiếp tục nhìn vào NAT table của lệnh thứ nhất để chuyển packet này thành (src=1.1.1.1, dst=3.3.3.3)
6. reverse proxy 1.1.1.1 gửi packet (src=1.1.1.1, dst=3.3.3.3) lại cho client 3.3.3.3
Tôi vào kiểm tra con squid này thì phát hiện trong log của nó phun ra khá nhiều lỗi. Google cho biết đây là những lỗi khá nghiêm trọng và cũng có đưa ra vài giải pháp, nhưng do tôi không có nhiều kinh nghiệm với squid thành ra loay hoay mãi mà vẫn không sao giải quyết được.
Tôi quyết định tạm thời stop con squid này lại, tìm một giải pháp thay thế. Ban đầu tôi định sử dụng Apache để làm reverse proxy do tôi có nhiều kinh nghiệm với thằng này. Tuy vậy, giải pháp này khá mất thời gian mà con reverse proxy này cũng sẽ bị "kết liễu" trong vài ngày tới, nên tôi quyết định sử dụng chức năng NAT của iptables để làm luôn cho gọn.
Thú thật là rất lâu rồi tôi không đụng đến iptables, nên tôi cũng mất gần 15' coi tài liệu mới nhớ lại cách làm. Tôi ghi lại ở đây để sau này có gặp sự cố tương tự thì có cách giải quyết nhanh:
iptables -t nat -A PREROUTING -p tcp --dport 80 -d 1.1.1.1 -i eth0 -j DNAT --to 2.2.2.2:80
iptables -t nat -A POSTROUTING -p tcp --dport 80 -o eth0 -j SNAT --to 1.1.1.1
Ghi chú:
- 1.1.1.1 là IP address của eth0 trên reverse proxy, 2.2.2.2 là IP address của eth0 trên web-server.
- 2 lệnh này được chạy trên reverse proxy và chúng chỉ "redirect" traffic đến cổng 80, nếu bạn cần redirect traffic đến các cổng khác như 443 chẳng hạn, bạn phải thêm vào các lệnh tương ứng.
- Lệnh số 1 có tác dụng chuyển destination IP address (hence DNAT) của tất cả TCP packet đến cổng 80 của IP 1.1.1.1 thành cổng 80 của IP 2.2.2.2. Lệnh này nằm ở chain PREROUTING, nghĩa là nó được apply trước giai đoạn routing.
- Lệnh số 2 có tác dụng chuyển source IP address (hence SNAT) của tất cả TCP packet đi ra bằng đường eth0 có destination port là 80 thành 1.1.1.1. Lệnh này nằm ở chain POSTROUTING, nghĩa là nó được apply sau giai đoạn routing.
Giải thích:
1. client 3.3.3.3 gửi một packet (src=3.3.3.3, dst=1.1.1.1) đến reverse proxy 1.1.1.1
2. Lệnh thứ nhất sẽ chuyển packet này thành (src=3.3.3.3, dst=2.2.2.2).
3. Lệnh thứ hai sẽ chuyển packet này thành (src=1.1.1.1, dst=2.2.2.2).
3. Sau khi web-server 2.2.2.2 nhận được packet này, nó sẽ tạo ra một packet (src=2.2.2.2, dst=1.1.1.1) và gửi lại cho reverse proxy 1.1.1.1.
4. reverse proxy 1.1.1.1 sẽ nhìn vào NAT table của lệnh thứ hai để chuyển packet này thành (src=2.2.2.2, dst=3.3.3.3)
5. reverse proxy 1.1.1.1 tiếp tục nhìn vào NAT table của lệnh thứ nhất để chuyển packet này thành (src=1.1.1.1, dst=3.3.3.3)
6. reverse proxy 1.1.1.1 gửi packet (src=1.1.1.1, dst=3.3.3.3) lại cho client 3.3.3.3
Comments
Bác có thể phác hoạ mô hình mạng (bằng hình vẻ đơn giản hoặc bằng text) trên của bác ko ? Vì theo mình mô hình trên Con Reverse Proxy phải có 2 NIC, 1 NIC là Public IP, NIC còn lại sẽ có Private IP & và đây chính là NIC connect trực tiếp đến Web Server thật. Như vậy eth0 trong bài viết trên của bácl là NIC nào ?
Thân
iptables -t nat -A POSTROUTING -p tcp --dport 80 -o eth0 -j SNAT --to 1.1.1.1
Ý nghĩa của nó thì mình hiểu (để NAT các máy nằm bên trong có thể đi ra NET được) nhưng mình ko hiểu được ý nghĩa của nó trong trường hợp reverse proxy của bác, mình nghĩ reverse proxy thì chỉ cần dòng đầu tiền (iptables -t nat -A PREROUTING -p tcp --dport 80 -d 1.1.1.1 -i eth0 -j DNAT --to 2.2.2.2:80) là đủ rồi chứ, vì webserver thật bên trong chỉ có nhiệm vụ là nhận request từ bên ngoài và xử lý và respone lại chứ nó đâu có nhu cầu tự mở kết nối ra ngoài đâu mà phải cần source NAT ?
Thân
Nếu chỉ có câu lệnh "iptables -t nat -A PREROUTING -p tcp --dport 80 -d 1.1.1.1 -i eth0 -j DNAT --to 2.2.2.2:80", các packet từ 3.3.3.3 đến rp 1.1.1.1 có (src=3.3.3.3,dst=1.1.1.1) sẽ tự động chuyển thành (src=3.3.3.3,dst=2.2.2.2) rồi chuyển sang cho thằng webserver 2.2.2.2. Lúc này, thằng 2.2.2.2 nhận được packet đó, nó sẽ reply lại cho thằng 3.3.3.3 bằng một packet có (src=2.2.2.2,dst=3.3.3.3), nhưng thằng 3.3.3.3 sẽ từ chối nhận packet này, bởi lẽ lúc đầu nó gửi cho thằng 1.1.1.1, chứ không gửi cho thằng 2.2.2.2. Đó là lý do cần dòng lệnh thứ hai.
BTW, dòng lệnh thứ hai nên sửa lại thế này sẽ chính xác hơn:
iptables -t nat -A POSTROUTING -p tcp -d 2.2.2.2 --dport 80 -o eth0 -j SNAT --to 1.1.1.1
các packet từ 3.3.3.3 đến rp 1.1.1.1 có (src=3.3.3.3,dst=1.1.1.1) sẽ tự động chuyển thành (src=3.3.3.3,dst=2.2.2.2) rồi chuyển sang cho thằng webserver 2.2.2.2. Lúc này, thằng 2.2.2.2 nhận được packet đó, nó sẽ reply lại cho thằng 3.3.3.3 bằng một packet có (src=2.2.2.2,dst=3.3.3.3), nhưng thằng 3.3.3.3 sẽ từ chối nhận packet này, bởi lẽ lúc đầu nó gửi cho thằng 1.1.1.1, chứ không gửi cho thằng 2.2.2.2. Đó là lý do cần dòng lệnh thứ hai.
Đơn giản vì nếu gói tin trả về đi qua máy đã forward cái port vào, iptables đủ thông minh để giải NAT (De-NAT) cho gói tin về địa chỉ trước khi NAT. Nghĩa là trong ví dụ của Thai, gói tin trả về cho 3.3.3.3 sẽ tự thay src=1.1.1.1, dù có hay không có dòng thứ 2. Iptables là statefull, và các CHAIN của nó được bố trí như thế mà.
Cậu cứ thử đi.
MyQuartz.
Mail : ngocanh99999@gmai.com
Thanks and best regards!