VPSSPark Блог
← Вернуться к дневнику

Диск сервера заполнен? Скрипт одним кликом для очистки типичных кэшей

Заметки о серверах · 2026.07.23 · ~11 мин чтения

Частый поиск: диск сервера заполнен · очистка диска Linux · место на VPS · скрипт кэша (Docker · journal · apt)

Обслуживание серверной стойки—место на диске Linux VPS и очистка
Алерты диска обычно — накопившиеся логи, слои контейнеров и кэш пакетов: сначала диагностика, потом скрипт вместо панического rm.

Три часа ночи, мониторинг будит дежурного: раздел / занят на 98 %, MySQL не пишет binlog, CI падает на docker pull с no space left on device. Подключаемся, запускаем df -h — на корне осталось 412 МБ. Это не взлом, а три месяца без контроля над логами, слоями Docker, кэшем apt и journal systemd, которые постепенно съели 40-гигабайтный VPS.

Такой сценарий типичен для небольших VPS: скромный диск, контейнеры круглосуточно, постоянные pull образов и непрерывное логирование. Ручной rm -rf медленный и опасный; рабочая схема — сначала найти «тяжёлых», затем пакетно очистить каталоги, которые можно восстановить. В этой статье — скрипт очистки, который мы регулярно запускаем в продакшене, с чёткими пометками: что можно автоматизировать, а что требует ручной проверки.

Предпосылки: SSH и sudo. Если подключиться невозможно (например, ключ SSH не записывается), начните с нашего гайда по устранению отказа SSH на Linux-сервере, чтобы отличить переполнение диска от сети или файрвола. Прежде чем менять правила UFW, освободите место — сервисам нужна возможность писать логи.

5 мин
Поиск + безопасная очистка
8+
Типичные каталоги кэша
1 скрипт
Готовый к копированию

Диск полон: что ломается первым?

Когда корневая ФС заполнена, симптомы кажутся случайными: SSH ещё работает, но vim не сохраняет, apt install падает, Docker не поднимает контейнеры, Nginx отдаёт 500, а error.log перестаёт расти. MySQL и PostgreSQL уходят в read-only или падают; systemd перезапускает сервисы в цикле — не создать pid-файл или socket. Cron молча проваливается, когда не может дописать лог.

Первый шаг — смотреть точки монтирования, а не угадывать «большую папку». Отдельный том /data может быть полупустым, пока корень забит; без df -hT легко уйти не туда:

Быстрая диагностика
# Свободное место по разделам
                df -hT

                # Крупнейшие каталоги первого уровня под / (может быть медленно)
                sudo du -xh --max-depth=1 / 2>/dev/null | sort -hr | head -20

                # Исчерпание inode тоже выглядит как «полный диск»
                df -ih

du на хостах с миллионами файлов может идти долго. Если машина уже тормозит, проверяйте подозрительные пути точечно: sudo du -sh /var/lib/docker /var/log /var/cache. В руководстве du(1) описаны -x (не переходить на другие ФС) и --apparent-size — не дайте bind mount или отдельным томам ввести вас в заблуждение.

Очистка диска сервера в четыре шага: диагностика df, поиск тяжёлых каталогов du, скрипт для удаления восстановимого кэша, проверка df и настройка logrotate
Рекомендуемый порядок: диагностика, затем очистка; сразу после — снова df и настройка logrotate / cron, чтобы не вернуться сюда через три месяца.

Частые «пожиратели» диска: справочная таблица

У каждого стека свой набор, но пути ниже постоянно всплывают на VPS Ubuntu и Debian. Web + Docker + CI на одном диске 40 ГБ — знакомая формула: journal и слои контейнеров растут в фоне, а прикладные логи взлетают при пиках трафика. В таблице отмечено, можно ли безопасно очистить скриптом — строки «осторожно» требуют проверки зависимостей перед удалением.

Путь / источник Типичный объём Авто-безопасно? Примечания
/var/lib/docker От нескольких ГБ до десятков ГБ Частично Висячие образы, остановленные контейнеры, неиспользуемые volumes; не трогать data volumes работающих контейнеров
/var/log/journal 1–10+ ГБ Да journal systemd быстро раздувается без лимита размера
/var/log/*.log Сотни МБ — ГБ Осторожно Truncate или logrotate; прямое rm может оставить открытые fd и «висячие» inode
/var/cache/apt Сотни МБ — несколько ГБ Да apt-get clean безопасен — удаляет только скачанные .deb
/tmp, /var/tmp Разный Частично Удалять файлы без доступа 7+ дней; следите за временными загрузками приложений
Nginx proxy_cache Несколько ГБ Да Кэш пересобирается; если вы настраивали cache по нашему гайду по оптимизации reverse proxy Nginx, ожидайте кратковременных MISS
Старые ядра в /boot Сотни МБ Да apt autoremove --purge удаляет старые kernel; оставьте текущий и предыдущий
Core dump, отчёты о сбоях Разный Да /var/crash, файлы core.* приложений
Сначала исключите «настоящие данные»
Если /home, /var/lib/mysql, монтирования object storage или каталоги бэкапов занимают больше всего — очистка кэша не спасёт. Нужна архивация, увеличение диска или перенос холодных данных. Скрипты возвращают восстановимое место; они не заменяют планирование ёмкости.

Скрипт очистки в один клик (готов к копированию)

Скрипт ниже по умолчанию в режиме dry-run: показывает, сколько места освободится, и какие команды выполнятся. Передайте --apply для реального удаления. Сначала dry-run, потом ручная проверка — мы уже видели, как команда пропускала этот шаг, prune недельный base-образ (единственная локальная копия выведенного сервиса) и час восстанавливала pipeline. Модули разделены: закомментируйте ненужное (Docker, если не установлен, или кэш Nginx без proxy_cache).

disk-cleanup.sh — сохранить как /usr/local/sbin/disk-cleanup.sh
#!/usr/bin/env bash
                # Очистка диска сервера в один клик — только восстановимый кэш
                # Использование: sudo ./disk-cleanup.sh          # предпросмотр
                #                sudo ./disk-cleanup.sh --apply  # выполнение
                set -euo pipefail

                APPLY=false
                [[ "${1:-}" == "--apply" ]] && APPLY=true

                log() { echo "[$(date '+%F %T')] $*"; }
                run() {
                  if $APPLY; then
                    log "EXEC: $*"
                    eval "$@"
                  else
                    log "DRY-RUN: $*"
                  fi
                }

                before=$(df -h / | awk 'NR==2 {print $3 " used, avail " $4}')
                log "Before: $before"

                # 1. кэш apt
                if command -v apt-get >/dev/null; then
                  run "apt-get clean -y"
                  run "apt-get autoremove -y --purge"
                fi

                # 2. journal systemd — оставить 7 дней или 500 МБ
                if command -v journalctl >/dev/null; then
                  run "journalctl --vacuum-time=7d"
                  run "journalctl --vacuum-size=500M"
                fi

                # 3. неиспользуемые ресурсы Docker (без бизнес-данных в named volumes)
                if command -v docker >/dev/null && docker info >/dev/null 2>&1; then
                  run "docker system prune -af --filter 'until=168h'"
                  run "docker builder prune -af --filter 'until=168h'"
                fi

                # 4. временные каталоги — без доступа 7+ дней
                run "find /tmp /var/tmp -type f -atime +7 -print 2>/dev/null | head -20"
                if $APPLY; then
                  find /tmp /var/tmp -type f -atime +7 -delete 2>/dev/null || true
                fi

                # 5. Nginx proxy_cache (подставьте свой cache_path)
                NGINX_CACHE="/var/cache/nginx"
                if [[ -d "$NGINX_CACHE" ]]; then
                  run "du -sh '$NGINX_CACHE'"
                  run "find '$NGINX_CACHE' -type f -delete 2>/dev/null || true"
                fi

                # 6. дампы сбоев
                [[ -d /var/crash ]] && run "rm -rf /var/crash/*"

                # 7. кэш pip / npm (если есть)
                [[ -d /root/.cache/pip ]] && run "rm -rf /root/.cache/pip/*"
                for u in /home/*; do
                  [[ -d "$u/.npm" ]] && run "npm cache clean --force --cache '$u/.npm' 2>/dev/null || rm -rf '$u/.npm/_cacache'"
                done

                after=$(df -h / | awk 'NR==2 {print $3 " used, avail " $4}')
                log "After:  $after"
                $APPLY || log "Dry-run завершён. Когда готовы: sudo $0 --apply"

Права: sudo chmod 750 /usr/local/sbin/disk-cleanup.sh. При первом запуске без --apply сохраните вывод DRY-RUN. Если секция Docker показывает массовое удаление образов, убедитесь, что не удаляете единственную локальную копию, чей тег в registry уже снят.

Docker prune — не панацея
docker system prune -a удаляет все неиспользуемые образы, заставляя полный re-pull при следующем деплое — больно на VPS с узким каналом. Безопаснее: --filter until=168h, чтобы уходили только недельные неиспользуемые слои, или регулярный docker image prune -f для dangling-образов. См. официальную документацию Docker по pruning.

По модулям: что удаляется, что нет

journalctl: --vacuum-time и --vacuum-size можно комбинировать; systemd обрезает бинарные журналы по документации journalctl. Для постоянного потолка задайте SystemMaxUse=500M в /etc/systemd/journald.conf, затем systemctl restart systemd-journald.

Файлы логов: для большого лога, который процесс ещё держит открытым, truncate -s 0 /var/log/nginx/access.log безопаснее, чем rm — процесс сохраняет fd, а удаление файла не освобождает место, пока процесс не перезапустится. Долгосрочно настройте logrotate, чтобы Nginx и приложения ротировали логи ежедневно с хранением N копий.

apt: apt-get clean очищает только /var/cache/apt/archives; autoremove --purge удаляет старые ядра и сиротские зависимости. После обновления kernel оставьте текущий и предыдущий — на случай, если новый не загрузится. На проде мы сверяем uname -r с dpkg -l 'linux-image-*' перед autoremove.

Бизнес-данные не трогать: /var/lib/mysql, /var/lib/postgresql, RDB Redis, каталоги загрузок пользователей и точки монтирования бэкапов — вне скрипта. Если du показывает их первыми, нужна архивация, расширение диска или холодное хранилище — не очистка кэша.

После очистки: не дать диску снова тихо заполниться

Снизить корень с 98 % до 60 % — только начало. Без ограничителей те же каталоги вернутся: journal снова вырастет до 8 ГБ за шесть недель, слои Docker накопятся после каждого деплоя, пик трафика повторит инцидент. Минимальный превентивный набор для маленького VPS — три пункта:

  • Пороги алертов: облачная консоль или self-hosted Prometheus на 80 %, SMS или pager на 85 % — не ждите 95 %.
  • Еженедельный cron: 0 4 * * 0 root /usr/local/sbin/disk-cleanup.sh --apply >> /var/log/disk-cleanup.log 2>&1
  • Потолки journald + logrotate: превратить безграничный рост в управляемый потолок.

На Docker Compose задайте max-size и max-file для logging driver json-file — иначе stdout одного контейнера заполнит диск так же надёжно, как осиротевшие слои образов, и эту ловушку слишком часто игнорируют.

Мышление о ёмкости на маленьком диске
Тариф 40 ГБ с Web + DB + Docker — тесно. Статику — в object storage или CDN, binlog БД — в архив по расписанию, CI-сборки — на отдельный runner. Дешевле, чем ежемесячная тревога в 3 часа ночи. Диск дешёв; время инженера — нет.

Чеклист перед вмешательством

Скопируйте в runbook и пройдите по порядку при следующем алерте:

  • df -hT и df -ih — место или inode?
  • du -sh точечно: docker, journal, logs, cache
  • Dry-run скрипта → ручная проверка → --apply
  • После очистки df -h, затем проверка сервисов (DB, Nginx, Docker)
  • Добавить лимиты journald, logrotate, cron и алерты на 80 %

Полный диск — не «удалить пару файлов», а проверка ёмкости и политики логирования. Скрипт переводит вас от панического rm в 3 часа ночи к повторяемой процедуре. Зафиксируйте, что очистили и насколько сдвинулся df — однострочный постмортем часто выявляет пропущенный stanza logrotate. Остальное — профилактика, чтобы pager молчал, а следующий дежурный получил playbook, а не загадку.

Сборки съедают диск? Разделите роли

Если VPS одновременно крутит прод и локальные xcodebuild, многослойные Docker-сборки или кэш моделей Ollama, маленький диск исчезает за неделю компиляции — DerivedData и слои образов конкурируют с прод-логами на одном SSD.

Здоровее: прод-VPS держать лёгким, тяжёлые сборки — отдельно: облачный Mac для iOS-пакетов, выделенный CI runner, прод тянет только финальные артефакты.

Mac mini M4 с unified memory и низким idle-потреблением хорошо подходит как узел «только сборка, без 24/7 трафика». В паре с Linux VPS для runtime кэши компиляции перестают бороться с прод-логами за один диск. Если планируете такое разделение, сначала перенесите тяжёлое на облачный Macтарифы VPSSpark и меньше ночей с df -h в три часа.

Ограниченное предложение

Сборки съедают диск? Разделите прод и компиляцию

Облачный Mac для сборок · лёгкий Linux VPS для runtime · меньше тревог в 3 ночи

На главную
Ограниченное предложение Смотреть тарифы