วิธีติดตั้ง Certbot สำหรับ nginx บน Ubuntu 24.04
สอนติดตั้ง Certbot บน Ubuntu 24.04 ทั้งแบบ apt และ snap พร้อมวิธีแก้ปัญหาการต่ออายุใบรับรอง Let's Encrypt และข้อควรระวังเรื่องการติดตั้งซ้ำซ้อน
การติดตั้ง Certbot: apt หรือ snap
บน Ubuntu 24.04 การใช้ sudo apt install certbot python3-certbot-nginx จะทำให้คุณได้ Certbot ที่ใช้งานได้จริง ซึ่งสามารถออกใบรับรอง Let's Encrypt ที่ได้รับการรับรองจากสาธารณะ เอกสารอย่างเป็นทางการของ Certbot แนะนำให้ใช้ snap ความแตกต่างมีเพียงเล็กน้อย โดย snap จะติดตามเวอร์ชันล่าสุดจากต้นทาง ส่วนแพ็กเกจจาก archive จะติดตามเวอร์ชันที่มาพร้อมกับ LTS และจะได้รับเพียงการแก้ไขด้านความปลอดภัยเท่านั้น
เลือกติดตั้งเพียงวิธีเดียว การมี Certbot สองชุดจะทำให้มี timer สำหรับการต่ออายุสองตัวที่ชี้ไปยัง /etc/letsencrypt tree เดียวกัน และตัวที่คุณลืมไปอาจทำให้เกิดปัญหาภายหลัง
วิธีติดตั้งผ่าน apt:
sudo apt update
sudo apt install certbot python3-certbot-nginxคำสั่งนี้จะติดตั้ง /usr/bin/certbot, nginx plugin, คู่ของ certbot.service + certbot.timer และรายการ /etc/cron.d/certbot ซึ่งไม่มีผลการทำงานภายใต้ systemd
วิธีติดตั้งผ่าน snap:
sudo apt remove certbot python3-certbot-nginx
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbotsnap จะมาพร้อมกับ timer ของตัวเองคือ snap.certbot.renew.timer โปรดลบแพ็กเกจ apt ออก ก่อน เริ่มการติดตั้ง snap
หลังจากนั้นการติดตั้งทั้งสองวิธีจะทำงานเหมือนกัน Certbot 2.x จะใช้ ECDSA (P-256) เป็นค่าเริ่มต้น ให้ใช้ flag --key-type rsa เฉพาะในกรณีที่ client ไม่รองรับ ECDSA เท่านั้น ข้อมูลสถานะทั้งหมดจะถูกเก็บไว้ภายใต้ /etc/letsencrypt โดยที่ archive/ เก็บไฟล์ key และ certificate ของจริง, live/ เก็บ symlinks ไปยังไฟล์ปัจจุบัน, renewal/ เก็บไฟล์คอนฟิกหนึ่งไฟล์ต่อหนึ่งใบรับรอง และ accounts/ เก็บ ACME account key ของคุณ
การทำงานของ HTTP-01 และเหตุผลที่ port 80 เป็นสิ่งจำเป็น
HTTP-01 challenge คือการเรียกกลับ (callback) เมื่อคุณขอใบรับรองสำหรับ example.com ทาง Let's Encrypt จะทำการตรวจสอบชื่อโดเมนผ่าน public DNS จากนั้นจะเปิดการเชื่อมต่อมายัง port 80 ตามที่อยู่ที่พบ และร้องขอ http://example.com/.well-known/acme-challenge/<token> เซิร์ฟเวอร์ของคุณต้องตอบกลับด้วยเนื้อหา token ที่ตรงกับสิ่งที่ Certbot เขียนลงใน disk ทุกประการ นี่คือกลไกทั้งหมด ซึ่งส่งผลให้เกิดข้อผิดพลาดในการออกใบรับรองส่วนใหญ่จาก 3 สาเหตุ ดังนี้
- Port 80 ต้องสามารถเข้าถึงได้จาก public internet ไม่ใช่เพียงแค่จากเครื่อง laptop ของคุณเท่านั้น กฎของ
ufw, cloud-provider security group หรือ firewall ของ VPS-console ที่เปิดเฉพาะ port 443 จะทำให้การออกใบรับรองล้มเหลว รวมถึงการต่ออายุในอนาคตด้วย - DNS ต้องชี้มาที่เครื่องนี้แล้ว เซิร์ฟเวอร์ตรวจสอบจะทำการ lookup ด้วยตนเองจากภายนอก ข้อมูลใน
/etc/hostsและ browser cache ของคุณไม่มีผลต่อการตรวจสอบนี้ - หากคุณประกาศ AAAA record ระบบจะพยายามใช้ IPv6 ก่อน Let's Encrypt จะพยายามใหม่ผ่าน IPv4 หากการเชื่อมต่อ IPv6 ล้มเหลวโดยสิ้นเชิง แต่หาก AAAA record ที่ล้าสมัยชี้ไปยัง host ที่ ยอมรับ การเชื่อมต่อแต่ส่งข้อมูลอื่นกลับมา จะทำให้การตรวจสอบล้มเหลวทันที
ระบบอนุญาตให้มีการทำ Redirect โดยการตรวจสอบจะติดตาม HTTP redirect ไปยัง HTTPS และไม่สนใจว่าใบรับรองที่ปลายทางจะหายไป, หมดอายุ หรือเป็น self-signed อย่างไรก็ตาม ระบบจะไม่เริ่มต้นการเชื่อมต่อจากช่องทางอื่นนอกเหนือจาก port 80 เนื่องจาก Certbot ไม่มีระบบ TLS-ALPN-01 ดังนั้นการใช้ "แค่ port 443" จึงไม่ใช่ทางออกของปัญหานี้
การเลือก authenticator: --nginx, --webroot, --standalone
--nginx เป็นค่าเริ่มต้นที่เหมาะสมที่สุด หาก nginx กำลังทำงานและให้บริการโดเมนอยู่แล้ว Certbot จะอ่านไฟล์ config ของคุณ จากนั้นจะแทรกตำแหน่งสำหรับ challenge ชั่วคราว และทำการ reload nginx เพื่อตรวจสอบความถูกต้อง จากนั้นจะเขียนคำสั่ง TLS ลงใน server block ของคุณ วิธีนี้ทำให้ระบบไม่หยุดทำงาน (No downtime)
sudo certbot --nginx -d example.com -d www.example.comสำหรับการใช้งานผ่าน script บนเครื่องใหม่:
sudo certbot --nginx \
-d example.com -d www.example.com \
--agree-tos -m ops@example.com --no-eff-email \
--redirect --non-interactive--webroot เหมาะสำหรับกรณีที่คุณไม่ต้องการให้ Certbot เข้าไปยุ่งกับ nginx config เช่น กรณีที่คุณสร้าง config จาก template, เก็บไว้ใน git หรือส่งผ่าน Ansible Certbot จะเขียนเพียงไฟล์ challenge ลงใน directory ที่คุณให้บริการอยู่แล้วเท่านั้น
sudo certbot certonly --webroot -w /var/www/example.com \
-d example.com -d www.example.com \
--deploy-hook "systemctl reload nginx"--standalone เหมาะสำหรับกรณีที่ไม่มีบริการใดใช้งาน port 80 อยู่ เช่น mail server, API ที่ใช้งานเฉพาะ port 443 หรือ script ที่ทำงานตอนเริ่มระบบครั้งแรกก่อนที่ nginx จะถูกติดตั้ง Certbot จะทำการ bind port 80 ด้วยตัวเองเป็นเวลาไม่กี่วินาที หาก nginx กำลัง ทำงานอยู่ การทำงานนี้จะล้มเหลว คุณต้องหยุดการทำงานของ nginx ก่อนเริ่มใช้งาน:
sudo certbot certonly --standalone -d mail.example.com \
--pre-hook "systemctl stop nginx" \
--post-hook "systemctl start nginx"คำสั่ง hook เหล่านี้จะถูกบันทึกไว้ในไฟล์ config สำหรับการต่ออายุใบรับรอง (renewal config) ดังนั้นระบบจะทำการ stop/start ให้โดยอัตโนมัติเมื่อมีการต่ออายุใบรับรอง
Server block ที่ใช้งานได้ทั้งก่อนและหลังจากการมี certificate
ปัญหาแบบ chicken-and-egg: nginx จะไม่สามารถ start ได้หาก ssl_certificate ชี้ไปยังไฟล์ที่ไม่มีอยู่จริง และ Certbot ก็ไม่สามารถตรวจสอบความถูกต้องได้หาก nginx ปิดอยู่ ให้เริ่มจากการเปิดใช้งานเว็บไซต์ผ่าน port 80 ก่อน
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
try_files $uri =404;
}
location / {
try_files $uri $uri/ =404;
}
}รัน sudo nginx -t && sudo systemctl reload nginx ตรวจสอบคำตอบจาก curl -I http://example.com/ โดยทดสอบจาก ภายนอก เครื่อง จากนั้นจึงดำเนินการออก certificate หลังจากนั้น:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}การใช้ prefix ^~ ใน ACME location มีความสำคัญ เนื่องจากช่วยป้องกันไม่ให้ return 301 block เข้ามาจัดการคำขอ challenge การคง location นี้ไว้บน port 80 จะช่วยให้การต่ออายุ certificate (renewal) ยังคงทำงานได้แม้เว็บไซต์ส่วนอื่นจะเปลี่ยนไปใช้ HTTPS-only แล้ว
รูปแบบไวยากรณ์ของ HTTP/2 ขึ้นอยู่กับ nginx version ที่คุณใช้งาน การใช้รูปแบบที่ปนกันจะทำให้เกิด error ขณะ startup โดย Ubuntu 24.04 มาพร้อมกับ nginx 1.24 ซึ่งต้องใช้รูปแบบ inline — listen 443 ssl http2; ส่วน Debian 13 มาพร้อมกับ nginx เวอร์ชันใหม่กว่า ซึ่งต้องใช้ directive http2 on; แยกต่างหาก ควรตรวจสอบ nginx -v ก่อน
ให้ nginx ชี้ไปที่ live/ ห้ามชี้ไปที่ archive/ เนื่องจาก symlinks ของ live/ จะถูกเปลี่ยนเส้นทางใหม่ทุกครั้งที่มีการ renewal การระบุ path แบบตายตัวไปยัง archive/ จะทำให้คุณติดอยู่กับ certificate ที่หมดอายุไปแล้ว
Wildcards หมายถึง DNS-01 และ DNS-01 หมายถึง plugin
ใบรับรองแบบ wildcard (*.example.com) ไม่สามารถตรวจสอบความถูกต้องผ่าน HTTP-01 ได้ เนื่องจากไม่มี hostname เดียวในการดึงไฟล์ DNS-01 จึงเป็นวิธีเดียว โดยคุณต้องพิสูจน์ความเป็นเจ้าของด้วยการสร้าง _acme-challenge.example.com TXT record คู่มือการทำ wildcard certificate ฉบับสมบูรณ์ จะอธิบายกลไกของ TXT record และปัญหาการต่ออายุในโหมด manual ส่วนเนื้อหาฉบับย่อสำหรับ Cloudflare จะอยู่ในลำดับถัดไป
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflareสำหรับระบบที่ใช้ apt จะใช้ sudo apt install python3-certbot-dns-cloudflare แทน ข้อมูลรับรอง (credentials) จะถูกเก็บไว้ในไฟล์ที่อนุญาตให้เฉพาะ root เท่านั้นที่เข้าถึงได้:
# /root/.secrets/cloudflare.ini
# then: sudo chmod 600 /root/.secrets/cloudflare.ini
dns_cloudflare_api_token = your_scoped_token_hereกำหนดขอบเขตของ token ให้มีสิทธิ์เฉพาะการแก้ไข DNS (DNS-edit) ใน zone นั้นเท่านั้น เนื่องจาก token นี้เปรียบเสมือนกุญแจสำหรับ DNS ของคุณ จึงต้องเก็บรักษาให้ปลอดภัย
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d '*.example.com'ต้องใส่เครื่องหมายอัญประกาศ (quote) ครอบ wildcard เพื่อไม่ให้ shell ทำการ globbing นอกจากนี้ DNS-01 ยังแก้ปัญหาที่ HTTP-01 ทำไม่ได้ คือการออกใบรับรองสำหรับ host ที่ไม่มีการเปิด port 80 ต่อสาธารณะ เช่น บริการภายใน, เครื่องที่เข้าถึงได้ผ่าน self-hosted WireGuard VPN on a VPS หรือแผงควบคุมผู้ดูแลระบบบน interface ส่วนตัว
การต่ออายุ: ระยะเวลา 90 วัน, ตัวจับเวลา และ deploy hook
ใบรับรองของ Let's Encrypt มีอายุการใช้งาน 90 วัน Certbot จะทำการต่ออายุเมื่อเหลือเวลาไม่ถึง 30 วัน ซึ่งทำให้คุณมีเวลา 30 วันในการแก้ไขหากการต่ออายุล้มเหลว แทนที่จะเกิดปัญหาเว็บไซต์ใช้งานไม่ได้ Let's Encrypt ไม่ส่งอีเมลแจ้งเตือนการหมดอายุอีกต่อไป ดังนั้นคุณต้องเป็นผู้ตรวจสอบด้วยตนเอง
ตรวจสอบตัวจับเวลาที่มาพร้อมกับการติดตั้งของคุณ:
systemctl list-timers 'certbot*' 'snap.certbot*'
sudo certbot certificatescertbot renew จะตรวจสอบทุกการตั้งค่าใน /etc/letsencrypt/renewal/ โดยจะข้ามรายการที่ไม่อยู่ในช่วง 30 วัน และจะต่ออายุรายการที่เหลือโดยใช้ flag เดียวกันกับการรันครั้งแรก นั่นคือเหตุผลที่การรันครั้งแรกมีความสำคัญ เพราะเป็นข้อมูลที่ถูกบันทึกไว้
การต่ออายุไฟล์บน disk เพียงอย่างเดียวไม่สามารถเปลี่ยนแปลงสถานะการทำงานได้ nginx จะยังคงใช้ใบรับรองเดิมจากหน่วยความจำจนกว่าจะมีการสั่ง reload คุณควรตั้งค่า deploy hook ไว้ดังนี้:
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/sh
set -e
nginx -t && systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shไฟล์ที่สามารถ execute ได้ใน renewal-hooks/deploy/ จะทำงานหลังจากต่ออายุสำเร็จ การใช้ flag --deploy-hook จะทำงานในลักษณะเดียวกันสำหรับใบรับรองเดียว โดยจะเก็บ renew_hook = ... ไว้ใน renewal config ของใบรับรองนั้น certbot --nginx จะทำการ reload ให้โดยอัตโนมัติ แต่การตั้งค่าแบบ --webroot และ --standalone จะไม่ทำเช่นนั้น การไม่ได้ตั้งค่า hook คือสาเหตุที่ทำให้เว็บไซต์แสดงใบรับรองที่หมดอายุ ในขณะที่ certbot certificates รายงานว่าใบรับรองใหม่พร้อมใช้งานแล้ว แอปพลิเคชันอื่นที่ต้องอ่านใบรับรองเมื่อเริ่มต้นระบบก็จำเป็นต้องใช้ hook แบบเดียวกัน เช่น แอปพลิเคชันใน container อย่าง Nextcloud VPS install with Docker, TLS and backups ซึ่งต้องมีการตั้งค่าขั้นตอน restart หรือ reload ไว้ในส่วนนี้ด้วย
การทดสอบการต่ออายุจริง
sudo certbot renew --dry-runคำสั่งนี้จะรันกระบวนการ challenge ทั้งหมดกับ staging environment ของ Let's Encrypt โดยใช้ code path, firewall และ DNS แบบเดียวกับของจริง แต่จะไม่มีการจำกัดจำนวนครั้ง (rate-limit) และไม่มีการเขียนข้อมูลลงใน disk หากการทดสอบผ่านในวันนี้ การต่ออายุแบบ unattended ในอีก 60 วันข้างหน้าก็จะผ่านเช่นกัน หากไม่มีการเปลี่ยนแปลงใดๆ เกิดขึ้นกับระบบ
การทำ dry run ไม่สามารถพิสูจน์ได้ว่า reload hook ทำงานหรือไม่ เนื่องจากพฤติกรรมของ Certbot แต่ละ version แตกต่างกัน โปรดทดสอบส่วนนี้ด้วยตนเอง โดยการรัน script ของ hook โดยตรง ตรวจสอบว่า systemctl reload nginx ทำงานสำเร็จ และตรวจสอบ sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf
ข้อผิดพลาดที่คุณอาจพบเจอ
Could not bind to IPv4 or IPv6. — --standalone เนื่องจาก nginx กำลังใช้งาน port 80 อยู่ ให้ใช้ --nginx หรือ --webroot หรือหยุดการทำงานของ nginx ก่อนเริ่มดำเนินการ ตรวจสอบว่าโปรแกรมใดใช้งาน port อยู่ด้วยคำสั่ง sudo ss -lntp | grep ':80'
Timeout during connect (likely firewall problem) — Let's Encrypt ไม่สามารถเชื่อมต่อผ่าน port 80 ได้ ให้ตรวจสอบตามลำดับดังนี้: sudo ufw status (เปิดใช้งานด้วย sudo ufw allow 'Nginx Full'), จากนั้นตรวจสอบ firewall ของผู้ให้บริการ VPS และตรวจสอบ DNS ให้ทดสอบจากเครื่องอื่นที่ไม่ใช่ server ของคุณด้วย curl -sSv http://example.com/.well-known/acme-challenge/test นอกจากนี้ การมี AAAA record ที่ล้าสมัยอาจทำให้เกิดข้อความนี้เช่นกัน
unauthorized :: Invalid response from http://example.com/.well-known/acme-challenge/xyz: 404 — port 80 สามารถเชื่อมต่อได้ แต่ไม่พบ token ให้ตรวจสอบว่าคำขอถูกส่งไปยัง server block อื่นหรือไม่ (ตรวจสอบว่า block ใดเป็นเจ้าของ default_server) หรือ directory ที่ส่งให้ -w ไม่ใช่ directory ที่ nginx ใช้งานอยู่ ให้ลองสร้างไฟล์ไว้ที่ /var/www/example.com/.well-known/acme-challenge/test แล้วทดสอบเรียกใช้งานจากภายนอก หากพบข้อผิดพลาด 404 แสดงว่าปัญหาไม่ได้เกิดจาก certificate
DNS problem: NXDOMAIN looking up A for example.com — ชื่อโดเมนไม่สามารถ resolve ผ่านระบบสาธารณะได้ อาจเกิดจาก record ใหม่ที่ยังไม่กระจายไปยัง DNS ทั่วโลก หรือเกิดจาก record ใน zone ที่ผู้ให้บริการจดทะเบียนไม่ได้ให้บริการ
too many certificates already issued for: example.com — การจำกัดจำนวนครั้ง (rate limit) ซึ่งมักพบเมื่อมีการแก้ไขปัญหาซ้ำๆ Let's Encrypt จำกัดการออก certificate ซ้ำ (ชื่อโดเมนชุดเดิม) ไว้ที่ 5 ครั้งต่อสัปดาห์ และจำกัดการออก certificate ใหม่สำหรับโดเมนที่จดทะเบียนไว้ที่ 50 ครั้งต่อสัปดาห์ โดยไม่มีวิธีแก้ไขอื่นนอกจากรอเวลา ให้ทดสอบกับ staging ด้วย --dry-run
nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": No such file or directory — nginx ถูกตั้งค่าให้ใช้ certificate ที่ไม่เคยถูกออกให้ หรือ certificate ที่ถูกลบออกด้วย certbot delete ให้ทำการ comment บรรทัด TLS server block ไว้ก่อน จากนั้นเริ่มการทำงาน nginx แล้วจึงดำเนินการออก certificate และจึงค่อยนำบรรทัดดังกล่าวกลับมาใช้งาน
open() "/etc/letsencrypt/options-ssl-nginx.conf" failed — ไฟล์ดังกล่าวมาพร้อมกับ nginx plugin package สำหรับระบบ certonly ที่ไม่มี python3-certbot-nginx ให้ติดตั้ง plugin เพิ่มเติม หรือเปลี่ยนบรรทัด include ด้วยการตั้งค่า ssl_protocols และ ssl_ciphers ของคุณเอง
การจัดการในระดับสเกลใหญ่
ใบรับรองหนึ่งใบสามารถบรรจุชื่อโดเมนได้สูงสุด 100 ชื่อ การใช้ certbot --nginx -d a.example.com -d b.example.com ... เพียงใบเดียวอาจดูน่าสนใจ แต่หากมี DNS record ชุดใดชุดหนึ่งที่ล้าสมัยจนทำให้การตรวจสอบล้มเหลว จะส่งผลให้ชื่อโดเมนอื่นทั้งหมดในใบรับรองนั้นใช้งานไม่ได้ไปด้วย การแยกใบรับรองตามแต่ละไซต์จะช่วยให้เกิดความผิดพลาดแบบแยกส่วนกัน ซึ่งเป็นสิ่งที่ควรทำสำหรับเครื่องที่โฮสต์บริการมากกว่าสองอย่างขึ้นไป เมื่อมีจำนวนไซต์มากขึ้น การใช้ front door ที่รองรับ ACME จะมีความคุ้มค่า เช่น Traefik reverse proxy running multiple apps under Docker Compose ซึ่งจะทำหน้าที่ร้องขอและต่ออายุใบรับรองด้วยตนเอง ทำให้ไม่จำเป็นต้องใช้ Certbot อีกต่อไป
ควรสำรองข้อมูล /etc/letsencrypt ทั้งหมด — sudo tar -czf letsencrypt-$(date +%F).tar.gz -C /etc letsencrypt — โดยรักษา symlinks ไว้ให้ครบถ้วน โครงสร้างนี้ประกอบด้วย accounts/ ซึ่งเป็น ACME account key ที่ไม่สามารถสร้างขึ้นใหม่ให้เหมือนเดิมได้ หากต้องการย้ายไปยัง VPS เครื่องใหม่ ขั้นตอนจะเหลือเพียง: rsync โครงสร้างข้อมูลด้วย -a, ติดตั้ง Certbot, ตั้งค่า DNS ใหม่ และรัน certbot renew --dry-run ก่อนเริ่มใช้งานจริง
หากคุณติดตั้งระบบใหม่หรือย้ายไปยัง LTS เวอร์ชันใหม่ ตัวตั้งเวลาการต่ออายุจะไม่ตามคุณไปด้วย หลังจากทำการ migration, restore snapshot หรืออัปเกรด distro ทุกครั้ง ให้รัน systemctl list-timers 'certbot*' และ --dry-run หนึ่งครั้ง การข้ามขั้นตอนนี้อาจทำให้เว็บไซต์ใช้งานไม่ได้ในอีก 89 วันต่อมา เวลา 03:00 น. เนื่องจากใบรับรองหมดอายุโดยที่ไม่มีการต่ออายุอัตโนมัติอย่างที่คาดการณ์ไว้
ข้อมูลทั้งหมดนี้ตั้งอยู่บนสมมติฐานว่าคุณเป็นเจ้าของเครื่องที่มี Public IP และเปิด port 80 ไว้สู่สาธารณะ หรือกล่าวคือเครื่อง VPS ซึ่งกลไกข้างต้นสามารถใช้ได้เหมือนกันในทุกเครื่อง
ขั้นตอนการจัดการใบรับรองแบบเดียวกันนี้สามารถใช้ บน Apache แทนที่จะเป็น nginx และในกรณีที่ไม่สามารถใช้ใบรับรองสาธารณะได้ การใช้ self-signed certificate บน Ubuntu สามารถใช้สำหรับบริการภายในได้
FAQ
ฉันจำเป็นต้องเปิด port 80 หรือไม่ หากเว็บไซต์ของฉันให้บริการเฉพาะ HTTPS?
จำเป็น สำหรับการทำ HTTP-01 challenge เนื่องจาก Let's Encrypt จะเริ่มส่งคำขอตรวจสอบผ่าน port 80 เสมอ และ Certbot ไม่มีการรองรับ TLS-ALPN-01 ดังนั้นหากตั้งค่า firewall ให้เปิดเฉพาะ port 443 จะทำให้ไม่สามารถออกใบรับรองครั้งแรกและไม่สามารถต่ออายุอัตโนมัติได้ การทำ redirect จาก port 80 ไปยัง HTTPS สามารถทำได้ เพราะการตรวจสอบจะวิ่งตาม redirect ไป วิธีเดียวที่จะข้ามการใช้ port 80 ได้คือการใช้ DNS-01 ร่วมกับ provider plugin
สำหรับ nginx บน Ubuntu 24.04 ควรติดตั้ง Certbot ผ่าน apt หรือ snap?
ควรใช้ apt เนื่องจาก sudo apt install certbot python3-certbot-nginx ให้ Certbot เวอร์ชัน 2.9.0 บน Ubuntu 24.04 ซึ่งเพียงพอต่อการใช้งานตามคู่มือนี้ ได้รับ security patches ผ่าน unattended-upgrades และไม่จำเป็นต้องใช้ snapd ให้เลือกใช้ snap เฉพาะเมื่อต้องการเวอร์ชันล่าสุดทันที หรือต้องการ DNS plugin ที่แจกจ่ายผ่าน snap เท่านั้น ไม่ว่าจะเลือกวิธีใด ให้เลือกเพียงวิธีเดียวเท่านั้น เพราะการติดตั้งสองวิธีจะทำให้มี renewal timers สองตัวชี้ไปยัง /etc/letsencrypt tree เดียวกัน และตัวที่ถูกลืมจะทำให้เกิดปัญหาภายหลัง
Certbot สามารถออก wildcard certificate สำหรับ nginx ได้หรือไม่?
ทำได้เฉพาะผ่าน DNS-01 เท่านั้น เนื่องจาก wildcard อย่าง *.example.com ไม่มี hostname เดียวในการดึงไฟล์ challenge ดังนั้นวิธี --nginx, --webroot และ --standalone จึงไม่สามารถใช้งานได้ ให้ติดตั้ง plugin สำหรับ DNS provider ของคุณ ใส่ API token ที่จำกัดสิทธิ์ไว้ในไฟล์ credentials ที่มีสิทธิ์เฉพาะ root และรันคำสั่ง certbot certonly --dns-cloudflare -d example.com -d '*.example.com' โดยต้องใส่เครื่องหมายคำพูดครอบ wildcard เพื่อป้องกันไม่ให้ shell ทำการ globbing
ทำไม nginx ยังคงแสดงใบรับรองเก่าแม้จะต่ออายุสำเร็จแล้ว?
nginx เก็บใบรับรองไว้ในหน่วยความจำ และจะไม่รับทราบถึงไฟล์ใหม่บน disk จนกว่าจะมีการ reload คำสั่ง certbot --nginx จะทำการ reload ให้โดยอัตโนมัติ แต่การรัน --webroot และ --standalone จะไม่มีการ reload ดังนั้นการต่ออายุอาจสำเร็จแต่ browser ยังคงเห็นใบรับรองที่กำลังจะหมดอายุ ให้สร้าง executable script ที่รันคำสั่ง nginx -t && systemctl reload nginx ไว้ใน /etc/letsencrypt/renewal-hooks/deploy/ เพื่อให้ script ทำงานทุกครั้งหลังการต่ออายุสำเร็จ
certbot renew --dry-run สามารถยืนยันได้หรือไม่ว่าการต่ออายุจะใช้งานได้จริง?
ยืนยันได้เกือบทั้งหมด เนื่องจากเป็นการรัน challenge จริงกับ staging environment ซึ่งใช้ firewall, DNS และ code path เดียวกัน โดยไม่มีผลกระทบต่อ rate-limit และไม่มีการเขียนข้อมูลลง disk ดังนั้นหากผ่านแสดงว่าระบบเครือข่ายไม่มีปัญหา อย่างไรก็ตาม วิธีนี้ไม่สามารถยืนยันได้ว่า deploy hook ของคุณจะทำงานหรือไม่ ให้ทดสอบแยกต่างหากโดยการรัน hook script ด้วยตนเองและตรวจสอบ sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf