Tạo dịch vụ wss
Hỏi:
Workerman làm thế nào để tạo một dịch vụ wss, để khách hàng có thể kết nối và giao tiếp qua giao thức wss, chẳng hạn như kết nối với máy chủ trong ứng dụng nhỏ WeChat.
Đáp:
Giao thức wss thực chất là websocket+SSL, tức là thêm lớp SSL trên giao thức websocket, tương tự như https(http+SSL).
Vì vậy, chỉ cần kích hoạt SSL trên nền tảng giao thức websocket là có thể hỗ trợ giao thức wss.
Phương pháp 1: Sử dụng nginx/apache để ủy quyền SSL (được khuyên dùng)
Lý do được khuyên dùng
- Có thể tái sử dụng cổng 443, khách hàng không cần chỉ định cổng khi kết nối
- Quản lý tập trung chứng chỉ SSL, có thể tái sử dụng cấu hình trang web
- Có thể cân bằng tải
- Tích hợp theo dõi nhật ký
- Tương thích tốt hơn
Nguyên lý và quy trình giao tiếp
-
Khách hàng khởi đầu kết nối wss đến nginx/apache
-
Nginx/apache chuyển đổi dữ liệu giao thức wss thành dữ liệu giao thức ws và chuyển tiếp đến cổng giao thức websocket của Workerman
-
Workerman nhận dữ liệu và xử lý logic nghiệp vụ
-
Khi Workerman gửi tin nhắn cho khách hàng, thì quá trình ngược lại, dữ liệu qua nginx/apache được chuyển đổi thành giao thức wss rồi gửi cho khách hàng
Tham khảo cấu hình nginx
Điều kiện tiên quyết và chuẩn bị:
-
Đã cài đặt nginx, phiên bản không thấp hơn 1.3
-
Giả sử Workerman lắng nghe trên cổng 8282 (giao thức websocket)
-
Đã yêu cầu chứng chỉ (tệp pem/crt và tệp key) giả sử được đặt tại /etc/nginx/conf.d/ssl
-
Dự định sử dụng nginx mở cổng 443 để cung cấp dịch vụ proxy wss ra ngoài (cổng có thể thay đổi theo nhu cầu)
-
Nginx thường chạy như một máy chủ trang web cho các dịch vụ khác, để không ảnh hưởng đến việc sử dụng trang web hiện tại, ở đây sử dụng địa chỉ
domain.com/wsslàm cổng vào proxy wss. Tức là địa chỉ kết nối của khách hàng là wss://domain.com/wss
Cấu hình nginx tương tự như sau:
server {
listen 443;
# Cấu hình tên miền được bỏ qua...
ssl on;
ssl_certificate /etc/ssl/server.pem;
ssl_certificate_key /etc/ssl/server.key;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
ssl_protocols SSLv3 SSLv2 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
location /wss
{
proxy_pass http://127.0.0.1:8282;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Real-IP $remote_addr;
}
# location / {} Cấu hình khác của trang web...
}
Kiểm tra
// Chứng chỉ sẽ kiểm tra tên miền, hãy sử dụng kết nối theo tên miền. Lưu ý không có cổng ở đây
ws = new WebSocket("wss://domain.com/wss");
ws.onopen = function() {
alert("Kết nối thành công");
ws.send('tom');
alert("Gửi một chuỗi đến máy chủ: tom");
};
ws.onmessage = function(e) {
alert("Nhận tin nhắn từ máy chủ: " + e.data);
};
Sử dụng apache làm proxy wss
Cũng có thể sử dụng apache làm proxy để chuyển tiếp đến workerman.
Chuẩn bị:
-
GatewayWorker lắng nghe cổng 8282 (giao thức websocket)
-
Đã yêu cầu chứng chỉ SSL, giả sử được đặt tại /server/httpd/cert/
-
Sử dụng apache để chuyển tiếp cổng 443 đến cổng 8282 đã chỉ định
-
httpd-ssl.conf đã được tải
-
openssl đã được cài đặt
Kích hoạt mô-đun proxy_wstunnel_module
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
Cấu hình SSL và proxy
#extra/httpd-ssl.conf
DocumentRoot "/thư mục/website"
ServerName domain
# Cấu hình proxy
SSLProxyEngine on
ProxyRequests Off
ProxyPass /wss ws://127.0.0.1:8282/wss
ProxyPassReverse /wss ws://127.0.0.1:8282/wss
# Thêm hỗ trợ giao thức SSL, loại bỏ các giao thức không an toàn
SSLProtocol all -SSLv2 -SSLv3
# Thay đổi bộ mã hóa như sau
SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM
SSLHonorCipherOrder on
# Cấu hình khóa công khai của chứng chỉ
SSLCertificateFile /server/httpd/cert/your.pem
# Cấu hình khóa riêng của chứng chỉ
SSLCertificateKeyFile /server/httpd/cert/your.key
# Cấu hình chuỗi chứng chỉ,
SSLCertificateChainFile /server/httpd/cert/chain.pem
Kiểm tra
// Chứng chỉ sẽ kiểm tra tên miền, hãy sử dụng kết nối theo tên miền. Lưu ý không có cổng
ws = new WebSocket("wss://domain.com/wss");
ws.onopen = function() {
alert("Kết nối thành công");
ws.send('tom');
alert("Gửi một chuỗi đến máy chủ: tom");
};
ws.onmessage = function(e) {
alert("Nhận tin nhắn từ máy chủ: " + e.data);
};
Phương pháp 2: Sử dụng Workerman để mở SSL trực tiếp (không được khuyên dùng)
Chú ý
Ủy quyền SSL nginx/apache và cài đặt SSL Workerman là hai lựa chọn, không thể mở đồng thời.
Chuẩn bị:
-
Workerman phiên bản >= 3.3.7
-
PHP đã cài đặt phần mở rộng openssl
-
Đã yêu cầu chứng chỉ (tệp pem/crt và tệp key) được đặt ở bất kỳ thư mục nào trên đĩa
Mã:
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// Chứng chỉ tốt nhất là chứng chỉ đã yêu cầu
$context = array(
// Tham khảo thêm các tùy chọn ssl trong tài liệu http://php.net/manual/zh/context.ssl.php
'ssl' => array(
// Vui lòng sử dụng đường dẫn tuyệt đối
'local_cert' => 'đường dẫn đĩa/server.pem', // cũng có thể là tệp crt
'local_pk' => 'đường dẫn đĩa/server.key',
'verify_peer' => false,
'allow_self_signed' => true, // nếu là chứng chỉ tự ký, cần mở tùy chọn này
)
);
// Ở đây đang thiết lập giao thức websocket (cổng bất kỳ, nhưng cần bảo đảm không bị chương trình khác chiếm dụng)
$worker = new Worker('websocket://0.0.0.0:8282', $context);
// Thiết lập transport mở ssl, websocket+ssl tức là wss
$worker->transport = 'ssl';
$worker->onMessage = function(TcpConnection $con, $msg) {
$con->send('ok');
};
Worker::runAll();
Với mã trên, Workerman đã lắng nghe giao thức wss, khách hàng có thể kết nối với workerman qua giao thức wss để thực hiện giao tiếp tức thì an toàn.
Kiểm tra
Mở trình duyệt chrome, nhấn F12 để mở bảng điều khiển gỡ lỗi, trong phần Console nhập (hoặc đưa mã dưới đây vào trang html để chạy bằng js)
// Chứng chỉ sẽ kiểm tra tên miền, hãy sử dụng kết nối theo tên miền, lưu ý có số hiệu cổng ở đây
ws = new WebSocket("wss://domain.com:8282");
ws.onopen = function() {
alert("Kết nối thành công");
ws.send('tom');
alert("Gửi một chuỗi đến máy chủ: tom");
};
ws.onmessage = function(e) {
alert("Nhận tin nhắn từ máy chủ: " + e.data);
};
Lỗi thường gặp
SSL routines:SSL23_GET_CLIENT_HELLO:http request
Nguyên nhân là do khách hàng sử dụng ws://domain.com để truy cập dẫn đến, địa chỉ truy cập đúng nên là wss://domain.com, tức là phải truy cập bằng giao thức wss.
Xuất hiện lỗi này trong hầu hết các trường hợp là do cổng ban đầu là ws nhưng đột nhiên thay đổi thành wss và một số trang khách hàng chưa được làm mới, vẫn truy cập bằng ws, dẫn đến lỗi.
Lỗi này có thể bỏ qua, không ảnh hưởng đến kết nối wss bình thường.
Chú ý:
-
Nếu phải sử dụng cổng 443 hãy sử dụng phương pháp ủy quyền nginx/apache như trên để thực hiện wss.
-
Cổng wss chỉ có thể được truy cập qua giao thức wss, không thể truy cập cổng wss bằng ws.
-
Chứng chỉ thường được liên kết với tên miền, vì vậy khi thử nghiệm, hãy sử dụng kết nối theo tên miền, không nên dùng ip để kết nối.
-
Nếu xuất hiện tình trạng không thể truy cập, hãy kiểm tra tường lửa của máy chủ.
-
Phương pháp này yêu cầu phiên bản PHP >= 5.6, vì ứng dụng nhỏ WeChat yêu cầu tls1.2, mà các phiên bản dưới PHP 5.6 không hỗ trợ tls1.2.
Các bài viết liên quan:
Thông qua proxy để lấy địa chỉ IP thật của khách hàng
Tham khảo các tùy chọn ngữ cảnh ssl của workerman