Menu
Szybki wybór
Hosting Domeny VPS SSL Kalkulator Porównania FAQ
Aktywne kody
Wszystkie kody rabatowe

Cron — zaawansowana konfiguracja i typowe pułapki

Przypomnienie składni crontab

# ┌───────────── minuta (0-59)
# │ ┌───────────── godzina (0-23)
# │ │ ┌───────────── dzień miesiąca (1-31)
# │ │ │ ┌───────────── miesiąc (1-12)
# │ │ │ │ ┌───────────── dzień tygodnia (0-7, 0 i 7 = niedziela)
# │ │ │ │ │
# * * * * * polecenie

# Przykłady
0 2 * * *    backup.sh          # Codziennie o 2:00
*/5 * * * *  check-health.sh    # Co 5 minut
0 0 1 * *    monthly-report.sh  # 1. dnia każdego miesiąca o północy
0 9-18 * * 1-5  send-digest.sh  # Co godzinę 9-18, pn-pt

Powiązane tematy: podstawy cron job, backup strategia, logi serwera oraz monitorowanie uptime. Do wyboru hostingu z cron job sprawdź kalkulator kosztów.

Zaawansowane opcje składni

# Skróty @
@reboot     polecenie    # Uruchom raz przy starcie systemu
@hourly     polecenie    # Co godzinę (0 * * * *)
@daily      polecenie    # Raz dziennie (0 0 * * *)
@weekly     polecenie    # Raz tygodniowo (0 0 * * 0)
@monthly    polecenie    # Raz miesięcznie (0 0 1 * *)
@yearly     polecenie    # Raz rocznie (0 0 1 1 *)

# Kroki
*/10 * * * *    # Co 10 minut
0 */4 * * *     # Co 4 godziny

# Zakresy i listy
0 9,12,17 * * *     # O 9:00, 12:00, 17:00
0 0 * * 1,3,5       # W poniedziałek, środę, piątek

# Ostatni dzień miesiąca (cronie)
0 0 L * *           # Nie wszystkie implementacje wspierają L

Zmienne środowiskowe w crontab

Środowisko cron jest ubogie — nie ma PATH, HOME ani zmiennych z .bashrc. Zawsze definiuj PATH explicite:

# Edytuj crontab
crontab -e

# Na początku pliku — definicja środowiska
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
HOME=/root
MAILTO=""     # Wyłącz emaile z błędami (domyślnie cron wysyła mail)

# Zamiast krótkiej nazwy używaj pełnej ścieżki
0 2 * * * /usr/bin/php /var/www/app/artisan schedule:run

# Lub załaduj .bashrc (workaround)
0 2 * * * source /root/.bashrc && backup.sh

Logowanie wyjścia i błędów

# Przekieruj stdout i stderr do pliku logu
0 2 * * * /usr/bin/php backup.php >> /var/log/cron-backup.log 2>&1

# Tylko błędy (stdout do /dev/null)
0 2 * * * /usr/bin/php backup.php > /dev/null 2>> /var/log/cron-errors.log

# Wyjście z timestampem
0 2 * * * echo "$(date): START" >> /var/log/backup.log && backup.sh >> /var/log/backup.log 2>&1

# Rotacja logów cronowych (dodaj do /etc/logrotate.d/cron-custom)
/var/log/cron-backup.log {
    weekly
    rotate 4
    compress
    missingok
    notifempty
}

Lockfile — zapobieganie równoległym uruchomieniom

Problem: cron uruchamia nowe zadanie zanim poprzednie się skończyło. Rozwiązanie — lockfile:

#!/bin/bash
# backup.sh z lockfile

LOCKFILE="/tmp/backup.lock"

# Sprawdź czy inny proces nie działa
if [ -f "$LOCKFILE" ]; then
    PID=$(cat "$LOCKFILE")
    if kill -0 "$PID" 2>/dev/null; then
        echo "$(date): Backup już uruchomiony (PID $PID), pomijam" >> /var/log/backup.log
        exit 0
    fi
fi

# Stwórz lockfile z PID
echo $$ > "$LOCKFILE"

# Posprzątaj lockfile przy wyjściu (nawet przy błędzie)
trap "rm -f $LOCKFILE" EXIT

echo "$(date): Backup start" >> /var/log/backup.log
# ... właściwa logika backupu ...
echo "$(date): Backup koniec" >> /var/log/backup.log

Alternatywa: użyj flock:

# W crontab — flock zapewni że działa tylko jedna instancja
0 2 * * * flock -n /tmp/backup.lock /usr/local/bin/backup.sh

WordPress — system cron vs wp-cron

Domyślny wp-cron WordPress jest wyzwalany przez wizytę na stronie — zawodny (nie uruchamia się gdy brak ruchu), spowalnia pierwsze żądanie każdej wizyty. Rekomendacja: wyłącz wp-cron i zastąp systemowym cronem.

# 1. Wyłącz wp-cron w wp-config.php
define('DISABLE_WP_CRON', true);
# 2. Dodaj do crontab — wyzwalaj WP-Cron co 5 minut
*/5 * * * * /usr/bin/php /var/www/html/wp-cron.php > /dev/null 2>&1

# Lub przez WP-CLI (bardziej niezawodne)
*/5 * * * * /usr/local/bin/wp --path=/var/www/html cron event run --due-now > /dev/null 2>&1

Systemd timers — nowoczesna alternatywa dla cron

Na VPS z systemd można używać timerów systemd zamiast crona — oferują lepszą obsługę błędów, integrację z journald i możliwość startu po boocie z opóźnieniem.

# /etc/systemd/system/backup.service
[Unit]
Description=Backup aplikacji

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=www-data
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/backup.timer
[Unit]
Description=Codziennie backup o 2:00

[Timer]
OnCalendar=daily
RandomizedDelaySec=300   # Losowe opóźnienie do 5 minut (rozłożenie obciążenia)
Persistent=true          # Uruchom jeśli pominięto (np. serwer był wyłączony)

[Install]
WantedBy=timers.target
sudo systemctl enable --now backup.timer

# Status
sudo systemctl status backup.timer
sudo systemctl list-timers --all
Cecha Cron Systemd timer
Logowanie Ręczne (redirect) Automatyczne (journald)
Obsługa błędów Email (często blokowany) systemctl status, journalctl
Opóźnienie po starcie Nie Tak (OnBootSec)
Pominięte zadania Gubione Można odrobić (Persistent=true)
Prostota Prosta składnia Dwa pliki

Debugowanie problemów z cron

# Sprawdź logi systemowe crona (Debian/Ubuntu)
grep CRON /var/log/syslog | tail -20

# Lub w systemd
journalctl -u cron --since "1 hour ago"

# Sprawdź czy cron jest uruchomiony
systemctl status cron

# Wyświetl aktualny crontab
crontab -l

# Crontab dla root
sudo crontab -l

# Pliki cron.d, cron.daily itp.
ls /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/