ANSIBLE — AUTOMATIZACION SIN AGENTE VIA SSH Nodo de Control Playbooks Inventario Roles ansible-playbook SSH Servidores Web nginx, deploy app Servidores BD mysql, respaldos Balanceadores haproxy, certs Flujo de Ejecucion del Playbook 1. Recopilar Facts (modulo setup) 2. Ejecutar Tareas (apt, copy, service) 3. Notificar Handlers (reiniciar servicios) 4. Reportar Resultados (ok/changed/failed) Idempotente — seguro de ejecutar multiples veces Automatizacion push: sin agentes necesarios en los hosts gestionados

Iniciar sesion en docenas de servidores uno por uno para instalar paquetes, editar archivos de configuracion y reiniciar servicios es tedioso y propenso a errores. Un paso olvidado en un servidor genera desviacion de configuracion, y de repente tus servidores “identicos” se comportan de manera diferente. Ansible resuelve esto permitiendote definir toda la configuracion de tu servidor en archivos YAML simples y aplicarla consistentemente en cientos de maquinas con un solo comando. Como Ansible no requiere agente y se comunica por SSH, no hay nada que instalar en tus servidores gestionados — si puedes conectarte por SSH a un host, Ansible puede gestionarlo.

Que Es Ansible?

Ansible es una herramienta de automatizacion de codigo abierto creada por Red Hat que gestiona la configuracion de servidores, el despliegue de aplicaciones y la orquestacion. A diferencia de herramientas que requieren un agente dedicado ejecutandose en cada servidor gestionado, Ansible usa SSH para conectarse a hosts remotos y ejecutar tareas.

Caracteristicas principales:

  • Sin agente — No hay software que instalar o mantener en los nodos gestionados. Ansible usa conexiones SSH existentes
  • Basado en push — El nodo de control envia configuraciones a los hosts gestionados bajo demanda, en lugar de que los hosts consulten un servidor central
  • Idempotente — Ejecutar un playbook multiples veces produce el mismo resultado. Ansible verifica el estado actual antes de hacer cambios
  • Basado en YAML — Los playbooks se escriben en YAML legible por humanos, haciendolos accesibles para cualquiera que pueda leer un archivo de configuracion
  • Extensible — Miles de modulos integrados para gestionar paquetes, archivos, servicios, recursos cloud y mas

Como Funciona Ansible

Ansible sigue un modelo de ejecucion directo:

  1. Escribes un playbook (archivo YAML) que describe el estado deseado de tus servidores
  2. Defines un inventario listando que hosts gestionar
  3. Ejecutas ansible-playbook, y Ansible se conecta a cada host por SSH
  4. Ansible transfiere pequenos programas llamados modulos al host remoto
  5. Los modulos se ejecutan, aplican el estado deseado y reportan resultados
  6. Ansible elimina los modulos y muestra un resumen

Ningun demonio se ejecuta en los hosts gestionados. Ninguna base de datos rastrea el estado. Cada ejecucion de playbook es autocontenida.

Requisitos Previos

Antes de comenzar, asegurate de tener:

  • Una maquina Ubuntu 22.04 o 24.04 como nodo de control (donde se ejecuta Ansible)
  • Uno o mas servidores destino accesibles via SSH
  • Autenticacion SSH basada en claves configurada entre el nodo de control y los hosts gestionados
  • Python 3 instalado en todos los nodos gestionados (preinstalado en la mayoria de distribuciones Linux)
  • Una cuenta de usuario con privilegios sudo en los hosts gestionados

Consejo: Si aun no has configurado la autenticacion SSH por claves, sigue nuestra guia de endurecimiento SSH para configurar acceso seguro basado en claves antes de continuar.

Instalar Ansible en Ubuntu

Usando el gestor de paquetes del sistema

sudo apt update
sudo apt install ansible -y

Usando pip (recomendado para la ultima version)

sudo apt install python3-pip python3-venv -y
python3 -m venv ~/ansible-venv
source ~/ansible-venv/bin/activate
pip install ansible

Verificar la instalacion

ansible --version

Deberias ver una salida mostrando la version de Ansible, la ruta del archivo de configuracion y la version de Python:

ansible [core 2.16.x]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules']
  python version = 3.12.x

Archivos de Inventario

El inventario le indica a Ansible que hosts gestionar. Puedes escribir inventarios en formato INI o YAML.

Formato INI (simple)

# inventory.ini
[webservers]
web1.example.com
web2.example.com
192.168.1.50

[dbservers]
db1.example.com ansible_port=2222
db2.example.com

