Otwarte na nowe projekty +48 887 255 528 · kontakt[at]kosari.pl

wp-cron nie działa i maile nie wychodzą? Sprawdź crontab i zabezpiecz zadania

wp-cron nie działa, a maile z WordPressa nie wychodzą? Sprawdź crontab w 5 minut, poznaj pułapkę „crontab -” i zabezpiecz zadania cykliczne strony.

10 min czytania WordPress
wp-cron nie działa i maile nie wychodzą? Sprawdź crontab i zabezpiecz zadania

Strona się otwiera, płatności przechodzą, panel WordPressa działa. A mimo to nie wychodzą przypomnienia o zajęciach, powiadomienia o zamówieniach ani maile o zaległych ratach. Rzeczy, które powinny dziać się same, po prostu przestają się dziać. Jeśli trafiłeś tu, bo wp-cron nie działa i maile nie wychodzą, a niczego nie zmieniałeś – ten poradnik może oszczędzić Ci kilka godzin szukania w złym miejscu.

Bardzo często przyczyną nie jest wtyczka ani serwer pocztowy, tylko pusty crontab. A najczęstszy sposób, w jaki crontab robi się pusty, to jeden niewinnie wyglądający potok, który można znaleźć w niemal każdym poradniku.

Kontekst: na czym stoją automatyzacje WordPressa

Na stronach, które żyją z automatyzacji – platformach kursowych, sklepach, systemach zapisów – wbudowany wp-cron zwykle wyłącza się stałą DISABLE_WP_CRON. Wbudowany mechanizm odpala zadania przy okazji wejścia użytkownika na stronę, więc przy małym ruchu potrafią one czekać godzinami, a przy dużym obciążają serwer. Zamiast tego każda strona ma własny wpis w systemowym cronie:

*/5 * * * * cd /sciezka/do/strony && wp cron event run --due-now --quiet

To jest fundament. Na tych wpisach stoją przypomnienia do klientów, kolejki mailowe, odnawianie subskrypcji, wystawianie faktur i synchronizacje z zewnętrznymi systemami. Przy kilku stronach na jednym serwerze takich linii jest kilka albo kilkanaście, obok zadań serwisowych.

Diagnoza krok po kroku: dlaczego wp-cron nie działa, skoro nic się nie zmieniło

Hipoteza 1: padła wtyczka mailowa albo SMTP

Pierwszy odruch, bo objawem jest brak maili. Zacznij od testu wysyłki i logu SMTP. Jeśli test przechodzi, konfiguracja jest nietknięta, a problem dotyczy kilku stron naraz, z różnymi wtyczkami do poczty, wspólny mianownik leży niżej niż pojedyncza strona.

Hipoteza 2: coś w samym WordPressie

Sprawdź kolejkę zadań:

wp cron event list --fields=hook,next_run_relative

Jeśli zadania są na miejscu, ale z terminami z przeszłości, masz pierwszą konkretną wskazówkę: WordPress wie, co ma zrobić, ale nikt go o to nie prosi. Problem nie siedzi w aplikacji, tylko w tym, co ją uruchamia.

Hipoteza 3, czyli sprawdzenie, które trzeba było zrobić jako pierwsze

crontab -l

Jeśli w odpowiedzi widzisz jedną linijkę zamiast kilku czy kilkunastu albo nie widzisz nic, crontab został wyczyszczony. I zwykle nie zostawia po sobie żadnego śladu: żadnego błędu w logach, żadnego maila z ostrzeżeniem, żadnego alertu.

Oś czasu awarii: od skryptu wieczorem do braku maili ranoWieczorem jednorazowy skrypt usuwa swój wpis, crontab zostaje pusty bez błędu, w nocy zadania WordPressa czekają, rano klienci nie dostają maili.Jak wygląda cicha awaria cronaWieczórTa sama minutaNocRanoSkrypt jednorazowyusuwa swój wpiscrontab - zapisujepustkę, kod wyjścia 0Zadania WordPressaczekają w kolejceKlienci nie dostajążadnych mailiMiędzy przyczyną a objawem: kilkanaście godzin i zero alertów
Błąd odpala się wieczorem, gdy nikogo nie ma przy komputerze. Widać go dopiero rano, po stronie klientów.

