Tutorial

OpenTofu: gestione su flota de VPS con Infrastructure as Code

Automatización10 min de lectura7 pasos

Usted gestiona diez VPS, luego veinte, y cada nuevo servidor exige la misma lista de comprobación manual: pedido, red, Docker, reverse proxy, certificado. Un paso olvidado en el orden y la entrega se cae. OpenTofu, el fork open source de Terraform alojado bajo la CNCF, invierte esta lógica: usted describe el estado objetivo de su infraestructura en HCL, ejecuta `tofu apply` y la herramienta calcula el delta entre lo que existe y lo que debe existir. Esta guía cubre el aprovisionamiento de VPS —la creación, la actualización y la destrucción de servidores— como complemento de la configuración de sistema que Ansible ya gestiona.

Contenido· Por qué OpenTofu en lugar de seguir con SSH manual1/9
  1. 01Por qué OpenTofu en lugar de seguir con SSH manual
  2. 02Lo que gana con un estado declarativo
  3. 03Requisitos previos antes de empezar
  4. 04Implementar OpenTofu en una flota de VPS
  5. 05Separe los workspaces por entorno
  6. 06Ansible y OpenTofu: la frontera entre ambos
  7. 07Solución de problemas: los errores frecuentes
  8. 08Errores comunes y su corrección
  9. 09Su infraestructura se convierte en código versionado

Por qué OpenTofu en lugar de seguir con SSH manual

Hasta cinco o seis clientes, la gestión manual aguanta: usted recuerda qué se ejecuta dónde y la lista de puesta en servicio se sabe de memoria. Más allá, la memoria se convierte en un riesgo operativo. Un VPS aprovisionado a mano no tiene un estado legible: usted no sabe, sin conectarse, si el firewall está configurado, si Docker tiene la versión esperada o si ese servidor sigue formando parte de la rotación.

OpenTofu resuelve un problema distinto al de Ansible. Ansible gestiona la *configuración* de un servidor que ya existe: lo que se ejecuta en él, los archivos presentes, los servicios arrancados. OpenTofu gestiona el *ciclo de vida* del servidor mismo: creación, actualización de atributos, destrucción. Mantiene un archivo de estado (terraform.tfstate) que sabe exactamente qué está aprovisionado y qué ya no lo está. Ambas herramientas son complementarias: OpenTofu aprovisiona, Ansible configura.

En agosto de 2023, HashiCorp cambió la licencia de Terraform de MPL-2.0 a BUSL-1.1, una licencia no libre que prohíbe ciertos usos comerciales. La comunidad respondió creando OpenTofu, un fork compatible con el HCL de las versiones anteriores a Terraform 1.6, hoy alojado bajo la CNCF (Cloud Native Computing Foundation) y la Linux Foundation. El comando es tofu, no terraform, pero los archivos .tf y la lógica son idénticos.

Lo que gana con un estado declarativo

  • Inventario fiable — el archivo terraform.tfstate dice exactamente qué servidores existen, con qué IP y qué atributos, sin tener que conectarse a cada uno.
  • Reproducibilidad — un nuevo cliente o un nuevo proyecto recibe el mismo VPS configurado de la misma forma, desde el mismo archivo .tf versionado en Git.
  • Destrucción limpiatofu destroy retira los recursos en el orden correcto, sin dejar servidores huérfanos que se siguen facturando.
  • Diff legibletofu plan muestra exactamente lo que se creará, modificará o destruirá antes de actuar, como un git diff de su infraestructura.
  • Complementariedad con Ansible — OpenTofu crea el VPS y coloca los metadatos (clave SSH, nombre, red); Ansible toma el relevo para desplegar Docker, Nginx y sus aplicaciones.
  • Versionable y auditable — su infraestructura se convierte en un repositorio Git con commits, revisiones de código y un historial de cambios.
  • Licencia open source duradera — OpenTofu está bajo MPL-2.0, sin restricción comercial, con una gobernanza comunitaria bajo la CNCF.

Requisitos previos antes de empezar

Esta guía supone que dispone de un VPS con acceso root e IPv4 dedicada para ejecutar sus cargas de trabajo, y de un equipo de desarrollo (macOS, Linux o Windows con WSL2) desde el que lanza tofu. OpenTofu no se ejecuta en el VPS de destino: corre localmente y habla con la API del proveedor o con el daemon Docker del servidor.

Para seguir los ejemplos necesita: OpenTofu instalado en local (consulte opentofu.org/docs/intro/install), un acceso API o credenciales SSH hacia el VPS de destino, y Git para versionar sus archivos .tf. No se requiere ninguna dependencia adicional — OpenTofu descarga él mismo los providers en el tofu init.

Para pilotar Docker en un VPS remoto mediante OpenTofu, el daemon Docker del servidor debe escuchar en su socket Unix (por defecto) o en un puerto TCP seguro. El provider kreuzwerker/docker se conecta a ese socket por SSH o TCP.

