--- title: "Cómo instalar y usar Ansible en Ubuntu 24.04" description: "Instala Ansible en un nodo de control con Ubuntu 24.04, conéctalo por SSH, crea un inventario, lanza comandos ad-hoc y escribe tu primer playbook con Nginx." category: "Herramientas de Automatización" language: es source: https://cubepath.com/es/docs/herramientas-de-automatización/introduccion-a-ansible-primeros-pasos updated: 2026-09-25 --- # Cómo instalar y usar Ansible en Ubuntu 24.04 Ansible es una herramienta de automatización de código abierto que configura servidores a través de SSH. No usa agentes: en los servidores gestionados solo hace falta Python, que Ubuntu ya incluye. En este tutorial instalarás Ansible en un nodo de control con Ubuntu 24.04, le darás acceso SSH a tus servidores, los describirás en un inventario, ejecutarás comandos ad-hoc y escribirás un primer playbook que instala y arranca Nginx. ## Requisitos previos Para seguir esta guía necesitas: - Un **nodo de control**: una máquina con Ubuntu 24.04 desde la que se ejecutará Ansible. Puede ser tu equipo de trabajo o un VPS pequeño de CubePath. - Uno o más **nodos gestionados**: servidores con Ubuntu 24.04 que Ansible configurará. Esta guía usa dos, `web1` (`web1_server_ip`) y `web2` (`web2_server_ip`). - Un usuario no root con privilegios `sudo` en cada nodo gestionado, llamado `your_user` en esta guía. - Acceso SSH (puerto 22) desde el nodo de control a todos los nodos gestionados. ## Paso 1: Instalar Ansible en el nodo de control Los repositorios de Ubuntu incluyen Ansible, pero con una versión antigua. El proyecto Ansible publica las versiones actuales en el PPA oficial `ppa:ansible/ansible`, que es compatible con Ubuntu 24.04. En el nodo de control, añade el PPA e instala el paquete `ansible`: ```bash sudo apt update sudo apt install software-properties-common sudo add-apt-repository --yes --update ppa:ansible/ansible sudo apt install ansible ``` El paquete `ansible` contiene `ansible-core` (el motor y los módulos integrados `ansible.builtin`) y un conjunto de colecciones como `community.general` y `ansible.posix`. Comprueba la instalación: ```bash ansible --version ``` ```output ansible [core 2.18.6] config file = None configured module search path = ['/home/your_user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3/dist-packages/ansible executable location = /usr/bin/ansible python version = 3.12.3 (main, ...) [GCC 13.2.0] jinja version = 3.1.2 ``` Los números de versión serán distintos en tu caso. En los nodos gestionados no hay que instalar nada. ## Paso 2: Configurar la autenticación con claves SSH Ansible se conecta a cada servidor por SSH, así que el nodo de control necesita acceso con clave, sin contraseña, a todos los nodos gestionados. Si todavía no tienes una clave en el nodo de control, créala: ```bash ssh-keygen -t ed25519 -C "ansible-control" ``` Pulsa `ENTER` para aceptar la ruta por defecto (`~/.ssh/id_ed25519`). Es recomendable usar una frase de paso; si la pones, carga la clave en el agente antes de usar Ansible con `eval "$(ssh-agent)"` y `ssh-add`. Copia la clave pública a cada nodo gestionado: ```bash ssh-copy-id your_user@web1_server_ip ssh-copy-id your_user@web2_server_ip ``` Prueba la conexión. Debe iniciar sesión e imprimir el nombre del servidor sin pedir contraseña: ```bash ssh your_user@web1_server_ip hostname ``` ```output web1 ``` Esta primera conexión también guarda la clave de host de cada servidor en `~/.ssh/known_hosts`. Ansible verifica las claves de host por defecto, y conviene mantenerlo así. ## Paso 3: Crear el directorio del proyecto y el inventario El inventario le dice a Ansible qué servidores existen, cómo llegar a ellos y cómo se agrupan. Guárdalo en un directorio de proyecto junto con la configuración y los playbooks, para que todo el proyecto pueda vivir en Git. Crea el directorio del proyecto: ```bash mkdir ~/ansible-first-steps cd ~/ansible-first-steps ``` Crea el archivo de inventario: ```bash nano inventory.ini ``` Añade tus servidores a un grupo llamado `webservers`: ```ini [webservers] web1 ansible_host=web1_server_ip web2 ansible_host=web2_server_ip [webservers:vars] ansible_user=your_user ``` `web1` y `web2` son los nombres que Ansible usa en su salida, `ansible_host` es la dirección a la que se conecta y `ansible_user` fija el usuario SSH para todos los hosts del grupo. Además, cada host pertenece al grupo implícito `all`. Muestra lo que Ansible ve en el inventario: ```bash ansible-inventory -i inventory.ini --graph ``` ```output @all: |--@ungrouped: |--@webservers: | |--web1 | |--web2 ``` ## Paso 4: Añadir un archivo ansible.cfg En lugar de pasar `-i inventory.ini` en cada comando, guarda los valores por defecto en un archivo `ansible.cfg`. Ansible lee el `ansible.cfg` del directorio actual cuando ejecutas los comandos desde la carpeta del proyecto. ```bash nano ansible.cfg ``` ```ini [defaults] inventory = inventory.ini interpreter_python = auto_silent [ssh_connection] pipelining = True ``` - `inventory` apunta al archivo de inventario. - `interpreter_python = auto_silent` deja que Ansible descubra Python en cada servidor sin mostrar un aviso. - `pipelining` reduce el número de operaciones SSH por tarea, lo que acelera bastante las ejecuciones. Confirma que Ansible usa el archivo: ```bash ansible --version | grep "config file" ``` ```output config file = /home/your_user/ansible-first-steps/ansible.cfg ``` ## Paso 5: Ejecutar comandos ad-hoc Los comandos ad-hoc ejecutan un único módulo sobre un conjunto de hosts sin escribir un playbook. Son útiles para comprobaciones rápidas y tareas puntuales. La sintaxis es `ansible -m -a ""`. Comprueba la conectividad con el módulo `ping`. No envía paquetes ICMP: inicia sesión por SSH y verifica que Python funciona. ```bash ansible all -m ping ``` ```output web1 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3.12" }, "changed": false, "ping": "pong" } web2 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3.12" }, "changed": false, "ping": "pong" } ``` Ejecuta un comando en todos los servidores web: ```bash ansible webservers -m ansible.builtin.command -a "uptime" ``` ```output web1 | CHANGED | rc=0 >> 10:14:02 up 3 days, 2:11, 1 user, load average: 0.00, 0.01, 0.00 web2 | CHANGED | rc=0 >> 10:14:02 up 3 days, 2:09, 1 user, load average: 0.02, 0.03, 0.00 ``` Las tareas que necesitan root usan `--become` (`-b`). Añade `-K` (`--ask-become-pass`) para que Ansible te pida la contraseña de sudo una sola vez: ```bash ansible webservers -b -K -m ansible.builtin.apt -a "update_cache=yes" ``` Recoge los facts, la información del sistema que Ansible obtiene de cada host, y fíltralos: ```bash ansible web1 -m ansible.builtin.setup -a "filter=ansible_distribution*" ``` ```output web1 | SUCCESS => { "ansible_facts": { "ansible_distribution": "Ubuntu", "ansible_distribution_file_parsed": true, "ansible_distribution_file_path": "/etc/os-release", "ansible_distribution_file_variety": "Debian", "ansible_distribution_major_version": "24", "ansible_distribution_release": "noble", "ansible_distribution_version": "24.04" }, "changed": false } ``` ## Paso 6: Escribir tu primer playbook Los comandos ad-hoc son imperativos: indicas qué ejecutar. Un playbook es declarativo: describes el estado que quieres y Ansible solo cambia lo que sea distinto. Los playbooks son archivos YAML que se pueden revisar, versionar y volver a ejecutar sin riesgo. Crea un playbook que instala Nginx, se asegura de que está en marcha, abre HTTP en UFW y publica una página de inicio sencilla: ```bash nano webserver.yml ``` ```yaml --- - name: Configurar los servidores web hosts: webservers become: true tasks: - name: Instalar Nginx ansible.builtin.apt: name: nginx state: present update_cache: true cache_valid_time: 3600 - name: Arrancar Nginx y activarlo en el arranque ansible.builtin.systemd_service: name: nginx state: started enabled: true - name: Permitir SSH en UFW community.general.ufw: rule: allow name: OpenSSH - name: Permitir HTTP en UFW community.general.ufw: rule: allow port: "80" proto: tcp - name: Activar UFW community.general.ufw: state: enabled - name: Publicar la página de inicio ansible.builtin.copy: dest: /var/www/html/index.html content: "

