[Guide]Pfsense Dynamic DNS with CloudFlare (v.2.1.5)

  • Hello All,

    I update Pfsense last week just for this function but as everyone know = It dont work (As several stuff inside…)! D***n !  >:( :( :(
    I rollback to Pfsense 2.1.5. and proceed in another way.

    Here how I do to use Pfsense Dynamic DNS with CloudFlare :

    1 >
    Need to check 1st some log with CloudFlare, as we need the "ID" of the entry of DNS A (eg.) of the domain we need to keep update.
    Just enter this in browser (Dont do in browser you are login in your CloudFlare account. Eg. If you login with Chrome, use Firefox) =


    "myapikey" = Your CloudFlare API key.
    "email@myemail.com" = Your email account for CloudFlare.
    "myweburl.com" = Your domain name on cloudFlare.

    Normally you should have this kind of log :

    Here we see = id":"25709999" for the DNS of my domain "myweburl.com" of "type":"A". Perfect!
    2 > 
    Now in Pfsense [b]Service>Dynamic DNS[/b], create new entry = Select [b]Service type "Custom"[/b]. In [u][b]Update URL[/b][/u] enter this =
    "%IP%" will be replaced by your IP by Pfsense.
    Then save.
    Now you can check that CloudFlare IP of my domain "myweburl.com" of "A" is now up to date by Pfsense! ;)
    Thats all folk!.

  • (as posted in another thread here)

    I actually worked out a fix at the dyndns.class file:

    CloudFlare now requires a "record ID" in order to update an address, for such I did another curl call before pfsense change of the IP in order to get the record ID from the target.

    Also the CloudFlare URL is quite different from the one in the original file of pfSense.

    if you open the /etc/inc/dyndns.class, line 607, the original case looks like:

    case 'cloudflare':
                                            $needsIP = TRUE;
                                            $dnsServer ='www.cloudflare.com';
                                            $dnsHost = str_replace(' ','', $this->_dnsHost);
                                            $URL = "https://{$dnsServer}/api.html?a=DIUP&hosts={$dnsHost}&u={$this->_dnsUser}&tkn={$this->_dnsPass}&ip={$this->_dnsIP}";
                                            /* $URL = "https://{$dnsServer}/api.html?a=DIUP&email={$this->_dnsUser}&tkn={$this->_dnsPass}&ip={$this->_dnsIP}&hosts={$dnsHost}"; */
                                            curl_setopt($ch, CURLOPT_URL, $URL);

    I change it to:

    case 'cloudflare':
                                            $needsIP = TRUE;
                                            $dnsServer ='www.cloudflare.com';
                                            list ($host,$zone) = split('.', $this->_dnsHost, 2);
                                            $getid = "https://$dnsServer/api_json.html?a=rec_load_all&tkn={$this->_dnsPass}&email={$this->_dnsUser}&z=$zone";
                                            $crl = curl_init();
                                            $timeout = 5;
                                            curl_setopt ($crl, CURLOPT_URL,$getid);
                                            curl_setopt ($crl, CURLOPT_RETURNTRANSFER, 1);
                                            curl_setopt ($crl, CURLOPT_CONNECTTIMEOUT, $timeout);
                                            $ids = curl_exec($crl);
                                            $json_ids = json_decode($ids, true);
                                            $jsonIterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($json_ids),RecursiveIteratorIterator::SELF_FIRST);
                                            foreach ($jsonIterator as $key => $val) { if(!is_array($val)) { if ($key == "rec_id") { $recid=$val; } if ($key == "name" and $val == $this->_dnsHost) { break; } } }
                                            $dnsHost = str_replace(' ','', $this->_dnsHost);
                                            $URL = "https://{$dnsServer}/api_json.html?a=rec_edit&tkn={$this->_dnsPass}&email={$this->_dnsUser}&id=$recid&z=$zone&type=A&name=$host&content={$this->_dnsIP}&service_mode=1&ttl=1";
                                            curl_setopt($ch, CURLOPT_URL, $URL);

    In the Dynamic DNS interface all the information is pretty much the same, except the password must be the Token ID found at https://www.cloudflare.com/my-account ("Your API key is: ")

    With this change he is automatically updating CloudFlare but the cached IP address still, something else must change to make this value also correct.

    I hope this help to fix the problem for other people as well.

  • I'm glad to see people making progress on this.  I got the updates to work with the custom & custom_v6 DynDns adapters being sure to include the new record id record.

    But I still have two issues:

    1. When DNS addresses change the custom https response from Cloudflare includes a "rec_hash" record that also changes whenever the IP address changes.  The custom adapter doesn't seem to have a built in way to ignore a changing record like this (no regular expressions etc.)

    2. When specifying adapters both A and AAAA records there is an issue binding to the interface using an IP address in the dyndns.class.  I've had to change the binding the IP address to the interface name in order to get both IPv4 and IPv6 to work on the same interface.

Log in to reply