DEV Community

Cover image for Implementar un sitio web estático en Cloudflare Pages usando Terraform y Wrangler CLI
Afu Tse (Chainiz)
Afu Tse (Chainiz)

Posted on

Implementar un sitio web estático en Cloudflare Pages usando Terraform y Wrangler CLI

En este tutorial, aprenderá a implementar un sitio web estático en Cloudflare Pages usando Terraform para el aprovisionamiento de infraestructura y Wrangler CLI para la implementación manual.

Este enfoque le permite administrar su proyecto de Cloudflare Pages como Infraestructura como Código (IaC), manteniendo un proceso de implementación simple y flexible.


Qué aprenderás

Al finalizar este tutorial, podrás:

  • Aprovisionar un proyecto de Cloudflare Pages con Terraform
  • Implementar un sitio web estático con la CLI de Wrangler
  • Configurar un dominio personalizado (opcional)
  • Administrar tu infraestructura de forma limpia y reproducible
  • Destruir todos los recursos de forma segura cuando ya no sean necesarios

¿Por qué Cloudflare Pages + Terraform?

Cloudflare Pages ofrece una plataforma rápida, global y sin servidor para alojar sitios web estáticos.

Terraform te permite definir y versionar tu infraestructura, lo que garantiza la consistencia y repetibilidad de tus implementaciones.

La combinación de ambas herramientas te ofrece:

  • Infraestructura como Código
  • CDN global rápida
  • Implementación sencilla de sitios estáticos
  • Gestión sencilla de dominios
  • Separación clara entre infraestructura y aplicación

Requisitos Previos

Antes de comenzar, asegúrese de tener:

  1. Terraform instalado (versión 1.10.0 o superior)
  2. Cuenta de Cloudflare con acceso a Pages
  3. API Token de Cloudflare con permisos de Cloudflare Pages
  4. Node.js y npm instalados (para Wrangler CLI)

Estructura del Proyecto

cloudflare-tf-staticweb/
└── infrastructure/           # Carpeta con archivos terraform
    ├── main.tf               # Configuración de Terraform
    ├── providers.tf          # Configuración de providers
    ├── variables.tf          # Definición de variables
    ├── cloudflare.tf         # Recursos de Cloudflare Pages
    ├── outputs.tf            # Outputs del proyecto
    ├── terraform.tfvars      # Variables (no versionar)
└── website/                  # Carpeta con el sitio web estático
    └── index.html            # Contiene el HTLM de la página principal
    └── styles.css            # Contiene el CSS de la página principal
    └── script.js             # Contiene el JS de la página principal
Enter fullscreen mode Exit fullscreen mode

Variables

Variable Descripción Requerida Default
cloudflare_api_token API Token de Cloudflare -
cloudflare_account_id Account ID de Cloudflare -
project_name Nombre del proyecto No "my-website"
custom_domain Dominio personalizado No ""

Configuración Inicial

1. Crear el Proyecto

# Crear la estructura de carpetas
mkdir cloudflare-tf-staticweb
cd cloudflare-tf-staticweb
Enter fullscreen mode Exit fullscreen mode

2. Configurar la Infraestructura

En la carpeta "cloudflare-tf-staticweb"

# Crear la carpeta de la infraestructura
mkdir infrastructure

# Accede a la carpeta infraestructura
cd infrastructure
Enter fullscreen mode Exit fullscreen mode
# Crear el archivo "main.tf"
cat <<EOF > main.tf
terraform {
  required_version = ">= 1.10.0"

  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 4.0"
    }
  }
}
EOF
Enter fullscreen mode Exit fullscreen mode
# Crear el archivo "provider.tf"
cat <<EOF > provider.tf
provider "cloudflare" {
  api_token = var.cloudflare_api_token
}
EOF
Enter fullscreen mode Exit fullscreen mode
# Crear el archivo "variables.tf"
cat <<EOF > variables.tf
variable "cloudflare_api_token" {
  description = "The API token for Cloudflare account"
  type        = string
  sensitive   = true
}

variable "cloudflare_account_id" {
  description = "Cloudflare Account ID (visible on dashboard)"
  type        = string
}

variable "project_name" {
  description = "Project name in Cloudflare Pages"
  type        = string
  default     = "my-website"
}

variable "custom_domain" {
  description = "Custom domain (optional, leave blank if not used)"
  type        = string
  default     = ""
}
EOF
Enter fullscreen mode Exit fullscreen mode
# Crear el archivo "outputs.tf"
cat <<EOF > outputs.tf
output "pages_project_url" {
  description = "Full URL of the Cloudflare Pages project"
  value       = "https://${cloudflare_pages_project.website.subdomain}"
}

output "pages_project_subdomain" {
  description = "Subdomain assigned by Cloudflare Pages"
  value       = cloudflare_pages_project.website.subdomain
}

output "project_id" {
  description = "Cloudflare project ID"
  value       = cloudflare_pages_project.website.id
}

output "project_name" {
  description = "Project Name"
  value       = cloudflare_pages_project.website.name
}

output "custom_domain_url" {
  description = "Custom domain URL (if configured)"
  value       = var.custom_domain != "" ? "https://${var.custom_domain}" : "Not configured"
}
EOF
Enter fullscreen mode Exit fullscreen mode
# Crear el archivo "cloudflare.tf"
cat <<EOF > cloudflare.tf
resource "cloudflare_pages_project" "website" {
  account_id        = var.cloudflare_account_id
  name              = var.project_name
  production_branch = "main"

  build_config {
    build_command   = ""        # No build required for static HTML
    destination_dir = "website" # Folder containing index.html
    root_dir        = ""        # Repository root
  }

  # Environment variables (if needed in the future)
  deployment_configs {
    production {
      environment_variables = {
        ENVIRONMENT = "production"
      }
    }

    preview {
      environment_variables = {
        ENVIRONMENT = "preview"
      }
    }
  }

}

# Custom domain (optional)
resource "cloudflare_pages_domain" "custom_domain" {
  count        = var.custom_domain != "" ? 1 : 0
  account_id   = var.cloudflare_account_id
  project_name = cloudflare_pages_project.website.name
  domain       = var.custom_domain
}
EOF
Enter fullscreen mode Exit fullscreen mode

3. Configurar la pagina web

En la carpeta "cloudflare-tf-staticweb"

# Crear la carpeta del sitio web
mkdir website

# Accede a la del sitio web
cd website
Enter fullscreen mode Exit fullscreen mode
# Crear el archivo "index.html"
cat > index.html << 'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple Web App</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h1 id="greeting">Hello, World!</h1>
        <input type="text" id="nameInput" placeholder="Enter your name">
        <button id="updateBtn">Update Greeting</button>
    </div>
    <script src="script.js"></script>
</body>
</html>
EOF
Enter fullscreen mode Exit fullscreen mode
# Crear el archivo "styles.css"
cat > styles.css << 'EOF'
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
}

.container {
    background: white;
    padding: 2rem;
    border-radius: 10px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
    text-align: center;
    max-width: 400px;
    width: 90%;
}

h1 {
    color: #333;
    margin-bottom: 1.5rem;
    font-size: 2rem;
}

input {
    padding: 0.8rem;
    width: 100%;
    margin-bottom: 1rem;
    border: 2px solid #ddd;
    border-radius: 5px;
    font-size: 1rem;
}

input:focus {
    outline: none;
    border-color: #2575fc;
}

button {
    background: #2575fc;
    color: white;
    border: none;
    padding: 0.8rem 1.5rem;
    border-radius: 5px;
    cursor: pointer;
    font-size: 1rem;
    transition: background 0.3s;
}

button:hover {
    background: #1a68e8;
}
EOF
Enter fullscreen mode Exit fullscreen mode
# Crear el archivo "script.js"
cat > script.js << 'EOF'
// Get DOM elements
const greetingElement = document.getElementById('greeting');
const nameInput = document.getElementById('nameInput');
const updateButton = document.getElementById('updateBtn');

// Update greeting when button is clicked
updateButton.addEventListener('click', () => {
    const name = nameInput.value.trim();

    if (name) {
        greetingElement.textContent = `Hello, ${name}!`;
        nameInput.value = ''; // Clear input
    } else {
        greetingElement.textContent = 'Please enter your name!';
        setTimeout(() => {
            greetingElement.textContent = 'Hello, World!';
        }, 2000);
    }
});

// Also update on Enter key press
nameInput.addEventListener('keypress', (e) => {
    if (e.key === 'Enter') {
        updateButton.click();
    }
});
EOF
Enter fullscreen mode Exit fullscreen mode

4. Obtener tu Account ID en Cloudflare

  1. Ve al Cloudflare Dashboard → Account Home
  2. Click en los 3 puntos la lado del "Account Name"
  3. Click en "Copy account ID"

    Get Account ID

5. Crear API Token en Cloudflare

  1. Ve a Cloudflare Dashboard → Manage Account → Account API Tokens
  2. Click en "Create Token""Create Custom Token"
  3. Configura los permisos necesarios:

    Token name: Terraform Cloudflare Pages
    
    Permissions:
    ├── Account
    │   ├── Cloudflare Pages → Edit
    │   └── Account Settings → Read
    └── Zone (opcional, solo si usas dominio personalizado)
        └── DNS → Edit
    
    Zone Resources:
    └── Include → All zones from an account → Your_Account
    

    Create Custom Token

  4. Click en "Continue to summary""Create Token"

  5. Copia el token inmediatamente (solo se muestra una vez)

6. Actualizar Configuración

Crear el archivos de variables y asignar los valores

  • cloudflare_account_id obtenido del paso 4
  • cloudflare_api_token obtenido del paso 5
# Crear el archivo "terraform.tfvars"
cat <<EOF > terraform.tfvars
# Cloudflare Account ID
cloudflare_account_id = "your-account-id-here"


# Cloudflare API Token
cloudflare_api_token = "your-token"

# Project name
project_name = "my-website"

# Custom domain (optional, leave blank if not used)
custom_domain = ""
EOF
Enter fullscreen mode Exit fullscreen mode

Uso

Crear la Infraestructura con Terraform

Accede a la carpeta infraestructura

cd infrastructure
Enter fullscreen mode Exit fullscreen mode

Inicializar Terraform

terraform init
Enter fullscreen mode Exit fullscreen mode

Validar la configuración

terraform validate
terraform fmt
Enter fullscreen mode Exit fullscreen mode

Planificar cambios

terraform plan
Enter fullscreen mode Exit fullscreen mode

Aplicar cambios

terraform apply -auto-approve
Enter fullscreen mode Exit fullscreen mode

Esto creará el proyecto de Cloudflare Pages, pero aún no habrá contenido desplegado.

Ver outputs

terraform output
Enter fullscreen mode Exit fullscreen mode

Desplegar el Sitio Web con Wrangler

Una vez que Terraform haya creado el proyecto, despliega tu sitio:

1. Instalar Wrangler (solo la primera vez)

npm install -g wrangler
Enter fullscreen mode Exit fullscreen mode

2. Autenticar con Cloudflare

wrangler login
Enter fullscreen mode Exit fullscreen mode

Esto abrirá un navegador para que autorices Wrangler.

3. Desplegar el sitio

Desde la raíz del proyecto

wrangler pages deploy website --project-name=my-website
Enter fullscreen mode Exit fullscreen mode

Reemplaza my-website con el valor de tu variable project_name.

4. Verificar el despliegue

Visita la URL mostrada en el output de Terraform o en el resultado del comando deploy:

terraform output pages_project_url

pages_project_url = "https://my-website-xxx.pages.dev"
Enter fullscreen mode Exit fullscreen mode

website

Despliegues Futuros

Para actualizar tu sitio después de hacer cambios:

  1. Edita tus archivos en website/
  2. Despliega de nuevo
wrangler pages deploy website --project-name=my-website
Enter fullscreen mode Exit fullscreen mode

Reemplaza my-website con el valor de tu variable project_name.


Dominio Personalizado

Para agregar un dominio personalizado:

  1. Actualiza terraform.tfvars:

    custom_domain = "www.tudominio.com"
    
  2. Asegúrate de que el dominio esté en Cloudflare

  3. Aplica los cambios

    terraform apply
    

Destruir Recursos

terraform destroy -auto-approve
Enter fullscreen mode Exit fullscreen mode

Recursos Adicionales

Top comments (0)