THỰC CHIẾN Cơ bản

Mang dashboard ở nhà theo bên mình bằng Tailscale Serve, không mở port router

Một lab nhỏ để xem trang trạng thái nội bộ từ điện thoại bằng Tailscale Serve: HTTP chỉ nghe loopback, HTTPS trong tailnet, kiểm tra quyền truy cập và dọn cấu hình sau khi thử. Không cần exit node hay public tunnel.

Vibe DevOps·· 6 phút đọc
Tailscale ServePython 3LinuxĐiện thoại

Đọc nhanh trước khi bắt tay làm

  • Muốn xem dashboard của chính mình từ bên ngoài không nhất thiết phải đưa nó lên Internet. Serve chia sẻ dịch vụ trong tailnet; Funnel mới là tính năng chia sẻ ra Internet.
  • Bắt đầu bằng một thư mục chỉ chứa trang HTML mẫu. Đừng dùng thư mục dự án, nơi có thể có token, log và file cấu hình riêng tư.
  • HTTP mẫu chỉ nghe 127.0.0.1; Tailscale Serve làm reverse proxy HTTPS. Quyền truy cập vẫn phụ thuộc chính sách của tailnet, không phải cứ có VPN là được bảo vệ khỏi mọi thành viên.
  • Đây là hướng dẫn lab, không phải báo cáo đã kiểm thử từ mạng di động. Cú pháp Serve được đối chiếu với trợ giúp CLI trên máy; bạn cần tự kiểm tra kết nối giữa hai thiết bị.

Ghép các mảnh lại với nhau

  1. 01 →Điện thoạiTailscale bật
  2. 02 →Tailnetquyền truy cập
  3. 03 →Serve HTTPSreverse proxy
  4. 04 →127.0.0.1:8888HTTP mẫu
Trong bài này

Đang ở ngoài đường mà muốn biết dashboard ở nhà có chạy không: mở port router, dựng tên miền rồi lo chứng chỉ chỉ để xem một trang nội bộ thì hơi quá tay. Đưa nguyên dashboard quản trị vào public tunnel lại tạo thêm một việc phải lo: ai đang nhìn thấy những route sửa nội dung, xem log hoặc gọi tác vụ của mình?

Một hướng gọn hơn là giữ trang trong mạng riêng Tailscale. Điện thoại và server cùng tham gia tailnet; Tailscale Serve đứng trước một dịch vụ chỉ nghe trên loopback. Không cần biến server thành exit node, cũng không cần route toàn bộ lưu lượng Internet của điện thoại qua nhà.

Bài viết lấy cảm hứng từ cách Thuận Bùi ghép Tailscale với các dịch vụ tự host: bắt đầu bằng nhu cầu cụ thể rồi nối từng mảnh lại. Lab bên dưới đơn giản hơn, không triển khai phần Google Home, Sinric Pro hay n8n của bài tham khảo.

Phân biệt ba thứ trước khi làm

Tính năng Dùng khi nào?
Tailscale Serve Chia sẻ trang hoặc dịch vụ cho thiết bị có quyền trong tailnet
Tailscale Funnel Cần người ngoài tailnet truy cập qua Internet
Exit node Muốn chuyển lưu lượng Internet của thiết bị qua một máy khác

Bài này chỉ cần Serve. Việc bật exit node không tự xuất bản dashboard, và Serve cũng không thay thế đăng nhập của ứng dụng.

Chuẩn bị

Bạn cần một máy Linux có Python 3, Tailscale đã cài và đăng nhập; một điện thoại đã đăng nhập vào cùng tailnet hoặc được cấp quyền phù hợp; quyền điều chỉnh chính sách của tailnet nếu mạng đang hạn chế kết nối.

Kiểm tra CLI trước:

tailscale version
tailscale serve --help
tailscale serve status

Cú pháp trong bài được đối chiếu với tailscale serve --help của bản 1.104.1 trên máy biên soạn. Với bản khác, hãy kiểm tra lại trợ giúp. Nếu serve status đã có dịch vụ, đừng ghi đè cấu hình đó: thử trên node riêng hoặc chọn cổng HTTPS khác sau khi xem hướng dẫn của phiên bản đang dùng.

Bước 1: Dựng một trang mẫu, không mang theo bí mật

Trước khi nối dashboard thật, dùng một thư mục riêng chỉ chứa đúng trang HTML thử nghiệm. Không chạy HTTP server ngay tại thư mục home hoặc thư mục dự án.

LAB_DIR=$(mktemp -d "$HOME/tailscale-lab.XXXXXX")
printf '%s\n' '<!doctype html><html lang="vi"><meta charset="UTF-8"><title>Homelab</title><h1>Dashboard mẫu đã lên</h1><p>Chỉ là trang kiểm tra kết nối, không chứa dữ liệu quản trị.</p></html>' > "$LAB_DIR/index.html"
python3 -m http.server 8888 --bind 127.0.0.1 --directory "$LAB_DIR"

Giữ terminal này mở. Nếu cổng 8888 đã có dịch vụ, chọn cổng khác và thay đồng nhất trong các lệnh tiếp theo. http.server chỉ phù hợp cho lab tạm; đừng dùng nó làm ứng dụng production có dữ liệu nhạy cảm.

Ở terminal thứ hai:

curl -I http://127.0.0.1:8888/
ss -ltn 'sport = :8888'

Mục tiêu là nhận HTTP 200 và thấy listener ở 127.0.0.1, không phải 0.0.0.0. Khi đó máy khác trong LAN không truy cập trực tiếp được HTTP server này qua địa chỉ LAN của server.

Bước 2: Để Serve đứng trước dịch vụ

Chỉ thực hiện sau khi xác nhận node chưa có cấu hình Serve mà bạn cần giữ:

tailscale serve http://127.0.0.1:8888

CLI sẽ hướng dẫn bật HTTPS trong tailnet nếu cần. Đọc thông báo và hoàn tất bước quản trị bằng tài khoản của bạn; không chia sẻ link đăng nhập hoặc auth key lên bài viết, chat công cộng hay ảnh chụp màn hình.

Dùng URL HTTPS mà CLI thực sự in ra. Không tự đoán tên miền của node. Giữ lệnh chạy foreground trong lúc thử; cách này dễ quan sát lỗi và dừng bằng Ctrl+C.

Bước 3: Thử từ điện thoại, không chỉ curl trên server

  1. Bật Tailscale trên điện thoại và xác nhận nó tham gia đúng tailnet.
  2. Tắt Wi-Fi, dùng mạng di động để tránh nhầm với đường LAN.
  3. Mở URL HTTPS lấy ở bước trước. Trang phải có dòng “Dashboard mẫu đã lên”.
  4. Tắt kết nối Tailscale trên điện thoại, mở lại bằng cửa sổ riêng tư hoặc tải lại để tránh nhìn bản cache.
  5. Nếu URL vẫn truy cập được từ thiết bị không thuộc tailnet, dừng lại và kiểm tra: có bật Funnel, public tunnel hoặc proxy nào khác không?

Bài viết không coi phép thử giữa hai thiết bị là đã hoàn tất thay bạn. Kết quả này phụ thuộc mạng, chính sách tailnet và thiết bị thực tế của bạn. Một lệnh curl localhost thành công chỉ chứng minh backend HTTP hoạt động.

Bước 4: Siết quyền trước khi nối dashboard thật

Một tailnet có nhiều thành viên không đồng nghĩa dashboard chỉ dành cho bạn. Rà lại ACL hoặc grants: nhóm người dùng nào được tới node này và cổng HTTPS mà Serve sử dụng? Chính sách mặc định hoặc chính sách quá rộng có thể cho nhiều người hơn dự kiến truy cập.

Với dashboard có nút chỉnh sửa, phát hành hay xem cấu hình, nên giữ thêm lớp đăng nhập ở ứng dụng. Không đưa token, raw log hoặc endpoint quản trị vào trang trạng thái chỉ vì nó nằm sau VPN.

Sau khi lab chạy đúng, mới thay backend mẫu bằng ứng dụng thật nghe loopback. Kiểm tra toàn bộ route của ứng dụng, không chỉ trang chủ. Serve proxy tới một server không tự lọc các route nguy hiểm cho bạn.

Khi không vào được, kiểm tra theo thứ tự

  • Localhost cũng không vào được: xử lý backend và cổng trước, chưa cần đụng tới Tailscale.
  • Server vào được, điện thoại không vào được: kiểm tra đăng nhập, tailnet, VPN đang bật và quyền tới node.
  • Tên miền không phân giải: dùng đúng URL do Serve in ra, xem lại MagicDNS và cấu hình DNS trên client.
  • Lỗi HTTPS: kiểm tra bước bật HTTPS và hướng dẫn CLI, không dùng tùy chọn bỏ xác minh chứng chỉ để che lỗi.
  • Máy ngủ thì mất kết nối: chọn máy chạy liên tục nếu muốn xem dashboard bất cứ lúc nào.

Dọn lab

Dừng lệnh Serve foreground bằng Ctrl+C, kiểm tra lại tailscale serve status, rồi dừng HTTP server ở terminal đầu tiên. Nếu đã dùng --bg, xem cách tắt đúng listener trong tailscale serve --help của phiên bản đang cài.

tailscale serve reset xóa toàn bộ cấu hình Serve của node, nên chỉ dùng trên node lab riêng sau khi đã xem status. Không chạy lệnh này trên máy đang phục vụ ứng dụng khác.

Thư mục lab chỉ chứa trang mẫu; xóa đúng thư mục tailscale-lab.* vừa tạo khi không cần nữa, không dùng wildcard rộng để dọn thư mục home.

Kết luận

Với nhu cầu xem dashboard cá nhân, câu hỏi đầu tiên nên là: có thật sự cần public không? Nếu chỉ vài thiết bị của mình truy cập, Serve cùng chính sách quyền hẹp thường là điểm bắt đầu đơn giản hơn một endpoint Internet phải bảo vệ liên tục.

Khi cần webhook từ dịch vụ bên ngoài, bài toán đã khác: lúc đó mới cân nhắc public endpoint, xác thực request và giới hạn route. Đừng mở công khai cả dashboard chỉ để giải quyết một webhook.

Đọc có chọn lọc, chạy có kiểm tra. Ví dụ dùng đường dẫn của dự án Vibe DevOps; thay lại cấu hình theo máy của bạn và thử trên môi trường riêng trước khi áp dụng.← Về mục Thực chiến

Làm tiếp một việc nữa