Что означает ошибка Permission denied в cron
Ошибка Permission denied (код завершения 126 или 1) появляется, когда служба cron пытается выполнить запланированную задачу, но операционная система блокирует доступ к файлу, директории или ресурсу. В отчётах вы увидите строки вроде /bin/sh: 1: /path/to/script.sh: Permission denied или Failed to execute: Permission denied.
Планировщик работает в фоне, от имени конкретного пользователя, без интерактивного терминала и с ограниченным набором переменных окружения. Если скрипт или файл вывода требует прав, которых у демона cron нет, выполнение прерывается сразу на старте.
Причины возникновения
- Отсутствует бит выполнения у самого скрипта. Файл может быть доступен для чтения, но не помечен как исполняемый.
- Использование относительных путей в crontab или внутри bash-скрипта.
cronне наследует стандартныйPATHиз вашего профиля. - Неверные права владельца на логи или временные файлы, куда скрипт пытается писать данные.
- Жёсткие политики безопасности (SELinux, AppArmor), которые блокируют запуск нестандартных бинарников или доступ к определённым каталогам.
- Попытка запуска задачи из системного
crontabбез указания пользователя. В/etc/crontabи/etc/cron.d/требуется явное указание имени пользователя перед командой.
Способы решения
Способ 1: Назначение прав на выполнение файла
Проверьте текущие права на ваш скрипт:
ls -l /opt/scripts/backup.sh
Если в первой колонке нет символа x (например, -rw-r--r--), добавьте его:
chmod +x /opt/scripts/backup.sh
💡 Совет: Убедитесь, что интерпретатор, указанный в шебанге (
#!/bin/bashили#!/usr/bin/env python3), также доступен для чтения и выполнения пользователю, от имени которого запускается задача.
Способ 2: Замена относительных путей на абсолютные
cron запускает команды в пустом окружении. Если в crontab написано backup.sh или в скрипте используется ./config.ini, система не найдёт файл или откажет в доступе к текущей директории.
Замените все пути на полные:
# Неправильно для cron
0 2 * * * my_script.sh
# Правильно
0 2 * * * /usr/local/bin/my_script.sh
Внутри самого скрипта явно указывайте полные пути к утилитам:
#!/bin/bash
/usr/bin/rsync -avz /home/user/data /mnt/backup
/usr/sbin/logrotate /etc/logrotate.d/myapp
Способ 3: Настройка прав доступа к логам и рабочим директориям
Частая причина ошибки — попытка записать вывод команды (>> /var/log/cron.log) в каталог, где у пользователя нет прав на запись. Cron запускает задачи от имени владельца crontab, поэтому целевые директории должны принадлежать ему:
sudo chown -R user:user /var/log/myapp
sudo chmod 755 /var/log/myapp
Если вы используете перенаправление вывода в crontab:
# Запускаем как пользователь www-data, логируем ошибки
*/15 * * * * www-data /usr/local/bin/fetch-data.sh >> /var/log/myapp/fetch.log 2>&1
Проверьте, что каталог /var/log/myapp существует и доступен для записи пользователю www-data.
Способ 4: Проверка политик безопасности (AppArmor / SELinux)
В современных дистрибутивах стандартные права chmod могут быть недостаточными. Если система защищена AppArmor (Ubuntu/Debian) или SELinux (RHEL/Alma/Rocky), они могут молча блокировать выполнение.
Проверьте статус AppArmor:
aa-status | grep my_script.sh
Если профиль находится в режиме enforce, переключите его в complain для тестирования:
sudo aa-complain /usr/local/bin/my_script.sh
Для SELinux используйте audit2why для анализа блокировок:
sudo ausearch -m avc -ts recent | audit2why
При подтверждении блокировки добавьте исключение или обновите политики через semodule.
Профилактика
- Тестируйте в чистом окружении. Перед добавлением в cron запускайте скрипт командой
env -i bash /путь/к/script.sh. Она имитирует пустое окружениеcronи сразу покажет проблемы с путями или переменными. - Используйте
sudo -u. Для проверки прав запускайтеsudo -u целевой_пользователь /путь/к/script.sh. Это покажет реальные ограничения задачи до её добавления в расписание. - Настройте уведомления. Добавьте в начало crontab строку
MAILTO="admin@example.com", чтобы система автоматически отправляла отчёты об ошибках на почту. - Фиксируйте пути в скриптах. Добавляйте в начало каждого bash-скрипта
set -euo pipefail. Это заставит выполнение прерываться при первой ошибке прав доступа или отсутствующей команде, упрощая отладку.