Your first Ansible playbook: install nginx and publish a page
A complete beginner playbook that installs nginx on Debian or Ubuntu servers, starts it at boot and deploys a home page, with the commands to dry-run, apply and verify it.
This tutorial takes you from an empty folder to a web server configured by Ansible. It targets Debian or Ubuntu hosts (it uses the apt module). You need Ansible on your machine, SSH key access to the servers and a user that can use sudo.
Step 1: create the inventory
Make a project folder and an inventory file named inventory.ini. Replace the example names and addresses with your own servers.
[web]
web1.example.com ansible_host=192.0.2.10
web2.example.com ansible_host=192.0.2.11
[web:vars]
ansible_user=admin
ansible_host is the address to connect to, ansible_user the SSH login. Check that Ansible can reach every host:
ansible web -i inventory.ini -m ping
Each host should answer SUCCESS with "ping": "pong". If you see UNREACHABLE!, fix SSH first (see the separate fix entry for that error).
Step 2: write the playbook
Save this as site.yml:
---
- name: Install nginx and publish a home page
hosts: web
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
cache_valid_time: 3600
- name: Make sure nginx is running and starts at boot
ansible.builtin.service:
name: nginx
state: started
enabled: true
- name: Publish a simple home page
ansible.builtin.copy:
content: "<h1>Deployed by Ansible</h1>\n"
dest: /var/www/html/index.html
owner: root
group: root
mode: "0644"
hosts: webruns the play on thewebgroup from the inventory.become: trueruns the tasks with sudo, because installing packages needs root.update_cachewithcache_valid_time: 3600refreshes the apt index only if it is older than an hour.enabled: truemakes nginx start automatically after a reboot.- On Debian and Ubuntu the default nginx site serves
/var/www/html, so the copiedindex.htmlbecomes the home page.
Step 3: dry run, then apply
- Check the YAML:
ansible-playbook -i inventory.ini site.yml --syntax-check - Preview without changing anything:
ansible-playbook -i inventory.ini site.yml --check. In check mode some tasks cannot know their final result (nginx is not installed yet, so the service task may fail); that is expected on a first run. - Apply it:
ansible-playbook -i inventory.ini site.yml. Add-K(--ask-become-pass) if sudo asks for a password on the servers.
At the end Ansible prints a PLAY RECAP line per host with counters such as ok, changed, unreachable and failed.
Step 4: verify and run it again
curl http://192.0.2.10/
ansible-playbook -i inventory.ini site.yml
The page should show “Deployed by Ansible”. The second playbook run should report changed=0 for every host: the package is present, the service is running and the file already has the right content, so nothing is touched. This is idempotency, and it is why you can safely re-run playbooks.
Where to go next
Move hard-coded values into variables, render the nginx configuration from a template and reload nginx only when it changes. Those are the next steps: variables, templates and handlers.
Official documentation
See also
- 0181 Ansible concepts: inventory, modules, playbooks, idempotency and roles Ansible configures many servers over SSH from one control machine. Learn the core pieces: inventory, modules, tasks, playbooks, roles, and why runs… Beginner · Concept · Linux, macOS Article Ansible 15 Oct 2026
- 0183 Ansible variables, templates and handlers: configure an nginx site Use group variables, Jinja2 templates and handlers together: render an nginx server block from variables, test the config and reload nginx only… Intermediate · How-to · Linux, macOS Script Ansible 15 Oct 2026
- 0184 Ansible Vault: keep passwords and keys encrypted in your repo Ansible Vault encrypts variable files or single values so secrets can live in Git next to your playbooks. Create, edit and rekey… Advanced · How-to · Linux, macOS Article Ansible 15 Oct 2026
- 0185 Ansible ad-hoc commands cheat sheet One-line ansible commands for quick jobs across many servers: ping hosts, run a command, copy files, manage packages, users and services, gather… Intermediate · Reference · Linux, macOS Article Ansible 15 Oct 2026
- 0186 Fix: Ansible UNREACHABLE! Failed to connect to the host via ssh Ansible could not open an SSH session to the host, so no task ran. The text after the colon tells you why:… Intermediate · Fix · Linux, macOS Article Ansible · SSH & servers 15 Oct 2026
- 0254 Automate three servers with Ansible: roles, templates, Vault and safe dry runs Build a real Ansible project for two web servers and one database server: inventory groups, SSH keys, roles, templates, handlers, an encrypted… Intermediate · Tutorial · Linux, macOS Article Ansible · Keys & config 15 Oct 2026
Repos in the wild
- Ansible: agentless IT automation ansible/ansible The source repository of ansible-core, the engine behind Ansible playbooks, ad-hoc commands and the ansible-galaxy and ansible-vault tools. GitHub
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- commitpedia-admin +3,241 chars