Infraestructura, automatización y backend
Periodo: 02 mar → 25 abr 2026
Definición del proyecto
Arrancamos con una fase de planificación conjunta. La idea es diseñar e implantar la infraestructura tecnológica completa de una inmobiliaria ficticia llamada Zitadel Inmobiliaria. En esta semana inicial definimos los objetivos del proyecto, repartimos las áreas de trabajo y trazamos la arquitectura general que guiaría todo el desarrollo.
Diseñando la infraestructura: VMs, redes y almacenamiento
Mientras Iria diseña la arquitectura de red y las VLANs, yo me centro en diseñar la capa de infraestructura: qué máquinas virtuales necesitamos y qué recursos tendrá cada una.
VMs definidas para el proyecto
Definimos el mapa completo de máquinas virtuales que componen Zitadel:
| VM ID | Nombre | Función | IP |
|---|---|---|---|
| 200 | Central-Node | Nodo de gestión, Terraform, Ansible | 10.0.10.200 |
| 201 | Firewall | OPNsense (gestión de red) | — |
| 202 | Zabbix | Monitorización | 10.0.20.202 |
| 203 | WordPress | Portal web + Docker | 10.0.30.203 |
| 204 | MariaDB | Base de datos | 10.0.40.204 |
| 205 | Teampass | Gestor de credenciales | — |
| 206 | Traefik | Proxy inverso + SSL | — |
| 207 | Bastion | Acceso SSH controlado | — |
Despliegue de VMs con Terraform: infraestructura como código
Con Proxmox ya instalado y configurado por Iria, llega el momento de automatizar el aprovisionamiento de todas las máquinas virtuales con Terraform. El objetivo es que cualquier VM pueda recrearse desde cero ejecutando un solo comando.
Proveedor utilizado: bpg/proxmox
El proveedor bpg/proxmox permite comunicarse con la API de Proxmox directamente desde Terraform. Las credenciales nunca van en texto plano: la contraseña se pasa como variable de entorno marcada como sensible.
# variables.tf — gestión segura de credenciales
variable "pm_password" {
description = "Password de acceso a la API de Proxmox"
sensitive = true
}
# main.tf — proveedor y ejemplo de creación de VM Central-Node
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "0.46.4"
}
}
}
provider "proxmox" {
endpoint = "https://192.168.1.220:8006/"
username = "root@pam"
password = var.pm_password
insecure = true
}
resource "proxmox_virtual_environment_vm" "central_node" {
name = "Central-Node"
node_name = "pve"
vm_id = 200
# ... resto de configuración
}
sensitive = true en Terraform. De lo contrario, aparecen en texto plano en los logs de terraform plan y terraform apply, lo que es un riesgo de seguridad grave.Base de datos con MariaDB: diseño e implementación
Una vez la red está operativa, llega el momento de desplegar la base de datos. El motor elegido es MariaDB, una solución de código abierto derivada de MySQL, muy estable y perfectamente compatible con WordPress. MariaDB vive en la VM 204, dentro de la VLAN de base de datos (10.0.40.204), la zona más protegida de toda la red.
¿Por qué MariaDB en su propia VM?
Aislar la base de datos en su propia máquina virtual tiene varias ventajas clave: si el servidor web es comprometido, el atacante no tiene acceso directo a los datos; los recursos de CPU y RAM se asignan de forma independiente; y los backups de la VM se pueden hacer sin afectar a otros servicios.
Usuario de aplicación con mínimos privilegios
No se usa el usuario root desde WordPress. Creamos un usuario específico con solo los permisos necesarios sobre la base de datos del proyecto:
-- Usuario de aplicación (principio de mínimo privilegio)
CREATE USER 'wp_user'@'10.0.30.%' IDENTIFIED BY 'contraseña_segura';
GRANT SELECT, INSERT, UPDATE, DELETE ON zitadel.* TO 'wp_user'@'10.0.30.%';
FLUSH PRIVILEGES;
Conexión con WordPress
La base de datos de WordPress se configuró mediante variables de entorno en Docker Compose, evitando que las credenciales aparezcan en texto plano en el código fuente. La conexión entre contenedores se realiza por la red interna de Docker.
WordPress en Docker: backend, contenedores y variables de entorno
El despliegue web es una de las partes fundamentales del proyecto, ya que es cuando finalmente se prueba que todo funciona correctamente. Aunque Iria se encarga del frontend (tema, contenidos y ajustes visuales de WordPress), yo me encargo del backend técnico: preparar la VM, desplegar el stack de contenedores y asegurar que WordPress conecta correctamente con la base de datos.
Arquitectura del stack
El sistema web se divide en dos contenedores que se comunican por una red interna de Docker:
- Contenedor WordPress: basado en
wordpress:apache, sirve la web con Apache + PHP 8.2. - Contenedor MariaDB: basado en
mariadb:10.11, almacena todos los datos de WordPress.
Los datos persisten mediante volúmenes Docker: ./wp-data para los archivos de WordPress (temas, uploads) y ./db-data para los datos de la base de datos. Así, aunque se destruyan los contenedores, los datos no se pierden.
docker-compose.yml
services:
db:
image: mariadb:10.11
container_name: wp_db
restart: always
command: --skip-name-resolve # evita resolución DNS inversa → más rápido
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wpuser
MYSQL_PASSWORD: wppass
MYSQL_ROOT_PASSWORD: rootpass
volumes:
- ./db-data:/var/lib/mysql
- ./backup.sql:/docker-entrypoint-initdb.d/backup.sql # importa BD al arrancar
wordpress:
image: wordpress:php8.2-apache
container_name: wp_web
restart: always
ports:
- "80:80"
- "443:443"
extra_hosts:
- "zitadel.a24iriabc.iesteis.gal:127.0.0.1" # resolución local del dominio
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: wppass
WORDPRESS_DB_NAME: wordpress
WORDPRESS_CONFIG_EXTRA: |
define('FS_METHOD', 'direct');
define('WP_MEMORY_LIMIT', '512M');
define('WP_MAX_MEMORY_LIMIT', '512M');
define('DISABLE_WP_CRON', true);
define('WP_HOME', 'https://zitadel.a24iriabc.iesteis.gal');
define('WP_SITEURL', 'https://zitadel.a24iriabc.iesteis.gal');
/* $$ evita que Docker interprete $ como variable de entorno */
if (isset($$_SERVER['HTTP_X_FORWARDED_PROTO'])
&& $$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$$_SERVER['HTTPS'] = 'on';
}
volumes:
- ./wp-data:/var/www/html
- ./apache2/000-default-ssl.conf:/etc/apache2/sites-available/000-default-ssl.conf
- ./apache2/certs:/etc/apache2/ssl
depends_on:
- db
command: >
bash -c "
a2enmod ssl rewrite headers &&
a2ensite 000-default-ssl &&
chown -R www-data:www-data /var/www/html &&
docker-entrypoint.sh apache2-foreground
"
Adaptación para proxy inverso (Traefik + HTTPS)
Como el tráfico llega a WordPress a través de Traefik (proxy inverso con SSL), fue necesario añadir la variable $_SERVER['HTTPS'] = 'on' para que WordPress entienda que está sirviendo bajo HTTPS, aunque el contenedor reciba la petición en HTTP por la red interna. Sin esto, WordPress generaba bucles de redirección o rompía los recursos CSS/JS.
Ansible: automatizando la configuración de toda la infraestructura
Con Terraform ya se crean las VMs. Ahora toca Ansible para configurarlas: instalar paquetes, copiar archivos de configuración y levantar servicios.
Inventario (inventory.ini)
El inventario define los grupos de hosts y las variables de conexión. Ansible entra en las máquinas usando las llaves SSH que Terraform inyectó al crear las VMs:
[all:vars]
ansible_user = admin
ansible_ssh_private_key_file = ~/.ssh/id_rsa
[zabbix]
zabbix ansible_host=10.0.20.202
[wordpress]
wordpress ansible_host=10.0.30.203
[mariadb]
mariadb ansible_host=10.0.40.204
playbook.yml — estructura general
El playbook está dividido en cinco bloques:
| # | Bloque | Hosts | Qué hace |
|---|---|---|---|
| 1 | Preparación | localhost | Clona el repositorio de GitHub y asegura que rsync está disponible |
| 2 | Docker | all | Instala Docker Engine + Compose plugin en todas las VMs |
| 3 | MariaDB | mariadb | Despliega dos bases de datos: WordPress y Zabbix |
| 4 | WordPress | wordpress | Sincroniza el repo, genera el compose e inicia el contenedor web |
| 5 | Zabbix | zabbix | Despliega server, frontend web y agente de Zabbix |
terraform apply crea las VMs → ansible-playbook playbook.yml clona el repo, instala Docker en todas las máquinas, levanta MariaDB con los datos importados, despliega WordPress contra la BD remota y deja Zabbix completamente operativo. Todo desde un solo comando.Control de versiones: cómo hemos gestionado el repositorio del proyecto
La gestión del repositorio es una tarea que cruza todo el proyecto. Como responsable del control de versiones, me encargué de establecer el flujo de trabajo en Git y mantener el repositorio organizado y operativo.
Estructura actual del repositorio
iac-deployment-lab/
├── terraform/
│ ├── main.tf # Proveedor Proxmox y definición de VMs
│ ├── variables.tf # Variables (contraseñas marcadas como sensitive)
│ └── modules/
│ └── vm/
│ ├── main.tf
│ └── variables.tf
├── ansible/
│ ├── inventory.ini # Inventario de hosts por VLAN
│ └── playbook.yml # Configuración de los servidores
└── wordpress-docker-proyecto/ # Submódulo: stack web dockerizado
└── docker-compose.yml
...

