การ self-host service ต่างๆ ที่บ้านแล้วต้องการให้เข้าถึงจาก internet เป็นเรื่องที่หลายคนทำ แต่การ port forward เปิด risk หลายอย่าง ตั้งแต่การ expose IP จริงของบ้าน ไปจนถึงต้องจัดการ SSL certificate เอง Cloudflare Tunnel แก้ปัญหาเหล่านี้ได้โดยไม่ต้องเปิด port เลย
บทความนี้จะอธิบายว่า Cloudflare Tunnel ทำงานยังไง setup ยังไง และใช้ร่วมกับ Docker และ Cloudflare Access ได้ยังไง
Cloudflare Tunnel คืออะไร
Cloudflare Tunnel (เดิมชื่อ Argo Tunnel) เป็น service ที่สร้าง outbound connection จาก server ที่บ้านไปยัง Cloudflare network แทนที่จะรอ inbound connection ผ่าน port ที่เปิดไว้
การทำงานคร่าวๆ คือ cloudflared daemon ที่รันบน server จะสร้าง tunnel ไปหา Cloudflare edge เมื่อมี request เข้ามายัง domain Cloudflare จะ forward request นั้นผ่าน tunnel มายัง server โดยที่ server ไม่ต้อง open port ใดเลย
ทำไมไม่ Port Forward
หลายคนคุ้นเคยกับ port forwarding บน router แต่มีข้อเสียชัดเจน:
- IP บ้าน expose — ใครก็รู้ IP จริงของบ้าน
- ISP block port 80/443 — ISP บางรายไม่อนุญาต
- Dynamic IP — ต้องจัดการ DDNS
- SSL management — ต้องจัดการ certificate เอง
- Attack surface — เปิด port ตรงๆ สู่ bot และ scanner
Cloudflare Tunnel แก้ทุกข้อข้างต้น และยังได้ DDoS protection, WAF และ CDN ฟรีตามมาด้วย
ติดตั้ง cloudflared
Linux (Ubuntu/Debian)
# เพิ่ม Cloudflare repo
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | \
sudo tee /usr/share/keyrings/cloudflare-main.gpg > /dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] \
https://pkg.cloudflare.com/cloudflared any main' | \
sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt update && sudo apt install cloudflared
# ยืนยันติดตั้งสำเร็จ
cloudflared version
Docker
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel --no-autoupdate run
environment:
- TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
networks:
- proxy
networks:
proxy:
external: true
สร้างและ Setup Tunnel
วิธีที่ 1: ผ่าน Cloudflare Dashboard (แนะนำ)
# 1. ไปที่ Cloudflare Dashboard > Zero Trust > Networks > Tunnels
# 2. คลิก "Create a tunnel"
# 3. เลือก "Cloudflared" และตั้งชื่อ tunnel
# 4. Copy token ที่ได้ไปใส่ใน server
# Login และ setup tunnel
cloudflared tunnel login
# สร้าง tunnel
cloudflared tunnel create my-homelab
# ดู tunnel ที่มี
cloudflared tunnel list
วิธีที่ 2: ผ่าน CLI
# หลัง login จะได้ credentials file ที่ ~/.cloudflared/
# สร้าง config file
mkdir -p ~/.cloudflared
cat > ~/.cloudflared/config.yml << 'EOF'
tunnel: your-tunnel-id-here
credentials-file: /root/.cloudflared/your-tunnel-id.json
ingress:
- hostname: app.yourdomain.com
service: http://localhost:8080
- hostname: nextcloud.yourdomain.com
service: http://localhost:8081
- service: http_status:404
EOF
การ Route Domain ไปยัง Service
# เพิ่ม DNS record ผ่าน CLI
cloudflared tunnel route dns my-homelab app.yourdomain.com
# หรือผ่าน config file (แนะนำกว่า)
# ใน ~/.cloudflared/config.yml
ingress:
- hostname: app.yourdomain.com
service: http://localhost:3000
originRequest:
noTLSVerify: false
connectTimeout: 30s
- hostname: nextcloud.yourdomain.com
service: http://nextcloud:80
originRequest:
httpHostHeader: nextcloud.yourdomain.com
- hostname: grafana.yourdomain.com
service: http://grafana:3000
# Default rule - ต้องมีเสมอ
- service: http_status:404
# รัน tunnel เป็น service
cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
# ดู log
sudo journalctl -u cloudflared -f
Docker Integration
การใช้ Cloudflare Tunnel ร่วมกับ Docker Compose ให้ทำ tunnel อยู่ใน network เดียวกับ service
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel --no-autoupdate run
environment:
- TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
networks:
- proxy
nginx-proxy-manager:
image: jc21/nginx-proxy-manager:latest
container_name: npm
restart: unless-stopped
volumes:
- npm_data:/data
- npm_letsencrypt:/etc/letsencrypt
networks:
- proxy
nextcloud:
image: nextcloud:latest
container_name: nextcloud
restart: unless-stopped
networks:
- proxy
networks:
proxy:
driver: bridge
volumes:
npm_data:
npm_letsencrypt:
ใน Cloudflare Dashboard ตั้ง service ของ tunnel ให้ชี้ไป http://nginx-proxy-manager:80 แล้วให้ NPM จัดการ routing ต่อ
Cloudflare Access: Authentication Layer
Cloudflare Access เพิ่ม authentication ก่อนเข้าถึง service โดยไม่ต้องแก้ application เลย เหมาะสำหรับ internal tools ที่ไม่ควรเปิดสาธารณะ
# ตั้งค่าผ่าน Cloudflare Dashboard
# Zero Trust > Access > Applications > Add an application
# เลือก "Self-hosted"
# - Application name: Grafana
# - Application domain: grafana.yourdomain.com
# - Session duration: 24 hours
# เพิ่ม Policy:
# - Policy name: Allow team
# - Action: Allow
# - Include: Email ends in @yourcompany.com
# หรือ
# - Include: Emails in list > upload CSV ของ email ที่อนุญาต
หลังตั้งค่า ทุกคนที่พยายามเข้า grafana.yourdomain.com จะต้อง authenticate ผ่าน Cloudflare Access ก่อน ซึ่งรองรับ Google OAuth, GitHub, Microsoft, Magic Link email และอื่นๆ
Access Policy ตัวอย่าง
# Policy แบบต่างๆ
# 1. อนุญาตเฉพาะ email ที่กำหนด
Rules:
Allow if: Emails > user@gmail.com, admin@gmail.com
# 2. อนุญาตตาม IP (เช่น อนุญาตจาก office IP)
Rules:
Allow if: IP Ranges > 203.x.x.x/32
# 3. ต้องผ่านทั้ง email และ IP
Rules:
Allow if: Emails > admin@gmail.com
Require: IP Ranges > 203.x.x.x/32
# 4. Bypass สำหรับ service account (API calls)
Rules:
Bypass if: Service Auth > service-token
Performance Tips
Cloudflare Tunnel รัน connection ไปหา Cloudflare edge ที่ใกล้ที่สุดอัตโนมัติ แต่ยังมี optimization เพิ่มเติม
# เปิด HTTP/2 ใน config
ingress:
- hostname: app.yourdomain.com
service: http://localhost:3000
originRequest:
http2Origin: true
keepAliveTimeout: 90s
keepAliveConnections: 10
# เปิด Compression ใน Cloudflare Dashboard
# Speed > Optimization > Content Optimization
# เปิด: Brotli, Auto Minify
# เปิด Caching
# Caching > Cache Rules > Add rule
# ตัวอย่าง: cache static files 30 วัน
# If: File extension matches css, js, png, jpg, woff2
# Cache Level: Cache Everything
# Edge Cache TTL: 1 month
Limitations ที่ต้องรู้
Cloudflare Tunnel ดีมากแต่มีข้อจำกัด:
- 100MB request limit — request body ต้องไม่เกิน 100MB สำหรับ free plan ปัญหากับ Nextcloud upload ไฟล์ใหญ่
- ไม่รองรับ UDP — ใช้กับ game server หรือ VoIP ที่ใช้ UDP ไม่ได้
- Latency เพิ่ม — traffic ต้องผ่าน Cloudflare เพิ่ม latency นิดหน่อยเทียบกับ direct connection
- Terms of Service — ห้ามใช้ฟรี plan สำหรับ video streaming large-scale
แก้ปัญหา 100MB limit สำหรับ Nextcloud
# ใน Cloudflare Dashboard
# Rules > Transform Rules > Request Header Modification
# หรือใช้ enterprise plan ที่เพิ่ม limit
#
# วิธีแก้อีกทาง: ใช้ Nextcloud WebDAV client sync แทน web upload
# หรือ mount storage ผ่าน network โดยตรงใน LAN
สำหรับ service ที่ต้องการ access แบบ private โดยไม่ผ่าน internet ดูที่ Tailscale VPN Zero Config แทน ทั้งสองใช้ร่วมกันได้ โดยใช้ Cloudflare Tunnel สำหรับ public-facing service และ Tailscale สำหรับ internal access
ถ้าต้องการ setup service ที่จะ expose ผ่าน Cloudflare Tunnel ดูที่ Docker Compose สำหรับ Home Lab ก่อน และทำ Server Hardening เพิ่มความปลอดภัย
คำถามที่พบบ่อย (FAQ)
Cloudflare Tunnel ฟรีไหม?
ฟรีสำหรับ personal use และ self-hosting รวมถึง Cloudflare Access สำหรับ user ไม่เกิน 50 คน ฟีเจอร์หลักทั้งหมดใช้ได้ในแพลนฟรี ยกเว้น advanced WAF rules, log retention และ enterprise support
domain ต้องอยู่ที่ Cloudflare ไหม?
ต้องให้ domain ใช้ Cloudflare nameserver แต่ไม่จำเป็นต้องซื้อ domain ที่ Cloudflare ใช้ domain จากที่ไหนก็ได้แล้วเปลี่ยน nameserver มาที่ Cloudflare เป็นบริการฟรี
ถ้า server ปิดหรือ tunnel down จะเกิดอะไร?
คนที่เข้า domain จะเห็น Cloudflare error page (522 Connection timed out หรือ 1016 Origin DNS error) tunnel จะพยายาม reconnect อัตโนมัติ และถ้า cloudflared เป็น systemd service จะ restart อัตโนมัติเมื่อ crash
Cloudflare เห็น traffic ที่เข้ารหัสไหม?
Cloudflare ทำหน้าที่เป็น reverse proxy จึงเห็น traffic ที่ unencrypted ระหว่าง Cloudflare edge กับ server (ถ้าใช้ HTTP) แต่ connection จาก browser ถึง Cloudflare เข้ารหัสด้วย HTTPS ถ้าต้องการ end-to-end encryption ตั้งค่า SSL mode เป็น "Full (Strict)" และใช้ certificate บน server ด้วย
ใช้กับ Raspberry Pi ได้ไหม?
ได้ cloudflared รองรับ ARM architecture ติดตั้งได้บน Raspberry Pi ทุก model ที่รัน Linux
ต่างจาก ngrok ยังไง?
ngrok เป็น development tool สำหรับ expose local port ชั่วคราว URL จะเปลี่ยนทุกครั้งที่ restart (ยกเว้น paid plan) Cloudflare Tunnel ออกแบบมาสำหรับ production ใช้ domain ของตัวเองได้ permanent และฟรีกว่ามาก
