وقتی دیسک سرور لینوکس پر می‌شود، اول با df -h ببینید کدام پارتیشن به ۱۰۰٪ رسیده، بعد با sudo du -xh --max-depth=1 / | sort -h پله‌پله پایین بروید تا پوشه‌ی بزرگ را پیدا کنید. در بیشتر سرورها مقصر یکی از این‌هاست: لاگ‌هایی که چرخانده نمی‌شوند، ژورنال systemd، کش apt و کرنل‌های قدیمی، ایمیج‌ها و لاگ‌های داکر، یا فایلی که پاک شده ولی هنوز یک پروسس آن را باز نگه داشته است.

برای آزاد کردن سریع و کم‌خطر جا، این سه دستور معمولاً اولین قدم‌اند: sudo journalctl --vacuum-size=200M، sudo apt clean و بررسی sudo lsof +L1. در ادامه هر مرحله را با جزئیات می‌بینیم، سراغ حالت عجیب «دیسک جا دارد ولی فایل ساخته نمی‌شود» (تمام شدن inode) می‌رویم و در آخر یاد می‌گیریم چطور پیش از پر شدن دیسک خبردار شویم. مثال‌ها برای Ubuntu 24.04 است.

چرا پر شدن دیسک این‌قدر خطرناک است؟

دیسک پر فقط یعنی «فایل جدید ذخیره نمی‌شود»، ولی پیامدش زنجیره‌ای است: پایگاه‌داده نمی‌تواند تراکنش بنویسد و گاهی از کار می‌افتد، نشست‌های PHP ساخته نمی‌شوند و کاربران از سایت بیرون می‌افتند، صف‌ها و کش خطا می‌دهند و حتی ورود با SSH ممکن است کند یا ناموفق شود. پس اول جای کمی آزاد کنید تا سرویس‌ها نفس بکشند، بعد با آرامش ریشه را پیدا کنید.

قدم ۱: کدام پارتیشن پر است؟

bash
df -h

ستون Use% را نگاه کنید. معمولاً / (پارتیشن ریشه) مقصر است، ولی اگر /var یا /home پارتیشن جدا دارند، ممکن است یکی از آن‌ها پر شده باشد.

یک نکته‌ی کوچک: در فایل‌سیستم ext4 به‌طور پیش‌فرض حدود ۵٪ فضا برای root رزرو می‌شود. برای همین گاهی Used و Avail جمعشان با Size جور درنمی‌آید و کاربر عادی زودتر از root به دیوار می‌خورد.

قدم ۲: پیدا کردن مقصر با du و ncdu

bash
sudo du -xh --max-depth=1 / 2>/dev/null | sort -h

گزینه‌ی -x مهم است: باعث می‌شود du وارد پارتیشن‌های دیگر و فایل‌سیستم‌های مجازی مثل /proc نشود. خروجی را از پایین بخوانید؛ بزرگ‌ترین پوشه آخر است. بعد همین دستور را روی همان پوشه تکرار کنید:

bash
sudo du -xh --max-depth=1 /var 2>/dev/null | sort -h
sudo du -xh --max-depth=1 /var/log 2>/dev/null | sort -h

اگر حوصله‌ی تکرار ندارید، ncdu همین کار را تعاملی انجام می‌دهد: با کلیدهای جهت بین پوشه‌ها می‌روید و اندازه‌ها مرتب‌شده نمایش داده می‌شوند.

bash
sudo apt install ncdu
sudo ncdu -x /

برای پیدا کردن تک‌فایل‌های بزرگ هم find کمک می‌کند:

bash
sudo find / -xdev -type f -size +500M -exec ls -lh {} + 2>/dev/null

دستورهای پایه‌ی df و du را در دستورهای ضروری لینوکس برای مدیریت سرور هم آورده‌ایم؛ این‌جا تمرکز روی حالت بحران است.

قدم ۳: وقتی du و df با هم نمی‌خوانند (فایل پاک‌شده‌ی باز)

گاهی df می‌گوید دیسک پر است ولی جمع du خیلی کمتر است. علت تقریباً همیشه این است: کسی یک لاگ بزرگ را با rm پاک کرده، ولی پروسسی که در آن می‌نوشت هنوز آن را باز نگه داشته. اسم فایل رفته، ولی فضا تا وقتی پروسس فایل را ببندد آزاد نمی‌شود.

bash
sudo lsof +L1

این دستور فایل‌های بازی را نشان می‌دهد که دیگر هیچ اسمی روی دیسک ندارند. ستون COMMAND و PID می‌گوید کدام برنامه مقصر است و SIZE/OFF اندازه را. راه‌حل تمیز، ری‌استارت همان سرویس است:

bash
sudo systemctl restart nginx

اگر ری‌استارت فعلاً ممکن نیست، می‌شود فایل را از طریق /proc خالی کرد (عدد FD را از ستون FD بردارید، بدون حرف کنارش):

bash
sudo truncate -s 0 /proc/1234/fd/7

درس اصلی: لاگی را که سرویس در آن می‌نویسد پاک نکنید؛ خالی‌اش کنید (sudo truncate -s 0 file.log) یا بگذارید logrotate کارش را بکند.

قدم ۴: لاگ‌ها، journal و logrotate

ژورنال systemd

bash
journalctl --disk-usage
sudo journalctl --vacuum-size=200M
sudo journalctl --vacuum-time=2weeks

vacuum فقط فایل‌های بایگانی‌شده‌ی ژورنال را پاک می‌کند و خطری برای سرویس‌ها ندارد. برای اینکه دوباره بزرگ نشود، سقف دائمی بگذارید:

/etc/systemd/journald.conf.d/size.conf
[Journal]
SystemMaxUse=300M
bash
sudo systemctl restart systemd-journald

logrotate

logrotate ابزاری است که روزانه اجرا می‌شود و لاگ‌ها را می‌چرخاند: فایل فعلی را کنار می‌گذارد، نسخه‌های قدیمی را فشرده می‌کند و قدیمی‌ترها را پاک می‌کند. بیشتر بسته‌ها (nginx، mysql و…) فایل خودشان را در /etc/logrotate.d/ دارند. دردسر از لاگ برنامه‌های خودتان شروع می‌شود که کسی برایشان قانونی ننوشته. مثلاً برای لاگ‌های یک پروژه‌ی لاراول:

/etc/logrotate.d/myapp
/var/www/myapp/storage/logs/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
    su www-data www-data
}

copytruncate یعنی فایل را کپی و بعد خالی کن، تا برنامه بدون ری‌استارت به نوشتن ادامه دهد. پیش از اعتماد، تنظیم را آزمایش کنید:

bash
sudo logrotate -d /etc/logrotate.d/myapp   # فقط نمایش، بدون تغییر
sudo logrotate -f /etc/logrotate.d/myapp   # اجرای اجباری

قدم ۵: apt و کرنل‌های قدیمی

bash
sudo apt clean                 # پاک‌کردن بسته‌های دانلودشده در /var/cache/apt
sudo apt autoremove --purge    # حذف وابستگی‌های بی‌استفاده، از جمله کرنل‌های قدیمی

در اوبونتو کرنل‌های قدیمی معمولاً با autoremove پاک می‌شوند و کرنل در حال اجرا و یکی قبل از آن نگه داشته می‌شوند. اگر می‌خواهید ببینید چه چیزی نصب است:

bash
uname -r
dpkg --list 'linux-image-*' | grep ^ii

کرنلی را که uname -r نشان می‌دهد هرگز دستی حذف نکنید.

قدم ۶: داکر

اگر داکر روی سرور دارید، به احتمال زیاد بخش بزرگی از /var/lib/docker مال ایمیج‌های قدیمی و کش بیلد است:

bash
docker system df
docker image prune -a      # ایمیج‌هایی که هیچ کانتینری از آن‌ها استفاده نمی‌کند
docker builder prune       # کش بیلد

هشدار: docker system prune --volumes والیوم‌هایی را که به کانتینر روشنی وصل نیستند پاک می‌کند. اگر پایگاه‌داده‌تان در والیوم است و کانتینرش فعلاً خاموش است، داده از دست می‌رود. پیش از هر prune، docker volume ls را ببینید و مطمئن باشید نسخه‌ی پشتیبان دارید.

لاگ کانتینرها هم بی‌سقف رشد می‌کند. در /etc/docker/daemon.json برایشان سقف بگذارید:

/etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": { "max-size": "50m", "max-file": "3" }
}

بعد sudo systemctl restart docker. این تنظیم فقط روی کانتینرهایی اثر دارد که از نو ساخته شوند. بیشتر درباره‌ی داکر: نصب داکر روی Ubuntu 24.04.

دیسک جا دارد ولی «No space left on device»: تمام شدن inode

هر فایل در ext4 یک inode مصرف می‌کند و تعداد inodeها هنگام ساختن فایل‌سیستم ثابت می‌شود. اگر میلیون‌ها فایل کوچک ساخته شود، inode تمام می‌شود در حالی که df -h هنوز فضای خالی نشان می‌دهد.

bash
df -i
sudo du --inodes -x --max-depth=1 / 2>/dev/null | sort -n

اگر IUse% نزدیک ۱۰۰٪ است، با تکرار du --inodes پوشه‌ی پرفایل را پیدا کنید. مقصرهای رایج: فایل‌های نشست PHP در /var/lib/php/sessions، کش فایلی برنامه که هرگز پاک نمی‌شود، و صف ایمیل. پوشه‌ای با میلیون‌ها فایل را با find پاک کنید، نه rm * که با خطای «Argument list too long» متوقف می‌شود:

bash
sudo find /var/www/myapp/storage/framework/cache -type f -mtime +7 -delete

پیشگیری: پیش از پر شدن خبردار شوید

پر شدن دیسک تقریباً هیچ‌وقت ناگهانی نیست؛ معمولاً هفته‌ها آرام بالا می‌رود. یک اسکریپت کوچک که هر چند دقیقه اجرا شود کافی است:

/usr/local/bin/disk-alert.sh
#!/usr/bin/env bash
LIMIT=85
df -P -x tmpfs -x devtmpfs -x squashfs -x overlay | awk 'NR>1 {print $5, $6}' |
while read -r use mount; do
  use=${use%\%}
  if (( use >= LIMIT )); then
    logger -t disk-alert "$mount is at ${use}%"
  fi
done
/etc/cron.d/disk-alert
*/10 * * * * root /usr/local/bin/disk-alert.sh

(chmod +x را فراموش نکنید.) logger پیام را در journal می‌نویسد؛ برای اینکه واقعاً به دستتان برسد، آن را به ایمیل یا یک وب‌هوک وصل کنید. نسخه‌ی کامل‌تری که حافظه، load و سرویس‌ها را هم بررسی می‌کند در مانیتورینگ ساده‌ی سرور لینوکس آمده و جزئیات کرون را در کرون جاب در لینوکس ببینید.

چند عادت دیگر:

  • برای هر لاگی که برنامه‌ی خودتان می‌نویسد، همان روز اول قانون logrotate بنویسید.
  • سقف ژورنال و لاگ داکر را در راه‌اندازی اولیه‌ی سرور تنظیم کنید.
  • بکاپ‌ها را روی همان دیسک سرور انباشته نکنید؛ هم جا می‌گیرند و هم با خراب شدن دیسک از بین می‌روند.

جمع‌بندی

وقتی دیسک پر می‌شود، ترتیب کار ساده است: df -h برای پیدا کردن پارتیشن، du -x یا ncdu برای پیدا کردن پوشه، lsof +L1 اگر اعداد با هم نمی‌خوانند، و df -i اگر جا هست ولی فایل ساخته نمی‌شود. بعد سراغ پاک‌سازی کم‌خطر بروید: vacuum ژورنال، apt clean و autoremove، و prune داکر با احتیاط درباره‌ی والیوم‌ها. و در آخر کاری کنید که دفعه‌ی بعد پیش از ۱۰۰٪ خبردار شوید: logrotate، سقف لاگ‌ها و یک هشدار ساده‌ی مصرف دیسک.