
Apache HTTP Server ยังคงเป็น Web Server ที่ได้รับความนิยมสูง โดยเฉพาะบน LAMP Stack ที่ใช้กันบน VPS การติดตั้ง SSL บน Apache ต้องเปิดใช้ mod_ssl และตั้งค่า VirtualHost สำหรับ HTTPS บทความนี้ครอบคลุมทั้ง SSL แบบซื้อและ Let's Encrypt ผ่าน Certbot Apache Plugin
สิ่งที่ต้องมีก่อน: VPS Ubuntu 20.04/22.04, ติดตั้ง Apache แล้ว (apache2), Domain ที่ DNS ชี้มายัง IP เซิร์ฟเวอร์แล้ว, Root หรือ Sudo access
ส่วนที่ 1 — สิ่งที่ต้องมีก่อน
ตรวจสอบว่า Apache กำลังทำงาน:
sudo systemctl status apache2
เปิด Port 80 และ 443 ใน UFW:
sudo ufw allow 80 sudo ufw allow 443 sudo ufw status
ทดสอบว่า Domain ชี้มาที่ IP เซิร์ฟเวอร์แล้ว:
dig example.com +short
ส่วนที่ 2 — เปิดใช้ mod_ssl บน Apache
Apache บน Ubuntu ต้องเปิดใช้ mod_ssl ก่อนจึงจะรับ HTTPS ได้:
# เปิด mod_ssl และ mod_rewrite (สำหรับ redirect) sudo a2enmod ssl sudo a2enmod rewrite # Restart Apache เพื่อให้ module มีผล sudo systemctl restart apache2
ตรวจสอบว่า mod_ssl เปิดใช้แล้ว:
apache2ctl -M | grep ssl
ถ้าเห็น ssl_module (shared) แสดงว่า mod_ssl พร้อมใช้งาน
ส่วนที่ 3 — ติดตั้ง SSL แบบซื้อ บน Apache
เมื่อได้รับไฟล์ Certificate จาก CA แล้ว ให้ทำตามขั้นตอนนี้:
3.1 วางไฟล์ Certificate
# สร้าง directory เก็บ SSL sudo mkdir -p /etc/apache2/ssl/example.com # วางไฟล์ certificate sudo cp your_domain.crt /etc/apache2/ssl/example.com/certificate.crt sudo cp your_private.key /etc/apache2/ssl/example.com/private.key # ถ้า CA ให้ intermediate certificate มาด้วย sudo cp intermediate.crt /etc/apache2/ssl/example.com/ca_bundle.crt # ตั้ง permission sudo chmod 600 /etc/apache2/ssl/example.com/private.key sudo chmod 644 /etc/apache2/ssl/example.com/certificate.crt
3.2 สร้าง VirtualHost สำหรับ HTTPS
sudo nano /etc/apache2/sites-available/example.com-ssl.conf
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/example.com/certificate.crt
SSLCertificateKeyFile /etc/apache2/ssl/example.com/private.key
# ถ้ามี intermediate certificate
SSLCertificateChainFile /etc/apache2/ssl/example.com/ca_bundle.crt
<Directory /var/www/example.com>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
</VirtualHost># เปิดใช้งาน site ใหม่
sudo a2ensite example.com-ssl.conf
sudo apache2ctl configtest
sudo systemctl reload apache2ส่วนที่ 4 — ติดตั้ง Let's Encrypt ด้วย Certbot Apache Plugin
Certbot สำหรับ Apache จะจัดการทุกอย่างให้อัตโนมัติ รวมถึงการแก้ไข VirtualHost:
# ติดตั้ง Certbot และ Apache plugin sudo apt update sudo apt install certbot python3-certbot-apache -y # ขอ Certificate สำหรับ Domain sudo certbot --apache -d example.com -d www.example.com
Certbot จะถาม:
- Email address สำหรับแจ้งเตือนเมื่อ Certificate ใกล้หมดอายุ
- ยอมรับ Terms of Service
- ต้องการ Redirect HTTP→HTTPS ทุก Request หรือไม่ (แนะนำเลือก Yes)
ข้อดีของ Certbot --apache: แก้ไข VirtualHost ให้อัตโนมัติ, เพิ่ม SSL directives ให้, และตั้ง Redirect ให้โดยไม่ต้องแก้ config เอง
ส่วนที่ 5 — ตั้งค่า VirtualHost + Redirect HTTP→HTTPS แบบ Manual
ถ้าต้องการตั้งค่า Redirect เองโดยไม่ผ่าน Certbot ให้แก้ VirtualHost Port 80:
sudo nano /etc/apache2/sites-available/example.com.conf
# VirtualHost Port 80: Redirect ทุก Request ไป HTTPS <VirtualHost *:80> ServerName example.com ServerAlias www.example.com # 301 Permanent Redirect Redirect permanent / https://example.com/ </VirtualHost> # หรือใช้ mod_rewrite แบบ Flexible กว่า <VirtualHost *:80> ServerName example.com ServerAlias www.example.com RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L] </VirtualHost>
⚠️ ระวัง: ถ้าใช้ Redirect permanent / จะต้องแน่ใจว่า VirtualHost HTTPS ทำงานก่อน มิฉะนั้นผู้เยี่ยมชมจะเจอ Error ทันที ทดสอบ HTTPS ให้ได้ก่อนเปิด Redirect เสมอ
ส่วนที่ 6 — ทดสอบ Configuration และ Reload
หลังแก้ไข config ทุกครั้ง ต้องทดสอบก่อน reload เสมอ:
# ตรวจสอบ Apache config syntax sudo apache2ctl configtest # ถ้า Syntax OK → reload Apache sudo systemctl reload apache2 # ตรวจสอบ HTTPS ด้วย curl curl -I https://example.com # ตรวจสอบ Certificate ด้วย openssl echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
ผล apache2ctl configtest ที่ถูกต้องจะแสดง Syntax OK ถ้ามี Error ให้อ่าน Error message และแก้ไขก่อน reload
ทดสอบ Auto-Renewal สำหรับ Let's Encrypt
# ทดสอบ renewal โดยไม่ต่ออายุจริง
sudo certbot renew --dry-runAuto-Renewal: Certbot ตั้ง systemd timer ให้อัตโนมัติ ตรวจสอบด้วย systemctl list-timers | grep certbot Certificate จะต่ออายุอัตโนมัติก่อนหมดอายุ 30 วัน
ขั้นตอนติดตั้ง Let's Encrypt ด้วย Certbot Apache Plugin (แบบละเอียด)
Let's Encrypt เป็น SSL ฟรีที่ออกใบรับรองแบบ DV (Domain Validation) อายุ 90 วัน และต่ออายุอัตโนมัติได้ Certbot Apache plugin เหมาะกับมือใหม่มากที่สุด เพราะแก้ไฟล์ VirtualHost ให้เองโดยที่เราแทบไม่ต้องแตะ config ด้วยตัวเอง ขั้นตอนตั้งแต่ต้นจนจบมีดังนี้
# 1) อัปเดต package list และติดตั้ง Certbot + Apache plugin sudo apt update sudo apt install certbot python3-certbot-apache -y # 2) ตรวจว่า Apache มี VirtualHost พอร์ต 80 ที่ ServerName ตรงกับ domain # Certbot อ่าน ServerName/ServerAlias เพื่อรู้ว่าจะออก cert ให้ domain ไหน sudo apache2ctl -S # 3) ขอใบรับรองและให้ Certbot แก้ VirtualHost ให้อัตโนมัติ sudo certbot --apache -d example.com -d www.example.com # 4) ถ้าต้องการขอ cert เฉยๆ โดยไม่ให้ Certbot แตะ config (จัดการ VirtualHost เอง) sudo certbot certonly --apache -d example.com -d www.example.com
เมื่อรัน certbot --apache ระบบจะถามอีเมลสำหรับแจ้งเตือนวันหมดอายุ ให้ยอมรับ Terms of Service และเลือกว่าจะ Redirect HTTP ไป HTTPS หรือไม่ (แนะนำเลือก Redirect) หลังจากนั้น Certbot จะสร้างไฟล์ example.com-le-ssl.conf ใน sites-available ให้โดยอัตโนมัติ และไฟล์ cert จะถูกเก็บไว้ที่ /etc/letsencrypt/live/example.com/
ข้อควรรู้ก่อนขอใบรับรองคือ Let's Encrypt จะตรวจสอบความเป็นเจ้าของ domain ผ่านวิธีที่เรียกว่า HTTP-01 challenge กล่าวคือเซิร์ฟเวอร์ของ Let's Encrypt จะส่งคำขอเข้ามาที่ domain ของเราทาง port 80 เพื่อยืนยันว่าเราควบคุมเว็บเซิร์ฟเวอร์นี้จริง ดังนั้นในตอนขอและตอนต่ออายุ port 80 ต้องเปิดและเข้าถึงได้จากภายนอกเสมอ หาก domain ยังไม่ได้ชี้มาที่ไอพีของเซิร์ฟเวอร์ หรือมี firewall ปิด port 80 อยู่ การออกใบรับรองจะล้มเหลวทันที จุดนี้เป็นสาเหตุที่มือใหม่มักติดบ่อยที่สุด แนะนำให้ตรวจ DNS ด้วยคำสั่ง dig และทดสอบเปิดหน้าเว็บผ่าน http ก่อนสั่งขอใบรับรองทุกครั้ง
กรณีเว็บไซต์ของคุณมีหลาย domain หรือหลาย subdomain บนเซิร์ฟเวอร์เดียวกัน สามารถใส่ -d ต่อท้ายได้หลายตัวในคำสั่งเดียว เช่น -d example.com -d www.example.com -d blog.example.com Certbot จะรวมทุก domain ไว้ในใบรับรองเดียว (เรียกว่า SAN certificate) ทำให้บริหารจัดการง่ายและต่ออายุพร้อมกันทั้งหมด อย่างไรก็ตามถ้าต้องการครอบคลุม subdomain แบบไม่จำกัด (เช่น ทุกอย่างที่ลงท้ายด้วย example.com) จะต้องใช้ Wildcard certificate ซึ่งต้องยืนยันผ่าน DNS-01 challenge แทน เป็นคนละวิธีกับ Apache plugin ทั่วไป
ตำแหน่งไฟล์ Let's Encrypt: fullchain.pem (cert + chain รวมกัน), privkey.pem (private key), cert.pem และ chain.pem — ทั้งหมดอยู่ใน /etc/letsencrypt/live/example.com/ โดย Certbot จะอ้างถึง fullchain.pem และ privkey.pem ใน VirtualHost ให้เอง
ตั้งค่า VirtualHost พอร์ต 443 ด้วยมือ (SSLCertificateFile / Key / Chain)
ถ้าใช้ SSL แบบซื้อ หรืออยากคุม config ของ Let's Encrypt เอง ให้สร้าง VirtualHost พอร์ต 443 และระบุไฟล์ certificate ทั้ง 3 ส่วนให้ครบ ได้แก่ certificate ของ domain, private key และ chain (intermediate) certificate
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com
SSLEngine on
# ไฟล์ certificate ของ domain (.crt หรือ cert.pem)
SSLCertificateFile /etc/apache2/ssl/example.com/certificate.crt
# private key ที่ใช้ตอนสร้าง CSR (.key หรือ privkey.pem)
SSLCertificateKeyFile /etc/apache2/ssl/example.com/private.key
# intermediate / chain certificate จาก CA (.ca-bundle หรือ chain.pem)
SSLCertificateChainFile /etc/apache2/ssl/example.com/ca_bundle.crt
# แนะนำ: เปิดเฉพาะ TLS 1.2 ขึ้นไป ปิดโปรโตคอลเก่าที่ไม่ปลอดภัย
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder on
<Directory /var/www/example.com>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
</VirtualHost>สำหรับ Apache เวอร์ชัน 2.4.8 ขึ้นไป สามารถรวม cert + chain ไว้ในไฟล์เดียวแล้วใช้ SSLCertificateFile อย่างเดียวก็ได้ (ไม่ต้องใช้ SSLCertificateChainFile) แต่การแยกไฟล์ตามตัวอย่างจะอ่านง่ายและจัดการชัดเจนกว่า ตารางด้านล่างสรุป directive สำคัญและไฟล์ที่ใช้คู่กัน
หัวใจสำคัญที่ทำให้มือใหม่พลาดบ่อยคือเรื่องของ chain certificate หรือ intermediate certificate ใบรับรองที่ CA ออกให้นั้นไม่ได้ถูกเซ็นโดย Root CA โดยตรง แต่ถูกเซ็นผ่านใบกลางอีกชั้นหนึ่ง หากเราไม่ติดตั้งใบกลางนี้ด้วย เบราว์เซอร์บนคอมพิวเตอร์อาจยังพอเชื่อมโยงไปหา Root ได้เอง แต่เบราว์เซอร์บนมือถือหลายรุ่นจะแสดงข้อความว่าใบรับรองไม่สมบูรณ์หรือไม่น่าเชื่อถือ ดังนั้นเมื่อ CA ส่งไฟล์มาให้ ควรติดตั้งทั้งใบของ domain และใบ intermediate ให้ครบเสมอ และทดสอบด้วยเครื่องมือตรวจสอบ SSL จากภายนอกเพื่อยืนยันว่า chain ต่อกันสมบูรณ์
ส่วนของ private key ถือเป็นไฟล์ที่ต้องเก็บเป็นความลับสูงสุด เพราะใครก็ตามที่ได้ไฟล์นี้ไปจะสามารถปลอมตัวเป็นเว็บไซต์ของเราได้ จึงต้องตั้งสิทธิ์การเข้าถึงเป็น chmod 600 ให้เฉพาะ root อ่านได้เท่านั้น ห้ามอัปโหลด private key ขึ้นที่สาธารณะ ห้ามส่งผ่านอีเมลแบบไม่เข้ารหัส และไม่ควรนำไปใช้ซ้ำข้ามเซิร์ฟเวอร์โดยไม่จำเป็น หากสงสัยว่า private key รั่วไหล ควรเพิกถอน (revoke) ใบรับรองเดิมและออกใบใหม่ทันที
| Directive | ไฟล์ที่ใช้ | คำอธิบาย |
|---|---|---|
SSLCertificateFile |
certificate.crt / fullchain.pem |
certificate ของ domain ที่ CA ออกให้ |
SSLCertificateKeyFile |
private.key / privkey.pem |
private key คู่กับ CSR ต้อง chmod 600 |
SSLCertificateChainFile |
ca_bundle.crt / chain.pem |
intermediate cert ของ CA (เลี่ยง chain error บนมือถือ) |
บังคับ HTTPS (Force Redirect) + เปิด HSTS บน Apache (.htaccess / VirtualHost)
หลังติดตั้ง SSL เรียบร้อยแล้ว ควรบังคับให้ทุก request ไปที่ HTTPS เสมอ และเปิด HSTS (HTTP Strict Transport Security) เพื่อบอก browser ให้จำว่า domain นี้ต้องเข้าผ่าน HTTPS เท่านั้น ทำได้ทั้งในระดับ VirtualHost และระดับ .htaccess
วิธีที่ 1 — Redirect ใน VirtualHost พอร์ต 80
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
# 301 ถาวร ไปยัง HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>วิธีที่ 2 — Force HTTPS ใน .htaccess (เหมาะกับ shared/DocumentRoot)
# วางไว้ที่ไฟล์ .htaccess ใน DocumentRoot (ต้องเปิด AllowOverride All)
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]วิธีที่ 3 — เปิด HSTS header
เพิ่ม HSTS header ใน VirtualHost พอร์ต 443 (ต้องเปิด mod_headers ด้วย sudo a2enmod headers ก่อน):
# ใน VirtualHost *:443 หลังจากตั้งค่า SSL แล้ว
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"⚠️ ระวัง HSTS: เมื่อ browser จำ HSTS แล้วจะ บังคับ HTTPS ตลอด max-age ที่ตั้งไว้ ถ้า SSL หมดอายุหรือพัง ผู้ใช้จะเข้าเว็บไม่ได้เลย — ควรเปิด HSTS หลังจากมั่นใจว่า HTTPS ทำงานเสถียรและต่ออายุอัตโนมัติได้แล้วเท่านั้น และอย่าเพิ่งใส่ preload จนกว่าจะพร้อมจริง
เปิด module ssl, ทดสอบ (apachectl configtest), ต่ออายุ + ปัญหาที่พบบ่อย
ก่อน reload ทุกครั้ง ให้ตรวจ syntax และยืนยันว่า module ที่จำเป็นเปิดอยู่ครบ ขั้นตอนตรวจสอบและคำสั่งที่ใช้บ่อยมีดังนี้
# เปิด module ที่จำเป็น (ssl, rewrite, headers) sudo a2enmod ssl rewrite headers # ตรวจ syntax ของ config ก่อน reload เสมอ sudo apachectl configtest # เทียบเท่า apache2ctl configtest # ถ้าได้ Syntax OK → reload ให้ config มีผล sudo systemctl reload apache2 # ต่ออายุ Let's Encrypt แบบทดสอบ (ไม่ต่อจริง) sudo certbot renew --dry-run # ตรวจวันหมดอายุของ cert ทั้งหมด sudo certbot certificates
ปัญหาที่พบบ่อยและวิธีแก้
- ERR_SSL_PROTOCOL_ERROR / เข้า HTTPS ไม่ได้: มักเกิดจาก
mod_sslยังไม่เปิด หรือ port 443 ยังไม่เปิดใน firewall — ตรวจด้วยapache2ctl -M | grep sslและsudo ufw allow 443 - เบราว์เซอร์เตือน "ไม่ปลอดภัย" ทั้งที่ติดตั้ง cert แล้ว: มักลืมใส่
SSLCertificateChainFileทำให้ chain ไม่สมบูรณ์ โดยเฉพาะบนมือถือ — เพิ่ม intermediate certificate ให้ครบ - configtest แจ้ง "key values mismatch": private key ไม่ตรงกับ certificate ตรวจด้วยการเทียบ modulus:
openssl x509 -noout -modulus -in cert.crt | openssl md5เทียบกับopenssl rsa -noout -modulus -in private.key | openssl md5— ค่าต้องตรงกัน - Redirect loop (ERR_TOO_MANY_REDIRECTS): เกิดเมื่อมี proxy/CDN ทำ SSL ปลายทางแล้วยัง force HTTPS ซ้ำ — ใช้
RewriteCond %{HTTP:X-Forwarded-Proto} !httpsแทน%{HTTPS} off - certbot renew ล้มเหลว: มัก port 80 ถูกปิดหรือ VirtualHost พอร์ต 80 หาย ทำให้ HTTP-01 challenge ไม่ผ่าน — เปิด port 80 ไว้เสมอเพื่อให้ต่ออายุได้
คำถามที่พบบ่อย (FAQ)
Let's Encrypt ฟรีจริงไหม ต่างจาก SSL แบบเสียเงินอย่างไร?
Let's Encrypt ฟรี 100% และเป็น DV (ยืนยันแค่ความเป็นเจ้าของ domain) อายุ 90 วันต่ออายุอัตโนมัติ เหมาะกับเว็บทั่วไป ส่วน SSL แบบเสียเงินจะมีออปชัน OV/EV ที่ตรวจตัวตนองค์กร มี warranty และซัพพอร์ตจาก CA ที่ AsiaGB มีทั้ง Let's Encrypt ฟรี และ SSL แบบ DV เริ่มต้น 1,000 บาท/ปี พร้อมทีมช่วยติดตั้ง
ติดตั้ง SSL บน Apache แล้วเว็บยังขึ้นว่า "ไม่ปลอดภัย" เพราะอะไร?
สาเหตุที่พบบ่อยคือยังมี mixed content (โหลดรูป/สคริปต์ผ่าน http://), ลืมใส่ SSLCertificateChainFile ทำให้ chain ไม่ครบ หรือยังไม่ได้บังคับ redirect ไป HTTPS ให้ตรวจ mixed content ใน Console ของเบราว์เซอร์ และเพิ่ม intermediate certificate ให้ครบ
ต้อง restart หรือ reload Apache หลังติดตั้ง SSL?
ใช้ sudo systemctl reload apache2 ก็เพียงพอสำหรับการโหลด config ใหม่โดยไม่ตัดการเชื่อมต่อที่กำลังทำงานอยู่ ส่วน restart จะใช้เมื่อเปิด/ปิด module (เช่น mod_ssl) ครั้งแรก และต้อง configtest ผ่านก่อนทุกครั้ง
Certbot ต่ออายุ Let's Encrypt อัตโนมัติจริงไหม ต้องตั้ง cron เองหรือไม่?
Certbot รุ่นใหม่ติดตั้ง systemd timer ให้อัตโนมัติแล้ว ไม่ต้องตั้ง cron เอง ตรวจได้ด้วย systemctl list-timers | grep certbot และทดสอบด้วย sudo certbot renew --dry-run ขอแค่ port 80 เปิดไว้ ใบรับรองจะต่ออายุก่อนหมด 30 วันโดยอัตโนมัติ
Checklist ติดตั้ง SSL บน Apache
- ติดตั้ง Apache, เปิด mod_ssl และ mod_rewrite
- ตรวจสอบ DNS A Record ชี้มาที่ IP เซิร์ฟเวอร์
- วางไฟล์ Certificate และ Key ด้วย permission 600/644
- สร้าง VirtualHost สำหรับ Port 443 พร้อม SSLCertificateFile directives
- เพิ่ม VirtualHost Port 80 สำหรับ Redirect → HTTPS
- รัน
apache2ctl configtestก่อน reload เสมอ - ตรวจสอบด้วย
curl -Iและopenssl s_client - สำหรับ Let's Encrypt: ทดสอบ renewal ด้วย
--dry-run
SSL Certificate สำหรับเว็บไซต์ของคุณ
AsiaGB มี SSL จาก RapidSSL, GeoTrust และ DigiCert เริ่มต้น 1,000 บาท/ปี พร้อมทีมซัพพอร์ตช่วยติดตั้ง
ดู SSL Certificate