Od czego się zaczęło?
Na serwisach pojawił się błąd:
Error 522
Connection timed out
W świecie Cloudflare oznacza to mniej więcej tyle:
Cloudflare działa. DNS działa. Ale Cloudflare nie może dogadać się z serwerem źródłowym.
Czyli użytkownik wchodzi na domenę, trafia do Cloudflare, Cloudflare próbuje połączyć się z moim serwerem, ale serwer pod wskazanym adresem IP nie odpowiada tak, jak powinien.
Pierwsze podejrzenie było proste: operator zmienił publiczne IP.
I tutaj zaczyna się zabawa.
Publiczne IP — rzecz niby oczywista, dopóki nie przestaje być oczywista
W klasycznym hostingu albo VPS-ie zwykle mamy przypisany stały adres IP. Ustawiasz rekord A w DNS, wskazujesz na serwer i temat jest względnie stabilny.
W homelabie bywa inaczej.
Jeżeli serwer stoi w domu, firmie, garażu, warsztacie albo — jak w tym przypadku — gdzieś lokalnie na fizycznym sprzęcie, to publiczne IP może zależeć od operatora. Może być stałe, może być dynamiczne, może się zmienić po restarcie routera, po odnowieniu dzierżawy, po pracach operatora albo wtedy, kiedy akurat najmniej tego chcesz.
A rekordy DNS w Cloudflare dalej wskazują na stary adres.
Efekt?
Cloudflare puka pod nieaktualne IP, nikt mu nie otwiera, więc dostajemy 522.
Pierwsza diagnoza: sprawdzamy fakty, nie zgadujemy
Na serwerze sprawdziłem aktualne publiczne IP:
curl -s https://api.ipify.org
Dodatkowo użyłem DNS-owych metod weryfikacji:
dig +short myip.opendns.com @resolver1.opendns.com
oraz:
dig TXT o-o.myaddr.l.google.com @ns1.google.com +short
To jest fajny moment, bo pokazuje różnicę między tym, co „wydaje nam się, że jest adresem serwera”, a tym, co realnie widzi świat zewnętrzny.
W moim przypadku istotne było ustalenie jednego źródła prawdy:
Aktualne publiczne IP Della: 109.173.244.38
Dopiero mając tę informację, można bezpiecznie ruszać dalej.
Cloudflare API — bo klikanie po panelu przestaje mieć sens
Przy jednej domenie można wejść do panelu Cloudflare i ręcznie zmienić rekord A.
Przy kilku domenach i kilkudziesięciu rekordach zaczyna się robić nudno.
A przy większej liczbie usług ręczna edycja DNS-ów staje się po prostu ryzykiem. Można coś pominąć, pomylić IP, ruszyć rekord, którego ruszać nie wolno, albo przypadkiem rozjechać działające usługi.
Dlatego poszedłem w API Cloudflare.
Wygenerowałem token API z odpowiednimi uprawnieniami. Nie globalny klucz API, nie pełny dostęp do wszystkiego, tylko token z konkretnymi prawami do konta i stref DNS.
Tu ważna zasada:
Token infrastrukturalny powinien mieć tyle uprawnień, ile potrzebuje. Nie więcej.
W praktyce potrzebne były uprawnienia do odczytu stref i edycji rekordów DNS.
Test połączenia:
curl -s -X GET "https://api.cloudflare.com/client/v4/accounts" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json"
Potem lista stref:
curl -s -X GET "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json"
I nagle z poziomu terminala widać cały DNS-owy krajobraz konta Cloudflare.
Pierwsza naprawa: aktualizacja rekordów A
Na początku skrypt aktualizował rekordy wskazujące na stare IP. To pozwoliło szybko przywrócić działanie usług.
Ale tu pojawiła się ważna lekcja.
Nie każdy rekord A na koncie Cloudflare musi wskazywać na ten sam serwer.
U mnie część rekordów prowadziła do Della, ale część wskazywała na inne maszyny, VPS-y albo usługi testowe.
Dlatego nie można robić brutalnego:
„Zmień wszystkie rekordy A na aktualne IP”.
To byłoby proszenie się o awarię.
Bezpieczna logika jest inna:
Zmieniaj tylko te rekordy, które wcześniej wskazywały na poprzednie IP tego konkretnego serwera.
To bardzo ważne.
Jeżeli last-ip.txt zawiera poprzedni adres Della, a operator zmieni IP, skrypt może znaleźć wszystkie rekordy A z tym starym adresem i przepisać je na nowy. Rekordy wskazujące na inne maszyny zostają nietknięte.
Od jednorazowej naprawy do automatyzacji
Ręczna naprawa to jedno. Ale skoro problem może wrócić, to trzeba było zrobić z tego mechanizm.
Powstał więc prosty, ale już całkiem sensowny DDNS dla Cloudflare.
Założenia:
- Skrypt działa na Debianie.
- Jest napisany w Node.js.
- Uruchamia się cyklicznie z crona.
- Co 30 sekund sprawdza publiczne IP.
- Nie pyta cały czas jednego serwisu, tylko rotuje źródła.
- Jeśli IP się nie zmieniło, kończy pracę.
- Jeśli IP wygląda na inne, potwierdza zmianę z wielu źródeł.
- Aktualizuje rekordy DNS przez Cloudflare API.
- Zapisuje logi.
- Nie działa jako stale wiszący proces, tylko jako krótkie zadanie uruchamiane cyklicznie.
I tu robi się ciekawie, bo mamy już nie tylko „skrypcik”, ale małą orkiestrację.
Kilka źródeł prawdy dla publicznego IP
Zamiast opierać się na jednym serwisie, dodałem kilka źródeł:
Cloudflare trace
api.ipify.org
checkip.amazonaws.com
icanhazip.com
OpenDNS przez dig
Google DNS przez dig
Przykładowe polecenia:
curl -s https://api.ipify.org
curl -s https://www.cloudflare.com/cdn-cgi/trace
dig +short myip.opendns.com @resolver1.opendns.com
dig TXT o-o.myaddr.l.google.com @ns1.google.com +short
Skrypt przy normalnym działaniu odpytuje jedno źródło na raz, rotacyjnie. Dzięki temu nie katuje jednego endpointu co 30 sekund.
Jeżeli wykryje zmianę IP, odpytuje wszystkie źródła i wymaga zgodności większości.
To jest rozsądny kompromis między szybkością reakcji a bezpieczeństwem.
Cron co 30 sekund
Cron standardowo działa co minutę, ale można zrobić prostą sztuczkę:
* * * * * cd /home/roman/onenetworks-infra && /usr/bin/node cloudflare-ddns.js run >> /home/roman/onenetworks-infra/logs/ddns-cron.log 2>&1
* * * * * sleep 30; cd /home/roman/onenetworks-infra && /usr/bin/node cloudflare-ddns.js run >> /home/roman/onenetworks-infra/logs/ddns-cron.log 2>&1
Pierwszy wpis odpala skrypt na początku minuty.
Drugi odpala go po 30 sekundach.
Czyli mamy cykl:
00s
30s
00s
30s
To nie jest daemon. Skrypt nie wisi stale w pamięci. Uruchamia się, robi swoje i kończy działanie.
Sprawdzenie procesów:
ps aux | grep cloudflare-ddns
Jeżeli widać tylko grep, to znaczy, że procesy nie wiszą niepotrzebnie.
Logi, czyli nie tylko „działa”, ale wiadomo co się dzieje
Zrobiłem osobne logi:
logs/ddns-read.log
logs/ddns-change.log
logs/ddns-error.log
logs/ddns-cron.log
Log odczytów pokazuje normalną pracę:
SOURCE_OK source=ipify ip=109.173.244.38
CHECK source=ipify observed_ip=109.173.244.38 last_ip=109.173.244.38
NO_CHANGE ip=109.173.244.38
Log zmian ma być dla sytuacji ważnych:
POSSIBLE_CHANGE
CONFIRMATION
DNS_UPDATED
CHANGE_DONE
Dzięki temu zwykła praca nie miesza się z historią realnych zmian IP.
To jest ważne, bo po miesiącu nie chcesz czytać ściany logów i zastanawiać się, czy coś się faktycznie wydarzyło.
Inicjalizacja — niech skrypt wie, czym zarządza
Bardzo ważnym elementem była komenda:
node cloudflare-ddns.js init
Podczas inicjalizacji skrypt:
- sprawdza
.env, - sprawdza token Cloudflare,
- testuje API,
- pobiera aktualne publiczne IP z wielu źródeł,
- skanuje wszystkie strefy Cloudflare,
- znajduje rekordy A wskazujące na aktualne IP serwera,
- zapisuje snapshot DNS,
- zapisuje
last-ip.txt, - tworzy listę rekordów zarządzanych.
Wynik:
INIT OK
Aktualne IP: 109.173.244.38
Stref Cloudflare: 9
Rekordów A zarządzanych: 30
To jest bardzo przyjemny moment.
Bo nagle widzisz, że domowy serwer, Debian, Node.js, Cloudflare API i DNS zaczynają ze sobą gadać jak mały system infrastrukturalny.
Czy to jest wielkie odkrycie?
Nie.
I właśnie dlatego lubię takie tematy.
Dla doświadczonego administratora to nie jest magia. To nie jest Kubernetes, wieloregionowa infrastruktura, Terraform i zespół SRE z pagerami.
Ale dla kogoś, kto rozwija własny homelab, uczy się infrastruktury, stawia swoje usługi, konfiguruje domeny, bawi się Cloudflare, Debianem, Node.js i automatyzacją — to jest bardzo wartościowy case.
Bo tutaj dotykamy prawdziwych elementów Internetu.
Nie w teorii.
Nie na slajdzie.
Tylko na działającym organizmie.
Co tu naprawdę zostało przećwiczone?
Ten mały projekt zahacza o kilka obszarów naraz:
DNS
Rekordy A, strefy, subdomeny, propagacja, wskazywanie domen na konkretne adresy IP.
Cloudflare
Proxy, SSL, API, tokeny, uprawnienia, błędy 522, relacja między użytkownikiem, Cloudflare i origin serverem.
Linux
Debian, terminal, SSH, cron, pliki konfiguracyjne, uprawnienia, logi.
Programowanie
Node.js, JavaScript, obsługa API, pliki stanu, JSON, walidacja, obsługa błędów.
Automatyzacja
Cykliczne uruchamianie, logika decyzyjna, rotacja źródeł, fail-safe, lock file.
Homelab
Najpiękniejsza część: robienie rzeczy samemu, psucie, naprawianie, rozumienie i wyciąganie wniosków.
Homelab uczy pokory
Ten case pokazał mi jeszcze jedną rzecz.
Można mieć Cloudflare, proxy, SSL, API, automatyzację, kilka domen, Node.js i serwer na Debianie, a i tak wszystko może się wyłożyć na czymś tak prostym jak zmiana publicznego IP.
I to jest piękne.
Bo technologia nie jest magicznym pudełkiem. To warstwy zależności.
Domena wskazuje na IP.
Cloudflare łączy się z originem.
Origin musi odpowiadać.
Router musi przepuszczać ruch.
Firewall nie może blokować.
Nginx musi działać.
A operator może zmienić dzierżawę.
Wszystko jest połączone.
Podsumowanie
Zaczęło się od błędu 522.
Skończyło się na własnym mechanizmie DDNS dla Cloudflare, działającym na Debianie, napisanym w Node.js, uruchamianym z crona co 30 sekund, korzystającym z kilku źródeł publicznego IP i aktualizującym rekordy DNS przez API.
Czy to jest coś wielkiego?
Nie.
Czy daje satysfakcję?
Ogromną.
Bo właśnie takie rzeczy budują praktyczne zrozumienie Internetu.
Nie z definicji.
Nie z kursu.
Tylko z własnego przypadku, własnego serwera, własnych domen i własnego błędu, który trzeba było naprawić.
I właśnie takie są uroki hobby zwanego homelabem.
Czasem coś padnie.
Czasem Cloudflare pokaże 522.
Czasem operator zmieni IP.
A czasem siadasz wieczorem, łączysz się po SSH, odpalasz terminal, poprawiasz DNS-y przez API, piszesz automatyzację w Node.js i po chwili widzisz w logach:
NO_CHANGE ip=109.173.244.38
I człowiek siedzi przed ekranem z bananem na twarzy.
Bo działa.
OneNetworks / homelab / infrastruktura
Tu później planuję dodać linki do kolejnych wpisów o DNS, NGINX, Cloudflare, Debianie, automatyzacji i self-hostingu.