Moment odkrycia: „crontab -” nadpisuje wszystko i nie protestuje

Typowy scenariusz: mały, jednorazowy skrypt ma uruchomić się raz wieczorem, a potem usunąć z crona własny wpis. Usuwa go wzorcem, który można znaleźć w niemal każdym poradniku:

crontab -l | grep -v przypomnienie.sh | crontab -

Polecenie crontab - nie usuwa jednej linii. Ono zastępuje cały crontab tym, co dostanie na wejściu. Jeśli lewa strona potoku zwróci pusty strumień, prawa strona posłusznie zapisze pusty crontab i zakończy się sukcesem. Bez błędu, bez ostrzeżenia, bez pytania.

A lewa strona potrafi zwrócić pustkę z banalnych powodów. Skrypt uruchomiony z crona ma inne środowisko niż sesja w terminalu. Polecenie może nie trafić na właściwą binarkę w PATH. Zdalne połączenie może się urwać. Zmienna, do której ktoś wcześniej wczytał crontab, może być pusta po nieudanym odczycie. Wystarczy jedno z tych zdarzeń.

Ten sam efekt daje drugi popularny wzorzec, ze zmienną: crontab wczytany do zmiennej, nowa linia doklejona na końcu, całość przekazana do crontab -. Jeśli zmienna jest pusta po nieudanym odczycie, znikają wszystkie wpisy naraz. Różne skrypty, jeden mechanizm.

Zapis crontaba wprost kontra zapis przez bramkę z walidacjąPo lewej pusty strumień trafia do crontab minus i czyści wszystkie wpisy. Po prawej bramka liczy wpisy, odrzuca pusty zapis, przywraca kopię i wysyła alert.PRZED - zapis wprost1. crontab -l zwraca pustkę2. grep -v przepuszcza pustkę3. crontab - zapisuje pustkę4. kod wyjścia: 0, brak loguWpisy wp-cron: 0Nikt się nie dowie do ranaPO - zapis przez bramkę1. kopia crontaba do pliku2. liczenie wpisów w nowej wersji3. za mało = odmowa zapisu4. po zapisie ponowne liczenie5. rozjazd = przywrócenie kopiiWpisy zostają + alert mailem
Ten sam pusty strumień. Po lewej kasuje fundament, po prawej kończy się odmową i powiadomieniem.

Rozwiązanie: crontab wyłącznie przez bramkę z walidacją

Odtworzenie wpisów to kilka minut, jeśli masz z czego je odtworzyć. Ważniejsze, żeby to samo nie mogło się powtórzyć. Nie chodzi o notatkę „uważaj na crontab”, tylko o zmianę, która działa także wtedy, gdy nikt o niej nie pamięta. Tak zabezpieczamy zadania cykliczne na stronach, którymi się opiekujemy – monitoring crona jest standardem w naszej opiece nad stronami WordPress.

1. Jedna droga zapisu: skrypt-bramka

Żaden skrypt nie powinien pisać do crontaba bezpośrednio. Wszystko przechodzi przez jeden skrypt-bramkę, który w środku ma:

  • kopię obecnego crontaba do pliku przed jakąkolwiek zmianą,
  • blokadę zapisu pustej albo podejrzanie krótkiej zawartości,
  • minimalną liczbę wpisów wp-cron, poniżej której zapis jest odrzucany,
  • blokadę ubytku więcej niż kilku wpisów naraz,
  • ponowne liczenie po zapisie i automatyczne przywrócenie kopii, gdy coś się nie zgadza,
  • alert mailem przy każdej odrzuconej próbie.

Sedno tej walidacji mieści się w kilku liniach. Warto je mieć u siebie, nawet jeśli masz jedną stronę:

KOPIA=~/crontab-kopia-$(date +%F-%H%M).txt
crontab -l > "$KOPIA" 2>/dev/null
LICZ=$(grep -c . nowy-crontab.txt)
[ "$LICZ" -ge "$MINIMUM" ] || { echo "BLAD: crontab podejrzanie krotki"; exit 1; }
crontab nowy-crontab.txt
[ "$(crontab -l | grep -c .)" -ge "$MINIMUM" ] || crontab "$KOPIA"

