Cài Caddy trên Dev Server (native, không Docker)
Dev server cài thủ công (api/web chạy bằng
yarn, không Docker). Hướng dẫn này cài Caddy native lên host để test custom domain giống production — auto-HTTPS Let's Encrypt thật + on-demand TLS.Production thì khác: Caddy chạy trong Docker (
docker-compose.prod.yml+caddy/Caddyfile) — xemdocker-deploy.md §2.4. Đừng lẫn 2 cái.
Điều kiện: dev server có IP public, port 80 + 443 mở ra internet (Caddy cần port 80 cho ACME http-01). api chạy ở 127.0.0.1:3010, web ở 127.0.0.1:3020.
1. Cài Caddy (Ubuntu/Debian, apt repo chính thức)
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 apt update
sudo apt install -y caddy
Gói này tự tạo systemd service caddy.service đọc /etc/caddy/Caddyfile, chạy dưới user caddy, data ở /var/lib/caddy/.local/share/caddy (cert store ở đây).
caddy version # xác nhận đã cài
systemctl status caddy # service có sẵn (đang chạy với Caddyfile mặc định)
2. Đặt Caddyfile
Copy caddy/Caddyfile.dev từ repo lên server, sửa dev.glamvoo.com thành dev platform domain thật của bạn (domain trỏ về IP dev server):
sudo cp /path/to/booking-system/caddy/Caddyfile.dev /etc/caddy/Caddyfile
sudo nano /etc/caddy/Caddyfile # đổi dev.glamvoo.com → domain của bạn
Caddyfile.dev dùng upstream 127.0.0.1:3010 (api) + 127.0.0.1:3020 (web) — khớp với api/web chạy yarn trên host.
3. Inject env (ACME_EMAIL) qua systemd override
sudo systemctl edit caddy
Thêm:
[Service]
Environment=ACME_EMAIL=dev@glamvoo.com
Lưu → reload:
sudo systemctl restart caddy
{$ACME_EMAIL}trong Caddyfile đọc từ env của process Caddy. systemd override là cách chuẩn để set env cho gói Caddy.
4. Mở firewall + dừng thứ chiếm port 80/443
sudo ufw allow 80,443/tcp # nếu dùng ufw
# Nếu trước đó có nginx/apache native chiếm 80/443 → dừng:
sudo systemctl disable --now nginx 2>/dev/null || true
sudo systemctl disable --now apache2 2>/dev/null || true
sudo lsof -i :443 # xác nhận chỉ còn caddy
Nếu dev đang dùng Cloudflare tunnel cho
app-dev.novagoo.com: tunnel không chiếm 80/443 trên host (nó là outbound), nên không xung đột. Caddy phục vụ dev platform domain + custom domain qua đường public IP trực tiếp, song song với tunnel.
5. Cấu hình api + web cho dev domain
Trong .env của api (dev):
PLATFORM_DOMAINS=dev.glamvoo.com # + domain test KHÁC custom domain
PUBLIC_WEB_URL=https://dev.glamvoo.com
# Chỉ cần nếu test APEX custom domain — IP public của dev server:
CUSTOM_DOMAIN_SERVER_IPS=<IP-dev-server>
# Đích CNAME mà custom domain trỏ tới (nếu test subdomain). Có thể trỏ
# thẳng A record về IP dev cũng được — xem bước 6.
CUSTOM_DOMAIN_CNAME_TARGET=dev.glamvoo.com
Trong env của web (dev):
NEXT_PUBLIC_PLATFORM_DOMAINS=dev.glamvoo.com
# Nếu chạy `yarn dev` (next dev): cho host custom-domain test qua HMR check
DEV_ORIGINS=salon-test.example.com
Restart api + web (yarn start:dev / yarn dev / yarn start) để nạp env mới.
NEXT_PUBLIC_PLATFORM_DOMAINSquyết địnhproxy.tscoi host nào là platform (không rewrite). Custom domain test KHÔNG nằm trong list này → mới được rewrite về/b/<slug>.
6. Test custom domain trên dev
- DNS: trỏ host test về IP dev server. Khuyến nghị subdomain (dễ nhất):
salon-test.example.com CNAME dev.glamvoo.com(hoặc A record → IP dev)._glamvoo-verify.salon-test.example.com TXT <token>(token hiện ở admin sau khi add).
- Admin: đăng nhập owner → Settings → Domain → thêm
salon-test.example.com→ copy DNS → Verify → statusACTIVE. - Mở
https://salon-test.example.com/→ Caddyaskhỏi api/internal/tls-allow→ 200 (vì ACTIVE) → cấp cert Let's Encrypt thật → trang salon hiện, URL sạch.
7. Verify + debug
sudo systemctl status caddy
sudo journalctl -u caddy -f # log realtime — tìm "certificate obtained"
curl -I https://dev.glamvoo.com # platform domain OK
curl "http://127.0.0.1:3010/api/internal/tls-allow?domain=salon-test.example.com" # 200 nếu ACTIVE
# Reload Caddyfile sau khi sửa (zero-downtime, không mất cert)
sudo systemctl reload caddy
Failure modes: xem troubleshooting.md §Custom domain. Hay gặp trên dev:
- Cert không cấp → domain chưa
ACTIVE(ask trả 404) hoặc port 80 bị chặn. - Mở custom domain ra
/error-404→NEXT_PUBLIC_PLATFORM_DOMAINSlỡ chứa host đó, hoặc cache proxy 60s chưa hết sau verify.
Liên quan
- Production (Docker):
docker-deploy.md §2.4 - Kiến trúc + setup per-tenant:
../architecture/custom-domain.md - Scaling:
../architecture/custom-domain.md §12