Wildcard SSL ด้วย Certbot + DNS Challenge บน VPS
Wildcard SSL Certificate คือ certificate เดียวที่ครอบคลุมทุก subdomain ของ domain เดียวกัน เช่น *.example.com ใช้ได้กับ www, api, mail, staging — ไม่ต้องออก certificate แยกให้แต่ละ subdomain Let's Encrypt ออก Wildcard SSL ได้ฟรี แต่ต้องใช้วิธี DNS Challenge แทน HTTP Challenge ทั่วไป
ความแตกต่าง HTTP Challenge กับ DNS Challenge
Certbot มีสองวิธีพิสูจน์ว่าคุณเป็นเจ้าของ domain:
- HTTP Challenge (--webroot / --nginx): วาง token ไว้ที่
/.well-known/acme-challenge/ใช้ได้กับ single domain แต่ออก Wildcard ไม่ได้ - DNS Challenge (--manual หรือ plugin): เพิ่ม TXT record ใน DNS เพื่อพิสูจน์ว่าควบคุม domain ได้ — วิธีเดียวที่รองรับ Wildcard
ติดตั้ง Certbot บน Ubuntu 22.04
# ติดตั้ง snap-based certbot (แนะนำ)
sudo apt update
sudo apt install snapd -y
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# ตรวจสอบ version
certbot --version
ขอ Wildcard Certificate แบบ Manual DNS
วิธีนี้เหมาะเมื่อ DNS provider ไม่มี certbot plugin รองรับ ต้องเพิ่ม TXT record ด้วยมือ แต่ทำได้กับทุก DNS provider:
# ขอ certificate สำหรับ domain หลักและ wildcard พร้อมกัน
sudo certbot certonly \
--manual \
--preferred-challenges dns \
-d "example.com" \
-d "*.example.com"
Certbot จะแสดง challenge ให้เพิ่มใน DNS:
Please deploy a DNS TXT record under the name:
_acme-challenge.example.com
with the following value:
oHbFTCFMzL_X_aBcDeFgHiJkLmNoPqRsTuVwXy
Before continuing, verify the TXT record is deployed with:
dig -t txt _acme-challenge.example.com
dig ก่อน ถ้ากด Enter ก่อน DNS propagate certbot จะ fail และต้องเริ่มใหม่
# ตรวจสอบว่า DNS TXT record propagate แล้ว
dig -t txt _acme-challenge.example.com +short
# หรือใช้ nslookup
nslookup -type=TXT _acme-challenge.example.com 8.8.8.8
ตั้งค่า Auto-Renew ด้วย DNS Plugin (Cloudflare ตัวอย่าง)
Wildcard Certificate แบบ manual ต้อง renew ด้วยมือทุก 90 วัน การตั้ง DNS plugin ช่วยให้ renew อัตโนมัติได้:
# ติดตั้ง Cloudflare plugin
sudo snap install certbot-dns-cloudflare
# สร้างไฟล์ credentials
sudo mkdir -p /etc/letsencrypt/cloudflare
sudo nano /etc/letsencrypt/cloudflare/credentials.ini
# ใส่ Cloudflare API Token (ต้องมีสิทธิ์ Zone:DNS:Edit)
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
# ตั้ง permission ให้ปลอดภัย
sudo chmod 600 /etc/letsencrypt/cloudflare/credentials.ini
# ขอ Wildcard certificate แบบ automatic
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
-d "example.com" \
-d "*.example.com" \
--preferred-challenges dns-01
นำ Certificate ไปใช้กับ Nginx
# certificate อยู่ที่
ls /etc/letsencrypt/live/example.com/
# fullchain.pem privkey.pem cert.pem chain.pem
# ตั้งค่า Nginx server block
server {
listen 443 ssl http2;
server_name example.com *.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# HSTS (6 เดือน)
add_header Strict-Transport-Security "max-age=15768000" always;
}
# ทดสอบ config และ reload
nginx -t && systemctl reload nginx
ตั้ง Auto-Renew และทดสอบ
# certbot timer ถูกตั้งอัตโนมัติเมื่อติดตั้ง snap
systemctl status snap.certbot.renew.timer
# ทดสอบ renew (dry-run)
sudo certbot renew --dry-run
# ดู certificate ที่มีอยู่
sudo certbot certificates
--deploy-hook "systemctl reload nginx" เพื่อ reload nginx อัตโนมัติหลัง renew สำเร็จ ใส่ไว้ใน /etc/letsencrypt/renewal/example.com.conf ส่วน [renewalparams]
ตรวจสอบว่า Wildcard SSL ทำงานถูกต้อง
# ตรวจสอบ certificate ที่ออก
sudo certbot certificates
# ควรแสดง: Domains: example.com *.example.com
# ทดสอบ SSL ด้วย openssl
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -subject -dates
# ทดสอบกับ subdomain
openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null | \
openssl x509 -noout -subject
# ดูวันหมดอายุ
sudo certbot certificates | grep "Expiry Date"
curl -vI https://staging.example.com 2>&1 | grep -i "SSL\|certificate\|expire" ทดสอบ subdomain ใหม่ได้อย่างรวดเร็วโดยไม่ต้องติดตั้ง tool เพิ่ม
แก้ปัญหาที่พบบ่อย
Error: "DNS problem: NXDOMAIN looking up TXT for _acme-challenge"
TXT record ยังไม่ propagate หรือเพิ่ม record ผิด subdomain วิธีแก้:
ตรวจจากภายนอกด้วย SSL Checker ของ dnsxray.com จะเห็นว่าใบรับรองที่เสิร์ฟจริงมี SAN ครอบคลุม *.example.com หรือไม่ พร้อม Chain, วันหมดอายุ และ Signature Algorithm — มีประโยชน์มากหลัง Renew เพราะบางครั้ง Certbot ต่ออายุสำเร็จแต่ Nginx ยังไม่ Reload
# ตรวจสอบ TXT record จาก multiple nameserver
dig -t txt _acme-challenge.example.com @8.8.8.8 +short
dig -t txt _acme-challenge.example.com @1.1.1.1 +short
# ถ้าไม่มีผล ให้รอ 5 นาทีแล้วลองใหม่
# DNS TTL ของ provider บางเจ้าช้าถึง 10 นาที
Error: "An unexpected error occurred: The server will not issue certificates for the identifier"
Domain ถูก rate limit จาก Let's Encrypt (ขอ certificate เกิน 5 ครั้งต่อสัปดาห์ต่อ domain) ให้รอ 1 สัปดาห์หรือใช้ staging environment ทดสอบก่อน:
# ทดสอบด้วย staging (ไม่มี rate limit แต่ certificate ใช้จริงไม่ได้)
sudo certbot certonly \
--manual \
--preferred-challenges dns \
--staging \
-d "example.com" \
-d "*.example.com"
Error: "certbot renew" ไม่ทำงานสำหรับ Wildcard แบบ manual
การ renew แบบ manual ต้องมีคนอยู่หน้าจอเพื่อเพิ่ม TXT record ทุกครั้ง ซึ่ง automate ไม่ได้ ต้องเปลี่ยนไปใช้ DNS plugin:
# ดู renewal config ปัจจุบัน
cat /etc/letsencrypt/renewal/example.com.conf
# บรรทัดที่แก้ไข
authenticator = manual
# เปลี่ยนเป็น dns-cloudflare หรือ plugin ที่ตรงกับ DNS provider
Error: Nginx ไม่ serve wildcard subdomain ที่ยังไม่มี server block
ต้องตั้ง server_name *.example.com และให้ Nginx จัดการ subdomain ที่ไม่มี config แยกด้วย default server block:
server {
listen 443 ssl;
server_name ~^(?<subdomain>.+)\.example\.com$;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/$subdomain; # แต่ละ subdomain ใช้ root directory ตัวเอง
}
คำถามที่พบบ่อย
Wildcard SSL ครอบคลุม sub-subdomain เช่น a.b.example.com ด้วยไหม?
ไม่ครอบคลุม *.example.com ใช้ได้กับ www.example.com, api.example.com แต่ไม่ครอบ a.b.example.com ซึ่งเป็น sub-subdomain หากต้องการครอบคลุม ต้องขอ certificate สำหรับ *.b.example.com เพิ่มแยกอีกอัน
Let's Encrypt Wildcard SSL ใช้ได้นานเท่าไหร่?
90 วัน เหมือน certificate ทั่วไปของ Let's Encrypt Certbot จะ renew อัตโนมัติเมื่อเหลืออายุ 30 วัน ถ้าตั้ง DNS plugin ครบ การ renew จะเกิดขึ้นแบบ silent ไม่ต้องทำอะไรเพิ่ม
ใช้ Wildcard certificate เดียวกันบนหลาย VPS ได้ไหม?
ได้ certificate ที่ออกโดย Let's Encrypt คือไฟล์ PEM ธรรมดา copy ไปติดตั้งบน server อื่นได้เลย แต่ต้องดูแล renewal บน server ต้นทางและ sync ไฟล์ไปยัง server อื่นหลัง renew ทุกครั้งด้วย