Zwróć uwagę, że pracujemy na pliku, a nie na zmiennej w potoku: crontab -l > plik, edycja pliku, crontab plik. Każdy krok da się wtedy sprawdzić osobno, a pusty plik widać gołym okiem.

Pułapka przy alertach: sprawdź, czy na serwerze w ogóle jest polecenie mail. Na wielu hostingach go nie ma, jest tylko sendmail. Skrypt kończący się potokiem do mail przechodzi wtedy test składni, uruchamia się bez widocznego błędu i po cichu nie wysyła nic. Każdy skrypt alarmowy testuj jednym prawdziwym uruchomieniem.

2. Strażnik, który sprawdza, czy wpisy istnieją

Sama kopia nie wystarczy, bo ktoś musi zauważyć brak. Co kwadrans uruchamia się strażnik, który przechodzi po katalogach wszystkich stron i sprawdza, czy każda z nich ma swój wpis wp-cron. Brakujący dopisuje przez tę samą bramkę i melduje o tym.

Pułapka: jeśli strażnik sam jest wpisem w crontabie, wyczyszczony crontab zabiera go ze sobą. Dlatego to samo sprawdzenie warto odpalać także z drugiej maszyny, spoza hostingu, na przykład co 15 minut. Takie przenoszenie powtarzalnych zadań poza jeden punkt awarii to codzienność w automatyzacjach, które budujemy dla firm.

3. Blokada wzorca, zanim w ogóle trafi do skryptu

Ostatnia warstwa to zakaz samego wzorca | crontab -. Sama kontrola grepem po katalogu skryptów na serwerze nie wystarcza, bo nie widzi narzędzi uruchamianych z innych miejsc. Skuteczniejsza jest automatyczna blokada, która odrzuca zapis do crontaba potokiem, zanim komenda w ogóle się wykona. Mechanizm takich blokad opisuje wpis o hookach Claude Code blokujących groźne komendy.

Trzy warstwy ochrony crontabaBlokada wzorca przed wykonaniem komendy, bramka z walidacją przy zapisie i strażnik z zewnątrz, który odtwarza brakujące wpisy wp-cron co 15 minut.1. Blokada wzorcapotok do crontabaodrzucony przedwykonaniem2. Bramka zapisukopia, liczenie,odmowa, przywrócenie,alert3. Strażnik z zewnątrzco 15 minut sprawdzakażdą stronę i dopisujebrakujące wpisyKażda warstwa łapie to, co przepuściła poprzedniaStrażnik działa poza hostingiem, więc wyczyszczony crontab nie zabiera go ze sobą
Notatka „uważaj” działa tylko wtedy, gdy ktoś ją akurat czyta. Te trzy warstwy działają zawsze.

Efekt: błąd może się zdarzyć, ale nie dociera do klientów

Z trzema warstwami pusty crontab przestaje być cichą awarią. Bramka odrzuca podejrzany zapis, a gdy wpisy znikną inną drogą, strażnik z zewnątrz odtwarza je w ciągu kwadransa, zanim ktokolwiek zauważy brak maili. Zaległe zadania WordPressa wykonują się przy pierwszym przebiegu.

To jest właściwa miara takiej zmiany: nie to, że błąd już nigdy się nie zdarzy, tylko to, że gdy się zdarzy, nie dotrze do klientów.

Jak sprawdzić to u siebie

  1. Policz wpisy: crontab -l | grep -c .. Zapisz tę liczbę. Jeśli jej nie znasz, nie zauważysz, gdy spadnie.
  2. Poszukaj niebezpiecznego wzorca we własnych skryptach i narzędziach, także tych na komputerze: grep -rn "| *crontab -" ~/bin ~/skrypty.
  3. Sprawdź, czy WordPress ma zaległe zadania: wp cron event list --fields=hook,next_run_relative. Terminy z przeszłości to sygnał, że nikt ich nie odpala.
  4. Jeśli w wp-config.php masz DISABLE_WP_CRON, upewnij się, że istnieje systemowy wpis, który go zastępuje.
  5. Zrób kopię crontaba do pliku już teraz i dołącz ją do backupu.
  6. Dodaj monitoring z innej maszyny: raz na kwadrans albo raz na godzinę sprawdzenie liczby wpisów i powiadomienie, gdy jest ich mniej, niż powinno.
  7. Przetestuj alert prawdziwym uruchomieniem, a nie samym sprawdzeniem składni.