[loadbalancers]
lb1.example.com

[production:children]
webservers
dbservers
loadbalancers

[all:vars]
ansible_user=deployer
ansible_ssh_private_key_file=~/.ssh/id_ed25519

Formato YAML

# inventory.yml
all:
  vars:
    ansible_user: deployer
    ansible_ssh_private_key_file: ~/.ssh/id_ed25519
  children:
    webservers:
      hosts:
        web1.example.com:
        web2.example.com:
        192.168.1.50:
    dbservers:
      hosts:
        db1.example.com:
          ansible_port: 2222
        db2.example.com:
    loadbalancers:
      hosts:
        lb1.example.com:
    production:
      children:
        webservers:
        dbservers:
        loadbalancers:

Probar conectividad

Verifica que Ansible puede alcanzar todos los hosts:

ansible all -m ping -i inventory.ini

Salida esperada para una conexion exitosa:

web1.example.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Tu Primer Playbook

Un playbook es un archivo YAML que contiene uno o mas “plays.” Cada play apunta a un grupo de hosts y define tareas a ejecutar.

Instalar y configurar nginx

# site.yml
---
- name: Configurar servidores web
  hosts: webservers
  become: true

  tasks:
    - name: Actualizar cache de apt
      apt:
        update_cache: true
        cache_valid_time: 3600

    - name: Instalar nginx
      apt:
        name: nginx
        state: present

    - name: Copiar configuracion de nginx
      copy:
        src: files/nginx.conf
        dest: /etc/nginx/sites-available/default
        owner: root
        group: root
        mode: "0644"
      notify: Reiniciar nginx

    - name: Habilitar sitio nginx
      file:
        src: /etc/nginx/sites-available/default
        dest: /etc/nginx/sites-enabled/default
        state: link
      notify: Reiniciar nginx

    - name: Asegurar que nginx esta ejecutandose y habilitado
      service:
        name: nginx
        state: started
        enabled: true

  handlers:
    - name: Reiniciar nginx
      service:
        name: nginx
        state: restarted

Ejecutar el playbook:

ansible-playbook -i inventory.ini site.yml

Ejecutar con salida detallada para depuracion:

ansible-playbook -i inventory.ini site.yml -v

Realizar una ejecucion en seco para ver que cambiaria sin aplicar:

ansible-playbook -i inventory.ini site.yml --check --diff

Modulos de Ansible

Los modulos son las unidades de trabajo en Ansible. Cada modulo maneja una tarea especifica. Aqui estan los modulos mas utilizados:

Gestion de paquetes (apt)

- name: Instalar multiples paquetes
  apt:
    name:
      - nginx
      - curl
      - ufw
      - fail2ban
    state: present
    update_cache: true

- name: Eliminar un paquete
  apt:
    name: apache2
    state: absent
    purge: true

Gestion de servicios (service)

- name: Iniciar y habilitar un servicio
  service:
    name: nginx
    state: started
    enabled: true

- name: Reiniciar un servicio
  service:
    name: mysql
    state: restarted

Gestion de archivos (copy, template, file)

- name: Copiar un archivo al host remoto
  copy:
    src: files/app.conf
    dest: /etc/app/app.conf
    owner: www-data
    group: www-data
    mode: "0644"

- name: Desplegar una plantilla con variables
  template:
    src: templates/vhost.conf.j2
    dest: /etc/nginx/sites-available/myapp.conf
    owner: root
    group: root
    mode: "0644"

- name: Crear un directorio
  file:
    path: /var/www/myapp
    state: directory
    owner: www-data
    group: www-data
    mode: "0755"

Ejecucion de comandos (command, shell)

- name: Ejecutar un comando
  command: /usr/bin/myapp --init
  args:
    creates: /var/lib/myapp/initialized

- name: Ejecutar un comando shell con pipes
  shell: cat /var/log/syslog | grep error | wc -l
  register: error_count
  changed_when: false

Gestion de usuarios (user)

- name: Crear un usuario de despliegue
  user:
    name: deployer
    groups: sudo,www-data
    shell: /bin/bash
    create_home: true
    state: present

- name: Agregar clave SSH autorizada
  authorized_key:
    user: deployer
    key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
    state: present

Variables y Facts

Las variables hacen tus playbooks flexibles y reutilizables. Ansible soporta varias fuentes de variables.

Definir variables en playbooks

