MHOSTMHOST

Закончилось место на диске

Диск на VPS не предупреждает о нехватке места заранее — обычно вы узнаёте о ней по последствиям: сайт отвечает ошибкой 500, apt/dnf отказывается ставить пакеты, MySQL пишет в лог Disk full, а в выводе команд и системных логах мелькает No space left on device. В этой статье — как быстро найти, что именно занимает место, безопасно освободить его и что делать, если освобождать уже нечего.

Что понадобится

  • Доступ по SSH под root или пользователем с sudo — команды ниже нужно выполнять с правами администратора.
  • VPS MHost на Ubuntu 22.04/24.04, Debian 11/12 или AlmaLinux/Rocky Linux 8/9 — Шаги 1–7 (командная строка) написаны для этих систем; Шаг 8 (увеличение диска в VMmanager 6) одинаков и для Windows-серверов.
  • Доступ в панель VMmanager 6 — понадобится, если после очистки места всё ещё не хватает (Шаг 8).
Совет: все команды ниже даны от имени root. Если вы работаете под обычным пользователем, добавляйте sudo перед каждой командой.

Шаг 1. Найдите, на каком разделе кончилось место

Начните с общей картины: df (disk free) показывает, сколько места занято и свободно на каждом смонтированном разделе.

bash
df -h

Флаг -h (--human-readable) выводит размеры в удобных единицах (K, M, G) вместо байт. Пример вывода:

Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        40G   38G  1.2G  97% /
tmpfs           2.0G     0  2.0G   0% /dev/shm
/dev/vda15      105M  6.1M   99M   6% /boot/efi

Смотрите на колонку Use%. На большинстве VPS всё лежит на одном разделе /, но если под /home, /var или базу данных выделен отдельный раздел, забитым может оказаться именно он — определите точный Mounted on и все дальнейшие шаги выполняйте для него.

Совет: заодно посмотрите тип файловой системы — df -hT добавляет колонку Type (ext4, xfs и т.д.). Она пригодится в Шаге 8: команда для расширения файловой системы после увеличения диска для ext4 и xfs разная.

Диск может «закончиться» и без 100% в Use% — если кончились inode (лимит на количество файлов, а не на их суммарный размер):

bash
df -i

Если там IUse% близок к 100%, а по объёму всё в порядке, — дело не в размере файлов, а в их количестве (типичный пример — миллионы мелких файлов сессий или кеша). Шаги 2–7 ниже помогают и в этом случае: находите такой каталог тем же способом и чистите его.

Готово: вы знаете точный раздел (Mounted on), где кончилось место или inode. Переходите к Шагу 2.

Шаг 2. Определите, что именно занимает место

Дальше — найти конкретных виновников командой du (disk usage), спускаясь по дереву каталогов уровень за уровнем.

bash
du -sh /* 2>/dev/null | sort -rh | head -n 20
  • -s (--summarize) — не расписывать содержимое каждого каталога, а показать только общий итог по нему.
  • -h — размеры в человекочитаемом виде.
  • 2>/dev/null — скрыть ошибки доступа к каталогам, куда нет прав.
  • sort -rh — отсортировать по убыванию размера.
Совет: строки /proc и /sys в выводе можно не учитывать — это виртуальные файловые системы, реального места на диске они не занимают, что бы ни показал du.

Возьмите из вывода самый крупный каталог и повторите команду уже внутри него:

bash
du -sh /var/* 2>/dev/null | sort -rh | head -n 20

Продолжайте спускаться так же глубже, пока не увидите конкретные файлы или каталоги, которые действительно можно почистить. Частые кандидаты на VPS: /var/cache (Шаг 3), /var/log (Шаг 5), /var/lib/docker (Шаг 6), а также каталоги с бэкапами и дампами баз данных, если вы храните их на этом же диске, — см. «Автобэкапы по расписанию (cron)» и «Бэкапы баз данных», там же про перенос копий за пределы сервера.

Совет: если на сервере несколько разделов (например, отдельный /home или /var/lib/docker), команда выше просуммирует их вместе с корневым, не разбирая, где что физически лежит. Чтобы посчитать именно тот раздел, что нашли в Шаге 1, замените звёздочку на флаг -x (--one-file-system) на одном каталоге — например, для /:
bash
du -x --max-depth=1 / 2>/dev/null | sort -rh | head -n 20

-x не даёт du заходить на другие смонтированные файловые системы вообще — в отличие от команды со звёздочкой выше, эта покажет только то, что реально лежит на разделе /, а /proc, /sys и другие разделы (например, отдельный /home) окажутся в выводе пустыми.

Совет: если разбираться по одному каталогу за раз неудобно, поставьте интерактивный ncdu — на Ubuntu/Debian: apt install ncdu; на AlmaLinux/Rocky пакет идёт через репозиторий EPEL (dnf install epel-release, затем dnf install ncdu). Он строит то же дерево du, но с удобной навигацией по каталогам прямо в терминале.
Готово: вы нашли конкретные каталоги или файлы, которые можно почистить. Дальше — по типу находки: кеш пакетов (Шаг 3), логи (Шаги 4–5), Docker (Шаг 6) или что-то ещё (Шаг 7).

Шаг 3. Очистите кеш пакетного менеджера

apt и dnf хранят на диске уже скачанные .deb/.rpm пакеты — после нескольких обновлений это может занять пару гигабайт.

Ubuntu / Debian

Проверьте, сколько занимает кеш:

bash
du -sh /var/cache/apt/archives/

Очистите его:

bash
apt clean

apt clean удаляет всё содержимое /var/cache/apt/archives/ — уже установленные пакеты apt при необходимости просто скачает заново. Дополнительно уберите зависимости, которые остались от удалённых пакетов и больше никому не нужны:

bash
apt autoremove --purge

--purge удаляет ещё и файлы конфигурации не нужных больше пакетов (в /etc), а не только сами пакеты.

AlmaLinux / Rocky Linux

Проверьте кеш:

bash
du -sh /var/cache/dnf/

Очистите его:

bash
dnf clean all

В отличие от dnf clean packages (только скачанные пакеты), dnf clean all чистит ещё и кеш метаданных репозиториев — при следующей команде dnf просто скачает его заново. Уберите неиспользуемые зависимости:

bash
dnf autoremove
Совет: если хотите не думать об этом вручную, добавьте apt clean или dnf clean all в cron-задание раз в неделю — как настраивать задачи по расписанию, разобрано в статье «Автобэкапы по расписанию (cron)» (там на примере бэкапов, но принцип cron тот же самый).
Готово: du -sh на кеш-каталог теперь показывает мегабайты, а не гигабайты.

Шаг 4. Почистите журнал systemd (journald)

journald — служба логирования systemd — хранит журнал в бинарном виде и на некоторых серверах со временем разрастается, особенно если какая-то служба пишет в него слишком много.

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

bash
journalctl --disk-usage

Пример вывода:

Archived and active journals take up 3.2G in the file system.

Обрежьте журнал до нужного размера:

bash
journalctl --vacuum-size=500M

Команда удаляет самые старые архивные (уже ротированные) файлы журнала, пока суммарный размер не окажется меньше 500M, — активный файл, в который пишется прямо сейчас, при этом не трогается, так что это безопасно. Вместо размера можно ограничить журнал по возрасту:

bash
journalctl --vacuum-time=30d

(оставит записи не старше 30 дней)

Важно: --vacuum-size и --vacuum-time дают разовый эффект — журнал снова начнёт расти. Чтобы ограничение стало постоянным, задайте лимит в конфиге:
bash
cat >> /etc/systemd/journald.conf <<'EOF'
[Journal]
SystemMaxUse=500M
EOF
bash
systemctl restart systemd-journald
Совет: если каталога /var/log/journal на сервере нет, журнал хранится только в оперативной памяти (/run/log/journal) и не переживает перезагрузку — тогда он не занимает места на диске вообще, и этот шаг можно пропустить. Проверить: ls -d /var/log/journal 2>/dev/null — пустой вывод означает, что каталога нет.

Включить постоянное хранение журнала (и лимит из примера выше) можно так — команда создаёт каталог и просит systemd-tmpfiles инициализировать его; перезапуск не требуется, journald подхватит каталог сам:

bash
mkdir -p /var/log/journal
systemd-tmpfiles --create --prefix /var/log/journal
Готово: journalctl --disk-usage показывает объём в пределах заданного лимита.

Шаг 5. Найдите и очистите большие логи

Посмотрите, что именно тяжёлое лежит в /var/log:

bash
du -sh /var/log/* 2>/dev/null | sort -rh | head -n 20

На всех поддерживаемых дистрибутивах уже установлен и настроен logrotate — он запускается автоматически раз в сутки (через systemd-таймер logrotate.timer на новых версиях Ubuntu/Debian либо через классическое задание /etc/cron.daily/logrotate на остальных) и сам сжимает и удаляет старые копии логов по правилам из /etc/logrotate.d/. Проверить, каким именно способом он запускается на вашем сервере:

bash
systemctl list-timers | grep logrotate

Не обязательно ждать — заставьте logrotate отработать прямо сейчас:

bash
logrotate -f /etc/logrotate.conf

-f (--force) ротирует все логи немедленно, даже если они ещё не достигли лимита по размеру или возрасту. Если конкретный лог регулярно разрастается и стандартных правил не хватает, добавьте для него отдельный конфиг:

bash
cat > /etc/logrotate.d/myapp <<'EOF'
/var/log/myapp/*.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
}
EOF

Это правило ротирует *.log в /var/log/myapp/ ежедневно, хранит 7 последних копий, сжимает их (compress) и не ругается, если файла или новых записей нет (missingok, notifempty).

Важно: никогда не удаляйте (rm) лог, который прямо сейчас пишет работающий процесс, рассчитывая мгновенно освободить место. В Linux rm лишь убирает имя файла из каталога — если процесс всё ещё держит его открытым, диск остаётся занят до перезапуска этого процесса, и df не покажет освобождённое место, хотя ls файл уже не найдёт.

Найдите такие «файлы-призраки» — открытые, но уже удалённые:

bash
lsof +L1 2>/dev/null | head -n 20

Если lsof не установлен:

bash
# Ubuntu/Debian
apt install lsof

# AlmaLinux/Rocky Linux
dnf install lsof

+L1 показывает открытые файлы со счётчиком ссылок меньше 1 — то есть ровно случай «удалён, но всё ещё открыт». В колонках COMMAND и PID — какой процесс держит файл, в SIZE — сколько места он занимает. Освободить место, не перезапуская сам сервис, можно обнулением файла через файловый дескриптор процесса:

bash
truncate -s 0 /proc/<PID>/fd/<FD>

Подставьте <PID> и <FD> из вывода lsof.

Важно: никогда не делайте так с write-ahead логом или бинлогом СУБД и вообще с любым файлом, который процесс использует для восстановления после сбоя, — это повредит данные. Для обычных логов приложений и веб-сервера, где потерять буферизованное содержимое не страшно, это безопасно. И на будущее: вместо rm лога, который активно пишется, используйте truncate -s 0 /var/log/big.log (или : > /var/log/big.log) — это тот же файл и тот же дескриптор, так что место освобождается мгновенно и без всякого риска.
Готово: du -sh /var/log/* больше не показывает подозрительно крупных файлов.

Шаг 6. Если используете Docker — очистите неиспользуемые данные

Docker хранит образы, остановленные контейнеры, неиспользуемые сети и кеш сборки в /var/lib/docker (подробнее — «Docker и Docker Compose») — на сервере с контейнерами это часто самый крупный потребитель места.

Посмотрите разбивку по типам:

bash
docker system df

Выведет TYPE (Images, Containers, Local Volumes, Build Cache), TOTAL, ACTIVE и SIZE/RECLAIMABLE — сколько места можно освободить без потерь.

Безопасная очистка:

bash
docker system prune

Удаляет остановленные контейнеры, сети без единого подключённого контейнера, «висячие» (untagged) образы и неиспользуемый кеш сборки. Тома (volumes) и образы, у которых остался тег, эта команда не трогает, даже если ими давно никто не пользуется.

Чтобы убрать вообще все неиспользуемые образы (не только untagged) и неиспользуемые тома:

bash
docker system prune -a --volumes
Важно: --volumes удаляет анонимные тома, не подключённые ни к одному контейнеру, — в том числе каталоги с данными базы, если контейнер, который их использовал, уже удалён. Прежде чем запускать с этим флагом, убедитесь, что эти данные не нужны или что есть их копия — см. «Бэкапы баз данных».
Совет: обе команды перед удалением попросят подтверждение (y/N) и покажут список того, что будет удалено. Для использования в скриптах есть флаг -f (--force), который пропускает этот запрос.
Готово: docker system df показывает, что места освободилось.

Шаг 7. Найдите большие файлы отдельно

Иногда место съедает не каталог целиком, а один-два отдельных файла — забытый дамп базы, core dump после падения процесса, ISO-образ, залитый один раз и забытый.

bash
find / -xdev -type f -size +100M -exec ls -lh {} \; 2>/dev/null
  • -xdev — как и -x у du в Шаге 2, не заходить на другие смонтированные разделы (и заодно — в /proc).
  • -type f — только обычные файлы, не каталоги и не устройства.
  • -size +100M — только крупнее 100 МБ (порог можно поменять, например на +1G).
  • -exec ls -lh {} \; — вывести для каждого найденного файла размер и путь в человекочитаемом виде.

Если находок много, отсортируйте по размеру:

bash
find / -xdev -type f -size +100M -printf '%10s  %p\n' 2>/dev/null | sort -rn | head -n 20
Совет: если данные разбросаны по нескольким разделам (например, отдельный диск под /home или /data), уберите -xdev — команда пройдёт по всем смонтированным файловым системам сразу, хотя и медленнее и с лишним шумом от /proc.
Готово: крупные файлы найдены — удалите ненужные или перенесите их за пределы сервера (см. «Резервное копирование с rsync» и «Инкрементальные бэкапы с restic»).

Шаг 8. Если места всё ещё не хватает — увеличьте диск

Если после всех предыдущих шагов свободного места по-прежнему мало, единственный оставшийся вариант — увеличить сам диск. В зависимости от тарифа это либо апгрейд тарифа целиком, либо отдельное увеличение диска без изменения остальных характеристик сервера — точный вариант уточните в личном кабинете my.mhost.ee или в поддержке MHost.

Само увеличение выполняется в панели VMmanager 6 (как войти — статья «Как войти в VMmanager 6»):

  1. Откройте раздел «Виртуальные машины» и выберите нужный сервер.
  2. Нажмите кнопку «Параметры».
  3. Перейдите в раздел «Тонкие настройки» → вкладку «Настройка дисков VM».
  4. В поле Storage укажите новый, больший объём диска в гигабайтах — уменьшить диск из панели нельзя, только увеличить.

📷 скриншот: вкладка «Настройка дисков VM» в тонких настройках VMmanager 6

Дальше два варианта:

  • Чекбокс «Увеличивать размер дисков без перезагрузки VM» включён — диск увеличится «на лету», без остановки сервера. Работает только для файловых систем ext4, xfs и ntfs и только если диск подключён через контроллер VirtIO.
  • Чекбокс выключен — увеличение пройдёт с перезагрузкой сервера, и дополнительно нужно указать раздел (Partition) для увеличения — VMmanager расширит его сам в процессе перезагрузки. Этот способ не зависит от типа контроллера диска — используйте его, если чекбокс выше недоступен или не сработал.

После увеличения диска без перезагрузки операционная система пока не видит нового места — оно есть на самом диске, но не в разделе и не в файловой системе. Определите имя устройства и раздела (обычно уже видно в выводе df -h из Шага 1 — в примере оттуда корень находится на /dev/vda1, то есть раздел 1 диска /dev/vda; при сомнениях уточните командой lsblk), затем расширьте раздел и файловую систему изнутри ОС:

bash
lsblk
bash
growpart /dev/vda 1

Для ext4:

bash
resize2fs /dev/vda1

Для xfs команда принимает точку монтирования, а не устройство:

bash
xfs_growfs /

Если команды growpart нет в системе:

bash
# Ubuntu/Debian
apt install cloud-guest-utils

# AlmaLinux/Rocky Linux
dnf install cloud-utils-growpart

Если увеличивали диск с перезагрузкой сервера (чекбокс был выключен) — после перезагрузки проверьте df -h: если новый объём уже виден, дополнительно ничего делать не нужно; если нет, расширьте файловую систему теми же командами resize2fs/xfs_growfs, что и выше.

Windows: откройте «Управление дисками» (Disk Management), кликните правой кнопкой по разделу, у которого появилось нераспределённое место, и выберите «Расширить том» (Extend Volume).

Готово: df -h (в Windows — свойства диска) показывает новый, увеличенный объём в колонке Avail.

Профилактика: настройте мониторинг диска

Чистить диск вручную после того, как сайт уже упал, — плохая стратегия. Правильный вариант — узнавать о нехватке места заранее, по оповещению, а не по факту простоя.

Разверните Zabbix и подключите к нему сервер — в статье «Мониторинг с Zabbix» разобрана установка сервера и агента на VPS MHost. Стандартный шаблон «Linux by Zabbix agent» сам находит все смонтированные файловые системы и уже содержит триггеры на нехватку места — по умолчанию предупреждение при заполнении диска на 80% и критическое оповещение на 90% (макросы {$VFS.FS.PUSED.MAX.WARN} и {$VFS.FS.PUSED.MAX.CRIT}). Пороги можно поменять под конкретный раздел — например, поднять для раздела с логами, где 90% заполнения — обычный рабочий режим.

Совет: сам по себе мониторинг без оповещений вы будете проверять только тогда, когда сайт уже не открывается, — то есть постфактум. Настройте в Zabbix хотя бы e-mail или Telegram-оповещение для этих триггеров.

Что дальше

Если диск заполняется быстро и регулярно, а не разово, вероятная причина — в самом приложении: разрастающиеся логи, кеш, который никто не чистит, либо бэкапы, которые копятся на этом же диске, а не переносятся за пределы сервера — см. «Автобэкапы по расписанию (cron)», «Резервное копирование с rsync» и «Инкрементальные бэкапы с restic». Если после нехватки места сайт так и не поднялся сам — статьи «Сайт не открывается» и «Служба не запускается» помогут разобраться дальше. А если, наоборот, места и ресурсов достаточно, но сервер еле шевелится, — это уже тема статьи «Высокая нагрузка на сервер».