Le Duy Khuong

Chuỗi: vaultwarden-secret-management · Phần 4

Năng suất & công cụ dev

Cloudflare Tunnel và Zero Trust Access — Truy cập bảo mật không cần mở port

Expose vault self-hosted an toàn với Cloudflare Tunnel. Không mở port, SSL miễn phí, xác thực Zero Trust.

2026-03-2010 phút đọcVI

Phần 4 của 580% hoàn thành

Cloudflare Tunnel và Zero Trust Access cho Vaultwarden

Mở đầu — Bài toán expose dịch vụ nội bộ ra internet

Ở bài trước, chúng ta đã cài đặt Vaultwarden với Docker và bind trên 127.0.0.1 — chỉ truy cập được từ máy chủ local. Nhưng password manager cần được truy cập từ mọi nơi: điện thoại, laptop cá nhân, máy tính văn phòng. Vậy làm sao để expose dịch vụ ra internet một cách an toàn?

Cách truyền thống — Nhiều bước, nhiều rủi ro

Phương pháp cổ điển yêu cầu một chuỗi cấu hình phức tạp:

  1. Static IP hoặc Dynamic DNS: Cần IP tĩnh từ ISP (tốn phí) hoặc dịch vụ DDNS (duckdns, no-ip) để domain luôn trỏ đúng IP thay đổi.
  2. Port forwarding trên router: Mở port 443 trên router, chuyển tiếp đến máy chủ nội bộ. Mỗi port mở là một cánh cửa vào mạng nội bộ.
  3. SSL/TLS certificate: Cài đặt Let's Encrypt, cấu hình auto-renewal, xử lý certificate chain.
  4. Reverse proxy: Nginx hoặc Caddy để terminate SSL, proxy request đến Vaultwarden.
  5. Firewall rules: Cấu hình iptables/UFW để chỉ cho phép port 443, chặn phần còn lại.

Mỗi bước là một điểm có thể sai sót. Port forwarding mở bề mặt tấn công trực tiếp vào mạng nhà. SSL certificate hết hạn lúc nửa đêm. Dynamic DNS không cập nhật kịp khi ISP đổi IP. Và bạn phải tự xử lý DDoS protection.

Cách hiện đại — Cloudflare Tunnel

Cloudflare Tunnel đảo ngược mô hình kết nối: thay vì mở port chờ connection từ bên ngoài vào (inbound), máy chủ chủ động tạo connection đi ra (outbound) đến Cloudflare edge network. Mọi traffic từ internet đi qua Cloudflare, được lọc và xác thực, rồi mới đến máy chủ của bạn qua đường hầm đã thiết lập.

Kết quả:

  • Không cần mở port trên firewall hay router.
  • Không cần static IP — tunnel hoạt động qua bất kỳ kết nối internet nào.
  • SSL/TLS miễn phí — Cloudflare edge xử lý certificate, không cần Let's Encrypt.
  • DDoS protection tích hợp — Cloudflare lọc traffic độc hại trước khi đến máy chủ bạn.
  • Zero Trust authentication — thêm lớp xác thực trước khi user nhìn thấy Vaultwarden.

Tại sao chọn Cloudflare Tunnel

Không cần mở port trên firewall

Đây là ưu điểm quan trọng nhất. Mỗi port mở trên firewall là một potential entry point cho kẻ tấn công. Với Cloudflare Tunnel, firewall có thể block toàn bộ inbound traffic — chỉ cho phép outbound. Máy chủ của bạn trở nên "vô hình" trên internet: không port nào lắng nghe, không gì để scan.

Không cần static IP

ISP thường cấp dynamic IP cho hộ gia đình và doanh nghiệp nhỏ. IP có thể thay đổi khi router restart, khi ISP bảo trì, hoặc theo chu kỳ DHCP lease. Dynamic DNS giải quyết một phần nhưng có độ trễ cập nhật (thường 1-5 phút). Cloudflare Tunnel không quan tâm đến IP — nó duy trì persistent outbound connection.

SSL/TLS miễn phí

Cloudflare cấp và tự động renew certificate cho domain của bạn. Traffic từ client đến Cloudflare edge được mã hóa TLS. Traffic từ Cloudflare edge đến máy chủ bạn đi qua tunnel (cũng được mã hóa). Không cần cài đặt certbot, không cần worry về certificate expiration.

DDoS protection tích hợp

Cloudflare vận hành một trong những mạng lưới lớn nhất thế giới với hơn 300 data center. DDoS traffic được absorb và filter ở edge trước khi đến máy chủ bạn. Với self-hosted service trên đường truyền gia đình, đây là lớp bảo vệ bạn không thể tự xây dựng.

