W redakcji. Artykuł jest wersją roboczą, nie jest jeszcze wersją finalną i może ulec zmianie.
Usługa nie wstała po restarcie serwera. Adres, na którym miała nasłuchiwać, pojawił się na interfejsie pięć sekund po tym, jak system ogłosił, że sieć jest gotowa. To nie jest błąd konfiguracji, tylko wyścig - a naprawa, która się narzuca, tego wyścigu nie rozstrzyga.
W tym artykule rozbieramy awarię na czynniki pierwsze: skąd się bierze Cannot assign requested address przy starcie, dlaczego After=network-online.target bywa bezużyteczne, dlaczego usługa nie podniosła się sama przez siedem godzin i jak sprawdzić, czy ten sam problem czeka na pozostałych maszynach.
Spis treści
- Objaw: usługa nagios-nrpe-server nie startuje po restarcie serwera z błędem Cannot assign requested address
- Pierwszy trop: After=network-online.target i dlaczego tu nie pomaga
- Oś czasu rozruchu: adres IPv4 z DHCP pojawił się po network-online.target
- Dlaczego usługa nie wstała sama: Restart=on-abort nie reaguje na błąd startu
- Naprawa: drop-in z Restart=on-failure i limitem prób startu
- Pułapka: StartLimitBurst i StartLimitIntervalSec należą do sekcji [Unit]
- Dlaczego awaria trafiła serwer fizyczny z kartą 10 Gb/s
- Jak sprawdzić, czy inne usługi są podatne na ten sam wyścig
- Częste błędy przy usługach nasłuchujących na adresie z DHCP
- Checklista dla usług nasłuchujących na konkretnym adresie IP
Objaw: usługa nagios-nrpe-server nie startuje po restarcie serwera z błędem Cannot assign requested address
Usługa nagios-nrpe-server została skonfigurowana tak, aby nasłuchiwała na konkretnym adresie hosta zamiast na 0.0.0.0. Po restarcie serwera w dzienniku zostaje to:
systemd[1]: Started nagios-nrpe-server.service - Nagios Remote Plugin Executor.
nrpe[1360]: Starting up daemon
nrpe[1360]: Bind to port 5666 on 203.0.113.10 failed: Cannot assign requested address.
nrpe[1360]: Cannot bind to any address.
systemd[1]: nagios-nrpe-server.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: nagios-nrpe-server.service: Failed with result 'exit-code'.
Cannot assign requested address to EADDRNOTAVAIL. Jądro mówi wprost: tego adresu nie ma na żadnym interfejsie. Po zalogowaniu się na host adres oczywiście jest, a ręczny start usługi kończy się sukcesem.
To wystarczy, żeby wiedzieć, że mamy do czynienia z wyścigiem, a nie z pomyłką w konfiguracji. Pytanie brzmi, z kim ta usługa przegrała wyścig i dlaczego nie spróbowała ponownie.
Pierwszy trop: After=network-online.target i dlaczego tu nie pomaga
Odruch jest słuszny. Jednostka z pakietu ma w sekcji kolejności tylko tyle:
After=var-run.mount nss-lookup.target network.target local-fs.target remote-fs.target time-sync.target
network.target nie oznacza działającej sieci. Jest osiągany wtedy, gdy menedżer sieci wystartował, a nie wtedy, gdy interfejsy mają adresy. Do czekania na skonfigurowaną sieć służy network-online.target i to on wydaje się brakującym elementem.
W opisywanej awarii network-online.target był osiągnięty dwie sekundy przed nieudaną próbą zajęcia adresu. Dopisanie After=network-online.target niczego by nie zmieniło.
Oś czasu rozruchu: adres IPv4 z DHCP pojawił się po network-online.target
Tak wygląda ten sam rozruch systemu w dzienniku z szerszym filtrem:
07:12:39 systemd-networkd: eno3: Link UP
07:12:39 Starting systemd-networkd-wait-online.service...
07:12:44 systemd-networkd: eno3: Gained carrier
07:12:44 kernel: NIC Link is Up 10 Gbps
07:12:46 systemd-networkd: eno3: Gained IPv6LL <-- link-local IPv6
07:12:46 Finished systemd-networkd-wait-online.service
07:12:46 Reached target network-online.target
07:12:48 nrpe: Bind to port 5666 on 203.0.113.10 failed
07:12:53 systemd-networkd: eno3: DHCPv4 address 203.0.113.10/24 acquired
Kluczowa jest para linii o 07:12:46. Usługa systemd-networkd-wait-online uznała sieć za gotową w tej samej sekundzie, w której interfejs dostał adres link-local IPv6.
Tak zachował się konkretny systemd-networkd-wait-online oraz jego konfiguracja w opisanej awarii, nie jest to uniwersalna definicja network-online.target. Sprawdź u siebie systemctl cat systemd-networkd-wait-online.service i pliki .network. Jeżeli potrzebujesz routowalnego IPv4, poproś o niego wprost przełącznikiem --ipv4 albo ustawieniem RequiredFamilyForOnline=ipv4 dla właściwego linku.
Adres, o który chodziło usłudze, pojawił się siedem sekund po ogłoszeniu, że sieć jest online.
Dlaczego usługa nie wstała sama: Restart=on-abort nie reaguje na błąd startu
Sam wyścig oznaczałby kilkanaście sekund opóźnienia i nikt by go nie zauważył. Tymczasem usługa leżała siedem i pół godziny, aż ktoś uruchomił ją ręcznie. Powód siedzi w tej samej jednostce z pakietu:
Restart=on-abort
on-abort obejmuje wyłącznie zakończenie przez nieobsłużony sygnał. Wyjście z niezerowym kodem to exit-code, a tego on-abort nie łapie. Systemd zachował się dokładnie zgodnie z konfiguracją: zobaczył status=1/FAILURE, uznał to za stan końcowy i nie próbował ponownie.
$ systemctl show nagios-nrpe-server -p NRestarts
NRestarts=0
To jest właściwa lekcja z tej awarii. Wyścig o adres jest zwykły i zdarza się wszędzie. W wielogodzinną awarię zamienia się dopiero wtedy, gdy nic nie ponawia próby.
Naprawa: drop-in z Restart=on-failure i limitem prób startu
Rozwiązaniem jest drop-in do jednostki, nie edycja pliku z pakietu - ten wróci przy najbliższej aktualizacji. Tę samą poprawkę, w postaci szablonu drop-inu dla NRPE, stosujemy w roli monitoringu dla PLD Linux opublikowanej w repozytorium sysgroup/linuxlab: nrpe-bind-dropin.conf.j2 (stan z 22 września 2026, commit eba6d62).
# /etc/systemd/system/nagios-nrpe-server.service.d/10-bind-address.conf
[Unit]
After=network-online.target
Wants=network-online.target
StartLimitBurst=20
StartLimitIntervalSec=300
[Service]
Restart=on-failure
RestartSec=5s
Podział ról między tymi ustawieniami jest asymetryczny i warto go rozumieć:
After=network-online.targetskraca okno, ale go nie zamyka. Warto go mieć, nie wolno na nim polegać. Poza opisanym przypadkiem adresu link-local jest jeszcze drugi: na hoście, gdzie żadna usługa nie dostarcza tego targetu, jest on osiągany natychmiast, bo nie ma na co czekać.Restart=on-failureto właściwe zabezpieczenie. Po nieudanej próbie zajęcia adresu usługa spróbuje ponownie za pięć sekund; czy kolejna próba wystarczy, zależy od rzeczywistego czasu DHCP i startu sieci.- Limity startu chronią przed pętlą. Dwadzieścia prób w pięć minut daje sto sekund cierpliwości, po czym usługa idzie w stan
failedi przestaje zaśmiecać dziennik.
Po dołożeniu pliku potrzebny jest systemctl daemon-reload.
Pułapka: StartLimitBurst i StartLimitIntervalSec należą do sekcji [Unit]
Pierwsza wersja tego drop-inu miała oba klucze limitu w sekcji [Service]. Wygląda to naturalnie: skoro Restart= jest w [Service], to limit restartów też. Efekt:
$ systemctl show nagios-nrpe-server -p StartLimitIntervalUSec -p StartLimitBurst
StartLimitIntervalUSec=10s <-- deklarowano 300 s
StartLimitBurst=20 <-- to akurat przeszło
W dzienniku pojawia się jedna linia, łatwa do przeoczenia:
systemd[1]: /etc/systemd/system/.../10-bind-address.conf:21:
Unknown key 'StartLimitIntervalSec' in section [Service], ignoring.
Oba klucze należą do sekcji [Unit]. StartLimitBurst w [Service] jest nadal przyjmowany dla zgodności wstecznej, a StartLimitIntervalSec nie. Powstaje najgorszy możliwy układ: połowa polityki działa, połowa nie, a jedynym sygnałem jest ta jedna linia przy ładowaniu jednostki. W miejsce deklarowanej wartości wchodzi systemowa wartość domyślna, zwykle dziesięć sekund.
Sprawdzenie, które nie kłamie, porównuje deklarację z wartością efektywną, nigdy samą deklarację:
$ systemctl show <usługa> -p Restart -p RestartUSec \
-p StartLimitIntervalUSec -p StartLimitBurst
$ systemd-analyze verify <usługa>.service 2>&1 | grep -i 'unknown key'
Warto wiedzieć, że systemd-analyze verify wciąga też jednostki zależne i potrafi pokazać ostrzeżenia z zupełnie innych plików. Zanim uznasz wynik za swój błąd, sprawdź ścieżkę w komunikacie.
Dlaczego awaria trafiła serwer fizyczny z kartą 10 Gb/s
Maszyna wirtualna z kartą virtio często skraca to okno, ale go nie eliminuje: DHCP (od angielskiego Dynamic Host Configuration Protocol, czyli protokół automatycznego przydziału adresów), cloud-init i kolejność startu nadal mogą je wydłużyć. W opisywanej awarii chodziło o serwer fizyczny z kartą 10 Gb/s:
07:12:39 eno3: Link UP
07:12:44 eno3: Gained carrier <-- pięć sekund na autonegocjację
Samo ustalenie parametrów łącza trwało pięć sekund, a DHCP zaczyna się dopiero potem. Okno, które na maszynie wirtualnej jest niemierzalne, tutaj rozciąga się na kilkanaście sekund.
To prowadzi do ogólniejszej obserwacji: problem nie dotyczy jednego hosta, tylko jest kwestią prawdopodobieństwa. Ten sam błąd konfiguracji leży na wszystkich maszynach, a materializuje się tam, gdzie boot akurat trwa dłużej. Wolniejszy boot to nie tylko szybsza karta sieciowa - równie dobrze obciążony serwer DHCP, więcej interfejsów albo po prostu inny dzień.
Jak sprawdzić, czy inne usługi są podatne na ten sam wyścig
Podatna jest każda usługa, która spełnia trzy warunki naraz: nasłuchuje na konkretnym adresie, adres przychodzi z DHCP, a jednostka nie ponawia startu po błędzie.
# 1. Czy usługa binduje się punktowo (adres inny niż 0.0.0.0 i ::)
$ ss -lntp | grep <port>
# 2. Czy adres jest z DHCP
$ journalctl -b -0 | grep -iE 'DHCPv4 address|DHCPACK'
# 3. Czy jednostka w ogóle ponowi próbę
$ systemctl show <usługa> -p Restart
# on-abort -> NIE ponowi po błędzie
# no -> NIE ponowi wcale
# on-failure, always -> ponowi
# 4. Czy to już się zdarzało, choć nikt nie zauważył
$ journalctl -u <usługa> --since '3 months ago' | grep -iE 'cannot assign|failed'
Punkt czwarty bywa najbardziej pouczający. Usługa, która wstaje przy drugiej próbie, nie generuje żadnego alarmu, a w dzienniku zostaje ślad, że wyścig przegrywany jest regularnie.
W przypadku nagios-nrpe-server usługa sama nie zgłosi, że nie działa. Musi ją obserwować coś z zewnątrz, inaczej awaria pozostanie cicha tak długo, jak w opisywanym przypadku.
Częste błędy przy usługach nasłuchujących na adresie z DHCP
- Uznanie
network.targetza "sieć działa". Oznacza tylko, że menedżer sieci wystartował. - Uznanie
network-online.targetza "mam adres IPv4". W niektórych konfiguracjach adres link-local IPv6 wystarcza; sprawdź efektywną usługę wait-online i konfigurację linku. - Poleganie wyłącznie na kolejności zamiast na ponawianiu. Kolejność skraca okno;
Restart=on-failureogranicza skutki tylko wtedy, gdy interwał i limit prób pokrywają rzeczywisty czas oczekiwania na adres. - Przeoczenie, że
Restart=on-abortnie łapie błędu. To najczęstsza przyczyna tego, że awaria trwa godziny zamiast sekund. - Edycja pliku jednostki z pakietu. Wróci przy aktualizacji, drop-in nie.
- Limity startu w sekcji
[Service]. Oba klucze należą do[Unit]. - Weryfikacja po deklaracji zamiast po wartości efektywnej. Plik może mówić jedno, a systemd robić drugie i nie protestować głośno.
- Uznanie problemu za dotyczący jednego hosta. Jeżeli jedna maszyna przegrała wyścig, reszta go tylko jeszcze nie przegrała.
Checklista dla usług nasłuchujących na konkretnym adresie IP
- Czy usługa naprawdę musi nasłuchiwać na konkretnym adresie? Jeśli chodzi o ograniczenie dostępu, właściwym narzędziem jest zapora albo lista dozwolonych źródeł, a nie adres nasłuchu.
- Czy jednostka ma
Restart=on-failurei rozsądnyRestartSec? - Czy limity startu są w sekcji
[Unit]? - Czy wartości efektywne zgadzają się z deklaracją?
- Czy po wdrożeniu dziennik nie zgłasza nieznanych kluczy?
- Czy ta sama poprawka poszła na wszystkie maszyny o tym profilu, a nie tylko na tę, która się zepsuła?
- Czy cokolwiek zauważy, że ta usługa leży?
Usługa, która nie wstaje po restarcie serwera, zwykle nie jest jedyna
Przeglądamy konfiguracje jednostek systemd pod kątem kolejności startu i zachowania po błędzie, a potem pilnujemy, żeby poprawka trafiła na całą flotę, nie tylko na tę maszynę, która akurat się zepsuła.
Powiązany artykuł
Hardening usług systemd - Nginx, PHP-FPM i MariaDB
Jak ograniczyć uprawnienia usług przez drop-iny, nie psując przy tym ich działania.
Zobacz też