Recently I got a USG-3P from Ubiquiti and setup a network on that. I hosted the Unifi Controller in a server using docker compose. Unfortunately although the USG works very well with the controller, I was surpised to find out that Cloudflare DDNS does not work. I finally managed to find a hack to make it work, but it is far from ideal.
Note: EdgeRouter Lite 3 (ERL3) worked with the same configuration
Cloudflare
First you need to create the A Record for the hostname you wish to use for the USG. Make sure to have a low TTL value for the entry (I suggest 1 minute). Once the record is created, API calls can successfully modify the record. For example we create under Zone example.com
an A record for hostname myserver
.
Update USG ddclient binary
Unfortunately the USG has a really old version of ddclient that uses Cloudflare API v1, which is deprecated, unsupported and no longer working
Become root
sudo su -
then run
[[ -f /usr/sbin/ddclient-original ]] || cp /usr/sbin/ddclient /usr/sbin/ddclient-original
curl -L -o /tmp/ddclient https://gitlab.com/-/snippets/2458808/raw/main/ddclient
cp /tmp/ddclient /usr/sbin/ddclient
chmod +x /usr/sbin/ddclient
Now you should have a ddclient that supports Cloudflare API v4.
USG Advanced Configuration
Configuring Cloudflare Dynamic DNS is not possible through the Unifi controller, but only through UniFi - USG Advanced Configuration using config.gateway.json. This means that we have to create a file named config.gateway.json
under
Where is
- UniFi Cloud Key, : /usr/lib/unifi
- UniFi Dream Machine: /usr/lib/unifi (you must first enter unifi-os shell)
- Debian/Ubuntu Linux: /usr/lib/unifi
- Windows: %userprofile%/Ubiquiti UniFi.
- macOS: ~/Library/Application Support/UniFi
- Docker compose : /opt/containers/unifi/data
Path for config.gateway.json
The file config.gateway.json
should be created under <unifi_base>/data/sites/site_ID
, where site_ID value is default
most of the times. You can always find the site_ID from the url of the Unifi Controller https://192.168.11.10/manage/<site_ID>/dashboard
.
Missing sites path
In my case the site_ID
path was not there under <unifi_base>/data
. In order to have these folders you have to upload a floorplan at least one time so the folder structures will be created. Unfortunately there is no way to create a Floorplan using the modern UI of the controller (at least up to version 7.2.94), so we need to enable the “Legacy Interface”.
Go to Settings -> System -> Legacy Interface and enable it.
Then go to Map and from the top left dropdown select Topology
and change it to Floor plan
. Then add a floor plan and save it. Any map imagec in the UniFi GUI will work. Now the directory structure should be generated and you could delete the floor plan and disable the “Legacy Interface”.
Add Cloudflare configuration
I assume that the interface used for Dynamic DNS is pppoe0
, if you are using a different interface eg: eth0
change the value at line 6.
Now you should create the file <unifi_base>/data/sites/site_IDconfig.gateway.json
and add the cloudflare configuration
{
"service": {
"dns": {
"dynamic": {
"interface": {
"pppoe0": {
"service": {
"custom-cloudflare": {
"host-name": [
"myserver.example.com"
],
"login": "<USERNAME>",
"options": [
"zone=example.com"
],
"password": "<GlobalCloudFlareAPIToken>",
"protocol": "cloudflare",
"server": "api.cloudflare.com/client/v4"
}
}
}
}
}
}
}
}
Note: You may need to add a line just before service, in order to find the public IP by using DynDns web service instead of the IP assigned to the interface:
"web": "dyndns",
Note: This version of ddclient needs the Global Cloudflare API token. When we change this instructions to use ddclient version >= 3.10 we can start an API token that’s been granted All zones
, Zone:Read
and DNS:Edit
permissions.
The config.gateway.json
file must have unifi:unifi as the owner and group permissions. You can check to verify with
ls -l <unifi_base>/data/sites/site_ID
To change it, once you’re in the site directory, use the command:
chown unifi:unifi config.gateway.json
Applying the configuration
After adding the config.gateway.json
to the UniFi Network site of your choosing, you can test it by running a “force provision” to the USG in UniFi Devices -> select the USG -> Config -> Manage Device -> Force provision. This will take a while to provision (30 seconds to 3 minutes), and if it stays in provisioning longer than that, there may be a formatting error in the config.gateway.json, and you are experiencing the provisioning loop that was mentioned earlier. You shoould check the Unifi controller notifications about the provisioning of USG or you can check server.log in the application and search for commit error. You can usually find what went wrong with the provisioning of the newly customized configuration in the log files.
Verification
Check DNS entry
You can visit Cloudflare dashboard and check if the appropriate DNS entry is updated or you could simply lookup the appropriate DNS entry:
nslookup myserver.example.com 1.1.1.1
Check USG Dynamic DNS status
Connect to USG using SSH and become root to check dyndns status
sudo su -
show dns dynamic status
interface : pppoe0
ip address : 1.2.3.4
host-name : myserver.example.com
last update : Thu Jan 1 02:00:00 1970
update-status: good
Get Zone info
You can information for a zone by using Cloudflare authentication key:
curl -X GET "https://api.cloudflare.com/client/v4/zones?name=example.com" \
-H "Content-Type:application/json"
-H "X-Auth-Email: <USERNAME>" \
-H "X-Auth-Key: <GlobalCloudFlareAPIToken>"
or using an API token:
curl -X GET "https://api.cloudflare.com/client/v4/zones?name=example.com" \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type:application/json"
if the API token is not working you can validate it:
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type:application/json"
ddclient configuration
After the Forced provision of the USG a file with the configuration for the specified interface is created /etc/ddclient/ddclient_<INTERFACE>.conf
. In my case file /etc/ddclient/ddclient_pppoe0.conf
with the following contents:
#
# autogenerated by vyatta-dynamic-dns.pl on Mon ...
#
daemon=1m
syslog=yes
ssl=yes
pid=/var/run/ddclient/ddclient_pppoe0.pid
cache=/var/cache/ddclient/ddclient_pppoe0.cache
use=if, if=pppoe0
# Service : custom-cloudflare
server=api.cloudflare.com/client/v4, protocol=cloudflare max-interval=28d zone=example.com login=<USERNAME> password='<GlobalCloudFlareAPIToken>' myserver.example.com
Check ddclient logs
To see ddclient messages connect to USG using SSH and as root run:
grep ddclient /var/log/messages
Debug ddclient
Connect to USG using SSH and as root:
- kill ddclient
pkill ddclient
- run ddclient with extra logging
pkill ddclient ddclient -foreground -force -debug -verbose -file /etc/ddclient/ddclient_pppoe0.conf
Now check again the ddclient logs
Note: If you see http://www.cloudflare.com/api_json.html
in your requests, this means that you are using an old ddclient with API v1 support.
Links
- UniFi - USG Advanced Configuration using config.gateway.json
- Ubiquiti USG Advanced Configuration
- UniFi - Where is <unifi_base>?
- Cloudflare DDNS 1.9.0
- EdgeRouter - Custom Dynamic DNS
- Cloudflare DDNS configuration for Unifi USG
- Using Cloudflare for Dynamic DNS on Unifi - using cloudflare workers
- Edgemax ddclient v3.8.3 patched with support for Cloudflare v4 API