Tự dựng Dynamic DNS với Cloudflare: Chấm dứt nỗi lo mất kết nối từ xa lúc 2 giờ sáng

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Lỗi Connection Timed Out lúc 2 giờ sáng

Tôi đang ngồi trong một phòng khách sạn, cách văn phòng tại nhà ba múi giờ, nhìn chằm chằm vào con trỏ đang nhấp nháy. Tôi cần một file cấu hình từ máy chủ phát triển (dev server) để vá một lỗi nghiêm trọng. Tôi gõ ssh dev.itfromzero.com để truy cập từ xa, nhấn enter và chờ đợi. Năm giây trôi qua. Mười giây. Sau đó, thông báo đáng sợ xuất hiện: ssh: connect to host dev.itfromzero.com port 22: Connection timed out.

Tôi biết ngay thủ phạm là ai. Nhà cung cấp dịch vụ Internet (ISP) tại nhà đã thay đổi địa chỉ IP công cộng của tôi một lần nữa. Bản ghi DNS cho dev.itfromzero.com đang trỏ đến một địa chỉ “chết”, trong khi máy chủ của tôi đang nằm ở một địa chỉ mới mà tôi không hề biết. Tôi bị khóa bên ngoài thiết bị của chính mình. Điều này không chỉ gây khó chịu; nó còn làm tê liệt hoàn toàn quy trình làm việc từ xa của tôi.

Vòng xoay IP: Tại sao kết nối tại nhà thường xuyên bị ngắt

Các ISP hộ gia đình nổi tiếng với việc này. Họ quản lý một nhóm địa chỉ và cấp phát chúng qua DHCP, thường với chu kỳ thuê 24 giờ. Khi thời gian thuê hết hạn—hoặc nếu modem của bạn khởi động lại sau một đợt chớp điện 10 giây—IP của bạn sẽ thay đổi. Với một người đang xem Netflix, điều này gần như vô hình. Nhưng với một kỹ sư đang vận hành VPN hoặc private cloud, đây là một thay đổi gây gián đoạn hệ thống (breaking change).

Kẻ sát nhân thực sự chính là khoảng cách thời gian giữa lúc thay đổi và lúc cập nhật. Nếu IP của bạn thay đổi lúc 1:00 sáng nhưng bản ghi DNS vẫn giữ nguyên địa chỉ cũ, máy chủ của bạn về cơ bản sẽ trở thành một “bóng ma”. Để khắc phục điều này, chúng ta cần một cách để phát hiện sự thay đổi và yêu cầu nhà cung cấp DNS cập nhật bản ghi gần như theo thời gian thực.

Thực trạng DDNS: Tại sao hầu hết các lựa chọn đều tệ

Tôi đã xem xét các giải pháp tiêu chuẩn trước khi tự viết mã. Dưới đây là bức tranh chung của lĩnh vực này:

  • Các nhà cung cấp truyền thống (No-IP, DynDNS): Họ hoạt động ổn, nhưng các gói miễn phí giống như bị “bắt làm con tin”. Bạn thường phải nhấp vào một liên kết trong email sau mỗi 30 ngày chỉ để giữ cho hostname hoạt động, hoặc họ ép bạn sử dụng các subdomain như myhome.ddns.net.
  • DDNS tích hợp trên Router: Hầu hết các router phổ thông đều hỗ trợ sẵn, nhưng chúng thường bị giới hạn cứng ở một số nhà cung cấp (trả phí) cụ thể. Tệ hơn nữa, chúng hoàn toàn không có nhật ký (logging). Khi chúng gặp lỗi, bạn chỉ còn biết đoán mò nguyên nhân.
  • Cloudflare API + Bash: Đây là lựa chọn của các kỹ sư. Nếu bạn đã sử dụng Cloudflare, bạn có một API mạnh mẽ trong tầm tay. Nó miễn phí, hoạt động với tên miền riêng của bạn và bạn có thể viết script để nó hoạt động chính xác theo ý muốn. Bạn cũng có thể cân nhắc sử dụng Cloudflare Tunnel để bảo mật hơn.