---
- name: Desplegar aplicacion
  hosts: webservers
  become: true
  vars:
    app_name: myapp
    app_port: 8080
    app_user: www-data
    packages:
      - nginx
      - python3
      - python3-pip

  tasks:
    - name: Instalar paquetes requeridos
      apt:
        name: "{{ packages }}"
        state: present

    - name: Crear directorio de la aplicacion
      file:
        path: "/var/www/{{ app_name }}"
        state: directory
        owner: "{{ app_user }}"
        mode: "0755"

Variables de grupo y de host

Crea directorios para variables especificas por grupo y por host:

project/
  inventory.ini
  group_vars/
    all.yml
    webservers.yml
    dbservers.yml
  host_vars/
    web1.example.com.yml
    db1.example.com.yml
  playbook.yml
# group_vars/webservers.yml
http_port: 80
https_port: 443
document_root: /var/www/html
max_workers: 4
# host_vars/web1.example.com.yml
server_name: web1.example.com
ssl_certificate: /etc/ssl/certs/web1.pem

Recopilar facts

Ansible recopila automaticamente facts del sistema (SO, direcciones IP, memoria, disco) de los hosts gestionados. Usalos en plantillas y condicionales:

- name: Mostrar informacion del sistema
  debug:
    msg: >
      Hostname: {{ ansible_hostname }},
      SO: {{ ansible_distribution }} {{ ansible_distribution_version }},
      IP: {{ ansible_default_ipv4.address }},
      RAM: {{ ansible_memtotal_mb }} MB

- name: Instalar paquetes segun el SO
  apt:
    name: nginx
    state: present
  when: ansible_os_family == "Debian"

- name: Instalar paquetes en Red Hat
  yum:
    name: nginx
    state: present
  when: ansible_os_family == "RedHat"

Handlers y Notificaciones

Los handlers son tareas especiales que se ejecutan solo cuando son notificados por otra tarea. Se activan al final de un play, despues de que todas las tareas regulares se han completado. Esto previene reinicios innecesarios de servicios.

---
- name: Configurar servidor web
  hosts: webservers
  become: true

  tasks:
    - name: Instalar nginx
      apt:
        name: nginx
        state: present

    - name: Desplegar configuracion principal de nginx
      template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify:
        - Validar configuracion de nginx
        - Reiniciar nginx

    - name: Desplegar virtual host
      template:
        src: templates/vhost.conf.j2
        dest: /etc/nginx/sites-available/{{ domain }}.conf
      notify:
        - Validar configuracion de nginx
        - Reiniciar nginx

    - name: Habilitar virtual host
      file:
        src: /etc/nginx/sites-available/{{ domain }}.conf
        dest: /etc/nginx/sites-enabled/{{ domain }}.conf
        state: link
      notify:
        - Validar configuracion de nginx
        - Reiniciar nginx

  handlers:
    - name: Validar configuracion de nginx
      command: nginx -t
      listen: "Validar configuracion de nginx"

    - name: Reiniciar nginx
      service:
        name: nginx
        state: restarted
      listen: "Reiniciar nginx"

Aunque tres tareas notifican a los handlers, Reiniciar nginx se ejecuta solo una vez al final del play.

Roles y Estructura de Directorios

Los roles organizan tus playbooks en componentes reutilizables y compartibles. Cada rol encapsula tareas, handlers, variables, plantillas y archivos para una funcion especifica.

Crear un rol

ansible-galaxy init roles/webserver

Esto genera la siguiente estructura:

roles/
  webserver/
    tasks/
      main.yml
    handlers/
      main.yml
    templates/
    files/
    vars/
      main.yml
    defaults/
      main.yml
    meta/
      main.yml

Tareas del rol

# roles/webserver/tasks/main.yml
---
- name: Instalar nginx
  apt:
    name: nginx
    state: present
    update_cache: true

- name: Desplegar configuracion de nginx
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: Reiniciar nginx

- name: Desplegar virtual host
  template:
    src: vhost.conf.j2
    dest: "/etc/nginx/sites-available/{{ domain }}.conf"
  notify: Reiniciar nginx

- name: Habilitar virtual host
  file:
    src: "/etc/nginx/sites-available/{{ domain }}.conf"
    dest: "/etc/nginx/sites-enabled/{{ domain }}.conf"
    state: link
  notify: Reiniciar nginx

- name: Eliminar virtual host por defecto
  file:
    path: /etc/nginx/sites-enabled/default
    state: absent
  notify: Reiniciar nginx

- name: Asegurar que nginx esta ejecutandose
  service:
    name: nginx
    state: started
    enabled: true

Handlers del rol

# roles/webserver/handlers/main.yml
---
- name: Reiniciar nginx
  service:
    name: nginx
    state: restarted