Zero Trust authentication layer

Cloudflare Access cho phép thêm lớp xác thực trước khi request đến Vaultwarden. Ngay cả khi Vaultwarden có zero-day vulnerability, kẻ tấn công vẫn cần vượt qua Cloudflare Access trước — một lớp defense in depth quan trọng.


Kiến trúc Cloudflare Tunnel

┌──────────┐     HTTPS      ┌──────────────────┐    QUIC Tunnel    ┌─────────────┐
│  Client   │ ──────────────▶│  Cloudflare Edge  │◀─────────────────│  cloudflared │
│ (Browser/ │                │  (Nearest PoP)    │   (outbound-only)│  (Your host) │
│  App)     │                │                   │                  │      │       │
└──────────┘                └──────────────────┘                  │      ▼       │
                                                                   │  localhost:  │
                                                                   │   8080       │
                                                                   │ (Vaultwarden)│
                                                                   └─────────────┘

Luồng hoạt động:

  1. cloudflared (daemon trên máy chủ bạn) khởi tạo kết nối outbound đến Cloudflare edge qua giao thức QUIC (UDP, mã hóa, multiplexed).
  2. Tunnel duy trì persistent connection — nếu bị ngắt, cloudflared tự động reconnect.
  3. Khi client truy cập vault.example.com, DNS trỏ đến Cloudflare edge.
  4. Cloudflare edge nhận request, kiểm tra Access policy (nếu có), rồi forward qua tunnel đến cloudflared.
  5. cloudflared forward request đến localhost:8080 (Vaultwarden).
  6. Response đi ngược lại qua cùng đường hầm.

Giao thức QUIC: Cloudflare Tunnel sử dụng QUIC thay vì TCP truyền thống. QUIC có ưu điểm: 0-RTT reconnection (khôi phục tunnel nhanh hơn), multiplexing không bị head-of-line blocking, và built-in encryption. Điều này giúp tunnel ổn định hơn trên các kết nối không lý tưởng (WiFi, 4G).


Cài đặt cloudflared

Yêu cầu trước

  • Một domain đã thêm vào Cloudflare (free plan đủ dùng).
  • Máy chủ đang chạy Vaultwarden (từ bài trước).
  • Quyền truy cập terminal trên máy chủ.

Bước 1 — Cài đặt binary

Debian/Ubuntu:

# Thêm Cloudflare GPG key
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg > /dev/null
 
# Thêm repository
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
 
# Cài đặt
sudo apt update && sudo apt install cloudflared

macOS (Homebrew):

brew install cloudflared

Docker (alternative):

docker pull cloudflare/cloudflared:latest

Xác nhận cài đặt:

cloudflared --version
# cloudflared version 2026.x.x (built ...)

Bước 2 — Đăng nhập và tạo tunnel

# Đăng nhập vào Cloudflare — mở trình duyệt để authorize
cloudflared tunnel login
 
# Tạo tunnel mới
cloudflared tunnel create vaultwarden-tunnel
# Output: Created tunnel vaultwarden-tunnel with id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Lệnh tunnel login mở trình duyệt, yêu cầu bạn chọn domain để authorize. Sau khi hoàn tất, một certificate được lưu tại ~/.cloudflared/cert.pem.

Lệnh tunnel create tạo tunnel và sinh ra file credentials tại ~/.cloudflared/<TUNNEL_ID>.json. File này chứa secret để authenticate tunnel — bảo vệ file này như password.

Bước 3 — Cấu hình tunnel

Tạo file cấu hình ~/.cloudflared/config.yml:

# ~/.cloudflared/config.yml
 
tunnel: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  # Tunnel ID từ bước 2
credentials-file: /home/youruser/.cloudflared/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json
 
ingress:
  # Vaultwarden web interface
  - hostname: vault.example.com
    service: http://localhost:8080
    originRequest:
      noTLSVerify: false
      connectTimeout: 10s
 
  # Catch-all rule (bắt buộc — phải là rule cuối cùng)
  - service: http_status:404

Giải thích cấu hình:

  • tunnel: ID của tunnel đã tạo.
  • credentials-file: Đường dẫn tuyệt đối đến file credentials JSON.
  • ingress: Danh sách rules ánh xạ hostname đến service. Cloudflared xử lý rules theo thứ tự từ trên xuống, rule đầu tiên match sẽ được áp dụng.
  • hostname: Domain mà client sẽ truy cập.
  • service: Địa chỉ service trên máy chủ local. Ở đây là Vaultwarden đang lắng nghe trên port 8080.
  • Catch-all rule: Rule cuối cùng không có hostname, trả về 404 cho mọi request không match rule nào — đây là yêu cầu bắt buộc của cloudflared.

