Jak włączyć maintenance bez przerywania cronów skutecznie

Wprowadzenie: co naprawdę znaczy “bez przerywania cronów”

tryb maintenance to prosty sposób na odcięcie ruchu publicznego do serwisu podczas prac, aktualizacji czy migracji. Problem w tym, że wiele witryn polega na zadaniach cyklicznych: od publikacji wpisów, przez wysyłki maili i cache warm-up, po integracje z płatnościami. W WordPressie dochodzi jeszcze specyficzny mechanizm WP‑Cron, który wywoływany jest przy żądaniach HTTP. Jeśli włączysz stronę “dla wszystkich” na stronę 503 bez wyjątków, łatwo niechcący zatrzymać mechanizmy, które miały działać w tle.

W tym poradniku pokazuję, jak włączyć prace serwisowe tak, aby odwiedzający zobaczyli schludną stronę tymczasową, a cron (systemowy i/lub WP‑Cron) pracował dalej. Dostaniesz gotowe reguły dla Apache i Nginx, prostą strategię z cronem systemowym oraz checklistę wdrożenia bez potknięć. Wszystko po to, by prace były niewidoczne dla użytkowników, a automatyzacje działały bez przerwy.

Cron vs WP‑Cron: gdzie faktycznie powstaje problem

  • Cron systemowy (crontab) działa niezależnie od serwera www. Jeśli zadanie uruchamia skrypt w CLI (np. wp cron event run), to tryb maintenance nie ma na nie wpływu.

  • WP‑Cron działa inaczej. Domyślnie uruchamia się przy ruchu na stronie, wołając wp-cron.php. Jeżeli zablokujesz ruch HTTP lub zablokujesz ten endpoint, WP‑Cron przestanie być wyzwalany.

  • Integracje przez webhooki (płatności, fulfillment, marketing automation) również wymagają dostępu do konkretnych ścieżek lub API. Zbyt agresywny maintenance potrafi “uciąć” powiadomienia od operatorów.

Klucz: zablokuj to, co widzi użytkownik, ale zostaw “kroplówkę” dla cronów, AJAX‑ów i webhooków.

Najpewniejsza strategia: cron systemowy + wyłączenie WP‑Cron

Najbardziej niezawodne podejście polega na:

  1. Włączeniu crona systemowego zamiast WP‑Cron:
  • W wp-config.php dodaj: define(‘DISABLE_WP_CRON’, true);
  1. Dodaniu zadania w crontab (co 5 minut, dopasuj do potrzeb):

Tak skonfigurowany system nie zależy od ruchu użytkowników. Nawet jeśli front całkowicie zwróci 503, crontab uruchomi zadania normalnie. Przy wersji HTTP można dodatkowo whitelistić 127.0.0.1 lub IP serwera, by ominąć blokadę.

tryb maintenance bez blokowania cronów: Apache (.htaccess)

Poniższa reguła pokaże stronę maintenance.html wszystkim, poza:

  • ścieżkami istotnymi dla automatyzacji (wp-cron.php, admin-ajax.php, wybrane webhooki),
  • Twoim IP (dla podglądu),
  • samą stroną maintenance.

W katalogu publicznym dodaj plik maintenance.html oraz edytuj .htaccess:

RewriteEngine On

Pozwól na crony, AJAX i webhooki

RewriteCond %{REQUEST_URI} !/wp-cron.php$ [NC]
RewriteCond %{REQUEST_URI} !/wp-admin/admin-ajax.php$ [NC]
RewriteCond %{REQUEST_URI} !/wp-json/partner-webhook/. [NC]

Pozwól z Twojego IP (opcjonalnie)

RewriteCond %{REMOTE_ADDR} !^123.123.123.123$

Nie pętlij na stronie maintenance

RewriteCond %{REQUEST_URI} !/maintenance.html$ [NC]

Dla reszty pokaż 503

RewriteRule ^.$ /maintenance.html [R=503,L]

Dla SEO i robotów dodaj Retry-After (wymaga mod_headers)

Header set Retry-After “3600”

Zmień IP i ścieżki webhooków na własne. Dzięki temu wp-cron.php i admin-ajax.php nadal działają, a użytkownicy widzą stronę serwisową i status 503.

tryb maintenance na Nginx: wyklucz cron i ważne endpointy

Bardziej elegancko da się to zrobić przez map oraz custom error_page. Załóżmy, że obecność pliku maintenance.enable w katalogu www włącza prace serwisowe.

W bloku http (globalnie) dodaj:

map $request_uri $bypass_maintenance {
default 0;
~^/wp-cron.php$ 1;
~^/wp-admin/admin-ajax.php$ 1;
~^/wp-json/partner-webhook/.* 1;
}

map $request_uri $maintenance_asset {
default 0;
~^/maintenance.html$ 1;
}

W bloku server:

set $maintenance 0;

if (-f $document_root/maintenance.enable) {
set $maintenance 1;
}

Obsługa strony 503

error_page 503 = /maintenance.html;

location = /maintenance.html {
root /var/www/html;
add_header Retry-After “3600”;
}

location / {
if ($maintenance) {
if ($bypass_maintenance = 0) {
if ($maintenance_asset = 0) {
return 503;
}
}
}
try_files $uri $uri/ /index.php?$args;
}

location ~ .php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

Gdy chcesz włączyć prace serwisowe, utwórz pusty plik maintenance.enable. Crony i webhooki działają, a reszta dostaje 503 + Retry-After.