Implementar OpenTofu en una flota de VPS

  1. Instalar OpenTofu en local

    Diríjase a opentofu.org/docs/intro/install para las instrucciones según su OS. En macOS con Homebrew: brew install opentofu. En Debian/Ubuntu: el repositorio oficial de OpenTofu proporciona el paquete opentofu. Verifique la instalación con tofu version — el comando debe devolver la versión instalada.

  2. Estructurar su proyecto Infrastructure as Code

    Cree un directorio dedicado y cuatro archivos estándar.

    # main.tf — recursos principales
    # variables.tf — declaraciones de variables
    # outputs.tf — valores expuestos tras el apply
    # terraform.tfvars — valores concretos (añadir a gitignore si son secretos)

    Esta estructura no es obligatoria para OpenTofu, pero es la convención ampliamente adoptada: main.tf contiene los recursos, variables.tf declara los tipos y valores por defecto, outputs.tf expone lo que Ansible u otra herramienta debe leer tras el aprovisionamiento (IP del servidor, nombre de host…), y terraform.tfvars contiene los valores concretos que no desea codificar de forma fija en main.tf.

  3. Declarar el provider y generar una clave SSH

    OpenTofu instala los providers necesarios en el tofu init. El provider hashicorp/tls genera un par de claves SSH en local, lo que evita gestionar claves manualmente.

    terraform {
      required_providers {
        tls = {
          source  = "hashicorp/tls"
          version = "~> 4.0"
        }
      }
    }
    
    resource "tls_private_key" "vps_key" {
      algorithm = "ED25519"
    }
    
    output "private_key_pem" {
      value     = tls_private_key.vps_key.private_key_pem
      sensitive = true
    }

    Lance tofu init para descargar el provider y luego tofu apply para generar la clave. Recupérela con tofu output -raw private_key_pem > ~/.ssh/vps_key && chmod 600 ~/.ssh/vps_key.

  4. Aprovisionar el VPS con null y local-exec

    Si su proveedor de VPS no tiene un provider OpenTofu oficial, el provider hashicorp/null con un local-exec permite ejecutar un comando local (una llamada API con curl, un script shell) y modelar el recurso en el state.

    resource "null_resource" "vps_provision" {
      triggers = {
        server_name = var.server_name
      }
    
      provisioner "local-exec" {
        command = <<EOT
          curl -s -X POST https://api.votre-fournisseur.com/v1/servers \
            -H "Authorization: Bearer ${var.api_token}" \
            -d '{"name": "${var.server_name}", "image": "ubuntu-22.04"}'
        EOT
      }
    }

    Este patrón es adecuado para una fase transitoria. Si su proveedor expone una API REST, basta con un script shell llamado en local-exec para crear el servidor y escribir su IP en un archivo que outputs.tf expondrá después.

  5. Pilotar Docker en el VPS con el provider kreuzwerker

    Una vez aprovisionado el VPS e instalado Docker (por Ansible, normalmente), el provider kreuzwerker/docker le permite declarar contenedores, redes y volúmenes en OpenTofu.

    terraform {
      required_providers {
        docker = {
          source  = "kreuzwerker/docker"
          version = "~> 3.0"
        }
      }
    }
    
    provider "docker" {
      host = "ssh://root@${var.server_ip}:22"
    }
    
    resource "docker_container" "app" {
      name  = "mon-app"
      image = docker_image.app.image_id
    }
    
    resource "docker_image" "app" {
      name = "nginx:alpine"
    }

    El provider se conecta al daemon Docker del VPS por SSH — ningún puerto TCP adicional que abrir. La versión estable del provider está disponible en el Terraform Registry.

  6. Versionar el state para un equipo

    En desarrollo en solitario, el state local (terraform.tfstate) basta. En equipo o en CI/CD, dos desarrolladores que lanzan tofu apply a la vez corrompen el state. La solución es un backend remoto con bloqueo.

    OpenTofu soporta de forma nativa S3 (AWS, MinIO autoalojado) y el GitLab Managed Terraform State. Con un bucket MinIO en un VPS:

    terraform {
      backend "s3" {
        bucket                      = "tofu-state"
        key                         = "production/terraform.tfstate"
        region                      = "eu-west-1"
        endpoint                    = "https://minio.votre-domaine.com"
        skip_credentials_validation = true
        skip_metadata_api_check     = true
        skip_region_validation      = true
        force_path_style            = true
      }
    }

    El bloqueo es automático: si hay un tofu apply en curso, un segundo se rechaza hasta que termine el primero.

  7. Integrar OpenTofu en su pipeline CI/CD

    Un pipeline típico de Woodpecker CI o Forgejo Actions ejecuta tofu plan en cada pull request (para revisión humana del diff de infraestructura) y tofu apply al hacer merge en la rama principal.

    steps:
      - name: tofu-plan
        image: ghcr.io/opentofu/opentofu:latest
        commands:
          - tofu init
          - tofu plan -out=tfplan
    
      - name: tofu-apply
        image: ghcr.io/opentofu/opentofu:latest
        commands:
          - tofu apply tfplan
        when:
          branch: main
          event: push

    El state remoto (paso anterior) es indispensable aquí: el runner de CI no tiene acceso al state local de su equipo.

