Настройка cron jobs: автоматические задачи на сайте в 2026

За 10+ лет работы с сайтами я понял простую истину: задачи, которые можно автоматизировать, должны быть автоматизированы. И cron jobs — это основа всей автоматизации на Linux-серверах.

Честно говоря, когда я только начинал работать веб-разработчиком, то делал многие вещи вручную. Обновлял кеш, чистил логи, отправлял отчёты. А потом понял, что трачу на это часы каждую неделю. Cron решил все эти проблемы раз и навсегда.

Что такое cron и зачем он нужен

Cron — это демон (фоновый процесс) в Unix-подобных системах, который выполняет задачи по расписанию. Название происходит от греческого «chronos» — время. На деле это ваш личный помощник, который работает 24/7 и никогда не забывает выполнить задачу.

Я использую cron практически на всех проектах. Вот типичные задачи, которые автоматизирую:

У одного клиента был интернет-магазин с 50 000 товаров. Каждый день нужно было обновлять цены из 1С, проверять остатки, пересчитывать скидки. Раньше менеджер делал это вручную каждое утро — полтора часа работы. После настройки cron всё происходит автоматически в 6 утра, до открытия офиса.

ℹ️
Важно знать: Cron работает в контексте системного пользователя, поэтому у него могут быть другие переменные окружения и права доступа, чем при запуске скриптов через веб-интерфейс.

Синтаксис crontab и форматы записей

Расписание cron записывается в специальном формате, который многих пугает на первый взгляд. Но на самом деле всё просто. Формат состоит из пяти полей:

* * * * * команда
│ │ │ │ │
│ │ │ │ └─── день недели (0-7, где 0 и 7 = воскресенье)
│ │ │ └───── месяц (1-12)
│ │ └─────── день месяца (1-31)
│ └───────── час (0-23)
└─────────── минута (0-59)

Грубо говоря, читать нужно слева направо: минута, час, день месяца, месяц, день недели. Вот несколько примеров, которые я часто использую:

# Каждую минуту
* * * * * /path/to/script.sh

# Каждый день в 3:30 утра
30 3 * * * /usr/bin/php /var/www/backup.php

# Каждый понедельник в 9:00
0 9 * * 1 /var/www/html/weekly_report.php

# Каждое 1 число месяца в полночь
0 0 1 * * /usr/bin/mysql-dump backup.sql

# Каждые 15 минут в рабочие дни
*/15 * * * 1-5 /var/www/check_queue.php

# Дважды в день: в 8:00 и 20:00
0 8,20 * * * /usr/bin/php /var/www/sync_prices.php

Специальные символы делают cron очень гибким:

Есть также предопределённые макросы, которые я использую для читаемости:

💡
Лайфхак: Используйте онлайн-генераторы cron выражений типа crontab.guru для проверки синтаксиса. Они покажут, когда именно будет выполняться ваша задача.

Настройка cron jobs на сервере

Управление cron осуществляется через команду crontab. Я всегда начинаю с просмотра текущих задач:

# Показать текущие cron jobs
crontab -l

# Редактировать crontab текущего пользователя
crontab -e

# Удалить все cron jobs текущего пользователя
crontab -r

# Работа с cron другого пользователя (от root)
crontab -u username -l
crontab -u username -e

При первом запуске crontab -e система предложит выбрать редактор. Я рекомендую nano для новичков или vim для опытных пользователей.

Вот как я обычно настраиваю cron для типичного веб-проекта. Создаю файл /var/www/html/cron_tasks.txt с задачами:

# Резервное копирование БД каждую ночь в 2:00
0 2 * * * /usr/bin/mysqldump -u backup_user -pPASSWORD database_name > /backups/db_$(date +\%Y\%m\%d).sql

# Очистка старых логов каждое воскресенье
0 3 * * 0 find /var/log/apache2/ -name "*.log" -mtime +30 -delete

# Обновление курсов валют каждый час в рабочее время
0 9-18 * * 1-5 /usr/bin/php /var/www/html/update_rates.php

# Проверка очереди задач каждые 5 минут
*/5 * * * * /usr/bin/php /var/www/html/process_queue.php

# Генерация sitemap.xml каждую ночь
0 4 * * * /usr/bin/php /var/www/html/generate_sitemap.php

