OPNSense – Dynamic DNS with Cloudflare using a Custom Cron Job


I made a simple script and a custom Cron Job configd to monitor for changes and push the new IP to Cloudflare. The script can be used on another system rather than OPNSense, but the configd was made specifically for OPNSense use only.

Credit: Special thanks to Steve@Tech Otaku for the API scripts.

Original scripts: https://www.tech-otaku.com/web-development/using-cloudflare-api-manage-dns-records/#435

You can check out my YouTube channel if you prefer video content over written posts. Here’s the link to the video:

➡️ Step 1: Enable SSH service, permit root user login, and permit password login

** Note: you should make a backup of system configuration under System ‣ Configuration ‣ Backups in case things go south. You should be able to reverse any actions and restore the system to the known working state.

***This tutorial assumes that you already has an A record (or subdomain added on your Cloudflare DNS Records.

To enable the SSH server, permit root user login, and permit password login, navigate to System ‣ Settings ‣ Administration

Click Save when finished.

➡️ Step 2: Remote login to your OPNSense via SSH

Open Terminal or Command Prompt and login on using the below command:

└─$ ssh root@opnsense.sysadmin102.org
Last login: Sun Aug 27 09:40:46 2023 from 2603:8000:e700:80fb:7f08:1d41:7194:876c
|      Hello, this is OPNsense 23.7          |         @@@@@@@@@@@@@@@
|                                            |        @@@@         @@@@
| Website:      https://opnsense.org/        |         @@@\\\   ///@@@
| Handbook:     https://docs.opnsense.org/   |       ))))))))   ((((((((
| Forums:       https://forum.opnsense.org/  |         @@@///   \\\@@@
| Code:         https://github.com/opnsense  |        @@@@         @@@@
| Twitter:      https://twitter.com/opnsense |         @@@@@@@@@@@@@@@

*** OPNsense.sysadmin102.org: OPNsense 23.7.2 ***
  0) Logout                              7) Ping host
  1) Assign interfaces                   8) Shell
  2) Set interface IP address            9) pfTop
  3) Reset the root password            10) Firewall log
  4) Reset to factory defaults          11) Reload all services
  5) Power off system                   12) Update from console
  6) Reboot system                      13) Restore a backup

Enter an option: 8

You can substitute the Fully Qualified Domain Name (FQDN) with a valid IP Address.

Select Option 8 to open Shell

➡️ Step 3: Download the configd and bash script from github

3.1 Use the curl command to clone the script to your local folder /usr/home.

root@OPNsense:~ # cd /usr/home
root@OPNsense:/usr/home # curl -LJO https://raw.githubusercontent.com/nn0x96a/Cloudflare-Dynamic-DNS/main/Update_Cloudflare_Dynamic_IP.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   902  100   902    0     0   1948      0 --:--:-- --:--:-- --:--:--  1952
root@OPNsense:/usr/home # ls
root@OPNsense:/usr/home # 

3.2 Use cd command to change the directory to action.d folder

root@OPNsense:/usr/home # cd /usr/local/opnsense/service/conf/actions.d
root@OPNsense:/usr/local/opnsense/service/conf/actions.d #

3.3 Use the curl command to clone the actions_Cloudflare_DDNS.conf to your local folder

root@OPNsense:/usr/local/opnsense/service/conf/actions.d # curl -LJO https://raw.githubusercontent.com/nn0x96a/Cloudflare-Dynamic-DNS/main/actions_Cloudflare_DDNS.conf
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   219  100   219    0     0    458      0 --:--:-- --:--:-- --:--:--   459
root@OPNsense:/usr/local/opnsense/service/conf/actions.d # ls
actions_Cloudflare_DDNS.conf    actions_filter.conf             actions_openssh.conf
actions_acmeclient.conf         actions_firmware.conf           actions_openvpn.conf
actions_auth.conf               actions_health.conf             actions_proxy.conf
actions_captiveportal.conf      actions_ids.conf                actions_syslog.conf
actions_configd.conf            actions_interface.conf          actions_system.conf
actions_cron.conf               actions_ipfw.conf               actions_template.conf
actions_dhcpd.conf              actions_ipsec.conf              actions_unbound.conf
actions_dhcpd6.conf             actions_monit.conf              actions_webgui.conf
actions_dns.conf                actions_netflow.conf            actions_zfs.conf
root@OPNsense:/usr/local/opnsense/service/conf/actions.d #

**Note: If you store the Update_Cloudflare_Dynamic_IP.sh anywhere other than /usr/home, you will need to modify the actions_Cloudflare_DDNS.conf