Separe los workspaces por entorno

OpenTofu ofrece los workspaces para aislar varios estados en el mismo backend: tofu workspace new staging crea un espacio aislado y tofu workspace select production cambia a producción. Es más ligero que duplicar los directorios .tf. En la práctica, un workspace por cliente o por entorno (staging, prod) evita que un tofu destroy en staging afecte a producción. Nombre sus recursos con ${terraform.workspace} para que sigan siendo distintos en el state.

Ansible y OpenTofu: la frontera entre ambos

La pregunta surge a menudo: si Ansible ya hace el trabajo, ¿para qué añadir otra herramienta? La frontera es nítida una vez que se plantea con claridad.

OpenTofu responde a «¿qué existe?»: crea el servidor, le asigna una IP, coloca una clave SSH, registra su estado. Si lo elimina de su archivo .tf y lanza tofu apply, el servidor desaparece — OpenTofu gobierna el ciclo de vida.

Ansible responde a «¿en qué estado está lo que existe?»: instala Docker, configura Nginx, deja un archivo .env, reinicia un servicio. Si el servidor ya está ahí, Ansible hace con él lo que usted le pida — pero si no está, Ansible no puede crearlo.

El flujo natural para una agencia: OpenTofu aprovisiona el VPS y expone su IP como output, un playbook de Ansible consume ese output mediante un inventario dinámico, configura el servidor y despliega las aplicaciones. El artículo Ansible: automatizar la configuración de sus servidores VPS cubre la parte de configuración en detalle.

Solución de problemas: los errores frecuentes

Tres situaciones se repiten con regularidad cuando se adopta OpenTofu en una flota existente.

Errores comunes y su corrección

  • Error acquiring the state lock — un fallo durante un apply deja un archivo .terraform.tfstate.lock.info en el backend. OpenTofu se niega a continuar mientras exista el bloqueo. Tras comprobar que ningún otro apply está en curso, elimine el bloqueo con tofu force-unlock <LOCK_ID> (el ID aparece en el mensaje de error). En un backend S3/MinIO, el archivo es visible en el bucket.
  • tofu plan muestra un destroy + create inesperado — algunos atributos de un recurso fuerzan una recreación (force new resource) cuando cambian: el nombre del servidor, el tipo de imagen del OS, la región. Si modifica uno de esos atributos, OpenTofu no puede hacer una actualización en el sitio — destruye y vuelve a crear. Lea el plan con atención antes de aplicar y utilice tofu plan -target=resource.name para limitar el alcance.
  • State perdido o desincronizado — si el archivo de state se pierde y los servidores siguen existiendo, tofu state list enumera lo que OpenTofu cree aprovisionado, y tofu import <resource.type.name> <id-externe> importa un recurso existente en el state sin volver a crearlo. Es la herramienta de recuperación cuando la realidad y el state han divergido.
  • Provider no encontrado tras tofu init — compruebe que el source del provider es exacto (p. ej. kreuzwerker/docker y no docker/docker) y que tiene acceso a internet desde la máquina que lanza tofu init. En un entorno air-gapped, descargue los providers por adelantado y utilice plugin_cache_dir.
  • Error: No valid credential sources found — OpenTofu no encuentra las credenciales del provider. Compruebe las variables de entorno que espera el provider (a menudo TF_VAR_api_token o un archivo de credenciales específico) y que terraform.tfvars se lee correctamente (debe estar en el mismo directorio que main.tf).

Su infraestructura se convierte en código versionado

OpenTofu no sustituye a SSH: hace que SSH sea excepcional. El flujo diario pasa a ser: modificar un archivo .tf, lanzar tofu plan para leer el diff, validar, lanzar tofu apply. Los servidores que ya no tiene que gestionar se destruyen con tofu destroy y desaparecen de la facturación.

Para una agencia que supera la decena de clientes, es la palanca que hace pasar la gestión de infraestructura de un trabajo de memoria a un trabajo de código. Un VPS Cloud ServOrbit con acceso root, IPv4 dedicada y elección de OS es la unidad base que sus archivos .tf aprovisionan y destruyen a demanda. Su infraestructura se convierte en código versionado.

Un VPS Cloud listo para OpenTofu

Acceso root, IPv4 dedicada y elección de OS: un VPS Cloud ServOrbit es la unidad base que sus archivos `.tf` aprovisionan y destruyen a demanda.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva