Por qué no dejar MinIO donde está
El repositorio minio/minio fue archivado por su propietario el 25 de abril de 2026: es de solo lectura, su README indica que el proyecto ya no se mantiene y que los binarios ya publicados no recibirán actualizaciones. En la práctica, nadie corregirá en origen el próximo fallo que se descubra en su servidor S3. El cliente mc, también bajo AGPLv3, fue archivado el 14 de julio de 2026.
Su MinIO sigue funcionando, y eso es lo que hace traicionero el asunto: el día del archivado no se rompe nada. Pero un almacenamiento de objetos está expuesto, contiene sus archivos multimedia, copias de seguridad o exportaciones, y ahora funciona sin parches de seguridad. Dos destinos autoalojables aparecen una y otra vez en las discusiones: Garage, publicado bajo AGPLv3, y RustFS, publicado bajo licencia Apache 2.0.
Este artículo no repite la instalación de ninguno de los dos, que tienen su propia guía: Garage en un VPS y RustFS en un VPS. Aquí partimos de un MinIO en producción y respondemos a una sola pregunta: cómo mover los datos, demostrar que no falta nada y cambiar la aplicación sin URL rotas.
Lo que una copia de bucket no traslada por sí sola
- Los objetos actuales — es la parte fácil:
rcloneomc mirrorlos copian, con una comprobación posterior. - Las versiones anteriores — la documentación de
mc mirrorprecisa que solo sincroniza el objeto actual, sin información de versión. - Los usuarios y las políticas IAM — viven en MinIO, no en los buckets. Los secretos no se exportan: se generan claves nuevas en el destino.
- Las URL prefirmadas ya distribuidas — la firma depende del host, de la región y de las claves. Cambiar el endpoint las invalida.
- Las diferencias de compatibilidad S3 — ACL, políticas de bucket, acceso anónimo, versionado: cada destino tiene sus huecos, que se leen en su documentación en lugar de suponerlos.
- La configuración de los clientes — endpoint, región, direccionamiento path-style: todo lo que su aplicación, sus copias
restico su CDN llevan fijado.
Requisitos y plan de capacidad
Necesita acceso de administrador a MinIO, un equipo o un VPS con mc y rclone, y un destino ya instalado y accesible por HTTPS (consulte las dos guías anteriores para el proxy inverso y el certificado). La regla de capacidad es simple: mientras no haya validado la migración, conserva el origen intacto, así que paga el disco dos veces.
Nuestra recomendación editorial: prever en el destino el tamaño total de los datos del origen, más un margen de alrededor del 30 % para los metadatos y las diferencias de reparto. En el mismo VPS, eso significa disponer como mínimo del doble del volumen actual más el margen; en dos VPS, cada uno asume su parte. Un único nodo Garage con replication_factor = 1 guarda una sola copia de cada objeto: no es una copia de seguridad, y el origen aún en pie es su única red de seguridad durante la migración.
Paso 1: inventariar el origen antes de copiar
Declarar MinIO como alias
Cree un alias
srccon credenciales que lean todos los buckets:mc alias set src https://s3.your-domain.com ACCESS_KEY SECRET_KEYContar los objetos y el tamaño
Para cada bucket, anote el número de objetos y el volumen:
mc du --recursive src/mediasmc ls --recursive src/medias | wc -l
Lleve estas cifras a una tabla «antes / después»: es su prueba de que la migración está completa.Contar las versiones
Si el versionado está activo, la lista de versiones es más larga que la de objetos:
mc ls --recursive --versions src/medias | wc -l
La documentación demc lsprecisa que--versionsexige un servicio que admita el versionado. Una gran diferencia entre ambos recuentos indica cuánto historial está en juego.Exportar la lista de políticas y de usuarios
Conserve un registro de lo que tendrá que recrear:
mc admin policy list srcmc admin user list src
Los secretos no aparecen en esta salida y no pueden aparecer: los regenerará.Anotar la configuración de los clientes
En cada aplicación que habla con MinIO, anote el endpoint, la región, el estilo de direccionamiento y el nombre de la variable de entorno que los contiene. El cambio final solo modificará estos valores.
Garage y RustFS: las diferencias que conviene conocer antes de elegir
Desplace la tabla
| Tema | Garage | RustFS |
|---|---|---|
| Licencia | AGPLv3 (README del repositorio) | Apache 2.0 (README del repositorio) |
| Versionado | No admitido: `PutBucketVersioning` y `ListObjectVersions` figuran como ausentes | Indicado como disponible en el README |
| Políticas de bucket y ACL | Ninguna de las dos: un sistema propio, por clave y por bucket | IAM y políticas de bucket; las ACL no se admiten de forma deliberada |
| Acceso anónimo | Rechazado, con una respuesta 403 | Evaluado según la política del bucket |
| Región del cliente | `s3_region` de `garage.toml`, que hay que copiar en el cliente | `RUSTFS_REGION`, `us-east-1` por defecto, que hay que copiar en el cliente |
| Direccionamiento | Path-style y vhost-style admitidos | Path-style por defecto, sin configuración DNS |
| URL prefirmadas | Admitidas | Admitidas; host, esquema, puerto, región y ruta deben coincidir con la firma |
| API de administración de MinIO | No aplica: se administra con el comando `garage` | Superficie separada: el S3 funciona sin que `mc admin` esté garantizado |
Versionado: lo que pierde la copia y qué hacer
Este punto decide la elección del destino. Garage no admite el versionado: su página de compatibilidad S3 lo dice sin rodeos. Si sus buckets conservan un historial que la aplicación consulta o que debe guardar por razones de negocio, Garage no es el destino. RustFS indica el versionado como disponible, pero la copia con rclone sync o mc mirror no recreará allí su historial.
Tres vías, a elegir bucket por bucket. Asumir la pérdida: solo pasa la versión actual, lo cual basta cuando el versionado era solo una red de seguridad contra el error humano. Copiar versión por versión: se listan los identificadores con mc ls --versions y se reproducen las versiones de la más antigua a la más reciente hacia un destino que admita el versionado, tras activarlo en el bucket; las fechas de las versiones serán las de la copia, no las originales. O archivar el historial aparte, en un bucket de archivo, y migrar solo lo actual. En todos los casos, pruebe con un objeto de varias versiones antes de lanzar la copia general.
Paso 2: preparar el destino, Garage o RustFS
Garage: asignar y luego aplicar el layout
Ningún bucket es utilizable hasta que se aplica el layout. Obtenga el identificador del nodo y asígnele una zona y una capacidad:
garage statusgarage layout assign -z dc1 -c 1G <node_id>garage layout apply --version 1
Ajuste-cal espacio en disco realmente asignado.Garage: crear la clave, el bucket y los permisos
Los permisos se conceden por clave y por bucket:
garage key create app-keygarage bucket create mediasgarage bucket allow --read --write --owner medias --key app-key
El secreto se muestra al crear la clave: cópielo enseguida en su gestor de secretos.Garage: copiar la región en el cliente
La sección
[s3_api]degarage.tomldefines3_region. Ponga exactamente ese valor en la configuración de sus clientes y mantenga el direccionamiento path-style. Una región distinta provoca firmas rechazadas.RustFS: alias y bucket
Con
mcconfigurado sobre el destino:mc alias set dst http://127.0.0.1:9000 ACCESS_KEY SECRET_KEYmc mb dst/medias
La documentación de RustFS recomienda usuarios IAM o cuentas de servicio en lugar de las claves raíz para las aplicaciones.RustFS: recrear usuarios y políticas
Tome la lista exportada en el paso 1 y recree cada usuario y cada política en RustFS, con una clave nueva por aplicación. Después alinee la región:
RUSTFS_REGIONvaleus-east-1por defecto, y el cliente debe usar la misma.
Paso 3: copiar con rclone y demostrar el resultado
Declarar los dos remotes
Use el proveedor
Miniopara el origen yOtherpara el destino:rclone config create src s3 provider=Minio access_key_id=ACCESS_KEY secret_access_key=SECRET_KEY endpoint=https://s3.your-domain.comrclone config create dst s3 provider=Other access_key_id=ACCESS_KEY secret_access_key=SECRET_KEY endpoint=http://127.0.0.1:3900 region=garageregion=garagesupones3_region = "garage", el valor del ejemplo de Garage: ponga el suyo si difiere. Para RustFS, sustituya el endpoint por el del destino y la región por el valor deRUSTFS_REGION.Hacer un ensayo en seco
rclone syncmodifica el destino para que refleje el origen, incluidas las eliminaciones. No lo invierta nunca, y ejecute primero el ensayo:rclone sync src:medias dst:medias --checksum --metadata --transfers 16 --dry-runLanzar la copia en caliente
MinIO sigue en servicio durante esta primera pasada:
rclone sync src:medias dst:medias --checksum --metadata --transfers 16 --progress--metadatapide a rclone que conserve los metadatos: compruebe en un objeto de prueba que el tipo de contenido ha llegado intacto.Verificar la copia
Compruebe que todo lo que está en el origen existe en el destino:
rclone check src:medias dst:medias --one-way --combined /tmp/check-medias.txt
El archivo lista cada ruta con un símbolo:=idéntico,+ausente del destino,*distinto,!error. El objetivo es cero líneas+,*o!.Volver a contar tras la copia
Repita
mc du --recursivey el recuento de objetos en el destino, con el aliasdst, y rellene la columna «después» de su tabla. Las dos cifras deben ser idénticas, salvo diferencias explicadas por las versiones.
ETag multipart y mc mirror: leer las diferencias sin equivocarse
El ETag de un objeto pequeño enviado en una sola petición es su MD5, y rclone lo usa como suma de control. En un objeto multipart, la documentación de rclone recuerda que el ETag deja de ser el MD5 de los datos: es el MD5 de la sucesión de los MD5 de cada parte, seguido del número de partes. Depende, por tanto, del tamaño de las partes, que eligió el cliente al subir.
Su MinIO recibió el objeto con un troceado, rclone lo envía al destino con otro: el contenido es idéntico byte a byte, el ETag no. Un rclone check que señale esos objetos como distintos no tiene por qué tener razón. Repítalo sobre ellos con --download, que descarga ambos lados y compara los propios datos: más lento, pero sin ambigüedad. La misma cautela vale para mc mirror: su documentación precisa que las sumas compuestas pueden diferir simplemente porque cambió el reparto en partes.
Si prefiere quedarse en el ecosistema mc, la copia se escribe mc mirror --preserve src/medias dst/medias. --preserve conserva los atributos del origen y sus reglas de política de bucket; esto último solo tiene sentido si el destino sabe leerlas, lo que excluye a Garage. Sin --overwrite, un objeto ya presente en el destino no se vuelve a copiar: el error se registra y la copia continúa. Con --remove, se eliminan los objetos del destino ausentes del origen. Y mc mirror solo sincroniza el objeto actual, sin versiones. Su comparación se basa en el nombre, el tamaño, la fecha y la suma de control, sin leer el contenido. El repositorio de mc también está archivado: la herramienta funciona, pero no evolucionará.
URL prefirmadas: por qué fallan en el cambio
Una URL prefirmada contiene una firma calculada con la clave secreta, el host, la región y la ruta. La documentación de RustFS lo dice: el host, el esquema, el puerto, la región y la ruta de la petición deben coincidir con los usados para firmar. Cambiar de endpoint o de clave invalida, por tanto, todos los enlaces ya emitidos, sin excepción, y nada los redirige.
La consecuencia es una cuestión de secuencia. Los enlaces que su aplicación genera al vuelo se regeneran solos en cuanto se reconecta al nuevo destino. Los que envió por correo o guardó en base de datos morirán en el cambio. Acorte, pues, la vida útil de los enlaces unos días antes, para que circulen pocos enlaces largos, y avise a los equipos que los reparten a mano.
Paso 4: cambiar en tres tiempos, sin corte brusco
Sincronización inicial en caliente
Es la copia del paso 3, ejecutada mientras MinIO sigue sirviendo tráfico. Dura lo que tenga que durar y no molesta a nadie. Anote la hora de finalización.
Congelar las escrituras
Ponga la aplicación en solo lectura o en un mantenimiento breve, o active una doble escritura si su código lo permite. Las lecturas pueden seguir en MinIO mientras se ejecuta la sincronización final.
Sincronización final con --update
Transfiera solo lo que ha cambiado desde entonces:
rclone sync src:medias dst:medias --update --metadata --transfers 16 --progressrclone check src:medias dst:medias --one-way
Vuelva a contar los objetos y el tamaño, y compare con la tabla del paso 1.Cambiar el endpoint mediante una variable de entorno
Su aplicación debe leer el endpoint, la región y las claves de su entorno, nunca del código. Modifique esas variables, reinicie el servicio y pruebe una subida, una lectura y un borrado sobre un objeto de prueba. Regenere los enlaces prefirmados que importen.
Vigilar y solo después desmontar
Deje MinIO en su sitio, detenido o en solo lectura, el tiempo necesario para ver pasar un ciclo completo de sus copias de seguridad y de sus tareas programadas. Vuelva a apuntar sus copias
restical destino; vea la guía sobre las copias de seguridad con restic.
La vuelta atrás se reduce a una variable
Mientras MinIO no se haya eliminado y la última sincronización se haya hecho en solo lectura, volver atrás consiste en poner el endpoint antiguo en el entorno y reiniciar. Si ha habido escrituras en el destino desde el cambio, tráigalas antes al origen con un rclone copy en sentido contrario (nunca un sync, que eliminaría) y después vuelva. Borre MinIO solo tras un periodo de observación fijado de antemano.
Solución de problemas: los síntomas que se repiten
Una llamada sin firma a Garage responde 403 con el mensaje Garage does not support anonymous access yet. Es el comportamiento esperado de Garage, y la petición de acceso anónimo sigue en el seguimiento del proyecto como una función que nunca se priorizó. Si su aplicación servía archivos públicos sin firma, tendrá que usar URL prefirmadas o un proxy delante del bucket.
Si las escrituras se rechazan con errores de firma justo después del cambio, compare la región del cliente con la del destino (s3_region en Garage, RUSTFS_REGION en RustFS) y compruebe que el cliente usa direccionamiento path-style. Si rclone check señala objetos multipart como distintos aunque sus tamaños sean iguales, repítalo con --download. Si una nueva ejecución de mc mirror no copia un objeto modificado, la causa es la falta de --overwrite. Por último, si un bucket está vacío en el destino aunque la sincronización haya terminado bien, compruebe que la clave recibió --read --write sobre ese bucket en Garage, o la política adecuada en RustFS.
La documentación oficial
Relea estas fuentes antes de actuar, porque estos proyectos evolucionan: el repositorio github.com/minio/minio para el estado y la licencia de MinIO; github.com/rustfs/rustfs y docs.rustfs.com para RustFS; garagehq.deuxfleurs.fr para la compatibilidad S3 de Garage; rclone.org para sync y check; la documentación de MinIO sobre mc mirror. Para respaldar este almacenamiento, consulte el artículo 3-2-1 con restic y S3.