Cloudflare Registrar is a cost price domain registrar offering cheap domain transfers and registrations. However, at one point you may need to transfer many domains out of Cloudflare Registrar to another registrar – offering discount domain transfer pricing or specials. This guide will show you how to bulk transfer out the domains via Cloudflare Registrar API via command line or scripting.
Cloudflare Registrar offers a GUI based dashboard method for unlocking your domain and obtaining your EPP or AUTH code. If you have a few domains that should suffice. However, if you have hundreds of domains within Cloudflare Registrar for your Cloudflare Account, manually unlocking and obtaining your EPP/AUTH code for each domain will be time consuming. Cloudflare Registrar API allows you to programmatically script the process for unlocking your domains and obtaining your EPP/AUTH codes. Note, if you are looking to bulk transfer domains into Cloudflare Registrar, check out the guide here.
However, there’s a few undocumented commands not listed in the current version of the documentation (as at February 28, 2021) for obtaining the EPP/AUTH code which I will outline below as well.
- Step 1. Obtain your Cloudflare Account Global API Key & Account ID
- Step 2. Install jq JSON Tool
- Step 3. Populating Variables On SSH Command Line/Shell Scripts
- Step 4. Bulk Disable DNSSEC For Domains
- Step 5. Bulk Unlock & Obtain EPP/AUTH Code For Cloudflare Domains
- Step 6. Bulk Fast-Track Transfer Approvals
Step 1. Obtain your Cloudflare Account Global API Key & Account ID
Cloudflare Registrar API currently does not support Cloudflare API Tokens. So you will need to obtain your Cloudflare Account Global API Key from https://dash.cloudflare.com/profile/api-tokens. Then you’ll also need to obtain your Cloudflare Account ID via any of your domain’s dashboard right side column which lists your zone id and your account id. These two items will be used to populate variables on the SSH command line or via bash shell scripts you can write to run on Linux command line.
Step 2. Install jq JSON Tool
Install jq JSON tool which allows you to manipulate and filter Cloudflare Registrar API’s JSON output
yum -y install jq
or
apt-get install jq
Step 3. Populating Variables On SSH Command Line/Shell Scripts
You’ll need to populate the following variables with your Cloudflare Account ID, Cloudflare Account Global API Key, Cloudflare Account Email address and Cloudflare endpoint variables. Then on the command line in SSH session type or copy and paste them or set within your own shell scripts.
cfaccountid=your_cf_account_id cftoken=your_cf_global_api_token cfemail=your_cf_account_email_address endpoint=https://api.cloudflare.com/client/v4/ endpoint_target=accounts/$cfaccountid/registrar/domains
If you use curl command line to query Cloudflare Registrar API with this command below, you will return just all the domain names that are registered with Cloudflare Registrar. The below command will save all the domains in text file cfregistrar-domains.txt
.
curl -4sX GET "${endpoint}${endpoint_target}" -H "Content-Type:application/json" \ -H "X-Auth-Email: $cfemail" \ -H "X-Auth-Key: $cftoken" | jq -r '.result[].name' | tee cfregistrar-domains.txt domain.com domain.net
Then edit text file cfregistrar-domains.txt
and remove any domain names that you do not want to transfer out. Leaving just a list of domains you want to transfer out.
Step 4. Bulk Disable DNSSEC For Domains
To ensure domain transfers go smoothly, we’ll bulk disable DNSSEC for the domains via Cloudflare DNSSEC API end point for https://api.cloudflare.com/client/v4/zones/ZONEID/dnssec
. To do this we need to associated ZONEID for each domain name contained in previously populated cfregistrar-domains.txt
text file.
The below for loop run querying the Cloudflare API will save each domain’s ZONEID and domain name to their own file zoneid-domainname.log
for domain in $(cat cfregistrar-domains.txt); do endpoint=https://api.cloudflare.com/client/v4/ endpoint_target="zones/?name=${domain}&status=active&page=1&per_page=50&order=status&direction=desc&match=all" zid=$(curl -4sX GET "${endpoint}${endpoint_target}" -H "Content-Type:application/json" -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" | jq -r --arg d $domain '.result[] | select(.name == $d) | .id') echo "$zid $domain" | tee "zoneid-${domain}.log" done
Then save the concatenated output for the zoneid files to zoneid-domains-list.log
:
cat zoneid-*.log > zoneid-domains-list.log
The file will contain:
cat zoneid-domains-list.log zoneid1 domain.com zoneid2 domain.net
Check DNSSEC status
Now to do a while read loop reading the ZONEID and domain name to query the Cloudflare DNSSEC API end point to get the current DNSSEC status for each domain which is saved to file dnssec-${domain}.log
. The DNSSEC status will either be enabled, disabled or pending-disabled.
cat zoneid-domains-list.log | while read zid domain; do endpoint=https://api.cloudflare.com/client/v4/ endpoint_target="zones/${zid}/dnssec" dnssec_status=$(curl -4sX GET "${endpoint}${endpoint_target}" -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" -H "Content-Type: application/json" | jq -r '.result.status') echo "$domain $dnssec_status" | tee "dnssec-${domain}.log" done
Example output:
domain.com pending-disabled domain.net disabled
Disable DNSSEC
Then disable DNSSEC using another while read loop saving each API query’s result to file disable-dnssec-${domain}.log
cat zoneid-domains-list.log | while read zid domain; do endpoint=https://api.cloudflare.com/client/v4/ endpoint_target="zones/${zid}/dnssec" echo "$domain" curl -4sX PATCH "${endpoint}${endpoint_target}" \ -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" \ -H "Content-Type: application/json" --data '{"status":"disabled"}' | jq -r | tee "disable-dnssec-${domain}.log" done
Example output below is where DNSSEC has already been disabled:
domain.com { "result": null, "success": false, "errors": [ { "code": 1004, "message": "DNSSEC is already disabled" } ], "messages": [] } domain.net { "result": null, "success": false, "errors": [ { "code": 1004, "message": "DNSSEC is already disabled" } ], "messages": [] }
Disabling DNSSEC will take some time on Cloudflare’s end and isn’t immediate. So best to recheck DNSSEC status again before proceeding to the next step – ensuring all domains return a disabled DNSSEC status.
Step 5. Bulk Unlock & Obtain EPP/AUTH Code For Cloudflare Domains
Here we’ll be using a bash shell for loop iterating through a list of domain names returned from Cloudflare Registrar API end point for https://api.cloudflare.com/client/v4/accounts/$cfaccountid/registrar/domains
and then unlocking each domain, resetting the EPP/AUTH code and then querying and printing out the domain name and EPP/AUTH code in a format that is ready for bulk domain registrar transfers to other domain registrars like Namesilo, Namecheap, Internet.bs, Porkbun and GoDaddy.
First, we’ll populate the domains bash array using step 3 populated cfregistrar-domains.txt
file.
domains=$(cat cfregistrar-domains.txt)
If you echo the output of the domains bash array, it would be something like below:
echo ${domains[@]} domain.com domain.net
Now the for loop that does all the domain unlocking and EPP/AUTH code retrieval. You’ll either be scripting this is a shell script or running the entire code as one command via copy and paste into SSH command line.
It will loop through the above domains bash array and for each domain name returned it will:
- unlock the domain and save CF API output to log file
${d}-unlock.log
where${d}
is your domain name. - will save domain’s reset EPP/AUTH code to log file at
${d}-reset-auth.log
where${d}
is your domain name. This and the next step are not outlined in current Cloudflare Registrar API documentation which only outlines how to unlock the domain. - save full domain registrar info to
${d}-get-auth.log
log where${d}
is your domain name and - only the domain and EPP/AUTH code properly formatted in
${d}-get-auth-summary.log
where${d}
is your domain name. - these logs will be all saved in same working directory you run the commands from or run your shell script from
for d in ${domains[@]}; do domain=$d endpoint=https://api.cloudflare.com/client/v4/ endpoint_target=accounts/$cfaccountid/registrar/domains/$d # unlock echo echo "unlock: $d" echo curl -4sX PUT "${endpoint}${endpoint_target}" -H "Content-Type:application/json" \ -H "X-Auth-Email: $cfemail" \ -H "X-Auth-Key: $cftoken" --data '{"locked":false}' | tee ${d}-unlock.log | jq echo "saved: ${d}-unlock.log" # reset auth code echo "reset auth code: $d" echo curl -4sX PUT "${endpoint}${endpoint_target}" -H "Content-Type:application/json" \ -H "X-Auth-Email: $cfemail" \ -H "X-Auth-Key: $cftoken" --data-raw '{"reset_auth_code":true}' | tee ${d}-reset-auth.log | jq echo "saved: ${d}-reset-auth.log" # obtain auth code echo "obtain auth code: $d" echo curl -4sX GET "${endpoint}${endpoint_target}" -H "Content-Type:application/json" \ -H "X-Auth-Email: $cfemail" \ -H "X-Auth-Key: $cftoken" | tee ${d}-get-auth.log | jq -r '.result | "\(.name) \(.auth_code)"' | tee ${d}-get-auth-summary.log echo "saved: ${d}-get-auth.log" done
Example output from for loop which iterated over domain.com and domain.net domains.
unlock: domain.com { "result": { "message": "Domain updates complete!" }, "success": true, "errors": [], "messages": [] } saved: domain.com-unlock.log reset auth code: domain.com { "result": { "message": "Domain updates complete!" }, "success": true, "errors": [], "messages": [] } saved: domain.com-reset-auth.log obtain auth code: domain.com domain.com 3-2-HP0-oIbu-9Hb saved: domain.com-get-auth.log unlock: domain.net { "result": { "message": "Domain updates complete!" }, "success": true, "errors": [], "messages": [] } saved: domain.net-unlock.log reset auth code: domain.net { "result": { "message": "Domain updates complete!" }, "success": true, "errors": [], "messages": [] } saved: domain.net-reset-auth.log obtain auth code: domain.net domain.net iZY-ErqP--6n2-50 saved: domain.net-get-auth.log
Now each domain would of saved a log file named ${d}-get-auth-summary.log
. You can concatenate them to show all domains and their EPP/AUTH code in a format you can use to bulk domain transfer to another domain registrar like Namesilo, Namecheap, Internet.bs, Porkbun and GoDaddy.
ls -lrt *-get-auth-summary.log -rw-r--r-- 1 root root 33 Feb 28 08:00 domain.com-get-auth-summary.log -rw-r--r-- 1 root root 33 Feb 28 08:00 domain.net-get-auth-summary.log
cat *-get-auth-summary.log domain.com 3-2-HP0-oIbu-9Hb domain.net iZY-ErqP--6n2-50
If in future you need to transfer domains back to Cloudflare Domain Registrar, you can also use the Cloudflare API to do such as outlined in examples for Namecheap and Namesilo transfer to Cloudflare Registrar here. I’ll update this guide with further examples in the future so check back frequently.
Step 6. Bulk Fast-Track Transfer Approvals
Once you initiate the domain transfers at your new domain registrar, Cloudflare will send an email for each domain you’re transferring out outlining that it will take up to 5 days to transfer out.
Outbound Domain Transfer Initiated
Hi,
Domain: domain.com
Cloudflare Registrar received an authenticated request to transfer the domain listed above to another registrar.
You do not need to respond to this message to confirm your transfer away. Cloudflare will automatically release the domain to your new registrar five days after your request. Want to finish the transfer earlier? You can manually approve the request immediately in the Overview page of the Cloudflare dashboard for your domain.
If you want to cancel this transfer and stay with Cloudflare, you must visit the Overview page of the dashboard and select “Reject Transfer Out” from your options within the next five days.
On behalf of the Cloudflare team, we are sorry that we will no longer be providing registrar services for your domain
However, you can manually fast-track the domain transfer if you go to each domain’s management configuration page and hit the approve transfer button. Of course, if you have many domains being transferred out, it would take forever! The official Cloudflare API doesn’t document any way to use the API to approve each domain transfer out. But an undocumented API endpoint and query seem to work so you can bulk approve all your domain transfers as outlined below.
Approve Transfer Requests
The undocumented endpoint is at https://api.cloudflare.com/client/v4/zones/ZONEID/registrar/domains/DOMAINNAME/transfer_out
where you send a POST
request with the payload {"operation":"approve"}
.
Using a while read loop piping in the previously generated zoneid-domains-list.log
file:
cat zoneid-domains-list.log | while read zid domain; do endpoint=https://api.cloudflare.com/client/v4/ endpoint_target="zones/${zid}/registrar/domains/${domain}/transfer_out" echo "$domain" curl -4sX POST "${endpoint}${endpoint_target}" \ -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" \ -H "Content-Type: application/json" --data '{"operation":"approve"}' | jq -r | tee "approve-transfer-${domain}.log" done
Example out:
domain.com { "result": { "message": "Transfer request approved" }, "success": true, "errors": [], "messages": [] } domain.net { "result": { "message": "Transfer request approved" }, "success": true, "errors": [], "messages": [] }
If you already manually approved the transfer via the dashboard, then you’d get the following output:
{ "result": { "message": "You are not allowed to perform this action" }, "success": true, "errors": [], "messages": [] }
Now you should get an email from Cloudflare confirming approval of the domain transfers.
Domain Transfer Approved
Hi,
We have received your approval to transfer domain.com away from Cloudflare Registrar. We will begin the process of transferring the domain to your new registrar now.
If you have questions, please contact support@cloudflare.com.
The Cloudflare Registrar team