Bước 4 — Tạo DNS record

# Tạo CNAME record tự động
cloudflared tunnel route dns vaultwarden-tunnel vault.example.com

Lệnh này tạo một CNAME record trong Cloudflare DNS: vault.example.com → <TUNNEL_ID>.cfargotunnel.com. Bạn cũng có thể tạo thủ công trong Cloudflare Dashboard.

Bước 5 — Chạy thử

# Chạy tunnel (foreground, để debug)
cloudflared tunnel run vaultwarden-tunnel

Bạn sẽ thấy log hiển thị tunnel connected đến nhiều Cloudflare edge server (thường 4 connection để đảm bảo redundancy). Mở trình duyệt và truy cập https://vault.example.com — bạn sẽ thấy giao diện Vaultwarden.

Bước 6 — Cài đặt systemd service (auto-start)

# Cài đặt service
sudo cloudflared service install
 
# Hoặc tạo thủ công nếu lệnh trên không hoạt động
sudo cp ~/.cloudflared/config.yml /etc/cloudflared/config.yml
sudo cp ~/.cloudflared/<TUNNEL_ID>.json /etc/cloudflared/<TUNNEL_ID>.json

Tạo file service nếu cần:

# /etc/systemd/system/cloudflared.service
[Unit]
Description=Cloudflare Tunnel
After=network-online.target
Wants=network-online.target
 
[Service]
Type=notify
ExecStart=/usr/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run
Restart=on-failure
RestartSec=5s
 
# Security hardening cho service
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/etc/cloudflared
PrivateTmp=true
 
[Install]
WantedBy=multi-user.target
# Kích hoạt và khởi động
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
 
# Kiểm tra trạng thái
sudo systemctl status cloudflared
 
# Xem log
sudo journalctl -u cloudflared -f

Lưu ý security hardening trong systemd: Các directive NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp áp dụng nguyên tắc least privilege cho chính cloudflared daemon — tương tự các lớp hardening Docker ở bài trước.


Ingress rules — Cấu hình nâng cao

Nhiều service trên cùng tunnel

Một tunnel có thể phục vụ nhiều dịch vụ khác nhau. Ví dụ nếu bạn chạy thêm Gitea hoặc Uptime Kuma:

ingress:
  # Vaultwarden
  - hostname: vault.example.com
    service: http://localhost:8080
 
  # Gitea (ví dụ)
  - hostname: git.example.com
    service: http://localhost:3000
 
  # Uptime Kuma (ví dụ)
  - hostname: status.example.com
    service: http://localhost:3001
 
  # Catch-all
  - service: http_status:404

Mỗi hostname cần một DNS CNAME record trỏ đến tunnel. Chạy cloudflared tunnel route dns cho từng hostname.

Origin request configuration

ingress:
  - hostname: vault.example.com
    service: http://localhost:8080
    originRequest:
      connectTimeout: 10s      # Timeout kết nối đến origin
      tlsTimeout: 10s          # TLS handshake timeout
      keepAliveTimeout: 90s    # Keep-alive duration
      keepAliveConnections: 10 # Connection pool size
      httpHostHeader: "vault.example.com"  # Override Host header
      noHappyEyeballs: false   # Dùng Happy Eyeballs algorithm
  - service: http_status:404

Trong hầu hết trường hợp với Vaultwarden, cấu hình mặc định là đủ. Chỉ cần tùy chỉnh nếu bạn gặp timeout hoặc vấn đề kết nối cụ thể.


Cloudflare Access — Zero Trust Authentication

Tại sao cần thêm lớp xác thực

Vaultwarden đã có hệ thống đăng nhập riêng với master password. Vậy tại sao cần thêm Cloudflare Access?

Defense in depth: Nếu một lỗ hổng zero-day trong Vaultwarden cho phép bypass authentication, Cloudflare Access vẫn chặn ở tầng trước. Kẻ tấn công cần vượt qua hai lớp xác thực độc lập.

Giảm attack surface: Cloudflare Access chặn request trước khi chúng đến Vaultwarden. Bot scan, brute-force, exploit attempt — tất cả bị filter ở Cloudflare edge, không tiêu tốn tài nguyên máy chủ bạn.

Audit log: Cloudflare ghi lại mọi lần truy cập: ai, lúc nào, từ IP nào, quyết định allow/deny. Hữu ích cho incident investigation.

Bước 1 — Tạo Access Application

