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).

- Kolejna odsłona walki ze współdzieleniem kont w Netflixie, czyli (internetowe) gospodarstwo domowe Netflix - 1970-01-01
- Nowe wytyczne prezesa ULC w sprawie Krajowego Scenariusza Standardowego NSTS-01 i loty FPV, czyli nowe ograniczenia - 1970-01-01
- Brak akceptacji nowego regulaminu w przeciągu 3 dni, będzie skutkowało nałożeniem tymczasowej blokady konta Allegro, czyli kolejna próba wyłudzenia danych logowania - 1970-01-01
Dzień dobry,
W moim przypadku skrypt zadziałał tak się spodziewałem po pierwszym wykonaniu stąd mam kilka pytań odnośnie działania skryptu.
Czy skrypt powinien edytować istniejące wpisy? Skrypt po jego wykonaniu utworzył nowy wpis w cloudflare czy tak on powinien działać?
W przypadku wykorzystywania kilku subdomen jest możliwe można dokonać aktualizacji IP za pomoca jednego skryptu czy nalezy utworzyć i wykonać osobno skrypty dla każdej z subdomen?
Z założenia skrypt edytuje istniejący wpis, bo w innym miejscu na ten wpis /adres URL/ się powołujesz, właśnie na tym polega DDNS, że masz adres, a jego IP się zmienia dynamicznie. Co do kilku domen/subdomen można za pomocą jednego skryptu, ale trzeba by go przerobić, tak by np. w parametrach uruchomienia był ID strony/strefy. Ale można też użyć kilku kopii tego skryptu.