14.9 SSL certificate management
บทนี้อธิบายตำแหน่งของ SSL certificate, วิธีตรวจสอบ expiry, การต่ออายุ, และการ deploy cert ใหม่
ตำแหน่ง SSL certificate
| Service | Path บน host | โดเมน |
|---|---|---|
| vtrc-api host | /home/dev/vtrc-api/cert/ | vtrc.redcross.or.th, vtrcapi.redcross.or.th, vtrcbackoffice.redcross.or.th |
| cu-central-api host | /home/dev/cu-central-api/cert/ | centralizeapi.redcross.or.th |
| vtrc-rc-backoffice host | /home/dev/vtrc-rc-backoffice/cert/ | vtrcbackoffice.redcross.or.th (ใช้ร่วมกับ host อื่นบางครั้ง) |
ไฟล์ทั่วไปใน directory:
cert/
├── <domain>.crt ←── certificate
├── <domain>.key ←── private key
├── intermediate.crt ←── intermediate CA
└── fullchain.crt ←── cert + intermediate (ใช้กับ nginx)การตรวจสอบ expiry date
ตรวจจากภายนอก (ผ่าน network)
# ใช้ openssl ตรวจ cert ที่ server ส่ง
echo | openssl s_client -servername vtrc.redcross.or.th -connect vtrc.redcross.or.th:443 2>/dev/null | openssl x509 -noout -datesผลลัพธ์:
notBefore=Jan 1 00:00:00 2025 GMT
notAfter=Jan 1 23:59:59 2026 GMTตรวจจากไฟล์ cert
openssl x509 -in /home/dev/vtrc-api/cert/vtrc.redcross.or.th.crt -noout -dates
openssl x509 -in /home/dev/vtrc-api/cert/vtrc.redcross.or.th.crt -noout -subject -issuerสคริปต์ตรวจ cert ทุกโดเมน
cat > /usr/local/bin/check-certs.sh <<'EOF'
#!/bin/bash
DOMAINS=(
"vtrc.redcross.or.th"
"vtrcapi.redcross.or.th"
"vtrcbackoffice.redcross.or.th"
"uat-vtrc.redcross.or.th"
"uat-vtrcapi.redcross.or.th"
"uat-vtrcbackoffice.redcross.or.th"
"centralizeapi.redcross.or.th"
)
for domain in "${DOMAINS[@]}"; do
expiry=$(echo | openssl s_client -servername "$domain" -connect "$domain:443 2>/dev/null" | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [ -z "$expiry" ]; then
echo "$domain — ไม่สามารถตรวจได้"
else
expiry_epoch=$(date -d "$expiry" +%s)
now_epoch=$(date +%s)
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
if [ $days_left -lt 30 ]; then
echo "$domain — จะหมดอายุใน $days_left วัน (วันที่ $expiry)"
else
echo "$domain — ใช้งานได้ (เหลือ $days_left วัน)"
fi
fi
done
EOF
chmod +x /usr/local/bin/check-certs.shเพิ่มใน cron:
# ทุกวันที่ 1 ของเดือน
0 0 1 * * /usr/local/bin/check-certs.sh | mail -s "VTRC SSL cert check" ops@redcross.or.thการต่ออายุ certificate
VTRC ใช้ commercial certificate (ไม่ใช่ Let's Encrypt) — ต้องซื้อจากผู้ออกใบรับรอง
ขั้นตอนทั่วไป
- สร้าง CSR (Certificate Signing Request)
# สร้าง private key (ถ้ายังไม่มี)
openssl genrsa -out vtrc.redcross.or.th.key 2048
# สร้าง CSR
openssl req -new -key vtrc.redcross.or.th.key -out vtrc.redcross.or.th.csr -sha256
# กรอกข้อมูล
Country Name: TH
State or Province: Bangkok
Locality: Bangkok
Organization: Thai Red Cross Society
Organizational Unit: IT
Common Name: vtrc.redcross.or.th
Email: ops@redcross.or.thส่ง CSR ให้ผู้ออกใบรับรอง
รับ cert กลับมา — มักได้เป็นไฟล์
.crtและ intermediate CAสร้าง fullchain
cat vtrc.redcross.or.th.crt intermediate.crt > fullchain.crt- Deploy ตามขั้นตอนด้านล่าง
การ deploy cert ใหม่
สำรอง cert เดิม
cd /home/dev/vtrc-api/cert/
mkdir backup-$(date +%Y%m%d)
cp *.crt *.key backup-$(date +%Y%m%d)/คัดลอก cert ใหม่
# คัดลอกไฟล์ใหม่เข้า directory
cp /path/to/new/vtrc.redcross.or.th.crt /home/dev/vtrc-api/cert/
cp /path/to/new/vtrc.redcross.or.th.key /home/dev/vtrc-api/cert/
cp /path/to/new/fullchain.crt /home/dev/vtrc-api/cert/
# ตั้ง permission
chmod 644 /home/dev/vtrc-api/cert/*.crt
chmod 600 /home/dev/vtrc-api/cert/*.key
chown root:root /home/dev/vtrc-api/cert/*ทดสอบ config nginx
docker exec vtrc-web-server nginx -tถ้า error cannot load certificate แสดงว่า path ใน nginx config ไม่ตรง — ตรวจ ./nginx/default.conf
Reload nginx
docker exec vtrc-web-server nginx -s reloadตรวจสอบว่า cert ใหม่ใช้งาน
echo | openssl s_client -servername vtrc.redcross.or.th -connect vtrc.redcross.or.th:443 2>/dev/null | openssl x509 -noout -datesวันที่ notAfter ควรเป็นวันที่ใหม่
การตรวจสอบ nginx SSL config
nginx config อ้างถึง cert path:
server {
listen 443 ssl;
server_name vtrc.redcross.or.th;
ssl_certificate /etc/nginx/cert/fullchain.crt;
ssl_certificate_key /etc/nginx/cert/vtrc.redcross.or.th.key;
# ...
}path /etc/nginx/cert/ ใน container map กับ /home/dev/vtrc-api/cert/ บน host ผ่าน volume mount ใน docker-compose
ตรวจสอบ TLS version
# ทดสอบ TLS 1.0 (ควร fail)
openssl s_client -connect vtrc.redcross.or.th:443 -tls1
# ทดสอบ TLS 1.2 (ควรผ่าน)
openssl s_client -connect vtrc.redcross.or.th:443 -tls1_2
# ทดสอบ TLS 1.3
openssl s_client -connect vtrc.redcross.or.th:443 -tls1_3ตรวจสอบ cipher
nmap --script ssl-enum-ciphers -p 443 vtrc.redcross.or.thหรือใช้ tool ออนไลน์เช่น SSL Labs (แต่ต้องระวังการเปิดเผยข้อมูล)
ปัญหาที่พบบ่อย
1. nginx ไม่ reload
อาการ: nginx -t ผ่าน แต่ nginx -s reload แฮงค์
สาเหตุ: nginx กำลังประมวลผล connection ที่ยาวนาน (เช่น PDF generation)
แก้:
# รอสักครู่แล้วลองอีกครั้ง
sleep 30
docker exec vtrc-web-server nginx -s reload
# ถ้ายังไม่ได้ ต้อง restart nginx (จะกระทบผู้ใช้ชั่วคราว)
docker restart vtrc-web-server2. Browser ยังขึ้น warning หลัง deploy cert ใหม่
สาเหตุที่เป็นไปได้:
- Browser cache cert เดิม — ลองใน incognito
- Intermediate cert ไม่ครบ — ตรวจ fullchain
- Cert ไม่ตรง domain — ตรวจ SAN
# ดู SAN ที่รองรับ
openssl x509 -in /home/dev/vtrc-api/cert/vtrc.redcross.or.th.crt -noout -text | grep -A 1 "Subject Alternative Name"3. Cert chain ไม่ครบ
อาการ: browser บางตัว (เช่น Android เก่า) ไม่ยอมรับ cert
ตรวจ chain:
echo | openssl s_client -servername vtrc.redcross.or.th -connect vtrc.redcross.or.th:443 -showcerts 2>/dev/null | grep -c "BEGIN CERTIFICATE"ถ้าได้ 1 แสดงว่าส่งเฉพาะ leaf cert — ต้องใช้ fullchain.crt ที่รวม intermediate
4. Private key ไม่ตรงกับ cert
# เปรียบเทียบ modulus ของ key และ cert
openssl x509 -noout -modulus -in vtrc.redcross.or.th.crt | openssl md5
openssl rsa -noout -modulus -in vtrc.redcross.or.th.key | openssl md5ถ้า hash ไม่ตรง แสดงว่า key ผิด
การ deploy cert หลายโดเมนพร้อมกัน
ถ้าใช้ SAN cert (multi-domain) ต้อง deploy ทุก host ที่ใช้ cert นั้น:
# สคริปต์ deploy หลาย host
HOSTS=("vtrc-api-host" "cu-central-host" "backoffice-host")
for host in "${HOSTS[@]}"; do
echo "Deploying to $host..."
scp /path/to/new/cert/* dev@$host:/tmp/new-cert/
ssh dev@$host "sudo cp /tmp/new-cert/* /home/dev/vtrc-api/cert/ && sudo docker exec vtrc-web-server nginx -s reload"
doneแผนระยะยาว
- เปลี่ยนไปใช้ Let's Encrypt สำหรับ domain ที่เป็น public — ฟรี และ auto-renew
- ใช้ certbot ใน nginx container สำหรับ auto-renewal
- สร้าง alert ล่วงหน้า 30 วัน ก่อน cert หมดอายุ
- จัดทำ inventory ของ cert ทุกใบ พร้อม expiry date
Checklist การจัดการ cert
- [ ] รู้ expiry date ของ cert ทุกใบ
- [ ] มี alert ก่อนหมดอายุ 30 วัน
- [ ] มี backup ของ cert + key ในที่ปลอดภัย
- [ ] private key ไม่ถูก commit ใน git
- [ ] ทดสอบ cert ใน UAT ก่อน deploy production
- [ ] มี rollback plan (cert + key เดิมเก็บไว้)