Ejecutaste rsync. Terminó. Te sentiste poderoso por un instante. Luego todos los servicios empezaron a fallar porque la mitad de tus archivos ahora son propiedad del usuario equivocado,
tienen el modo incorrecto o perdieron sus ACL. La nueva máquina con Debian 13 parece estar bien hasta que intentas arrancar PostgreSQL, recargar nginx o dejar que tu app escriba en su propia caché.
El caos de permisos tras rsync rara vez es “rsync haciendo cosas raras”. Casi siempre somos nosotros dándole instrucciones equivocadas, copiando a través de un límite donde
la identidad cambia (mapeo de UID/GID), o copiando a un sistema de archivos que no puede representar lo que intentas preservar. Este artículo muestra la forma correcta de preservar
la propiedad en Debian 13: qué hacer, qué evitar y cómo demostrar que lo hiciste bien.
El modelo mental: qué es realmente la “propiedad”
En Debian (y Linux en general), un archivo no “pertenece” a un nombre de usuario. Pertenece a un ID numérico de usuario y un ID numérico de grupo. Los nombres son solo etiquetas en
/etc/passwd y /etc/group (o LDAP/SSSD), traducidas en tiempo de visualización. Si copias un archivo propiedad del UID 1001 desde el Host A al Host B,
y UID 1001 es “alice” en el Host A pero “postgres” en el Host B, acabas de asignar ese archivo a “postgres” en el Host B. rsync hizo lo que le pediste; tú hiciste la pregunta equivocada.
La preservación de la propiedad tiene tres capas:
- Bits de modo (rwx para usuario/grupo/otros más setuid/setgid/sticky): se almacenan por inodo; la mayoría de los sistemas de archivos los soportan.
- IDs numéricos de propietario/grupo (uid/gid): se almacenan por inodo; si puedes asignarlos depende de privilegios y opciones de montaje.
- Permisos extendidos (ACL POSIX) y metadatos (xattrs como etiquetas SELinux, capacidades, etiquetas user.*): opcionales y dependientes del sistema de archivos.
rsync puede preservar todo esto, pero solo si se lo dices y si el destino puede representarlo. Si apuntas rsync a un destino que miente (hola, algunas configuraciones de CIFS),
o lo ejecutas sin los privilegios necesarios para establecer la propiedad, obtendrás “éxito” y permisos rotos. No es una paradoja; es un martes.
Guía rápida de diagnóstico
Cuando los permisos “parecen incorrectos” tras rsync, el camino más rápido es determinar qué capa falló: IDs, bits o extras. No adivines. Mide.
1) Primero: confirma qué está mal (IDs vs modos vs ACL/xattr)
- Si la propiedad está mal en general: sospecha desajuste de UID/GID, falta de privilegios o root-squash.
- Si los modos están mal (por ejemplo, todo 755): sospecha umask, falta de
-p/-a, o un destino que normaliza permisos. - Si solo fallan apps específicas (por ejemplo, unidades de systemd, claves ssh, binarios): sospecha xattrs/capabilities perdidas, bits setuid faltantes o ACLs perdidas.
2) Segundo: comprueba el límite de transporte
- Disco local a disco local: lo más sencillo; rsync debería preservar casi todo como root.
- Sobre SSH: depende de rsync remoto y privilegios; root-to-root funciona si está configurado; de lo contrario verás degradaciones silenciosas.
- NFS: root-squash puede arruinar “preservar propiedad” sin avisarte de forma evidente para tu cerebro cansado.
- CIFS/SMB: la semántica de permisos puede ser emulada; la preservación puede ser imposible o mapeada.
3) Tercero: reproduce con un solo archivo con verbosidad máxima
Elige un archivo con propietario/modo/ACL/xattr conocidos, rsyncéalo con -vv e inspecciónalo en ambos extremos. Buscas la clase exacta de metadatos que
falló al transferirse.
Idea parafraseada de Gene Kim (autor de operaciones DevOps): “La confiabilidad viene de hacer el trabajo visible y repetible, no de heroicidades a las 2 a.m.”
Hechos y contexto histórico (por qué esto sigue ocurriendo)
- UID/GID son la fuente de la verdad. Los nombres de usuario son azúcar de lectura; rsync puede preservar IDs incluso si el nombre no existe—si se lo pides.
- “archive mode” de rsync es un paquete.
-aes un atajo para varias banderas, pero no incluye todo lo que la gente asume. - Las ACL POSIX existen desde hace mucho. Estuvieron en Unix empresarial durante décadas y llegaron a Linux como ciudadanos de primera clase, pero a menudo se olvidan en migraciones.
- Las capacidades de Linux se almacenan en xattrs. Si pierdes xattrs, un binario con
cap_net_bind_servicepodría dejar de enlazar al puerto 80 sin ser setuid root. - Root-squash de NFS es hostil a “preservar propiedad”. Es una medida de seguridad que mapea root a nobody, rompiendo esquemas ingenuos de backup/restore.
- Los hard links no se “copian” a menos que los preserves. Sin
-H, rsync puede duplicar archivos enlazados, inflando el uso de disco y cambiando la semántica de algunos árboles gestionados por paquetes. - El sticky bit y los directorios setgid importan para rutas de escritura compartida. Copiar mal los bits de modo en lugares como
/tmpo directorios de grupo compartido puede convertirse en un problema de seguridad, no solo en una caída. - Las etiquetas SELinux y metadatos de AppArmor viven fuera de los bits de modo clásicos. Incluso en Debian (frecuentemente con AppArmor), los xattrs pueden importar para runtimes de contenedores, entornos tipo snap o configuraciones LSM personalizadas.
- Algunos sistemas de archivos no pueden representar los metadatos que quieres. FAT y exFAT son los obvios, pero los montajes CIFS pueden ser “unixy” o “no unixy” según las opciones.
Qué preserva rsync (y qué no)
La primera mentira que nos contamos es: “Usé -a, así que todo es igual.” Archive mode es excelente, pero no es “cada bit de metadatos del universo.” Es:
-rrecursión-lpreservar symlinks-ppreservar permisos (bits de modo)-tpreservar tiempos-gpreservar grupo-opreservar propietario (requiere root)-Dpreservar dispositivos y especiales (requiere root)
Lo que -a no incluye automáticamente:
- ACLs a menos que añadas
-A - xattrs a menos que añadas
-X - hard links a menos que añadas
-H(y sí, esto puede ser costoso) - preservación de IDs numéricos entre servicios de nombres distintos a menos que añadas
--numeric-ids
Ese es el núcleo: si te importa la propiedad, te importa la identidad numérica. Si te importa que “la app siga funcionando”, te importan las ACLs, los xattrs y a veces las capabilities.
Broma #1: rsync no “pierde permisos.” Sigue instrucciones con la confianza de un becario que nunca pide aclaraciones.
Líneas de comando limpias para migraciones en Debian 13
Aquí tienes valores predeterminados con opinión que se comportan bien en migraciones reales. Ajusta deliberadamente. Si no puedes explicar por qué eliminaste una bandera, mantenla.
Copiado local a local (misma máquina, distintos discos)
Si estás copiando dentro de un mismo host (o hacia un sistema de archivos montado donde tienes privilegios root reales), esta es la línea base limpia:
cr0x@server:~$ sudo rsync -aHAX --numeric-ids --info=stats2,progress2 /src/ /dst/
...output...
Por qué este conjunto:
-a: preservar metadatos principales-H: preservar hard links (útil para algunos árboles del sistema, capas de contenedores, caches de paquetes)-A: preservar ACLs-X: preservar xattrs (capabilities, etiquetas, metadatos personalizados)--numeric-ids: preservar UID/GID numéricos, no nombres (crítico entre hosts)
Sobre SSH, root a root (preferido para migraciones de fidelidad completa)
cr0x@server:~$ sudo rsync -aHAX --numeric-ids --info=stats2,progress2 -e "ssh -o BatchMode=yes" /src/ root@newhost:/dst/
...output...
Si el SSH de root está deshabilitado (común y no inherentemente malo), usa una cuenta de automatización más sudo en el destino y ejecuta rsync en modo servidor. Eso se vuelve matizado.
Para la mayoría de equipos, la mejor opción es: copiar como root sobre SSH desde una red de gestión permitida, y luego cerrar la puerta de nuevo.
Cuando no puedes ser root (y aún quieres resultados sensatos)
Si eres no privilegiado, no puedes establecer propietarios arbitrarios. rsync preservará lo que pueda. No finjas que estás haciendo una migración fiel; trátalo como una copia de datos
donde la propiedad debe reasignarse después.
cr0x@server:~$ rsync -aAX --info=stats2,progress2 /src/ user@newhost:/dst/
...output...
Nota: -o y -g dentro de -a no tendrán éxito de la forma que deseas sin privilegios. rsync seguirá ejecutándose. Simplemente no hará milagros.
Cuando el destino es NFS (maneja root-squash como adulto)
Si la exportación NFS usa root-squash (a menudo por defecto), root en el cliente no puede establecer propiedad. Tienes tres opciones limpias:
- Exportar temporalmente con
no_root_squashdesde un host restringido para la ventana de migración (revisado en seguridad, con tiempo acotado). - Migrar a disco local en el servidor de destino y luego mover datos del lado del servidor en el host NFS (preservando la propiedad localmente).
- Aceptar que no puedes preservar la propiedad y planear un chown/chgrp/reaplicación de ACL controlada.
Tareas prácticas: comandos, salidas, decisiones
No corriges permisos entrecerrando los ojos ante ls -l y esperando. Corriges permisos preguntándole al sistema y dejando que las respuestas guíen el siguiente paso.
Aquí hay tareas prácticas que realmente ejecuto durante migraciones y respuesta a incidentes.
Tarea 1: Confirma versión de rsync y características compiladas (soporte ACL/xattr)
cr0x@server:~$ rsync --version
rsync version 3.2.7 protocol version 32
Capabilities:
64-bit files, 64-bit inums, 64-bit timestamps, ACLs, xattrs, iconv, symtimes
...output...
Qué significa: Buscas ACLs y xattrs en capabilities. Si faltan, banderas como -A y -X no harán lo que crees.
Decisión: Si no hay soporte para ACLs/xattrs, actualiza rsync o cambia de método (tar con xattrs, replicación por snapshot del sistema de archivos, etc.).
Tarea 2: Inspecciona el metadata completo de un archivo problemático (modo, UID/GID, ACL)
cr0x@server:~$ sudo stat -c '%n mode=%a uid=%u(%U) gid=%g(%G)' /dst/app/config.yml
/dst/app/config.yml mode=640 uid=1001(alice) gid=1001(alice)
Qué significa: Los IDs numéricos son la verdad; los nombres entre paréntesis son interpretación local. Si el UID es “correcto” pero el nombre está “mal”,
tienes un problema de mapeo, no de copia.
Decisión: Si los UID/GID difieren de las expectativas del origen, detente y arregla el mapeo de identidad antes de copiar más.
Tarea 3: Comprueba que existan ACLs y compara acceso esperado
cr0x@server:~$ sudo getfacl -p /dst/app
# file: /dst/app
# owner: 1001
# group: 1001
user::rwx
group::r-x
group:33:r-x
mask::r-x
other::---
Qué significa: El directorio concede lectura/ejecución al grupo 33 (a menudo www-data). Si esta ACL desapareció, tu servicio web no podrá leer
el árbol de la app aunque los bits de modo “parezcan correctos.”
Decisión: Si faltan ACLs donde las esperas, debes volver a ejecutar rsync con -A y asegurarte de que el sistema de archivos destino soporte
ACLs y que estén habilitadas.
Tarea 4: Comprueba xattrs en un archivo que pueda llevar capacidades o etiquetas
cr0x@server:~$ sudo getfattr -d -m- /dst/usr/local/bin/myhelper
# file: /dst/usr/local/bin/myhelper
security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=
Qué significa: El binario tiene capabilities de Linux almacenadas en un xattr. Si pierdes eso, puedes obtener un “permission denied” misterioso en operaciones privilegiadas sin cambios de propiedad.
Decisión: Si faltan xattrs, vuelve a copiar con -X. Si el sistema de archivos destino no puede almacenar xattrs, necesitas otro destino.
Tarea 5: Valida que rsync realmente se ejecute como root en ambos extremos
cr0x@server:~$ sudo rsync -a --rsync-path="id && rsync" /src/ root@newhost:/dst/ 2>/dev/null | head
uid=0(root) gid=0(root) groups=0(root)
Qué significa: El lado remoto imprimió su identidad antes de ejecutar rsync. Si ves un UID no root, la preservación de propiedad será limitada.
Decisión: Si el remoto no es root, arregla el enfoque SSH/sudo o acepta una estrategia de chown posterior a la copia.
Tarea 6: Detecta desajuste de UID/GID entre hosts para una cuenta de servicio específica
cr0x@server:~$ getent passwd www-data
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
cr0x@server:~$ ssh root@newhost getent passwd www-data
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
Qué significa: Bien: UID/GID consistentes para www-data. Pero no te quedes aquí; los usuarios de tu app suelen ser cuentas personalizadas, no defaults de Debian.
Decisión: Si los IDs no coinciden, alinéalos (preferible antes de copiar) o usa --numeric-ids y arregla el servicio de nombres después.
Tarea 7: Inventario de propietarios numéricos “desconocidos” en el destino
cr0x@server:~$ sudo find /dst -xdev -printf '%u %g %p\n' | awk '$1 ~ /^[0-9]+$/ || $2 ~ /^[0-9]+$/' | head
1001 1001 /dst/app
1001 1001 /dst/app/config.yml
Qué significa: Propietarios numéricos sin resolución de nombres. Eso no es inherentemente erróneo: puede ser preservación numérica correcta con definiciones de cuentas faltantes.
Decisión: Si aparecen muchos IDs numéricos, alinea /etc/passwd//etc/group (o LDAP/SSSD) antes de dejar que los servicios se ejecuten.
Tarea 8: Confirma que las opciones de montaje permiten permisos POSIX y ACLs
cr0x@server:~$ mount | grep " on /dst "
/dev/sdb1 on /dst type ext4 (rw,relatime,acl)
Qué significa: ext4 montado con soporte acl. En algunas configuraciones las ACLs están habilitadas por defecto; en otras, la opción de montaje importa.
Decisión: Si no ves acl y las ACLs no se comportan, vuelve a montar con ACL habilitado o ajusta los valores por defecto del sistema de archivos.
Tarea 9: Detecta root-squash en un montaje NFS de la manera difícil (probando)
cr0x@server:~$ sudo touch /dst/.rootsquash-test && sudo chown 0:0 /dst/.rootsquash-test; ls -ln /dst/.rootsquash-test
-rw-r--r-- 1 65534 65534 0 Dec 29 12:00 /dst/.rootsquash-test
Qué significa: UID/GID se convirtieron en 65534 (nobody/nogroup). Eso es comportamiento clásico de root-squash.
Decisión: Deja de intentar preservar la propiedad sobre este montaje. Cambia la política de exportación temporalmente o copia desde el servidor.
Tarea 10: Dry-run de rsync con cambios itemizados para ver qué metadata cambiaría
cr0x@server:~$ sudo rsync -aHAX --numeric-ids -n -i /src/ /dst/ | head
.d..t...... ./
>f..tpogax app/config.yml
>f..t...... app/static/logo.png
Qué significa: La salida itemizada codifica cambios. En >f..tpogax, las letras muestran qué se actualizará: tiempo (t),
permisos (p), propietario (o), grupo (g), ACL (a), xattr (x).
Decisión: Si ves muchas o/g que no esperabas, tu propiedad no está alineada; arréglala antes de ejecutar.
Tarea 11: Confirma que un árbol de directorios tiene setgid/sticky donde corresponde
cr0x@server:~$ sudo find /dst/shared -maxdepth 1 -type d -printf '%m %p\n'
2775 /dst/shared
2775 /dst/shared/team-a
2770 /dst/shared/private
Qué significa: 2 en el dígito inicial indica setgid en directorios (herencia de grupo). Si esto cambió a 0775,
los archivos nuevos pueden acabar en el grupo equivocado, causando fallos silenciosos de acceso.
Decisión: Si faltan setgid/sticky, vuelve a copiar con permisos preservados, o corrígelos explícitamente y reaudita.
Tarea 12: Verifica que los “archivos especiales” (dispositivos, sockets) no se hayan estropeado
cr0x@server:~$ sudo find /dst/dev -maxdepth 1 -type c -o -type b | head
/dst/dev/null
/dst/dev/zero
/dst/dev/random
Qué significa: Los nodos de dispositivo existen. Si copiaste una imagen del sistema o chroot y estos se convirtieron en archivos regulares, algo salió muy mal (probablemente
falta de privilegios root u omisión de -D).
Decisión: Para árboles del sistema, siempre copia como root con -a. Si los dispositivos están mal, reconstrúyelos (o recópialos correctamente) antes de arrancar
o chrootear.
Tarea 13: Comprueba el síntoma “todo propiedad del usuario que ejecutó rsync”
cr0x@server:~$ sudo find /dst -xdev -printf '%u\n' | sort | uniq -c | sort -nr | head
152340 backup
2193 root
812 www-data
Qué significa: La mayoría de archivos son propiedad de backup. Normalmente significa que la copia se ejecutó sin privilegios, o el destino rechazó chown.
Decisión: Si necesitas fidelidad, rehace la copia con privilegios adecuados y un destino que permita cambios de propiedad. No intentes “arreglarlo luego”
a menos que tengas un mapeo determinista.
Tarea 14: Compara propiedad de origen y destino para una muestra rápidamente
cr0x@server:~$ sudo (cd /src && find . -maxdepth 2 -type f -printf '%u:%g %m %p\n' | head) > /tmp/src.sample
cr0x@server:~$ sudo (cd /dst && find . -maxdepth 2 -type f -printf '%u:%g %m %p\n' | head) > /tmp/dst.sample
cr0x@server:~$ diff -u /tmp/src.sample /tmp/dst.sample
--- /tmp/src.sample
+++ /tmp/dst.sample
@@
-alice:alice 640 ./app/config.yml
+postgres:postgres 640 ./app/config.yml
Qué significa: Mismo modo, distinta propiedad. El archivo es legible, pero por la identidad equivocada. Esto es o un desajuste de UID o un mapeo por nombre.
Decisión: Usa --numeric-ids (o alinea cuentas) y rehace la copia, o comprométete a una reescritura planificada de la propiedad.
Desajuste de UID/GID: el asesino silencioso de permisos
Debian 13 no inventó el desajuste de UID/GID, pero es un momento común porque las actualizaciones/migraciones suelen coincidir con cambios en servicios de directorio, adopción de contenedores o “dejamos los usuarios para más tarde.” Más tarde es como obtienes incidentes.
Modo de fallo típico: en el host antiguo, tu usuario de app es UID 1005. En el host nuevo, UID 1005 pertenece a otra cuenta de servicio creada antes. Haces rsync “preservando propiedad.” Ahora los secretos de tu app pertenecen a algún demonio no relacionado. La app no arranca, y además creaste una fuga de privilegios accidental.
Qué hacer en su lugar (con opinión y aburrido)
- Antes de copiar, asegúrate de que el destino tenga las mismas asignaciones UID/GID para las cuentas de servicio que poseen datos.
- Usa
--numeric-idspara que rsync no intente ser inteligente con el mapeo por nombres. - Si dependes de LDAP/SSSD, valida que esté disponible en el destino antes de empezar la copia. Una solución temporal a usuarios locales puede crear desajustes.
Cuando no puedes alinear IDs
A veces heredas un lío: el entorno nuevo usa identidad centralizada y el antiguo fue hecho a mano. En ese caso, no trates la “preservación de propiedad” como religión. Trátalo como una transformación controlada:
- Primero copia los datos con integridad (contenido y marcas de tiempo).
- Luego aplica la política de propiedad/ACL de forma determinista (scripts, manifiestos o herramientas de la app).
- Finalmente ejecuta una auditoría de permisos y arranca servicios bajo supervisión.
ACL y xattrs: preservando los permisos “invisibles”
Los bits de modo son el primer 80% de los permisos. ACLs y xattrs son el último 20% que causa el 80% de los incidentes.
ACLs: la trampa “¿por qué www-data no puede leerlo?”
Las ACLs se usan comúnmente para dar a un grupo de servicio acceso de lectura a directorios propiedad de otra cuenta, o para permitir que desarrolladores desplieguen sin hacer todo el árbol escribible por el grupo.
Si las pierdes, ls -l no confesará. Puede que veas un + en algunas salidas, pero la gente lo ignora como ignora las luces de check engine.
Preserva ACLs con -A. Luego verifica con getfacl en algunas rutas conocidas. Si estás migrando servidores de aplicaciones, presta especial atención a:
- directorios de subida compartidos
- directorios de despliegue con propiedad mixta
- rutas donde un usuario de servicio necesita acceso pero no debería poseer los archivos
xattrs: capabilities, etiquetas y el efecto “pero ayer funcionaba”
Los atributos extendidos se usan para todo, desde contextos SELinux a metadatos definidos por el usuario y capacidades. En Debian, las capabilities son la parte importante en producción: permiten que un binario enlace puertos bajos o haga networking crudo sin ejecutar como root.
Preserva xattrs con -X. Luego comprueba un binario o archivo conocido que esperas que lleve xattrs. Si no se preservan, los síntomas pueden ser extraños:
servicios que fallan al bindear, contenedores que no arrancan o herramientas de seguridad que se comportan distinto.
Fronteras de sistemas de archivos: ext4 vs XFS vs ZFS vs NFS vs CIFS
rsync solo puede preservar lo que el sistema de archivos destino puede almacenar y lo que las opciones de montaje permiten establecer. La forma más fácil de provocar “caos de permisos” es copiar desde un sistema Unix a algo que solo finge ser uno.
Sistemas de archivos Linux locales (ext4, XFS)
Generalmente seguros para bits de modo, propiedad, ACLs y xattrs. Vigila las opciones de montaje. También vigila si copias a un sistema con comportamiento por defecto de ACL distinto.
ZFS en Linux
ZFS soporta permisos, ACLs y xattrs, pero el modo de ACL puede diferir (POSIX vs NFSv4 ACL). Si ves traducción extraña de ACL, confirma propiedades del dataset y cómo tu tooling espera las ACL. rsync puede preservar ACLs, pero si el modelo subyacente difiere, “preservado” puede no significar “equivalente.”
NFS
NFS es fantástico hasta que quieres hacer operaciones Unix de propiedad desde un cliente como root y el servidor dice “absolutamente no.” Eso es root-squash. Es normal.
Planea para ello en vez de pelearte.
CIFS/SMB
Los montajes CIFS pueden mapear propiedad y permisos según opciones de montaje y capacidades del servidor. Algunas configuraciones pueden almacenar bits de modo Unix; otras mapean todo a un único UID/GID. Si tu destino es CIFS y necesitas semántica Unix real, prueba con un pequeño conjunto de archivos antes de migrar algo serio.
Broma #2: los permisos CIFS son como las cafeteras de oficina—alguien jura que está configurada correctamente, y luego hace lodo.
Tres microhistorias corporativas desde las trincheras
Microhistoria 1: El incidente causado por una suposición equivocada
Un equipo migró una flota de servidores de aplicaciones Debian a hardware nuevo. El plan era limpio: construir Debian 13, rsync los árboles de la app, volcar el balanceador de carga.
Usaron rsync -a y una cuenta no root “deploy” porque SSH root estaba prohibido (política razonable). La migración terminó antes de tiempo. Todos se fueron a almorzar con esa sensación inquietante que ignoras cuando el gráfico está verde.
Los primeros reportes de error fueron sobre “403 aleatorios” y “subidas fallidas.” Reinstalaron un servidor, igual. Volvieron al pool antiguo, todo bien. De nuevo al nuevo, roto. La gente discutía sobre rutas de red y reglas de firewall porque eso es lo que se hace cuando no quieres pensar en permisos de archivos.
El problema real: las ACLs se usaban en los servidores antiguos para dar al grupo worker web acceso a un árbol de directorios propiedad de otra cuenta de servicio. El usuario deploy podía leer los archivos, así que rsync copió el contenido bien, pero no preservó las ACLs porque no se usó -A. Los bits de modo parecían similares. Las ACLs faltantes solo importaron cuando el servicio web intentó escribir nuevos objetos.
Arreglarlo no fue heroico. Volvieron a ejecutar rsync con -aA (y luego -X por completitud) usando un flujo sudo controlado en el destino. Luego añadieron una comprobación de verificación de ACL al runbook de migración: elegir tres directorios con uso intensivo de ACL, comparar la salida de getfacl, fallar la migración si no coinciden.
La suposición equivocada fue simple: “archive mode significa todo.” Archive mode significa “mucho,” no “todo.”
Microhistoria 2: La optimización que salió mal
Otra organización tenía una gran canalización de medios moviendo datos entre servidores cada noche. Querían acelerar una ventana lenta de rsync, así que eliminaron banderas “costosas” y activaron opciones agresivas. Alguien propuso: quitar -H y -X, y añadir --inplace y --no-owner porque “la propiedad no importa para archivos multimedia.” Benchmarkó más rápido en un dataset de laboratorio tranquilo. El cambio se hizo en producción.
Dos semanas después, el uso de disco en el destino creció inesperadamente. No fue un simple “necesitamos más almacenamiento”; los jobs empezaron a fallar a mitad de ejecución por volúmenes llenos, lo que se tradujo en colas atrasadas. Operaciones pasó una noche borrando directorios temporales y reejecutando jobs. El postmortem inicialmente culpó a “crecimiento inesperado de entrada.” Eso era reconfortante y equivocado.
La causa raíz fueron los hard links. Algunos árboles origen usaban hard linking para desduplicar payloads idénticos generados por etapas anteriores. Eliminar -H hizo que rsync copiara cada archivo enlazado como archivo independiente, multiplicando el espacio. El cambio de banderas de propiedad también eliminó una comprobación sutil de seguridad: algunos directorios estaban protegidos por reglas de propiedad de grupo y setgid; aplanar la propiedad hizo que jobs posteriores escribieran donde no debían, produciendo “éxitos” con salidas mal ubicadas.
Revirtieron la “optimización”, luego rehicieron la canalización correctamente: mantuvieron -H donde el dataset lo usa, mantuvieron -X para herramientas con capabilities, y enfocaron el trabajo de rendimiento en patrones de I/O (batching, evitar rescaneos innecesarios) en vez de quitar banderas de corrección. Rápido y equivocado sigue siendo equivocado; solo falla con confianza.
Microhistoria 3: La práctica aburrida pero correcta que salvó el día
Un tercer equipo hizo una migración Debian 13 para un monolito legacy. La app era lo bastante vieja para tener opiniones sobre modos de archivo, y el árbol de despliegue tenía mezcla de directorios setgid, algunas concesiones ACL raras, y un binario con capabilities para poder bindear un puerto bajo sin root. El líder del equipo era terco con el proceso:
comprobaciones previas, dry-runs y una copia canaria pequeña antes de tocar el dataset principal.
Empezaron por la identidad: aseguraron que las cuentas de servicio tuvieran UID/GID coincidentes entre servidores antiguos y nuevos. No “mismo nombre”, mismos números. Verificaron disponibilidad de LDAP/SSSD. Luego ejecutaron rsync en dry-run con salida itemizada y guardaron la salida en un ticket. Fue tedioso. También era el punto.
Durante la canaria notaron un puñado de archivos que perderían xattrs. El destino era un montaje NFS con root-squash. Nadie lo había mencionado porque era “solo almacenamiento.” Ese detalle habría roto todo el corte: binarios perderían capabilities y algunos directorios quedarían en propiedad de nobody. Al detectarlo temprano, cambiaron el plan: stage de datos primero en disco local, luego mover datos server-side dentro del host de almacenamiento donde la propiedad podía preservarse.
El día del cutover fue aburrido. Los servicios arrancaron. El monitor se mantuvo en silencio. La victoria no fue genio; fue negarse a saltarse las comprobaciones aburridas que atrapan problemas de permisos antes que los clientes.
Errores comunes: síntoma → causa raíz → solución
-
Síntoma: Todo en el destino es propiedad del usuario que ejecutó rsync.
Causa raíz: rsync se ejecutó sin privilegios, o el destino rechazóchown(root-squash, mapeo CIFS).
Solución: Ejecuta rsync como root de extremo a extremo en un sistema de archivos que soporte propiedad; o acepta una reaplicación de chown/ACL basada en políticas después de la copia. -
Síntoma: Los propietarios parecen correctos por nombre, pero los servicios aún fallan con “permission denied.”
Causa raíz: ACLs o xattrs perdidas; los bits de modo solos no bastan.
Solución: Reejecuta con-Ay-X; verifica congetfaclygetfattr. -
Síntoma: Los archivos muestran modos correctos, pero la propiedad está asignada a la cuenta local equivocada.
Causa raíz: Desajuste de UID/GID entre hosts; rsync mapeó por nombre sin preservar IDs numéricos, o el destino resuelve nombres diferente.
Solución: Alinea UID/GID antes de la migración; usa--numeric-ids; valida constatygetent. -
Síntoma: La app web puede leer archivos pero no puede escribir uploads o cachés tras la migración.
Causa raíz: Bits setgid/sticky faltantes o ACLs por defecto de directorio que conceden escritura al grupo de servicio.
Solución: Preserva permisos y ACLs; reaplica ACLs por defecto; valida congetfaclen directorios. -
Síntoma: Un binario que antes podía bindear en puerto 80 ahora falla a menos que se ejecute como root.
Causa raíz: xattr de capability perdida (security.capability).
Solución: Re-copia con-X, o reaplica capabilities usandosetcapy luego asegura que futuras migraciones preserven xattrs. -
Síntoma: Uso de disco explotó tras la migración; árboles “idénticos” consumen mucho más espacio.
Causa raíz: Hard links no preservados porque se omitió-H.
Solución: Reejecuta con-Hpara datasets que usan hard links; considera si el coste es aceptable y prueba en un subconjunto. -
Síntoma: rsync reporta éxito, pero archivos especiales/dispositivos están mal (o faltan).
Causa raíz: La copia no se ejecutó como root o no preservó especiales (-Dvía-a), o el sistema de archivos destino no puede almacenarlos.
Solución: Usa root + archive mode sobre un sistema de archivos compatible; para imágenes de sistema, considera migración basada en snapshots en su lugar. -
Síntoma: Algunos directorios son escribibles por “other” tras la migración.
Causa raíz: Alguien usó--chmodde forma amplia o se copió a través de un montaje que normaliza permisos; o se arregló un síntoma aflojando todo.
Solución: Deshaz el chmod amplio. Restaura desde origen con banderas de preservación apropiadas. Audita confinden busca de rutas world-writable.
Listas de verificación / plan paso a paso
Plan A: Migración de fidelidad completa (preferido)
- Confirma alineación de identidades: cuentas y grupos de servicio tienen UID/GID consistentes entre origen y destino. Si usas LDAP/SSSD, verifica que funcione en el destino.
- Valida semántica del sistema de archivos destino: preferible sistema de archivos Linux local. Evita CIFS para árboles críticos con permisos Unix. Trata root-squash de NFS como una restricción dura.
- Elige un directorio canario: incluye un archivo con ACLs y un binario con xattrs/capabilities si aplica.
-
Dry-run de rsync con
-n -iy guarda la salida itemizada. Busca cambios de owner/group/ACL/xattr. -
Rsync real:
sudo rsync -aHAX --numeric-ids --info=stats2,progress2. -
Verifica: muestrea con
stat,getfacl,getfattr. Ejecuta una prueba de humo de la app que toque rutas de escritura. - Sync final: vuelve a ejecutar rsync para captar deltas justo antes del cutover (mismas banderas).
- Cutover: inicia servicios; monitorea logs por errores relacionados con permisos; mantiene los datos antiguos en solo lectura hasta tener alta confianza.
Plan B: Transformación controlada (cuando los IDs no pueden coincidir)
- Copia el contenido con timestamps: usa rsync pero no finjas que la propiedad coincidirá.
- Aplica la política de propiedad:
chown/chgrpexplícitos y scripts de ACL por directorio. - Valida con una auditoría: revisa propietarios numéricos, archivos world-writable inesperados y ACLs faltantes esperadas.
- Documenta el mapeo para que la próxima migración no sea arqueología.
Plan C: Destino NFS con root-squash (opciones pragmáticas)
- Prefiere staging a disco local en el host destino, preservando la propiedad allí.
- Luego mueve los datos del lado del servidor (en el servidor NFS) hacia la ruta exportada, donde puede preservarse la propiedad localmente.
- Si debes copiar directamente a NFS: acepta que la preservación de propiedad puede ser imposible y trátalo como un trabajo de repropiedad.
Preguntas frecuentes (FAQ)
1) ¿rsync -a preserva la propiedad?
Incluye -o y -g, pero solo preserva verdaderamente la propiedad si rsync tiene privilegios suficientes para establecer uid/gid en el destino. Sobre SSH,
eso típicamente significa root en el lado remoto también.
2) ¿Por qué necesito --numeric-ids?
Porque los nombres pueden mapear a diferentes IDs numéricos en distintos hosts. --numeric-ids le dice a rsync que preserve los números exactamente, evitando el mapeo “útil”
por nombres que puede reasignar la propiedad silenciosamente.
3) Ejecuté como root, pero la propiedad sigue mal. ¿Cómo?
Causas comunes: el destino es NFS con root-squash; el destino es CIFS con mapeo forzado de uid/gid; o copiaste en un sistema de archivos/montaje que rechaza chown.
Prueba con un chown manual en la ruta destino.
4) ¿Qué flags preservan ACLs y xattrs?
-A preserva ACLs. -X preserva atributos extendidos. Si te importa que “las apps sigan funcionando”, normalmente quieres ambos.
5) ¿Debería siempre usar -H?
No siempre. -H puede aumentar uso de memoria y tiempo de ejecución, porque rsync debe rastrear relaciones de hard link. Úsalo cuando tu dataset use hard links
(algunos árboles del sistema, contenido desduplicado, ciertos caches de paquetes) y te importe preservarlos.
6) ¿Puedo preservar propiedad copiando como usuario no root?
No en el caso general. Un usuario no root solo puede establecer propiedad a sí mismo (y a veces grupos a los que pertenece). Si necesitas fidelidad de propiedad, usa root o un
flujo de trabajo privilegiado controlado.
7) ¿Por qué los permisos parecen bien pero los servicios systemd fallan?
Los servicios pueden fallar por capabilities perdidas en binarios (xattrs), pérdida de acceso a directorios runtime por ACLs perdidas, o propiedad equivocada en directorios de estado bajo
/var. Revisa getfattr para capabilities y getfacl para directorios.
8) ¿Es seguro “arreglar todo” con chmod -R 777 o un chown -R amplio?
Es rápido, “funciona” y es la forma de convertir una migración en un incidente de seguridad. Si necesitas reescribir propiedad, hazlo con un plan mapeado y audita el resultado.
9) ¿Cuál es la forma más rápida de probar que origen y destino coinciden?
Usa rsync en dry-run con salida itemizada (-n -i) y fíjate en los marcadores p, o, g, a y x.
Luego valida una muestra con stat, getfacl y getfattr.
10) Estoy copiando a un sistema de archivos que no soporta propiedad Unix. ¿Ahora qué?
Entonces no puedes “preservar propiedad” de forma significativa. O cambias el destino (preferible), o aceptas que los permisos se representarán de forma distinta
y ejerces control de acceso mediante el modelo de ese sistema en vez de fingir que es POSIX.
Conclusión: próximos pasos que puedes ejecutar
Si quieres que las migraciones a Debian 13 sean aburridas, deja de tratar los permisos como un efecto secundario. Trátalos como datos primarios. La propiedad son IDs numéricos, no nombres.
Las ACLs y xattrs no son opcionales cuando mueves sistemas de producción reales. Y las fronteras de sistemas de archivos son donde las buenas intenciones van a morir.
Pasos prácticos siguientes:
- Elige un directorio problemático y ejecuta comprobaciones canarias:
stat,getfacl,getfattr. - Ejecuta un dry-run de rsync con
-aHAX --numeric-ids -n -iy lee las letras como si fueran un contrato. - Confirma la alineación UID/GID para tus cuentas de servicio con
getenten ambos hosts. - Si apuntas a NFS/CIFS, prueba establecer propiedad con un solo archivo antes de empezar la migración. Si no puede chown, no puede preservar propiedad—discutir no ayuda.
- Luego haz la copia real con el conjunto de banderas de fidelidad completa y verifica antes del cutover.