Cấu hình HTTPS với nginx và Let's Enscrypt

(Last update on May 24, 2018: Bổ sung phần cấu hình wildcard)

Bạn vừa mua domain getsolution.pro trên GoDaddy với giá $0.99 trong năm đầu. Vài phút sau, bạn trỏ nó về một server ở Digital Ocean. Trên server này, bạn dùng nginx bắt các requests và forward đến port 5678, nơi có một Node.js process đang chạy Nuxt.js để render website của bạn.

Tại sao phải HTTPS?

Bỏ qua phần thiết lập trên GoDaddy và Digital Ocean. Chúng ta chỉ cần quan tâm tầng máy chủ web trở xuống. File cấu hình nginx của domain là /etc/nginx/sites-enabled/getsolution, lúc này đại khái trông như sau:

server {

  listen 80;

  server_name getsolution.pro;

  location / {
    proxy_pass http://127.0.0.1:5678;
    # other stuff
  }

}

Như vậy người dùng sẽ truy cập vào website của bạn theo đường dẫn http://getsolution.pro.

Website with HTTP protocol

Lúc này mọi dữ liệu trao đổi giữa máy khách với máy chủ của bạn đi qua giao thức HTTP và hoàn toàn không được mã hóa.

Để tăng cường bảo mật, giúp người dùng tin tưởng hơn, bạn nên tạo SSL Certificate cho domain getsolution.pro, sau đó cài đặt nginx tự điều hướng trang web của bạn về https://getsolution.pro.

Trước kia, muốn mua được SSL Certificate cũng khá tốn kém và đòi hỏi nhiều bước chứng thực. Còn bây giờ, Let's Enscrypt đã mang đến cho chúng ta một giải pháp hoàn toàn miễn phí, trình tự thao tác thực hiện cũng rất nhanh chóng, dễ dàng.

Thêm một lý do nữa, việc trang bị HTTPS thay cho HTTP còn có ý nghĩa về mặt thẩm mỹ và nâng cao đẳng cấp cho website của bạn. Web HTTP ngày nay bị xem như thành phần đáng ngờ, những công dân hạng hai trên internet. Chỉ có HTTPS mới được các trình duyệt xem trọng, vừa mở ra đã thấy chiếc khóa và chữ Secure màu xanh đầy cá tính! Có giả thiết cho rằng Google đánh thứ hạng kết quả từ những trang HTTPS cao hơn "tụi HTTP".

Secure signal

Nếu bạn chưa đủ quyết tâm thì vẫn còn 1 lý do quan trọng khác, đó là nếu bạn muốn làm Progressive Web Apps, bạn sẽ phải dùng đến Service Worker, mà bé chảnh này thì dứt khoát không chơi với HTTP, phải HTTPS mới chịu! Tất cả các loại đồ chơi hiện đại based trên Service Worker, như Workbox, UpUp... đều đòi hỏi HTTPS.

Vậy thì làm thôi!

Yêu cầu kỹ thuật

  • Ubuntu server 16.04 trở lên
  • nginx v1.9.x hoặc mới hơn

Các bước thực hiện

1. Cài đặt certbot

sudo add-apt-repository ppa:certbot/certbot
sudo apt update
sudo apt install certbot

Trong quá trình cài đặt, chương trình có thể sẽ yêu cầu lựa chọn các thông số, bạn cần theo dõi để đưa ra option phù hợp:

Choose timezone

Sau khi hoàn tất, trên máy sẽ có thêm 1 lệnh letsencrypt. Bạn thử kiểm tra lại bằng cách gõ letsencrypt --version. Đây là phần client của dịch vụ Let's Enscrypt.

2. Point domain tới 1 web tạm

Tạo SSL certificate cho getsolution.pro thực chất là sử dụng phần client của Let's Enscrypt - lệnh letsencrypt - để tương tác với phần server của nó. Hầu hết tiến trình diễn ra tự động. Chúng ta chỉ cần hiểu sơ sơ rằng, máy chủ Let's Enscrypt sẽ gửi request đến http://getsolution.pro để làm vài chuyện gì đó riêng nó biết!

Cho nên tạm thời chúng ta tạo 1 web tĩnh, trỏ getsolution.pro vào đó.

mkdir /var/www/html
touch /var/www/html/index.html
mkdir /var/www/html/.well-known

Bạn có thể thêm nội dung cho file index.html.

