Almacenamiento de archivos
¿Qué es un almacén de objetos?
Un almacén de objetos es un bucket tuyo — en Amazon S3 o en Cloudflare R2 — en el que nuzur puede escribir archivos en tu nombre. Lo registras una sola vez a nivel de equipo, le das un identificador y a partir de ahí lo referencias por nombre: un campo File apunta a él, y nuzur-cli deploy entrega sus credenciales a una app desplegada.
Registrar el almacén en nuzur en lugar de pegar las claves en un archivo de configuración es justamente la idea. El bucket sigue siendo tuyo, las credenciales quedan cifradas y todos los proyectos del equipo pueden usar el mismo almacén sin que nadie tenga que ir copiando un secreto.
Registrar un almacén
En la aplicación web de nuzur, abre configuración del equipo → Almacenes de objetos (Object Stores) y haz clic en Nuevo almacén de objetos.
Todo almacén tiene:
- Identificador — un nombre corto que reconozcas después (p. ej.
media-prod,uploads-eu). - Tipo —
S3para Amazon S3,R2para Cloudflare R2. - Estado —
activeodisabled. Deshabilitar un almacén lo deja registrado pero fuera de circulación, así que puedes retirar un bucket sin borrar su configuración.
El resto del formulario depende del tipo.
S3 y R2, campo a campo
| Campo | Amazon S3 | Cloudflare R2 |
|---|---|---|
| Bucket | nombre del bucket | nombre del bucket |
| Región | p. ej. us-east-1 |
no se pide — en R2 siempre es auto |
| Account id | — | el account id de tu cuenta de Cloudflare |
| Clave de acceso | access key id | access key id |
| Secreto | secret access key | secret access key |
| Endpoint | se deriva de la región | se deriva del account id, se puede sobrescribir |
Amazon S3
Crea (o reutiliza) un usuario o rol de IAM con permisos de lectura y escritura sobre el bucket, y pega su access key id, su secret access key, la región y el nombre del bucket.
Cloudflare R2
R2 habla la API de S3, así que nuzur se comunica con él igual que con S3 — solo lo direcciona de otra forma. Hay dos valores propios de R2:
Tu account id. Abre el panel de Cloudflare y ve a R2. El account id aparece en la página de resumen de R2, junto al endpoint de la API de S3. Es el mismo identificador hexadecimal de 32 caracteres que ves en la URL del panel. nuzur deriva el endpoint a partir de él:
https://<account_id>.r2.cloudflarestorage.com
Un token de API de R2. También en R2, entra en Manage R2 API Tokens → Create API token. Dale el permiso Object Read & Write y limítalo al bucket que vas a registrar. Cloudflare te mostrará entonces un Access Key ID y un Secret Access Key — esos son los dos valores que nuzur necesita. Cópialos en ese momento; Cloudflare enseña el secreto una sola vez.
Región: R2 no tiene regiones en el sentido de S3. Su región siempre es
autoy nuzur la rellena por ti — un almacén R2 no tiene campo de región.
Sobrescribir el endpoint
El endpoint derivado es el correcto para un bucket de R2 estándar. Si tu bucket vive en una de las ubicaciones jurisdiccionales de R2, su host es distinto — la jurisdicción de la UE, por ejemplo, se sirve desde:
https://<account_id>.eu.r2.cloudflarestorage.com
Para eso está el campo opcional endpoint. Si lo dejas vacío, nuzur deriva el host estándar; si lo rellenas, nuzur usa exactamente lo que escribiste. También sirve para cualquier otro servicio compatible con S3 que hable la misma API.
Dónde se guardan tus claves
La clave de acceso y el secreto nunca tocan el esquema de tu proyecto, y nunca se escriben en el JSON de una versión del proyecto. Al guardar un almacén, nuzur envía ese par a AWS Secrets Manager, cifrado con KMS y asociado a tu equipo. Lo que vive en el proyecto — y en cualquier cosa que exportes — es el UUID del almacén y sus datos no secretos.
Esto significa que:
- Compartir un proyecto, exportar una versión o pasarle un modelo a un compañero nunca filtra una credencial.
- Rotar una clave es un cambio en un solo sitio: edita el almacén, y cada campo y cada despliegue futuro que lo referencie usará el valor nuevo.
- Una app desplegada recibe las credenciales en el momento del despliegue (ver más abajo), no leyéndolas de nuzur en tiempo de ejecución.
Apuntar un campo a un almacén
Hay cuatro tipos de campo que guardan archivos: File, Image, Audio y Video. Cada uno tiene un tipo de almacenamiento en su configuración de tipo:
| Tipo de almacenamiento | Dónde van los bytes |
|---|---|
binary |
el almacenamiento propio de nuzur — no hay nada que configurar |
object_store |
tu bucket, a través de un almacén de objetos registrado |
Si eliges object_store, el campo te pedirá dos cosas más:
- Almacén de objetos — elige uno de los almacenes registrados del equipo.
- Prefijo de ruta — el prefijo de clave bajo el que se escriben todos los archivos de este campo, p. ej.
avatars/oinvoices/2026/. Evita que los archivos de un campo choquen con los de otro dentro de un bucket compartido.
Esa es toda la configuración del campo: un UUID de almacén y un prefijo. Las credenciales no se copian dentro del campo — nuzur las resuelve desde el equipo en cada petición, y por eso rotar una clave no requiere tocar el modelo.
Consulta Tipos de campo para la lista completa de tipos y sus validaciones.
Los endpoints generados /upload y /sign
La opción de campo anterior trata de los archivos que nuzur guarda por ti. Go Code Gen tiene, aparte, un interruptor opcional de almacenamiento de archivos que le da a tu backend generado su propia vía de subida. Actívalo y la app generada expone dos endpoints:
POST /upload
Una petición multipart/form-data con el archivo en una parte llamada file. Devuelve la URL y la clave del objeto almacenado:
{ "url": "https://…/uploads/9f2c….png", "key": "uploads/9f2c….png" }
POST /sign
Recibe un key o una url y devuelve una URL firmada con caducidad. Petición:
{ "key": "uploads/9f2c….png", "expiry_seconds": 900 }
Respuesta:
{ "url": "https://…/uploads/9f2c….png?X-Amz-Signature=…" }
expiry_seconds es opcional.
Cómo los usa tu modelo
Los endpoints son genéricos: no están ligados a ninguna entidad. En la app generada, los campos de archivo siguen siendo columnas de texto/URL normales, así que el flujo tiene dos pasos:
- Sube los bytes con
POST /uploady toma laurlde la respuesta. - Pon esa
urlen un payload normal de creación o actualización, como cualquier otro campo de texto.
Si falta el bloque de configuración
aws:de la app,/uploady/signdevuelven503. La app arranca igual y el resto de endpoints siguen funcionando — una configuración de almacenamiento ausente degrada esas dos rutas en lugar de tumbar el servicio.
Llevar las credenciales a una app desplegada
nuzur-cli deploy se encarga de conectarlo todo. La vía recomendada es referenciar un almacén registrado:
nuzur-cli deploy --host 203.0.113.10 --project mi-proyecto \
--storage-enabled --storage 8f1c2b7e-....
--storage recibe el UUID del almacén de objetos. Sus credenciales se resuelven en el servidor, desde tu equipo, en el momento del despliegue — el secreto nunca se escribe en tu línea de comandos ni se guarda en un archivo de configuración de despliegue.
Si prefieres indicar un bucket a mano — incluido un bucket de R2, o cualquier otro compatible con S3, que no esté registrado en nuzur — usa los flags manuales:
| Flag | Descripción |
|---|---|
--storage-enabled |
Genera la capa de almacenamiento de archivos (/upload y /sign) |
--storage |
UUID de un almacén de objetos registrado; las credenciales se resuelven en el servidor desde tu equipo |
--s3-bucket |
Nombre del bucket |
--s3-region |
Región del bucket (usa auto para R2) |
--s3-access-key |
Access key id |
--s3-secret |
Secret access key — solo por CLI, nunca se escribe en un archivo de configuración de despliegue |
--s3-endpoint |
Endpoint alternativo para R2 o cualquier servicio compatible con S3 |
Para un bucket de R2 configurado a mano, --s3-endpoint https://<account_id>.r2.cloudflarestorage.com junto con --s3-region auto equivale a un almacén R2 registrado.
Se resuelvan como se resuelvan, deploy escribe las credenciales en el prod.yaml del proyecto en el servidor con permisos chmod 600 — legible únicamente por la cuenta que ejecuta la app. Consulta Desplegar un proyecto para el resto de flags de despliegue.