Najważniejsza zasada

Operacja, która potrafi po cichu skasować fundament, nie może być dostępna „z palca”. Musi mieć jedną drogę wykonania, walidację w środku i sprawdzenie po zapisie. Do tego potrzebny jest ktoś, kto patrzy z zewnątrz, bo mechanizm ochronny, który żyje w tym samym miejscu co awaria, ginie razem z nią. A „jednorazowy” skrypt to najgroźniejszy przypadek: działa raz, wieczorem, bez nikogo przy klawiaturze i nikt go już drugi raz nie przetestuje.

FAQ

Czym różni się wp-cron od systemowego crona?

Wbudowany wp-cron uruchamia zadania przy okazji wejścia użytkownika na stronę, więc przy małym ruchu potrafią one czekać godzinami. Systemowy cron uruchamia je o stałej porze, niezależnie od ruchu. Dlatego na stronach z automatyzacjami wyłączamy wbudowany mechanizm i zastępujemy go wpisem systemowym.

Jak sprawdzić, czy zadania WordPressa się wykonują?

Najprościej komendą wp cron event list --fields=hook,next_run_relative. Jeśli przy zadaniach widzisz terminy z przeszłości, kolejka czeka i nikt jej nie uruchamia. Bez dostępu do konsoli podobną listę pokazują wtyczki do podglądu zadań cron.

Dlaczego polecenie crontab z minusem jest niebezpieczne?

Bo zastępuje cały crontab tym, co dostanie na wejściu. Pusty strumień oznacza pusty crontab, a polecenie kończy się sukcesem, bez ostrzeżenia. Błąd ujawnia się dopiero wtedy, gdy przestają działać zadania.

Jak bezpiecznie usunąć jeden wpis z crontaba?

Pracuj na pliku: crontab -l > plik, edycja pliku, sprawdzenie liczby linii, crontab plik. Po zapisie policz wpisy jeszcze raz i porównaj z oczekiwaną liczbą. Kopię zrób przed pierwszym krokiem.

Czy wystarczy sam backup crontaba?

Nie. Backup ratuje dane, ale ktoś musi zauważyć, że trzeba go przywrócić. Bez monitoringu liczby wpisów dowiesz się o problemie od klienta, który nie dostał maila.

Maile z WordPressa nie wychodzą, ale crontab jest w porządku. Co dalej?

Wtedy sprawdź kolejno: czy zadanie wysyłki jest w kolejce wp-cron, czy test wysyłki z konsoli przechodzi, czy wtyczka SMTP ma poprawne dane i czy domena ma ustawione rekordy SPF i DKIM. Kolejność ma znaczenie: najpierw to, co uruchamia wysyłkę, potem sama wysyłka.

Masz kilka stron i nie wiesz, czy ich automatyzacje działają? Napisz do nas

Jeśli utrzymujesz strony WordPress z przypomnieniami, subskrypcjami albo kolejkami maili i nie masz pewności, czy zadania faktycznie się wykonują, to nie jest pytanie „czy”, tylko „kiedy”. Zajmujemy się tym na co dzień: monitoring zadań cyklicznych, kopie konfiguracji, strażnicy działający spoza hostingu. Zobacz, co obejmuje opieka WordPress w Kosari.

Napisz do nas – sprawdzimy, czy Twoje automatyzacje naprawdę działają

Grzegorz Rówiński · Kosari

Buduję strony, sklepy i platformy kursowe, automatyzuję procesy i wdrażam AI w firmach. Ten wpis powstał z realnego wdrożenia, nie z teorii.

Napisz do mnie →

Przeczytaj też

Masz podobny problem i nie chcesz go debugować sam?

Napisz krótko co się dzieje. Odpowiadamy konkretnie, bez zobowiązań - powiemy z czego to najpewniej wynika i ile kosztuje naprawa.

Napisz do nas

Wolisz porozmawiać? Zadzwoń: +48 887 255 528

Zadzwoń +48 887 255 528