How to disable (or enable) IPv6 AAAA records added by CloudFlare


I was surprised to find that CloudFlare created AAAA records for my domains when my server doesn't support IPv6 at all. Reading the CloudFlare community I found the only way to disable the "feature" is via the API.

I might have left the records turned on, as a few people advised, but ran into a couple problems on my VPS that forced my hand. In my case fail2ban was banning CloudFlare IPs of bots hitting my WordPress wp-login.php pages due to a special jail I set up. To stop that I installed mod_remoteip for apache as recommended to get the proper client IP address instead of the CloudFlare proxy address. Then I found I was getting IPv6 IPs in my website logs. My server and fail2ban can only handle IPv4, and I didn't want to add IPv6 support to fail2ban just for CloudFlare, so I disabled the IPv6 AAAA records using the CloudFlare API.

I made a bash shell script so I could do it again easily in the future, which I'm happy to share below. The following script can disable (or enable) AAAA records on all (or one) of your CloudFlare domains in your account. Copy it into a file and execute it. You should install the utilities curl and jq first, e.g. with sudo apt-get install curl jq on Ubuntu. Your email address and API key are not stored in the script or on the server for maximum security.

#!/bin/bash
# Turn CloudFlare AAAA records on or off
echo "Enter CloudFlare account email:"
read EMAIL
echo "Enter key from Dashboard > My Profile > API Tokens > Global API Key:"
read KEY
# https://api.cloudflare.com/#zone-list-zones
curl -s -X GET "https://api.cloudflare.com/client/v4/zones" \
	-H "X-Auth-Email: $EMAIL" \
	-H "X-Auth-Key: $KEY" \
	-H "Content-Type: application/json" \
	> /tmp/cf-tmp
jq -r '.result[] | .id + " " + .name' /tmp/cf-tmp > /tmp/cf-zones
rm /tmp/cf-tmp
I=1
for NAME in $(cat /tmp/cf-zones | awk '{print $2}'); do
	echo $I. $NAME
	let I+=1
done
echo "$I. ALL"
echo -n "Choose domain to modify [$I]: "
read SELECT
ZONES=()
if [ -z "$SELECT" ] || [ "$SELECT" -eq "$I" ]; then
	SELECT=$I
	while read LINE; do ZONES+=("$LINE"); done < /tmp/cf-zones
else
	ZONES+=("$(sed "${SELECT}q;d" /tmp/cf-zones)")
fi
echo "Selected: $SELECT"
echo "What do you want to do with the AAAA records?"
echo "1. Turn off"
echo "2. Turn on"
echo -n "Make a selection [1]: "
read SELECT
if [ -z "$SELECT" ] || [ "$SELECT" -eq "1" ]; then SELECT=1; VAL=off; else VAL=on; fi
echo "Selected: $SELECT"
for ((I = 0; I < ${#ZONES[@]}; I++)); do
	ID=$(echo ${ZONES[$I]} | awk '{print $1}')
	NAME=$(echo ${ZONES[$I]} | awk '{print $2}')
	echo -n "Turning $VAL AAAA records for $NAME... "
	# https://api.cloudflare.com/#zone-settings-change-ipv6-setting
	curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$ID/settings/ipv6" \
     	-H "X-Auth-Email: $EMAIL" \
     	-H "X-Auth-Key: $KEY" \
     	-H "Content-Type: application/json" \
     	--data "{\"value\":\"$VAL\"}" > /tmp/cf-tmp
	if [ "`jq .success /tmp/cf-tmp`" == "true" ]; then
		echo "OK";
	else
		echo "ERROR:"
		cat /tmp/cf-tmp
	fi
done
rm /tmp/cf-tmp
rm /tmp/cf-zones