Thư mục .well-known là nơi Let's Enscrypt sẽ thử access. Bây giờ chúng ta cấu hình lại nginx để từ bên ngoài có thể truy cập đến http://getsolution.pro/index.htmlhttp://getsolution.pro/.well-known. Mở lại file cấu hình nginx phía trên, sửa lại thành:

server{

  listen 80;

  server_name getsolution.pro www.getsolution.pro;
  root /var/www/html;

  index index.htm index.html;

  charset utf-8;

  location / {
    try_files $uri $uri/ =404;
  }
  location ~ /.well-known {
     allow all;
  }
}

Load lại thiết lập nginx:

sudo service nginx reload

Nếu mọi thứ chính xác, reload lại trang http://getsolution.pro, chúng ta sẽ nhận được nội dung index.html:

Temp website with HTML only

Chú ý ở nơi quản lý domain bạn cần phải thêm CNAME để cấu hình www.getsolution.pro như alias của getsolution.pro, đâu đó như hình dưới:

CNAME config

Nếu không, ở bước sau letsencrypt sẽ báo lỗi:

Error with www

3. Tạo SSL Certificate files

Với lệnh như dưới:

sudo letsencrypt certonly -a webroot \
  -w /var/www/html/ \
  -d getsolution.pro -d www.getsolution.pro

Nếu thành công, letsencrypt sẽ hiển thị kết quả và chúc mừng:

Successfully generated

Kể từ tháng 1 năm 2018, Let's Enscrypt đã chính thức hỗ trợ wildcard. Điều này có nghĩa là bạn chỉ cần generate SSH key 1 lần và dùng cho mọi subdomain có dạng *.getsolution.pro.

Để làm điều này, bạn cần:

  • cấu hình *.getsolution.pro như alias của getsolution.pro
  • phiên bản cerbot từ 0.22 trở về sau. Kiểm tra phiên bản cerbot với lệnh cerbot --version

Câu lệnh tạo SSH key cho cả subdomain sẽ hơi khác một chút:

sudo certbot certonly  --server https://acme-v02.api.letsencrypt.org/directory \
  --manual --preferred-challenges dns \
   -d getsolution.pro -d *.getsolution.pro

Với các câu hỏi, đọc kỹ trước khi Enter. Thường yêu cầu trả lời "Yes" mới cho đi tiếp.

Let's Enscrypt sẽ yêu tạo ra các TXT field trên domain. Làm theo hướng dẫn là được:

Please deploy a DNS TXT record under the name
_acme-challenge.getsolution.pro with the following value:

Rs1-6mHlkFqN_GyazftvFBpZD4Ti8rZpUMbF-9Ap6yY

Before continuing, verify the record is deployed.

Bây giờ letsencrypt đã generate ra các key cho bạn, lưu trong /etc/letsencrypt/.

Kiểm tra với lệnh ls:

sudo ls -l  /etc/letsencrypt/live/getsolution.pro

Kết quả hiển thị:

Listing the keys

Chúng ta sẽ tạo một snippet của nginx tên là ssl-getsolution.pro.conf và đưa các khóa này vào để dễ quản lý:

sudo nano /etc/nginx/snippets/ssl-getsolution.pro.conf

Copy & paste:

ssl_certificate /etc/letsencrypt/live/getsolution.pro/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/getsolution.pro/privkey.pem;

Save file lại.

4. Tham số Diffie-Hellman

Diffie-Hellman parameters định nghĩa cách thức OpenSSL xử lý tác vụ trao đổi khóa Diffie–Hellman giữa máy khách và máy chủ. Tham số này đóng vai trò quan trọng trong việc đánh giá chất lượng SSL.

Để generate ra bộ tham số Diffie-Hellman mới cho server, chúng ta chạy lệnh:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Lệnh này chạy mất vài phút:

Generating Diffie-Hellman parameters

Chúng ta sẽ đưa khóa trong file /etc/ssl/certs/dhparam.pem này vào một snippet khác của nginx:

sudo nano /etc/nginx/snippets/ssl-params.conf

Dán vào nội dung sau:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

Save lại.

5. Cấu hình nginx lần nữa

Mọi thứ đã gần như hoàn tất, chúng ta đã có SSL certificate, bộ khóa Diffie-Hellman mới. Cả 2 đều đã chuẩn bị sẵn dưới dạng 2 snippets cho nginx.

Trở lại file cấu hình nginx của domain getsolution.pro. Vừa nãy chúng ta đã sửa nó để điều hướng về trang HTML tĩnh. Bây giờ mới là cấu hình về cổng Node.js process, kèm theo HTTPS.

