zfs send y zfs receive son el momento en el que los snapshots dejan de ser solo una foto local y se convierten en algo que puedes mover. ZFS coge un snapshot, lo transforma en un stream y ese stream lo puedes guardar en un archivo, comprimir, pasar por SSH o recibir en otro pool. Es una idea muy limpia. También es una herramienta con la que puedes hacer bastante daño si escribes el destino mal.
En Proxmox lo veo útil para datasets concretos. Plantillas, datos de contenedores, carpetas auxiliares, datasets de aplicación y algún volumen que quiero mover con cuidado. No lo uso como reemplazo universal de Proxmox Backup Server. PBS sigue siendo mi opción preferida para backups de VMs y contenedores gestionados desde Proxmox. Pero cuando tengo ZFS debajo y quiero replicar un dataset como ZFS manda, send y receive son una maravilla.
La idea mínima es esta.
| |
Ese comando parece inocente, pero toca dos sistemas y escribe en destino. Antes de ejecutarlo de verdad, suelo hacer una prueba seca para ver tamaño estimado.
| |
La opción -n no envía. -P muestra información parseable. -v da más detalle. Me sirve para detectar si voy a mandar 4 GB o 400 GB antes de quedarme mirando una terminal con cara de idiota.
la captura de este post#
La captura usa una salida saneada. No hay IPs reales, nombres internos ni dominios privados. Enseña el flujo que más uso: snapshot completo inicial y después incremental.

