Cấu hình HTTPS đúng chưa chắc đã dùng được HTTP/2 ?

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ị.

Kiểm tra HTTP2 Protocol - Trước

Trước khi dùng HTTP/2

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 56Firefox 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
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.

Check PID Master Process

Dùng lệnh PS

Htop check Master Process PID

Dùng lệnh HTOP

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 ProcessPID 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.

Check HTTP/2 trên Chrome - Sau

Sau khi dùng được HTTP/2

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 7Ubuntu 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.

11 Comments

  1. phố nhạc May 11, 2018 Reply
    • Mr Thủy May 11, 2018 Reply
  2. Bouble June 4, 2017 Reply
    • Mr Thủy June 4, 2017 Reply
  3. KimGiang June 3, 2017 Reply
    • Mr Thủy June 3, 2017 Reply
  4. Huy Tran June 1, 2017 Reply
    • Mr Thủy June 1, 2017 Reply
  5. Huy Tran June 1, 2017 Reply
  6. Hai Au February 22, 2017 Reply
    • admin February 22, 2017 Reply

Leave a Reply