Kilka lat temu napisałem artykuł (i skrypt) opisujący wykorzystanie serwisu Cloudflare jako serwisu DDNS (Dynamic DNS). Oczywiście tego typu serwisów (Dynamic DNS) jest sporo, ale w większości przypadków za dodatkowe opcje – np. podpięcie własnej domeny – trzeba płacić. A po co to robić, jeśli w tym celu można wykorzystać właśnie usługę Cloudflare. Wspomniany artykuł opiera się na API w wersji 1, i choć u znajomego (jak i u mnie, podczas choćby dzisiejszych testów) nadal działa, to pojawiają się w komentarzach informacje, że nie u każdego tak jest. Dlatego postanowiłem zaktualizować skrypt do nowej wersji API (v4), przy okazji modyfikując niektórego jego założenia/funkcje…

Cloudflare (API v4) jako Dynamic DNS (DDNS)

Wprawdzie ten artykuł może być traktowany jako samodzielny byt, to jednak zachęcam do przeczytania jego „starszej wersji”, gdzie oprócz informacji o samym skrypcie i jego działaniu (tu akurat będzie trochę zmian) pisałem również o całej otoczce, towarzyszących usługach, wymaganiach systemowych, poleceniach czy programach…

Założenia skryptu pozostały bez zmian – w wybranych odstępach czasu (np. za pomocą usługi CRON) skrypt sprawdza aktualne publiczne IP (wykorzystuje zewnętrzne usługi), który następnie podstawia pod wybraną domenę lub subdomenę, skonfigurowaną na naszym koncie Cloudflare:

#!/bin/bash

# --------------------------------------------------
#
# ----- ---- --- Cloudflare DDNS --- ---- -----
#
# Code from: https://Webinsider.pl/cloudflare-ddns-api4
#
# Cloudflare API DOC:
# https://api.cloudflare.com/
#
# --------------------------------------------------

IP_CONTROL_LAST=1 # 1 - check the latest IP (file $IP_LOG_FILE), 0 - always sends the new IP

# Use Your fav IP chceck URL:
IP_CHECK_URL=
# e.g.:
# https://cdn.pryc.eu/add/myip.php

IP_LOG_FILE=/boot/last-ip.txt # Last IP LOG file

CF_API_KEY= # CF API KEY
CF_EMAIL= # CF E-mail

DOMAIN= # Domain
DOMAIN_RECORD_NAME= # Domain or subdomain to set IP

CF_RECORD_PROXIED=true # Whether the record is receiving the performance and security benefits of Cloudflare, valid values: true,false

CF_ZONE_ID= # CF Zone ID for selected domain
CF_REKORD_ID= # CF Record (domain/subdomain) ID


# Basic config test
if [[ ! $IP_CHECK_URL ]] || [[ ! $CF_API_KEY ]] || [[ ! $CF_EMAIL ]] || [[ ! $DOMAIN ]] || [[ ! $DOMAIN_RECORD_NAME ]] || [[ ! $CF_RECORD_PROXIED ]] || [[ ! $IP_LOG_FILE ]]
then
 echo "First set: IP_CHECK_URL, CF_API_KEY, CF_EMAIL, DOMAIN DOMAIN_RECORD_NAME, CF_RECORD_PROXIED, IP_LOG_FILE"
 exit 0
fi


# Start oprions: Basic config (ZONE ID, REKORD ID)

START_OPTION=$1

if [ "$START_OPTION" = "CF_ZONE_ID" ]
then
 curl -X GET "https://api.cloudflare.com/client/v4/zones?name="$DOMAIN"&status=active&page=1&per_page=20&order=status&direction=desc&match=all" \
 -H "X-Auth-Email: "$CF_EMAIL \
 -H "X-Auth-Key: "$CF_API_KEY \
 -H "Content-Type: application/json"
 exit 0
fi

if [ "$START_OPTION" = "CF_REKORD_ID" ]
then 
 curl -X GET "https://api.cloudflare.com/client/v4/zones/"$CF_ZONE_ID"/dns_records?page=1&per_page=20&order=type&direction=desc&match=all" \
 -H "X-Auth-Email: "$CF_EMAIL \
 -H "X-Auth-Key: "$CF_API_KEY \
 -H "Content-Type: application/json"
 exit 0
fi


# ZONE config test
if [[ ! $CF_ZONE_ID ]]
then
 echo "First run: script_name CF_ZONE_ID"
 echo "E.g.: cloudflare-ddns CF_ZONE_ID"
 echo "Next set it in script"
 exit 0
fi

if [[ ! $CF_REKORD_ID ]]
then
 echo "First run: script_name CF_REKORD_ID"
 echo "Eg: cloudflare-ddns CF_REKORD_ID"
 echo "Next set it in script"
 exit 0
fi


if [ -z "$IP_CHECK_URL" ]
then
 echo "IP_CHECK_URL is empty!"
 exit 0
else
 IP_NOW=`wget -O - -q $IP_CHECK_URL` # Get current IP, if IP_CONTROL_LAST=1 
fi
 

if [ ! -f $IP_LOG_FILE ] && [ "$IP_CONTROL_LAST" = "1" ]
then
 sudo touch $IP_LOG_FILE
fi

if [ $IP_LOG_FILE ] && [ "$IP_CONTROL_LAST" = "1" ]
then
 IP_LAST=$(cat $IP_LOG_FILE)
fi

# --------------------------------------------------

function f_cf_api_change_ip() {

 curl -X PUT "https://api.cloudflare.com/client/v4/zones/"$CF_ZONE_ID"/dns_records/"$CF_REKORD_ID \
 -H "X-Auth-Email: "$CF_EMAIL \
 -H "X-Auth-Key: "$CF_API_KEY \
 -H "Content-Type: application/json" \
 --data '{"type":"A","name":"'$DOMAIN_RECORD_NAME'","content":"'$IP_NOW'","proxied":'$CF_RECORD_PROXIED'}'

}

if [ "$IP_CONTROL_LAST" = "1" ]
then
 if [ "$IP_NOW" != "$IP_LAST" ]
 then
 echo "New IP - changing..."
 echo $IP_NOW | sudo tee $IP_LOG_FILE > /dev/null
 f_cf_api_change_ip 
 else 
 echo "IP is OK"
 fi
else
 echo "Changing IP..."
 echo $IP_NOW | sudo tee $IP_LOG_FILE > /dev/null
 f_cf_api_change_ip 
fi

exit 0

Skrypt możecie skopiować z „listingu” powyżej, lub – chyba bezpieczniej – pobrać z tego adresu. Ew możecie pobrać do bezpośrednio na serwer za pomocą komendy:

wget https://webinsider.pl/add/download/?link=cloudflare_ddns_api4 -O /ścieżka/do/zapisania/cloudflare-ddns

Pamiętajcie, by nadać mu atrybuty wykonywalności:

sudo chmod 755 /ścieżka/do/pliku/cloudflare-ddns

W tym momencie można przystąpić do pierwszej, podstawowej konfiguracji:

  • IP_CONTROL_LAST – czy skrypt ma aktualizować adres IP w Cloudflare tylko, gdy się zmienił (1), czy zawsze (0)
  • IP_CHECK_URL – adres serwisu, gdzie można sprawdzić aktualny adres IP (publiczny)
  • IP_LOG_FILE – plik, gdzie skrypt przechowuje ostatni adres IP (do porównania czy się zmienił)
  • CF_API_KEY – klucz API z serwisu Cloudflare
  • CF_EMAIL – adres e-mail powiązany z kontem w Cloudflare
  • DOMAIN – domena, z której będziemy korzystać
  • DOMAIN_RECORD_NAME – rekord, z którego będziemy korzystać w ramach wybranej domeny (domena lub subdomena)
  • CF_RECORD_PROXIED – czy rekord ma być chroniony przez usługę Cloudflare, czy ruch ma być przepuszczany swobodnie

Od jednego z czytelników dostałem sugestie, by przy poleceniu „wget” dodać parametr wymuszający połączenie po IP4 do skrytpu, z którego pobierany jest adres:

Dopisz w skrypcie do wget parametr -4 lub –inet4-only. Chodzi o to, żeby wymusić połączenie po IPv4, żeby dostać adres IPv4, a nie IPv6. Przydatne jak ktoś korzysta z tunelu IPv6 albo jakimś cudem dostał dual stack z dynamicznym IPv4 + IPv6

W skrypcie takiej modyfikacji na razie nie będę dodawał, bo może być tak, że ktoś ma tylko IPv6, ale na pewno jest to sugestia, którą warto rozważyć. Zwłaszcza że w przypadkach opisywanych przez Michała (tak ma na imię) może to być nie tylko pomocne, ale i wymagane…

Gdy powyższe zmienne są skonfigurowane (niektóre są uzupełnione wartościami domyślnymi, niektóre trzeba samemu uzupełnić) uruchamiamy skrypt z parametrem CF_ZONE_ID (chyba że znamy ID strefy):

/ścieżka/do/pliku/cloudflare-ddns CF_ZONE_ID

Dzięki czemu uzyskamy ID całej strefy związanej z domeną, który wprowadzamy do skryptu CF_ZONE_ID).

Kolejnym krokiem jest uzyskanie ID konkretnego rekordu, a więc uruchamiamy kolejny raz skrypt, tym razem z parametrem CF_REKORD_ID (chyba że znamy ID wybranego rekordu):

/ścieżka/do/pliku/cloudflare-ddns CF_REKORD_ID

Uzyskany identyfikator rekordu (ID) dla domeny lub wybranej subdomeny również wprowadzamy do skryptu (CF_REKORD_ID).

W tym momencie skrypt jest już gotowy do pracy. Wystarczy skorzystać z polecenia:

/ścieżka/do/pliku/cloudflare-ddns 

Oczywiście warto to zautomatyzować, korzystając z systemowego harmonogramu zadań (CRON).

(!) Zgłoś błąd na stronie
Pomogłem? To może postawisz mi wirtualną kawę?
LUTy dla D-Cinelike (DJI Mini 3 Pro, DJI Avata, OSMO Pocket) od MiniFly
Wdrożenie Omnibusa w sklepie na WooCommerce
Jak (legalnie) latać dronem w Kategorii Otwartej
Patryk