// DevOps

Cómo domé Terraform: migración del estado de Git a Cloudflare R2

Publicado el 10.04.2026

Cuando empecé a trabajar en la infraestructura del proyecto, guardar terraform.tfstate localmente (o, lo confieso, subirlo a Git) me parecía una solución razonable. Pero en cuanto mis colegas se sumaron al trabajo, entendí rápido: el state local es un barril de pólvora.

Uno olvidó hacer git pull, otro aplicó cambios desde su máquina — y me pasaba medio día «resolviendo» conflictos en la infraestructura. En cierto momento se hizo evidente: necesitaba un Remote State.

Como backend elegí Cloudflare R2. La razón es simple: es un almacenamiento compatible con S3 sin coste por salida de datos (zero egress fees), y me llevó literalment unos minutos configurarlo.


Por qué renuncié al state local

El problema principal del archivo local es la falta de sincronización y control.

Riesgo de sobrescribir cambios ajenos

Si dos personas ejecutan terraform apply simultáneamente, Terraform no evita la carrera sin mecanismos de bloqueo. Al final gana quien escribió el state por último.

Secretos a la vista

En terraform.tfstate pueden estar contraseñas, tokens y claves — a menudo en claro. Tener eso en Git es, francamente, una mala idea.

Imposibilidad de un CI/CD decente

Sin un estado remoto, cada ejecución de Terraform en CI ve «su» propio mundo, lo que hace la automatización inútil.


Cómo lo configuré

Dado que R2 soporta la API S3, usé el backend estándar s3. Pero como no es AWS, tuve que desactivar varias comprobaciones de Terraform.

Saqué la configuración a un archivo separado backend.hcl, para no ensuciar el código principal:

bucket                      = "my-infrastructure-state"
key                         = "prod/main.tfstate"
region                      = "auto"

# Importante para R2
use_path_style              = true

# Desactivo comprobaciones específicas de AWS
skip_credentials_validation = true
skip_metadata_api_check     = true
skip_region_validation      = true
skip_requesting_account_id  = true

# A veces es necesario según la versión de Terraform
skip_s3_checksum            = true

endpoints = {
  s3 = "https://<YOUR_ACCOUNT_ID>.r2.cloudflarestorage.com"
}

En el código principal de Terraform dejé el bloque mínimo:

terraform {
  backend "s3" {}
}

Cómo resolví el problema de los bloqueos (State Locking)

El esquema clásico para el backend S3 es usar DynamoDB para los locks. Pero en el caso de Cloudflare R2 no tengo esa opción, porque no es AWS.

Probé a usar:

use_lockfile = true

Ese parámetro apareció en versiones nuevas de Terraform (a partir de la 1.10) y permite usar un archivo en el bucket como mecanismo de bloqueo.

Pero en la práctica entendí algo importante:

esto no es un reemplazo completo del locking con DynamoDB.

Qué significa esto en la práctica

  • el bloqueo funciona bajo el principio de best-effort
  • no hay garantía de atomicidad completa
  • teóricamente las carreras aún son posibles

Cómo lo manejo

No confié solo en el lockfile e introduje reglas simples para mí:

  • no ejecuto terraform apply en paralelo con otros
  • procuro sacar los apply al CI/CD
  • considero el locking en R2 como protección adicional, no como garantía

Si tuviera una infraestructura crítica, haría un pipeline estricto solo en CI con un mecanismo externo de bloqueo.


Cómo migré

La migración se hizo con un solo comando:

terraform init \
  -backend-config=backend.hcl \
  -migrate-state

Terraform por sí mismo:

  1. encontró el terraform.tfstate local
  2. solicitó confirmación
  3. lo trasladó a R2

Después de eso borré el archivo local y lo añadí a .gitignore.


Qué obtuve al final

Tranquilidad

Ahora el state no está en mi máquina.

Además activé versionado en el bucket de R2 para poder retroceder si es necesario.


Trabajo en equipo

Incluso sin un locking perfecto:

  • tengo una única fuente de verdad
  • desaparecieron las preguntas «¿quién tiene el state actualizado?»

Seguridad

  • los secretos ya no están en Git
  • el acceso se regula mediante API tokens de Cloudflare
  • es posible restringir permisos

Conclusiones prácticas

Si vuelvo a configurar un backend Terraform en R2, seguro que:

  • activo versionado
  • separo entornos (prod/stage)
  • no ejecuto apply desde distintas máquinas
  • siempre que sea posible, saco los apply al CI/CD

Conclusión

Si sigo guardando el state localmente o en Git — me estoy provocando problemas a propósito.

Cloudflare R2 me dio una forma rápida de pasar a Remote State sin AWS. Sí, tiene limitaciones, especialmente en lo relativo a bloqueos, pero sigue siendo un gran paso adelante.

Para mí es uno de esos cambios infraestructurales pequeños que realmente ahorraron tiempo, nervios y me libraron de una clase de problemas que antes parecían «normales».

// Reviews

Reseñas relacionadas

Hubo varios problemas, tanto en la parte técnica como en la comprensión general. Mijaíl respondió rápido a la solicitud, ayudó a aclarar las cosas y resolvió los problemas técnicos; por ello, muchas gracias. Estoy satisfecho con el resultado.

Hubo varios problemas relacionados tanto con la parte técnica como con la comprensión en general. Mijaíl respondió rápidamente a la solicitud, ayudó a aclarar las cosas y resolvió los problemas técnicos, por lo que le …

abazawolf

Configuración de VPS, configuración del servidor

18.02.2026 · ★ 5/5

// Contact

¿Necesitas ayuda?

Escríbeme y te ayudaré a resolver el problema

Enviar solicitud
Escribir y recibir una respuesta rápida