Tôi đã vận hành hệ thống này trên thiết bị cá nhân hơn hai năm nay. Nó chưa từng bỏ lỡ một nhịp nào. Nó vượt qua các hạn chế của dịch vụ thương mại trong khi trao cho bạn toàn quyền kiểm soát logic cập nhật và báo cáo lỗi.

Giải pháp 30 dòng mã: Tự xây dựng Client cho riêng mình

Để hệ thống này hoạt động, bạn chỉ cần ba thứ: một Cloudflare API Token, vài dòng mã Bash và một cách để lập lịch chạy. Bash là công cụ hoàn hảo ở đây—nó có sẵn trên mọi bản phân phối Linux, tốc độ cực nhanh và không tốn tài nguyên hệ thống.

Bước 1: Lấy chìa khóa vạn năng

An toàn là trên hết: Đừng sử dụng Global API Key của bạn. Nếu khóa đó bị rò rỉ, hacker có thể xóa toàn bộ tài khoản của bạn. Thay vào đó, hãy tạo một token có phạm vi giới hạn (scoped token):

  1. Đăng nhập vào Cloudflare và đi tới My Profile > API Tokens.
  2. Tạo một token bằng template Edit zone DNS.
  3. Giới hạn phạm vi (scope) cụ thể for tên miền bạn muốn cập nhật.
  4. Sao chép token và lưu trữ nó trong trình quản lý mật khẩu.

Bạn cũng sẽ cần Zone ID, có thể tìm thấy trên trang Tổng quan (Overview) của bảng điều khiển tên miền.

Bước 2: Cốt lõi của Logic

Logic rất đơn giản. Chúng ta lấy IP công cộng hiện tại, so sánh nó với một file lưu tạm (cache) cục bộ, và chỉ khi chúng khác nhau, chúng ta mới gửi yêu cầu đến Cloudflare. Dưới đây là đoạn script. Tôi đã giữ it tinh gọn để bạn có thể thấy chính xác những gì đang diễn ra bên dưới.

#!/bin/bash

# Cấu hình
AUTH_TOKEN="your_api_token_here"
ZONE_ID="your_zone_id_here"
RECORD_NAME="dev.itfromzero.com"
IP_FILE="/tmp/current_ip.txt"

# Lấy IP công cộng hiện tại bằng dịch vụ bên ngoài tin cậy
CURRENT_IP=$(curl -s https://api.ipify.org)

# Kiểm tra xem có IP đã lưu trong cache để so sánh không
if [ -f "$IP_FILE" ]; then
    OLD_IP=$(cat "$IP_FILE")
else
    OLD_IP=""
fi

# IP không khớp? Cập nhật ngay. Nếu không? Nghỉ.
if [ "$CURRENT_IP" = "$OLD_IP" ]; then
    echo "IP chưa thay đổi ($CURRENT_IP). Bỏ qua cập nhật."
    exit 0
fi

echo "IP đã thay đổi từ $OLD_IP sang $CURRENT_IP. Đang cập nhật Cloudflare..."

# Lấy Record ID duy nhất từ Cloudflare
RECORD_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$RECORD_NAME" \
     -H "Authorization: Bearer $AUTH_TOKEN" \
     -H "Content-Type: application/json" | jq -r '.result[0].id')

# Đẩy bản cập nhật
UPDATE_RESULT=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
     -H "Authorization: Bearer $AUTH_TOKEN" \
     -H "Content-Type: application/json" \
     --data "{\"type\":\"A\",\"name\":\"$RECORD_NAME\",\"content\":\"$CURRENT_IP\",\"ttl\":1,\"proxied\":false}")