sudo nano /etc/nginx/sites-enabled/getsolution

Nhập vào nội dung sau:

server {

  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  server_name getsolution.pro;

  charset utf-8;

  include snippets/ssl-getsolution.pro.conf;
  include snippets/ssl-params.conf;

  location / {
    proxy_pass http://127.0.0.1:5678;
    proxy_read_timeout 300;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_cache_bypass $http_upgrade;
  }
}

Chỉ có 2 điểm khác biệt với file cấu hình đầu tiên. Đó là chúng ta thiết lập lắng nghe ở cổng 443 và chèn 2 snippets ở trên để nginx đọc được.

Reload lại cấu hình nginx:

sudo service nginx reload

Xong, bây giờ chúng ta đã có thể truy cập bằng giao thức HTTPS:

HTTPS is already now

6. Thêm tự điều hướng

Lúc này trang web hỗ trợ cả 2 giao thức HTTP và HTTPS. Lại thêm 2 biến thể có www. nữa, thành ra tổng cộng 4 đường dẫn:

Theo kinh nghiệm của tôi, chúng ta nên chọn https://getsolution.pro làm đường dẫn chính, mấy cái còn lại thì tự động redirect về đó.

Để làm điều này, chỉ việc mở file cấu hình domain ra, thêm vào một đoạn ở đầu file, trở thành:

server {
  listen 80;
  listen [::]:80;
  server_name getsolution.pro www.getsolution.pro;
  return 301 https://$server_name$request_uri;
}

server {
  listen 443;
  listen [::]:443;

  include snippets/ssl-getsolution.pro.conf;
  include snippets/ssl-params.conf;

  server_name www.getsolution.pro;
  return 301 https://getsolution.pro$request_uri;
}

server {

  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  server_name getsolution.pro;

  charset utf-8;

  include snippets/ssl-getsolution.pro.conf;
  include snippets/ssl-params.conf;

  location / {
    proxy_pass http://127.0.0.1:5678;
    proxy_read_timeout 300;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_cache_bypass $http_upgrade;
  }
}

Reload nginx một lần nữa để nhận kết quả mong muốn.

7. Kiểm tra chất lượng

Để đánh giá chất lượng SSL/TLS của website, các bạn có thể dùng công cụ phân tích của SSLLabs.

Đây là kết quả cho getsolution.pro:

Estimate SSL quality

Sở dĩ được xếp hạng A phần lớn nhờ bước tạo tham số Diffie-Hellman. Các website không cập nhật giá trị này thường chỉ dừng lại ở hạng B.

Hạn chế của Let's Enscrypt

  • Chưa hỗ trợ wildcard, sub domain (Update: đã hỗ trợ từ tháng 1 năm 2018)
  • Chưa hỗ trợ Extended Validation, nên không nhúng tên thương hiệu vào được. Chỉ có chữ "Secure".
  • 3 tháng hết hạn, phải nhớ chạy lệnh renew hoặc cài đặt cronjob tự động.

That's it.

Chúc các bạn chơi vui vẻ. Có gì thiếu sót vui lòng bổ sung thêm bên dưới :)

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Dong Nguyen

7 bài viết.
141 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
63 15
Phần 1: Con đường sáng (Link) (Link) Lúc bấy giờ, Tin giới Tây phương xuất hiện 2 lão quái Nguyên Anh hậu kỳ đỉnh phong, chỉ thiếu nửa bước cả...
Dong Nguyen viết 2 tháng trước
63 15
White
36 17
(Link) (Link) Phần 3: Buông bỏ Functional Programming là một con đường khác, một phương pháp tư duy khác trong coding. Ở tầm nhìn trừu tượng ...
Dong Nguyen viết 2 tháng trước
36 17
White
28 4
(Link) Phần 2: Nhập đạo (Link) Như vậy, Functional Programming là nghệ thuật lập trình trong đó ta: sử dụng functions để điều khiển workflow ...
Dong Nguyen viết 2 tháng trước
28 4
Bài viết liên quan
White
29 13
Vẫn theo khung sườn đã định trước từ phần 1, trong phần này tôi sẽ giới thiệu cách cấu hình nginx để thực hiện vai trò của một load balancer. Trư...
manhdung viết 3 năm trước
29 13
White
6 3
Gần đây mình thấy có một module khá thú vị của nginx trên github nên đã thử biên dịch nginx với module này và test thử. Nhân tiện nên note lại để m...
Quăng viết 2 năm trước
6 3
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
7 bài viết.
141 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!