ติดตั้ง SSL ฟรีบน VPS ด้วย Let's Encrypt และ Certbot
SSL ไม่ใช่แค่กุญแจล็อก มันส่งผลต่อ SEO, ความน่าเชื่อถือของเว็บ และ browser warning ที่จะขับไล่ผู้เยี่ยมชม บทความนี้อธิบายการติดตั้ง SSL ฟรีบน VPS ตั้งแต่ต้นจนจบ
Let's Encrypt คืออะไร
Let's Encrypt คือ Certificate Authority (CA) ที่ให้ SSL Certificate ฟรี ออกโดย Internet Security Research Group (ISRG) ซึ่งได้รับการสนับสนุนจาก Mozilla, Google, Cisco และอีกหลายองค์กร
Certificate มีอายุ 90 วัน แต่ Certbot จะต่ออายุอัตโนมัติ ไม่ต้องทำเองทุกครั้ง
ข้อกำหนดก่อนติดตั้ง
- โดเมนชี้มาที่ IP ของเซิร์ฟเวอร์ถูกต้องแล้ว (A Record พร้อม)
- Port 80 เปิดอยู่ (Let's Encrypt ใช้ HTTP challenge)
- มี web server ติดตั้งไว้แล้ว (Nginx หรือ Apache)
ติดตั้งบน Nginx (Ubuntu/Debian)
apt update
apt install certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.com
Certbot จะถาม email สำหรับแจ้งเตือนก่อน certificate หมดอายุ และถามว่าต้องการ redirect HTTP → HTTPS อัตโนมัติหรือไม่ แนะนำให้เลือก redirect
ติดตั้งบน Apache (Ubuntu/Debian)
apt install certbot python3-certbot-apache
certbot --apache -d example.com -d www.example.com
ทดสอบการต่ออายุอัตโนมัติ
certbot renew --dry-run
คำสั่งนี้จำลองการต่ออายุโดยไม่ได้ออก certificate จริง ใช้ตรวจสอบว่าระบบทำงานได้ถูกต้อง
Wildcard Certificate
ถ้าต้องการ SSL ครอบ subdomain ทั้งหมด เช่น *.example.com ต้องใช้ DNS challenge แทน HTTP challenge
certbot certonly --manual --preferred-challenges dns \
-d "*.example.com" -d example.com
ระบบจะให้เพิ่ม TXT record ใน DNS ก่อน แล้วจึงออก certificate ให้
ตรวจสอบ Certificate ที่ได้
# ดู certificate ทั้งหมดที่ Certbot จัดการ
certbot certificates
# ตรวจสอบวันหมดอายุด้วย openssl
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -dates
# ตรวจว่า auto-renew timer ทำงานอยู่
systemctl status certbot.timer
systemctl status certbot.timer ถ้าเห็น active = ทำงานปกติ ถ้าไม่ active ให้รัน systemctl enable certbot.timer --nowตั้งค่า HTTPS Redirect ใน Nginx
Certbot มักตั้ง redirect ให้อัตโนมัติ แต่ถ้าต้องการตั้งเองหรือแก้ไข:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
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;
# เพิ่ม HSTS บอก browser ให้ใช้ HTTPS เสมอ
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
}
แก้ปัญหาที่พบบ่อย
Error: "Connection refused on port 80" หรือ "Challenge failed"
Let's Encrypt ต้องเข้าถึง http://example.com/.well-known/acme-challenge/ ได้ในระหว่าง verify:
# ดูว่า web server กำลังรัน
systemctl status nginx # หรือ apache2
# ตรวจ firewall ว่าเปิด port 80
ufw status | grep "80\|ALLOW"
# ทดสอบ path จากภายนอก
curl -I http://example.com/.well-known/acme-challenge/test
Error: "Too many failed authorizations" หรือ "Too many certificates already issued"
Let's Encrypt จำกัด 5 certificate ต่อ domain ต่อชั่วโมง และ 50 ต่อสัปดาห์ ใช้ staging environment ทดสอบก่อนไม่ติด rate limit:
certbot --nginx -d example.com --staging
# ถ้า staging สำเร็จ ค่อยออก certificate จริง (ไม่ต้องใส่ --staging)
Certificate ได้ Grade B หรือ C ที่ SSL Labs
เพิ่มใน Nginx server block เพื่อปิด protocol เก่าและ cipher ที่อ่อนแอ:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ทดสอบผลลัพธ์ที่ ssllabs.com/ssltest/ ควรได้ Grade A หรือ A+
Certbot renew ล้มเหลว: "Port 80 is already in use"
เกิดเมื่อใช้ standalone mode และ web server กำลังรันอยู่ แก้โดยใช้ webroot mode แทน:
# แก้ /etc/letsencrypt/renewal/example.com.conf
authenticator = webroot
webroot_path = /var/www/html
certbot renew --quiet
Wildcard certificate ขอแล้ว TXT record ไม่ผ่าน
Certbot ต้องการให้เพิ่ม TXT record ใน DNS ก่อน แล้วรอ propagate สักครู่ก่อนกด Enter:
# ตรวจว่า TXT record propagate แล้ว
dig TXT _acme-challenge.example.com +short
# รอให้ตรงกับค่าที่ certbot แสดง ค่อยกด Enter ใน certbot
คำถามที่พบบ่อย
Let's Encrypt ฟรีจริงไหม มีค่าใช้จ่ายซ่อนไหม?
ฟรีทั้งหมด ไม่มีแผนชำระเงิน Let's Encrypt เป็น non-profit ที่ได้รับการสนับสนุนจาก Mozilla, Google, Cisco และ EFF ข้อจำกัดคือเป็น Domain Validated (DV) เท่านั้น ไม่มี OV หรือ EV certificate ที่แสดงชื่อบริษัทใน address bar
ต้อง renew เองทุก 90 วันไหม?
ไม่ต้อง Certbot ติดตั้ง systemd timer หรือ cron job อัตโนมัติระหว่างติดตั้ง จะ renew เมื่อ certificate เหลือน้อยกว่า 30 วัน ทดสอบว่าระบบ auto-renew ทำงานได้ด้วย certbot renew --dry-run (ไม่ออก certificate จริง)
Let's Encrypt รองรับ wildcard *.example.com ไหม?
รองรับตั้งแต่ปี 2018 แต่ต้องใช้ DNS challenge ไม่ใช่ HTTP challenge และต้องมี DNS plugin รองรับ provider เช่น certbot-dns-cloudflare สำหรับ Cloudflare Wildcard ครอบ subdomain ชั้นเดียว *.example.com ครอบ mail.example.com แต่ไม่ครอบ a.b.example.com
ถ้า certificate หมดอายุโดยไม่ได้ renew จะเกิดอะไร?
Browser แสดงหน้าเตือน "Your connection is not private" พร้อม error NET::ERR_CERT_DATE_INVALID ผู้เยี่ยมชมส่วนใหญ่จะออกทันที Let's Encrypt ส่งอีเมลเตือนล่วงหน้า 20 วันและ 10 วันก่อนหมดอายุไปยัง email ที่ลงทะเบียนไว้
ใช้ Let's Encrypt กับ wildcard domain บน Cloudflare ยังไง?
ติดตั้ง plugin และสร้าง API token ของ Cloudflare ที่มีสิทธิ์แก้ DNS zone แล้วรัน Certbot:
pip install certbot-dns-cloudflare
# สร้างไฟล์ ~/.secrets/cloudflare.ini ใส่ dns_cloudflare_api_token = YOUR_TOKEN
certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
-d "example.com" -d "*.example.com"
สรุป
Let's Encrypt ลบข้อแก้ตัวเรื่อง "SSL แพง" ออกไปทั้งหมด ไม่มีเหตุผลที่เว็บสมัยนี้จะไม่มี HTTPS ขั้นตอนทั้งหมดใช้เวลาไม่ถึง 10 นาทีและทำงานอัตโนมัติหลังจากนั้น ถ้าพบปัญหาระหว่างออก certificate ให้ตรวจ port 80, firewall และ DNS ก่อนเสมอ