if [[ $UPDATE_RESULT == *"\"success\":true"* ]]; then
    echo "Cập nhật thành công."
    echo "$CURRENT_IP" > "$IP_FILE"
else
    echo "Cập nhật thất bại! Hãy kiểm tra quyền của token."
    exit 1
fi

Mẹo nhỏ: Bạn sẽ cần cài đặt jq (sudo apt install jq) để phân tích phản hồi JSON. Đây là công cụ tiêu chuẩn để xử lý dữ liệu API trong terminal.

Bước 3: Tại sao Script này lại “thân thiện với API”

Đầu tiên, chúng ta sử dụng một file cục bộ (/tmp/current_ip.txt) để lưu IP được biết đến gần nhất. Điều này đảm bảo chúng ta không “dội bom” máy chủ của Cloudflare sau mỗi vài phút nếu không có gì thay đổi. Mặc dù Cloudflare cho phép 1.200 yêu cầu mỗi 5 phút, nhưng việc trở thành một “công dân API” tốt là một thói quen kỹ thuật chuẩn mực.

Việc đặt "proxied": false cũng rất quan trọng. Nếu bạn sử dụng DNS này cho SSH hoặc VPN, bạn muốn lưu lượng truy cập đi thẳng đến IP của mình. Proxy tiêu chuẩn của Cloudflare chỉ xử lý lưu lượng web (HTTP/S), vì vậy trừ khi bạn trả phí cho dịch vụ Spectrum, proxy sẽ chặn luôn kết nối SSH của bạn.

Thiết lập một lần rồi quên luôn: Tự động hóa

Một đoạn script sẽ vô dụng nếu bạn phải chạy nó bằng tay. Bạn có thể sử dụng một cron job đơn giản để kiểm tra mỗi 5 phút:

*/5 * * * * /home/user/scripts/cloudflare-ddns.sh >> /var/log/ddns.log 2>&1

Tuy nhiên, tôi thích sử dụng Systemd Timer hơn. Tại sao? Vì Systemd xử lý các phụ thuộc (dependencies) một cách đúng đắn, ghi nhật ký trực tiếp vào journalctl và chờ mạng trực tuyến trước khi kích hoạt. Nếu script thất bại vì modem của bạn vẫn đang khởi động lại, Systemd có thể thử lại với cơ chế exponential backoff (thời gian chờ tăng dần).

File Service (/etc/systemd/system/cf-ddns.service)

[Unit]
Description=Cập nhật Cloudflare DDNS
After=network-online.target

[Service]
Type=oneshot
ExecStart=/home/user/scripts/cloudflare-ddns.sh
User=user

File Timer (/etc/systemd/system/cf-ddns.timer)

[Timer]
OnBootSec=1min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target

Kích hoạt bằng lệnh systemctl enable --now cf-ddns.timer. Giờ đây bạn đã có một DDNS client cấp độ chuyên nghiệp được tích hợp trực tiếp vào trình quản lý dịch vụ của hệ thống.

Sự ổn định và sự an tâm

Kể từ khi triển khai việc này, tôi chưa bao giờ bị khóa bên ngoài thêm lần nào. Nhưng đừng dừng lại ở đây. Một đoạn script chỉ tốt khi nó được giám sát. Hãy cân nhắc thêm một bước kiểm tra sức khỏe (health check) đơn giản—nếu việc cập nhật thất bại, hãy để script thông báo cho một bot Telegram hoặc Discord webhook. Bạn sẽ muốn biết có vấn đề xảy ra *về sau* trước khi bạn cố gắng đăng nhập qua SSH trong khi xử lý sự cố mạng lúc 2 giờ sáng.

Bằng cách tự xây dựng hệ thống này, bạn đã loại bỏ được bên trung gian và hiểu sâu hơn về tự động hóa DNS. Đây là một dự án 15 phút mang lại thành quả mỗi khi ISP của bạn quyết định chơi trò “ghế âm nhạc” với địa chỉ IP của bạn.

Share: