Ostatnio jeden z „komentatorów” zainspirował mnie do nakręcenia wideo do wpisu dotyczącego zmiany duetu Apache2 + MOD-PHP na Apache2 + PHP-FPM. Tym razem jego „boje z no-ip.com” skłoniły mnie do przygotowania tego wpisu – czyli jak wykorzystać Cloudflare jako klienta DDNS (DNS dla dynamicznego IP).

Cloudflare jako Dynamic DNS (DDNS)

Wprawdzie na co dzień Cloudflare wykorzystuje jako „frontend” dla stron internetowych, to tym razem użyjemy tego serwisu w formie dynamicznego DNSa – korzystając z faktu, że właściwie każda zmiana w DNSach w ramach Cloudflare odbywa się w czasie rzeczywistym.

Dynamiczny adres IP, DDNS i własna domena

Gdy mamy publiczny i stały adres IP – sprawa jest prosta, w kilka(naście) minut możemy postawić u siebie serwer dostępny „z internetu”. Sytuacja trochę się komplikuje gdy wprawdzie mamy publiczny adres IP, ale jest on zmienny – jak np. w przypadku Neostrady.

W takiej sytuacji nadal możemy uzyskać „z internetu” dostęp do swojego serwera pod stałym adresem (domena/subdomena) korzystając z popularnych serwisów oferujących usługi pozwalające pod konkretną domenę/subdomenę podstawiać dynamicznie aktualny adres IP.

Własna domena

Często są to usługi bezpłatne, choć w takim wariancie nie możemy np. podpiąć własnej domeny – co dla niektórych z Was może być sporym minusem/problemem. W takim przypadku możecie przejść na konto „premium”, lub skorzystać z metody którą za chwilę przedstawię…

Cloudflare jako DNS z dynamicznie aktualizowanym adresem IP

Wykorzystanie Cloudflare w formie DDNS ma sporo zalet, m.in.:

  • Usługa w pełni bezpłatna (choć są pakiety płatne)
  • CDN (sieć serwerów serwujących kontent)
  • Dodatkowa ochrona (adresu IP, jak i serwera)
  • Dowolna ilość własnych domen (kierujących na serwer, nawet z dynamicznym IP)
  • Pełne wykorzystanie możliwości domeny (obsługa nie tylko rekordu A, ale i pozostałych)

To rozwiązanie ma też jedną – potencjalną – wadę, bo o ile:

  • Na komputerze domowym (jeśli ma robić jako serwer) możecie zainstalować klienta DDNS
  • Większość routerów posiada obsługę kilku serwisów DDNS

To w przypadku rozwiązania opartego na Cloudflare trzeba będzie skorzystać z dedykowanego skryptu – ale w końcu jest to przykład oparty na serwerze działającym na Raspberry Pi, więc i wymienione minusy są nam nie straszne. Nas nie dotyczą… ;-)

Aby przedstawione tu rozwiązanie działało domena musi być zarejestrowana, dodana do usługi Cloudflare i odpowiednio skonfigurowana (ustawione adresy serwerów DNS na podane przez Cloudflare podczas dodawania domeny).

W przypadku świeżo zarejestrowanych domen czasem trzeba poczekać 10-15 minut, aż odświeżą/zaktualizują się dane w rejestrze operatora danej domeny zanim będzie można dodać domenę do konta (komunikat o niezarejestrowanej domenie).

Należy też pamiętać, że zależnie m.in. od rejestratora domeny, czy ISP (dostawca internetu, u którego często znajdują się przypisane do łącza internetowego DNSy) zmiana adresów serwerów DNSów dla domeny na te od Cloudflare może zająć nawet 24-48 godzin.

Cloudflare API

By móc płynnie zmieniać IP dla rekordu A domeny skorzystamy z API Cloudflare, czyli będzie potrzebny klucza API – znajdziecie go w ustawieniach swojego konta:

cloudflare_account_api

Oprócz tego potrzebny będzie adres e-mail przypisany do konta – ale ten na pewno znacie… ;-)

CRON + cURL

Wykorzystamy tu też systemowe harmonogram zadań (CRON) i cURL – najprawdopodobniej macie w systemie, ale na wszelki wypadek:

sudo apt-get install cron
sudo apt-get install curl

Jeszcze tylko…

Zakładam, że serwer WWW lub np. VPN z którego chcecie korzystać za pośrednictwem domeny już jest gotowy do pracy. Oczywiście potrzebne będzie konto na Cloudflare i podpięta do niego domena – ale to chyba oczywiste… ;-)

Tyle teorii czy przygotowań, bierzemy się za „mięcho”, czyli skrypt:

Skrypt Cloudflare DDNS

