Hướng dẫn sử dụng Apache như một reverse proxy bằng công cụ mod_proxy trên CentOS 7

1 năm trước

 

Giới thiệu

 reverse proxy là một loại proxy server nhận yêu cầu truy cập HTTP rồi sau đó phân bổ tới một hoặc nhiều server phụ trợ. Nó là một công cụ rất hữu hiệu vì rất nhiều các ứng dụng web ngày nay đều xử lý đầu vào từ nguồn HTTP bằng các server ứng dụng phụ trợ mà người dùng không thể truy cập trực tiếp được và thường chỉ hỗ trợ các tính năng HTTP căn bản . 

Có thể sử dụng reverse proxy để ngăn chặn các server ứng dụng phụ trợ này khỏi bị truy cập trực tiếp. Hoặc cũng có thể được sử dụng để phân bổ lượng truy cập đầu vào tới nhiều server ứng dụng khác nhau nhằm tăng hiệu quả về mặt quy mô cũng như tính an toàn cho ứng dụng. Hơn nữa chúng có thể khắc phục các lỗ hổng mà các server ứng dụng không thể làm được như là bộ đệm, bộ nén , hệ thống ma hóa SSL.

Trong phần này ta sẽ cài Apache như là một reverse proxy căn bản sử dụng công cụ mở rộng   mod_proxy để định vị lại các kết nối đầu vào với nhiều server phụ trợ đang hoạt động trên cùng một mạng lưới. Cụ thể hơn ta sẽ dùng  Flask web framework.

Yêu cầu căn bản

  • Một máy chủ Cloud Server CentOS 7 và người dùng giả định sudo.
  • Cài đặt ứng dụng Apache 2.
  • Công cụ chỉnh sửa văn bản nano cài bằng yum install nano (không bắt buộc). CentOS thường dùng vi , nhưng nano thì hữu dụng hơn.
 

Bước 1 - Giới thiệu những modun Apache cần thiết

Bên cạnh modun mod_proxy  thì ta cần thêm vài modun phụ trợ khác để mở rộng thêm chức năng hoạt động cũng như có thể hỗ trợ nhiều giao thức mạng khác nhau.

  • mod_proxy điều hướng kết nối , biến Apache thành một gateway cho các server ứng dụng phụ trợ.
  • mod_proxy_http, hỗ trợ kết nối HTTP.
  • mod_proxy_balancer và mod_lbmethod_byrequests, tạo tính năng cân bằng tải cho các server phụ trợ đa năng.

Tất cả các modun đó được cài mặc định trên CentOS 7 , bạn có thể xác minh bằng lệnh sau:

httpd -M 

Kết quả trả về liệt kê tên tất cả các modun Apache đang hoạt động :

Output
. . . proxy_module (shared) 
. . . lbmethod_byrequests_module (shared) 
. . . proxy_balancer_module (shared) 
. . . proxy_http_module (shared) 
. . . 

Nếu thiếu một modun nào vừa nêu thì bạn vào mục /etc/httpd/conf.modules.d/00-proxy.conf để mở với lệnh nano:

sudo nano /etc/httpd/conf.modules.d/00-proxy.conf 

Và nếu muốn modun nào hoạt động thì chỉ cần bỏ ký tự # đầu dòng đi là xong:

/etc/httpd/conf.modules.d/00-proxy.conf
. . . LoadModule proxy_module modules/mod_proxy.so. . . LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so. . . LoadModule proxy_balancer_module modules/mod_proxy_balancer.so. . . LoadModule proxy_http_module modules/mod_proxy_http.so. . . 

Lưu và khởi động lại Apache để lưu thay đổi.

sudo systemctl restart httpd 

Apache giờ hoạt động như một reverse proxy cho các yêu cầu truy cập HTTP. Tiếp theo ta sẽ tạo hai server phụ trợ căn bản để xác minh liệu cấu hình cài đặt có hoạt động đúng hay không. Nếu bạn đã có server rồi thì không cần làm bước 3 nữa.

 

Bước 2 - Tạo các Server phụ trợ kiểm tra

Ta sẽ chạy thử các server phụ trợ đơn giản để kiểm tra xem liệu rằng cấu hình Apache vừa thay đổi có hoạt động đúng hay không. Ta sẽ dùng 2 server để phản hồi lại truy cập HTTP và hiển thị kết quả, một cái hiển thị  Hello world! và cái còn lại sẽ là Howdy world!.

Note: Trong tình huống cài đặt không kiểm tra thì các server phụ trợ sẽ trả về kết quả như nhau. Tuy nhiên trong phần này ta dùng 2 server để gửi về 2 tin nhắn khác nhau để có thể dễ dàng kiểm tra cơ chế cân bằng tải của nó.

Flask là một microframework của Python để xây dựng các ứng dụng web , ta dùng Flask để tạo các server kiểm tra vì việc tạo một ứng dụng cơ bản chỉ cần vài dòng code đơn giản là xong.

