SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-07

Cài Certbot cho Apache trên Ubuntu 24.04

Cài chứng chỉ Let's Encrypt cho Apache bằng apt trên Ubuntu 24.04 với Certbot 2.9.0, tránh snap và xử lý lỗi ServerName, DNS hoặc firewall cổng 80.

Bạn sẽ xây dựng gì

Một website Apache trên Ubuntu 24.04, phản hồi qua HTTPS bằng chứng chỉ Let's Encrypt miễn phí được trình duyệt tin cậy. Certbot cấp chứng chỉ này và một systemd timer tự động gia hạn mà bạn không cần quan tâm thêm. Lệnh thực hiện việc này chỉ có một dòng. Mọi lỗi đều xảy ra trước dòng lệnh đó: vhost không có ServerName, cổng 80 bị firewall của nhà cung cấp chặn, hoặc DNS vẫn trỏ đến server cũ. Vì vậy, phần lớn nội dung của hướng dẫn này tập trung vào các điều kiện tiên quyết và nêu chính xác chuỗi lỗi mà từng sai sót in ra.

Có 2 lưu ý về phạm vi. Nếu web server của bạn là nginx, quy trình có cấu trúc tương tự nhưng plugin và các file cấu hình khác nhau; hãy dùng phiên bản hướng dẫn này cho nginx. Nếu dịch vụ cần bảo vệ chỉ dùng nội bộ, chẳng hạn một admin panel trên địa chỉ private hoặc một staging box không có người khác truy cập, bạn không cần certificate authority; self-signed certificate cần ít cấu hình hơn và hoạt động offline.

Điều kiện tiên quyết và ba nguyên nhân khiến quy trình lỗi trước cả khi Certbot chạy

  • Apache đã phục vụ website của bạn qua HTTP không mã hóa. Plugin Apache của Certbot chỉnh sửa một site có sẵn; nó không tạo site mới. Nếu bạn bắt đầu với một VPS mới, trước hết hãy dựng stack LAMP trên Ubuntu 24.04 rồi quay lại; hướng dẫn này là chương TLS còn thiếu của quy trình đó.
  • Một domain public có bản ghi A trỏ đến địa chỉ VPS của bạn. Challenge HTTP-01 của Let's Encrypt yêu cầu các máy chủ xác thực kết nối đến máy của bạn từ Internet: không dùng homelab phía sau NAT nếu chưa forward port, không dùng tên .local, và không dùng IP trần. dig +short example.com phải trả về địa chỉ VPS của bạn. Nếu bạn vừa thay đổi DNS trong một giờ qua, hãy chờ TTL của bản ghi cũ hết hạn rồi mới cấp chứng chỉ.
  • Nếu có bản ghi AAAA, bản ghi đó phải chính xác. Let's Encrypt ưu tiên IPv6 khi có bản ghi AAAA, vì vậy AAAA cũ hoặc sai sẽ khiến xác thực thất bại dù curl từ laptop của bạn, có thể đang dùng IPv4, vẫn hoạt động bình thường. Hãy khai báo AAAA chính xác hoặc không khai báo bản ghi này.

Cả port 80 443 đều phải được mở trong ufw firewall mạng của nhà cung cấp. Hầu hết panel hosting có thêm một firewall riêng mà hệ điều hành không nhìn thấy. HTTP-01 chỉ xác thực qua port 80; bạn không thể chỉ chạy qua port 443.

sudo ufw allow "Apache Full"
sudo ufw status

Khi các điều kiện trên đã sẵn sàng, toàn bộ công việc chỉ mất mười lăm phút, trong đó mười phút là để đọc.

Certbot từ Snap hay apt? Trên 24.04, apt cuối cùng đã dùng ổn