Skrypt który przygotowałem może wydawać się rozbudowany, ale dzięki temu cała obsługa sprowadza się do modyfikacji kilku parametrów – a „zainteresowani” zawsze mogą wyciągnąć z niego odpowiednie fragmenty…


#!/bin/bash

# --------------------------------------------------
#
# ----- ---- --- Cloudflare DDNS --- ---- -----
#
# Code from: https://Webinsider.pl/cloudflare-ddns
#
# Cloudflare API DOC:
# https://www.cloudflare.com/docs/client-api.html
#
# --------------------------------------------------

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

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

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

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

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

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

CF_API_KEY= #insert here Your API key
CF_EMAIL= #insert here Your e-mail

DOMAIN= #insert here domain name
DOMAIN_RECORD_NAME= #insert here domain or subdomain name
CF_DOMAIN_REC_ID= #insert here record ID # First time read it - see below

CF_DOMAIN_READ_REC_ID=1 # 1 - ONLY read domain REC_ID, 0 - controls (changing) IP

CF_PROXY4RECORD=1 # Status of Cloudflare Proxy, 1 = orange cloud, 0 = grey cloud. 

if [ -z "$CF_API_KEY" ] || [ -z "$CF_EMAIL" ] || [ -z "$DOMAIN" ] || [ -z "$DOMAIN_RECORD_NAME" ]
then
	echo "Check script config!"
	exit 0
fi

if [ "CF_DOMAIN_READ_REC_ID" = "0" ] && [ -z "$CF_DOMAIN_REC_ID" ]
then
	echo "Check CF_DOMAIN_REC_ID"
	exit 0
fi

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

function f_cf_api_rec_load_all() {
	curl https://www.cloudflare.com/api_json.html \
		-d 'a=rec_load_all' \
		-d 'tkn='$CF_API_KEY \
		-d 'email='$CF_EMAIL \
		-d 'z='$DOMAIN
}

function f_cf_api_rec_edit() {
	curl https://www.cloudflare.com/api_json.html \
		-d 'a=rec_edit' \
		-d 'tkn='$CF_API_KEY \
		-d 'email'=$CF_EMAIL \
		-d 'z='$DOMAIN \
		-d 'id='$CF_DOMAIN_REC_ID \
		-d 'type=A' \
		-d 'name='$DOMAIN_RECORD_NAME \
		-d 'content='$IP_NOW \
		-d 'service_mode='$CF_PROXY4RECORD \
		-d 'ttl=1'
}

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

if [ "$CF_DOMAIN_READ_REC_ID" = "1" ]
then
	echo "Read CF DOMAIN REC_ID..."
	f_cf_api_rec_load_all
	exit 0
fi

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

if [ "$IP_CONTROL_LAST" = "1" ]
then
	if [ "$IP_NOW" != "$IP_LAST" ]
	then
		echo "New IP - changing..."
		echo $IP_NOW | sudo tee $IP_LOG > /dev/null
		f_cf_api_rec_edit
	else
		echo "IP is OK"
	fi
else
	echo "Changing IP..."
	echo $IP_NOW | sudo tee $IP_LOG > /dev/null
	f_cf_api_rec_edit
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 -O /ścieżka/do/zapisania/cloudflare_ddns

Konfiguracja skryptu

Konfiguracja skryptu sprowadza się do zmiany wartości kilku zmiennych:

  • IP_CONTROL_LAST – Gdy zmienna ma wartość „1” to po uruchomieniu skryptu następuje połączenie z serwerem w celu sprawdzenia aktualnego adresu IP (IP_NOW), po czym następuje jego porównanie z wcześniej zapisanym (IP_LAST) i dopiero jeśli te 2 wartości są różne – następuje wysłanie nowego adresu (IP_NOW) do Cloudflare. Gdy zmienna ma wartość „0” – adres IP jest wysyłany do Cloudflare przy każdym uruchomieniu skryptu, niezależnie od tego czy od ostatniego uruchomienia został zmieniony.
  • IP_CHECK_URL – Tu należy podać adres skryptu/strony wyświetlającej adres IP. W skrypcie są podane przykładowe, ale jeśli macie taką możliwość, to warto użyć własnego pliku. Więcej na ten temat za chwilę…
  • IP_NOW – Pobranie „z internetu” aktualnego adresu IP. W skrypcie są podane 2 przykładowe strony z których można pobrać adres IP w „czystej postaci” – możecie też podstawić tu własny adres…
  • IP_LOG – Adres (ścieżka) pliku służącego do zapisywania ostatniego adresu IP. Ma szczególne znaczenia gdy zmienna IP_CONTROL_LAST  ma wartość „1”.
  • IP_LAST – Adres IP pobierany z pliku IP_LOG
  • CF_API_KEY – Klucz API Waszego konta w Cloudflare
  • CF_EMAIL – E-mail przypisany do Waszego konta w Cloudflare
  • DOMAIN – Domena na której skrypt będzie pracował. W przypadku korzystania z subdomen w tym miejscu wpisujecie domenę, nie subdomenę.
  • DOMAIN_RECORD_NAME – Nazwa rekordu. W przypadku modyfikacji rekordu A dla domeny będzie to nazwa domeny, w przypadku modyfikowania rekordu A dla subdomeny będzie to nazwa subdomeny.
  • CF_DOMAIN_REC_ID – Jedna z ważniejszych zmiennych, dzięki której skrypt i Cloudflare wiedzą który rekord chcemy zmodyfikować. Więcej na ten temat za chwilę…
  • CF_DOMAIN_READ_REC_ID – Ustawiamy wartość na „1” gdy chcemy uzyskać CF_DOMAIN_REC_ID. W każdym innym przypadku wartość ustawiamy na „0”. Więcej na ten temat za chwilę…
  • CF_PROXY4RECORD – Włączenie (1) lub wyłączenie (0) usługi Cloudflare dla rekordu.

