Caddy: เว็บเซิร์ฟเวอร์ที่ทำ HTTPS ให้อัตโนมัติบน Linux

ติดตั้ง Caddy บน Linux Server ให้ขอและต่ออายุใบรับรอง HTTPS เอง เขียน Caddyfile ทำ Reverse Proxy เสิร์ฟเว็บ Static เก็บ Log และรู้ว่าเมื่อไรควรเลือกแทน Nginx

โดย ทีมงาน THAI DATA CLOUD อัปเดต อ่าน 9 นาที

แชร์FacebookXLINELinkedIn
Caddy — Caddy: เว็บเซิร์ฟเวอร์ที่ทำ HTTPS ให้อัตโนมัติบน Linux
Caddy: เว็บเซิร์ฟเวอร์ที่ทำ HTTPS ให้อัตโนมัติบน Linux

คำตอบสั้น ๆ: ติดตั้ง Caddy บน Linux Server ให้ขอและต่ออายุใบรับรอง HTTPS เอง เขียน Caddyfile ทำ Reverse Proxy เสิร์ฟเว็บ Static เก็บ Log และรู้ว่าเมื่อไรควรเลือกแทน Nginx

คู่มือนี้อธิบาย Caddy ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย

Caddy คือเว็บเซิร์ฟเวอร์และ Reverse Proxy ที่ขอใบรับรอง HTTPS จาก Let's Encrypt และต่ออายุให้เองโดยอัตโนมัติ เพียงใส่ชื่อโดเมนในไฟล์ตั้งค่า ไม่ต้องติดตั้ง Certbot หรือตั้ง Cron ต่ออายุ เหมาะกับนักพัฒนาและผู้ดูแลที่รันแอป Node.js, Python, Go หรือเว็บ Static ไม่กี่เว็บ และอยากได้ HTTPS ที่ถูกต้องโดยมีการตั้งค่าน้อยที่สุด

เมื่อทำตามคู่มือนี้ คุณจะมีเว็บเซิร์ฟเวอร์ที่รันเป็น systemd service มีไฟล์ตั้งค่าที่ทำ Reverse Proxy ไปแอปที่พอร์ต 3000 เสิร์ฟเว็บ Static พร้อมบีบอัดไฟล์ Redirect โดเมนหลักไป www เก็บ Log แยกตามเว็บ และรู้ว่างานแบบไหนควรใช้ Nginx ต่อ

สิ่งที่ต้องเตรียม

  • Linux Server ที่ใช้ Ubuntu 22.04/24.04, Debian 12 หรือ AlmaLinux/Rocky Linux 9 มี Public IP (ตัวอย่าง 203.0.113.10) และสิทธิ์ sudo
  • DNS ของ app.example.com, www.example.com และ example.com ชี้มาที่ IP ของเซิร์ฟเวอร์แล้ว (ดู ชี้โดเมนไปยังเซิร์ฟเวอร์)
  • พอร์ต 80 และ 443 ว่าง ไม่มี Nginx หรือ Apache ใช้อยู่ และเปิดจากอินเทอร์เน็ตได้ เพราะ Let's Encrypt ต้องเข้ามายืนยันโดเมน
  • แอปที่รันอยู่บน 127.0.0.1:3000 เช่น แอป Node.js ที่รันด้วย PM2
แผนภาพ Caddy รับคำขอ HTTPS ของสามโดเมน ส่งต่อไปแอปที่พอร์ต 3000 และเสิร์ฟไฟล์เว็บจากโฟลเดอร์
Caddy ขอใบรับรองจาก Let's Encrypt ให้ทุกโดเมนในไฟล์ แล้วแยกงานตามชื่อโดเมน

ขั้นตอนที่ 1: ติดตั้ง Caddy จาก Repository ทางการ

Ubuntu และ Debian มีแพ็กเกจนี้ใน Repository ของระบบเหมือนกัน แต่เป็นรุ่นเก่า แนะนำ Repository ทางการของโครงการ ซึ่งจะเริ่ม Service ชื่อ caddy ให้ทันทีหลังติดตั้ง

# Ubuntu / Debian
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy

