Sincronizar Nextcloud y un servidor de archivos automáticamente
Un Nextcloud alojado es cómodo mientras funcione internet. Si se cae la conexión, en cambio, los datos quedan fuera de alcance. Un servidor de archivos en la red doméstica que guarde una copia completa del Nextcloud cierra esta brecha y es, además, el punto de partida ideal para las copias de seguridad locales. nc-bisync.sh mantiene esa copia al día automáticamente con rclone bisync. Se ejecuta sin supervisión mediante cron y solo da la alarma cuando algo no cuadra.
Descarga: nc-bisync.sh (los comentarios y mensajes del script están en alemán)
El punto de partida
Nextcloud es el almacén central, y el servidor de archivos lo refleja en la red doméstica:
Portátiles, móviles ⇄ Cliente de Nextcloud ⇄ Nextcloud
⇅ rclone bisync (automático)
Servidor de archivos → recursos SMB en la red doméstica
│
└─ rsnapshot (diario, versionado) → disco externo
Los portátiles y móviles se sincronizan como siempre con el cliente de Nextcloud. El servidor de archivos se sincroniza periódicamente con Nextcloud y está disponible en la red doméstica a través de sus recursos compartidos SMB. Si se cae la conexión a internet, sigue habiendo allí una copia completa de todos los datos. Como la sincronización funciona en ambos sentidos, también los archivos guardados directamente en el servidor de archivos llegan a Nextcloud. Las copias de seguridad se hacen desde el servidor de archivos, con independencia del proveedor.
Para esta sincronización, rclone bisync es muy adecuado: rclone habla WebDAV directamente y no necesita un montaje davfs. Además trae mecanismos de protección que, de otro modo, exigirían un script envoltorio propio.
Qué hace el script
Un par de directorios por carpeta compartida. Cada carpeta compartida del servidor de archivos se sincroniza con la carpeta correspondiente en Nextcloud, de forma independiente de las demás. Los pares pueden lanzarse por separado o en grupos, incluso con frecuencias distintas. Si hace falta, una subcarpeta concreta, por ejemplo un proyecto grande, pasa a ser un par propio y se excluye automáticamente del par superior.
Archivo solo cuando se pide. Una subcarpeta archiv dentro de un par nunca se sincroniza en una ejecución normal, solo con --archiv. Internamente es un par aparte con su propio estado. Eso es más estable que una carpeta que un filtro incluye unas veces y excluye otras.
Protección contra daños masivos. Tres mecanismos integrados protegen contra daños mayores:
--check-access: En cada raíz hay un archivoRCLONE_TEST. Si falta en un lado, porque una ruta es incorrecta o una unidad no está montada, la ejecución se interrumpe. Esto también evita que un bind mount vacío se transmita a Nextcloud como «todo borrado».--max-delete 10: Si se fuera a borrar más del 10 % de los archivos, no pasa nada.--backup-dir1: Los archivos sobrescritos o borrados en el servidor de archivos van a una carpeta diaria y se eliminan a los 30 días.
Conflictos. Si un archivo se modificó en ambos lados, gana la versión más reciente (--conflict-resolve newer). La más antigua se conserva con otro nombre.
Robustez. Con --resilient y --recover, bisync suele superar ejecuciones interrumpidas sin un --resync manual. Un archivo de bloqueo evita ejecuciones solapadas.
Notificaciones. Si hay errores llega un mensaje por correo o a través de ntfy. El script distingue si hace falta un resync, si se alcanzó el límite de borrado o si falló la comprobación de acceso. Cada ejecución queda registrada con su duración en summary.log.
Filtros. Los archivos temporales de Office, macOS y Windows nunca se sincronizan.
Requisitos
En el servidor de archivos:
- Linux con
bashversión 4 o posterior y las herramientas estándarflock(de util-linux),findycmp. En Debian, Ubuntu y Raspberry Pi OS ya vienen todas instaladas. - rclone 1.66 o posterior, véase el paso 1.
- Un usuario con permisos de escritura en los directorios sincronizados, con el que se ejecuta el script.
- Opcionalmente
curlpara notificaciones push a través de ntfy y un envío de correo configurado para los avisos por correo, véase el paso 7.
En Nextcloud:
- Una cuenta con acceso WebDAV y una contraseña de aplicación.
- Las carpetas de destino;
--initcrea por sí mismo las que falten.
Instalación
El script no se ejecuta como root, sino como el usuario propietario de los archivos en el servidor de archivos. De lo contrario, los archivos traídos de Nextcloud pertenecerían a root y los demás usuarios de la carpeta compartida ya no podrían modificarlos. sudo solo hace falta para la instalación.
1. Instalar rclone
El script necesita rclone 1.66 o posterior. Muchas distribuciones traen paquetes más antiguos, así que es mejor usar el script de instalación oficial:
curl https://rclone.org/install.sh | sudo bash
rclone version
2. Configurar el remoto de Nextcloud
En Nextcloud, crea una contraseña de aplicación en Configuración → Seguridad. Después configura el remoto como el usuario con el que se ejecutará el script (sin sudo):
rclone config
# n) New remote
# name> nc
# Storage> webdav
# url> https://cloud.example.com/remote.php/dav/files/USUARIO/
# vendor> nextcloud
# user> USUARIO
# pass> (contraseña de aplicación)
Para probar:
rclone lsd nc:
3. Instalar y adaptar el script
sudo install -m 755 nc-bisync.sh /usr/local/bin/nc-bisync.sh
sudo install -d -o USUARIO /var/lib/nc-bisync /var/log/nc-bisync
sudo install -d -o USUARIO -m 700 /mnt/USB-Crucial/.bisync-backup
El modo 755 hace que todos los usuarios puedan ejecutar el script, pero solo root puede modificarlo. La segunda línea crea los directorios de estado y de registros y se los asigna al usuario con el que se ejecuta el script. La tercera crea el directorio de copias (BACKUP_ROOT); modo 700, porque allí van a parar los archivos sobrescritos de todas las carpetas compartidas y solo debe verlos el usuario del script.
En el bloque de configuración del principio introduces los pares, uno por línea con nombre, ruta local y ruta en Nextcloud:
PAIRS=(
"administration|/mnt/shares/administration|nc:Administration"
"bibliothek|/mnt/shares/bibliothek|nc:Bibliothek"
"dokumente|/mnt/shares/dokumente|nc:Dokumente"
"fotos|/mnt/shares/fotos|nc:Fotos"
"projekte|/mnt/shares/projekte|nc:Projekte"
"unternehmen|/mnt/shares/unternehmen|nc:Unternehmen"
)
Otros ajustes:
| Variable | Significado | Ejemplo |
|---|---|---|
ARCHIVE_SUBDIR |
Subcarpeta que solo se sincroniza con --archiv |
archiv |
BACKUP_ROOT |
Depósito de archivos sobrescritos | /mnt/USB-Crucial/.bisync-backup |
MAX_DELETE |
Límite de borrado en porcentaje | 10 |
NOTIFY_MAIL |
Destinatario de los avisos de error (opcional) | admin@example.com |
NTFY_URL |
Tema de ntfy para notificaciones push (opcional) | https://ntfy.sh/mi-tema |
Asegúrate de que BACKUP_ROOT queda fuera de todos los pares. Con nc-bisync.sh --list compruebas qué pares están configurados y cuáles tienen una subcarpeta de archivo.
4. Permisos de grupo en el servidor de archivos
El script crea los archivos nuevos con umask 002 para que el grupo pueda seguir modificándolos. Para que además reciban el grupo correcto y no el grupo principal del usuario, los directorios sincronizados deberían tener el bit setgid. El bit setgid en un directorio hace que los archivos y subcarpetas creados en él hereden automáticamente su grupo, en lugar de recibir el grupo principal de quien los crea.
Para los pares del ejemplo anterior, lo activas así en todos los directorios existentes:
for d in administration bibliothek dokumente fotos projekte unternehmen; do
sudo find "/mnt/shares/$d" -type d -exec chmod g+s {} +
done
Se reconoce que está activado por una s en los permisos de grupo:
$ ls -ld /mnt/shares/dokumente
drwxrws--- 10 stefan familie 4,0K 21. Jul 13:19 /mnt/shares/dokumente
5. Sincronización inicial
Prueba primero con --dry-run y después lanza la sincronización inicial:
nc-bisync.sh --init --dry-run
nc-bisync.sh --init
--init crea los archivos RCLONE_TEST en cada par y en cada subcarpeta de archivo existente y lo sincroniza todo con --resync. Donde haya diferencias, gana el archivo más reciente. Con muchos datos conviene configurar los pares de uno en uno, por ejemplo nc-bisync.sh --init fotos.
En la prueba el script no cambia nada: tampoco crea los archivos RCLONE_TEST y por eso omite la comprobación de acceso.
6. Programación
Añade las tareas con crontab -e al crontab del usuario con el que se ejecuta el script. Como cada par tiene su propio bloqueo, las carpetas que cambian a menudo pueden sincronizarse con más frecuencia que las que cambian poco:
# cambia a menudo: cada 2 horas
0 */2 * * * /usr/local/bin/nc-bisync.sh dokumente fotos projekte unternehmen administration
# cambia poco: por la noche
30 2 * * * /usr/local/bin/nc-bisync.sh bibliothek
Con muchos archivos, lo que frena no es la transferencia sino el listado por WebDAV, y eso se hace completo en cada ejecución. Por eso empieza con dos horas y consulta las duraciones al cabo de unos días:
tail /var/log/nc-bisync/summary.log
Como regla general, el intervalo debería ser unas tres veces más largo que una ejecución. No sincronices con demasiada frecuencia, porque algunos proveedores limitan las peticiones WebDAV numerosas.
7. Configurar las notificaciones (opcional)
Si NOTIFY_MAIL y NTFY_URL se dejan vacíos, el script solo escribe los errores en summary.log. Para un funcionamiento sin supervisión conviene configurar al menos una de las dos vías; también pueden combinarse.
Correo (NOTIFY_MAIL). El script envía el mensaje con el comando mail. Para ello debe estar instalado un paquete adecuado, como mailutils o bsd-mailx, y el servidor tiene que poder entregar correo al exterior. Lo más sencillo es msmtp-mta, que envía el correo a través de la cuenta SMTP de tu proveedor. Para comprobar que funciona, ejecuta como el usuario del script:
echo "Prueba" | mail -s "Prueba de nc-bisync" admin@example.com
Si falta el comando mail, el script omite el envío de correo sin mensaje de error.
Notificación push (NTFY_URL). Para ello el servidor necesita curl. Instala la app de ntfy en el móvil y suscríbete allí a un tema. El servidor público ntfy.sh no necesita cuenta, pero cualquiera que conozca el nombre del tema puede leer los mensajes. Por eso elige un nombre largo y aleatorio, por ejemplo https://ntfy.sh/nc-bisync-7f3k9x2q. Para probar:
curl -d "Prueba de nc-bisync" https://ntfy.sh/nc-bisync-7f3k9x2q
Un servidor ntfy propio funciona igual. Los temas que exigen inicio de sesión o un token de acceso no los admite el script en su forma actual.
Uso diario
| Comando | Cuándo |
|---|---|
nc-bisync.sh |
sincronizar todos los pares, sin archivo |
nc-bisync.sh fotos dokumente |
sincronizar solo los pares indicados |
nc-bisync.sh --archiv projekte |
después de archivar archivos en projekte |
nc-bisync.sh --dry-run fotos |
ver antes qué pasaría |
nc-bisync.sh --archiv --force projekte |
cuando al archivar se alcanzó el límite de borrado |
nc-bisync.sh --list |
mostrar los pares configurados |
Las opciones de rclone que llevan un valor se indican siempre como --opcion=valor; si no, el script toma el valor por el nombre de un par.
Archivar archivos
Mueve los archivos dentro de la carpeta compartida a la subcarpeta archiv y lanza después la sincronización de esa carpeta:
nc-bisync.sh --archiv projekte
El script sincroniza primero el archivo y solo después el resto de la carpeta. Así los archivos ya están en el archivo de Nextcloud antes de desaparecer allí del resto de la carpeta. Si falla la sincronización del archivo, el resto de la carpeta no se toca.
Si mueves muchísimos archivos a la vez, puede saltar el límite de borrado. En ese caso revisa brevemente el registro y vuelve a lanzar con --force.
Para añadir un archivo más adelante, crea la carpeta archiv en local y ejecuta una vez nc-bisync.sh --init NOMBRE.
Subcarpetas concretas como par propio
Si una carpeta compartida crece demasiado para ejecuciones frecuentes, una subcarpeta puede tener su propio par:
"tango|/mnt/shares/projekte/Tango|nc:Projekte/Tango"
El script excluye entonces Tango automáticamente del par projekte. Como así cambia su filtro, hace falta ejecutar una vez nc-bisync.sh --init projekte tango. La subcarpeta tiene que estar en el lugar correspondiente de Nextcloud; si no, el script se detiene con un aviso.
Cuando llega una notificación
- Hace falta un resync: Consulta la causa en el registro indicado. Después,
nc-bisync.sh --init NOMBREsuele arreglar el estado, mejor primero con--dry-run. - Demasiados borrados: Comprueba si los borrados son intencionados. Si es así, lanza con
--force. - Falló la comprobación de acceso: Falta un archivo
RCLONE_TEST. Comprueba que la ruta es correcta, que Nextcloud está accesible y que la unidad está montada.
Solución de problemas
Cortes de conexión en transferencias grandes
Síntomas. Sobre todo en la sincronización inicial de grandes cantidades de datos aparecen en el registro, para archivos concretos, errores como este:
ERROR : 2014/…/IMG_0929.PNG: Failed to copy: unchunked simple update failed: Put "https://…":
http2: Transport: cannot retry err [http2: Transport received Server's graceful shutdown GOAWAY]
after Request.Body was written; define Request.GetBody to avoid this error
La ejecución no se interrumpe, sino que sigue transfiriendo los demás archivos. Aun así, al final de una sincronización inicial bisync indica Bisync aborted. Must run --resync to recover., porque con --resync basta un solo archivo fallido. En el resumen aparece entonces, por ejemplo, un 100 % transferido pero varios errores.
Qué falla con HTTP/2. HTTP/2 envía muchas peticiones a la vez por una única conexión. En algún momento el servidor, o un proxy delante de él, cierra esa conexión de forma ordenada con un GOAWAY, por ejemplo tras un número fijo de peticiones o al reiniciarse. Las peticiones que aún no han empezado pueden enviarse sin problema por una conexión nueva. Con las subidas cuyos datos ya estaban en camino no es posible: el contenido del archivo ya se ha enviado y en ese punto no puede volver a enviarse. El archivo falla.
Qué cambia con HTTP/1.1. Aquí cada petición va por su propia conexión. Si el servidor cierra una de ellas, solo afecta a esa transferencia, y rclone la repite por una conexión nueva con sus reintentos normales. Como rclone transfiere de todos modos varios archivos en paralelo, en la práctica HTTP/1.1 apenas es más lento.
Solución para una ejecución concreta. A menudo basta con repetir la ejecución: los cortes solo ocurren de forma esporádica, y en el siguiente intento los archivos fallidos suelen transferirse. Los archivos ya transferidos solo se comparan, no se vuelven a subir. Si no, queda recurrir a HTTP/1.1. El script pasa a rclone todas las opciones que no conoce. Así repites con HTTP/1.1 una sincronización inicial fallida:
nc-bisync.sh --init fotos --disable-http2
Desactivarlo de forma permanente. Cualquier opción de rclone puede definirse también como variable de entorno RCLONE_<OPCIÓN>. Añade para ello esta línea en el bloque de configuración del script:
export RCLONE_DISABLE_HTTP2=true
Así todas las llamadas a rclone del script usan HTTP/1.1, también las del cron.
Límites
rclone bisync no es una copia de seguridad. La sincronización también transmite cambios accidentales; solo se interceptan los borrados masivos. Si, por ejemplo, un ransomware cifra archivos en un portátil, llegan a Nextcloud a través del cliente de Nextcloud y al servidor de archivos mediante bisync, porque se sobrescriben, no se borran. Las versiones sobrescritas se conservan aún 30 días en el directorio de copias, pero la verdadera protección la dan las copias versionadas de rsnapshot y las versiones de archivos de Nextcloud. El periodo de conservación debería ser más largo que el tiempo que se tarda en notar un daño.