Sprawdzanie aktualnego IP

Wprawdzie możecie skorzystać z adresu podanego w skrypcie:

https://cdn.pryc.eu/add/myip.php

To jeśli macie taką możliwość – warto rozważyć skorzystanie z własnego plik/adresu… Bo zawsze „adres niezależny” może przestać istnieć, czy… A wystarczy na serwerze WWW – oczywiście nie tym z dynamicznym IP na którym działa skrypt – stworzyć plik PHP o takiej zawartości:

<?php
 echo $_SERVER['REMOTE_ADDR'];
?>

I jego adres ustawić dla zmiennej IP_CHECK_URL.

Odczyt ID wybranego rekordu

By odczytać ID rekordu uzupełniamy wszystkie niezbędne dane – oczywiście poza CF_DOMAIN_REC_ID którego jeszcze nie znamy – i ustawiamy wartość „CF_DOMAIN_READ_REC_ID” na „1”.

Następnie zapisujemy i uruchamiamy skrypt.

Jak konfiguracja nie zawiera żadnych błędów zobaczycie wynik podobny do tego:

cloudflare_ddns_api_skrypt01

To wynik dla domeny z tylko 3 rekordami, więc przy bardziej rozbudowanych konfiguracjach DNS będzie tego więcej – ale tylko wygląda to strasznie… ;-)

To co nas interesuje to pozycja „rec_id” występująca tuż przed „rec_hash” i „zone_name” interesującego nas rekordu.

Wartość z „rec_id” wpisujemy jako wartość zmiennej CF_DOMAIN_REC_ID i ustawiamy „CF_DOMAIN_READ_REC_ID” na „0”.

Kilka regułek „kontrolnych”

W skrypcie znalazło się kilka regułek kontrolnych, którym zadaniem jest sprawdzanie, czy wszystkie niezbędne pola zostały odpowiednio wypełnione/skonfigurowane.

Jeśli coś będzie nie tak – dostaniecie stosowną informację…

Działanie skryptu

Oczywiście skrypt trzeba gdzieś zapisać, ja w przypadku Raspberry Pi wszystkie skrypty trzymam w katalogu:

/boot/bin

który jest „podlinkowany” jako „bin” w katalogu każdego użytkownika, dzięki czemu skrypt można wywołać bez potrzeby wpisywania całej ścieżki.

Dodatkową zaletą trzymania skryptów na partycji „boot” jest to, że jest ona w formacie FAT32, a więc można odczytać i modyfikować znajdujące się na niej pliki właściwie na każdym komputerze, a nawet smartfonie (OTG).

Po wywołaniu skonfigurowanego skryptu – zależnie od konfiguracji – sprawdza on (lub nie) adres IP, i gdy trzeba przesyła odpowiednią komendę do Cloudflare w celu jego aktualizacji:

cloudflare_ddns_api_skrypt02

Może się zdarzyć, że system nie będzie chciał uruchomić pliku – w tym celu należy skorzystać z polecenia:

sudo chmod +x /ścieżka/do/pliku/cloudflare_ddns

Harmonogram (CRON)

Oczywiście naszym celem jest automatyzacja całego procesu, dlatego warto skonfigurować systemowy harmonogram (CRON) do wywoływania skryptu o określonej godzinie, czy co określony przedział czasu.

Z racji tego, że już kiedyś pisałem artykuł poświęcony temu tematowi – odsyłam do niego…

(!) 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