Cron-задачі на сервері: як автоматизувати рутину і звільнити собі 10 годин на тиждень
Уявіть: кожного ранку о 3:00 хтось невидимий заходить на ваш сервер, чистить старі логи, робить бекап бази даних, перезапускає завислий PHP-процес і тихо йде. Ви спите. Сайт працює. Клієнти задоволені. Це не магія і не дорогий адміністратор на зарплаті - це cron, один з найпотужніших і водночас найбільш недооцінених інструментів на будь-якому Linux-сервері. Але ось парадокс: більшість власників сайтів або взагалі не знають про cron-задачі, або налаштовують їх раз і забувають. А потім дивуються, чому бекапи не робляться, кеш переповнений, а сервер повільнішає з кожним тижнем.
Що таке cron і чому він важливіший за ваш ранковий будильник
Cron - це планувальник задач в Unix-подібних системах. Він існує з 1975 року, і за майже 50 років принцип не змінився: ви кажете серверу "роби ось це, в ось цей час, з ось такою періодичністю". Все. Без графічних інтерфейсів, без drag-and-drop, без підписок за $29/місяць. Просто один рядок тексту - і сервер виконує вашу команду як годинник.
Файл, де зберігаються ці інструкції, називається crontab. Кожен користувач системи має свій crontab, і є окремий системний - для задач від імені root. Синтаксис виглядає як набір цифр зі зірочками, і саме тут більшість людей лякаються і закривають термінал. Даремно.
Формат простий - п'ять полів через пробіл, потім команда:
| Поле | Значення | Діапазон | Приклад |
|---|---|---|---|
| Хвилина | Коли запускати (хвилина) | 0-59 | 30 |
| Година | Коли запускати (година) | 0-23 | 3 |
| День місяця | Який день | 1-31 | 15 |
| Місяць | Який місяць | 1-12 | * |
| День тижня | Який день тижня | 0-7 | 1 |
Зірочка (*) означає "кожен". Тобто 30 3 * * * - це "кожного дня о 3:30 ночі". Бачите? Не складніше за налаштування будильника. Тільки цей будильник не для вас - для сервера.
П'ять задач, які мають бути в crontab кожного сервера
Я бачив сотні серверів, де crontab був абсолютно порожній. Це як купити автомобіль і ніколи не міняти масло - якийсь час їде, а потім раптово помирає. Ось мінімальний набір cron-задач, без якого ваш сервер живе в борг:
- Автоматичний бекап бази даних. Щоденно, о 2:00-4:00 ночі. Команда
mysqldumpдля MySQL абоpg_dumpдля PostgreSQL. Без цього ви граєте в рулетку з даними клієнтів. - Ротація та очищення логів. Логи ростуть непомітно, поки не з'їдять весь диск. Щотижневе стиснення та видалення файлів старше 30 днів - це гігієна сервера.
- Перевірка вільного місця на диску. Скрипт, який надсилає email-сповіщення, коли залишається менше 10% простору. Один рядок в cron, який рятує від катастрофи.
- Оновлення SSL-сертифікатів. Якщо використовуєте Let's Encrypt, certbot має автоматично поновлювати сертифікати. Без cron - забудете, і сайт покаже страшне попередження браузера.
- Перезапуск "зомбі"-процесів. PHP-FPM, Node.js, Redis - все це іноді зависає. Проста перевірка раз на 5 хвилин і перезапуск при потребі коштує нуль, а економить години простою.
"Автоматизація - це не про лінь. Це про визнання того, що людський мозок не пристосований виконувати одну й ту ж дію ідеально 365 днів поспіль. Машина - пристосована." - Tom Limoncelli, автор книги "The Practice of System and Network Administration"
Типові помилки, які перетворюють автоматизацію на бомбу сповільненої дії
Cron простий у використанні, але підступний у деталях. Я пам'ятаю випадок, коли клієнт налаштував бекап бази даних кожні 5 хвилин замість кожні 5 годин. Одна зайва зірочка - і сервер генерував 288 дампів на добу по 2 ГБ кожен. Диск закінчився за три дні. У п'ятницю ввечері, звісно.
Ось топ помилок, які я зустрічаю регулярно:
- Відсутність перенаправлення виводу. Cron надсилає результат виконання на email кореневому користувачу. Якщо email не налаштований, вивід накопичується в мертвій поштовій скриньці і їсть місце.
- Використання відносних шляхів. Cron не знає ваш робочий каталог. Пишіть
/usr/bin/php /var/www/site/cron.php, а не простоphp cron.php. - Перекриття задач. Якщо скрипт виконується 15 хвилин, а ви запускаєте його кожні 10 - дві копії почнуть конфліктувати. Використовуйте flock для блокування.
- Забуті задачі. Хтось колись додав тестовий рядок і забув видалити. Через рік ніхто не знає, що це і навіщо, але боїться чіпати.
- Неправильний часовий пояс. Cron працює в часовій зоні сервера. Якщо сервер у Франкфурті, а ви думаєте за київським часом - ваш "нічний" бекап запуститься в прайм-тайм.
Золоте правило: після додавання будь-якої cron-задачі перевіряйте її вручну. Виконайте команду в терміналі, переконайтеся, що вона працює, і тільки тоді довіряйте автоматизації.
Альтернативи та доповнення: коли cron недостатньо
Cron чудовий для простих повторюваних задач. Але у нього є обмеження. Він не вміє реагувати на події ("запусти бекап, коли навантаження впаде нижче 20%"). Він не має вбудованого моніторингу ("попередь мене, якщо задача не виконалася"). І він не підходить для складних ланцюжків залежностей ("спочатку зроби A, потім B, але тільки якщо A пройшло успішно").
Для таких сценаріїв існують більш просунуті інструменти:
| Інструмент | Складність | Найкраще для | Вартість |
|---|---|---|---|
| Cron | Низька | Прості повторювані задачі | Безкоштовно |
| Systemd timers | Середня | Задачі з логуванням і залежностями | Безкоштовно |
| Ansible + cron | Середня | Керування cron на багатьох серверах | Безкоштовно |
| Healthchecks.io | Низька | Моніторинг виконання cron-задач | Від $0 |
| Apache Airflow | Висока | Складні пайплайни обробки даних | Безкоштовно |
Але для 90% хостинг-серверів стандартного cron з додатковим моніторингом через Healthchecks.io або аналоги - більш ніж достатньо. Ідея проста: cron-задача після виконання "пінгує" зовнішній URL. Якщо пінг не прийшов - сервіс надсилає вам сповіщення. Елегантно і майже безкоштовно.
Практичний шаблон: налаштовуємо crontab за 15 хвилин
Досить теорії. Відкривайте термінал і вводьте crontab -e. Ось готовий шаблон, який я використовую як стартову точку для нових серверів:
# Бекап MySQL щодня о 3:00
0 3 * * * /usr/bin/mysqldump -u root mydb | gzip > /backups/db_$(date +%F).sql.gz 2>&1 | logger -t cron-backup
# Видалення бекапів старше 14 днів
30 3 * * * /usr/bin/find /backups/ -name "*.sql.gz" -mtime +14 -delete
# Перезапуск PHP-FPM щонеділі о 4:00
0 4 * * 0 /usr/bin/systemctl restart php8.2-fpm
# Оновлення SSL кожні 12 годин
0 */12 * * * /usr/bin/certbot renew --quiet
# Перевірка диску кожну годину
0 * * * * /scripts/check_disk.sh
Зверніть увагу на кілька речей. Всі шляхи - абсолютні. Час розподілено так, щоб задачі не запускалися одночасно. Бекапи чистяться автоматично. SSL оновлюється з запасом (сертифікат дійсний 90 днів, а перевірка йде двічі на добу).
Для перевірки того, що ваш crontab коректний, використовуйте онлайн-валідатор crontab.guru. Вставляєте свій вираз часу - отримуєте людиночитабельне пояснення. Це як Google Translate, тільки для cron-синтаксису.
Безпека cron-задач: те, про що мовчать туторіали
Ось що рідко згадують у статтях про cron: кожна cron-задача - це потенційна вразливість. Якщо зловмисник отримає доступ до вашого crontab, він може додати задачу, яка запускатиметься з правами вашого користувача. А якщо це root-crontab - з правами суперкористувача.
Базові правила безпеки:
- Ніколи не зберігайте паролі напряму в crontab. Використовуйте файли конфігурації з обмеженими правами (chmod 600) або змінні оточення.
- Обмежте, хто може використовувати cron, через файли
/etc/cron.allowта/etc/cron.deny. - Регулярно переглядайте crontab всіх користувачів:
for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l 2>/dev/null; done - Логуйте виконання задач - стандартний syslog записує запуски, але не результати. Додавайте власне логування.
Один мій знайомий адміністратор виявив у crontab забутого тестового користувача скрипт, який щогодини завантажував файл з невідомого URL. Скрипт був там понад рік. Ніхто не перевіряв. Це як знайти чужі ключі від вашої квартири на дверному килимку - неприємний сюрприз.
Налаштування cron - це не разова задача. Це живий організм, який потребує уваги хоча б раз на місяць. Перегляньте свій crontab прямо зараз. Серйозно - відкрийте термінал і введіть crontab -l. Що ви там побачите? Порожнечу, хаос чи чітку систему? Відповідь на це питання скаже більше про стан вашого сервера, ніж будь-який моніторинг.