SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor

วิธีติดตั้ง Certbot บน Ubuntu 24.04 สำหรับ Apache

ติดตั้ง Let's Encrypt บน Apache บน Ubuntu 24.04 ด้วยคำสั่งเดียวผ่าน apt โดยไม่ต้องใช้ snap พร้อมวิธีแก้ไขข้อผิดพลาด ServerName ที่มักทำให้การออกใบรับรองล้มเหลว

สิ่งที่คุณกำลังสร้าง

เว็บไซต์ Apache บน Ubuntu 24.04 ที่ตอบสนองผ่าน HTTPS ด้วยใบรับรอง Let's Encrypt ที่เชื่อถือได้โดยเบราว์เซอร์ ออกโดย Certbot และต่ออายุโดยอัตโนมัติผ่าน systemd timer ซึ่งคุณไม่จำเป็นต้องกังวลอีกต่อไป คำสั่งที่ใช้ดำเนินการมีเพียงบรรทัดเดียว ทุกสิ่งที่ผิดพลาดมักเกิดขึ้น ก่อน บรรทัดนั้น เช่น vhost ที่ไม่มี ServerName, พอร์ต 80 ที่ถูกปิดไว้ที่ไฟร์วอลล์ของผู้ให้บริการ หรือ DNS ที่ยังชี้ไปยังเซิร์ฟเวอร์เก่า ดังนั้นคู่มือนี้จึงเน้นไปที่เงื่อนไขเบื้องต้นเป็นหลัก และระบุข้อความแสดงข้อผิดพลาดที่ชัดเจนสำหรับแต่ละปัญหา

หมายเหตุเกี่ยวกับขอบเขต: หากเว็บเซิร์ฟเวอร์ของคุณคือ nginx ขั้นตอนจะมีลักษณะเดียวกันแต่ปลั๊กอินและไฟล์คอนฟิกจะแตกต่างกัน ให้ใช้ คู่มือเวอร์ชันสำหรับ nginx แทน และหากสิ่งที่คุณกำลังรักษาความปลอดภัยเป็นบริการภายในเท่านั้น เช่น แผงควบคุมผู้ดูแลระบบบนที่อยู่ส่วนตัว หรือเซิร์ฟเวอร์ทดสอบที่ไม่มีบุคคลภายนอกเข้าถึง คุณไม่จำเป็นต้องใช้หน่วยงานออกใบรับรอง (Certificate Authority) เลย การใช้ ใบรับรองที่ลงนามด้วยตนเอง (self-signed certificate) จะลดความซับซ้อนของระบบและสามารถใช้งานแบบออฟไลน์ได้

ข้อกำหนดเบื้องต้น และสาเหตุ 3 ประการที่ทำให้การทำงานล้มเหลวก่อนที่ Certbot จะเริ่มทำงาน

  • Apache ให้บริการเว็บไซต์ผ่าน HTTP ปกติอยู่แล้ว ปลั๊กอิน Apache ของ Certbot จะแก้ไขเว็บไซต์ที่มีอยู่เดิมเท่านั้น ไม่ได้สร้างเว็บไซต์ขึ้นมาใหม่ หากคุณเริ่มต้นจาก VPS เปล่า ให้ติดตั้ง LAMP stack บน Ubuntu 24.04 ให้เรียบร้อยก่อนแล้วค่อยกลับมา คู่มือนี้คือบท TLS ที่ขาดหายไปของขั้นตอนดังกล่าว
  • โดเมนสาธารณะที่มี A record ชี้ไปยังที่อยู่ VPS ของคุณ การตรวจสอบแบบ HTTP-01 ของ Let's Encrypt หมายความว่าเซิร์ฟเวอร์ตรวจสอบของพวกเขาจะเชื่อมต่อเข้ามายังเครื่องของคุณจากอินเทอร์เน็ต ดังนั้นจึงไม่สามารถใช้ homelab ที่อยู่หลัง NAT โดยไม่มีการทำ port forward และไม่สามารถใช้ .local ได้ แม้ว่า HTTP-01 จะสามารถตรวจสอบ IP เปล่าได้ แต่ Let's Encrypt จะออกใบรับรองสำหรับ IP เฉพาะในโปรไฟล์ shortlived ที่ต้องเลือกใช้เท่านั้น (มีอายุ 160 ชั่วโมง) และ Certbot เวอร์ชัน 2.9.0 ใน apt ไม่สามารถร้องขอ ACME profile หรือใบรับรองสำหรับ IP ได้ คู่มือนี้จึงจำเป็นต้องใช้ชื่อโดเมน dig +short example.com ต้องชี้กลับมายังที่อยู่ VPS ของคุณ และหากคุณเพิ่งเปลี่ยนค่า DNS ในช่วงหนึ่งชั่วโมงที่ผ่านมา ให้รอจนกว่าค่า TTL ของ record เดิมจะหมดอายุก่อนเริ่มออกใบรับรอง
  • หากมี AAAA record อยู่ ต้องเป็นค่าที่ถูกต้อง Let's Encrypt จะพยายามเชื่อมต่อผ่าน IPv6 ก่อนเสมอหากมีการประกาศ AAAA record ไว้ หากการเชื่อมต่อดังกล่าวหมดเวลา (timeout) ระบบจะลองใหม่ผ่าน IPv4 แต่จะไม่มีการลองใหม่หากเกิดข้อผิดพลาดอื่น ดังนั้นหาก AAAA record ชี้ไปยังที่อยู่ที่ปฏิเสธการเชื่อมต่อ หรือชี้ไปยังเซิร์ฟเวอร์อื่นที่ไม่ใช่เครื่องนี้ การตรวจสอบจะล้มเหลวแม้ว่าการทดสอบ curl จากแล็ปท็อปของคุณ (ซึ่งมักจะเป็น IPv4) จะทำงานได้ปกติก็ตาม ให้ประกาศค่า AAAA ที่ถูกต้องหรือลบออกไปเลย

