GuíasGuides · Nivel 2Level 2

Ubuntu Server: un disco lleno, journald, logrotate, kernels antiguos y un servicio que no arrancaUbuntu Server: a full disk, journald, logrotate, old kernels and a service that won't start

Encontrar qué llena el disco con df, du y ncdu, poner límite al journal, rotar los logs de una aplicación con logrotate, limpiar la caché de apt y los kernels antiguos, leer systemctl status y journalctl -u, ajustar un servicio con systemctl edit y su política de reinicio, y el ticket de la aplicación que dejó de escribir logs.Find what fills the disk with df, du and ncdu, cap the journal, rotate an application's logs with logrotate, clean the apt cache and old kernels, read systemctl status and journalctl -u, adjust a service with systemctl edit and its restart policy, and the ticket of the app that stopped writing logs.

¿Prefieres practicarlo?Resuelve el ticket simulado «502 Bad Gateway: la aplicación de fichajes no funciona» en SysAdmin Desks ↗

Qué vas a conseguir

Saber en cinco minutos qué está llenando un Ubuntu Server y liberar espacio sin borrar lo que no toca; dejar el journal y los logs de las aplicaciones con un tamaño máximo para que no vuelva a pasar; y, cuando un servicio no arranca, leer lo que systemd dice de él, corregir su unidad sin tocar el fichero del paquete y darle una política de reinicio sensata.

Antes de empezar

  • Ubuntu Server 22.04 o 24.04 LTS y un usuario con sudo.
  • El nombre del servicio de la aplicación (aquí, contoso-api.service) y dónde escribe sus logs (/var/log/contoso-api/).
  • ncdu instalado (sudo apt install ncdu). Si el disco está al 100 %, puede que ni apt funcione: los pasos 1 y 2 se hacen con lo que ya trae el sistema.

1. Qué está lleno: df, du y ncdu

bash · srv-app-02
df -h -x tmpfs -x squashfsFilesystem                         Size  Used Avail Use% Mounted on/dev/mapper/ubuntu--vg-ubuntu--lv   48G   48G     0 100% //dev/sda2                          2.0G  1.6G  248M  87% /bootdf -i /Filesystem                        Inodes  IUsed   IFree IUse% Mounted on/dev/mapper/ubuntu--vg-ubuntu--lv 3.1M    212K    2.9M    7% /sudo du -xh --max-depth=1 /var 2>/dev/null | sort -h | tail -n 41.2G    /var/cache3.9G    /var/lib41G     /var/log46G     /var
  • df -h dice qué sistema de ficheros está lleno; df -i, si lo que se ha acabado son los inodos (millones de ficheros pequeños, como sesiones o colas de correo). Con los inodos al 100 % hay espacio libre y aun así no se puede crear ningún fichero.
  • du -x no cruza a otros sistemas de ficheros: así no cuentas un recurso NFS montado debajo. Baja nivel a nivel (/var, luego /var/log) hasta dar con el culpable.
  • sudo ncdu -x / hace lo mismo de forma interactiva: flechas para entrar, d para borrar. Úsalo para mirar, y borra con cabeza.
  • En ext4, el 5 % del disco está reservado para root. Por eso los servicios que corren con su propio usuario fallan primero, mientras root aún puede escribir.

Un fichero borrado que un proceso tiene abierto no libera espacio hasta que el proceso lo cierra. Si df no baja después de un rm, sudo lsof +L1 lista esos ficheros. Para vaciar un log en uso, se trunca (sudo truncate -s 0 fichero.log), no se borra.

2. El journal de systemd

bash · srv-app-02
journalctl --disk-usageArchived and active journals take up 3.9G in the file system.sudo journalctl --vacuum-size=500MVacuuming done, freed 3.4G of archived journals from /var/log/journal/4c1f0e8a7d2b4e0f9a3c5d6e7f8a9b0c.sudo journalctl --vacuum-time=2weeks

--vacuum-size y --vacuum-time solo borran ficheros archivados; para que el límite sea permanente, un fichero propio en journald.conf.d:

/etc/systemd/journald.conf.d/10-tamano.conf
[Journal]SystemMaxUse=500MSystemKeepFree=2G