Truy cập Cloudflare Dashboard -> Zero Trust -> Access -> Applications -> Add an application.

Cấu hình cơ bản:

FieldValue
Application nameVaultwarden
Application domainvault.example.com
Session duration24 hours
Application typeSelf-hosted

Session duration: Sau khoảng thời gian này, user phải xác thực lại. 24 giờ là cân bằng giữa bảo mật và tiện lợi. Với password manager, bạn có thể giảm xuống 12 giờ hoặc tăng lên 7 ngày tùy mức độ tin tưởng môi trường.

Bước 2 — Tạo Access Policy

Access Policy quyết định ai được phép truy cập. Cloudflare Access hỗ trợ nhiều loại policy:

Policy ví dụ — Email-based:

Policy name: Allow Personal Emails
Action: Allow
Include:
  - Emails: you@gmail.com, family@gmail.com

Policy ví dụ — Email domain:

Policy name: Allow Company Domain
Action: Allow
Include:
  - Email domain: example.com

Policy ví dụ — IP range (kết hợp):

Policy name: Allow Office
Action: Allow
Include:
  - IP ranges: 203.0.113.0/24

Policy ví dụ — Service token (cho API access):

Policy name: API Access
Action: Service Auth
Include:
  - Service Token: vaultwarden-api-token

Bạn có thể kết hợp nhiều rules. Ví dụ: Allow nếu email match VA IP thuộc dải cho phép. Hoặc Allow nếu email match, NHUNG Block nếu đến từ quốc gia cụ thể.

Bước 3 — One-Time PIN (Email OTP)

Đây là phương pháp xác thực đơn giản nhất, không cần Identity Provider (IdP) phức tạp:

  1. User truy cập vault.example.com.
  2. Cloudflare Access hiển thị trang đăng nhập, yêu cầu nhập email.
  3. Nếu email nằm trong policy cho phép, Cloudflare gửi mã OTP 6 số qua email.
  4. User nhập mã OTP -> Cloudflare cấp session cookie.
  5. Request được forward đến Vaultwarden -> user đăng nhập bình thường với master password.

Ưu điểm: Không cần setup IdP (Okta, Google Workspace, Azure AD). Hoạt động với bất kỳ email nào. Zero cost.

Nhược điểm: Phụ thuộc vào bảo mật email. Nếu email bị compromised, kẻ tấn công có thể nhận OTP. Tuy nhiên, chúng vẫn cần master password để vào Vaultwarden — nên rủi ro được giảm thiểu.

Quan trọng — Bypass cho Bitwarden client apps

Bitwarden client apps (desktop, mobile, browser extension) giao tiếp với Vaultwarden qua API endpoints (/api/, /identity/). Các endpoint này không thể hiển thị trang Cloudflare Access login.

Giải pháp 1 — Bypass path cụ thể:

Trong Access Application settings, thêm bypass policy cho API paths:

Policy name: Bypass API Paths
Action: Bypass
Include:
  - Everyone