พอร์ต 80 และ 443 ต้องเปิดใช้งานใน ufw และ ในไฟร์วอลล์เครือข่ายของผู้ให้บริการของคุณ โดยโฮสติ้งส่วนใหญ่จะมีไฟร์วอลล์ชั้นที่สองที่ระบบปฏิบัติการมองไม่เห็น การตรวจสอบแบบ HTTP-01 จะทำผ่านพอร์ต 80 โดยเฉพาะ คุณไม่สามารถรันการตรวจสอบนี้โดยใช้เพียงพอร์ต 443 ได้

sudo ufw allow "Apache Full"
sudo ufw status

หากเตรียมการทั้งหมดนี้แล้ว งานทั้งหมดจะใช้เวลาเพียง 15 นาที โดย 10 นาทีนั้นคือเวลาสำหรับการอ่านทำความเข้าใจ

จะใช้ Certbot ผ่าน Snap หรือ apt ดี? บน 24.04 การใช้ apt ถือว่าเหมาะสมแล้ว

Certbot เปลี่ยนไปใช้การแจกจ่ายผ่าน snap เมื่อหลายปีก่อนด้วยเหตุผลที่สมเหตุสมผล นั่นคือแพ็กเกจของ distro มักจะล้าสมัย Ubuntu 20.04 มาพร้อมกับ Certbot 0.40 และไม่เคยอัปเดตเวอร์ชัน ทำให้ทีมพัฒนาต้องคอยแก้ไขบั๊กที่มีอายุเก่าแก่ถึง 5 ปี แต่บน 24.04 เหตุผลดังกล่าวหมดไปแล้ว เนื่องจากคลังซอฟต์แวร์มี Certbot 2.9.0 ซึ่งเป็นเวอร์ชันที่ปล่อยออกมาในเดือนกุมภาพันธ์ 2024 จากสายการพัฒนา 2.x ที่ทันสมัย และ unattended-upgrades จะติดตั้งการอัปเดตความปลอดภัยใดๆ ที่ Ubuntu เผยแพร่ออกมาให้โดยอัตโนมัติ แม้ว่าต้นทางจะขยับไปที่ซีรีส์ 5.x แล้ว แต่ไม่มีส่วนใดในคู่มือนี้ที่จำเป็นต้องใช้เวอร์ชันดังกล่าว คำแนะนำของผมสำหรับ OS นี้คือ: ให้ใช้ apt คุณจะสามารถหลีกเลี่ยงการใช้ snapd daemon, ปลั๊กอิน Apache จะถูกติดตั้งไปพร้อมกันในการทำรายการเดียว และตัวตั้งเวลาต่ออายุจะทำงานร่วมกับ systemd ตามมาตรฐานของ Debian

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

ผลลัพธ์ที่ถูกต้องคือ: certbot 2.9.0 แพ็กเกจ python3-certbot-apache คือปลั๊กอินที่ทำหน้าที่อ่านและแก้ไขไฟล์คอนฟิก Apache ของคุณ หากไม่มีปลั๊กอินนี้ certbot --apache จะล้มเหลวพร้อมกับข้อความ The requested apache plugin does not appear to be installed

การใช้ snap ยังคงเป็นทางเลือกที่เหมาะสมในสองกรณี: คุณต้องการใช้ Certbot เวอร์ชันล่าสุดทันทีที่ปล่อยออกมา หรือคุณจำเป็นต้องใช้ DNS plugin ที่มีการแจกจ่ายในรูปแบบ snap เท่านั้น (ปลั๊กอินของผู้ให้บริการ certbot-dns-* หลายตัวเป็นเช่นนั้น) หากคุณเลือกวิธีนี้:

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