3.4 Restart configd service

root@OPNsense:/usr/local/opnsense/service/conf/actions.d # service configd restart
Stopping configd...done
Starting configd.
root@OPNsense:/usr/local/opnsense/service/conf/actions.d # 

➡️ Step 4: Obtain the required parameters for the script

4.1 Use the cd command to get back to folder where the script located:

root@OPNsense:/usr/local/opnsense/service/conf/actions.d # cd /usr/home
root@OPNsense:/usr/home # ls
root@OPNsense:/usr/home # 

The following parameters need to be set for the script to work:

TOKEN="Replace with API Token"; \ 
ZONE_ID="Replace with Zone ID"; \
DNS_ID="Replace with DNS ID"; \
TYPE="A"; \
NAME="Replace with DNS Record Name"; \

4.2 Create a new API Token:

Follow the official guidance to create a new API Token: https://developers.cloudflare.com/fundamentals/api/get-started/create-token/

Copy the new API token to a text file.

4.3 Zone ID:

Follow the offical guidance to find your Zone ID: https://developers.cloudflare.com/fundamentals/get-started/basic-tasks/find-account-and-zone-ids/

4.4 DNS ID:

4.4.a Copy the below script to text file.

4.4.b Replace with your API Token created in step 4.2

4.4.c Replace Zone ID with your actual ID

Copy and paste the script to a new Terminal or Command Prompt.

└─$ TOKEN="********6dpaSHsHSuE7gyrjgu1Hzc********"; \
ZONE_ID="********7961c234582ace******"; \
TYPE="A"; \
PROXIED="false"; \
curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_ID" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \
    | python -m json.tool;
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2577    0  2516  100    61   3429     83 --:--:-- --:--:-- --:--:--  3510
    "result": [
            "id": "*****725c72dcd2bb1ebe****",
            "zone_id": "*****987961c234582aced*****",
            "zone_name": "sysadmin102.org",
            "name": "openvpn.sysadmin102.org",
            "type": "A",
            "content": "",
            "proxiable": true,
            "proxied": false,
            "ttl": 120,
            "locked": false,
            "meta": {
                "auto_added": false,
                "managed_by_apps": false,
                "managed_by_argo_tunnel": false,
                "source": "primary"
            "comment": null,
            "tags": [],
            "created_on": "2023-08-27T17:34:04.920836Z",
            "modified_on": "2023-08-27T21:07:01.019364Z"

In the above example, *****725c72dcd2bb1ebe**** is the DNS Record ID for subdomain openvpn.sysadmin102.org. That’s the subdomain that I want to point to my Dynamic IP at home.

➡️ Step 5: Modify and the script file

Modify the script file with the required parameter obtained in step 4 using Easy Text Editor (ee).

root@OPNsense:/usr/local/opnsense/service/conf/actions.d # cd /usr/home
root@OPNsense:/usr/home # ee Update_Cloudflare_Dynamic_IP.sh
#!/usr/bin/env sh

# Instructions on how to use this script:
# git clone https://github.com/nn0x96a/Cloudflare-Dynamic-DNS
# chmod 755 Update_Cloudflare_Dynamic_IP.sh
# Set the required parameters
# ./Update_Cloudflare_Dynamic_IP.sh
# SCRIPT: Update_Cloudflare_Dynamic_IP.sh
# Use: This script will update your DNS Record IP

#Set the below parameters:
TOKEN="********6dpaSHsHSuE7gyrjgu1Hzc********"; \
ZONE_ID="*****987961c234582aced*****"; \
DNS_ID="*****725c72dcd2bb1ebe****"; \
TYPE="A"; \
NAME="openvpn"; \
CONTENT="$(curl -s checkip.amazonaws.com)"; \
PROXIED="false"; \

curl -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_ID" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \

Once you done, Click ESC to escape to Menu. Enter to leave editor, and Enter to save changes.

➡️ Step 6: Create a new Cron Job to push Dynamic IP to Cloudflare

To setup a new Cron job go to System ‣ Settings‣ Cron and click Add on the bottom right corner of the form.

Click Save to add new Cron job.

Click Appy to aply the new changes.

With the below setting this Cron Job will run every minute. This is to force update right the way. You should change it to every 5 minutes or every hour.

I set my Cloudflare DNS IP to loopback IP: to see if the script is working. If it is, the new IP should reflect on DNS Records within minutes.

DNS Records 2 minutes later:

➡️ If you think this tutorial is helpful, please subscribe to my YouTube channel for more tutorials: https://www.youtube.com/@sysadmin102

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Translate »