Сообщение No space left on device — один из самых коварных ночных кошмаров вебмастера и системного администратора. Когда на виртуальном сервере (VDS) свободное дисковое пространство заполняется до 100%, последствия наступают мгновенно:
- СУБД (MySQL / PostgreSQL) аварийно останавливается или блокирует таблицы на запись с ошибкой Can't create/write to file.
- Веб-сервер Nginx перестает отдавать динамические страницы и возвращает ошибку
500 Internal Server Errorили502 Bad Gateway. - SSH-сессия перестает сохранять историю команд, а автодополнение (Tab completion) выдает ошибки создания временных файлов в
/tmp. - Почтовые службы (Postfix/Exim) блокируют доставку входящих и исходящих писем.
В этой статье мы подробно разберем пошаговый алгоритм реанимации сервера: от экстренного поиска истинных причин нехватки места до глубокой очистки скрытого мусора (логов, Docker, старых ядер, MySQL binlog) и настройки автоматической профилактики по расписанию.
sudo journalctl --vacuum-size=50M. Это сразу вернет сервер к жизни и позволит спокойно продолжить диагностику.
1. Экстренная диагностика: df -h, переполнение Inodes и открытые удаленные файлы (lsof)
Первый шаг при падении сервера — понять, чем именно вызвано переполнение: физическими мегабайтами, исчерпанием файловых дескрипторов (Inodes) или зависшими процессами.
1.1. Проверка физического объема диска (df -h)
# Проверяем занятое пространство на всех смонтированных разделах
df -h
Обратите внимание на корневой раздел / (или /dev/vda1, /dev/sda1). Если в столбце Use% указано 100% — диск физически переполнен большими файлами.
1.2. Проверка файловых дескрипторов Inodes (df -i)
Типичная загадочная ситуация: команда df -h показывает 10–15 ГБ свободного места, но при попытке создать любой файл система выдает No space left on device. Причина — 100% исчерпание Inodes (индексных дескрипторов файлов).
# Проверяем количество свободных Inodes
df -i
В Linux каждый файл, каталог или сокет занимает один Inode. Если на сервере скопились миллионы крошечных файлов (старые сессии PHP, кэш мелких картинок, спам-очередь почты в /var/spool/postfix), таблица дескрипторов переполняется, даже если сам диск свободен на 90%.
1.3. Поиск удаленных, но удерживаемых процессов файлов (lsof + deleted)
Очень частая ошибка новичков: вы удалили огромный лог-файл командой rm -f /var/log/nginx/access.log, но df -h по-прежнему показывает 100% занятости. Почему так происходит?
В операционных системах Linux файл физически удаляется с диска только тогда, когда закрыты все его файловые дескрипторы. Если веб-сервер Nginx продолжает держать файл открытым, место на диске не освобождается до перезагрузки процесса.
# Находим процессы, удерживающие удаленные файлы
sudo lsof -nP | grep '(deleted)'
# Пример вывода:
# nginx 1420 www-data 3w REG 253,1 8589934592 /var/log/nginx/access.log (deleted)
Чтобы мгновенно освободить место без перезагрузки всей ОС, достаточно перезапустить сервис, удерживающий файл:
# Мягкий перезапуск службы
sudo systemctl reload nginx
# или для PHP-FPM:
sudo systemctl reload php8.3-fpm
2. Визуальный поиск тяжелых папок через ncdu и du
Чтобы не гадать вслепую, воспользуемся лучшей интерактивной консольной утилитой анализа диска — ncdu (NCurses Disk Usage).
# Устанавливаем ncdu в Ubuntu / Debian
sudo apt update && sudo apt install -y ncdu
# Запускаем сканирование корневой директории
# Флаг -x запрещает утилите сканировать сетевые диски и виртуальные каталоги (/proc, /sys)
sudo ncdu / -x
↑ и ↓ для перемещения по папкам, Enter для входа в директорию, n для сортировки по имени или размеру, и клавишу q для выхода. Клавиша d удаляет выбранный файл (используйте с предельной осторожностью!).
Если по какой-то причине установить ncdu невозможно, используйте встроенную команду du для поиска топ-10 самых тяжелых директорий:
# Поиск 10 самых объемных папок в корне
sudo du -ahx / | sort -rh | head -n 10
# Поиск 10 самых объемных папок внутри /var
sudo du -hx --max-depth=2 /var | sort -rh | head -n 10
3. Очистка и ограничение системных журналов systemd-journald
В современных дистрибутивах (Ubuntu 22.04 / 24.04 LTS, Debian 11 / 12) служба systemd-journald логирует все системные события в двоичном формате. По умолчанию в базовых настройках journald может съедать до 10% от общего объема диска (от 2 до 10 ГБ), что катастрофично для недорогих VDS.
# 1. Проверяем, сколько места сейчас занимают журналы journald
journalctl --disk-usage
# Пример вывода: Archived and active journals take up 4.8G in the file system.
# 2. Экстренно удаляем логи старше 3 дней
sudo journalctl --vacuum-time=3d
# 3. Или ограничиваем максимальный размер журналов 100 мегабайтами
sudo journalctl --vacuum-size=100M
Как ограничить размер journald навсегда:
Отредактируйте конфигурационный файл /etc/systemd/journald.conf:
[Journal]
# Задаем жесткий лимит на максимальный объем логов
SystemMaxUse=100M
SystemMaxFileSize=20M
MaxRetentionSec=1month
Примените настройки перезапуском службы:
sudo systemctl restart systemd-journald
4. Тотальная чистка Docker: контейнеры, образы, билдер-кэш и волюмы
Docker — абсолютный рекордсмен по незаметному пожиранию дискового пространства. Сборка образов, промежуточные слои (BuildKit Cache), остановленные контейнеры и JSON-логи накапливают гигабайты мусора за считанные недели.
# Смотрим детализированную статистику занятого пространства в Docker
docker system df
Вы увидите разбивку по категориям: Images (образы), Containers (контейнеры), Local Volumes (тома) и Build Cache (кэш сборщика).
4.1. Безопасная очистка неиспользуемых ресурсов
# Удаляем все остановленные контейнеры, висячие образы (dangling) и кэш сборки
docker system prune -f
# Глубокая очистка: удаление ВСЕХ неиспользуемых образов (а не только без тега)
docker system prune -a --volumes -f
--volumes удалит безымянные тома, не привязанные к активным контейнерам. Если вы храните базы данных в именованных томах, они останутся нетронутыми, но анонимные тома будут стерты.
4.2. Ограничение бесконечных логов Docker-контейнеров
По умолчанию Docker сохраняет стандартный вывод (stdout/stderr) контейнеров в формате JSON без ротации. Чтобы логи не раздувались до сотен гигабайт, создайте или дополните файл /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "3"
}
}
Перезапустите демон Docker для применения глобального правила:
sudo systemctl restart docker
5. Очистка кэша APT и удаление старых неиспользуемых ядер Linux
Каждый раз при выполнении apt install или apt upgrade пакетный менеджер загружает .deb архивы в директорию /var/cache/apt/archives/. Они остаются на диске навсегда, если их не чистить вручную.
# 1. Проверяем размер кэша пакетов APT
du -sh /var/cache/apt/archives
# 2. Полностью очищаем кэш загруженных пакетов
sudo apt clean
# 3. Удаляем старые пакеты, которые больше не требуются установленным программам
sudo apt autoclean
# 4. Удаляем старые ядра Linux и неиспользуемые зависимости
sudo apt autoremove --purge -y
5.1. Очистка кэша пакетов Snap (для Ubuntu)
Пакетный менеджер Snap по умолчанию сохраняет по 2–3 старые версии каждого приложения. Если у вас используется Snap, отключите хранение старых ревизий и удалите дубликаты:
# Задаем лимит сохранения только 2 последних версий пакетов
sudo snap set system refresh.retain=2
# Однострочник для удаления отключенных (disabled) ревизий snap
sudo snap list --all | awk '/disabled/{print $1, $3}' | while read snapname revision; do sudo snap remove "$snapname" --revision="$revision"; done
6. Очистка логов Nginx, сессий PHP и бинарных логов MySQL/MariaDB
Для веб-серверов и CMS (WordPress, Bitrix, OpenCart) основными источниками скрытого разрастания файлов выступают:
6.1. Логи Nginx / Apache и правильное усечение
Никогда не удаляйте активные файлы логов через rm. Используйте команду truncate, которая обнуляет размер файла, не разрывая файловый дескриптор:
# Безопасное обнуление файла лога до 0 байт
sudo truncate -s 0 /var/log/nginx/access.log
sudo truncate -s 0 /var/log/nginx/error.log
# Удаление старых сжатых архивов логов (.gz)
sudo find /var/log -type f -name "*.gz" -delete
sudo find /var/log -type f -name "*.1" -delete
Для автоматической ежедневной ротации используйте нашу готовую конфигурацию Logrotate для Nginx и PHP-FPM.
6.2. Очистка миллионов мелких сессий PHP (борьба за Inodes)
В некоторых конфигурациях PHP сборщик мусора (Garbage Collector) не успевает удалять старые сессии из /var/lib/php/sessions, из-за чего исчерпываются Inodes:
# Удаляем файлы сессий старше 7 дней
sudo find /var/lib/php/sessions -type f -cmin +10080 -delete
6.3. Удаление бинарных логов MySQL / MariaDB (binlog)
Бинарные логи репликации MySQL (binlog.000001, mysql-bin.*) в каталоге /var/lib/mysql могут занимать десятки гигабайт. Категорически запрещено удалять их через rm (это сломает индекс СУБД!).
Очистка выполняется строго через SQL-консоль:
-- Подключаемся к MySQL: mysql -u root -p
-- Удаляем все бинарные логи старше 3 дней:
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY;
Чтобы логи автоматически удалялись в будущем, добавьте в секцию [mysqld] файла /etc/mysql/my.cnf параметр автоматического срока жизни логов (подробнее в нашем руководстве по тюнингу MySQL my.cnf):
# Хранить бинарные логи максимум 3 дня (259200 секунд)
binlog_expire_logs_seconds = 259200
max_binlog_size = 100M
7. Рекомендуемые VDS-провайдеры с гибким расширением NVMe
Если проект перерос объем диска даже после полной оптимизации, оптимальное решение — выбор надежного провайдера с быстрыми накопителями NVMe и возможностью добавления дискового пространства в 1 клик:
Рекомендуемые VDS-провайдеры
Отказоустойчивые сервера с быстрыми NVMe и каналом до 1 Гбит/с
Selectel VPS / VDS
Сверхбыстрые серверы KVM на NVMe с бесплатными 3 ТБ трафика. Легкое масштабирование диска и подключение облачных хранилищ S3 в панели управления.
Timeweb Cloud
Мощные процессоры до 5.0 GHz, расширение дискового пространства без переустановки ОС, автоматические резервные копии и поминутная тарификация.
Beget VPS
Удобная фирменная панель управления сервером, установка Docker и любого веб-стека в 1 клик, русскоязычная техническая поддержка 24/7.
8. Автоматизация: готовый bash-скрипт регулярной самоочистки по Cron
Чтобы не доводить сервер до аварийных ситуаций, настроим регулярную еженедельную профилактику. Создадим системный скрипт автоматической очистки.
Создайте исполняемый файл /usr/local/bin/syskit-disk-cleanup.sh:
#!/usr/bin/env bash
# ====================================================================
# SysKit.ru - Автоматический скрипт еженедельной очистки диска Linux
# ====================================================================
set -e
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Запуск регламентной очистки диска..."
# 1. Очистка кэша пакетов APT
apt-get -y clean > /dev/null 2>&1 || true
apt-get -y autoclean > /dev/null 2>&1 || true
apt-get -y autoremove --purge > /dev/null 2>&1 || true
# 2. Ограничение и ротация journald (оставляем последние 7 дней / до 100MB)
journalctl --vacuum-time=7d > /dev/null 2>&1 || true
journalctl --vacuum-size=100M > /dev/null 2>&1 || true
# 3. Удаление старых ротированных логов старше 14 дней в /var/log
find /var/log -type f -name "*.gz" -mtime +14 -delete > /dev/null 2>&1 || true
find /var/log -type f -name "*.1" -mtime +14 -delete > /dev/null 2>&1 || true
# 4. Очистка устаревших сессий PHP (старше 7 дней)
if [ -d "/var/lib/php/sessions" ]; then
find /var/lib/php/sessions -type f -mtime +7 -delete > /dev/null 2>&1 || true
fi
# 5. Очистка Docker (если установлен и запущен)
if command -v docker >/dev/null 2>&1 && systemctl is-active --quiet docker; then
docker system prune -f > /dev/null 2>&1 || true
fi
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Очистка успешно завершена. Свободно на диске: $(df -h / | awk 'NR==2 {print $4}')"
Установите права на выполнение:
sudo chmod +x /usr/local/bin/syskit-disk-cleanup.sh
Добавьте задание в системный планировщик Cron для запуска каждое воскресенье в 04:00 утра. Для быстрого составления расписания используйте наш Генератор Cron задач.
# Открываем crontab суперпользователя root
sudo crontab -e
# Добавляем строку запуска:
0 4 * * 0 /usr/local/bin/syskit-disk-cleanup.sh >> /var/log/syskit-cleanup.log 2>&1
9. Чек-лист безопасности: что категорически нельзя удалять
✅ Что можно безопасно чистить:
- Кэш загруженных deb-пакетов (
apt clean). - Системные логи journald через
journalctl --vacuum-*. - Удаленные сжатые архивы логов
*.gzстарше 14 дней. - Неиспользуемые контейнеры и build-кэш Docker (
docker system prune). - Старые удаленные сессии PHP в
/var/lib/php/sessions. - Старые ядра Linux через
apt autoremove --purge.
⚠️ Что категорически НЕЛЬЗЯ делать:
- Удалять папку /var/log целиком: Многие сервисы не умеют самостоятельно создавать эту директорию и упадут при старте.
- Удалять файлы СУБД (ibdata1, ib_logfile*): Прямое удаление файлов из
/var/lib/mysqlбезвозвратно уничтожит базу данных InnoDB. - Удалять /tmp через rm -rf /tmp: Временная папка содержит сокеты процессов (например,
mysql.sock). - Удалять активные логи через rm: Используйте только
truncate -s 0 file.log, иначе память не освободится.
10. Резюме и выводы
Переполнение диска — штатная ситуация в жизни любого сервера, с которой регулярно сталкиваются как новички, так и опытные инженеры. Своевременный контроль через ncdu, ограничение аппетитов systemd-journald, ротация логов Nginx и регулярный docker prune позволяют комфортно работать даже на компактных тарифах с 10–20 ГБ диска.
Для генерации надежных паролей баз данных воспользуйтесь нашим Генератором паролей, а проверить доступность сетевых сервисов после перезагрузки можно через Сканер портов SysKit.
Нужен надежный сервер с быстрыми NVMe и запасом места?
Арендуйте производительный VDS с чистой KVM-виртуализацией и каналом 1 Гбит/с на Selectel всего от 200 ₽ в месяц.
Выбрать тариф VDS на Selectel →