А затем загружаю их в crontab:

crontab /var/www/html/cron_tasks.txt

На практике я предпочитаю создавать отдельный скрипт-обёртку для каждой задачи. Это упрощает отладку и логирование. Вот пример такого скрипта:

#!/bin/bash

# backup_wrapper.sh
LOG_FILE="/var/log/cron_backup.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

echo "[$DATE] Starting backup process" >> $LOG_FILE

# Выполняем резервное копирование
if /usr/bin/mysqldump -u backup_user -pPASSWORD mysite_db > /backups/db_$(date +%Y%m%d).sql; then
    echo "[$DATE] Backup completed successfully" >> $LOG_FILE
    # Удаляем бэкапы старше 7 дней
    find /backups/ -name "db_*.sql" -mtime +7 -delete
else
    echo "[$DATE] Backup failed!" >> $LOG_FILE
    # Отправляем уведомление об ошибке
    echo "Backup failed on $(hostname)" | mail -s "Backup Error" admin@example.com
fi

И в crontab записываю просто:

0 2 * * * /var/www/scripts/backup_wrapper.sh

Cron для WordPress сайтов

WordPress имеет собственную систему cron — WP-Cron, но она работает только при посещении сайта. Для стабильной работы я всегда отключаю WP-Cron и настраиваю системный cron.

Сначала добавляю в wp-config.php:

// Отключаем встроенный WP-Cron
define('DISABLE_WP_CRON', true);

Затем настраиваю системный cron для запуска wp-cron.php:

# Запуск WordPress cron каждые 15 минут
*/15 * * * * /usr/bin/php /var/www/html/wp-cron.php

# Или через curl (если нужны cookie и сессии)
*/15 * * * * /usr/bin/curl -s https://yoursite.com/wp-cron.php >/dev/null 2>&1

Для WordPress я также часто настраиваю дополнительные задачи:

# Оптимизация базы данных раз в неделю
0 3 * * 0 /usr/bin/wp db optimize --path=/var/www/html

# Обновление плагинов (осторожно, только на dev-окружении!)
0 4 * * 1 /usr/bin/wp plugin update --all --path=/var/www/html

# Генерация превью изображений для новых размеров
0 5 * * * /usr/bin/wp media regenerate --yes --path=/var/www/html

# Очистка кеша объектов
*/30 * * * * /usr/bin/wp cache flush --path=/var/www/html

У меня был клиент с новостным сайтом на WordPress, который публиковал 50+ статей в день. WP-Cron не справлялся с отправкой уведомлений подписчикам — письма отправлялись с задержкой в несколько часов. После перехода на системный cron всё заработало как часы.

⚠️
Внимание: При использовании curl для запуска wp-cron.php убедитесь, что сайт доступен по HTTPS и нет проблем с SSL-сертификатом. Иначе cron будет падать с ошибками.

Cron для Битрикс проектов

В Битрикс есть свой механизм агентов, но для тяжёлых задач я всё равно использую системный cron. Особенно это важно для интернет-магазинов с большим каталогом.

Стандартная настройка для Битрикс:

# Запуск агентов Битрикс каждые 5 минут
*/5 * * * * /usr/bin/php -f /var/www/html/bitrix/modules/main/tools/cron_events.php

# Или через curl
*/5 * * * * /usr/bin/curl -s "https://yoursite.com/bitrix/tools/cron_events.php" >/dev/null 2>&1

Но на практике я создаю более продвинутую схему. Вот пример скрипта для обработки агентов с логированием:


И в crontab:

*/5 * * * * /usr/bin/php /var/www/html/cron/bitrix_agents.php

Для интернет-магазинов на Битрикс я также настраиваю:

# Обновление остатков из 1С каждые 30 минут в рабочее время
*/30 9-18 * * 1-5 /usr/bin/php /var/www/html/local/cron/update_catalog.php

# Пересчёт цен со скидками каждую ночь
0 3 * * * /usr/bin/php /var/www/html/local/cron/recalculate_prices.php

# Отправка уведомлений о заканчивающихся товарах
0 10 * * * /usr/bin/php /var/www/html/local/cron/low_stock_notify.php

# Очистка корзин старше 30 дней
0 4 * * * /usr/bin/php /var/www/html/local/cron/clear_old_baskets.php