sudo systemctl restart systemd-journald lo aplica. Por defecto el journal puede ocupar el 10 % del sistema de ficheros, con un máximo de 4 GB: en un disco de 40 GB son 4 GB de logs del sistema.

3. Los logs de la aplicación con logrotate

journald no rota los ficheros que una aplicación escribe por su cuenta. Para eso, un fichero en /etc/logrotate.d/:

/etc/logrotate.d/contoso-api
/var/log/contoso-api/*.log {    daily    rotate 14    maxsize 500M    compress    delaycompress    missingok    notifempty    su contoso contoso    create 0640 contoso contoso    postrotate        systemctl kill -s HUP contoso-api.service    endscript}
  • rotate 14 guarda 14 ficheros; compress los comprime y delaycompress deja sin comprimir el más reciente, por si la aplicación aún escribe en él.
  • su hace falta cuando la carpeta pertenece al usuario de la aplicación; sin él, logrotate se niega con parent directory has insecure permissions.
  • postrotate avisa a la aplicación para que reabra el fichero. Si no sabe hacerlo, cambia create y el bloque postrotate por copytruncate: copia y vacía el fichero en su sitio, y puede perder las líneas escritas en ese instante.
  • En Ubuntu, logrotate lo lanza logrotate.timer una vez al día. maxsize solo se comprueba en cada ejecución: si la aplicación puede escribir gigas en unas horas, toca ejecutarlo más a menudo.
bash · probar la configuración
sudo logrotate -d /etc/logrotate.d/contoso-apisudo logrotate -f /etc/logrotate.d/contoso-apisystemctl list-timers logrotate.timer

-d simula y explica lo que haría sin tocar nada; -f fuerza una rotación ahora.

4. La caché de apt y los kernels antiguos

bash · srv-app-02
uname -r6.8.0-87-genericdpkg --list 'linux-image-[0-9]*' | awk '/^ii/{print $2}'linux-image-6.8.0-79-genericlinux-image-6.8.0-84-genericlinux-image-6.8.0-87-genericsudo apt cleansudo apt autoremove --purge
  • apt clean vacía /var/cache/apt/archives/, los paquetes ya instalados.
  • apt autoremove --purge quita los kernels que ya no hacen falta: conserva el que está en uso y el anterior, como vuelta atrás. Es lo que libera /boot cuando una actualización falla por falta de espacio. Nunca borres a mano el kernel que muestra uname -r.
  • Si el servidor usa snaps, sudo snap set system refresh.retain=2 limita a dos las versiones guardadas de cada uno.

5. Un servicio: systemctl status y journalctl -u

bash · srv-app-02
systemctl status contoso-api --no-pager× contoso-api.service - Contoso API de facturas     Loaded: loaded (/etc/systemd/system/contoso-api.service; enabled; preset: enabled)     Active: failed (Result: start-limit-hit) since Mon 2026-11-02 08:14:03 CET; 3min ago    Process: 2311 ExecStart=/opt/contoso-api/bin/contoso-api (code=exited, status=1/FAILURE)   Main PID: 2311 (code=exited, status=1/FAILURE)journalctl -u contoso-api -b -n 20 --no-pagerjournalctl -u contoso-api --since "08:00" -p err
  • Loaded dice dónde está el fichero de la unidad y si arranca con el sistema (enabled). Active dice cómo terminó: exit-code, oom-kill, timeout o start-limit-hit.
  • journalctl -u filtra por unidad; -b, desde el último arranque; -p err, solo errores; -f, en directo mientras lo arrancas en otra ventana.
  • systemctl cat contoso-api muestra la unidad completa, con los ficheros que la modifican.

6. Ajustar la unidad con systemctl edit y la política de reinicio

El fichero de la unidad lo instala el paquete o el equipo de la aplicación. Los cambios propios van en un fichero aparte, que sobrevive a las actualizaciones:

bash · sudo systemctl edit contoso-api
[Unit]StartLimitIntervalSec=300StartLimitBurst=5 [Service]Restart=on-failureRestartSec=10
  • systemctl edit crea /etc/systemd/system/contoso-api.service.d/override.conf y recarga systemd al guardar. systemctl revert contoso-api lo deshace.
  • Restart=on-failure vuelve a arrancar el servicio si muere con error, pero no si alguien lo para con systemctl stop. RestartSec es la espera entre intentos.
  • StartLimitBurst y StartLimitIntervalSec (en [Unit]) ponen el tope: más de 5 arranques en 300 segundos y systemd deja de intentarlo con start-limit-hit. Sin tope, un servicio roto se reinicia en bucle y llena el journal.

7. El ticket: "la aplicación ha dejado de escribir logs y el servicio no arranca"

Lunes, 8:20. Administración no puede emitir facturas. El equipo de la aplicación dice que el último log es del domingo a las 23:47 y que el servicio no levanta.

  1. El estado: systemctl status contoso-api dice failed (Result: start-limit-hit). Ese resultado no es la causa: es systemd diciendo que dejó de intentarlo.
  2. La causa, en el journal:
bash · journalctl -u contoso-api
journalctl -u contoso-api -b --no-pager | tail -n 4nov 02 08:13:52 srv-app-02 contoso-api[2311]: FATAL cannot open /var/log/contoso-api/app.log: No space left on devicenov 02 08:13:52 srv-app-02 systemd[1]: contoso-api.service: Main process exited, code=exited, status=1/FAILUREnov 02 08:14:03 srv-app-02 systemd[1]: contoso-api.service: Start request repeated too quickly.nov 02 08:14:03 srv-app-02 systemd[1]: contoso-api.service: Failed with result 'start-limit-hit'.
  1. El disco: df -h / al 100 % y du lleva a /var/log/contoso-api/app.log, de 38 GB. La aplicación cambió el nivel de log a debug en el despliegue del viernes y no había ninguna regla de logrotate para esa carpeta.
  2. Liberar espacio sin perder la evidencia: guardar las últimas líneas (sudo tail -n 5000 app.log > /root/app-tail.log), truncar el fichero (sudo truncate -s 0 /var/log/contoso-api/app.log) y vaciar lo archivado del journal (journalctl --vacuum-size=500M). Comprobar que df baja; si no baja, lsof +L1.
  3. Arrancar: después de un start-limit-hit, systemd no deja arrancar hasta reiniciar el contador:
bash · srv-app-02
sudo systemctl reset-failed contoso-apisudo systemctl start contoso-apisystemctl is-active contoso-apiactivecurl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/health200
  1. Que no se repita: la regla de logrotate del apartado 3, el límite del journal del apartado 2, el nivel de log devuelto a info por el equipo de la aplicación y una alerta de disco al 80 % en la monitorización.

En el ticket: sistema de ficheros y uso antes y después, qué fichero lo llenó y por qué, qué se truncó y qué se guardó, y las dos reglas nuevas.

Siguientes pasos

¿Quieres practicarlo? Resuelve el ticket «502 Bad Gateway: la aplicación de fichajes no funciona» en SysAdmin Desks, gratis y en el navegador.

¿Falta algo o en tu entorno es distinto? Escríbeme y lo corrijo.

Rather practise it?Solve the simulated ticket "502 Bad Gateway: the timesheets app is down" in SysAdmin Desks ↗

What you'll get

Knowing within five minutes what is filling an Ubuntu Server and freeing space without deleting the wrong thing; capping the journal and the applications' logs so it does not happen again; and, when a service won't start, reading what systemd says about it, fixing its unit without touching the package's file and giving it a sensible restart policy.

Before you start

  • Ubuntu Server 22.04 or 24.04 LTS and a user with sudo.
  • The application's service name (here, contoso-api.service) and where it writes its logs (/var/log/contoso-api/).
  • ncdu installed (sudo apt install ncdu). If the disk is at 100 %, even apt may not work: steps 1 and 2 use what the system already has.

1. What is full: df, du and ncdu

bash · srv-app-02
df -h -x tmpfs -x squashfsFilesystem                         Size  Used Avail Use% Mounted on/dev/mapper/ubuntu--vg-ubuntu--lv   48G   48G     0 100% //dev/sda2                          2.0G  1.6G  248M  87% /bootdf -i /Filesystem                        Inodes  IUsed   IFree IUse% Mounted on/dev/mapper/ubuntu--vg-ubuntu--lv 3.1M    212K    2.9M    7% /sudo du -xh --max-depth=1 /var 2>/dev/null | sort -h | tail -n 41.2G    /var/cache3.9G    /var/lib41G     /var/log46G     /var
  • df -h tells you which file system is full; df -i, whether what has run out is inodes (millions of small files, such as sessions or mail queues). With inodes at 100 % there is free space and still no file can be created.
  • du -x does not cross into other file systems: that way you do not count an NFS share mounted underneath. Go down level by level (/var, then /var/log) until you find the culprit.
  • sudo ncdu -x / does the same interactively: arrows to go in, d to delete. Use it to look, and delete carefully.
  • On ext4, 5 % of the disk is reserved for root. That is why services running under their own user fail first, while root can still write.

A deleted file that a process still holds open frees no space until the process closes it. If df does not go down after an rm, sudo lsof +L1 lists those files. To empty a log in use, truncate it (sudo truncate -s 0 file.log), do not delete it.

2. The systemd journal

bash · srv-app-02
journalctl --disk-usageArchived and active journals take up 3.9G in the file system.sudo journalctl --vacuum-size=500MVacuuming done, freed 3.4G of archived journals from /var/log/journal/4c1f0e8a7d2b4e0f9a3c5d6e7f8a9b0c.sudo journalctl --vacuum-time=2weeks

--vacuum-size and --vacuum-time only delete archived files; to make the limit permanent, a file of your own in journald.conf.d:

/etc/systemd/journald.conf.d/10-size.conf
[Journal]SystemMaxUse=500MSystemKeepFree=2G

sudo systemctl restart systemd-journald applies it. By default the journal may take 10 % of the file system, up to 4 GB: on a 40 GB disk that is 4 GB of system logs.

3. The application's logs with logrotate

journald does not rotate files an application writes on its own. For that, a file in /etc/logrotate.d/:

/etc/logrotate.d/contoso-api
/var/log/contoso-api/*.log {    daily    rotate 14    maxsize 500M    compress    delaycompress    missingok    notifempty    su contoso contoso    create 0640 contoso contoso    postrotate        systemctl kill -s HUP contoso-api.service    endscript}
  • rotate 14 keeps 14 files; compress compresses them and delaycompress leaves the newest uncompressed, in case the app is still writing to it.
  • su is needed when the folder belongs to the application's user; without it, logrotate refuses with parent directory has insecure permissions.
  • postrotate tells the application to reopen the file. If it cannot, replace create and the postrotate block with copytruncate: it copies and empties the file in place, and may lose the lines written at that instant.
  • On Ubuntu, logrotate is run by logrotate.timer once a day. maxsize is only checked on each run: if the app can write gigabytes in a few hours, it has to run more often.
bash · test the configuration
sudo logrotate -d /etc/logrotate.d/contoso-apisudo logrotate -f /etc/logrotate.d/contoso-apisystemctl list-timers logrotate.timer

-d simulates and explains what it would do without touching anything; -f forces a rotation now.

4. The apt cache and old kernels

bash · srv-app-02
uname -r6.8.0-87-genericdpkg --list 'linux-image-[0-9]*' | awk '/^ii/{print $2}'linux-image-6.8.0-79-genericlinux-image-6.8.0-84-genericlinux-image-6.8.0-87-genericsudo apt cleansudo apt autoremove --purge
  • apt clean empties /var/cache/apt/archives/, packages that are already installed.
  • apt autoremove --purge removes kernels no longer needed: it keeps the running one and the previous one as a way back. It is what frees /boot when an update fails for lack of space. Never remove by hand the kernel uname -r shows.
  • If the server uses snaps, sudo snap set system refresh.retain=2 limits each one to two saved revisions.

5. A service: systemctl status and journalctl -u

bash · srv-app-02
systemctl status contoso-api --no-pager× contoso-api.service - Contoso invoicing API     Loaded: loaded (/etc/systemd/system/contoso-api.service; enabled; preset: enabled)     Active: failed (Result: start-limit-hit) since Mon 2026-11-02 08:14:03 CET; 3min ago    Process: 2311 ExecStart=/opt/contoso-api/bin/contoso-api (code=exited, status=1/FAILURE)   Main PID: 2311 (code=exited, status=1/FAILURE)journalctl -u contoso-api -b -n 20 --no-pagerjournalctl -u contoso-api --since "08:00" -p err
  • Loaded says where the unit file is and whether it starts at boot (enabled). Active says how it ended: exit-code, oom-kill, timeout or start-limit-hit.
  • journalctl -u filters by unit; -b, since the last boot; -p err, errors only; -f, live while you start it in another window.
  • systemctl cat contoso-api shows the whole unit, with the files that modify it.

6. Adjusting the unit with systemctl edit and the restart policy

The unit file is installed by the package or by the application team. Your own changes go in a separate file that survives updates:

bash · sudo systemctl edit contoso-api
[Unit]StartLimitIntervalSec=300StartLimitBurst=5 [Service]Restart=on-failureRestartSec=10
  • systemctl edit creates /etc/systemd/system/contoso-api.service.d/override.conf and reloads systemd on save. systemctl revert contoso-api undoes it.
  • Restart=on-failure starts the service again if it dies with an error, but not if someone stops it with systemctl stop. RestartSec is the wait between attempts.
  • StartLimitBurst and StartLimitIntervalSec (in [Unit]) set the ceiling: more than 5 starts in 300 seconds and systemd stops trying with start-limit-hit. Without a ceiling, a broken service restarts in a loop and fills the journal.

7. The ticket: "the application stopped writing logs and the service fails to start"

Monday, 8:20. Accounts cannot issue invoices. The application team says the last log line is from Sunday at 23:47 and the service will not come up.

  1. The state: systemctl status contoso-api says failed (Result: start-limit-hit). That result is not the cause: it is systemd saying it gave up.
  2. The cause, in the journal:
bash · journalctl -u contoso-api
journalctl -u contoso-api -b --no-pager | tail -n 4Nov 02 08:13:52 srv-app-02 contoso-api[2311]: FATAL cannot open /var/log/contoso-api/app.log: No space left on deviceNov 02 08:13:52 srv-app-02 systemd[1]: contoso-api.service: Main process exited, code=exited, status=1/FAILURENov 02 08:14:03 srv-app-02 systemd[1]: contoso-api.service: Start request repeated too quickly.Nov 02 08:14:03 srv-app-02 systemd[1]: contoso-api.service: Failed with result 'start-limit-hit'.
  1. The disk: df -h / at 100 % and du leads to /var/log/contoso-api/app.log, 38 GB. The application switched its log level to debug in Friday's deployment and there was no logrotate rule for that folder.
  2. Free space without losing the evidence: keep the last lines (sudo tail -n 5000 app.log > /root/app-tail.log), truncate the file (sudo truncate -s 0 /var/log/contoso-api/app.log) and clear the archived journal (journalctl --vacuum-size=500M). Check that df goes down; if it does not, lsof +L1.
  3. Start it: after a start-limit-hit, systemd will not start the unit until the counter is reset:
bash · srv-app-02
sudo systemctl reset-failed contoso-apisudo systemctl start contoso-apisystemctl is-active contoso-apiactivecurl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/health200
  1. So it does not happen again: the logrotate rule from section 3, the journal limit from section 2, the log level set back to info by the application team, and a disk alert at 80 % in monitoring.

In the ticket: file system and usage before and after, which file filled it and why, what was truncated and what was kept, and the two new rules.

Next steps

Want to practise it? Solve the ticket “502 Bad Gateway: the timesheets app is down” in SysAdmin Desks, free and in your browser.

Is something missing, or different in your environment? Get in touch and I'll fix it.

Tech Career Lab · newsletter

¿Te ha servido? Cada dos semanas envío una idea práctica para perfiles IT: LinkedIn, proyectos, networking y procesos de selección.Found this useful? Every two weeks I send one practical idea for IT professionals: LinkedIn, projects, networking and hiring processes.

Apúntate y llévate las 33 ideasSign up and get the 33 ideas →