Certbot chuyển sang phân phối bằng snap từ nhiều năm trước vì một lý do chính đáng: các gói của distro bị đóng băng. Ubuntu 20.04 cung cấp Certbot 0.40 rồi không cập nhật nữa, còn dự án đã quá mệt mỏi với việc xử lý các lỗi tồn tại từ năm năm trước. Trên 24.04, lý do đó không còn nữa. Archive cung cấp Certbot 2.9.0, một bản release thế hệ hiện tại, và unattended-upgrades vẫn cập nhật bản vá cho nó. Khuyến nghị của tôi cho hệ điều hành này: dùng apt. Bạn không cần daemon snapd, plugin Apache được cài trong cùng một transaction, và timer gia hạn tích hợp với systemd theo cách thông thường của Debian.

sudo apt update
sudo apt install -y certbot python3-certbot-apache
certbot --version

Kết quả đúng: certbot 2.9.0. Gói python3-certbot-apache là plugin dùng để đọc và chỉnh sửa cấu hình Apache. Nếu thiếu plugin này, certbot --apache sẽ fail với The requested apache plugin does not appear to be installed.

Snap vẫn là lựa chọn phù hợp trong 2 trường hợp: bạn muốn dùng bản Certbot mới nhất ngay ngày bản đó được release, hoặc bạn cần một plugin DNS chỉ được phân phối dưới dạng snap (một số plugin của các nhà cung cấp certbot-dns-* được phân phối như vậy). Nếu chọn cách đó:

sudo apt remove -y certbot python3-certbot-apache
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Dù chọn cách nào, không bao giờ chạy cả hai. Hai bản cài đặt sẽ khiến 2 scheduler gia hạn tranh chấp /etc/letsencrypt, và certbot mà shell tìm thấy trong PATH có thể không phải là bản đang quản lý các chứng chỉ của bạn. Dòng apt remove ở trên không phải phần trang trí tùy chọn.

Vhost mà Certbot chỉnh sửa phải tồn tại từ trước, ServerName quyết định tất cả

certbot --apache hoạt động bằng cách tìm virtual host trên cổng 80 có ServerName hoặc ServerAlias khớp với từng domain -d bạn truyền vào. Sau đó, nó xác minh quyền kiểm soát domain thông qua virtual host này rồi tạo một bản sao SSL của vhost đó. Không có ServerName khớp thì không thể khớp. Ubuntu cũng cài sẵn 000-default.conf với ServerName bị comment. Một dòng bị comment này là nguyên nhân phổ biến nhất khiến lệnh lớn trong hướng dẫn này thất bại.

Vì vậy, trước khi chạy Certbot, hãy tạo một vhost dùng đúng tên của site. Tạo /etc/apache2/sites-available/example.com.conf:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>

Enable vhost này rồi xác nhận Apache phân tích được cấu hình và định tuyến hostname đến đúng vhost:

sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo apache2ctl -S

configtest phải in ra Syntax OK. Nếu lệnh cũng in ra AH00558: apache2: Could not reliably determine the server's fully qualified domain name thì đó là cảnh báo về ServerName toàn cục, không phải vhost của bạn. Cảnh báo này không gây ảnh hưởng trong trường hợp này và có thể tắt bằng echo "ServerName $(hostname -f)" | sudo tee /etc/apache2/conf-available/servername.conf && sudo a2enconf servername && sudo systemctl reload apache2.

Kết quả của -S mới là phần cần kiểm tra. Bạn cần thấy một dòng như port 80 namevhost example.com (/etc/apache2/sites-enabled/example.com.conf:1) với alias www.example.com bên dưới. Apache báo symlink sites-enabled mà nó thực sự đã đọc, không phải file bạn chỉnh sửa trong sites-available. Nếu example.com không được liệt kê trên cổng 80 thì Certbot cũng sẽ không tìm thấy vhost đó.

Cấp chứng chỉ: certbot --apache

sudo certbot --apache -d example.com -d www.example.com