Valores por defecto del rol

# roles/webserver/defaults/main.yml
---
domain: example.com
http_port: 80
https_port: 443
document_root: /var/www/html
worker_processes: auto
worker_connections: 1024

Usar roles en un playbook

# site.yml
---
- name: Configurar infraestructura
  hosts: webservers
  become: true
  roles:
    - role: webserver
      vars:
        domain: knowledgexchange.xyz
    - role: security
    - role: monitoring

Ejemplos Practicos

Despliegue de stack LAMP

# lamp.yml
---
- name: Desplegar stack LAMP
  hosts: webservers
  become: true
  vars:
    mysql_root_password: "{{ vault_mysql_root_password }}"
    php_version: "8.3"

  tasks:
    - name: Instalar Apache y PHP
      apt:
        name:
          - apache2
          - libapache2-mod-php{{ php_version }}
          - php{{ php_version }}
          - php{{ php_version }}-mysql
          - php{{ php_version }}-curl
          - php{{ php_version }}-xml
          - php{{ php_version }}-mbstring
        state: present
        update_cache: true

    - name: Instalar servidor MySQL
      apt:
        name: mysql-server
        state: present

    - name: Iniciar y habilitar MySQL
      service:
        name: mysql
        state: started
        enabled: true

    - name: Iniciar y habilitar Apache
      service:
        name: apache2
        state: started
        enabled: true

    - name: Desplegar pagina PHP info para pruebas
      copy:
        content: "<?php phpinfo(); ?>"
        dest: /var/www/html/info.php
        owner: www-data
        group: www-data
        mode: "0644"

Gestion de usuarios en todos los servidores

# users.yml
---
- name: Gestionar cuentas de usuario
  hosts: all
  become: true
  vars:
    admin_users:
      - name: jcarlos
        key: "ssh-ed25519 AAAAC3Nza... jcarlos@workstation"
        groups: sudo,adm
      - name: deployer
        key: "ssh-ed25519 AAAAC3Nza... deployer@ci"
        groups: www-data
    removed_users:
      - oldadmin
      - tempuser

  tasks:
    - name: Crear usuarios administradores
      user:
        name: "{{ item.name }}"
        groups: "{{ item.groups }}"
        shell: /bin/bash
        create_home: true
        state: present
      loop: "{{ admin_users }}"

    - name: Agregar claves SSH para usuarios administradores
      authorized_key:
        user: "{{ item.name }}"
        key: "{{ item.key }}"
        exclusive: true
      loop: "{{ admin_users }}"

    - name: Eliminar usuarios antiguos
      user:
        name: "{{ item }}"
        state: absent
        remove: true
      loop: "{{ removed_users }}"

Endurecimiento de seguridad

# harden.yml
---
- name: Endurecimiento de seguridad
  hosts: all
  become: true

  tasks:
    - name: Instalar paquetes de seguridad
      apt:
        name:
          - ufw
          - fail2ban
          - unattended-upgrades
        state: present
        update_cache: true

    - name: Configurar valores por defecto de UFW
      ufw:
        direction: incoming
        policy: deny

    - name: Permitir SSH a traves de UFW
      ufw:
        rule: allow
        port: "2222"
        proto: tcp

    - name: Permitir HTTP y HTTPS
      ufw:
        rule: allow
        port: "{{ item }}"
        proto: tcp
      loop:
        - "80"
        - "443"

    - name: Habilitar UFW
      ufw:
        state: enabled

    - name: Desplegar configuracion de fail2ban
      copy:
        src: files/jail.local
        dest: /etc/fail2ban/jail.local
      notify: Reiniciar fail2ban

    - name: Habilitar actualizaciones de seguridad automaticas
      copy:
        content: |
          APT::Periodic::Update-Package-Lists "1";
          APT::Periodic::Unattended-Upgrade "1";
          APT::Periodic::AutocleanInterval "7";
        dest: /etc/apt/apt.conf.d/20auto-upgrades

    - name: Deshabilitar inicio de sesion SSH como root
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: "^PermitRootLogin"
        line: "PermitRootLogin no"
      notify: Reiniciar sshd

  handlers:
    - name: Reiniciar fail2ban
      service:
        name: fail2ban
        state: restarted

    - name: Reiniciar sshd
      service:
        name: sshd
        state: restarted

Ansible Vault para Secretos

Nunca almacenes contrasenas o claves API en texto plano. Ansible Vault cifra datos sensibles:

# Crear un archivo de variables cifrado
ansible-vault create group_vars/all/vault.yml