Desplegado por Ansible en {{ inventory_hostname }}

\n" owner: www-data group: www-data mode: "0644" ``` Algunos detalles importantes: - `hosts: webservers` apunta al grupo del inventario y `become: true` ejecuta todas las tareas con sudo. - Cada tarea llama a un módulo por su nombre completo (`ansible.builtin.apt`), lo que evita ambigüedades entre colecciones. - `cache_valid_time: 3600` solo actualiza la caché de apt si tiene más de una hora. - La regla de OpenSSH va antes de `state: enabled`, así que activar el cortafuegos nunca te deja fuera. - `{{ inventory_hostname }}` es una variable Jinja2 con el nombre del host en el inventario. Comprueba la sintaxis antes de ejecutarlo: ```bash ansible-playbook webserver.yml --syntax-check ``` ```output playbook: webserver.yml ``` ## Paso 7: Ejecutar el playbook Empieza con una ejecución de prueba. `--check` informa de lo que cambiaría sin cambiar nada, y `--diff` muestra las diferencias en los archivos: ```bash ansible-playbook webserver.yml -K --check --diff ``` En modo check, algunas tareas posteriores pueden dar error porque las anteriores no se ejecutaron de verdad (por ejemplo, el servicio de Nginx todavía no existe). Es normal en la primera ejecución. Ahora aplica el playbook: ```bash ansible-playbook webserver.yml -K ``` Introduce tu contraseña de sudo en el aviso `BECOME password:`. La ejecución termina con un resumen por host: ```output PLAY RECAP ********************************************************************* web1 : ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 web2 : ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ``` `ok` cuenta las tareas que se ejecutaron correctamente (incluida la recogida de facts) y `changed` las que modificaron algo. Verifica el resultado desde el nodo de control: ```bash curl http://web1_server_ip ``` ```output