Ta sẽ cài gói IUS (Inline with Upstream Stable) là một dự án cộng đồng mang đến những phiên bản phần mềm mới nhất cho CentOS bao gồm Python 3:

sudo yum -y install https://centos7.iuscommunity.org/ius-release.rpm 

Sau đó cài Python 3 và Pip, trình quản lý gói Python.

sudo yum -y install python35u python35u-pip 

Sử dụng Pip để cài Flask.

sudo pip3.5 install flask 

Giờ thì ta sẽ tạo một file mới cho server phụ trợ đầu tiên trong thư mục chính của người dùng hiện tại.

nano ~/backend1.py 

Copy đoạn code dưới đây vào file rồi lưu và đóng lại.

~/backend1.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'Hello world!'

Hai dòng đầu khởi tạo Flask framework. Chức năng home() sẽ trả về dòng (Hello world!). Dòng @app.route('/') bên trên home() sử dụng để thông báo Flask dùng giá trị trả về của   home()  để phản hồi lại yêu cầu truy cập HTTP tại địa chỉ  / URL gốc của ứng dụng.

Server phụ trợ thứ hai cũng giống như cái thứ nhất , nên ta chỉ việc copy là xong.

cp ~/backend1.py ~/backend2.py 

Mở file đó ra.

nano ~/backend2.py 

Thay đổi giá trị trả về Hello world! thành Howdy world!, rồi lưu và đóng file.

~/backend2.py
from flask import Flask
app = Flask(__name__)@app.route('/')
def home():
return 'Howdy world!'

Sử dụng lệnh sau để khởi động server phụ trợ đầu tiên trên cổng 8080. Nó cũng sẽ điều hướng đầu ra Flask ở mục /dev/null vì nó sẽ tạo đám mây để quản lý đầu ra trên đó.

FLASK_APP=~/backend1.py flask run --port=8080 >/dev/null 2>&1 & 

Giờ thì ta sẽ thao tác lệnh flask trước bằng cách cài biến môi trường FLASK_APP  trên cùng một dòng, biến môi trường là một cách tiện lợi để truyền thông tin tới hệ thống xử lý được tạo ra từ shell.

Trong trường hợp này, ta sử dụng biến môi trường để đảm bảo việc cài đặt chỉ được áp dụng khi lệnh đang chạy và sẽ không còn tồn tại sau đó vì ta còn muốn truyền thêm một file nữa vào trên cùng một biến đó để lệnh cho  flask khởi động server phụ trợ thứ hai.

Tương tự như thế ta khởi động server phụ trợ thứ hai cũng trên cổng 8081. Nhưng lưu ý là cần đặt giá trị khác cho biến môi trường FLASK_APP nhé.

FLASK_APP=~/backend2.py flask run --port=8081 >/dev/null 2>&1 & 

Kiểm tra cả hai server sử dụng lệnh curl. server đầu tiên:

curl http://127.0.0.1:8080/ 

Đầu ra hiển thị Hello world! ở đoạn cuối. Kiểm tra server thứ hai:

curl http://127.0.0.1:8081/ 

Đầu ra sẽ là  Howdy world! .

Note: Để đóng cả hai server kiểm tra này khi bạn không cần dùng nó nữa, bạn có thể sử dụng killall flask.

Tiếp theo là điều chỉnh cấu hình Apache để nó hoạt động như một reverse proxy.

 

Bước 3 - Điều chỉnh cấu hình mặc định để hữu hiệu hóa Reverse Proxy

 Ta sẽ cài đặt Apache virtual host mặc định để hoạt động như một reverse proxy cho một hoặc một nhóm server phụ trợ cân bằng tải.

Note:Ta đang áp dụng cấu hình ở mức độ virtual host. Theo mặc định thì khi cài Apache sẽ không có virtual host nên ta sẽ tạo một virtual host mặc định sẽ đáp ứng tất cả các lưu lượng truy cập và bạn cũng có thể sử dụng cấu hình này để áp dụng cho các virtual host khác.

Nếu Apache server hoạt động ở cả HTTP và HTTPS server,thì cấu hình reverse proxy cần phải đặt ở cả  HTTP và HTTPS virtual hosts.

Tạo một virtual host mặc định bằng cách tạo một file cấu hình Apache trống ở mục   /etc/httpd/conf.d sử dụng nano .

sudo nano /etc/httpd/conf.d/default-site.conf 

Ví dụ đầu tiên là hướng dẫn cách cài virtual host cho reverse proxy dành cho một server phụ trợ đơn lẻ, và ví dụ thứ hai là dành cho các server phụ trợ đa năng.

Ví dụ 1 - Cài reverse proxy dành cho server phụ trợ đơn 

Dán đoạn mã dưới đây vào file default-site.conf :