ไม่ว่าคุณจะเลือกวิธีใด ห้ามติดตั้งทั้งสองแบบพร้อมกัน การติดตั้งสองชุดหมายถึงตัวกำหนดเวลาการต่ออายุสองตัวที่แย่งกันทำงานกับ /etc/letsencrypt และ certbot ที่ shell ของคุณพบใน PATH อาจไม่ใช่ตัวที่จัดการ certificate ของคุณอยู่ บรรทัด apt remove ด้านบนไม่ใช่สิ่งที่ใส่ไว้เพื่อความสวยงาม แต่เป็นสิ่งที่จำเป็นต้องทำ

vhost ที่ Certbot แก้ไขต้องมีอยู่จริง และ ServerName คือหัวใจสำคัญ

certbot --apache ทำงานโดยการค้นหา virtual host บนพอร์ต 80 ที่มี ServerName หรือ ServerAlias ตรงกับแต่ละ -d โดเมนที่คุณระบุ เพื่อพิสูจน์การควบคุมโดเมนผ่าน vhost นั้น จากนั้นจึงเขียน vhost เวอร์ชัน SSL ขึ้นมา หากไม่มี ServerName ที่ตรงกัน ก็จะไม่พบ vhost เป้าหมาย และ 000-default.conf ค่าเริ่มต้นของ Ubuntu ก็มาพร้อมกับ ServerName ที่ถูกคอมเมนต์ไว้ บรรทัดที่ถูกคอมเมนต์ไว้นั้นเป็นสาเหตุที่พบบ่อยที่สุดที่ทำให้คำสั่งหลักในคู่มือนี้ทำงานล้มเหลว

ดังนั้น ก่อนจะเริ่มใช้งาน Certbot ให้กำหนดชื่อ vhost ให้ถูกต้องเสียก่อน โดยสร้างไฟล์ /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>

เปิดใช้งาน vhost ดังกล่าวและตรวจสอบว่า Apache สามารถอ่านค่าและกำหนดเส้นทางตามชื่อโดเมนได้ถูกต้อง:

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

configtest ต้องแสดงผลเป็น Syntax OK หากมีการแสดงผล AH00558: apache2: Could not reliably determine the server's fully qualified domain name ด้วย นั่นเป็นเพียงคำเตือนเกี่ยวกับ ServerName ในระดับ global ไม่ใช่ vhost ของคุณ ซึ่งไม่มีผลกระทบใดๆ ในที่นี้ และสามารถปิดการแจ้งเตือนได้ด้วยการตั้งค่า echo "ServerName $(hostname -f)" | sudo tee /etc/apache2/conf-available/servername.conf && sudo a2enconf servername && sudo systemctl reload apache2

ผลลัพธ์จาก -S คือสิ่งที่ใช้ตรวจสอบความถูกต้อง คุณต้องเห็นบรรทัดที่คล้ายกับ port 80 namevhost example.com (/etc/apache2/sites-enabled/example.com.conf:1) โดยมี alias www.example.com อยู่ด้านล่าง ซึ่ง Apache จะรายงาน sites-enabled symlink ที่อ่านจริง ไม่ใช่ไฟล์ที่คุณแก้ไขใน sites-available หาก example.com ไม่ปรากฏในรายการของพอร์ต 80 Certbot ก็จะไม่พบ vhost นั้นเช่นกัน

ออกใบรับรอง: certbot --apache

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

