Сайт вдруг отдаёт ошибку 500, в админку не войти, база данных перестала сохранять изменения, а в логах — No space left on device. На сервере закончилось место. Обычно это не внезапная беда, а результат месяцев накопления: логов, резервных копий, кэша, которые никто не чистил.
Коротко: посмотрите df -h и df -i, затем найдите крупные каталоги через du или ncdu, не уходя на другие разделы. Если df показывает, что диск занят, а du столько не находит, — место держат удалённые, но ещё открытые файлы. Активные логи не удаляйте, а обнуляйте, и сразу настройте ограничения, чтобы ситуация не повторилась.
Как проявляется нехватка места
| Симптом | Что это значит | Что делать |
|---|---|---|
No space left on device при записи, df -h показывает 100% |
Закончилось место на разделе | Найти крупные каталоги через du или ncdu |
Та же ошибка, но в df -h место есть |
Закончились inode — слишком много мелких файлов | Проверить df -i, найти каталог с файлами |
df показывает занятое место, du его не находит |
Удалённые файлы ещё держит открытыми какой-то процесс | lsof +L1, перезапустить процесс или обнулить файл |
| Сайт отдаёт 500, MySQL или MariaDB не сохраняет данные или не запускается | Базе данных и PHP некуда писать временные файлы, сессии, журналы | Освободить место, затем проверить журнал ошибок базы |
В error.log nginx — (28: No space left on device) или логи перестали пополняться |
Веб-серверу некуда писать логи и временные файлы | Освободить место, переоткрыть логи nginx -s reopen |
По документации MySQL, при заполненном диске сервер раз в минуту проверяет, не освободилось ли место, и раз в десять минут пишет предупреждение в журнал ошибок. Запись при этом ждёт — сайт выглядит «зависшим» (подробнее в разделе How MySQL Handles a Full Disk).
Первая минута: df -h и df -i
df -h
Filesystem Size Used Avail Use% Mounted on
udev 1.9G 0 1.9G 0% /dev
tmpfs 392M 628K 391M 1% /run
/dev/vda1 40G 38G 0 100% /
tmpfs 2.0G 0 2.0G 0% /dev/shm
/dev/vda15 124M 12M 113M 10% /boot/efi
Смотрите на реальные разделы, а не на tmpfs — это память. Если Used меньше Size, а Avail уже ноль, это не ошибка: на ext4 часть блоков по умолчанию (5%) зарезервирована для root. Поэтому службы, работающие от root, ещё какое-то время пишут, а сайты от обычных пользователей уже нет.
Вторая обязательная проверка — inode, то есть количество файлов:
df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/vda1 2621440 2621440 0 100% /
При 100% в IUse% новый файл не создать, даже если гигабайты свободны. Число inode на ext4 задаётся при создании файловой системы, и настройкой его не увеличить — помогает только удаление лишних файлов.
Отдельно проверьте раздел /boot, если он вынесен: он маленький, и его часто заполняют старые ядра — тогда перестаёт устанавливаться обновление ядра.
Где именно занято место
du: по каталогам, сверху вниз
du -xh --max-depth=1 / 2>/dev/null | sort -h
16K /lost+found
7.6M /etc
212M /root
1.9G /usr
3.1G /var
32G /home
38G /
Ключ -x не даёт уходить на другие файловые системы — иначе в подсчёт попадут /proc, сетевые и смонтированные диски. Дальше повторяете команду для самого большого каталога: du -xh --max-depth=1 /home | sort -h, и так до виновника.
Для поиска отдельных больших файлов:
find / -xdev -type f -size +500M -exec ls -lh {} + 2>/dev/null
ncdu: то же самое, но удобнее
ncdu -x /
Программа один раз сканирует диск и показывает интерактивный список: стрелками заходите в каталоги, d удаляет выбранное (с подтверждением), q — выход. Ставится из основных репозиториев Debian и Ubuntu (apt install ncdu), в AlmaLinux — из EPEL. Если места ноль, установить её может не получиться — тогда хватит du.
Если не хватает inode
Ищите каталог, где больше всего файлов:
du --inodes -x --max-depth=1 / 2>/dev/null | sort -n | tail
Чаще всего это сессии PHP, кэш сайтов в виде тысяч мелких файлов, очередь почты или каталог, куда скрипт годами складывает временные файлы.
Удалённые, но открытые файлы
Классическая ситуация: большой лог удалили через rm, а место не освободилось. Файл исчез из каталога, но процесс, который в него пишет, держит его открытым, и данные остаются на диске, пока процесс не закроет файл.
lsof +L1
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
nginx 1187 www-data 5w REG 254,1 6442450944 0 393251 /var/log/nginx/access.log.1 (deleted)
+L1 выводит файлы, у которых не осталось ни одного имени в файловой системе. Если lsof не установлен, то же покажет find /proc/*/fd -ls 2>/dev/null | grep deleted.
Освободить место можно двумя способами: перезапустить или попросить переоткрыть файлы сам процесс (для nginx — nginx -s reopen или systemctl reload nginx), либо обнулить файл через его дескриптор:
truncate -s 0 /proc/1187/fd/5
Где обычно копится
Логи и журнал systemd
du -sh /var/log/* 2>/dev/null | sort -h | tail
journalctl --disk-usage
Archived and active journals take up 3.9G in the file system.
Журнал systemd по умолчанию может занимать до 10% файловой системы (но не больше 4 ГБ). Сократить сразу:
journalctl --vacuum-size=500M
и закрепить лимит в файле /etc/systemd/journald.conf.d/size.conf (описание параметров — в man journald.conf):
[Journal]
SystemMaxUse=500M
После этого — systemctl restart systemd-journald. В Debian 12 и 13 rsyslog по умолчанию не ставится, поэтому основной системный лог — именно журнал. Сжатые старые логи (*.gz, *.1) в /var/log можно удалять. А вот текущий лог, в который пишет служба, только обнуляйте:
truncate -s 0 /var/log/nginx/error.log
Кэши пакетов и старые ядра
# Debian, Ubuntu
apt clean
apt autoremove --purge
# AlmaLinux, Rocky
dnf clean all
dnf remove --oldinstallonly
apt autoremove убирает ненужные зависимости, включая старые ядра. dnf remove --oldinstallonly удаляет старые ядра, оставляя последние и текущее работающее; сколько хранить, задаёт installonly_limit в /etc/dnf/dnf.conf (по умолчанию 3).
Бэкапы, дампы и архивы
Самая частая находка — резервные копии и дампы баз в /root, /home, /var/backups или прямо в каталоге сайта: backup.tar.gz, site_old.zip, db-2025.sql. Заодно проверьте, нет ли копий в публичном каталоге сайта: их могут скачать посторонние.
Если включены бинарные логи MySQL (в MySQL 8.0 и 8.4 они включены по умолчанию), не удаляйте файлы binlog.* вручную — используйте команду сервера:
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY;
Кэш страниц сайтов
Плагины кэширования (у WordPress — каталог wp-content/cache) и fastcgi_cache nginx могут разрастаться без предела. Для nginx задайте max_size в fastcgi_cache_path, для плагинов — срок жизни кэша.
Docker
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 14 5 9.214GB 6.871GB (74%)
Containers 7 5 1.032GB 0B (0%)
Local Volumes 6 4 3.5GB 812.4MB (23%)
Build Cache 41 0 2.106GB 2.106GB
docker system prune удаляет остановленные контейнеры, неиспользуемые сети, «висячие» образы и кэш сборки; с -a — все неиспользуемые образы. Ключ --volumes без понимания, что лежит в томах, не используйте — там могут быть данные. Ещё один источник — логи контейнеров: у драйвера json-file по умолчанию нет ограничения размера, его задают через log-opts (max-size, max-file) в /etc/docker/daemon.json. Новые настройки действуют только на контейнеры, созданные после перезапуска Docker.
Как освобождать безопасно
Если сервер нужно вернуть к жизни прямо сейчас, начните с того, что точно ничего не сломает: сократите журнал systemd, удалите сжатые старые логи и почистите кэш пакетов. Обычно это даёт достаточно места, чтобы заработали база данных и сайт, а дальше можно спокойно разбираться с главной причиной.
journalctl --vacuum-size=200M
find /var/log -type f -name '*.gz' -delete
apt clean # или dnf clean all
Дальше несколько правил, которые я соблюдаю при любой чистке:
- Не удаляйте активные логи — обнуляйте их через
truncate -s 0. Удалённый лог продолжит занимать место, пока служба его не закроет. - Не трогайте вручную
/var/lib/mysql,/var/lib/docker,/var/lib/dpkg,/var/lib/rpm: такие каталоги чистятся только средствами самих программ. - Прежде чем удалять бэкап, убедитесь, что его копия есть в другом месте.
- Освободив место, перезапустите службы, которые падали: базу данных, PHP-FPM, веб-сервер. Проверьте журнал ошибок базы: операции, прерванные нехваткой места, могут оставить таблицы в неисправном состоянии.
Бывает и обратная ситуация: Apache пишет No space left on device, хотя место есть и inode тоже. Это нехватка семафоров, а не диска — разбор в статье Apache: No space left on device: Couldn’t create accept lock.
Типичная история
Чаще всего диск заполняют резервные копии. Скрипт каждую ночь архивирует файлы и базы сайтов и складывает архивы в каталог на том же диске, где лежат сами сайты, а удалять старые копии никто не настроил. Несколько месяцев всё работает, пока архивы не займут диск целиком: тогда сайты начинают отдавать ошибки, а база перестаёт сохранять данные.
Место быстро освобождается удалением старых архивов, но настоящих исправлений два. Первое — копии должны уходить на отдельный сервер: копия на том же диске не спасёт ни от отказа диска, ни от потери сервера целиком. Второе — ротация с ограничением числа копий, чтобы хранилище не росло бесконечно. Простейший вариант — оставлять семь последних архивов:
ls -1t /backup/site-*.tar.gz | tail -n +8 | xargs -r rm --
Как копировать файлы между серверами, описано в статье scp, sftp и rsync.
Как не допустить повторения
- Мониторинг свободного места и inode с уведомлением на 80–85% — заранее, а не по жалобам посетителей.
- Ограничение журнала systemd (
SystemMaxUse) и проверкаlogrotateдля логов сайтов:logrotate -d /etc/logrotate.confпокажет, что будет сделано, ничего не меняя. - Бэкапы — на другой сервер или в отдельное хранилище, с ротацией.
- Лимиты для кэшей и логов Docker.
- Раз в месяц —
du -xh --max-depth=1 / | sort -h, чтобы видеть, что растёт.
Частые вопросы
Удалил большие файлы, а df показывает то же самое. Почему?
Файлы держит открытыми какой-то процесс. Найдите его через lsof +L1 и перезапустите службу или обнулите файл через /proc/<PID>/fd/<номер>. Пока процесс держит файл, место не освободится.
Места полно, но пишет No space left on device. Что это?
Чаще всего закончились inode — проверьте df -i. Если и там свободно, причина может быть не в диске: например, Apache так же сообщает о нехватке семафоров. Ещё вариант — квота пользователя на хостинге.
Можно ли просто удалить все логи в /var/log?
Нет. Старые сжатые логи удалять можно, текущие лучше обнулять через truncate -s 0. Журнал systemd чистится только через journalctl --vacuum-size или --vacuum-time, а не удалением файлов.
Почему в Debian 13 tmp занимает память, а не диск?
Начиная с Debian 13, каталог /tmp по умолчанию находится в tmpfs — в памяти, до 50% её объёма. Временные файлы там не занимают диск, но расходуют оперативную память, и после перезагрузки исчезают.