/etc/httpd/conf.d/default-site.conf
ProxyPreserveHost OnProxyPass / http://127.0.0.1:8080/ProxyPassReverse / http://127.0.0.1:8080/

 Nếu làm theo bước 2 thì sử dụng địa chỉ  127.0.0.1:8080 để ghi vào khối bên trên. Còn nếu không thì sử dụng địa chỉ của server ứng dụng của riêng bạn. 

Có 3 mục xuất hiện:

  • ProxyPreserveHost giúp Apache truyền qua header Host  tới server phụ trợ. Điều này giúp cho  server phụ trợ có thể nhận biết được địa chỉ truy cập vào ứng dụng của nó.
  • ProxyPasslà mục cấu hình proxy chính, trong trường hợp này nó xác định tất cả dữ liệu dưới URL gốc (/) để ánh xạ tới server phụ trợ tại địa chỉ cho trước. Ví dụ nếu Apache nhận yêu cầu truy cập /example, nó sẽ kết nối tới http://your_backend_server/example và phản hồi kết quả cho người truy cập.
  • ProxyPassReverse có cùng cấu hình với ProxyPass. Nó lệnh cho Apache điều chỉnh header phản hồi từ server phụ trợ để đảm bảo rằng nếu nó trả về header được định vị lại vị trí, thì trình duyệt của người truy cập sẽ được điều hướng lại tới địa chỉ proxy chứ không phải địa chỉ server phụ trợ, cái mà sẽ không hoạt động như dự kiến.

Khởi tạo lại Apache để lưu thay đổi.

sudo systemctl restart httpd 

Giờ nếu truy cập http://your_server_ip  bạn  sẽ thấy server phụ trợ phản hồi lại thay vì page Apache chuẩn. Nghĩa là nếu làm theo bước 2 thì bạn sẽ thấy dòng Hellow world!

Ví dụ 2 - Cân bằng tải qua các server phụ trợ đa năng

Nếu có các server phụ trợ đa năng thì bạn cần phân bố lưu lượng truy cập qua chúng khi cấu hình proxy để sử dụng các tính năng cân bằng tải của mod_proxy.

Thay toàn bộ nội dung trong VirtualHost bằng nội dung sau, cấu hình của bạn sẽ thế này:

/etc/httpd/conf.d/default-site.conf
BalancerMember http://127.0.0.1:8080BalancerMember http://127.0.0.1:8081ProxyPreserveHost OnProxyPass / balancer://mycluster/ProxyPassReverse / balancer://mycluster/

Cũng giống với cái trước nhưng thay vì chỉ định cho server phụ trợ đơn thì ta đã sử dụng một khối Proxy thêm vào để định nghĩa các server đa năng. Khối sẽ được đặt tên là   balancer://mycluster (có thể thay thế tùy bạn) gồm một vài BalancerMemberxác định địa chỉ server phụ trợ. Còn ProxyPass và ProxyPassReversesử dụng công cụ cân bằng tải gọi là mycluster thay vì một server cụ thể nào đó.

Nếu làm theo bước 2 thì sử dụng địa chỉ  127.0.0.1:8080 và 127.0.0.1:8081 cho mục BalancerMember trong khối trên. Còn không thì sử dụng địa chỉ của riêng bạn.

Khởi tạo lại Apache để lưu thay đổi.

sudo systemctl restart httpd 

Nếu truy cập http://your_server_ip bạn sẽ thấy server phụ trợ phản hồi lại thay vì một page Apache chuẩn,và nếu làm như ví dụ bước 2 thì sẽ hiển thị Hello world! và Howdy world!,  nghĩa là reverse proxy đang hoạt động và là một công cụ cân bằng tải giữa hai server.

Kết luận

Như vậy bạn đã biết cách cài Apache hoạt động như một reverse proxy cho một hoặc nhiều các server phụ trợ . mod_proxy  có thể được sử dụng một cách rất hữu hiệu để định cấu hình reverse proxy cho các server ứng dụng sử dụng trong hầu hết các nhóm ngôn ngữ lập trình và công nghệ như Python và Django hoặc Ruby và Ruby trên Rails.  Cũng có thể được sử dụng để cân bằng luồng dữ liệu giữa các server phụ trợ đa năng với nhiều lưu lượng truy cập hoặc để cung cấp tính khả dụng cao cho các server đa năng hay cung cấp công cụ SSL bảo mật phục vụ cho server phụ trợ chứ không phải là hỗ trợ SSL một cách đơn thuần.

Trong khi  mod_proxy với mod_proxy_http là dạng kết hợp modun phổ biến nhất thì vẫn có nhiều dạng kết hợp khả dụng khác được sử dụng để hỗ trợ các giao thức mạng khác nhau như là:

  • mod_proxy_ftp cho FTP.
  • mod_proxy_connect cho ống SSL.
  • mod_proxy_ajp cho AJP (Apache JServ Protocol),giống như công cụ phụ trợ dựa trên nền tảng Tomcat.
  • mod_proxy_wstunnel cho web sockets.