Esta es la salida saneada que usé para generar la captura:
| |
El primer envío es completo. El segundo es incremental. Esa diferencia es la gracia del asunto. Si ya existe el snapshot base en destino, no necesito reenviar todo el dataset. Solo mando lo que cambió entre lunes-0800 y lunes-1500.
qué problema me resuelve#
Hay veces en las que quiero mover un dataset conservando su historia y sus propiedades, no copiar ficheros con rsync como si todo fuera una carpeta cualquiera. rsync me gusta mucho, pero trabaja a nivel de archivo. ZFS tiene su propio modelo, con snapshots, propiedades y bloques. Si el origen y el destino son ZFS, muchas veces prefiero hablar en idioma ZFS.
Un caso típico: tengo un dataset de plantillas en un nodo Proxmox y quiero replicarlo a otro servidor para tener una copia utilizable. No necesito meterlo en un tar, copiarlo, extraerlo y cruzar los dedos. Creo snapshot, envío, recibo.
Otro caso: quiero preparar una migración. Antes de mover servicios, replico datasets grandes con un envío completo. Luego, cuando llega el momento del cambio, hago un incremental pequeño. La ventana de parada baja muchísimo porque el trabajo gordo ya está hecho.
También lo uso para pruebas. Si quiero montar un dataset en otro servidor y verificar una actualización sin tocar producción, puedo clonar el estado a un entorno aparte. No siempre merece la pena, pero cuando los datos pesan, se agradece.
completo frente a incremental#
El envío completo manda el snapshot entero.
| |
Para que un incremental funcione, origen y destino tienen que compartir un snapshot base. Si el destino no tiene @lunes-0800, no puedes mandarle solo lo cambiado desde ese punto. ZFS necesita una referencia común.
El incremental básico es este.
| |
Lo leo así: manda la diferencia entre el snapshot de las 08:00 y el de las 15:00. En destino, aplica esa diferencia sobre el dataset que ya tenía el snapshot de las 08:00.
Si esto parece delicado es porque lo es. No complicado, pero sí delicado. Los nombres importan. El orden importa. Que el destino tenga la base correcta importa. La primera vez que lo haces en serio conviene practicar con un dataset de juguete.
mi rutina antes de enviar nada#
Nunca empiezo por el comando destructivo. Primero miro origen.
| |
Luego pruebo el envío.
| |
Después miro destino. En el servidor receptor quiero saber si el dataset existe, si tiene snapshots y si el nombre no pisa algo que me importe.
| |
Si el destino no existe, perfecto. Si existe y tiene datos, paro. No uso -F por costumbre. -F fuerza rollback en destino si hace falta para recibir el stream. Es útil, pero también puede descartar cambios locales del destino. Me parece una opción razonable para réplicas gestionadas donde el destino no se toca a mano. Me parece una mala idea si alguien usa ese dataset receptor para pruebas.
Cuando todo encaja, ejecuto.
| |
Y al terminar verifico.
| |
No celebro antes de verificar. Eso aplica a ZFS y a casi todo lo que lleva almacenamiento en el nombre.
por qué uso SSH aunque no sea lo más elegante#
Para un homelab, SSH es suficiente en muchísimos casos. Ya tengo claves, ya tengo red, ya tengo logs razonables y no tengo que montar un sistema nuevo solo para mover un dataset puntual.
El patrón es fácil de leer.
| |
Si quiero comprimir en medio, puedo meter zstd.
| |
Esto puede ayudar si la red es más lenta que la CPU disponible. Si la red va sobrada y la CPU va justa, igual no compensa. No hay dogma. Se prueba con datos reales.
También puedo limitar ancho de banda con pv si no quiero saturar una red compartida.
| |
No siempre instalo pv, pero me gusta porque me da progreso y control. Para envíos grandes, ver pasar bytes tranquiliza bastante.
cuidado con receive y los nombres#
zfs receive escribe en destino. Eso significa que el nombre importa mucho.
| |
Esto crea o actualiza ese dataset. Si quería mandar a backup/proxmox/templates-test y escribí templates, ya tengo una conversación incómoda conmigo mismo.
Para evitarlo, en pruebas uso nombres explícitos.
| |
Y cuando termino, borro la prueba si no la necesito.
| |
La opción -r borra recursivamente. No la uso si no he listado antes lo que cuelga de ahí. Es una de esas opciones que parecen cómodas hasta que te recuerdan que la comodidad y la destrucción hacen buena pareja.
propiedades y montaje#
Al recibir un dataset, conviene revisar propiedades. No asumo que el punto de montaje final sea el que quiero.
| |
A veces me interesa recibir sin montar automáticamente.
| |
La -u deja el dataset sin montar después de recibir. Para backups o réplicas frías, me parece sano. No todo lo que copio tiene que aparecer montado y listo para que alguien lo toque.
Si necesito cambiar mountpoint, lo hago explícito después.
| |
Otra vez: explícito gana a mágico.
enviar a un archivo#
No siempre quiero recibir en otro pool directamente. A veces quiero guardar el stream como archivo.
| |
Luego puedo recibirlo así.
| |
No es mi flujo favorito para el día a día porque acabas gestionando archivos enormes, pero puede servir para mover datos por disco externo o para archivar un punto concreto. Si lo hago, suelo comprimir.
| |
Y apunto de qué dataset salió, qué snapshot contiene y dónde debería recibirse. Un archivo .zfs.zst sin notas dentro de seis meses es arqueología, no backup.
lo que no haría#
No usaría zfs send como única estrategia para VMs importantes si ya tengo Proxmox Backup Server bien montado. PBS entiende Proxmox, deduplica, comprime, verifica y restaura desde una interfaz pensada para eso. zfs send es muy bueno, pero no reemplaza todo el ecosistema.
Tampoco haría réplicas incrementales a un destino que alguien modifica a mano. Si el destino cambia, la cadena incremental puede complicarse o directamente romperse. Para mí un destino de réplica es casi sagrado. Se recibe, se verifica y no se toca salvo para restaurar o probar en copia separada.
No ejecutaría receive -F en un dataset con valor sin revisar antes. -F puede hacer rollback del destino para que encaje con el stream. En una réplica automática dedicada tiene sentido. En un dataset donde alguien pudo añadir cambios, es una forma estupenda de perderlos con autoridad.
cómo restauraría#
Si el dataset receptor está en otro servidor y quiero restaurar al origen, invierto el flujo. Creo o elijo el snapshot del destino y lo envío de vuelta.
| |
Fíjate en el nombre: templates-restaurado. No recibo encima del dataset original a la primera. Prefiero restaurar a un nombre nuevo, montar, revisar y luego decidir. Si tengo prisa, más razón para no pisar el origen sin mirar.
Después puedo comparar contenido, copiar lo necesario o planificar el cambio definitivo. Restaurar no debería ser un acto de fe. Si el backup existe pero nunca has probado a recibirlo, tienes una promesa, no una restauración.
una receta segura para empezar#
Si estás probando esto por primera vez, crea un dataset pequeño.
| |
Haz una prueba seca.
| |
Recíbelo en otro nombre dentro del mismo servidor si no tienes segundo nodo.
| |
Lista y verifica.
| |
Luego cambia el origen, crea otro snapshot y manda incremental.
| |
Cuando entiendes ese flujo pequeño, el grande deja de parecer magia. Sigue siendo almacenamiento, así que respeto siempre. Pero ya no vas a ciegas.
mi regla práctica#
Uso zfs send y zfs receive cuando quiero mover estado ZFS como estado ZFS. Si solo necesito sincronizar una carpeta sencilla, quizá rsync basta. Si necesito backups de VMs Proxmox, probablemente PBS es mejor. Si quiero replicar datasets con snapshots e incrementales, aquí ZFS juega en casa.
La parte importante no es memorizar comandos. Es tener una rutina: snapshot claro, prueba seca, destino revisado, envío, verificación. Cinco pasos aburridos. Los pasos aburridos son los que evitan historias interesantes, y en almacenamiento las historias interesantes casi siempre salen caras.