# AlmaLinux / Rocky Linux 9 (แพ็กเกจจาก COPR ไม่เปิด Service ให้เอง)
sudo dnf install -y dnf-plugins-core
sudo dnf -y copr enable @caddy/caddy
sudo dnf install -y caddy
sudo systemctl enable --now caddy

ตรวจด้วย caddy version และ systemctl status caddy ตอนนี้เซิร์ฟเวอร์ยังเสิร์ฟหน้าต้อนรับที่พอร์ต 80 จากไฟล์ตั้งต้น

ขั้นตอนที่ 2: เปิดพอร์ตบน Firewall

# Ubuntu / Debian (UFW)
sudo ufw allow 80,443/tcp
sudo ufw allow 443/udp      # สำหรับ HTTP/3 (ไม่บังคับ)

# AlmaLinux / Rocky Linux 9 (firewalld)
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload

ถ้ามี Security Group หรือ Firewall ของแพลตฟอร์มคลาวด์ ให้เปิด TCP 80 และ 443 ที่นั่นด้วย พอร์ต 80 ต้องเปิดค้างไว้ตลอด เพราะเว็บเซิร์ฟเวอร์ใช้ทั้งยืนยันโดเมนตอนต่ออายุและ Redirect ผู้ใช้จาก HTTP ไป HTTPS

ขั้นตอนที่ 3: เขียน Caddyfile ทำ Reverse Proxy ไปแอป

แทนที่เนื้อหาใน /etc/caddy/Caddyfile ด้วยบล็อกด้านล่าง บล็อกแรกที่ไม่มีชื่อคือ Global Options ใส่อีเมลไว้รับแจ้งเตือนจาก Let's Encrypt ส่วนบล็อกที่ขึ้นต้นด้วยชื่อโดเมนคือเว็บหนึ่งเว็บ

{
    email [email protected]
}

app.example.com {
    reverse_proxy 127.0.0.1:3000
}

เพียงสามบรรทัดนี้ ระบบจะขอใบรับรองของ app.example.com ตั้ง Redirect จาก HTTP เป็น HTTPS ส่ง Header X-Forwarded-For และ X-Forwarded-Proto ไปให้แอป และรองรับ WebSocket ให้เองโดยไม่ต้องตั้งเพิ่ม

ขั้นตอนที่ 4: เพิ่มเว็บ Static และ Redirect โดเมนหลัก

เพิ่มต่อท้ายไฟล์เดิม root คือโฟลเดอร์ของเว็บ file_server สั่งให้เสิร์ฟไฟล์ และ encode บีบอัดไฟล์ข้อความด้วย zstd หรือ gzip ตามที่เบราว์เซอร์รองรับ ไฟล์ในโฟลเดอร์ต้องให้ผู้ใช้ caddy อ่านได้

www.example.com {
    root * /var/www/example
    file_server
    encode zstd gzip
}

example.com {
    redir https://www.example.com{uri} permanent
}
ตารางเปรียบเทียบ Caddy กับ Nginx เรื่อง HTTPS อัตโนมัติ ความยาวไฟล์ตั้งค่า และงานที่เหมาะ
Caddy ชนะเรื่องความง่าย ส่วน Nginx ชนะเรื่องความยืดหยุ่นและตัวอย่างที่หาได้

ขั้นตอนที่ 5: เก็บ Log ของแต่ละเว็บ

ค่าเริ่มต้นไม่เขียน Access Log ให้เพิ่มบล็อก log ในเว็บที่ต้องการ Log เป็นรูปแบบ JSON และระบบหมุนไฟล์ให้เอง (ค่าเริ่มต้น 100 MiB ต่อไฟล์ เก็บ 10 ไฟล์) จึงไม่ต้องตั้ง logrotate เพิ่ม

sudo mkdir -p /var/log/caddy
sudo chown caddy:caddy /var/log/caddy
app.example.com {
    reverse_proxy 127.0.0.1:3000
    log {
        output file /var/log/caddy/app.example.com.log
    }
}

ขั้นตอนที่ 6: ตรวจไฟล์และ reload แบบไม่สะดุด

จัดรูปแบบไฟล์ให้อ่านง่าย ตรวจไวยากรณ์ด้วย caddy adapt แล้วจึง reload ถ้าค่าใหม่มีปัญหา ระบบจะคงค่าเดิมไว้ เว็บไม่ล่ม