На одном проекте интернет-магазина автозапчастей каталог обновлялся из 1С каждые 15 минут. 200 000 товаров, изменение цен и остатков. Без правильно настроенного cron сайт просто «умирал» от нагрузки во время обновления.

Cron для Laravel приложений

Laravel имеет отличную систему планировщика задач (Task Scheduler). Вместо создания множества cron записей, я создаю всего одну, которая запускает планировщик Laravel:

# Единственная запись cron для Laravel
* * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1

А всё расписание задач описываю в файле app/Console/Kernel.php:

command('backup:run')
                 ->dailyAt('02:00')
                 ->emailOutputOnFailure('admin@example.com');

        // Обработка очереди писем каждые 5 минут
        $schedule->command('queue:work --stop-when-empty')
                 ->everyFiveMinutes()
                 ->withoutOverlapping();

        // Генерация отчётов по понедельникам
        $schedule->command('reports:generate')
                 ->weeklyOn(1, '09:00')
                 ->onOneServer(); // Если несколько серверов

        // Очистка старых логов раз в месяц
        $schedule->command('logs:clear')
                 ->monthly()
                 ->when(function () {
                     // Дополнительная проверка условий
                     return Storage::disk('local')->size('logs') > 1000000; // 1MB
                 });

        // Пинг внешнего API каждые 30 минут в рабочие часы
        $schedule->call(function () {
            Http::get('https://api.partner.com/ping');
        })->everyThirtyMinutes()->between('9:00', '18:00');
    }
}

Преимущества Laravel Scheduler:

Я также создаю специальные Artisan команды для сложных задач:

# Генерация команды
php artisan make:command ProcessOrders
option('limit');
        $orders = Order::where('status', 'pending')->limit($limit)->get();
        
        $this->info("Processing {$orders->count()} orders...");
        
        foreach ($orders as $order) {
            try {
                $order->process();
                $this->line("Order #{$order->id} processed");
            } catch (\Exception $e) {
                $this->error("Failed to process order #{$order->id}: " . $e->getMessage());
            }
        }
        
        $this->info('Done!');
    }
}

Мониторинг и логирование cron задач

Главная проблема cron — он работает в фоне, и если что-то сломается, вы можете об этом не узнать. Поэтому я всегда настраиваю подробное логирование.

Системные логи cron находятся в /var/log/cron или /var/log/syslog. Но для веб-задач я создаю собственные логи:

# Перенаправление вывода в лог-файл
*/15 * * * * /usr/bin/php /var/www/html/sync.php >> /var/log/cron_sync.log 2>&1

# Логирование с временными метками
*/15 * * * * echo "$(date): Starting sync" >> /var/log/cron_sync.log && /usr/bin/php /var/www/html/sync.php >> /var/log/cron_sync.log 2>&1

# Ротация логов (не даём им разрастись)
0 0 * * * find /var/log/ -name "cron_*.log" -size +10M -exec truncate -s 0 {} \;

Я создал универсальный скрипт-обёртку для логирования cron задач:

#!/bin/bash
# /usr/local/bin/cron_wrapper.sh

SCRIPT_PATH=$1
LOG_DIR="/var/log/cron"
SCRIPT_NAME=$(basename "$SCRIPT_PATH" .php)
LOG_FILE="$LOG_DIR/${SCRIPT_NAME}.log"
PID_FILE="/var/run/cron_${SCRIPT_NAME}.pid"

# Создаём директорию для логов
mkdir -p $LOG_DIR

# Проверяем, не запущен ли уже этот скрипт
if [ -f "$PID_FILE" ]; then
    PID=$(cat "$PID_FILE")
    if ps -p $PID > /dev/null 2>&1; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') - Script already running (PID: $PID)" >> $LOG_FILE
        exit 1
    fi
fi

# Сохраняем PID
echo $$ > $PID_FILE

# Логируем начало выполнения
echo "$(date '+%Y-%m-%d %H:%M:%S') - Starting $SCRIPT_NAME" >> $LOG_FILE

