Lets’s Encrypt là một certificate authority (cơ quan cấp chứng chỉ) mở và miễn phí được phát triển bởi Internet Security Research Group (ISRG). Chứng chỉ được ban hành bởi Let’s Encrypt được hầu hết các trình duyệt web hiện đại ngày nay tin tưởng.
Trong bài viết này, mình sẽ hướng dẫn các bạn cách thiết lập bảo mật HTTPS cho website sử dụng Let’s Encrypt trên Nginx sử dụng công cụ certbot trên Ubuntu 18.04.
Yêu cầu
Trước khi bắt đầu, bạn cần phải đảm bảo chuẩn bị và đáp ứng những yêu cầu sau đây trước khi tiến hành thực hiện theo bài hướng dẫn này.
- DNS tên miền đã trỏ tới đúng IP public của server mà bạn sẽ thực hiện cài đặt. Trong bài viết này, mình sẽ sử dụng domain vu-review.com.
- Server đã cài đặt sẵn Nginx
Hướng dẫn cài đặt Certbot
Certbot là một công cụ đầy đủ các tính năng và dễ dàng sử dụng, cho phép chúng ta tự động hóa các tác vụ để lấy và làm mới chứng chỉ SSL của Let’s Encrypt và cấu hình web server sử dụng chứng chỉ. Gói certbot có sẵn trong repository của Ubuntu rồi, nên bạn chỉ cần dùng câu lệnh apt để cài đặt thôi.
Cập nhật danh sách các packages và cài đặt gói certbot như sau:
sudo apt update
sudo apt install certbot
Tạo nhóm DH (Diffie-Hellma)
Trao đổi khóa Diffie–Hellman (DH) là một cơ chế trao đổi khóa mã hóa (cryptographic keys) qua một kênh giao tiếp không an toàn. Mình sẽ tạo ra một tập tham số 2048 bit DH mới để tăng cường bảo mật.
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Nếu thích, bạn cũng có thể thay đổi kích cỡ lên tới 4096 bits, nhưng trong trường hợp này, quá trình khởi tạo key có thể lên tới 10 phút – tùy thuộc vào entropy hệ thống.
Nhận chứng chỉ SSL của Let’s Encrypt
Để nhận chứng chỉ SSL cho domain của mình, mình sẽ sử dụng plugin Webroot – nó sẽ tạo ra một file tạm để xác thực domain được truy vấn trong thư mục ${webroot-path}/.well-known/acme-challenge
Để đơn giản hơn, mình sẽ map tất cả các request HTTP có đường dẫn .well-known/acme-challenge
tới thư mục là /var/lib/letsencrypt
.
Các câu lệnh sau đây sẽ tạo ra thư mục cho phép nó có thể ghi tới server Nginx.
sudo mkdir -p /var/lib/letsencrypt/.well-known
sudo chgrp www-data /var/lib/letsencrypt
sudo chmod g+s /var/lib/letsencrypt
Để tránh trùng lặp mã, mình sẽ tạo ra 2 đoạn mã trong block của server Nginx.
Đầu tiên, mở vim lên tạo đoạn mã đầu tiên là letsencrypt.conf
:
sudo vi /etc/nginx/snippets/letsencrypt.conf
Sau đó dán đoạn mã này vào
location ^~ /.well-known/acme-challenge/ {
allow all;
root /var/lib/letsencrypt/;
default_type "text/plain";
try_files $uri =404;
}
Tạo đoạn mã thứ hai là ssl.conf
đây là đoạn mã chứa các đề xuất như OCSP Stapling, HTTP Strict Transport Security (HSTS) và security‑focused HTTP headers của FireFox.
sudo nano /etc/nginx/snippets/ssl.conf
Dán đoạn mã này vào
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 30s;
add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
Sau khi đã khởi tạo và lưu 2 đoạn mã trên, mở block domain có chứaletsencrypt.conf
vào như sau:
sudo vi /etc/nginx/sites-available/vu-review.com.conf
Sau đó dán đoạn mã này vào
server {
listen 80;
server_name vu-review.com www.vu-review.com;
include snippets/letsencrypt.conf;
}
Để kích hoạt file block server mới, mình cần phải tạo một symbolic link từ file này với thư mục sites-enabled
– đây là thư mục được Nginx đọc trong quá trình startup.
sudo ln -s /etc/nginx/sites-available/vu-review.com.conf /etc/nginx/sites-enabled/
Sau đó, khởi đọng lại nginx
sudo systemctl restart nginx
Bây giờ, bạn có thể chạy Certbot với plugin webhoot và nhận file chứng chỉ SSL bằng cách chạy lệnh sau:
sudo certbot certonly --agree-tos --email contact@vu-review.com --webroot -w /var/lib/letsencrypt/ -d vu-review.com -d www.vu-review.com
Nếu như nhận được chứng chỉ SSL thành công, certbot sẽ in ra message có dạng như sau:
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/vu-review.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/vu-review.com/privkey.pem
Your cert will expire on 2020-06-13. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Bây giờ mình đã có được file chứng chỉ rồi, mình có thể edit block server domain lại để sử dụng SSL thành dạng như sau:
sudo vi /etc/nginx/sites-available/vu-review.com.conf
# Redirect HTTP -> HTTPS
server {
listen 80;
server_name www.vu-review.com vu-review.com;
include snippets/letsencrypt.conf;
return 301 https://vu-review.com$request_uri;
}
# Redirect WWW -> NON WWW
server {
listen 443 ssl http2;
server_name www.vu-review.com;
ssl_certificate /etc/letsencrypt/live/vu-review.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vu-review.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/vu-review.com/chain.pem;
include snippets/ssl.conf;
return 301 https://vu-review.com$request_uri;
}
server {
listen 443 ssl http2;
server_name vu-review.com;
root /var/www/html/vu-review.com;
index index.php;
# SSL parameters
ssl_certificate /etc/letsencrypt/live/vu-review.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vu-review.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/vu-review.com/chain.pem;
include snippets/ssl.conf;
include snippets/letsencrypt.conf;
# log files
access_log /var/log/nginx/vu-review.com.access.log;
error_log /var/log/nginx/vu-review.com.error.log;
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires max;
log_not_found off;
}
}
Với cấu hình bên trên mình đã ép website phải sử dụng HTTPS và chuyển hướng từ www sang non-www.
Reload lại Nginx server để các thay đổi ảnh được thực hiện ngay lập tức.
sudo systemctl reload nginx
Làm mới tự động chứng chỉ SSL của Let’s Encrypt
Chứng chỉ SSL của Let’s Encrypt chỉ có hiệu lực vỏn vẹn trong vòng 90 ngày thôi. Để tự động làm mới chứng chỉ trước khi nó hết hạn, certbot tạo ra một cronjob chạy 2 lần mỗi ngày và sẽ tự động làm mới chứng chỉ bất kỳ chứng chỉ nào sau 30 ngày nữa sẽ hết hạn.
Vì mình sẽ sử dụng plugin webroot certbot khi mà chứng chỉ SSL đã được làm mới, mình cũng sẽ cần phải reload lại nginx. Lúc này, mình sẽ thêm --renew-hook "systemctl reload nginx"
vào file /etc/cron.d/certbot
sudo vi /etc/cron.d/certbot
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "systemctl reload nginx"
Để kiểm tra quá trình làm mới, bạn có thể sử dụng certbot với option --dry-run
sudo certbot renew --dry-run
Nếu không có lỗi nào cả, nghĩa là quá trình làm mới chứng chỉ thành công rồi đấy.
Kết luận
Trong bài viết này, mình đã sử dụng Let’s Encrypt để download chứng chỉ SSL cho domain vu-review.com của mình. Và tạo 2 đoạn code Nginx để tránh trùng lặp code và cấu hình Nginx khi sử dụng chứng chỉ. Và sau cùng, dùng cronjob để tự động làm mới chứng chỉ SSL trước khi nó hết hạn.