Desplegado por Ansible en web1

``` ## Paso 8: Comprobar la idempotencia Ejecuta de nuevo el mismo playbook: ```bash ansible-playbook webserver.yml -K ``` ```output PLAY RECAP ********************************************************************* web1 : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 web2 : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ``` `changed=0` significa que los servidores ya coinciden con el estado descrito, así que Ansible no ha hecho nada. Esta propiedad, la idempotencia, es la que permite ejecutar los playbooks una y otra vez sin riesgo, por ejemplo de forma programada o después de añadir un servidor nuevo al inventario. También es la razón para preferir módulos específicos (`apt`, `copy`, `systemd_service`) en lugar de `command` o `shell`, que siempre informan de `changed` porque Ansible no sabe qué han hecho. ## Solución de problemas **`UNREACHABLE! ... Permission denied (publickey,password)`**: la clave SSH no está instalada para el usuario que usa Ansible. Revisa `ansible_user` en el inventario y prueba con `ssh your_user@web1_server_ip`. Ejecuta Ansible con `-vvv` para ver el comando SSH exacto que lanza. **`Missing sudo password`**: la tarea usa `become` y tu usuario necesita contraseña para sudo. Añade `-K` al comando. **`Host key verification failed`**: la clave del servidor no está en `~/.ssh/known_hosts` o ha cambiado (por ejemplo, tras reinstalar el servidor). Conéctate una vez con `ssh` para aceptarla, o elimina la entrada antigua con `ssh-keygen -R web1_server_ip`. **`couldn't resolve module/action 'community.general.ufw'`**: solo has instalado `ansible-core`. Instala la colección con `ansible-galaxy collection install community.general`, o instala el paquete completo `ansible` como en el paso 1. ## Conclusión Has instalado Ansible en un nodo de control, configurado el acceso con claves SSH, descrito tus servidores en un inventario, ejecutado comandos ad-hoc y aplicado un playbook idempotente que configura Nginx y el cortafuegos en varios servidores a la vez. A partir de aquí, guarda el proyecto en Git, aprende a organizar configuraciones más grandes con plantillas y handlers en playbooks prácticos, y usa variables, bucles y condicionales para que el mismo playbook funcione en entornos distintos.