Как запускать Python-скрипт по расписанию в Linux через systemd
Настройте запуск Python по расписанию через systemd timer: сервисный пользователь, виртуальное окружение, права на файлы, проверка времени и просмотр логов.
Чтобы запускать Python-скрипт по расписанию на Linux-сервере, оформите его как systemd service и привяжите к нему timer. Сервис задаёт пользователя, рабочую папку и команду запуска; timer отвечает за календарное расписание. Такой вариант подходит для отчётов и небольших фоновых задач, если сервер работает на systemd.
Ниже настроим запуск ежедневно в 08:30 по часовому поясу сервера. Python-код остаётся обычной программой: сначала он должен запускаться вручную из виртуального окружения.
Подготовьте проект
Допустим, проект расположен в /opt/csv-report, а точка входа — merge_csv.py:
/opt/csv-report/
.venv/bin/python
merge_csv.py
data/inbox/
data/out/
Создайте виртуальное окружение и установите зависимости, если они есть:
cd /opt/csv-report
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python merge_csv.py
Убедитесь, что скрипт завершается с кодом 0, читает нужные входные файлы и сохраняет результат туда, куда ожидается. Планировщик не исправит неверные пути, отсутствующие переменные окружения или права на папку.
Создайте отдельного непривилегированного пользователя automation и выдайте ему чтение проекта и запись только в папку результата. Не запускайте регулярную задачу от root, если ей не нужны системные привилегии.
Опишите одноразовый сервис
Создайте /etc/systemd/system/csv-report.service:
[Unit]
Description=Build the scheduled CSV report
[Service]
Type=oneshot
User=automation
Group=automation
WorkingDirectory=/opt/csv-report
ExecStart=/opt/csv-report/.venv/bin/python /opt/csv-report/merge_csv.py
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/csv-report/data/out
Путь в ExecStart должен указывать прямо на Python из виртуального окружения: systemd не запускает интерактивную оболочку и не активирует .venv автоматически. Проверьте, что automation может читать data/inbox, а папка data/out существует и доступна для записи.
Если программе нужны переменные окружения, задайте отдельный файл с ограниченными правами и добавьте EnvironmentFile=/etc/csv-report.env. Не помещайте токены и пароли в публичный репозиторий или командную строку процесса.
Добавьте расписание
Создайте /etc/systemd/system/csv-report.timer:
[Unit]
Description=Run the CSV report every day
[Timer]
OnCalendar=*-*-* 08:30:00
Persistent=true
RandomizedDelaySec=5m
Unit=csv-report.service
[Install]
WantedBy=timers.target
OnCalendar задаёт локальное календарное время сервера. Persistent=true позволяет выполнить пропущенный календарный запуск после повторной активации timer. RandomizedDelaySec добавляет небольшой случайный сдвиг, чтобы множество задач не стартовали строго одновременно. Это не обещание запуска до секунды: systemd допускает окно точности таймера.
До установки проверьте выражение:
systemd-analyze calendar '*-*-* 08:30:00'
timedatectl
Перечитайте units и включите расписание:
sudo systemctl daemon-reload
sudo systemctl enable --now csv-report.timer
systemctl list-timers csv-report.timer
Выражение OnCalendar и поведение Persistent описаны в официальной документации systemd timer; синтаксис календаря проверяет команда systemd-analyze calendar.
Проверьте запуск и разберите сбой
Не ждите следующего утра: запустите сервис вручную и посмотрите его статус и журнал:
sudo systemctl start csv-report.service
systemctl status csv-report.service
journalctl -u csv-report.service --since today
Для такой задачи print() и стандартный Python logging попадут в журнал systemd. Добавляйте туда статус и количество обработанных записей, но не содержимое строк, персональные данные или секреты.
Если сервис не сработал, проверьте по порядку: абсолютные пути, WorkingDirectory, права пользователя automation, зависимости в .venv, переменные окружения и доступность входных файлов. Ошибка задачи не должна считаться успешным пустым отчётом. Для важных операций добавьте в сам скрипт понятный код завершения, безопасные повторы и уведомление об ошибке.
Таймер не заменяет мониторинг результата: смотрите время последнего успешного выполнения и проверяйте, что отчёт действительно обновился. Для задачи дольше интервала запуска отдельно продумайте защиту от параллельного выполнения и повторную обработку.
Соберите автоматизацию целиком
Расписание полезно, когда скрипт уже умеет проверять данные и сохранять воспроизводимый результат. В примере объединения CSV-файлов на Python показана обработка входных выгрузок, а в руководстве по Python-парсерам — получение и проверка данных из разрешённых источников. Оба материала входят в бесплатный курс Python для автоматизации, где эти шаги собраны в проектную последовательность.
по теме
следующий шаг
Собрать первого Telegram-бота
Бесплатный практикум Aiogram 3 помогает пройти путь от первого ответа до FSM и деплоя на VPS.
поделиться
Хотите автоматизировать рутинные задачи?
Создаю парсеры, интеграции и скрипты, которые экономят время команды.