Lần chạy đầu tiên sẽ hỏi 3 thông tin: địa chỉ email (dùng cho tài khoản ACME và các thông báo khẩn từ CA; Let's Encrypt không còn gửi cảnh báo sắp hết hạn, nên bạn phải tự monitor việc renewal), xác nhận đồng ý với điều khoản của Let's Encrypt, và có muốn chia sẻ email với EFF hay không. Certbot không còn hỏi về redirect: từ Certbot 2.0, Apache installer mặc định redirect HTTP sang HTTPS, đúng với nhu cầu ở đây. Truyền --no-redirect nếu bạn thực sự cần tiếp tục cung cấp nội dung qua HTTP thuần.

Kết quả thành công sẽ như sau. Bạn nên đọc kỹ thay vì chỉ lướt qua:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2026-10-14.

Deploying certificate
Successfully deployed certificate for example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Successfully deployed certificate for www.example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Congratulations! You have successfully enabled HTTPS on https://example.com and https://www.example.com

Đằng sau thông báo đó, Certbot đã thực hiện 4 việc: bật module ssl của Apache nếu module này chưa được bật, ghi example.com-le-ssl.conf — một bản sao của vhost trên *:443SSLEngine on và các đường dẫn đến chứng chỉ — bật vhost này, rồi thêm block RewriteRule vào vhost cổng 80 ban đầu để redirect toàn bộ request sang HTTPS bằng mã 301. File vhost ban đầu được chỉnh sửa chứ không bị thay thế. Bản sao SSL nằm ngay bên cạnh, nên bạn có thể đọc từng dòng mà Certbot đã thêm.

Vị trí thực sự của certificate và lý do bạn không bao giờ copy nó

Mọi thứ đều nằm trong /etc/letsencrypt/live/example.com/: fullchain.pem (certificate cùng intermediate chain, là tệp các server nên trỏ đến), privkey.pem (private key, chỉ root được phép đọc), cùng với cert.pemchain.pem dành cho phần mềm cần các thành phần này ở dạng tách riêng. Đây là các symlink trỏ vào /etc/letsencrypt/archive/. Cơ chế liên kết này phục vụ việc gia hạn: khi gia hạn, hệ thống ghi các tệp mới vào archive/ rồi cập nhật symlink. Hãy trỏ mọi phần mềm khác vào các đường dẫn live/ để chúng tự nhận certificate mới sau mỗi lần gia hạn; nếu copy các tệp sang nơi khác, bạn sẽ tự tạo ra một sự cố ngừng dịch vụ sau 90 ngày.

Tệp còn lại cần biết là /etc/letsencrypt/renewal/example.com.conf. Tệp này ghi lại certificate được cấp như thế nào, gồm authenticator = apache, installer = apache và các domain, để quá trình gia hạn có thể lặp lại tự động mà không cần thao tác thủ công, bao gồm cả việc reload Apache sau đó.

Gia hạn đã được lập lịch, hãy xác minh thay vì tự tạo lại

Chứng chỉ Let's Encrypt có thời hạn 90 ngày theo thiết kế, và gói apt đã cài sẵn cơ chế cần thiết: một systemd timer chạy Certbot 2 lần mỗi ngày vào các thời điểm ngẫu nhiên, gia hạn mọi chứng chỉ còn 30 ngày hoặc ít hơn trước khi hết hạn. Không cần thêm cron job; scheduler thứ hai không mang lại lợi ích gì ngoài việc tạo thêm log và tăng nguy cơ chạm rate limit.

systemctl list-timers certbot.timer
sudo certbot renew --dry-run

Lệnh đầu tiên hiển thị timer đang hoạt động, với thời điểm NEXT nằm trong 24 giờ tới. Lịch chạy là 2 lần mỗi ngày với độ trễ ngẫu nhiên, nên thời điểm chính xác được cố ý giữ không cố định (trên bản cài snap, timer là snap.certbot.renew.timer). Dry run thực hiện đầy đủ quy trình diễn tập gia hạn với môi trường staging của Let's Encrypt: challenge thật, không phát hành chứng chỉ, không tốn rate limit. Kết quả đúng sẽ kết thúc bằng:

Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

Nếu dry run thất bại, lần gia hạn thật sau khoảng 60 ngày cũng sẽ thất bại theo cách tương tự. Hãy sửa ngay khi chứng chỉ hiện tại vẫn còn gần như toàn bộ thời hạn sử dụng. Nguyên nhân thường gặp là một firewall rule được thêm sau khi cấp chứng chỉ, rồi lại đóng cổng 80.

Xác minh bằng curl và kiểm tra biểu tượng ổ khóa hiển thị gì

curl -sI http://example.com | head -n 3
curl -I https://example.com
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -issuer -dates

Lệnh đầu tiên phải trả về HTTP/1.1 301 Moved Permanently kèm header Location: https://example.com/. Đây là redirect do Certbot cài đặt. Lệnh thứ hai phải trả về HTTP/1.1 200 OK và curl không báo lỗi TLS. Lệnh thứ ba in ra issuer, một dòng O = Let's Encrypt có CN ngắn như R12 hoặc E7, cùng notAfter còn khoảng 90 ngày. Trong trình duyệt, bạn sẽ thấy biểu tượng ổ khóa. Khi nhấp vào đó, issuer hiển thị phải giống như trên. Nếu curl hoạt động nhưng trình duyệt cảnh báo, gần như chắc chắn bạn đang xem trang trong cache hoặc dùng sai hostname, không phải gặp lỗi chứng chỉ.

Nhiều site: một chứng chỉ SAN hay mỗi site một chứng chỉ

Cả hai cách đều hoạt động và được gia hạn theo cùng một cách. Với các site không liên quan trên cùng một máy, hãy chạy lệnh cấp chứng chỉ một lần cho mỗi site. Mỗi site sẽ có thư mục riêng bên dưới live/ và cấu hình gia hạn riêng. Sự cố ở một domain sẽ không bao giờ chặn việc gia hạn các domain khác. Đây là lựa chọn mặc định của tôi.

Với một site có nhiều tên, hãy đặt các tên đó vào một chứng chỉ SAN. Một chứng chỉ có thể chứa tối đa 100 tên. Bạn đã thực hiện việc này ở trên với example.comwww.example.com. Sau này, để thêm một tên vào chứng chỉ hiện có, hãy cấp lại chứng chỉ bằng cách chỉ định tên chứng chỉ và toàn bộ danh sách mới:

sudo certbot --apache --cert-name example.com -d example.com -d www.example.com -d blog.example.com

Certbot nhận thấy tập domain đã thay đổi, yêu cầu bạn xác nhận việc mở rộng rồi thay thế chứng chỉ tại chỗ, vẫn dùng đường dẫn live/. Vì vậy, không cần thay đổi gì khác. Lưu ý rằng danh sách mới thay thế danh sách cũ, không phải bổ sung vào danh sách cũ: nếu bỏ www khỏi lệnh đó, chứng chỉ mới sẽ âm thầm loại bỏ tên này.

Wildcard cần DNS-01, nhưng thường bạn không cần wildcard

HTTP-01 không thể cấp *.example.com. Đặt một file trên web server chỉ chứng minh bạn kiểm soát một hostname, không phải toàn bộ namespace. Wildcard yêu cầu challenge DNS-01: Certbot đặt một bản ghi TXT tại _acme-challenge.example.com. Trên thực tế, bạn cần một plugin certbot-dns-* có API credentials của nhà cung cấp DNS, hoặc phải tự sửa bản ghi TXT mỗi lần gia hạn bằng --manual (rất bất tiện, không nên dựa vào cách này). Hướng dẫn đầy đủ, từ cơ chế bản ghi TXT đến plugin tự động gia hạn mà không cần can thiệp, có tại chứng chỉ wildcard với Certbot qua DNS-01. Khuyến nghị thực tế: nếu bạn có 4 subdomain đã biết, chứng chỉ SAN liệt kê cả 4 subdomain sẽ đơn giản hơn wildcard và không cần để DNS API key trên server.

Các lỗi thường gặp và chuỗi thông báo bạn sẽ thấy

Certbot từ chối khởi động vì cấu hình Apache bị lỗi.

The apache plugin is not working; there may be problems with your existing configuration.
The error was: MisconfigurationError('Error while running apache2ctl configtest.\n\nAction \'configtest\' failed.\nThe Apache error log may have more information.\n\nAH00526: Syntax error on line 12 of /etc/apache2/sites-enabled/example.com.conf')

Plugin chạy configtest trước khi thực hiện bất kỳ thao tác nào. Nếu chính Apache đang lỗi, plugin sẽ dừng. Các \n là chuỗi literal vì Certbot in ra kết quả repr của exception. Tự chạy sudo apache2ctl configtest: lệnh này cho biết file và dòng bị lỗi. Nguyên nhân thường là lỗi gõ khi chỉnh sửa thủ công, một SSLCertificateFile trỏ đến path không còn tồn tại hoặc một module được tham chiếu nhưng chưa enable. Sửa cho đến khi lệnh in ra Syntax OK, rồi chạy lại Certbot.

Không có vhost nào khớp với domain.

Unable to find a virtual host listening on port 80 which is currently the only challenge port.

Đây là lỗi thiếu-ServerName được đề cập trước đó, xảy ra khi issue certificate. Certbot đã tìm trong mọi vhost port-80 đang enable một ServerName/ServerAlias khớp với -d nhưng không tìm thấy. sudo apache2ctl -S cho biết Apache thực sự đang định tuyến request như thế nào. Thêm dòng ServerName vào đúng vhost, reload rồi thử lại. Một trường hợp gần giống là quá trình validation đến nhầm vhost. Challenge response trả về Invalid response ... 404 vì một site khác đã nhận request. Cách chẩn đoán giống nhau, dùng cùng một tool: apache2ctl -S.

Validation bị timeout.

Certbot failed to authenticate some domains (authenticator: apache).
...
Detail: ...: Timeout during connect (likely firewall problem)

Let's Encrypt không thể mở kết nối TCP đến port 80 tại địa chỉ mà DNS của bạn đang quảng bá. Theo thứ tự khả năng thường gặp: firewall mạng của provider, tách biệt với ufw và được cấu hình trong hosting panel; ruleset của ufw chỉ cho phép 443 hoặc chỉ cho phép SSH; DNS vẫn trỏ đến server cũ; hoặc gặp lỗi stale-AAAA, tức là server của Let's Encrypt thử IPv6 nhưng server của bạn chỉ trả lời trên IPv4. Test từ bên ngoài VPS: curl -I http://example.com trên laptop để tái hiện đúng những gì validator của họ nhìn thấy.

Bạn đã retry đến mức chạm rate limit.

Error creating new order :: too many failed authorizations recently: see https://letsencrypt.org/docs/rate-limits/

Let's Encrypt cho phép 5 lần validation thất bại trên mỗi hostname, mỗi account, mỗi giờ. Sau đợt điều chỉnh rate limit năm 2025, đây là một bucket tự bổ sung. Hệ thống chỉ phục hồi khoảng một lần retry sau mỗi 12 phút. Retry liên tục khi firewall đang lỗi sẽ nhanh chóng dùng hết giới hạn. Chờ sẽ giải quyết tạm thời, nhưng cách sửa đúng là thay đổi quy trình: sau mỗi lần thất bại, debug bằng staging environment cho đến khi thành công.

sudo certbot certonly --apache --dry-run -d example.com -d www.example.com

Lưu ý certonly: --dry-run chỉ được chấp nhận bởi các subcommand certonlyrenew. Dạng certbot --apache --dry-run không có tham số sẽ từ chối chạy hoàn toàn và báo --dry-run currently only works with the 'certonly' or 'renew' subcommands. Dry run thực hiện validation với staging. Môi trường này có giới hạn rộng hơn và không issue certificate thật, nên bạn có thể để nó fail cả buổi chiều. Chỉ chạy lại command thật sau khi staging đã pass. Các giới hạn khác, gồm 50 certificate trên mỗi registered domain mỗi tuần và 5 certificate trùng cùng một name set mỗi tuần, chỉ xảy ra nếu một script đang lặp lại việc reissue.

Sau khi HTTPS hoạt động, hãy nhớ certificate chỉ bảo vệ transport, không bảo vệ server. Port 22 vẫn đang nhận các lần đoán password cả ngày. Kết hợp thêm Fail2ban trên Ubuntu 24.04 là bước tiếp theo hợp lý trong 30 phút tới.

FAQ

Tôi nên cài Certbot bằng snap hay apt cho Apache trên Ubuntu 24.04?

Dùng apt. Ubuntu 24.04 phát hành Certbot 2.9.0, phiên bản này đủ mới cho mọi nội dung trong hướng dẫn này, nhận bản vá bảo mật qua unattended-upgrades và không cần snapd. Chỉ chọn snap nếu bạn cần ngay bản phát hành mới nhất hoặc một DNS plugin chỉ được phân phối dưới dạng snap. Nếu chuyển sang snap, hãy apt remove certbot python3-certbot-apache trước để hai scheduler gia hạn không bao giờ cùng tồn tại.

Vì sao Certbot báo "Unable to find a virtual host listening on port 80"?

Vì không có vhost cổng 80 nào đang được bật với ServerName hoặc ServerAlias khớp với domain bạn truyền qua -d. Vhost mặc định của Ubuntu được phát hành với ServerName bị comment out. Chạy sudo apache2ctl -S, tìm hoặc tạo vhost phải sở hữu hostname đó, thêm ServerName example.com, reload Apache rồi chạy lại Certbot.

Làm cách nào sửa lỗi "Timeout during connect (likely firewall problem)"?

Let's Encrypt không thể truy cập cổng 80 tại địa chỉ mà DNS của bạn công bố. Kiểm tra firewall mạng ở cấp panel của nhà cung cấp và cả ufw. Xác nhận dig +short example.com trả về VPS này, đồng thời xóa hoặc sửa bản ghi AAAA cũ. Khi có bản ghi AAAA, quá trình xác thực sẽ ưu tiên IPv6. Xác nhận bản sửa từ bên ngoài server bằng curl -I http://example.com, rồi diễn tập bằng sudo certbot certonly --apache --dry-run -d example.com trước khi cấp chứng chỉ thật.

Certbot có tự động gia hạn chứng chỉ trên Ubuntu 24.04 không?

Có. Gói apt cài đặt certbot.timer, một systemd timer chạy 2 lần mỗi ngày và gia hạn mọi chứng chỉ còn không quá 30 ngày trước khi hết hạn, sau đó reload Apache. snap dùng snap.certbot.renew.timer cho cùng tác vụ. Kiểm tra bằng systemctl list-timers certbot.timer và diễn tập bằng sudo certbot renew --dry-run. Không thêm cron job riêng.

Làm cách nào lấy wildcard certificate bằng Certbot và Apache?

Wildcard certificate yêu cầu challenge DNS-01. Certbot phải đặt một bản ghi TXT tại _acme-challenge.example.com. Vì vậy, bạn cần một certbot-dns-* plugin có API credentials cho nhà cung cấp DNS. Phương án --manual yêu cầu chỉnh sửa thủ công các bản ghi TXT ở mỗi lần gia hạn. Nếu bạn chỉ có một vài subdomain đã biết, SAN certificate liệt kê rõ từng subdomain sẽ đơn giản hơn và giữ DNS API key ngoài server.