# Editar un archivo cifrado
ansible-vault edit group_vars/all/vault.yml

# Cifrar un archivo existente
ansible-vault encrypt secrets.yml

# Ejecutar un playbook con vault
ansible-playbook site.yml --ask-vault-pass

# Usar un archivo de contrasena en su lugar
ansible-playbook site.yml --vault-password-file ~/.vault_pass

Dentro del archivo vault, prefija las variables sensibles con vault_:

# group_vars/all/vault.yml (cifrado)
vault_mysql_root_password: "s3cur3P@ssw0rd"
vault_api_key: "abc123def456"
vault_ssl_private_key: |
  -----BEGIN PRIVATE KEY-----
  ...
  -----END PRIVATE KEY-----

Referencia las variables vault en tu archivo de variables regular:

# group_vars/all/vars.yml
mysql_root_password: "{{ vault_mysql_root_password }}"
api_key: "{{ vault_api_key }}"

Solucion de Problemas

Fallos de conexion SSH

# Probar conectividad SSH manualmente
ssh -i ~/.ssh/id_ed25519 deployer@web1.example.com

# Ejecutar con modo detallado para ver detalles SSH
ansible all -m ping -i inventory.ini -vvvv

# Verificar si Python esta disponible en el host remoto
ansible all -m raw -a "python3 --version" -i inventory.ini

Errores de permiso denegado

# Asegurar que become (sudo) esta configurado
ansible-playbook site.yml -i inventory.ini --become --ask-become-pass

# Verificar configuracion de sudo en el host remoto
ssh deployer@web1.example.com "sudo -l"

Errores de modulo no encontrado

# Listar todos los modulos disponibles
ansible-doc -l | grep apt

# Ver documentacion de un modulo especifico
ansible-doc apt

# Verificar version de Ansible para compatibilidad de modulos
ansible --version

Errores de sintaxis en playbooks

# Validar sintaxis del playbook sin ejecutar
ansible-playbook site.yml --syntax-check

# Lint del playbook para mejores practicas
pip install ansible-lint
ansible-lint site.yml

Depurar salida de tareas

- name: Ejecutar comando y capturar salida
  command: systemctl status nginx
  register: nginx_status
  ignore_errors: true

- name: Mostrar la salida
  debug:
    var: nginx_status.stdout_lines

Referencia de Comandos Esenciales

ComandoDescripcion
ansible --versionMostrar version y configuracion de Ansible
ansible all -m ping -i inventory.iniProbar conectividad a todos los hosts
ansible all -m setup -i inventory.iniRecopilar y mostrar facts de los hosts
ansible webservers -m apt -a "name=nginx state=present" -i inventory.ini --becomeInstalar nginx en webservers via comando ad-hoc
ansible-playbook site.yml -i inventory.iniEjecutar un playbook
ansible-playbook site.yml --check --diffEjecucion en seco con salida diff
ansible-playbook site.yml --limit web1.example.comEjecutar playbook en un solo host
ansible-playbook site.yml --tags "nginx,security"Ejecutar solo tareas con etiquetas especificas
ansible-playbook site.yml --start-at-task "Install nginx"Reanudar playbook desde una tarea especifica
ansible-vault create secrets.ymlCrear un nuevo archivo cifrado
ansible-vault edit secrets.ymlEditar un archivo cifrado
ansible-galaxy init roles/myroleCrear estructura de directorio de un nuevo rol
ansible-galaxy install geerlingguy.nginxInstalar un rol desde Ansible Galaxy
ansible-inventory -i inventory.ini --graphMostrar grafo de hosts del inventario
ansible-doc aptVer documentacion del modulo

Resumen

Ansible proporciona un camino poderoso y accesible hacia la automatizacion de infraestructura. Su arquitectura sin agente significa que puedes comenzar a automatizar inmediatamente — si puedes conectarte por SSH a tus servidores, puedes gestionarlos con Ansible. Comienza con comandos ad-hoc simples, avanza a playbooks para tareas repetibles y organiza configuraciones complejas en roles. La combinacion de legibilidad YAML, ejecucion idempotente y miles de modulos integrados hace de Ansible la herramienta preferida para la gestion de configuracion en entornos Linux y Windows.

Para aprovisionar la infraestructura en si — crear servidores cloud, redes y registros DNS antes de configurarlos — explora nuestra guia de infraestructura como codigo con Terraform. Para asegurar que los servidores que gestiona Ansible esten seguros desde el inicio, sigue nuestra guia de endurecimiento SSH para proteger el acceso remoto con autenticacion basada en claves, fail2ban y reglas de firewall.