Cloudflare Tunnel (cloudflared): Đưa Ứng Dụng Self-Hosted Ra Internet Mà Không Mở Bất Kỳ Cổng Nào

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Sau khi server của tôi bị tấn công brute-force SSH lúc nửa đêm, bảo mật không còn là thứ tính sau nữa. Vì vậy khi bắt đầu tự host Gitea, Vaultwarden và Uptime Kuma, câu hỏi không bao giờ là “làm sao để expose dịch vụ này?” mà là “làm sao expose mà không biến máy mình thành mục tiêu?” Port forwarding thông thường vẫn hoạt động — cho đến khi một rule cấu hình sai hoặc một lỗ hổng mới được phát hiện làm nó thất bại thảm hại.

Cloudflare Tunnel đã giải quyết vấn đề đó. Bài viết này sẽ so sánh trực tiếp cả hai cách tiếp cận, chỉ ra điểm hạn chế của Tunnel, và hướng dẫn cài đặt đầy đủ trên Linux — bao gồm systemd service, định tuyến DNS và chính sách Zero Trust Access.

So Sánh Hai Cách Tiếp Cận: Reverse Proxy vs. Cloudflare Tunnel

Truyền Thống: Reverse Proxy + Port Forwarding

Cách cổ điển: router chuyển tiếp cổng 80/443 đến Nginx hoặc Caddy cài cục bộ, rồi proxy đến ứng dụng của bạn. Bạn tự xử lý gia hạn Let’s Encrypt, rule fail2ban, chính sách firewall và cấu hình WAF. Cách này hoạt động được. Nhưng IP thật của bạn sẽ xuất hiện trên DNS công khai, cổng của bạn hiện lên Shodan trong vòng một giờ sau khi đưa vào hoạt động, và mỗi dịch vụ được expose đều trở thành bề mặt tấn công mà bạn phải tự chịu trách nhiệm.

ISP dành cho hộ gia đình còn thêm một rào cản nữa. Nhiều nhà cung cấp chặn hoàn toàn cổng inbound 80/443, buộc bạn phải dùng cổng không chuẩn hoặc thuê thêm một VPS riêng chỉ để terminate TLS.

Cloudflare Tunnel: Mô Hình Chỉ Kết Nối Ra Ngoài

Cloudflare Tunnel đảo ngược chiều kết nối. Bạn chạy cloudflared — một daemon trên server — để thiết lập kết nối outbound liên tục đến edge của Cloudflare. Khi người dùng truy cập domain của bạn, traffic đi qua Cloudflare và được định tuyến vào tunnel đó. Server của bạn không bao giờ lắng nghe trên cổng công khai.

Chặn toàn bộ traffic inbound ở tầng firewall. Ứng dụng của bạn vẫn hoạt động bình thường. IP thật của bạn không bao giờ lộ ra DNS công khai. Cloudflare xử lý TLS termination, chống DDoS, và tùy chọn thêm xác thực Zero Trust trước khi bất kỳ request nào chạm đến ứng dụng của bạn.

Ưu và Nhược Điểm

Reverse Proxy Truyền Thống

  • Ưu điểm: Toàn quyền kiểm soát, không phụ thuộc bên thứ ba, hỗ trợ mọi giao thức (TCP/UDP/raw sockets), độ trễ thấp hơn cho người dùng ở gần về mặt địa lý
  • Nhược điểm: IP thật bị lộ và có thể bị quét, bạn phải tự quản lý mọi tầng bảo mật, ISP dân dụng thường chặn cổng, một block proxy cấu hình sai có thể lộ nội bộ

Cloudflare Tunnel

  • Ưu điểm: Không cần mở cổng inbound, IP thật ẩn khỏi DNS công khai, miễn phí bảo vệ DDoS và CDN, Zero Trust Access thêm tầng xác thực trước khi traffic đến ứng dụng, gói miễn phí hỗ trợ đến 50 người dùng
  • Nhược điểm: Toàn bộ traffic đi qua hạ tầng Cloudflare (cần xem xét về quyền riêng tư), thêm một chút độ trễ cho người dùng ở xa PoP của Cloudflare, domain phải dùng DNS Cloudflare, tunnel TCP/UDP thô cần Cloudflare WARP ở gói miễn phí

