28 กรกฎาคม 2569

Mikrotik script for update cloudflare DNS IP

 
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# USER CONFIGURATION
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# On the first run, leave cfRecordId empty "". 
# Once you get the ID from the Log, paste it here (e.g., :local cfRecordId "abcdef123456...")
:local cfRecordId ""

:local cfToken "YOUR_CLOUDFLARE_API_TOKEN"
:local cfZoneId "YOUR_CLOUDFLARE_ZONE_ID"
:local cfRecordName "ddns.domain.com"
:local wanInterface "ether1"

# Specify the DNS server used to resolve your Cloudflare domain IP (e.g., 1.1.1.1 or 8.8.8.8)
:local dnsServer "1.1.1.1"

# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# AUTOMATIC PROCESS (Determined by the cfRecordId status above)
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:local httpHeaders "Authorization: Bearer $cfToken"

# If cfRecordId is empty, fetch the ID from Cloudflare and print it to the log
:if ([:len $cfRecordId] = 0) do={
    :log warning "CF-DDNS: [STEP 1] cfRecordId is EMPTY. Fetching ID from Cloudflare..."
    
    :local getUrl "https://api.cloudflare.com/client/v4/zones/$cfZoneId/dns_records"
    :local fetchResult ""
    
    :do {
        :set fetchResult [/tool fetch url=$getUrl http-header-field=$httpHeaders as-value output=user]
    } on-error={
        :log error "CF-DDNS: Failed to connect to Cloudflare API. Check your Token/Zone ID."
    }

    :if ($fetchResult != "") do={
        :local responseData ($fetchResult->"data")
        :local idKeyword "\"id\":\""
        :local idPos [:find $responseData $idKeyword]
        
        :if ($idPos > 0) do={
            :local idStart ($idPos + [:len $idKeyword])
            :local idEnd [:find $responseData "\"" $idStart]
            :local fetchedId [:pick $responseData $idStart $idEnd]
            
            # Action required: Print the Record ID to the log for copying
            :log error "=========================================================="
            :log warning "CF-DDNS: [SUCCESS] Your Record ID is: $fetchedId"
            :log warning "CF-DDNS: Please copy this ID and paste it into ':local cfRecordId \"\"' at the top of this script!"
            :log error "=========================================================="
        } else={
            :log error "CF-DDNS: DNS Record Name not found on Cloudflare. Please check your spelling."
        }
    }
} else={
    # If cfRecordId is provided, proceed to check IP and update DDNS
    :local currentIp [/ip address get [/ip address find interface=$wanInterface] address]
    :set currentIp [:pick $currentIp 0 [:find $currentIp "/"]]

    :local cloudflareIp ""
    :do {
        # Resolve the domain using the specific DNS resolver configured above
        :set cloudflareIp [:resolve $cfRecordName server=$dnsServer]
    } on-error={
        :log info "CF-DDNS: Cannot resolve $cfRecordName via $dnsServer, proceeding to check update."
    }

    # Only execute API update if the WAN IP has changed
    :if ($currentIp != $cloudflareIp) do={
        :log info "CF-DDNS: IP changed from $cloudflareIp to $currentIp. Updating Cloudflare..."
        
        :local putUrl ("https://api.cloudflare.com/client/v4/zones/" . $cfZoneId . "/dns_records/" . $cfRecordId)
        :local putData "{\"type\":\"A\",\"name\":\"$cfRecordName\",\"content\":\"$currentIp\",\"ttl\":300,\"proxied\":false}"
        
        :do {
            /tool fetch url=$putUrl http-method=put http-data=$putData http-header-field=$httpHeaders as-value output=user
            :log info "CF-DDNS: Successfully updated $cfRecordName to $currentIp"
        } on-error={
            :log error "CF-DDNS: Failed to update IP on Cloudflare."
        }
    }
}