Почему cron не запускается: 7 причин и как их проверить
Классическая ситуация: команда работает в терминале, вы добавляете её в crontab — и ничего не происходит. Логов нет, ошибок нет, просто тишина.
Ниже причины по убыванию частоты, с командами для проверки.
1. Урезанный PATH
Самая частая причина. Cron запускает задачи с минимальным окружением: обычно это только /usr/bin:/bin. Ваш .bashrc не подключается, а nvm, pyenv и rbenv недоступны.
Посмотреть, что видит cron:
* * * * * env > /tmp/cron-env.txt
Подождите минуту и сравните файл с выводом env в терминале.
Решение — указывать абсолютные пути:
0 3 * * * /usr/local/bin/python3 /opt/app/task.py
Либо задать PATH в начале crontab:
PATH=/usr/local/bin:/usr/bin:/bin
2. Нет перевода строки в конце файла
Ошибка, которую сложно заметить. Если последняя строка crontab не заканчивается символом новой строки, cron молча её игнорирует.
crontab -l | tail -c 1 | xxd
Должно вывести 0a. Если нет — откройте crontab -e, поставьте курсор в конец последней строки и нажмите Enter.
3. Символ % не экранирован
В crontab % — специальный символ: он превращается в перевод строки, а всё после первого % уходит команде на stdin.
# не сработает
0 3 * * * tar -czf /backup/site-$(date +%Y%m%d).tar.gz /var/www
# правильно
0 3 * * * tar -czf /backup/site-$(date +\%Y\%m\%d).tar.gz /var/www
4. Задача запускается, но падает
Cron отправляет вывод на локальную почту, которую обычно никто не читает. Перенаправьте вывод в файл:
0 3 * * * /opt/backup.sh >> /var/log/backup.log 2>&1
Ключевое здесь — 2>&1. Без него в лог попадёт только stdout, а ошибки исчезнут.
5. Сервис cron не запущен
systemctl status cron # Debian, Ubuntu
systemctl status crond # RHEL, CentOS, Rocky
Отдельно проверьте, что задача вообще попала в планировщик:
grep CRON /var/log/syslog | tail -20
На системах без syslog поможет journalctl -u cron --since today.
6. Права на файл и shebang
ls -l /opt/backup.sh
У файла должен быть бит исполнения (x). Если его нет:
chmod +x /opt/backup.sh
И первая строка скрипта должна указывать интерпретатор:
#!/usr/bin/env bash
7. Предыдущий запуск ещё не завершился
Если прошлый запуск завис, следующий может конфликтовать с ним за ресурсы или лок-файл. Защититься помогает flock:
0 * * * * /usr/bin/flock -n /tmp/task.lock /opt/task.sh
Флаг -n означает: если лок занят, новый запуск сразу завершается, а не встаёт в очередь.
Главная проблема остаётся
Все семь пунктов объединяет одно: о сбое вы узнаёте постфактум. Скрипт молчал неделю, и обнаружилось это случайно — когда понадобился бэкап.
Классический мониторинг здесь не помогает: сервер отвечает, диск на месте, процессы работают. Просто задача не выполнилась.
Решение — обратная логика. Скрипт сам сообщает об успешном завершении, а если сообщение не пришло вовремя, приходит алерт:
0 3 * * * /opt/backup.sh && curl -fsS -m 10 --retry 3 https://opspulse.ru/ping/<uuid>
Оператор && гарантирует, что пинг уйдёт только при успешном завершении. Не отработала задача — через заданный допуск приходит уведомление в Telegram или на почту.
Если задача запускается не через равные промежутки, а, например, по понедельникам и четвергам, в OpsPulse можно указать то же cron-выражение, что и в вашем crontab. Тогда пинг будет.
Проверьте, что ваши задачи реально работают
Одна строка в crontab — и вы узнаете о сбое раньше клиента. Бесплатный тариф навсегда.
Начать бесплатно