Skip to content

Your first playbook

This playbook prepares a fresh Ubuntu server: baseline settings, Docker, and fail2ban. It needs the installation first.

inventory.yml
all:
children:
servers:
hosts:
app-1:
ansible_host: 203.0.113.10
ansible_user: deploy

ansible_user must be able to use sudo, and its SSH key must work: the base role turns on key-only login.

site.yml
- hosts: servers
become: true
vars:
# Never banned by fail2ban or CrowdSec.
security_allowlist: [192.0.2.0/24, 2001:db8::/32]
# Keep the account Ansible connects as; see the gotchas of the base role.
base_sshd_allow_users: [deploy]
roles:
- noixdev.infra.base
- noixdev.infra.docker
- noixdev.infra.fail2ban

Set security_allowlist to the networks you manage the server from (your office, your VPN). Replace the example ranges above; they are documentation ranges and match nothing real. The list is the guard against locking yourself out, described in the lockout guard.

Look at what would change first:

Terminal window
ansible-playbook -i inventory.yml site.yml --check --diff

Then apply it:

Terminal window
ansible-playbook -i inventory.yml site.yml

Run it a second time. A role that is idempotent reports changed=0. The collection’s own tests check exactly that for every role.

  • Common packages, the time zone set to UTC, unattended security upgrades, and an sshd drop-in at /etc/ssh/sshd_config.d/50-base.conf that allows key-only login.
  • Docker CE and the compose plugin, with a daemon.json that limits log size.
  • fail2ban banning repeated SSH failures through nftables, with your management networks never banned.

Roles go in the order of their dependencies: base and docker first, then the roles that run containers or read their state.

roles:
- noixdev.infra.base
- noixdev.infra.docker
- noixdev.infra.fail2ban
- noixdev.infra.crowdsec # after docker, so the bouncer also guards Docker ports
- role: noixdev.infra.traefik
vars:
traefik_acme_email: ops@example.com
traefik_dns_env: { HETZNER_API_TOKEN: "{{ vault_dns_token }}" }
traefik_cert_domains: [{ main: example.com, sans: ["*.example.com"] }]

Keep tokens and passwords in Ansible Vault, as the example does with vault_dns_token. Each role’s page in the guide lists its variables, examples and pitfalls.