Настройка cron-задания: расписание, права и частые ошибки
Задание отрабатывает в shell, но не в cron. Это руководство разбирает пять полей времени, разницу между пользовательской crontab и /etc/cron.d, ловушку PATH и то, как доказать, что задание действительно выполнилось.
Cron-задание настраивается за пять минут, а потом нередко отнимает часы. Команда прекрасно отрабатывает в shell, из cron не происходит ничего, а в логе в лучшем случае написано, что cron что-то запустил. Эта статья начинается ровно там, где обычные руководства заканчиваются: реальные сообщения об ошибках, различия между дистрибутивами и вопрос о том, по каким признакам видно, что задание действительно доработало до конца, а не просто стартовало.
Все сведения относятся к Debian 13 (trixie), Debian 12 (bookworm), Ubuntu 24.04 LTS и Ubuntu 22.04 LTS. Все четыре системы используют один и тот же cron (вариант Vixie Cron от Debian), а не cronie, как Red Hat и Fedora. Дальше, в разделе про часовой пояс, это различие окажется решающим.
Запущена ли вообще служба cron?
В полных установках cron присутствует. В минимальных облачных образах, базовых образах контейнеров и урезанных netinst-установках пакета регулярно нет. Это первый вопрос, который стоит выяснить, прежде чем что-то отлаживать.
command -v crontab
systemctl status cron
Намеренно command -v crontab, а не command -v cron: сама служба лежит в /usr/sbin, а этот каталог в Debian входит только в путь поиска пользователя root. Обычный пользователь просто не получит там никакого вывода, хотя cron установлен. В Ubuntu 24.04 запрос работает и без привилегий. crontab, наоборот, везде лежит в /usr/bin и виден каждому, а systemctl status cron и без того отвечает на более важный вопрос: работает ли служба.
Если службы нет, доустановите её:
apt-get update
apt-get install -y cron
systemctl enable --now cron
В Debian и Ubuntu служба называется cron, а не crond. Тот, кто привык к Red Hat, получит здесь Unit crond.service could not be found. и будет искать не в том месте.
В обычной работе перезапускать ничего не требуется: cron в Debian следит за каталогами crontab через inotify и сам подхватывает изменения. То есть после правки crontab перезапуск не нужен. Исключения: смена системного часового пояса и изменения в /etc/default/cron.
Пять полей и ловушка в пятом
Каждая строка начинается с пяти полей времени, за ними следует команда.
| Поле | Диапазон | Примечание |
| Минута | от 0 до 59 | |
| Час | от 0 до 23 | 24-часовой формат, без часового пояса |
| День месяца | от 1 до 31 | |
| Месяц | от 1 до 12 | также от jan до dec |
| День недели | от 0 до 7 | 0 и 7 оба обозначают воскресенье, также от sun до sat |
30 4 * * * /usr/local/bin/backup.sh # ежедневно в 04:30
*/10 * * * * /usr/local/bin/check.sh # каждые 10 минут
0 2 * * 0 /usr/local/bin/weekly.sh # по воскресеньям в 02:00
15 3 1 * * /usr/local/bin/monthly.sh # 1-го числа в 03:15
0 9-17 * * 1-5 /usr/local/bin/business.sh # по будням ежечасно с 9 до 17
Две детали почти всегда понимают неправильно.
День месяца и день недели связаны через ИЛИ, а не через И. Как только оба поля ограничены, то есть ни в одном из них не стоит звёздочка, задание выполняется, если подходит хотя бы одно из двух. 0 3 13 * 5 означает не «пятницу 13-го», а «каждое 13-е число и вдобавок каждую пятницу». Если вам нужна именно пятница 13-го, проверяйте это внутри самого скрипта.
Шаг делит интервал неравномерно. */7 * * * * срабатывает на минутах 0, 7, 14, 21, 28, 35, 42, 49 и 56, после чего счётчик переходит к следующему часу. Между 56 и 0 остаётся всего четыре минуты. Это касается любого интервала, который не делит нацело 60 или, соответственно, 24. Для «каждые 90 минут» аккуратной записи в cron не существует, здесь лучше взять systemd-таймер.
Как правильно пользоваться crontab -e
Пользовательскую crontab никогда не правят напрямую в /var/spool/cron/crontabs/, только через штатную утилиту:
crontab -e
При первом вызове программа сообщает no crontab for root - using an empty one. На свежеустановленных системах дальше предлагается выбрать редактор. Если редактора нет вообще, например в урезанном образе, вызов прерывается сообщением вроде /usr/bin/sensible-editor: 25: editor: not found. Решение: установить редактор или явно задать нужный.
apt-get install -y nano
EDITOR=nano crontab -e
Главное преимущество crontab -e перед прямой записью файла: проверка при сохранении. Если строка сломана, вы увидите:
"/tmp/crontab.7hK2mn/crontab":3: bad minute
errors in crontab file, can't install.
Do you want to retry the same edit? (y/n)
Номер строки указан верно, а вот поле в сообщении не всегда: bad minute появляется и тогда, когда просто пропущено одно поле, потому что парсер читает всё со сдвигом влево. При успехе процесс завершается строкой crontab: installing new crontab. Только она означает, что изменение принято.
Ещё несколько команд, которые стоит знать:
crontab -l # показать
crontab -l > /root/crontab.bak # сохранить
crontab -u www-data -l # прочитать чужую crontab (от root)
crontab -i -r # удалить, с подтверждением (только в терминале)
Замечание про резервную копию: crontab -l > /root/crontab.bak выводит no crontab for root и возвращает код 1 до тех пор, пока у пользователя вообще нет crontab. Целевой файл при этом всё равно создаётся, размером 0 байт. При чтении статьи по порядку это незаметно, а вот в скрипте, который проверяет код возврата или перезаписывает более старую копию, очень даже заметно.
crontab -r без -i удаляет всю crontab сразу и без вопросов. Клавиши r и e на клавиатуре расположены рядом, так что потеря данных здесь вполне реальна. Приучите себя в терминале к crontab -i -r и делайте копию заранее через crontab -l.
Важно здесь слово «терминал». crontab -i -r — сугубо интерактивная команда. Если стандартный ввод не подключён к терминалу, то есть в скрипте, в cron-задании или в однострочнике вроде ssh host "crontab -i -r", запрос уходит в бесконечный круг: crontab: really delete root's crontab? (y/n) Please enter Y or N: Please enter Y or N: ... повторяется без остановки и за секунды пишет сотни килобайт вывода, а прервать вызов можно уже только извне. Поэтому для всего автоматического берите неинтерактивный вариант и сохраняйте копию заранее:
crontab -l > /root/crontab.bak # сохранить перед удалением
crontab -r # удалить без подтверждения
printf "y\n" | crontab -i -r # оставить подтверждение, подставить ответ
Если существуют /etc/cron.allow или /etc/cron.deny, именно они решают, кому вообще разрешено создавать crontab. Затронутые пользователи получают: You (username) are not allowed to use this program (crontab). Если файл /etc/cron.allow есть, он действует эксклюзивно: любой не перечисленный в нём пользователь заблокирован.
Пользовательская crontab, /etc/crontab и /etc/cron.d
Расписания могут храниться в четырёх местах, и форматы у них разные. Именно здесь возникают ошибки, которые труднее всего найти.
Пользовательская crontab: пять полей
Ведётся через crontab -e, выполняется от имени того пользователя, которому принадлежит, и поля пользователя в ней нет. Если всё же вписать его туда, cron попытается выполнить имя пользователя как команду, и в письме или в логе окажется:
/bin/sh: 1: root: not found
/etc/cron.d: шесть полей
Файлы в /etc/cron.d/ — системные crontab, и между полями времени и командой у них стоит поле пользователя. Это правильное место для заданий, относящихся к приложению или к системе управления конфигурацией, потому что каждый файл можно заменять по отдельности.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
0 3 * * * root /usr/local/bin/backup.sh >> /var/log/kh-backup.log 2>&1
Если забыть поле пользователя, cron примет первое слово команды за имя пользователя, и строка молча провалится, потому что такого пользователя не существует.
Три правила для /etc/cron.d/ нарушают регулярно:
- В имени файла не должно быть точки. Разрешены исключительно буквы, цифры, подчёркивания и дефисы.
backup.cronилиkh-backup.shигнорируются без единого сообщения. Причина в управлении пакетами: так остатки вроде.dpkg-distили.dpkg-oldникогда не выполнятся. Назовите файл простоkh-backup. - Права и владелец должны быть верными. Ожидаются
root:rootи режим 0644. Иначе в логе появляются сообщения вроде(*system*) WRONG FILE OWNER,(*system*) BAD FILE MODEили указание на небезопасный режим, доступный на запись группе или всем остальным. Задание в этом случае не выполняется. - Файл должен заканчиваться переводом строки. cron требует, чтобы каждая запись завершалась символом newline. Если последняя строка обрывается без перевода, она пропускается, причём без единого сообщения: в контрольной проверке с точно таким же файлом, но без завершающего перевода строки, задание не отработало ни разу, ни ошибки, ни строки в логе. Тот, кто создаёт файл через
echo -n, черезprintfбез завершающего\nили из шаблона без пустой строки в конце, теряет ровно последнее задание.
chown root:root /etc/cron.d/kh-backup
chmod 0644 /etc/cron.d/kh-backup
/etc/crontab и каталоги cron.*
У /etc/crontab тоже шесть полей, и этот файл принадлежит дистрибутиву. Меняйте его, только если понимаете зачем. Через run-parts он вызывает каталоги /etc/cron.hourly, cron.daily, cron.weekly и cron.monthly. Скриптам в них нужен бит выполнения, и точки в имени у них тоже быть не должно. backup.sh в /etc/cron.daily/ не выполнится никогда, а backup выполнится. Проверить это можно без запуска:
run-parts --test /etc/cron.daily
Выводятся только те скрипты, которые run-parts действительно запустил бы. Если вашего в списке нет, дело в имени или в бите выполнения.
Почему PATH в cron другой
Это с большим отрывом самая частая причина ситуации «в shell работает, а в cron нет». cron не запускает login-shell. Не читаются ни ~/.bashrc, ни ~/.profile, ни /etc/profile. Для пользовательских crontab cron в Debian задаёт минимальный путь поиска:
PATH=/usr/bin:/bin
В нём нет /usr/local/bin и /usr/sbin. В Debian 12, Debian 13, Ubuntu 22.04 и Ubuntu 24.04 /usr/bin и /usr/sbin по-прежнему остаются разными каталогами, usr-merge затронул только /bin и /sbin. Всё, что вы сами положили в /usr/local/bin, всё из pip install, всё из node под nvm и системные утилиты вроде ufw или iptables для cron попросту не существуют. Сообщение об ошибке будет таким:
/bin/sh: 1: backup.sh: not found
Вторая часть ловушки: cron задаёт SHELL=/bin/sh. В Debian и Ubuntu /bin/sh — ссылка на dash, а не на bash. Любая конструкция bash в заголовке скрипта или прямо в строке crontab ломается:
/bin/sh: 1: [[: not found
/bin/sh: 1: source: not found
/bin/sh: 1: Syntax error: "(" unexpected
Три меры противодействия, именно в таком порядке:
- Использовать абсолютные пути.
/usr/local/bin/backup.shвместоbackup.sh,/usr/bin/phpвместоphp. Это самый надёжный вариант, потому что он не зависит ни от одной переменной окружения. Но путь именно считывайте, а не набирайте по памяти:command -v dateв Debian 13, Debian 12, Ubuntu 24.04 и Ubuntu 22.04 выдаёт/usr/bin/date, а в более старых системах вроде Debian 11 наоборот/bin/date. Строку с неверным путём crontab принимает молча и без предупреждения, она провалится только во время выполнения и опять же тихо. Для контроля выполните один разcrontab -lи один разenv -i /bin/sh -c "/usr/bin/date": неверный путь сразу отзовётся сообщениемnot found. - Задать PATH и SHELL в начале crontab. Присваивания действуют на все последующие строки. Важно: cron при этом не разворачивает переменные,
PATH=$PATH:/opt/binне работает, пишите путь целиком. - Использовать скрипт-обёртку. Строка crontab вызывает только скрипт, а собственное окружение скрипт настраивает себе сам.
#!/bin/bash
set -euo pipefail
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cd /srv/app
exec ./do-the-work.sh
Если хотите узнать, что cron действительно передаёт вашему заданию, попросите его это показать. Впишите на одну минуту:
* * * * * /usr/bin/env > /tmp/cron-env.txt 2>&1
Только этот путь показывает окружение, которое cron задаёт на самом деле. Оболочка, собранная через env -i, лишь приближается к нему, потому что приносит с собой собственный путь по умолчанию. После этого сравните /tmp/cron-env.txt со своим интерактивным окружением. В глаза бросаются обычно не только PATH и SHELL, но и отсутствующие переменные локали. Без LANG всё работает в локали C, а это меняет порядок сортировки, форматы даты и вывод символов вне ASCII. Скрипты, рассчитанные на LANG=de_DE.UTF-8, ведут себя в cron иначе. Отсутствует и ssh-agent, поэтому заданиям с доступом по SSH нужен ключ без парольной фразы и явное -i.
Последняя мелкая подлость в этой категории: знак процента. В строке crontab неэкранированный % превращается в перевод строки, а всё, что идёт после него, попадает команде на стандартный ввод. Значит, форматы даты нужно экранировать.
0 2 * * * /usr/bin/tar -czf /backup/web-$(date +\%F).tar.gz /var/www
Перенаправление вывода, письма и «No MTA installed»
По умолчанию всё, что задание выводит в stdout или stderr, cron отправляет письмом владельцу crontab. На сервере без почтовой системы это оседает в логе:
(CRON) info (No MTA installed, discarding output)
Это не ошибка задания. Строка означает лишь, что вывод появился, а принять его было некому. Молчаливое задание такой строки не порождает. Поэтому она даже полезна как сигнал: если она возникла внезапно, значит, задание начало что-то выводить, чаще всего сообщение об ошибке.
Для перенаправления есть три разумных шаблона:
# всё в лог-файл, включая ошибки
0 3 * * * /usr/local/bin/backup.sh >> /var/log/kh-backup.log 2>&1
# обычный вывод отбросить, ошибки по-прежнему письмом
0 3 * * * /usr/local/bin/backup.sh > /dev/null
# всё в journal, с понятной меткой
0 3 * * * /usr/local/bin/backup.sh 2>&1 | /usr/bin/logger -t kh-backup
Вариант > /dev/null 2>&1 популярен и опасен: он выбрасывает и все сообщения об ошибках. Задание, которое падает уже четыре месяца, выглядит тогда точно так же, как исправно работающее. Если письма вам не нужны, лучше поставьте MAILTO="" в начале crontab и пишите вывод в файл. Если письма нужны на конкретный адрес, задайте MAILTO=alerts@example.org, но для этого потребуется установленная почтовая система.
Собственные лог-файлы в /var/log/ растут без ограничений. Заведите для них небольшое правило в /etc/logrotate.d/, иначе самое успешное cron-задание однажды заполнит накопитель.
По каким признакам видно, что задание действительно отработало
Здесь быстрая инструкция расходится с надёжной проверкой. cron записывает запуск задания. Ни завершение, ни код возврата он не записывает. Строка CMD в логе доказывает только то, что cron запустил оболочку, а не то, что ваш скрипт отработал успешно.
Логи читаются по-разному в зависимости от системы:
journalctl -u cron --since "30 min ago"
journalctl -t CRON --since today
В Debian 12 и Debian 13 это единственный путь, потому что начиная с bookworm rsyslog по умолчанию больше не устанавливается. Файла /var/log/syslog там, как правило, уже нет. Тот, кто ищет его и не находит, ошибочно считает, что задание не запускалось.
В Ubuntu 22.04 и 24.04 rsyslog обычно присутствует, там дополнительно работает:
grep CRON /var/log/syslog
Отдельного файла /var/log/cron.log ни в одной из четырёх версий из коробки нет. Соответствующее правило в /etc/rsyslog.d/50-default.conf закомментировано. Не ищите этот файл, он существует, только если кто-то включил правило сам.
Поэтому чистое подтверждение приходит из самого задания. Пусть скрипт в конце запишет отметку времени и код возврата:
#!/bin/bash
set -euo pipefail
trap 'echo "$(date -Is) kh-backup завершён, exit $?" >> /var/log/kh-backup.log' EXIT
# основная работа
Так у вас появляются три доказательства вместо одного: строка CRON в journal (cron запустил задание), финальная строка в вашем лог-файле (скрипт дошёл до конца) и код возврата (завершился корректно). Задание работает только тогда, когда сходятся все три.
Если задание может выполняться дольше собственного интервала, дополнительно защитите его от наложения. Иначе однажды параллельно стартуют десять экземпляров и уронят сервер:
*/5 * * * * /usr/bin/flock -n /var/lock/kh-sync.lock /usr/local/bin/sync.sh
flock -n завершается сразу, если один экземпляр уже работает. Утилита входит в util-linux и есть во всех четырёх системах.
@reboot и почему systemd чаще всего лучше
С помощью @reboot команду можно выполнить при старте системы. Рядом с ним есть @daily, @hourly, @weekly, @monthly и @yearly, каждый из которых заменяет собой все пять полей времени.
@reboot /usr/local/bin/start-app.sh
Выглядит удобно, но имеет три серьёзные слабости:
- Момент срабатывания — это не «после загрузки», а «когда стартует cron». Будут ли к этому моменту готовы сеть, база данных или точка монтирования, зависит исключительно от везения. Обычный костыль: поставить перед командой
sleep 30, но так проблема лишь откладывается. - Перезапуск службы cron заново запускает @reboot. Команда
systemctl restart cron, например после обновления пакетов, запустит ваше приложение во второй раз, хотя первый экземпляр ещё работает. - Никакого контроля нет. Ни кода возврата, ни перезапуска после сбоя, ни статуса.
Для всего, что должно работать постоянно, нужен systemd-сервис, а не cron-задание. Для периодических задач лучше подходит таймер. Достаточно двух файлов:
[Unit]
Description=KernelHost Backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
[Unit]
Description=KernelHost Backup ежедневно
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=900
[Install]
WantedBy=timers.target
Активируется таймер, а не сервис:
systemctl daemon-reload
systemctl enable --now kh-backup.timer
systemctl list-timers kh-backup.timer
Три решающих преимущества перед cron: Persistent=true догоняет пропущенный запуск после следующей загрузки, а cron молча его пропускает. Код возврата попадает в systemctl status kh-backup.service, то есть результат виден без собственного логирования. А полный вывод доступен через journalctl -u kh-backup.service, без перенаправления и без писем. Путь поиска у systemd, кстати, щедрее, чем у cron, и по умолчанию содержит в том числе /usr/local/bin, но совсем без собственных добавок он всё равно остаётся скудным.
Для задач при старте системы замените @reboot сервисом с явными зависимостями:
[Unit]
After=network-online.target
Wants=network-online.target
Так ваше задание гарантированно стартует только тогда, когда сеть действительно поднялась. Подробнее о юнитах и их устройстве написано в статье создание systemd-сервиса.
Часовой пояс, UTC и переход на летнее время
cron всегда считает по системному часовому поясу из /etc/localtime. На многих серверах и почти во всех облачных образах это UTC. Задание 0 3 * * * отработает тогда летом в 05:00 по центральноевропейскому летнему времени, а не в 03:00. Сначала выясните, с чем вы имеете дело:
readlink -f /etc/localtime
timedatectl show -p Timezone --value
date
date -u
readlink -f /etc/localtime называет путь в /usr/share/zoneinfo, а значит и фактически действующую зону, например /usr/share/zoneinfo/Etc/UTC или /usr/share/zoneinfo/Europe/Vienna. Команда работает во всех четырёх версиях, в том числе там, где systemd не запущен. timedatectl show -p Timezone --value выдаёт ту же информацию коротко и в машиночитаемом виде, но требует systemd.
От чего стоит отвыкнуть, так это от заглядывания в /etc/timezone. Debian 13 этот файл больше не поставляет, cat /etc/timezone заканчивается там сообщением cat: /etc/timezone: No such file or directory, и установка tzdata его не возвращает. В Debian 12, Ubuntu 24.04 и Ubuntu 22.04 он ещё есть, так что ответ различается от версии к версии. Решающей в любом случае остаётся только символьная ссылка /etc/localtime: значение, вписанное вручную в /etc/timezone, не меняет ни системный часовой пояс, ни, соответственно, момент срабатывания ваших заданий.
Системный часовой пояс можно сменить в любой момент, после этого стоит перезапустить cron, чтобы служба гарантированно подхватила изменение:
timedatectl set-timezone Europe/Vienna
systemctl restart cron
На системах без работающего systemd вместо этого задайте символьную ссылку напрямую, результат тот же и сразу проверяется командой readlink -f /etc/localtime:
ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime
Теперь пункт, который во многих руководствах изложен неверно: cron в Debian и Ubuntu не знает переменной CRON_TZ. Она пришла из cronie, то есть из cron в Red Hat, Fedora и AlmaLinux. В Debian 13, Debian 12, Ubuntu 24.04 и Ubuntu 22.04 часового пояса на пользователя или на отдельную crontab не существует. Если вписать там в crontab TZ=Europe/Vienna, это подействует исключительно на окружение выполняемых команд, то есть date внутри скрипта покажет венское время. Сам момент срабатывания это не затрагивает вообще никак, он по-прежнему определяется системным часовым поясом. Кто этого не замечает, получает задание, которое выглядит настроенным правильно и всё равно срабатывает на два часа мимо.
Остаётся три чистых пути: выставить подходящий системный часовой пояс, пересчитать время в UTC самостоятельно или перейти на systemd-таймер, который принимает часовой пояс прямо в расписании. Проверить это можно без риска:
systemd-analyze calendar "Mon..Fri 03:00 Europe/Vienna"
Вывод называет ближайшее срабатывание конкретной датой. Это самая надёжная проверка, которую можно сделать до активации.
И практический совет про летнее время: не планируйте задания между 02:00 и 03:00. В марте этого часа не существует, в октябре он существует дважды. В зависимости от задания это означает пропущенный или сдвоенный запуск, и то и другое случается раз в год и плохо воспроизводится. 01:30 или 03:30 — спокойные альтернативы. В systemd-таймерах дополнительно помогает Persistent=true, тогда пропущенный запуск будет наверстан.
Быстрая диагностика за семь шагов
Если cron-задание не работает, пройдите по этому списку по порядку. Он покрывает практически все случаи.
- Служба работает?
systemctl status cron. Нет службы, нет и задания. - Запись вообще сохранилась?
crontab -lдля пользовательских заданий, иначе посмотрите файл в/etc/cron.d/. Проверьте имя файла без точки, режим 0644, владельца root и завершающий перевод строки. - cron его вообще запускал?
journalctl -t CRON --since today. Если строки CMD нет, проблема в расписании или в файле, а не в скрипте. - Число полей верное? Пять полей в пользовательской crontab, шесть в
/etc/cron.dи/etc/crontab. - Абсолютные пути? Каждую команду и каждый скрипт вписывайте с полным путём, а сам путь определяйте заранее через
command -v, а не набирайте по памяти. - Окружение проверено? Один раз впишите
* * * * * /usr/bin/env > /tmp/cron-env.txt 2>&1, подождите минуту, сравните. - Тестировать в контексте cron. Запускайте скрипт не в своей оболочке, а с пустым окружением:
env -i PATH=/usr/bin:/bin /bin/sh -c '/usr/local/bin/backup.sh'. Путь поиска здесь указывается намеренно. Один толькоenv -i /bin/shокружение действительно очищает, но dash затем выставляет себе собственный путь по умолчанию/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, а он щедрее, чем у cron. Именно те ошибки, о которых здесь идёт речь, остались бы при этом незамеченными. Если вызов провалится, причина найдена, и ждать следующего срабатывания не придётся.
Последний пункт самый ценный. Почти каждое cron-задание, которое «необъяснимо» не работает, воспроизводимо падает, стоит запустить его с пустым окружением. Так загадка, которая проявляется раз в 24 часа, превращается в ошибку, устранимую за десять секунд.
Тем, кто регулярно снимает резервные копии через cron-задание, стоит дополнительно защитить и целевую сторону. Подходящие рекомендации собраны в нашей статье о защите Linux-сервера.
Частые вопросы
Почему скрипт работает в shell, но не работает как cron-задание?
Что означает сообщение No MTA installed, discarding output?
Поддерживают ли Debian и Ubuntu переменную CRON_TZ?
Почему мой файл в /etc/cron.d игнорируется?
Где найти логи cron в Debian 12 и 13?
Доказывает ли строка CMD в логе, что задание отработало успешно?
Что выбрать: @reboot или systemd-сервис?
2026 KernelHost GmbH. Все права защищены. Эта инструкция охраняется авторским правом. Публикация на других сайтах, в том числе частично или в изменённом виде, без нашего письменного согласия не разрешается. Цитирование с указанием источника и активной ссылкой мы приветствуем.