WordPress od strony aplikacji: szybkie opcje i pułapki

  • .maintenance (tryb “briefly unavailable” podczas aktualizacji) włącza się tylko na krótko; to nie jest trwały maintenance. Nie polegaj na nim przy dłuższych pracach.

  • Wtyczki trybu serwisowego często oferują whitelisty IP oraz wykluczenia ścieżek. Upewnij się, że wykluczają co najmniej:

    • /wp-cron.php
    • /wp-admin/admin-ajax.php
    • konkretne endpointy /wp-json/… używane przez integracje
  • Jeżeli zostajesz przy WP‑Cron, testowo wywołaj: https://twojadomena.pl/wp-cron.php?doing_wp_cron=1 podczas aktywnego maintenance — powinien zwrócić 200 (lub 204), a nie 503.

Webhooki, płatności i API podczas prac serwisowych

Najczęstszy ból to operator płatności wysyłający potwierdzenia na endpoint REST. Gdy zwrócisz 503, transakcje mogą ugrzęznąć. Zrób listę krytycznych integracji i wyklucz ich ścieżki, np.:

  • /wp-json/wc/v3/webhooks/…
  • /?wc-api=WC_Gateway_Payu
  • /webhook/payments/…
  • /wp-json/custom/v1/…

W razie wątpliwości, policz od góry do dołu: co musi działać “mimo wszystko”? Cron, AJAX, webhooki, XML‑RPC (jeśli używasz), monitoringi (np. /healthz). Reszta — na 503.

SEO i UX: właściwy status oraz delikatna komunikacja

  • Zwracaj 503 Service Unavailable + nagłówek Retry-After, np. 3600 sekund. To czytelny sygnał dla robotów i narzędzi cache, że to przerwa tymczasowa.

  • Użyj lekkiej, statycznej strony maintenance.html. Im mniej zasobów, tym mniejsze ryzyko błędów i zapętleń.

  • Dodaj lakoniczne, ludzkie wyjaśnienie i przybliżony czas powrotu. To drobiazg, który buduje zaufanie.

Checklista wdrożenia krok po kroku

  1. Zidentyfikuj, co musi działać: WP‑Cron/systemowy cron, webhooki, AJAX, health-check.

  2. Jeśli to możliwe, przełącz się na cron systemowy i wyłącz WP‑Cron (define(‘DISABLE_WP_CRON’, true)).

  3. Przygotuj statyczną maintenance.html.

  4. Skonfiguruj reguły Apache/Nginx z wykluczeniami dla:

  • /wp-cron.php
  • /wp-admin/admin-ajax.php
  • krytycznych webhooków/API
  • opcjonalnie Twojego IP
  1. Włącz 503 i Retry-After tylko dla publicznego frontu.

  2. Przetestuj:

  1. Włącz prace serwisowe (plik flagi, reguła, wtyczka).

  2. Monitoruj logi (access/error) i kolejkę crona.

  3. Po zakończeniu usuń plik flagi/wyłącz reguły i przywróć normalny ruch.

Częste błędy, które zatrzymują zadania w tle

  • Brak wykluczenia wp-cron.php w regułach maintenance.
  • Liczenie na WP‑Cron bez ruchu użytkowników podczas 503 — zadania “nie mają kiedy” się uruchomić.
  • Zablokowanie admin-ajax.php, co potrafi wstrzymać wiele wtyczek.
  • Zapomnienie o webhookach płatności — skutkuje ręcznym odtwarzaniem transakcji.
  • Brak nagłówka Retry-After (roboty i cache “nie rozumieją”, że to chwilowe).
  • Dynamiczna strona maintenance w PHP, która sama zależy od WordPressa — błędne koło.

Testy, zanim dotkniesz produkcji

  • Zrób próbę na stagingu z kopią ruchu (lub przynajmniej symulacją curl).
  • Sprawdź, czy cron systemowy faktycznie uruchamia zaległe zdarzenia (wp cron event list / run).
  • Zakolejkuj “sztuczny” webhook z narzędzia dostawcy i upewnij się, że przechodzi przez maintenance.
  • Monitoruj metryki: liczba zamówień, logi webhooków, kolejka zadań, e-maile transakcyjne.

Podsumowanie: bezpieczne prace serwisowe bez przestojów w automatyzacji

Najważniejsze jest świadome rozdzielenie frontu od back-endowych mechanizmów. Zewnętrzni odwiedzający powinni widzieć 503 i statyczną stronę, a wewnętrzne procesy nadal “oddychać” przez wykluczone ścieżki i/lub cron systemowy. W praktyce najprościej i najpewniej jest:

  • przejść na cron systemowy (wyłączyć WP‑Cron),
  • dodać lekką stronę maintenance,
  • skonfigurować reguły serwera z jasnymi wyjątkami,
  • ustawić 503 z Retry-After,
  • i przetestować to na zimno, zanim dokonasz zmian na produkcji.

Dzięki temu prace w tle trwają, a użytkownicy widzą uporządkowaną, tymczasową komunikację — dokładnie tak, jak powinno to wyglądać w dojrzałym procesie utrzymania serwisu.

Kacper Jedynak

Zostaw swój numer - oddzwonię

Cześć! Zadzwoń +48 572 651 439 lub napisz lub zostaw numer telefonu, a oddzwonię w ciągu 1h i porozmawiamy o ofercie.

Picture of Łukasz Janeczko

Łukasz Janeczko

Programista - DropDigital.pl