Cấu Hình Được Khuyến Nghị

Ứng dụng web và dashboard trên home server hoặc VPS? Dùng Cloudflare Tunnel kết hợp chính sách Zero Trust Access. Không mở cổng inbound, Cloudflare làm WAF cho bạn, và cổng xác thực cứng trước khi bất kỳ request nào chạm đến code ứng dụng. Dù ứng dụng có CVE chưa vá, kẻ tấn công cũng không thể tiếp cận nếu chưa vượt qua tầng xác thực của Cloudflare.

Dịch vụ nhạy cảm với độ trễ, game server, giao thức TCP thô như SSH trực tiếp hoặc kết nối database — hãy dùng WireGuard hoặc reverse proxy truyền thống với rule firewall chặt chẽ. Phân chia thực tế: ứng dụng web đi qua Cloudflare Tunnel, quản trị server đi qua WireGuard trên cổng không chuẩn với IP allowlist.

Hướng Dẫn Triển Khai

Yêu Cầu Trước

  • Domain có DNS được quản lý bởi Cloudflare (tài khoản miễn phí là được)
  • Linux server với ứng dụng đang chạy cục bộ (hướng dẫn này dùng Debian/Ubuntu)
  • Tài khoản Cloudflare Zero Trust (gói miễn phí)

Bước 1: Cài Đặt cloudflared

curl -L --output cloudflared.deb \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb
cloudflared --version

Với các distro dùng RPM hoặc macOS, tải file binary phù hợp từ trang releases trên GitHub. Binary này được liên kết tĩnh — không có runtime dependency nào cần quản lý.

Bước 2: Xác Thực với Cloudflare

cloudflared tunnel login

Lệnh này mở cửa sổ trình duyệt. Đăng nhập và chọn domain bạn muốn dùng. Cloudflared sẽ ghi certificate vào ~/.cloudflared/cert.pem. Hãy bảo mật file này — nó cấp quyền tạo tunnel cho toàn bộ tài khoản của bạn.

Bước 3: Tạo Tunnel Có Tên

cloudflared tunnel create my-homelab

Kết quả đầu ra có chứa tunnel UUID. File credentials được lưu vào ~/.cloudflared/<UUID>.json. Ghi lại UUID đó — bạn sẽ cần nó ở bước tiếp theo.

Bước 4: Viết File Cấu Hình

Tạo file ~/.cloudflared/config.yaml:

tunnel: <YOUR-TUNNEL-UUID>
credentials-file: /home/youruser/.cloudflared/<UUID>.json

ingress:
  - hostname: gitea.yourdomain.com
    service: http://localhost:3000
  - hostname: uptime.yourdomain.com
    service: http://localhost:3001
  - service: http_status:404

Rule catch-all cuối cùng trả về 404 cho bất kỳ hostname nào không khớp với ingress entry. Bỏ qua nó và cloudflared sẽ báo lỗi với các request không khớp — có thể khiến daemon bị crash.

Bước 5: Định Tuyến DNS Đến Tunnel

cloudflared tunnel route dns my-homelab gitea.yourdomain.com
cloudflared tunnel route dns my-homelab uptime.yourdomain.com

Lệnh này tự động tạo bản ghi CNAME trỏ đến tunnel trong Cloudflare DNS. Không cần chỉnh sửa thủ công trên bảng điều khiển DNS.

Bước 6: Chạy Như systemd Service

sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
sudo systemctl status cloudflared

Service không khởi động được? Kiểm tra log:

sudo journalctl -u cloudflared -f

