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).
- Home Assistant 2024.11, czyli „sekcje” domyślnym widokiem z opcją migracji, WebRTC oraz wirtualna kamera - 1970-01-01
- Black Friday w ZUS, czyli jest jeszcze kilka dni, by złożyć wniosek RWS i skorzystać z wakacji składkowych płacąc ZUS za grudzień 2024 - 1970-01-01
- Wakacje składkowe ZUS a zawieszenie działalności gospodarczej, czyli uważaj, bo być może nie będziesz mógł skorzystać (w 2024) - 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.
Witam,
Próbuję skonfigurować skrypt do DDNS na Cloudflare.
Wydaje mi się, że wszystkie parametry mam poprawnie,
ale zwrotnie otrzymuję:
Sorry, you have been blocked
You are unable to access http://www.cloudflare.com
W komunikacie błędu masz wszystko, co pewnie musisz mieć: z jakiegoś pwoodu zostałeś zablokowany (pewnie IP). Spróbuj na innym IP, albo pisz do Cloudflare, z prośbą, by Cię odblokowali. Przy okazji zapytaj, czemu zablokowali, byś mógł uniknąć tego w przyszłości.
Tak szybkiej odpowiedzi się nie spodziewałem – szacun.
Chyba znalazłem problem – robiłem to starym skryptem.
Teraz użyłem tego do API4 i już było OK.
Wygląda na to, że to stare IP już nie działa? Nieważne. v4 – działa.
Zobaczę jak to będzie w praktyce, bo na razie mam jeszcze przez jakiś czas usługę ze stałym IP (UPC), ale niedługo zmieniam ze względu na niestabilność (odkąd przejął ich Play)
Natomiast jak w uprawnieniach dasz wszystko OK, to nie powinni odcinać. Mi przez lata jeszcze się nie zdażyło. Ba, nawet podczas testów, gdy nie zawsze wszystko „się udaje”, nigdy nie odcięli. Ale jak próbowałeś starego API, to masz odpowiedź. Dlatego pojawił się kolejny artykuł na ten temat, z nową wersją skryptu, właśnie dla API V4, czyli ten, pod którym są te komentarze :-)
Zasugerowałem się postami z 2022, że stary API też działa :)
A jeszcze taki drobiazg – mam dwa rekordy A DNS – jeden dla domeny, drugi dla poddomeny www.
Czy wystarczy zmienić tylko ten dla domeny, czy trzeba uruchamiać drugi raz skrypt (a właściwie kopię, skonfigurowaną dla drugiego rekordu) ?.
Wielkie podziękowania za opis usługi i gotowy skrypt – bardzo mi to ułatwi dostęp do „Malinki” z zewnątrz.
Jak subdomena ma inny rekord niż główna domena i chcesz go zmienić, to też musisz wysłać takie „zgłoszenie”. Natomiast jak subdomena „www” i tak wskazuje na domenę główną (zazwyczaj tak jest), to być może lepiej ustawić subdomenę „www” jako CNAME, kierujące na domenę główną. Wtedy jak ktoś wpisze http://www.domena (np. http://www.webinsider.pl), to trafi na domena (np. webinsider.pl).