Administración de Linux
El sistema de archivos de Linux: jerarquía, rutas, enlaces, montajes y discos
Principiante12 min de lecturaActualizado
Esta página se tradujo del inglés con ayuda de IA y se cotejó con el original. Leer la versión en inglés
Al terminar esta guía sabrás para qué sirve cada directorio de primer nivel, cómo leer una línea de ls -l, por qué los enlaces duros y los simbólicos se comportan de forma distinta, cómo se incorporan las particiones al árbol con mount y /etc/fstab, y cómo averiguar a dónde se ha ido el espacio en disco. Los ejemplos se centran en sistemas Debian/Ubuntu y de la familia RHEL actuales.
Lo que aprenderás
- Describir la función de los principales directorios de la FHS, como /etc, /var, /usr, /opt, /proc y /run
- Leer una línea de ls -l e identificar el tipo de archivo, los permisos, el número de enlaces, el propietario y el tamaño
- Explicar la diferencia entre un enlace duro y un enlace simbólico, y elegir el adecuado
- Inspeccionar dispositivos de bloque y montajes con lsblk, findmnt y df, y añadir una entrada persistente a /etc/fstab
- Localizar archivos con find y medir el tamaño de los directorios con du
Linux no tiene letras de unidad. Hay un único árbol, con raíz en /, y cada disco, memoria USB, recurso compartido de red e incluso la contabilidad interna del kernel se injerta en él en algún punto. Cuando conoces las convenciones sobre dónde va cada cosa, un servidor desconocido deja de ser un laberinto: la configuración está en /etc, los datos variables en /var, la vista en vivo que el kernel tiene de la máquina en /proc, y así sucesivamente. Esta guía recorre el árbol, explica los objetos que lo habitan (archivos, directorios, enlaces, dispositivos) y muestra cómo se conecta el almacenamiento y cómo inspeccionarlo.
Un árbol, muchos sistemas de archivos
La expresión sistema de archivos se usa para dos cosas distintas, y separarlas bien evita mucha confusión.
El árbol de directorios es el espacio de nombres lógico: /home/alice/notes.txt es una ruta dentro del árbol. Un sistema de archivos, en el sentido de almacenamiento, es una estructura de datos sobre un dispositivo de bloque —ext4, XFS, Btrfs, FAT— que guarda archivos y directorios. El árbol se construye durante el arranque montando sistemas de archivos sobre directorios: el sistema de archivos raíz se monta en /, y otros pueden montarse en /boot, /home, /var/lib/postgresql o en cualquier otro sitio. Para un programa que recorre el árbol, las costuras son invisibles.
Debian y Ubuntu se instalan con ext4 por defecto; las distribuciones de la familia RHEL (Rocky Linux, AlmaLinux, RHEL) usan XFS por defecto. Ambos son sistemas de archivos con journaling maduros; XFS no se puede reducir una vez creado, y esa es la principal diferencia operativa con la que te vas a encontrar.
Los directorios estándar
El Filesystem Hierarchy Standard (FHS) define la organización que ves a continuación. Las distribuciones la siguen de cerca, con algunas variaciones modernas que se indican sobre la marcha.
| Directorio | Qué contiene |
|---|---|
/bin, /sbin, /lib | En las distribuciones actuales son enlaces simbólicos a /usr (el «usr merge»). Históricamente, sbin contenía los binarios reservados al administrador. |
/usr | El grueso del software instalado: /usr/bin para los comandos, /usr/lib y /usr/lib64 para las bibliotecas compartidas, /usr/share para los datos independientes de la arquitectura, como las páginas de manual y los archivos de locale. De solo lectura en funcionamiento normal. |
/usr/local | El software que compilas o instalas a mano, organizado como /usr. Los gestores de paquetes nunca escriben aquí, así que nada de lo que pongas en /usr/local/bin lo sobrescribirá una actualización. |
/opt | Aplicaciones de terceros autocontenidas, un directorio cada una (/opt/jdk-21, /opt/myapp). |
/etc | La configuración propia de la máquina, en texto plano. Sin binarios. |
/var | Datos que cambian mientras el sistema está en marcha: logs (/var/log), cachés de paquetes (/var/cache/apt), estado de las aplicaciones (/var/lib/mysql), colas de correo, y /var/tmp para archivos temporales que deben sobrevivir a un reinicio. |
/home | Los directorios personales de los usuarios. /root es el del superusuario, separado para que siga disponible aunque /home no llegue a montarse. |
/tmp | Espacio de trabajo temporal que puede vaciarse al arrancar (a menudo un tmpfs en RAM). |
/run | El estado de ejecución desde el último arranque: archivos PID, sockets, archivos de bloqueo. Un tmpfs que queda vacío tras cada reinicio. |
/boot | La imagen del kernel, el disco RAM inicial y los archivos del gestor de arranque. A menudo es una partición pequeña independiente. |
/dev | Los archivos de dispositivo, que el kernel y udev crean dinámicamente. |
/proc, /sys | Sistemas de archivos virtuales que exponen el estado del kernel y del hardware; no ocupan espacio en disco. |
/srv | Los datos que sirve la máquina (contenido web, árboles FTP) cuando el administrador prefiere mantenerlos fuera de /var. |
/mnt, /media | Puntos de montaje temporales para el administrador y para los medios extraíbles, respectivamente. |
/lost+found | Donde fsck deja los datos huérfanos que recupera en un sistema de archivos ext. Hay uno por cada sistema de archivos ext. |
Algunos merecen que nos detengamos en ellos.
/etc: la configuración como texto
Casi todo lo que determina cómo se comporta una máquina es un archivo legible bajo /etc: /etc/hostname, /etc/hosts, /etc/fstab, /etc/passwd, /etc/ssh/sshd_config, /etc/systemd/system/ para tus unidades de servicio, /etc/nginx/ o /etc/httpd/ para los servidores web. Como es texto plano, /etc se puede comparar con diff, versionar y auditar con grep. Cuando algo se comporta de forma inesperada, un grep -r por /etc suele ser más rápido que leer la documentación.
Muchos paquetes admiten un directorio drop-in *.d junto a su archivo principal: /etc/sudoers.d/, /etc/apt/sources.list.d/, /etc/systemd/system/app.service.d/. Pon tus cambios en un archivo nuevo dentro de ese directorio en lugar de editar el archivo del paquete, y las actualizaciones no los machacarán.
/proc y /sys: el kernel como archivos
/proc es una ventana al kernel en ejecución. /proc/cpuinfo y /proc/meminfo describen el hardware; /proc/loadavg es lo que lee uptime; cada proceso tiene un directorio /proc/<pid>/ con su línea de comandos, su entorno, sus descriptores de archivo abiertos (fd/), sus mapas de memoria y su directorio de trabajo actual. Herramientas como ps, top y lsof no hacen nada más exótico que leer estos archivos.
cat /proc/loadavg # 0.42 0.31 0.28 1/412 18342
ls -l /proc/$$/fd # descriptores de archivo del shell actual
cat /proc/$(pgrep -o nginx)/cmdline | tr '\0' ' '
/sys expone el modelo de dispositivos: qué controladores están asociados a qué dispositivos, los parámetros de los dispositivos de bloque, las estadísticas de las interfaces de red. Escribir en algunos de sus archivos cambia el comportamiento del kernel en caliente (por ejemplo, el planificador de E/S de un disco en /sys/block/sda/queue/scheduler).
/dev: todo es un archivo
Los dispositivos aparecen como archivos especiales, de modo que las mismas llamadas open/read/write funcionan sobre un disco, un terminal o una fuente de números aleatorios. Los discos aparecen como /dev/sda, /dev/nvme0n1, /dev/vda y sus particiones como /dev/sda1, /dev/nvme0n1p1. Hay unos cuantos pseudodispositivos que se usan a diario:
/dev/nulldescarta todo lo que se escribe en él y se lee como vacío: el sitio habitual al que mandar la salida que no quieres./dev/zeroproduce un flujo infinito de bytes a cero, útil para crear archivos en blanco./dev/urandomproduce bytes aleatorios./dev/ttyes el terminal de control del proceso actual.
Cómo leer una línea de ls -l
ls -l condensa mucha información en una sola línea. Fíjate en estas entradas de /etc:
-rw-r--r-- 1 root root 1354 Mar 14 09:12 fstab
drwxr-xr-x 2 root root 4096 Aug 30 17:40 cron.d
lrwxrwxrwx 1 root root 21 Jan 6 10:02 localtime -> /usr/share/zoneinfo/UTC
De izquierda a derecha: el tipo de archivo (- archivo normal, d directorio, l enlace simbólico, c dispositivo de caracteres, b dispositivo de bloque, s socket, p tubería con nombre), nueve bits de permisos en tres grupos para el propietario, el grupo y el resto, el número de enlaces duros, el propietario, el grupo, el tamaño en bytes, la fecha de modificación y el nombre. Los permisos tienen su propia guía en Usuarios, grupos y permisos.
Hay dos detalles que suelen confundir. Los archivos cuyo nombre empieza por un punto no aparecen con un ls simple; usa ls -a (o -A para omitir . y ..). Y el tamaño de un directorio que muestra ls es el de su lista de entradas, no el de su contenido; para eso necesitas du.
Inodos, enlaces duros y enlaces simbólicos
Cada archivo de un sistema de archivos está descrito por un inodo: un registro que guarda el propietario, los permisos, las marcas de tiempo, el tamaño y la lista de bloques de datos; todo menos el nombre. Un directorio no es más que una tabla que asocia nombres con números de inodo. ls -i muestra esos números y stat el registro completo:
$ stat /etc/fstab
File: /etc/fstab
Size: 1354 Blocks: 8 IO Block: 4096 regular file
Device: 259,2 Inode: 1572867 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Como el nombre no forma parte del inodo, un mismo inodo puede tener varios nombres. Un enlace duro (hard link) es una segunda entrada de directorio para el mismo inodo; el contador Links de arriba te dice cuántas hay. Borrar un nombre solo decrementa ese contador, y los datos se liberan cuando llega a cero y ningún proceso mantiene el archivo abierto. Los enlaces duros no pueden cruzar sistemas de archivos (los números de inodo son propios de cada uno) ni apuntar a directorios.
Un enlace simbólico (symlink) es otra cosa muy distinta: un archivo pequeño cuyo contenido es una ruta. El kernel sigue esa ruta cuando abres el enlace. Un symlink puede apuntar a cualquier sitio, incluidos directorios, otros sistemas de archivos o destinos que todavía no existen; en ese caso se habla de enlace roto (dangling).
ln /var/lib/app/data.db /backup/data.db # enlace duro: mismo inodo
ln -s /opt/app-2.4.1 /opt/app # symlink: puntero a la "versión actual"
readlink -f /opt/app/bin/start # resuelve todos los enlaces de la ruta
El patrón /opt/app -> /opt/app-2.4.1 es un recurso de despliegue muy habitual: descomprimes la nueva versión junto a la anterior y luego cambias el enlace de forma atómica con ln -sfn /opt/app-2.5.0 /opt/app. Volver atrás es otro ln.
Un symlink relativo (ln -s ../shared/config.yml config.yml) se resuelve respecto al directorio que contiene el enlace, lo que lo mantiene válido si se mueve o se copia todo el árbol; uno absoluto, en ese caso, se rompe. Prefiere destinos relativos dentro del árbol de un proyecto y destinos absolutos para los punteros de todo el sistema.
Rutas y navegación
Una ruta absoluta empieza por /; una ruta relativa se resuelve respecto al directorio de trabajo actual, que pwd muestra y cd cambia. En todo directorio existen dos entradas especiales: . (el propio directorio) y .. (su directorio padre). El shell expande ~ a tu directorio personal y ~bob al de Bob.
cd /var/log # absoluta
cd ../lib # relativa: /var/lib
cd - # vuelta al directorio anterior
cd # directorio personal
Los comandos de archivos del día a día son ls, cp, mv, rm, mkdir y rmdir. Hay tres opciones que importan más que el resto: mkdir -p crea los directorios intermedios y no se queja si la ruta ya existe; cp -a copia de forma recursiva conservando permisos, propietario, marcas de tiempo y symlinks (lo que quieres para una copia de seguridad, a diferencia de un simple cp -r); y rm -rf borra sin preguntar: escribe la ruta, revísala y solo entonces pulsa Intro.
Discos, particiones y montajes
lsblk dibuja el panorama del almacenamiento: dispositivos, sus particiones, tamaños, tipos de sistema de archivos y dónde está montado cada uno.
$ lsblk -f
NAME FSTYPE FSVER LABEL UUID MOUNTPOINTS
nvme0n1
├─nvme0n1p1 vfat FAT32 6E1A-3B7C /boot/efi
├─nvme0n1p2 ext4 1.0 3f2c8a1e-4b5d-4f6a-9c1d-2e3f4a5b6c7d /
└─nvme0n1p3 swap 1 9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d [SWAP]
findmnt lista los montajes en forma de árbol con sus opciones; mount sin argumentos muestra la misma información en el formato plano antiguo. Para montar un sistema de archivos a mano:
sudo mkdir -p /mnt/data
sudo mount /dev/sdb1 /mnt/data
sudo umount /mnt/data # falla con "target is busy" si algún proceso lo está usando
Un montaje manual desaparece al reiniciar. Los montajes persistentes se declaran en /etc/fstab, una línea por sistema de archivos: dispositivo, punto de montaje, tipo, opciones y dos números para el orden de dump y de fsck.
# <device> <mount> <type> <options> <dump> <pass>
UUID=3f2c8a1e-4b5d-4f6a-9c1d-2e3f4a5b6c7d / ext4 errors=remount-ro 0 1
UUID=6E1A-3B7C /boot/efi vfat umask=0077 0 1
UUID=b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e /srv/data xfs defaults,nofail 0 2
Identifica los dispositivos por UUID (obtenido con blkid o lsblk -f), nunca por /dev/sdX: los nombres de dispositivo dependen del orden de detección y pueden cambiar al añadir un disco. La opción nofail indica al proceso de arranque que continúe si falta ese dispositivo, y marca la diferencia entre un servidor que arranca sin su disco de datos y otro que cae en un shell de emergencia. Después de editar fstab, sudo mount -a monta todo lo que aún no está montado y valida tu sintaxis antes de que lo descubras en el siguiente reinicio; en máquinas con systemd, ejecuta primero sudo systemctl daemon-reload para que se regeneren las unidades de montaje.
¿Dónde se ha ido el espacio?
df informa del espacio libre de cada sistema de archivos montado; du mide lo que ocupa un árbol de directorios. Usados juntos, resuelven la mayoría de las alertas de «disco lleno».
df -h # tamaños legibles, una línea por sistema de archivos
df -i # uso de inodos: un sistema de archivos puede estar "lleno" con bytes libres
sudo du -sh /var/* | sort -h # qué directorio de primer nivel bajo /var es el más grande
sudo du -xh --max-depth=2 /var/log | sort -h | tail
du -x se queda en un único sistema de archivos, lo que importa cuando, de no ser así, se contarían /proc o un montaje de red. Quedarse sin inodos es un fallo clásico de las colas de correo y de los directorios de sesiones que guardan millones de archivos diminutos.
Cuando df y du no cuadran, busca archivos borrados pero todavía abiertos:
sudo lsof -nP +L1 # archivos con 0 enlaces que siguen abiertos
El culpable habitual es un archivo de log borrado con rm mientras el servicio seguía escribiendo en él. Truncarlo a través del descriptor de archivo libera el espacio sin reiniciar: : > /proc/<pid>/fd/<n>.
Encontrar archivos
find recorre un árbol y aplica pruebas y acciones a cada entrada. Su lenguaje de expresiones recompensa aprender un puñado de primitivas:
find /var/log -name '*.log' -size +100M # logs grandes
find /etc -type f -mtime -1 # archivos modificados en las últimas 24 h
find /srv/app -type d -name node_modules -prune -o -name '*.js' -print
find /tmp -type f -atime +7 -delete # limpia archivos temporales antiguos
find . -name '*.orig' -exec rm -v {} + # ejecuta rm una sola vez con muchas rutas
find /home -type f -perm -o+w # archivos escribibles por todos: señal de alarma
-mtime -1 significa «modificado hace menos de un día», +7 «hace más de siete días»; la misma convención de signos se aplica a -size. Pon los patrones entre comillas para que el shell no los expanda antes de que find los vea. -exec ... {} + agrupa las rutas en el menor número posible de invocaciones del comando, mientras que \; lo ejecuta una vez por archivo.
Si solo buscas nombres de archivo, locate (paquete plocate o mlocate) responde en milisegundos a partir de un índice que se actualiza cada noche; ejecuta updatedb después de instalarlo. which y type te dicen a qué ejecutable se resuelve un nombre de comando.
Archivar y copiar árboles
tar empaqueta un árbol de directorios en un único archivo, normalmente comprimido:
tar -czf site-2026-09-07.tar.gz -C /var/www example.com # crear, gzip
tar -tzf site-2026-09-07.tar.gz | head # listar el contenido
tar -xzf site-2026-09-07.tar.gz -C /tmp/restore # extraer en otro sitio
tar --zstd -cf app.tar.zst --exclude='*.log' /opt/app # zstd: más rápido, ratio comparable
-C dir cambia de directorio antes de archivar, de modo que el archivo guarda example.com/... en lugar de var/www/example.com/.... Lista siempre el contenido de un archivo de origen desconocido antes de extraerlo: uno creado desde / con rutas absolutas puede sobrescribir archivos del sistema.
Para copiar árboles entre directorios o entre máquinas, rsync -a es mejor que cp y scp: conserva los metadatos, se salta los archivos que no han cambiado y se reanuda tras una interrupción.
rsync -a --delete /srv/data/ backup:/srv/data/ # espejo; barra final = "el contenido de"
Errores comunes
Montar por nombre de dispositivo. /dev/sdb1 en fstab funciona hasta que un disco nuevo desplaza las letras. Usa UUID= o LABEL=.
Confundir cp -r con cp -a. La copia recursiva simple sigue los symlinks, asigna los archivos al usuario que copia y actualiza las marcas de tiempo. Las copias de seguridad y las migraciones necesitan -a.
Guardar datos en /tmp. Puede residir en RAM y es habitual que se vacíe al arrancar o mediante un timer. Usa /var/tmp si los datos deben sobrevivir a un reinicio, o la ubicación adecuada /var/lib/<app> si realmente son estado.
Editar directamente los archivos de los paquetes en /etc. La siguiente actualización puede pedirte que fusiones los cambios o sustituirlos sin avisar. Usa el directorio .d del paquete o un mecanismo de override cuando exista.
Borrar un archivo abierto para liberar espacio. El espacio no se devuelve hasta que el proceso que escribe lo cierra. Mejor trúncalo (: > file) o rota el log como es debido.
Extraer tarballs no fiables como root. Inspecciónalos antes con tar -tf, extráelos en un directorio vacío y nunca extraigas archivos que contengan rutas absolutas o componentes ...
Ideas clave
- Hay un único árbol; los discos, los sistemas de archivos virtuales y los recursos compartidos de red se montan sobre directorios de ese árbol.
- La FHS te dice dónde va cada cosa:
/etcpara la configuración,/varpara los datos que cambian,/usrpara el software instalado,/opty/usr/localpara el software ajeno al gestor de paquetes,/runy/tmppara los archivos efímeros. - Un inodo guarda todo lo relativo a un archivo salvo su nombre; los enlaces duros son nombres adicionales para un mismo inodo, y los symlinks son archivos que contienen una ruta.
lsblk,findmntydfmuestran el almacenamiento;/etc/fstabhace persistentes los montajes y debe referenciar los dispositivos por UUID, connofailen los discos no esenciales.- Entre
du -xh --max-depth,df -iylsof +L1se explican casi todos los incidentes de «disco lleno». findcon-name,-type,-mtime,-sizey-exec ... +sustituye a buena parte de los scripts improvisados.
Fuentes y lecturas recomendadas
Preguntas frecuentes
- ¿Qué diferencia hay entre /usr/local y /opt?
- Ambos contienen software que no procede del gestor de paquetes de la distribución. /usr/local replica la estructura de /usr (bin, lib, share) y está pensado para lo que compilas o instalas tú mismo y debe integrarse en el PATH del sistema. /opt aloja paquetes de terceros autocontenidos que guardan todos sus archivos en un único directorio, como /opt/myapp, lo que permite eliminarlos de una sola vez.
- ¿Por qué no puedo crear un enlace duro a un directorio o a otro disco?
- Un enlace duro no es más que otra entrada de directorio que apunta al mismo inodo, y los números de inodo solo tienen sentido dentro de un sistema de archivos, así que un enlace no puede cruzar un punto de montaje. Los enlaces duros a directorios se rechazan porque permitirían ciclos en el árbol, lo que rompería cualquier herramienta que lo recorra. En ambos casos, usa un enlace simbólico.
- ¿Dónde debe escribir mi aplicación sus datos y sus logs?
- El estado persistente va en /var/lib/<app>, los logs en /var/log/<app> (o en el journal), las cachés que se pueden reconstruir en /var/cache/<app>, y los archivos de ejecución como los ficheros PID o los sockets en /run/<app>. La configuración va en /etc/<app>. Si respetas estas convenciones, las herramientas de copia de seguridad, rotación de logs y monitorización encontrarán tus archivos donde esperan.
- ¿Por qué df dice que el disco está lleno si du no encuentra los archivos?
- Normalmente porque un proceso mantiene abierto un archivo borrado. La entrada de directorio ya no existe, así que du no lo cuenta, pero los bloques no se liberan hasta que se cierra el último descriptor de archivo. Ejecuta lsof +L1 (o lsof -nP | grep deleted) para encontrar el proceso y después reinícialo o trunca el archivo a través de /proc/<pid>/fd.