Chín trong mười trường hợp, nguyên nhân là đường dẫn sai trong credentials-file. Xác minh rằng UUID trong config khớp với tên file thực tế trên đĩa.

Bước 7: Thêm Xác Thực Zero Trust Access

Hầu hết các hướng dẫn bỏ qua bước này. Đó là sai lầm. Zero Trust Access chính là thứ biến cloudflared từ một thủ thuật định tuyến thông minh thành ranh giới bảo mật thực sự. Trong bảng điều khiển Cloudflare Zero Trust:

  1. Vào Access → Applications → Add an application
  2. Chọn Self-hosted
  3. Nhập hostname của bạn, ví dụ: gitea.yourdomain.com
  4. Trong Policies, thêm rule — cho phép email khớp với @yourdomain.com, hoặc liệt kê các địa chỉ cụ thể

Sau khi kích hoạt, Cloudflare sẽ chặn mọi người dùng bằng màn hình đăng nhập trước khi chuyển tiếp bất cứ thứ gì đến ứng dụng. Dùng cá nhân thì email OTP không cần thiết lập OAuth — Cloudflare gửi mã một lần đến địa chỉ được phép. Không cần mật khẩu. Không cần duy trì dịch vụ xác thực.

Xác Minh Cài Đặt

# Liệt kê các tunnel đang hoạt động và trạng thái
cloudflared tunnel list

# Xác nhận không có gì đang lắng nghe trên cổng công khai 80/443
ss -tlnp | grep ':80\|:443'
# Kết quả mong đợi: không có output

# Kiểm tra ứng dụng qua tunnel
curl -I https://gitea.yourdomain.com

Tăng Cường Bảo Mật Sau Khi Cài Đặt

Giờ hãy đóng chặt perimeter. Cloudflared chỉ cần kết nối outbound, nên chặn toàn bộ inbound không làm thay đổi gì — ngoài việc loại bỏ hoàn toàn bề mặt tấn công cho các công cụ quét cổng:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh  # xóa dòng này khi bạn đã có WireGuard hoặc WARP
sudo ufw enable

Định kỳ xoay vòng credentials của tunnel:

cloudflared tunnel rotate-secret my-homelab

Theo dõi tình trạng tunnel trong bảng điều khiển tại Zero Trust → Networks → Tunnels. Bạn sẽ thấy uptime của connector, kết nối đang hoạt động và lưu lượng traffic theo từng tunnel.

Một lưu ý về Docker đáng nhắc sớm: nếu bạn chạy cloudflared trong container, hãy mount thư mục config dưới dạng volume và chỉ định đường dẫn tường minh với --config /etc/cloudflared/config.yaml. Nếu thiếu flag đó, quá trình tìm đường dẫn mặc định của binary sẽ thất bại trong im lặng bên trong container — nó khởi động với config trống mà không có thông báo lỗi nào. Đó là thứ cực kỳ khó chịu để debug lúc 2 giờ sáng.

Hạn Chế Của Tunnel

HTTP và HTTPS hoạt động trơn tru. TCP thô thì lại khác. Phiên SSH trực tiếp, kết nối database, giao thức tùy chỉnh — những thứ này cần Cloudflare WARP-to-Tunnel (có trên gói Zero Trust miễn phí, nhưng cần cấu hình thêm) hoặc một lớp VPN riêng. Cách tiếp cận qua WARP có nghĩa là mỗi client cần cài ứng dụng WARP. Ổn với cài đặt cá nhân, nhưng sẽ nhanh chóng thêm rào cản khi bạn chia sẻ quyền truy cập với người khác.

Cấu hình của tôi sau sự cố brute-force lúc nửa đêm đó: ứng dụng web qua Cloudflare Tunnel với Zero Trust Access, quản trị server qua WireGuard trên cổng số cao với IP allowlist. Bot brute-force hoạt động tự động và không bao giờ dừng quét. Biện pháp đối phó duy nhất thực sự hiệu quả là không để chúng có gì để quét.

Share: