Новинка Виртуальный VDS сервер в Нидерландах от 490р
Выберите продукт

systemd-tmpfiles: безопасная очистка /tmp и кэшей вместо cron rm -rf

Когда /tmp разрастается, рука тянется к cron и rm -rf. Разбираем, почему это рискованно, как работает systemd-tmpfiles, где лежат правила tmpfiles.d и как настроить аккуратную очистку кэшей на сервере.
systemd-tmpfiles: безопасная очистка /tmp и кэшей вместо cron rm -rf

В Linux временные файлы живут везде: в /tmp, /var/tmp, кэшах приложений, директориях сборки, каталогах загрузок и промежуточных папках веб-проектов. На рабочей станции это часто просто раздражает, а на VDS может быстро превратиться в инцидент: закончилось место, база не пишет WAL или binlog, PHP не может создать сессию, Nginx получает ошибку при буферизации, пакетный менеджер не обновляется.

Самый привычный ответ из старых инструкций — добавить в cron что-то вроде rm -rf /tmp/*. Работает? Иногда. Безопасно? Не очень. Современный systemd уже содержит инструмент, созданный именно для таких задач: systemd-tmpfiles. Он умеет создавать временные директории с правильными правами, чистить старые файлы по возрасту, учитывать исключения, запускаться при загрузке и по systemd timer. Разберёмся, как использовать его для /tmp и cache cleanup без опасных самодельных скриптов.

Почему cron с rm -rf — плохая идея для /tmp

Команда rm -rf сама по себе не зло. Проблема в том, что она слишком простая для задачи, где важны возраст файла, активные процессы, сокеты, lock-файлы, точки монтирования, права доступа и человеческие ошибки. Очистка временных каталогов кажется рутинной, но именно в таких местах чаще всего прячутся аварии уровня «удалили не то».

Типичный cron-скрипт выглядит коротко:

0 3 * * * root rm -rf /tmp/*

На первый взгляд всё понятно: каждую ночь удаляем содержимое /tmp. На практике возникают вопросы. Что если в /tmp лежит Unix socket сервиса, который сейчас работает? Что если приложение держит временный файл открытым несколько часов? Что если в скрипт позже добавят переменную, она окажется пустой, и путь станет не тем? Что если внутри каталога окажется отдельное монтирование? Что если удалённый открытый файл продолжит занимать место, а администратор решит, что очистка не помогла?

Главная проблема rm -rf в cron — он не знает, что для вас временное, а что временно нужное прямо сейчас.

Можно сделать cron аккуратнее: использовать find, ограничить глубину, добавить -xdev, удалять только старые файлы. Например:

find /tmp -xdev -mindepth 1 -mtime +7 -delete

Это уже лучше, но всё равно остаётся самодельная логика: нужно отдельно создавать директории, выставлять права, продумывать исключения, логировать результат, проверять запуск после перезагрузки. systemd-tmpfiles закрывает эти задачи штатным способом и хранит политику очистки в декларативных правилах tmpfiles.d.

Что делает systemd-tmpfiles

systemd-tmpfiles — утилита из состава systemd, которая применяет правила из каталогов tmpfiles.d. Правила описывают, какие пути нужно создать, какие права назначить, какие файлы очистить по возрасту, какие пути удалить, а какие исключить из обработки.

Важно: это не только «чистильщик /tmp». Через systemd-tmpfiles дистрибутивы и пакеты создают runtime-директории, socket-каталоги, lock-каталоги, кэши и временные структуры, которые должны существовать после загрузки с корректными владельцами и правами.

Обычно участвуют две системные единицы:

  • systemd-tmpfiles-setup.service — применяет правила создания при загрузке системы;
  • systemd-tmpfiles-clean.timer — периодически запускает очистку старых файлов через соответствующий service.

На большинстве дистрибутивов Linux это уже включено из коробки. Проверить можно так:

systemctl status systemd-tmpfiles-clean.timer
systemctl list-timers systemd-tmpfiles-clean.timer
systemctl status systemd-tmpfiles-clean.service

Если timer отключён, его можно включить:

systemctl enable --now systemd-tmpfiles-clean.timer

Команды одинаковы для Debian/Ubuntu, AlmaLinux/Rocky Linux/CentOS Stream/Oracle Linux и Fedora, потому что управление выполняется через systemd. На минимальных контейнерных образах systemd может отсутствовать или работать не как PID 1; в таком случае tmpfiles обычно запускают снаружи, при сборке образа или через оркестратор, но для обычного VDS с полноценной Linux-системой штатный timer — нормальный путь.

Схема работы systemd-tmpfiles и таймера очистки временных файлов

Где лежат правила tmpfiles.d и как работает приоритет

Правила читаются из нескольких каталогов. В разных версиях systemd набор может немного отличаться, но базовая идея такая:

  • /usr/lib/tmpfiles.d/ или /lib/tmpfiles.d/ — правила, поставляемые пакетами дистрибутива;
  • /run/tmpfiles.d/ — временные правила, созданные во время работы системы;
  • /etc/tmpfiles.d/ — локальные правила администратора.

Локальные настройки администратора должны жить в /etc/tmpfiles.d/. Не правьте файлы в /usr/lib/tmpfiles.d/: при обновлении пакета изменения могут быть перезаписаны. Если нужно заменить правило, поставляемое дистрибутивом, обычно создают файл с тем же именем в /etc/tmpfiles.d/ и аккуратно вносят изменения туда.

Посмотреть итоговую конфигурацию удобно командой:

systemd-tmpfiles --cat-config

А для диагностики конкретного каталога можно ограничиться префиксом:

systemd-tmpfiles --clean --prefix=/tmp

Эта команда вручную запускает очистку по правилам, которые относятся к /tmp. Для проверки создания директорий используют --create:

systemd-tmpfiles --create --prefix=/var/cache/myapp

Если ваша версия systemd поддерживает пробный режим, полезно сначала выполнить проверку без изменений:

systemd-tmpfiles --dry-run --clean --prefix=/var/cache/myapp

На старых дистрибутивах параметра --dry-run может не быть. Тогда тестируйте правило на отдельном каталоге, а не сразу на боевом /tmp или каталоге приложения.

FastFox VDS
Облачный VDS-сервер
Виртуальные серверы с быстрым запуском и гибкой конфигурацией от 390₽ / мес
Доступные локации
Россия Нидерланды

Синтаксис tmpfiles.d: минимум, который нужен администратору

Строка правила tmpfiles.d состоит из нескольких полей. В упрощённом виде:

# Type Path Mode User Group Age Argument

Самые полезные типы для задач очистки:

  • d — создать директорию, выставить права и владельца; если указан Age, содержимое может очищаться по возрасту;
  • D — похоже на d, но при операции удаления содержимое директории может быть очищено более агрессивно;
  • e — применить настройки и очистку к существующей директории, не создавая её, если она отсутствует;
  • x — исключить путь из очистки;
  • r — удалить файл или пустую директорию;
  • R — удалить путь рекурсивно, используйте очень осторожно.

Поле Age задаёт возраст: например, 10d для десяти дней, 12h для двенадцати часов, 30min для тридцати минут. Не воспринимайте это как строгий TTL с момента создания файла. systemd-tmpfiles оценивает возраст по файловым метаданным; детали зависят от типа объекта и версии systemd. Для практики важно простое правило: если файл активно меняется или используется, он с меньшей вероятностью будет считаться старым кандидатом на удаление.

Пример отдельной политики для кэша приложения:

# /etc/tmpfiles.d/myapp-cache.conf
# Type Path Mode User Group Age Argument
d /var/cache/myapp 0750 myapp myapp 14d -
d /var/cache/myapp/tmp 0750 myapp myapp 2d -
x /var/cache/myapp/keep - - - - -

Здесь мы создаём основной каталог кэша и временный подкаталог, назначаем владельца myapp, а также исключаем /var/cache/myapp/keep из очистки. Такое правило проще ревьюить, чем shell-скрипт: намерение видно сразу.

Как настроена очистка /tmp по умолчанию

Во многих дистрибутивах базовые правила для /tmp и /var/tmp лежат в файле наподобие tmp.conf внутри каталога с пакетными правилами. Часто там указано, что /tmp очищается быстрее, а /var/tmp хранит файлы дольше.

Это соответствует традиционному смыслу каталогов:

  • /tmp — временные файлы, которые могут исчезнуть после перезагрузки или регулярной очистки;
  • /var/tmp — временные файлы, которым иногда нужно пережить перезагрузку;
  • /run — runtime-данные текущей загрузки, обычно в tmpfs и обычно не предназначены для ручной очистки.

Перед изменениями посмотрите, что уже задано системой:

systemd-tmpfiles --cat-config

Если нужно найти только строки, связанные с временными каталогами, можно использовать обычные инструменты фильтрации:

systemd-tmpfiles --cat-config | grep -E '/tmp|/var/tmp'

Не добавляйте второе конфликтующее правило для /tmp «на всякий случай». Лучше понять существующее правило и при необходимости заменить его через файл с тем же именем в /etc/tmpfiles.d/. Иначе можно получить неочевидный порядок применения и предупреждения в журнале.

Практический сценарий: хотим чистить /tmp через 3 дня

Допустим, на сервере много сборок, временных архивов и файлов загрузок, а /tmp регулярно разрастается. Вы хотите хранить временные файлы не дольше трёх дней. Сначала найдите исходное правило:

systemd-tmpfiles --cat-config | grep /tmp

Затем определите файл, который поставляет это правило. В выводе --cat-config обычно видны заголовки файлов. Если правило находится в пакетном tmp.conf, создайте локальный вариант в /etc/tmpfiles.d/tmp.conf. Не обязательно копировать весь файл бездумно: но если в исходном файле есть исключения для systemd-private каталогов или других служебных путей, их важно сохранить.

Пример локального файла:

# /etc/tmpfiles.d/tmp.conf
# Local tmp cleanup policy
q /tmp 1777 root root 3d -
q /var/tmp 1777 root root 14d -
x /tmp/systemd-private-* - - - - -
X /tmp/systemd-private-*/tmp - - - - -

Тип q часто встречается в системных правилах для /tmp: на файловых системах с поддержкой субтомов он может использовать дополнительные возможности, а в обычном случае ведёт себя близко к созданию директории. Если в вашем дистрибутиве исходное правило использует d, не меняйте тип просто ради красоты — лучше оставить подход, выбранный сопровождающими пакета, и изменить только возраст.

После создания файла проверьте синтаксис и примените очистку вручную:

systemd-tmpfiles --clean --prefix=/tmp
journalctl -u systemd-tmpfiles-clean.service -n 100 --no-pager

Если ошибок нет, дальше будет работать timer. Его расписание можно посмотреть так:

systemctl cat systemd-tmpfiles-clean.timer
systemctl list-timers systemd-tmpfiles-clean.timer

/tmp на tmpfs: удобно, но не всегда бесплатно

Отдельная тема — размещение /tmp в tmpfs. В этом режиме временный каталог находится в памяти и swap, а не на диске. Плюсы очевидны: быстрые временные операции, автоматическое исчезновение данных после перезагрузки, меньше мелкой записи на диск. Но на небольшом VDS tmpfs может внезапно начать конкурировать за RAM с базой, PHP-FPM, Redis или Java-приложением.

Проверить, где смонтирован /tmp, можно так:

findmnt /tmp
df -h /tmp
mount | grep ' /tmp '

Если /tmp уже в tmpfs, очистка по возрасту всё равно может быть полезна: не все серверы перезагружаются часто, а временные файлы могут копиться неделями. Но лимит tmpfs нужно задавать осознанно. Иначе большой upload, распаковка архива или временная таблица приложения может съесть значимую часть памяти.

Пример строки в /etc/fstab для отдельного tmpfs с лимитом:

tmpfs /tmp tmpfs mode=1777,nosuid,nodev,size=1G 0 0

Перед использованием noexec подумайте дважды. Это популярная рекомендация для усиления безопасности, но некоторые установщики, сборщики и старые приложения запускают временные исполняемые файлы из /tmp. На веб-сервере noexec может быть уместен, на CI-сборщике — стать источником странных ошибок.

Мониторинг использования tmpfs и диска для каталога /tmp на сервере

Cache cleanup для приложений: лучше отдельные правила, а не общий пылесос

Хорошая практика — не складывать всё в общий /tmp, если у приложения есть собственный кэш. Для веб-проекта удобнее иметь отдельные каталоги: /var/cache/site, /var/lib/site/tmp, /srv/site/shared/cache. Тогда можно задать разные сроки хранения и исключения.

Например, для PHP-приложения можно разделить кэш шаблонов и временные файлы загрузок:

# /etc/tmpfiles.d/site-cache.conf
d /srv/example/shared/cache 0775 www-data www-data 30d -
d /srv/example/shared/tmp 0770 www-data www-data 1d -
x /srv/example/shared/cache/preload - - - - -

На RHEL-based системах пользователь веб-сервера часто называется apache или используется отдельный пользователь PHP-FPM-пула. Тогда правило будет отличаться владельцем:

# /etc/tmpfiles.d/site-cache.conf
d /srv/example/shared/cache 0775 apache apache 30d -
d /srv/example/shared/tmp 0770 apache apache 1d -
x /srv/example/shared/cache/preload - - - - -

Не копируйте имена пользователей механически. Проверьте, от кого работает процесс:

ps -eo user,group,comm | grep -E 'php-fpm|nginx|apache|httpd'

Для Node.js, Python, Java и Go-сервисов логика такая же: отдельный каталог, отдельный владелец, отдельный срок хранения. Это особенно удобно, когда сервис запускается через systemd и вы заранее знаете пользователя в параметре User unit-файла. Если у вас PHP-проект активно использует Redis или Memcached, отдельно посмотрите, как устроить кэширование PHP-приложений через Memcached и Redis: файловая очистка и in-memory кэш решают разные задачи и хорошо дополняют друг друга.

Как не удалить лишнее: правила безопасности

systemd-tmpfiles безопаснее случайного rm -rf, но это не магическая защита от неверной политики. Если вы напишете рекурсивное удаление важного пути, система постарается выполнить именно это. Поэтому подходите к правилам как к инфраструктурному коду.

  • Не начинайте с R. Для cache cleanup чаще достаточно d или e с возрастом.
  • Не задавайте слишком маленький Age для каталогов, где приложения держат долгие операции: загрузки, экспорт отчётов, временные файлы резервного копирования.
  • Не чистите каталоги баз данных и очередей через tmpfiles, если продукт сам управляет retention.
  • Не меняйте права системного /tmp: там почти всегда нужен режим 1777 со sticky bit.
  • Сначала тестируйте правило на отдельном каталоге с копией структуры.

Sticky bit в режиме 1777 важен: он позволяет разным пользователям создавать файлы в /tmp, но запрещает удалять чужие файлы обычным пользователям. Если случайно поставить 0777, вы ослабите изоляцию между пользователями. Если поставить слишком строгий режим, сломаются приложения, ожидающие стандартное поведение /tmp.

Проверить права можно так:

stat -c '%A %a %U %G %n' /tmp /var/tmp

Ожидаемый режим для классического /tmp1777. В символьном виде это часто выглядит как drwxrwxrwt, где последняя t и есть sticky bit.

Наблюдение и диагностика: почему место не освободилось

После очистки бывает неприятный сюрприз: файлы удалены, а df показывает прежнее использование диска. Частая причина — файл удалён из каталога, но процесс продолжает держать его открытым. Место освободится только после закрытия дескриптора или перезапуска процесса.

Найти такие файлы можно командой:

lsof +L1

Если lsof не установлен, поставьте пакет из репозитория.

Debian/Ubuntu

apt update
apt install lsof

AlmaLinux/Rocky Linux/CentOS Stream/Oracle Linux/Fedora

dnf install lsof

Также полезно сравнивать df и du. df показывает занятое место на файловой системе, а du суммирует видимые файлы. Большая разница часто указывает на удалённые, но открытые файлы, точки монтирования или особенности файловой системы.

df -h /tmp
du -shx /tmp

Журнал запусков tmpfiles смотрите через systemd:

journalctl -u systemd-tmpfiles-clean.service --since today --no-pager

Если правило не сработало, проверьте четыре вещи: включён ли timer, видит ли systemd ваш файл в /etc/tmpfiles.d, нет ли конфликтующего правила, действительно ли файлы старше заданного Age. В спорных случаях временно создайте тестовый каталог и файл с искусственно старым временем изменения:

mkdir -p /var/cache/tmpfiles-test
touch -d '10 days ago' /var/cache/tmpfiles-test/old-file

Затем добавьте отдельное правило для теста и запустите очистку только по этому префиксу. Такой подход безопаснее, чем экспериментировать на каталоге с реальными данными.

Когда всё-таки нужен cron или отдельный systemd timer

systemd-tmpfiles хорошо подходит для файловой политики: создать путь, назначить права, удалить старое содержимое. Но он не должен заменять всю бизнес-логику приложения. Если очистка требует запросов к базе, проверки статуса задач, отправки метрик, удаления связанных объектов в S3-совместимом хранилище или сложной сортировки по размеру, лучше писать отдельную утилиту и запускать её через systemd timer.

Граница простая: если правило можно выразить как «в этом каталоге удалять старше N дней, кроме этих путей» — используйте tmpfiles.d. Если нужно «удалить только завершённые экспорты, которые отмечены в базе и не скачивались пользователем» — это задача приложения.

Даже в таком случае лучше не возвращаться к голому cron. Systemd timer даёт журналирование, зависимости, ограничения ресурсов, единый способ диагностики и понятный статус. Cron остаётся рабочим инструментом, но для серверов на systemd всё чаще удобнее описывать периодические задачи в unit-файлах.

Короткий чек-лист внедрения

  1. Проверьте текущие правила: systemd-tmpfiles --cat-config.
  2. Проверьте timer: systemctl list-timers systemd-tmpfiles-clean.timer.
  3. Не правьте пакетные файлы в /usr/lib/tmpfiles.d или /lib/tmpfiles.d.
  4. Для своих приложений создавайте отдельные файлы в /etc/tmpfiles.d.
  5. Для /tmp сохраняйте режим 1777 и системные исключения.
  6. Сначала запускайте очистку с --prefix, чтобы не затронуть лишние пути.
  7. После очистки проверяйте журнал и открытые удалённые файлы через lsof +L1.

В итоге systemd-tmpfiles даёт аккуратную, предсказуемую и документированную очистку временных файлов. Вместо ночного rm -rf, который живёт в crontab и пугает следующего администратора, вы получаете понятные правила tmpfiles.d, штатный systemd timer и нормальную диагностику через journal. Для VDS это особенно ценно: диск обычно ограничен, простой из-за переполненного /tmp неприятен, а хорошая политика cache cleanup экономит и место, и время на аварийные разборы.

Поделиться статьей

Вам будет интересно

Zabbix Agent 2 на Linux VDS: TLS PSK, systemd и шаблоны мониторинга OpenAI Статья написана AI (GPT 5)

Zabbix Agent 2 на Linux VDS: TLS PSK, systemd и шаблоны мониторинга

Разбираем установку и безопасную настройку Zabbix Agent 2 на Linux VDS: генерируем TLS PSK, подключаем хост в Zabbix, настраиваем ...
Linux sudoers.d и visudo: безопасный sudo для deploy user OpenAI Статья написана AI (GPT 5)

Linux sudoers.d и visudo: безопасный sudo для deploy user

Показываем, как выдать deploy user только нужные sudo-права для выкладки приложения: создать правило в sudoers.d, проверить его че ...
Linux capabilities: как слушать 80 и 443 без запуска приложения от root OpenAI Статья написана AI (GPT 5)

Linux capabilities: как слушать 80 и 443 без запуска приложения от root

Показываем, как разрешить приложению bind privileged ports 80 и 443 без запуска от root: через setcap, cap_net_bind_service и syst ...