Cũng định viết bài này lâu rồi cơ mà cuối năm 2016 bận quá lại thôi, đợi mãi mà thằng nginx nó không chịu sửa lỗi nên hôm này viết ra đây.
Như tiêu đề, bài này không hướng dẫn cài đặt HTTPS cho website mà giúp các bạn tìm hiều nguyên nhân và sửa lỗi HTTP/2 (H2). Tại sao cấu hình HTTP/2 trên VPS/Server đúng mà trình duyệt nó vẫn báo là HTTP/1.1 mới nhọ, một lỗi mà rất nhiều site dùng HTTPS bị.
Mình lấy THỦY SYS ra diễn giải cho dễ hiểu.
– Website của mình đang chạy trên CentOS 7 dùng HTTPS và HTTP/2 được cấu hình làm chuẩn truyền dữ liệu giữa client và thuysys.com để trang có tốc độ load trang bá đạo nhất.
– Bộ cài nginx lấy từ repo của nginx.org nên nó được built sẵn với OpenSSL version 1.0.1e-fips đây là phiên bản thời napoleon không còn được support nữa. Rủi mà thế giới có công bố thêm cái bug nào giống Heatbleed thì mình không muốn website mình nằm trong số đó. Để nâng cấp openssl lên bản mới hơn thì phải biên dịch nginx (compile) lại từ source chứ không thể thêm thắt module đơn giản như server chạy Apache được.
– Dùng OpenSSL 1.0.1 nên thuysys.com chỉ hỗ trợ giao thức NPN (Next Protocol Negotiation).
– Lý do tiếp theo là hiện tại hầu như tất cả người dùng đều sử dụng trình duyệt Chrome version 56 và Firefox version 51 bản mới nhất tính đến thời điểm viết bài. Các trình duyệt này được mặc định dùng giao thức ALPN (Application Layer Protocol Negotiation) khi truy cập trang HTTPS.
Ừ thí đúng là như thế đấy, rồi sao ?
Bây giờ mình sẽ giải thích và xâu chuỗi lại các vấn đề lại.
1. ALPN & NPN là gì ?
Hầu như bạn không quan tâm đến hai khái niệm này nếu như web bạn không dùng HTTPS và HTTP/2.
Quay lại lịch sử một tí, từ thời Google phát triển SPDY cho HTTPS dùng chuẩn HTTP/1.1 thì quá trình đàm phán TCP (negotiation) giữa Client ( trình duyệt) và Server ( Webserver Nginx) sử dụng giao thức NPN. Đến hiện tại khi HTTPS đã dùng chuẩn HTTP/2 mới thì NPN không còn phù hợp nữa. Giao thức ALPN được phát triển thay thế cho NPN trong quá trình negotiation. Đồng thời các nhà phát triển trình duyệt Google, Firefox … cũng theo đó mà chuyển sang ALPN.
Như vậy, nếu ai đó dùng trình duyệt phiên bản mới muốn truy cập website của bạn bằng HTTP/2 thì Webserver của bạn buộc phải hỗ trợ tương tác bằng ALPN. Nếu không bạn sẽ dùng NPN vơi HTTP/1.1 và đánh mất lợi thế rất lớn khi dùng HTTPS vì HTTP/2 không hoạt động.
Ở hình bên trên bạn thấy chỉ có cái file analytics.js
của thằng Google dùng H2 vì đây là script được load từ Google chứ không phải từ server của bạn đâu, đừng thấy có chữ H2 là nghĩ nó chạy H2 rồi nhá.
Bạn đã hiểu vấn đề, để giải quyết chúng ta buộc phải biên dịch lại mã nguồn của NGINX.
2. Chuẩn bị
Tóm lại muốn dùng HTTP/2 thì phải hỗ trợ ALPN mà muốn có ALPN thì phải dùng OpenSSL version 1.0.2 trở lên. Với NGINX muốn làm được điều đó thì phải compile lại nginx với OpenSSL.
Vì đã mất công compile mình sẽ dùng Nginx và OpenSSL bản mới nhất, toàn bộ dư liệu down về mình để trong thư mục /data
, bạn thích để thư mục khác thì tùy miễn sao dễ nhớ.
- NGINX version 1.11.10
wget https://nginx.org/download/nginx-1.11.10.tar.gz
- OpenSSL 1.1.0e
wget https://www.openssl.org/source/openssl-1.1.0e.tar.gz
- Thêm repo EPEL, bạn chưa cài có thể chạy lệnh bên dưới.
yum install epel #hoặc yum install epel-release
- VPS/Server đang chạy webserver nginx, ai đang setup webserver mới cũng áp dụng được nội dung bài này không khác gì cả.
Nếu các bạn dùng Ubuntu bản 16.04 LTS trở lên thì có thể bỏ qua bài viết này, vì nginx đã được built với OpenSSL 1.0.2g rồi.
3. Biên dịch nginx.
Mục tiêu: biên dịch lại nginx với openssl để khích hoạt ALPN thì ok nhưng tuyệt đối không được làm website bị stop hay mất một request nào. Nghe có vẻ khó khăn nhưng rất đơn giản nginx cung cấp cho bạn cơ chế update binary rất tuyệt với, bạn cứ làm theo bài này là ngon thôi.
Đầu tiên bạn cần cài đặt công cụ để biên dịch, nginx viết bằng C thì bạn cần cài trình biên dịch ngôn ngữ C, rồi dùng gzip module thì cài zlib và cài thêm thư viện PCRE cho module rewrite.
Lệnh cài:
yum install gcc-c++ pcre-devel zlib-devel
Tiếp theo bạn cần lấy các thông tin cấu hình nginx webserver đang chạy, lệnh.
nginx -V
Output sẽ như hình bên dưới
[root@srv1 ~]# nginx -V nginx version: nginx/1.10.2 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC) built with OpenSSL 1.0.1e-fips 11 Feb 2013 TLS SNI support enabled configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic'
Bạn thấy các thông tin về webserver, hiện nó đang chạy bản nginx 1.10.2 và openssl 1.0.1e.
Tiếp theo copy cái đoạn Configure arguments đánh dấu đỏ và lưu lại đấy sẽ là các thông số bạn dùng để compile lại nginx, phải chính xác tuyệt đối đấy.
Sau đó chúng ta sẽ giải nén source nginx và openssl vừa down về trong /data
, chạy hai lệnh:
tar -xvf nginx-1.11.10.tar.gz tar -xvf openssl-1.1.0e.tar.gz
Giải nén xong bạn vào thư mục chứa source nginx để compile, lệnh:
cd nginx-1.11.10
Nhập thông số cấu hình với lệnh ./configure
, nhớ là paste nguyên cái đoạn mình đã đánh dấu đỏ ở bước trên và thêm vào --with-openssl=/data/openssl-1.1.0e
(đây là đường dẫn đến source của openssl).
Toàn bộ thông số cấu hình sẽ như sau và chú ý cái dòng đỏ cuối cùng:
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-mail \
--with-mail_ssl_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic' \
--with-openssl=/root/openssl-1.1.0e
Đợi khoảng 30s kết quả config như bên dưới là thành công.
Configuration summary + using threads + using system PCRE library + using OpenSSL library: /root/openssl-1.1.0e + using system zlib library nginx path prefix: "/etc/nginx" nginx binary file: "/usr/sbin/nginx" nginx modules path: "/usr/lib64/nginx/modules" nginx configuration prefix: "/etc/nginx" nginx configuration file: "/etc/nginx/nginx.conf" nginx pid file: "/var/run/nginx.pid" nginx error log file: "/var/log/nginx/error.log" nginx http access log file: "/var/log/nginx/access.log" nginx http client request body temporary files: "/var/cache/nginx/client_temp" nginx http proxy temporary files: "/var/cache/nginx/proxy_temp" nginx http fastcgi temporary files: "/var/cache/nginx/fastcgi_temp" nginx http uwsgi temporary files: "/var/cache/nginx/uwsgi_temp" nginx http scgi temporary files: "/var/cache/nginx/scgi_temp"
Gõ lệnh tiếp.
make
Đợi thêm 5 phút nữa là compile xong bạn có thể dùng bộ source này chạy như một webserver hoàn chỉnh rồi.
Compile nghe có vẻ hầm hố nhưng nó có mấy bước đấy thôi, quan trọng là bạn phải hiểu các thông số config và tác dụng của những module được thêm vào.
4. Nâng cấp nginx
Việc quan trọng bây giờ chúng ta phải thay thế phiên bản nginx 1.10.2 sang 1.11.10 mà không làm gián đoạn truy cập của người dùng.
Đầu tiên bạn phải xác định webserver nginx đang chạy với PID là bao nhiêu và binary của nó ở đâu. Bạn có thể dùng lệnh ps
hoặc htop
đều được.
Dùng lệnh ps
thử phát xem sao.
ps ax |grep nginx |grep master
Kết quả.
3695 ? Ss 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
Vậy là nginx đang chạy có PID 3695
và file binary có đường dẫn /usr/sbin/nginx
.
Nếu là “lần đầu tiên làm chuyện ấy” cứ backup file binary cũ của nginx lại cho chắc, thực chất việc nâng cấp nginx là thay thế file binary cũ bằng file binary mới hơn.
Đổi tên file nginx
sang nginx.bak
để lưu lại.
mv /usr/sbin/nginx /usr/sbin/nginx.bak
Bạn yên tầm file binary đã được nạp vào bộ nhớ của server rồi có delete đi thì website vẫn truy cập ầm ầm. Sau đó copy file binary mới sang thay thế, lệnh.
cp /data/nginx-1.11.10/objs/nginx /usr/sbin/nginx
Xong bước này server của bạn đã được nâng cấp lên phiên bản mới bạn có thể kiểm tra bằng lệnh nginx -V
.
Nếu không quan tâm đến việc người dung nghĩ gì khi website bị gián đoạn bạn chỉ cần restart server là coi như công cuộc nâng cấp webserver hoàn tất. Nếu coi là việc lớn thì phải làm thêm một số bước nữa để chuyển đổi hoàn toàn sang phiên bản mới.
Trên terminal nhập lệnh.
kill -s USR2 3695
Mục đích để gửi tính hiệu USR2
đến Master Process thông báo thay đổi PID để nâng cấp binary mới. Bạn show lại sẽ thấy một master process nữa được tạo ra với PID 5852
khác.
Tiếp theo sẽ stop tất cả các Worker Process con của Master Process, lệnh.
kill -s WINCH 3695
Và lệnh cuối cùng để stop hẳn Master Process có PID 3695
và chạy nginx với PID 5852
thay thế.
kill -s QUIT 3695
Done, xong việc website không mất bất cứ request nào quá trình nâng cấp webserver là như vô hình với người dùng. Bạn dùng htop xem lại sẽ thấy nginx đang chạy với PID 5852
.
Kiểm tra trên trình duyệt Chrome, truy cập lại website thuysys và kết như bên dưới.
Bây giờ site của bạn đã thực sự dùng HTTP/2 rồi, tốc độ cũng tăng lên chút, lúc đầu load trang chủ thuysys.com là 380ms giờ xuống còn 287ms.
Mấy hôm nay gọi lên tổng đài CMC các bác lại báo đứt cáp, truy cập THUYSYS từ Việt Nam chậm đi một chút vì mình thuê VPS nước ngoài mà, với site cùi này thì tốc độ đó cũng khá ngon rồi.
Thôi kết lại, site nào đang dùng các distro cũ như Debian 8, CentOS 6.8, CentOS 7 và Ubuntu 14.04 nhớ biên dịch lại nginx nhé, tất cả đều đang chạy với OpenSSL 1.0.1 đấy.
Chào quyết thắng và hẹn gặp lại trong bài tiếp theo.
admin cho mình hỏi có nhà cung cấp host nào có http2 không ah.
Mình không rõ hóting nào
.Chào ad, mình có làm theo hướng dẫn tới đoạn nhập thông số cấu hình với lệnh ./configure.
/configure –prefix=/etc/nginx –sbin-path=/usr/sbin/nginx –modules-path=/usr/lib64/nginx/modules –conf-path=/etc/nginx/nginx.conf –error-log-path=/var/log/nginx/error.log –http-log-path=/var/log/nginx/access.log –pid-path=/var/run/nginx.pid –lock-path=/var/run/nginx.lock –http-client-body-temp-path=/var/cache/nginx/client_temp
Sao khi chạy lênh này nó lại báo
checking for gcc -pipe switch … found
checking for -Wl,-E switch … found
checking for gcc builtin atomic operations … found
checking for C99 variadic macros … found
checking for gcc variadic macros … found
…….
Mà không hiện kết quả config như trong bài của ad nhỉ ?
Bạn cài đủ mấy thư viện này chưa
gcc-c++ pcre-devel zlib-devel
Nội dung bạn gửi không thấy lỗi.Chào anh Thủy, cho em hỏi lúc em nhập thông số cấu hình với lệnh ./configure thì nó trả kết quả lỗi như phía dưới. Trong khi mấy đường dẫn này có tồn tại mà 🙁
-bash: –prefix=/etc/nginx: No such file or directory
-bash: –sbin-path=/usr/sbin/nginx: No such file or directory
-bash: –modules-path=/usr/lib64/nginx/modules: No such file or directory
-bash: –conf-path=/etc/nginx/nginx.conf: No such file or directory
-bash: –error-log-path=/var/log/nginx/error.log: No such file or directory
-bash: –http-log-path=/var/log/nginx/access.log: No such file or directory
Bạn kiểm tra lại dấu “cách (space)”, “/”, “\” đã đúng hay chưa
Cho em hỏi vấn đề này là khi mình ./configure nginx mới thì nó có đè lên config của nginx cũ ko anh ?
Không, khi bạn make install thì mới ghi đè lên file cấu hình.
Em làm tới bước make compile nginx thì bị lỗi
make: *** No rule to make target `build’, needed by `default’. Stop.
Cái này giải quyết thế nào ạ ?
bài viết hay quá, rất chi tiết và tỉ mỉ. bạn có face hoặc skype ko? mình có thể add face và skype của bạn được ko?
Thanks bạn ủng hộ, bạn có thể liên hệ với mình qua facebook.com/thuysysdotcom hoặc comment trên thuysys.com.