Logo
Published on

[Cloudflare DDNS] Tự động cập nhật DNS cho server với IP động

Authors

Hi anh em dev 👋, các bạn có bao giờ tự dựng server ở nhà để nghịch chưa? Hay để host mấy project cá nhân? Nếu có thì chắc cũng từng gặp vấn đề như mình đây...

Vấn đề gặp phải

Tại nhà mình có một em server vật lý đang chạy và mình sử dụng domain không trỏ thẳng đến server mà đi qua Cloudflare rồi mới đến server, để sử dụng các đặc quyền như SSL free, caching tốc độ cao, và hỗ trợ chống DDOS ^^

Nghe cứ tưởng hoàn hảo, nhưng có một vấn đề đau đầu: gói internet nhà mình thuộc dạng... IP động! Tức là địa chỉ IP có thể thay đổi bất cứ lúc nào mà không báo trước, y như tính khí của crush vậy 😅

Khi IP thay đổi mình phải lên cập nhật lại IP trên Cloudflare để trỏ đúng về IP của server khá mất thời gian

Tớ từng nghĩ phải bỏ thêm tiền để đăng ký IP tĩnh? 😂

Mày mò và phát hiện

Sau một buổi lăn lộn với Google và hỏi các AI assistant, mình tìm ra một phát hiện đáng giá: Cloudflare có API cho phép cập nhật DNS tự động, quá là xịn, vậy là bài toán đã được giải quyết rồi

Ý tưởng ngay lập tức hiện ra trong đầu: Tại sao không tạo một service, định kỳ kiểm tra IP hiện tại, và tự động cập nhật DNS record trên Cloudflare khi IP thay đổi? 💡

Eureka moment

Giải pháp: DDNS Updater Service

Sau một hồi tìm hiểu thêm mới biết DDNS (Dynamic DNS) Updater là một khái niệm không mới, nhưng mình muốn tự xây một service riêng cho mình, phù hợp với nhu cầu và dễ tích hợp vào hệ thống hiện tại :)))))

Cách hoạt động

Về cơ bản, service sẽ:

  1. Chạy định kỳ (ví dụ: mỗi phút)
  2. Lấy địa chỉ IP công khai hiện tại của server
  3. Kiểm tra tất cả các DNS record trên Cloudflare
  4. Nếu phát hiện IP trong record khác với IP hiện tại, tự động cập nhật

Chỉ đơn giản vậy thôi 🤪

Triển khai: NodeJS + Cloudflare API

Do mình đã quen thuộc với JavaScript/TypeScript, mình quyết định xây dựng service này bằng NodeJS.

Luồng hoạt động

Mình sẽ vẽ một flowchart để minh họa cách service hoạt động:

https://urdraw.click/?link=MDUzMjZmYmMtZTc3Yi00ZTViLWJlZDctYzk4YTAzNmRlYTA2

Cấu trúc project

Mình tổ chức project theo cấu trúc đơn giản:

cloudflare-ddns-updater/
├── index.ts
├── .env
├── functions/
│   ├── dns-updater.ts
│   ├── ip-fetcher.ts
│   └── cloudflare-client.ts

Các thành phần chính

1. ip-fetcher.ts - Lấy IP hiện tại

import axios from "axios";

export async function fetchIPAddress(): Promise<string> {
  try {
    const response = await axios.get("https://cloudflare.com/cdn-cgi/trace");
    const data = response.data;

    const ipMatch = data.match(/ip=([\d.]+)/);
    if (ipMatch) {
      return ipMatch[1];
    } else {
      throw new Error("IP address not found in the response");
    }
  } catch (error) {
    throw new Error("Error fetching IP: " + error);
  }
}

Ở đây mình sử dụng luôn service của Cloudflare để lấy IP public hiện tại, dễ hơn việc dùng các service bên thứ ba

2. cloudflare-client.ts - Tương tác với Cloudflare API

Service sẽ giao tiếp với Cloudflare API để:

  • Lấy tất cả các zone (domain) mà mình quản lý
  • Lấy tất cả các DNS record trong mỗi zone
  • Cập nhật các record A khi cần thiết

3. dns-updater.ts - Logic chính

export async function updateDNSRecordsForAllZones() {
  try {
    console.log("-------------\nStart Update DNS");
    const ip = await fetchIPAddress();
    const zones = await fetchZones();

    for (const zone of zones) {
      const dnsRecords = await fetchDNSRecords(zone.id);

      for (const record of dnsRecords) {
        if (record.type === "A" && record?.content !== ip) {
          console.log(
            `  DNS Record: ${record.name} (${record.type}) - ${record.content}`
          );
          await updateDNSRecord(zone.id, record.id, ip);
          await sleep(50);
        }
      }
    }
  } catch (error) {
    console.log("Update DNS Failed: ", error);
  }
}

Function này sẽ được gọi định kỳ để kiểm tra và cập nhật các record DNS.

4. index.ts - Điểm khởi đầu

import { schedule } from "node-cron";
import { updateDNSRecordsForAllZones } from "./functions/dns-updater";

schedule("0 * * * * *", updateDNSRecordsForAllZones);

Ở đây mình dùng node-cron để lên lịch chạy service mỗi phút một lần, đủ nhanh để phát hiện thay đổi IP mà không tạo quá nhiều request đến Cloudflare API.


Service này không chỉ giải quyết vấn đề ban đầu mà còn mở ra nhiều khả năng khác như tự động quản lý nhiều domain, monitoring trạng thái DNS, và có thể mở rộng để hỗ trợ nhiều nhà cung cấp DNS khác.

Các bạn có gặp phải vấn đề tương tự không? Hoặc có ý tưởng nào để cải tiến service này? Hãy comment bên dưới để chia sẻ nhé! 🤓

GitHub Repository: Cloudflare DDNS Updater, các bạn có thể clone về và tùy biến theo ý thích nhé ^^