ติดตั้ง Traefik Reverse Proxy บน VPS Docker
Traefik คือ modern reverse proxy ที่ออกแบบมาสำหรับ containerized environment โดยเฉพาะ ข้อดีคือตรวจ Docker labels อัตโนมัติ รับ SSL จาก Let's Encrypt โดยไม่ต้องตั้ง Certbot แยก และ reload config โดยไม่ต้อง restart service เหมาะมากสำหรับ VPS ที่รัน หลาย service พร้อมกัน
เตรียม Docker Network
# สร้าง network กลางสำหรับ Traefik
docker network create traefik-public
# ตรวจว่ามี Docker แล้ว
docker --version
docker compose version
โครงสร้าง Directory
mkdir -p ~/traefik/config ~/traefik/certs
cd ~/traefik
# สร้าง acme.json สำหรับเก็บ SSL cert
touch certs/acme.json
chmod 600 certs/acme.json
สร้าง traefik.yml (Static Config)
cat > config/traefik.yml << 'EOF'
api:
dashboard: true
insecure: false
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: /certs/acme.json
tlsChallenge: {}
providers:
docker:
exposedByDefault: false
network: traefik-public
file:
directory: /config/dynamic
watch: true
EOF
สร้าง docker-compose.yml ของ Traefik
cat > docker-compose.yml << 'EOF'
version: "3.8"
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config/traefik.yml:/traefik.yml:ro
- ./config/dynamic:/config/dynamic:ro
- ./certs/acme.json:/certs/acme.json
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(\`traefik.yourdomain.com\`)"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$hash"
networks:
traefik-public:
external: true
EOF
docker compose up -d
เพิ่ม Service ให้ Traefik Route
# ตัวอย่าง docker-compose.yml ของ application
services:
myapp:
image: nginx:alpine
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(\`app.yourdomain.com\`)"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
- "traefik.http.services.myapp.loadbalancer.server.port=80"
networks:
traefik-public:
external: true
ตั้ง Middleware เพิ่มเติม
# Dynamic config: config/dynamic/middlewares.yml
http:
middlewares:
security-headers:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
contentTypeNosniff: true
browserXssFilter: true
referrerPolicy: "strict-origin-when-cross-origin"
rate-limit:
rateLimit:
average: 100
burst: 50
ตรวจสอบว่า Traefik ทำงานถูกต้อง
# ดู container status
docker compose ps
# ดู logs
docker compose logs traefik -f
# ตรวจ port 80/443 เปิดหรือยัง
ss -tlnp | grep -E '80|443'
# ทดสอบ HTTP redirect
curl -I http://yourdomain.com
https://traefik.yourdomain.com เพื่อดู routers, services และ middlewares ทั้งหมดที่ active อยู่แบบ real-time
แก้ปัญหาที่พบบ่อย
Error: "acme.json has wrong permissions"
acme.json ต้องมี permission 600 เท่านั้น ไม่งั้น Traefik จะไม่ยอม start:
chmod 600 ~/traefik/certs/acme.json
docker compose restart traefik
SSL Certificate ไม่ออก (stuck ที่ ACME challenge)
Port 80 ต้องเปิดสาธารณะสำหรับ HTTP challenge ตรวจ firewall:
# ตรวจ UFW
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# ดู Traefik log หา error ACME
docker logs traefik 2>&1 | grep -i "acme\|cert\|error"
Container ใหม่ไม่ถูก Route
ลืมใส่ label traefik.enable=true หรือ network ไม่ตรง ตรวจ:
# ดู labels ของ container
docker inspect myapp | grep -A 20 Labels
# ตรวจว่า container อยู่ใน traefik-public network
docker network inspect traefik-public
Dashboard เข้าไม่ได้ (401 Unauthorized)
สร้าง basic auth hash ให้ถูกต้อง:
# สร้าง hash สำหรับ user admin password=mypassword
echo $(htpasswd -nb admin mypassword) | sed -e s/\\$/\\$\\$/g
# นำ output ใส่ใน basicauth.users label
คำถามที่พบบ่อย
Traefik กับ Nginx Proxy Manager ต่างกันอย่างไร?
Nginx Proxy Manager มี Web UI ใช้ง่ายสำหรับมือใหม่ แต่ Traefik ทำงานร่วมกับ Docker labels ได้อัตโนมัติ เหมาะกับ DevOps ที่ manage infrastructure as code ไม่ต้องคลิก UI ทุกครั้งที่เพิ่ม service
Traefik รองรับ TCP (non-HTTP) ได้ไหม?
ได้ Traefik รองรับ TCP และ UDP routing ผ่าน EntryPoint ที่กำหนดเอง เช่น route MySQL port 3306 หรือ game server UDP port ได้ โดยไม่ต้องใช้ Nginx แยก
ใช้ Traefik กับ Cloudflare ได้ไหม?
ได้ดีมาก ใช้ Cloudflare DNS challenge แทน HTTP challenge ทำให้รับ wildcard SSL ได้ และ Cloudflare ทำ DDoS protection ก่อน traffic จะถึง Traefik สามารถตั้ง trustedIPs เพื่อให้ Traefik เห็น real IP ของ visitor ด้วย