Selector:
  - Path: /api/*
  - Path: /identity/*
  - Path: /notifications/hub

Giải pháp 2 — Service Token cho apps:

Tạo Service Token trong Cloudflare Access, cấu hình client apps gửi token trong header. Phức tạp hơn nhưng an toàn hơn bypass.

Khuyến nghị: Bắt đầu với Giải pháp 1 (bypass API paths). Vaultwarden API endpoints đã có xác thực riêng (API key/master password). Cloudflare Access bảo vệ tầng web interface — nơi brute-force và exploit nhắm đến nhiều nhất.


Testing — Xác nhận mọi thứ hoạt động

Kiểm tra tunnel

# Kiểm tra trạng thái tunnel
cloudflared tunnel info vaultwarden-tunnel
 
# Kiểm tra DNS resolution
dig vault.example.com CNAME
# Expected: vault.example.com. CNAME <TUNNEL_ID>.cfargotunnel.com.
 
# Kiểm tra service đang chạy
sudo systemctl status cloudflared

Kiểm tra Access gate

# Từ máy khác (không phải server), curl để xem Access có chặn không
curl -I https://vault.example.com
# Expected: HTTP 302 redirect đến Cloudflare Access login page
# Hoặc: HTTP 200 với cf-access-* headers nếu đã bypass

Kiểm tra trình duyệt

  1. Mở trình duyệt incognito/private.
  2. Truy cập https://vault.example.com.
  3. Nếu Access bật: Bạn thấy trang Cloudflare đăng nhập -> nhập email -> nhận OTP -> nhập mã -> thấy Vaultwarden.
  4. Nếu Access bypass: Bạn thấy trực tiếp trang Vaultwarden login.

Kiểm tra Bitwarden client

  1. Mở Bitwarden app (desktop/mobile/extension).
  2. Settings -> Self-hosted -> Server URL: https://vault.example.com.
  3. Đăng nhập với tài khoản Vaultwarden.
  4. Tạo một mục mới, kiểm tra sync.

Troubleshooting — Xử lý sự cố thường gặp

Lỗi 502 Bad Gateway

Triệu chứng: Trình duyệt hiển thị "502 Bad Gateway" từ Cloudflare.

Nguyên nhân: Cloudflare edge kết nối được đến tunnel, nhưng cloudflared không thể kết nối đến service local.

Kiểm tra:

# Vaultwarden có đang chạy không?
docker ps | grep vaultwarden
 
# Vaultwarden có respond không?
curl -f http://localhost:8080
 
# Port có đúng trong config.yml không?
cat ~/.cloudflared/config.yml | grep service

Khắc phục: Đảm bảo Vaultwarden đang chạy và port trong config.yml khớp với port trong docker-compose.yml.

Lỗi 403 Forbidden

Triệu chứng: "Access denied" từ Cloudflare.

Nguyên nhân: Cloudflare Access policy đang chặn request.

Kiểm tra:

  1. Cloudflare Dashboard -> Zero Trust -> Logs -> Access logs.
  2. Tìm request bị deny, xem lý do.
  3. Kiểm tra email bạn dùng có nằm trong policy Allow không.

Khắc phục: Cập nhật Access policy, thêm email hoặc IP range cần thiết.

Tunnel disconnect liên tục

Triệu chứng: Log hiển thị reconnecting liên tục, service gián đoạn.

Kiểm tra:

# Xem log chi tiết
sudo journalctl -u cloudflared --since "1 hour ago"
 
# Kiểm tra network connectivity
ping -c 5 region1.v2.argotunnel.com
 
# Kiểm tra DNS resolution
dig region1.v2.argotunnel.com

Nguyên nhân thường gặp:

  • Firewall/router chặn outbound UDP (QUIC dùng UDP). Khắc phục: Cho phép outbound UDP port 7844.
  • ISP throttle hoặc block QUIC. Khắc phục: Thêm protocol: http2 vào config.yml để fallback về HTTP/2 (TCP).
  • Credentials file bị corrupt. Khắc phục: Xóa tunnel, tạo lại.
# Fallback về HTTP/2 nếu QUIC bị chặn
tunnel: xxxxxxxx
credentials-file: /path/to/credentials.json
protocol: http2  # Thêm dòng này
 
ingress:
  - hostname: vault.example.com
    service: http://localhost:8080
  - service: http_status:404

DNS propagation chậm

Triệu chứng: Sau khi tạo DNS record, domain chưa resolve được.

Kiểm tra:

# Kiểm tra DNS propagation
dig vault.example.com @1.1.1.1
dig vault.example.com @8.8.8.8
 
# Kiểm tra trong Cloudflare Dashboard → DNS
# CNAME record có xuất hiện không? Proxy status có bật (orange cloud) không?

Khắc phục: DNS propagation thường mất 1-5 phút với Cloudflare (vì Cloudflare quản lý authoritative DNS). Nếu lâu hơn, kiểm tra:

  • Record đã được tạo đúng chưa.
  • Proxy status (orange cloud) đã bật chưa — phải bật để tunnel hoạt động.
  • Local DNS cache: sudo dscacheutil -flushcache (macOS) hoặc sudo resolvectl flush-caches (Linux).

Tóm tắt

Trong bài này, bạn đã đi qua:

  1. Vấn đề expose service — rủi ro của port forwarding, static IP, self-managed SSL.
  2. Cloudflare Tunnel — outbound-only connection, QUIC protocol, zero open ports.
  3. Cài đặt cloudflared — install, login, create tunnel, config file, DNS routing, systemd service.
  4. Ingress rules — hostname mapping, multi-service, catch-all.
  5. Cloudflare Access — Zero Trust authentication, email OTP, bypass cho API paths.
  6. Troubleshooting — 502, 403, tunnel disconnect, DNS propagation.

Kết quả: Vaultwarden giờ truy cập được từ internet qua https://vault.example.com, được bảo vệ bởi Cloudflare DDoS protection, Zero Trust Access, và tunnel mã hóa — tất cả mà không cần mở một port nào trên firewall.

LDK

Le Duy Khuong

AI Transformation & Digital Strategy. Writing about agentic systems, engineering leadership, and building in public.