sudo caddy fmt --overwrite /etc/caddy/Caddyfile
caddy adapt --config /etc/caddy/Caddyfile > /dev/null && echo "syntax OK"
sudo systemctl reload caddy
journalctl -u caddy -n 30 --no-pager
หน้าจอ reload Caddy และ Log ที่แจ้งว่าออกใบรับรองให้ app.example.com สำเร็จ
ข้อความ certificate obtained successfully คือสัญญาณว่า HTTPS พร้อมใช้งาน

ตรวจสอบว่าออกใบรับรองสำเร็จ

รัน curl -I https://app.example.com ควรได้ HTTP/2 200 และ Header server: Caddy และ curl -I http://example.com ควรได้ 308 ไป HTTPS ก่อน แล้ว 301 ไป www ใบรับรองของ Service นี้เก็บอยู่ใน /var/lib/caddy/.local/share/caddy ควรรวมโฟลเดอร์นี้ในงานสำรองข้อมูล เพื่อไม่ต้องขอใหม่ทั้งหมดเมื่อย้ายเครื่อง

ปัญหาที่พบบ่อยเกี่ยวกับ Caddy

ขอใบรับรองไม่สำเร็จ ดู Log แล้วเห็น challenge failed ต้องทำอย่างไร?

ตรวจสามอย่างตามลำดับ: DNS ของโดเมนชี้มาที่เครื่องนี้จริงด้วย dig +short app.example.com, พอร์ต 80 และ 443 เปิดจากภายนอก และไม่มี AAAA Record ที่ชี้ไป IPv6 เก่า ถ้าใช้ Proxy ของ Cloudflare ให้ตั้งเป็น DNS only ชั่วคราวจนขอใบรับรองได้ แล้วจึงเปิดกลับพร้อมตั้ง SSL/TLS เป็น Full (strict) Caddy จะลองใหม่เองแบบเว้นระยะ

เซอร์วิสเริ่มไม่ได้และแจ้ง address already in use แก้อย่างไร?

มีโปรแกรมอื่นจองพอร์ต 80 หรือ 443 อยู่ ตรวจด้วย sudo ss -ltnp | grep -E ':(80|443) ' ถ้าเป็น Nginx หรือ Apache ที่ไม่ใช้แล้ว ให้ sudo systemctl disable --now nginx (หรือ apache2, httpd) ก่อนเริ่มบริการใหม่

เปิดเว็บแล้วได้ 502 Bad Gateway เกิดจากอะไร?

เว็บเซิร์ฟเวอร์ต่อแอปไม่ได้ ตรวจว่าแอปทำงานและฟังที่ 127.0.0.1:3000 จริงด้วย curl -I http://127.0.0.1:3000 ถ้าตั้งแอปให้ฟังที่ localhost แอปบางตัว เช่น Node.js รุ่นใหม่ อาจฟังเฉพาะ IPv6 ::1 ให้ระบุที่อยู่ให้ตรงกันทั้งสองฝั่ง

ควรย้ายจาก Nginx มาใช้ Caddy หรือไม่?

ถ้า Nginx ทำงานดีและมีการตั้งค่า Cache, Rate Limit หรือหลายเว็บซับซ้อนอยู่แล้ว ไม่จำเป็นต้องย้าย Caddy เหมาะกับเซิร์ฟเวอร์ใหม่ที่มีแอปไม่กี่ตัว ส่วนเว็บ PHP ที่ใช้แผงควบคุมหรือทีมคุ้นเคยกับ Nginx Server Block ใช้ Nginx ต่อจะดูแลง่ายกว่า

ถ้าต้องการเซิร์ฟเวอร์สำหรับรันแอปพร้อม HTTPS เลือกสเปกได้ที่ Cloud Linux Server หรือ ติดต่อทีมงาน THAI DATA CLOUD เพื่อช่วยวางระบบ ศึกษาคำสั่งทั้งหมดได้ที่ เอกสารทางการของโครงการ

อ่านเพิ่มเติมเกี่ยวกับ Caddy

แชร์FacebookXLINELinkedIn

มีคำถามเรื่องบริการ? ติดต่อทีมงาน