# Выполняем скрипт и логируем результат
if /usr/bin/php "$SCRIPT_PATH" >> $LOG_FILE 2>&1; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $SCRIPT_NAME completed successfully" >> $LOG_FILE
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $SCRIPT_NAME failed with exit code $?" >> $LOG_FILE
    # Отправляем уведомление об ошибке
    echo "Cron job $SCRIPT_NAME failed on $(hostname)" | mail -s "Cron Error" admin@example.com
fi

# Удаляем PID файл
rm -f $PID_FILE

# Ротация лога если он больше 10MB
if [ $(stat -f%z "$LOG_FILE" 2>/dev/null || stat -c%s "$LOG_FILE" 2>/dev/null || echo 0) -gt 10485760 ]; then
    tail -n 1000 "$LOG_FILE" > "${LOG_FILE}.tmp" && mv "${LOG_FILE}.tmp" "$LOG_FILE"
fi

И использую его в crontab:

*/15 * * * * /usr/local/bin/cron_wrapper.sh /var/www/html/sync_prices.php
0 2 * * * /usr/local/bin/cron_wrapper.sh /var/www/html/backup.php

Для критически важных задач настраиваю мониторинг через внешние сервисы. Например, мониторинг сайта может включать проверку успешности выполнения cron задач.

💡
Совет по мониторингу: Используйте Dead Man's Switch паттерн — настройте задачу, которая каждые N минут отправляет ping на внешний сервис. Если ping не приходит, значит что-то сломалось.

Безопасность и лучшие практики

За годы работы я выработал несколько правил безопасности для cron задач. Первое и главное — никогда не запускайте cron от root, если это не absolutely необходимо.

Создаю отдельного пользователя для cron задач:

# Создаём пользователя для cron
sudo useradd -r -s /bin/bash -d /var/www -G www-data cronuser

# Настраиваем права доступа
sudo chown -R cronuser:www-data /var/www/html/scripts/
sudo chmod 750 /var/www/html/scripts/

И настраиваю cron от этого пользователя:

sudo crontab -u cronuser -e

Основные правила безопасности, которых я придерживаюсь:

Пример безопасного скрипта для обновления каталога:

 PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_TIMEOUT => 30
    ]);
    
    // Обновляем товары
    $updated = updateProducts($pdo);
    
    $executionTime = round(microtime(true) - $startTime, 2);
    
    // Логируем успех
    error_log(date('Y-m-d H:i:s') . " - Catalog updated successfully. {$updated} products, {$executionTime}s", 3, '/var/log/cron_catalog.log');
    
} catch (Exception $e) {
    // Логируем ошибку
    error_log(date('Y-m-d H:i:s') . " - Catalog update failed: " . $e->getMessage(), 3, '/var/log/cron_catalog.log');
    
    // Отправляем уведомление
    mail('admin@example.com', 'Catalog Update Failed', $e->getMessage());
    
    exit(1);
} finally {
    // Освобождаем блокировку
    flock($lockHandle, LOCK_UN);
    fclose($lockHandle);
    unlink($lockFile);
}

function updateProducts($pdo) {
    // Логика обновления товаров
    $stmt = $pdo->prepare("UPDATE products SET updated_at = NOW() WHERE status = 'active'");
    $stmt->execute();
    return $stmt->rowCount();
}
?>

Отладка и тестирование cron задач

Отладка cron задач — это отдельное искусство. Главная сложность в том, что cron выполняется в другом контексте, чем веб-запросы. Переменные окружения, пути, права доступа — всё может быть по-другому.

Вот мой чек-лист для отладки проблемных cron задач:

1. Проверяю базовые вещи:

# Работает ли cron вообще?
sudo systemctl status cron

# Есть ли задачи в crontab?
crontab -l

# Какие переменные окружения у cron?
* * * * * env > /tmp/cron_env.txt

2. Тестирую скрипт вручную:

# Запускаю от того же пользователя, что и cron
sudo -u cronuser /usr/bin/php /var/www/html/script.php

# Проверяю с теми же переменными окружения
sudo -u cronuser env -i /usr/bin/php /var/www/html/script.php

3. Добавляю временную отладочную задачу:

# Каждую минуту пишем отладочную информацию
* * * * * echo "$(date): Cron is working" >> /tmp/cron_debug.log 2>&1
* * * * * /usr/bin/whoami >> /tmp/cron_debug.log 2>&1
* * * * * /usr/bin/php -v >> /tmp/cron_debug.log 2>&1