การรันครั้งแรกจะถามข้อมูล 3 อย่าง ได้แก่ ที่อยู่อีเมล (ปัจจุบัน Let's Encrypt ไม่เก็บอีเมลไว้กับบัญชี ACME และไม่ส่งการแจ้งเตือนเมื่อใบรับรองหมดอายุอีกต่อไป ดังนั้นคุณต้องตรวจสอบการต่ออายุด้วยตนเอง), การยอมรับข้อตกลงของ Let's Encrypt และการยินยอมแบ่งปันอีเมลกับ EFF ปัจจุบันไม่มีคำถามเรื่องการ redirect อีกต่อไป เนื่องจากตั้งแต่ Certbot 1.0 เป็นต้นมา ตัวติดตั้ง Apache จะทำ redirect จาก HTTP ไปยัง HTTPS เป็นค่าเริ่มต้น (คำถามนี้ถูกตัดออกตั้งแต่เวอร์ชัน 1.4) ซึ่งเป็นสิ่งที่ควรทำอยู่แล้ว หากคุณจำเป็นต้องให้บริการผ่าน HTTP แบบปกติจริงๆ ให้ใช้แฟล็ก --no-redirect

เมื่อสำเร็จจะปรากฏข้อความดังนี้ ซึ่งคุณควรอ่านรายละเอียดให้ครบถ้วนแทนการกวาดสายตาผ่านๆ:

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 2027-01-09.

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

เบื้องหลังข้อความดังกล่าว Certbot ได้ดำเนินการ 4 อย่าง ได้แก่ เปิดใช้งานโมดูล ssl ของ Apache (หากยังไม่ได้เปิด), สร้างไฟล์ example.com-le-ssl.conf ซึ่งเป็นสำเนาของ vhost เดิมของคุณที่ *:443 พร้อมระบุ SSLEngine on และพาธของใบรับรอง, เปิดใช้งาน vhost ดังกล่าว และเพิ่มบล็อก RewriteRule เข้าไปใน vhost พอร์ต 80 เดิมเพื่อทำ 301 redirect ทราฟฟิกทั้งหมดไปยัง HTTPS ไฟล์ vhost เดิมของคุณจะถูกแก้ไข ไม่ใช่ถูกแทนที่ และไฟล์ SSL ที่สร้างขึ้นใหม่จะถูกวางไว้คู่กัน ซึ่งคุณสามารถตรวจสอบทุกบรรทัดที่ถูกเพิ่มเข้าไปได้

ตำแหน่งที่จัดเก็บใบรับรองจริง และเหตุผลที่คุณไม่ควรคัดลอกไฟล์เหล่านั้น

ไฟล์ทั้งหมดจะถูกจัดเก็บไว้ภายใต้ /etc/letsencrypt/live/example.com/ ได้แก่ fullchain.pem (ใบรับรองรวมถึง intermediate chain ซึ่งเป็นสิ่งที่เซิร์ฟเวอร์ควรชี้ไปหา), privkey.pem (private key ซึ่งควรเข้าถึงได้โดย root เท่านั้น) รวมถึง cert.pem และ chain.pem สำหรับซอฟต์แวร์ที่ต้องการไฟล์แยกส่วนกัน ไฟล์เหล่านี้เป็น symlink ที่ชี้ไปยัง /etc/letsencrypt/archive/ ซึ่งการอ้างอิงผ่านทางอ้อมนี้คือกลไกการต่ออายุใบรับรอง โดยกระบวนการต่ออายุจะเขียนไฟล์ชุดใหม่ลงใน archive/ แล้วปรับ symlink ให้ชี้ไปยังไฟล์ชุดใหม่นั้น หากคุณกำหนดค่าซอฟต์แวร์อื่นให้ชี้ไปยังเส้นทาง live/ ซอฟต์แวร์เหล่านั้นจะได้รับใบรับรองที่ต่ออายุโดยอัตโนมัติ แต่หากคุณคัดลอกไฟล์ไปไว้ที่อื่น คุณจะประสบปัญหาบริการหยุดทำงานเมื่อครบกำหนด 90 วัน

ไฟล์อื่นที่ควรทราบคือ /etc/letsencrypt/renewal/example.com.conf ซึ่งบันทึกวิธีการออกใบรับรองนี้ รวมถึง authenticator = apache, installer = apache และชื่อโดเมน เพื่อให้กระบวนการต่ออายุสามารถทำซ้ำได้โดยไม่ต้องมีผู้ดูแล รวมถึงการสั่ง reload Apache หลังจากเสร็จสิ้นกระบวนการ

การต่ออายุถูกกำหนดไว้แล้ว ให้ตรวจสอบสถานะ ไม่ต้องสร้างใหม่

ใบรับรอง Let's Encrypt มีอายุการใช้งาน 90 วันตามการออกแบบ และแพ็กเกจ apt ได้ติดตั้งกลไกการทำงานไว้เรียบร้อยแล้ว นั่นคือ systemd timer ที่จะเรียกใช้ Certbot วันละ 2 ครั้งในเวลาที่สุ่มขึ้นมา เพื่อต่ออายุใบรับรองใดก็ตามที่เหลืออายุการใช้งานไม่ถึง 30 วัน ห้ามเพิ่ม cron job ซ้อนทับลงไป เพราะตัวจัดตารางเวลาตัวที่สองไม่ได้ช่วยอะไรนอกจากทำให้เกิด log ที่ไม่จำเป็นและเสี่ยงต่อการติด rate-limit ของ Let's Encrypt ได้ประกาศว่าตั้งแต่วันที่ 10 กุมภาพันธ์ 2027 เป็นต้นไป ใบรับรองใหม่จะมีอายุการใช้งานเริ่มต้นที่ 64 วัน ซึ่งช่วงเวลา 30 วันก่อนหมดอายุยังคงใช้งานได้ตามปกติ การต่ออายุจะเกิดขึ้นในช่วงวันที่ 34 แทนที่จะเป็นวันที่ 60 ดังนั้นจึงไม่มีสิ่งใดที่ต้องแก้ไขบนเซิร์ฟเวอร์นี้

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

คำสั่งแรกจะแสดงสถานะของ timer ที่กำลังทำงานอยู่ โดยจะมีเวลา NEXT แสดงในช่วง 24 ชั่วโมงข้างหน้า ตารางการทำงานคือวันละ 2 ครั้งพร้อมการหน่วงเวลาแบบสุ่ม ดังนั้นเวลาที่แน่นอนจึงไม่สามารถคาดเดาได้ (หากติดตั้งผ่าน snap ตัว timer จะเป็น snap.certbot.renew.timer แทน) การทำ dry run คือการซ้อมต่ออายุจริงกับสภาพแวดล้อม staging ของ Let's Encrypt ซึ่งจะมีการตรวจสอบ challenge จริง แต่จะไม่มีการออกใบรับรองจริงและไม่เสียโควตา rate-limit ผลลัพธ์ที่ถูกต้องจะลงท้ายด้วย:

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

หากการทำ dry run ล้มเหลว การต่ออายุจริงในอีกประมาณ 60 วันข้างหน้าก็จะล้มเหลวในลักษณะเดียวกัน ให้แก้ไขปัญหาทันทีในขณะที่ใบรับรองปัจจุบันยังมีอายุการใช้งานเหลืออยู่ สาเหตุที่พบบ่อยคือการตั้งค่า firewall ที่เพิ่มเข้ามาหลังจากออกใบรับรอง ซึ่งไปปิดพอร์ต 80 อีกครั้ง

ตรวจสอบด้วย curl และสิ่งที่ไอคอนรูปแม่กุญแจควรแสดง

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

คำสั่งแรกควรส่งกลับ HTTP/1.1 301 Moved Permanently พร้อมส่วนหัว Location: https://example.com/ ซึ่งเป็นการเปลี่ยนเส้นทาง (redirect) ที่ Certbot ติดตั้งไว้ คำสั่งที่สองควรส่งกลับ HTTP/1.1 200 OK โดยไม่มีการแจ้งเตือนข้อผิดพลาดเกี่ยวกับ TLS จาก curl คำสั่งที่สามจะแสดงผู้ออกใบรับรอง (issuer) บรรทัด O = Let's Encrypt ที่มี CN สั้นๆ เช่น YE1 หรือ YE2 (สำหรับคีย์ ECDSA) หรือ YR1 หรือ YR2 (สำหรับคีย์ RSA) และ notAfter ซึ่งมีอายุเหลือประมาณ 90 วัน ใบรับรองที่ออกก่อนที่ Let's Encrypt จะเลิกใช้ intermediate รุ่นเก่าอาจยังแสดง CN เป็น R12 หรือ E7 จนกว่าจะถึงการต่ออายุครั้งถัดไป ซึ่งไม่ใช่ข้อผิดพลาด ในเบราว์เซอร์คุณจะเห็นไอคอนรูปแม่กุญแจ และเมื่อคลิกดูจะพบผู้ออกใบรับรองเดียวกัน หาก curl ทำงานได้ปกติแต่เบราว์เซอร์แจ้งเตือน เป็นไปได้สูงว่าคุณกำลังดูหน้าเว็บที่แคชไว้หรือใช้ชื่อโฮสต์ผิด ไม่ใช่ปัญหาที่ตัวใบรับรอง

หลายเว็บไซต์: ใบรับรอง SAN ใบเดียว หรือใบรับรองแยกต่อเว็บไซต์

ทั้งสองวิธีใช้งานได้และมีวิธีการต่ออายุเหมือนกัน สำหรับเว็บไซต์ที่ไม่เกี่ยวข้องกันบนเซิร์ฟเวอร์เดียวกัน ให้รันคำสั่งออกใบรับรองแยกกันต่อเว็บไซต์ แต่ละเว็บไซต์จะมีไดเรกทอรีของตนเองภายใต้ live/ และมีไฟล์กำหนดค่าการต่ออายุแยกกัน ทำให้ปัญหาของโดเมนหนึ่งไม่ส่งผลกระทบต่อการต่ออายุของโดเมนอื่น นี่เป็นวิธีที่ผมใช้เป็นค่าเริ่มต้น

สำหรับเว็บไซต์เดียวที่มีหลายชื่อ ให้รวมไว้ในใบรับรอง SAN ใบเดียว โดยใบรับรองหนึ่งใบสามารถรองรับชื่อได้สูงสุด 100 ชื่อ ซึ่งคุณได้ดำเนินการไปแล้วข้างต้นด้วย example.com และ www.example.com หากต้องการเพิ่มชื่อลงในใบรับรองที่มีอยู่ภายหลัง ให้ทำการออกใบรับรองใหม่โดยระบุชื่อใบรับรองและรายการชื่อใหม่ทั้งหมด:

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

Certbot จะตรวจพบชุดโดเมนที่เปลี่ยนแปลงไป และขอให้คุณยืนยันการขยายใบรับรอง จากนั้นจะแทนที่ใบรับรองเดิมในตำแหน่งเดิมที่ live/ ทำให้ไม่ต้องแก้ไขส่วนอื่นเพิ่มเติม โปรดทราบว่ารายการที่ระบุคือการแทนที่รายการเดิม ไม่ใช่การเพิ่มต่อท้าย: หากคุณละ www ออกจากคำสั่งดังกล่าว ใบรับรองใหม่จะตัดชื่อนั้นออกโดยไม่มีการแจ้งเตือน

Wildcard ต้องใช้ DNS-01 และโดยปกติแล้วคุณไม่จำเป็นต้องใช้ Wildcard

HTTP-01 ไม่สามารถออก *.example.com ได้ การวางไฟล์บนเว็บเซิร์ฟเวอร์เป็นการพิสูจน์การควบคุมเพียงหนึ่ง hostname ไม่ใช่ทั้ง namespace การใช้ Wildcard จำเป็นต้องผ่านการตรวจสอบแบบ DNS-01: Certbot จะตั้งค่า TXT record ที่ _acme-challenge.example.com ซึ่งในทางปฏิบัติหมายถึงการใช้ปลั๊กอิน certbot-dns-* ร่วมกับ API credentials ของผู้ให้บริการ DNS ของคุณ หรือการแก้ไข TXT record ด้วยตนเองทุกครั้งที่มีการต่ออายุผ่าน --manual (ซึ่งเป็นวิธีที่ลำบากและไม่ควรนำมาวางแผนใช้งาน) คำแนะนำโดยละเอียดตั้งแต่กลไกของ TXT record ไปจนถึงการใช้ปลั๊กอินเพื่อต่ออายุโดยอัตโนมัติอยู่ใน ใบรับรอง Wildcard ด้วย Certbot ผ่าน DNS-01 คำแนะนำจากประสบการณ์จริงคือ หากคุณมี subdomain ที่ระบุได้ชัดเจน 4 รายการ การใช้ SAN certificate ที่ระบุชื่อทั้ง 4 รายการนั้นจะจัดการได้ง่ายกว่าการใช้ Wildcard และไม่จำเป็นต้องเก็บ DNS API keys ไว้บนเซิร์ฟเวอร์

รูปแบบความล้มเหลวและข้อความที่คุณจะพบ

Certbot ปฏิเสธที่จะเริ่มทำงานเนื่องจากไฟล์ config ของ Apache มีข้อผิดพลาด

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')

ปลั๊กอินจะรัน configtest ก่อนที่จะดำเนินการใดๆ และจะหยุดทำงานทันทีหาก Apache มีปัญหา ข้อความ \n ที่ปรากฏคือค่าที่แสดงผลจริงเนื่องจาก Certbot พิมพ์ค่า repr ของ exception ออกมา ให้คุณรัน sudo apache2ctl configtest ด้วยตนเอง คำสั่งนี้จะระบุชื่อไฟล์และบรรทัดที่มีปัญหา ซึ่งมักเกิดจากการพิมพ์ผิดขณะแก้ไขไฟล์ด้วยมือ, SSLCertificateFile ที่ชี้ไปยัง path ที่ไม่มีอยู่จริง หรือการอ้างอิงโมดูลที่ยังไม่ได้เปิดใช้งาน ให้แก้ไขจนกว่าคำสั่งจะแสดงผล Syntax OK แล้วจึงรัน Certbot อีกครั้ง

ไม่มี vhost ใดตรงกับโดเมน

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

นี่คือความล้มเหลวจากกรณีที่ขาด ServerName ซึ่งตรวจพบในขั้นตอนการออกใบรับรอง Certbot ได้ค้นหา vhost พอร์ต 80 ทุกตัวที่เปิดใช้งานอยู่เพื่อหา ServerName/ServerAlias ที่ตรงกับ -d ของคุณแต่ไม่พบสิ่งใด sudo apache2ctl -S จะแสดงให้เห็นว่า Apache ทำการ route คำขออย่างไรบ้าง ให้เพิ่มบรรทัด ServerName ลงใน vhost ที่ถูกต้อง จากนั้น reload และลองใหม่อีกครั้ง ปัญหาที่ใกล้เคียงกันคือการตรวจสอบไปถึง vhost ที่ ผิด ทำให้การตอบสนองต่อ challenge ส่งค่ากลับมาเป็น Invalid response ... 404 เนื่องจากเว็บไซต์อื่นรับคำขอนั้นไปเสียก่อน ให้ใช้วิธีวินิจฉัยและเครื่องมือเดียวกันคือ apache2ctl -S

การตรวจสอบหมดเวลา (Validation times out)

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

Let's Encrypt ไม่สามารถเปิดการเชื่อมต่อ TCP ไปยังพอร์ต 80 ที่ที่อยู่ซึ่ง DNS ของคุณประกาศไว้ได้ โดยเรียงลำดับความเป็นไปได้ดังนี้: firewall ของผู้ให้บริการเครือข่าย (แยกจาก ufw ซึ่งตั้งค่าในแผงควบคุมโฮสติ้ง), กฎของ ufw ที่อนุญาตเฉพาะพอร์ต 443 หรือ SSH เท่านั้น หรือ DNS ยังคงชี้ไปยังเซิร์ฟเวอร์ตัวเก่า การมี AAAA record ที่ล้าสมัยเพียงอย่างเดียวมักไม่ทำให้เกิดปัญหานี้ เพราะเมื่อการเชื่อมต่อผ่าน IPv6 หมดเวลา Let's Encrypt จะลองใหม่ผ่าน IPv4 ปัญหาจาก AAAA มักจะปรากฏเป็น Connection refused หรือ Invalid response จากเซิร์ฟเวอร์ที่ไม่ถูกต้องมากกว่า ให้ทดสอบจาก ภายนอก VPS: การใช้ curl -I http://example.com จากแล็ปท็อปของคุณจะจำลองสิ่งที่ตัวตรวจสอบของพวกเขาเห็น

คุณลองซ้ำจนติด rate limit

Error creating new order :: too many failed authorizations (5) for "example.com" in the last 1h0m0s, retry after ... UTC: see https://letsencrypt.org/docs/rate-limits/...

Let's Encrypt อนุญาตให้ตรวจสอบล้มเหลวได้ 5 ครั้งต่อชื่อโฮสต์ต่อบัญชีต่อชั่วโมง โดยเปรียบเสมือนถังที่ค่อยๆ เติมกลับมาทีละหนึ่งครั้งในทุกๆ 12 นาที การกดลองซ้ำๆ ในขณะที่ firewall ยังมีปัญหาจะทำให้โควตานี้หมดลงอย่างรวดเร็ว การรอช่วยได้ แต่การแก้ไขที่แท้จริงคือการปรับพฤติกรรม: หลังจากเกิดความล้มเหลว ให้ debug ด้วย staging environment จนกว่าจะสำเร็จ

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

โปรดสังเกต certonly: --dry-run จะยอมรับได้เฉพาะในคำสั่งย่อย certonly และ renew เท่านั้น ส่วนการใช้ certbot --apache --dry-run เปล่าๆ จะปฏิเสธการทำงานและแจ้งเตือนคุณว่า --dry-run currently only works with the 'certonly' or 'renew' subcommands การทำ dry run จะตรวจสอบกับ staging ซึ่งมีขีดจำกัดที่ยืดหยุ่นกว่าและไม่ออกใบรับรองจริง คุณจึงสามารถทดสอบจนกว่าจะผ่านได้ตลอดทั้งบ่าย ให้รันคำสั่งจริงอีกครั้งก็ต่อเมื่อผ่านการทดสอบใน staging แล้วเท่านั้น สำหรับขีดจำกัดอื่นๆ เช่น 50 ใบรับรองต่อโดเมนที่ลงทะเบียนต่อสัปดาห์ หรือ 5 ใบรับรองที่ซ้ำกันต่อสัปดาห์ คุณจะพบปัญหานี้ก็ต่อเมื่อมีสคริปต์ที่พยายามออกใบรับรองซ้ำเป็นวงวนเท่านั้น

เมื่อ HTTPS ใช้งานได้แล้ว โปรดจำไว้ว่าใบรับรองช่วยรักษาความปลอดภัยให้แก่ การรับส่งข้อมูล ไม่ใช่ตัวเซิร์ฟเวอร์: พอร์ต 22 ยังคงถูกสุ่มรหัสผ่านอยู่ตลอดเวลา การใช้งานร่วมกับ Fail2ban บน Ubuntu 24.04 คือขั้นตอนถัดไปที่ควรทำภายใน 30 นาทีนี้

FAQ

ฉันควรติดตั้ง Certbot ด้วย snap หรือ apt สำหรับ Apache บน Ubuntu 24.04?

ให้ใช้ apt เนื่องจาก Ubuntu 24.04 มาพร้อมกับ Certbot 2.9.0 ซึ่งทันสมัยเพียงพอสำหรับทุกขั้นตอนในคู่มือนี้ อีกทั้งยังได้รับอัปเดตความปลอดภัยผ่าน unattended-upgrades ของ Ubuntu โดยตรง และไม่จำเป็นต้องใช้ snapd ให้เลือกใช้ snap เฉพาะในกรณีที่คุณต้องการรุ่นล่าสุดทันที หรือต้องการ DNS plugin ที่แจกจ่ายผ่าน snap เท่านั้น หากคุณเปลี่ยนมาใช้ snap ให้ apt remove certbot python3-certbot-apache ก่อน เพื่อป้องกันไม่ให้ตัวกำหนดเวลาการต่ออายุ (renewal scheduler) ทำงานซ้อนทับกัน

ทำไม Certbot ถึงแจ้งว่า "Unable to find a virtual host listening on port 80"?

เนื่องจากไม่มี vhost ที่เปิดใช้งานอยู่บนพอร์ต 80 ที่มีค่า ServerName หรือ ServerAlias ตรงกับโดเมนที่คุณระบุด้วย -d โดยปกติแล้ว vhost เริ่มต้นของ Ubuntu จะใส่เครื่องหมายคอมเมนต์ไว้ที่ ServerName ให้รัน sudo apache2ctl -S เพื่อค้นหา (หรือสร้าง) vhost ที่ควรเป็นเจ้าของชื่อโดเมนนั้น จากนั้นเพิ่ม ServerName example.com, โหลด Apache ใหม่ และรัน Certbot อีกครั้ง

ฉันจะแก้ไขปัญหา "Timeout during connect (likely firewall problem)" ได้อย่างไร?

Let's Encrypt ไม่สามารถเชื่อมต่อพอร์ต 80 ที่ที่อยู่ซึ่ง DNS ของคุณประกาศไว้ได้ ให้ตรวจสอบ firewall ระดับเครือข่ายในแผงควบคุมของผู้ให้บริการของคุณควบคู่ไปกับ ufw, ตรวจสอบว่า dig +short example.com ส่งค่ากลับมาเป็น VPS เครื่องนี้ และแก้ไขหรือลบ AAAA record ที่ไม่ถูกต้องออก เนื่องจากกระบวนการตรวจสอบจะพยายามใช้ IPv6 ก่อนเสมอและจะเปลี่ยนไปใช้ IPv4 ก็ต่อเมื่อเกิด timeout เท่านั้น ให้ยืนยันการแก้ไขจากภายนอกเซิร์ฟเวอร์ด้วย curl -I http://example.com จากนั้นทดสอบด้วย sudo certbot certonly --apache --dry-run -d example.com ก่อนการออกใบรับรองจริง

Certbot ต่ออายุใบรับรองโดยอัตโนมัติบน Ubuntu 24.04 หรือไม่?

ใช่ แพ็กเกจ apt จะติดตั้ง certbot.timer ซึ่งเป็น systemd timer ที่ทำงานวันละสองครั้งเพื่อต่ออายุใบรับรองที่เหลืออายุไม่ถึง 30 วัน และทำการโหลด Apache ใหม่หลังจากนั้น ส่วน snap จะใช้ snap.certbot.renew.timer สำหรับงานเดียวกัน ให้ตรวจสอบสถานะด้วย systemctl list-timers certbot.timer และทดสอบด้วย sudo certbot renew --dry-run โดยไม่จำเป็นต้องเพิ่ม cron job ของคุณเองเข้าไปซ้อน

ฉันจะขอใบรับรองแบบ wildcard ด้วย Certbot และ Apache ได้อย่างไร?

ใบรับรองแบบ wildcard ต้องใช้การตรวจสอบแบบ DNS-01: Certbot จะต้องวาง TXT record ไว้ที่ _acme-challenge.example.com ซึ่งหมายความว่าต้องใช้ plugin certbot-dns-* ที่มี API credentials ของผู้ให้บริการ DNS ของคุณ (ทางเลือกอื่นอย่าง --manual จำเป็นต้องแก้ไข TXT record ด้วยตนเองทุกครั้งที่มีการต่ออายุ) หากคุณมี subdomain ที่ทราบจำนวนแน่นอนเพียงไม่กี่รายการ การใช้ใบรับรองแบบ SAN ที่ระบุชื่อ subdomain เหล่านั้นไว้อย่างชัดเจนจะง่ายกว่าและช่วยให้ไม่ต้องเก็บ API key ของ DNS ไว้บนเซิร์ฟเวอร์