Cuando el disco se llena, los síntomas aparecen por todas partes: bases de datos que no arrancan, errores No space left on device, logs que dejan de escribirse o una aplicación web que devuelve errores 500. En esta guía aprenderás a localizar qué ocupa el espacio en Ubuntu 24.04, a liberarlo sin borrar nada importante y a configurar el sistema para que no vuelva a ocurrir.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. En Debian 12 los comandos son los mismos.
- Un usuario no root con privilegios
sudo.
Advertenciaantes de borrar un fichero, asegúrate de saber qué es. Borrar datos de
/var/lib(bases de datos, Docker, paquetes) puede dejar servicios inservibles. Si tienes dudas, mueve el fichero a otro disco o haz una copia antes de eliminarlo.
Paso 1: Confirmar qué sistema de ficheros está lleno
df muestra el uso de cada sistema de ficheros. Excluye los sistemas virtuales para ver solo los discos reales:
df -hT -x tmpfs -x devtmpfs -x squashfs -x efivarfs
Filesystem Type Size Used Avail Use% Mounted on
/dev/vda1 ext4 39G 38G 0 100% /
/dev/vda16 ext4 881M 112M 707M 14% /boot
/dev/vda15 vfat 105M 6.1M 99M 6% /boot/efi
Fíjate en la columna Mounted on: a partir de aquí buscarás dentro de ese punto de montaje.
Un disco también se considera "lleno" si se agotan los inodos (el número máximo de ficheros), aunque quede espacio libre. Compruébalo:
df -i /
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/vda1 2580480 2580480 0 100% /
Si IUse% está al 100 %, salta directamente al paso 6.
Paso 2: Encontrar los directorios que más ocupan
du suma el tamaño de cada directorio. La opción -x evita entrar en otros sistemas de ficheros y -d1 limita la salida al primer nivel:
sudo du -xh -d1 / 2>/dev/null | sort -rh | head -15
38G /
29G /var
6.1G /usr
1.8G /home
Repite el comando bajando por el directorio más grande hasta encontrar el culpable:
sudo du -xh -d1 /var 2>/dev/null | sort -rh | head -10
sudo du -xh -d1 /var/lib 2>/dev/null | sort -rh | head -10
Para explorar de forma interactiva, ncdu es mucho más cómodo. Te permite navegar con las flechas y borrar con d:
sudo apt install ncdu
sudo ncdu -x /
Notasi el disco está al 100 %,
apt installpuede fallar porque no tiene espacio para descargar el paquete. En ese caso, libera primero algo de espacio consudo apt cleanosudo journalctl --vacuum-size=200M(paso 5).
Paso 3: Encontrar los ficheros más grandes
Si prefieres ir directamente a los ficheros, este comando lista los 20 mayores de 100 MB en el sistema de ficheros raíz, con el tamaño en formato legible:
sudo find / -xdev -type f -size +100M -printf '%s %p\n' 2>/dev/null | sort -rn | head -20 | numfmt --field=1 --to=iec
12G /var/log/myapp/debug.log
4.3G /var/lib/docker/containers/3f2a.../3f2a...-json.log
2.0G /swapfile
1.1G /var/lib/mysql/binlog.000412
Los culpables más habituales son logs de aplicaciones sin rotación, logs de contenedores Docker, binlogs de MySQL, copias de seguridad antiguas y volcados de memoria.
Paso 4: Buscar ficheros borrados que siguen abiertos
Si df dice que el disco está lleno pero du suma mucho menos, lo más probable es que haya ficheros borrados que un proceso mantiene abiertos. El espacio no se libera hasta que el proceso cierra el fichero. Ocurre a menudo al borrar un log con rm mientras el servicio sigue escribiendo en él. Encuéntralos con lsof:
sudo lsof -nP +L1
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
java 18233 myapp 5w REG 252,1 9663676416 0 524301 /var/log/myapp/app.log (deleted)
La forma limpia de liberar ese espacio es reiniciar el servicio que tiene el fichero abierto:
sudo systemctl restart myapp
Si no puedes reiniciarlo, vacía el fichero a través del descriptor usando el PID y el número de la columna FD (sin la letra):
sudo truncate -s 0 /proc/18233/fd/5
Para evitarlo en el futuro, vacía los logs activos con truncate en lugar de borrarlos con rm:
sudo truncate -s 0 /var/log/myapp/debug.log
Paso 5: Liberar espacio en los sitios habituales
Journal de systemd
Comprueba cuánto ocupa el journal y redúcelo:
journalctl --disk-usage
sudo journalctl --vacuum-size=500M
Archived and active journals take up 3.8G in the file system.
Vacuuming done, freed 3.3G of archived journals from /var/log/journal/...
Para que no vuelva a crecer, fija un tamaño máximo con un fichero de configuración adicional:
sudo mkdir -p /etc/systemd/journald.conf.d
sudo nano /etc/systemd/journald.conf.d/size.conf
[Journal]
SystemMaxUse=500M
Reinicia el servicio para aplicarlo:
sudo systemctl restart systemd-journald
Logs rotados en /var/log
Los logs que ya ha rotado logrotate (con extensión .gz o .1) se pueden borrar sin problemas:
sudo find /var/log -type f \( -name '*.gz' -o -name '*.[0-9]' \) -mtime +7 -delete
Caché de apt y paquetes huérfanos
apt guarda los paquetes descargados en /var/cache/apt/archives. Vacíalo y elimina las dependencias que ya no se usan, incluidos los kernels antiguos:
sudo apt clean
sudo apt autoremove --purge
Revisiones antiguas de snap
snap conserva varias versiones de cada paquete. Lista las desactivadas:
snap list --all | awk '/disabled/ {print $1, $3}'
lxd 29351
core22 1564
Elimina cada una indicando su revisión y limita las que se conservan en el futuro a 2 (el mínimo permitido):
sudo snap remove lxd --revision=29351
sudo snap set system refresh.retain=2
Docker
Si usas Docker, consulta cuánto ocupan imágenes, contenedores, volúmenes y caché de compilación:
docker system df
Elimina los contenedores parados, las redes sin uso, las imágenes sin etiqueta y la caché de compilación:
docker system prune
Añade -a para borrar también todas las imágenes que no usa ningún contenedor. No uses --volumes salvo que tengas claro que no necesitas los datos de los volúmenes sin usar.
Los logs de los contenedores (/var/lib/docker/containers/*/*-json.log) crecen sin límite por defecto. Limítalos en la configuración del demonio:
sudo nano /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Reinicia Docker. El límite solo se aplica a los contenedores que se creen a partir de ahora, así que recrea los existentes (por ejemplo con docker compose up -d --force-recreate):
sudo systemctl restart docker
Binlogs de MySQL
MySQL 8 guarda los binary logs 30 días por defecto. Si ocupan mucho, puedes purgar los antiguos desde el cliente de MySQL:
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY;
Si usas replicación, asegúrate antes de que las réplicas han leído esos ficheros. Para reducir la retención de forma permanente, fija binlog_expire_logs_seconds = 259200 (3 días) en la sección [mysqld] de la configuración.
Volcados de memoria
Los informes de fallos se acumulan en /var/crash y, si usas systemd-coredump, en /var/lib/systemd/coredump. Revísalos y bórralos si no los necesitas:
sudo du -sh /var/crash /var/lib/systemd/coredump 2>/dev/null
sudo rm -f /var/crash/*.crash
Comprueba después el espacio recuperado:
df -h /
Paso 6: Resolver el agotamiento de inodos
Si el problema son los inodos, busca el directorio con más ficheros. du --inodes cuenta ficheros en lugar de bytes:
sudo du --inodes -x -d1 / 2>/dev/null | sort -rn | head -10
2580479 /
2311004 /var
201330 /usr
Baja nivel a nivel igual que en el paso 2. Las causas habituales son sesiones de PHP (/var/lib/php/sessions), cachés de aplicaciones con millones de ficheros pequeños y colas de correo (/var/spool/postfix). Por ejemplo, para borrar sesiones de PHP de más de un día:
sudo find /var/lib/php/sessions -type f -mtime +1 -delete
find -delete es la forma correcta de borrar millones de ficheros: rm * fallará con el error Argument list too long.
Paso 7: Configurar la rotación de logs de tus aplicaciones
La causa más frecuente de un disco lleno es un log propio sin rotación. Crea una regla de logrotate para tu aplicación:
sudo nano /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
copytruncate
}
copytruncate copia el log y vacía el original, así que funciona con aplicaciones que no reabren el fichero al rotar. Prueba la configuración en modo de depuración, que no hace cambios:
sudo logrotate -d /etc/logrotate.d/myapp
Solución de problemas
dfmuestra el 100 % perodusuma menos: hay ficheros borrados abiertos (paso 4), o ficheros escritos en un directorio antes de montar encima otro disco. Para ver estos últimos, monta la raíz en otro punto consudo mount --bind / /mnty ejecutasudo du -xh -d1 /mnt.Availes 0 peroUse%no llega al 100 %: ext4 reserva un 5 % del disco para root. Los servicios que se ejecutan como root pueden seguir escribiendo, pero el resto no. Libera espacio en lugar de reducir la reserva./bootlleno yaptfalla al instalar un kernel: lista los kernels instalados condpkg -l 'linux-image-*' | grep ^ii, comprueba el que usas conuname -ry elimina uno antiguo consudo apt purge linux-image-VERSION. Nunca borres el kernel en uso.- MySQL o PostgreSQL no arrancan tras llenarse el disco: libera espacio primero y revisa después su log (
sudo journalctl -u mysql). No borres ficheros dentro de su directorio de datos.
Conclusión
Has aprendido a localizar qué llena el disco con df, du, ncdu y find, a recuperar el espacio retenido por ficheros borrados abiertos y a limpiar de forma segura el journal, apt, snap, Docker y los binlogs. Como siguientes pasos, limita el tamaño del journal y de los logs de Docker, añade logrotate a tus aplicaciones y configura una alerta de uso de disco al 80 % en tu sistema de monitorización. Si el disco se queda corto de forma habitual, amplía el almacenamiento de tu VPS.