Был случай: клиент жаловался, что cron не работает. Потратил час на поиски проблемы. Оказалось, что скрипт использовал относительные пути, а cron запускается из домашней директории пользователя. Добавил cd /var/www/html в начало команды — всё заработало.

Ещё одна частая проблема — кодировка. Cron может не устанавливать UTF-8 по умолчанию. Поэтому в начале crontab я всегда добавляю:

LANG=ru_RU.UTF-8
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
MAILTO=admin@example.com

Для тестирования новых задач я использую такую схему:

# Сначала запускаю каждую минуту для быстрой проверки
* * * * * /var/www/html/scripts/new_task.php

# После успешного тестирования меняю на нужное расписание  
0 2 * * * /var/www/html/scripts/new_task.php

И обязательно проверяю логи:

# Системный лог cron
sudo tail -f /var/log/cron

# Лог конкретной задачи
tail -f /var/log/cron_new_task.log

# Общий системный лог (на Ubuntu/Debian)
sudo tail -f /var/log/syslog | grep cron

Оптимизация производительности cron

На высоконагруженных проектах важно правильно распределять cron задачи по времени. Если все задачи запускать одновременно, сервер может не выдержать нагрузки.

Я использую принцип «размазывания» нагрузки:

# Плохо - все задачи в одно время
0 3 * * * /var/www/html/backup.php
0 3 * * * /var/www/html/cleanup.php  
0 3 * * * /var/www/html/reports.php

# Хорошо - распределяем по времени
0 3 * * * /var/www/html/backup.php
15 3 * * * /var/www/html/cleanup.php
30 3 * * * /var/www/html/reports.php

Для задач, которые могут выполняться долго, использую очереди. Например, в Laravel:

# В Kernel.php создаём задачи в очереди, а не выполняем сразу
$schedule->job(new ProcessLargeDataset)->hourly()->onQueue('heavy');
$schedule->job(new SendNewsletters)->daily()->onQueue('emails');

И запускаю воркеры очереди через supervisor:

# /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/log/worker.log

На одном проекте интернет-магазина было 15 различных cron задач. Изначально все запускались в 3:00 ночи — сервер «умирал» на 20 минут каждую ночь. После оптимизации распределил задачи с 2:00 до 6:00 утра с интервалом 15-30 минут. Нагрузка стала равномерной.

Также важно мониторить производительность задач:


Альтернативы cron и современные решения

Хотя cron остаётся стандартом де-факто, существуют более современные альтернативы, которые я использую в определённых ситуациях.

Systemd timers — современная замена cron в Linux:

# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup timer
Requires=backup.service

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target
# /etc/systemd/system/backup.service  
[Unit]
Description=Backup service

[Service]
Type=oneshot
User=cronuser
ExecStart=/usr/bin/php /var/www/html/backup.php

Преимущества systemd timers:

Kubernetes CronJobs для контейнеризированных приложений:

# cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: backup-cronjob
spec:
  schedule: "0 2 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: myapp:latest
            command: ["php", "/var/www/html/backup.php"]
          restartPolicy: OnFailure

Облачные решения типа AWS CloudWatch Events, Google Cloud Scheduler, Azure Logic Apps — отличный выбор для cloud-native приложений.

Но честно говоря, для 90% веб-проектов обычный cron остаётся оптимальным выбором. Он простой, надёжный, и работает везде где есть Linux.

Настройка автоматических задач — это инвестиция в стабильность вашего проекта. Правильно настроенный cron экономит часы ручной работы и предотвращает множество проблем. Главное — не забывать про мониторинг и логирование. Автоматизация без контроля может принести больше проблем, чем пользы.

Если у вас сложный проект с множеством задач, обратитесь за поддержкой Битрикс, поддержкой WordPress или доработкой сайта — поможем настроить всё правильно с первого раза.

Нужна помощь с настройкой автоматических задач?

Наши специалисты настроят cron jobs и автоматизируют процессы на вашем сайте.

П
Павел
Веб-разработчик · 10+ лет опыта · Bitrix, WordPress, Laravel

Читайте также

Автоматическое тестирование сайта: зачем и как Версионирование и откат обновлений сайта: настройка 2026 Как настроить автообновление CMS: WordPress, Bitrix, Laravel