20 Essential Ansible Playbook Examples for Linux System Administration

This guide provides 20 practical Ansible playbook examples that you can use immediately for Linux system administration. Each example is production-ready and follows Ansible best practices. Copy, customize, and automate your infrastructure.

1. Update All Packages

---
- name: Update all packages on servers
  hosts: all
  become: true
  tasks:
    - name: Update packages (RHEL/CentOS)
      ansible.builtin.dnf:
        name: "*"
        state: latest
        update_cache: true
      when: ansible_os_family == "RedHat"

    - name: Update packages (Ubuntu/Debian)
      ansible.builtin.apt:
        upgrade: dist
        update_cache: true
      when: ansible_os_family == "Debian"

2. Create Users with SSH Keys

---
- name: Create users with SSH keys
  hosts: all
  become: true
  vars:
    users:
      - name: john
        ssh_key: "ssh-rsa AAAA... john@example.com"
        groups: ["wheel", "docker"]
      - name: jane
        ssh_key: "ssh-rsa AAAA... jane@example.com"
        groups: ["developers"]
  tasks:
    - name: Create user accounts
      ansible.builtin.user:
        name: "{{ item.name }}"
        groups: "{{ item.groups }}"
        shell: /bin/bash
        create_home: true
        state: present
      loop: "{{ users }}"

    - name: Add SSH authorized keys
      ansible.posix.authorized_key:
        user: "{{ item.name }}"
        key: "{{ item.ssh_key }}"
        state: present
      loop: "{{ users }}"

3. Install and Configure Nginx

---
- name: Install and configure Nginx
  hosts: webservers
  become: true
  vars:
    nginx_port: 80
    server_name: example.com
  tasks:
    - name: Install Nginx
      ansible.builtin.package:
        name: nginx
        state: present

    - name: Deploy nginx configuration
      ansible.builtin.template:
        src: nginx.conf.j2
        dest: /etc/nginx/conf.d/{{ server_name }}.conf
        mode: "0644"
      notify: Reload nginx

    - name: Ensure nginx is running
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded

4. Configure Firewall Rules

---
- name: Configure firewall
  hosts: all
  become: true
  vars:
    allowed_ports:
      - { port: 22, proto: tcp }
      - { port: 80, proto: tcp }
      - { port: 443, proto: tcp }
  tasks:
    - name: Install firewalld
      ansible.builtin.package:
        name: firewalld
        state: present

    - name: Start firewalld
      ansible.builtin.service:
        name: firewalld
        state: started
        enabled: true

    - name: Allow ports through firewall
      ansible.posix.firewalld:
        port: "{{ item.port }}/{{ item.proto }}"
        permanent: true
        immediate: true
        state: enabled
      loop: "{{ allowed_ports }}"

5. Deploy Docker and Docker Compose

---
- name: Install Docker
  hosts: docker_hosts
  become: true
  tasks:
    - name: Install required packages
      ansible.builtin.package:
        name:
          - dnf-plugins-core
          - curl
        state: present

    - name: Add Docker repository
      ansible.builtin.yum_repository:
        name: docker-ce
        description: Docker CE Repository
        baseurl: https://download.docker.com/linux/centos/$releasever/$basearch/stable
        gpgcheck: true
        gpgkey: https://download.docker.com/linux/centos/gpg
        enabled: true

    - name: Install Docker
      ansible.builtin.package:
        name:
          - docker-ce
          - docker-ce-cli
          - containerd.io
          - docker-compose-plugin
        state: present

    - name: Start Docker service
      ansible.builtin.service:
        name: docker
        state: started
        enabled: true

    - name: Add user to docker group
      ansible.builtin.user:
        name: "{{ ansible_user }}"
        groups: docker
        append: true

6. Setup PostgreSQL Database

---
- name: Install and configure PostgreSQL
  hosts: databases
  become: true
  vars:
    postgres_version: 15
    db_name: myapp
    db_user: appuser
    db_password: "{{ vault_db_password }}"
  tasks:
    - name: Install PostgreSQL
      ansible.builtin.package:
        name:
          - postgresql-server
          - postgresql-contrib
          - python3-psycopg2
        state: present

    - name: Initialize PostgreSQL
      ansible.builtin.command: postgresql-setup --initdb
      args:
        creates: /var/lib/pgsql/data/PG_VERSION

    - name: Start PostgreSQL
      ansible.builtin.service:
        name: postgresql
        state: started
        enabled: true

    - name: Create database
      community.postgresql.postgresql_db:
        name: "{{ db_name }}"
        state: present
      become_user: postgres

    - name: Create database user
      community.postgresql.postgresql_user:
        name: "{{ db_user }}"
        password: "{{ db_password }}"
        db: "{{ db_name }}"
        priv: ALL
        state: present
      become_user: postgres

7. Configure SSH Hardening

---
- name: Harden SSH configuration
  hosts: all
  become: true
  tasks:
    - name: Configure SSH settings
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: "{{ item.regexp }}"
        line: "{{ item.line }}"
        state: present
        validate: sshd -t -f %s
      loop:
        - { regexp: "^#?PermitRootLogin", line: "PermitRootLogin no" }
        - { regexp: "^#?PasswordAuthentication", line: "PasswordAuthentication no" }
        - { regexp: "^#?X11Forwarding", line: "X11Forwarding no" }
        - { regexp: "^#?MaxAuthTries", line: "MaxAuthTries 3" }
        - { regexp: "^#?Protocol", line: "Protocol 2" }
      notify: Restart sshd

  handlers:
    - name: Restart sshd
      ansible.builtin.service:
        name: sshd
        state: restarted

8. Setup Automated Backups

---
- name: Configure automated backups
  hosts: all
  become: true
  vars:
    backup_dirs:
      - /etc
      - /home
      - /var/www
    backup_destination: /backup
    retention_days: 30
  tasks:
    - name: Create backup directory
      ansible.builtin.file:
        path: "{{ backup_destination }}"
        state: directory
        mode: "0700"

    - name: Deploy backup script
      ansible.builtin.template:
        src: backup.sh.j2
        dest: /usr/local/bin/backup.sh
        mode: "0755"

    - name: Schedule daily backup
      ansible.builtin.cron:
        name: "Daily backup"
        minute: "0"
        hour: "2"
        job: "/usr/local/bin/backup.sh >> /var/log/backup.log 2>&1"

9. Install and Configure Fail2ban

---
- name: Install and configure Fail2ban
  hosts: all
  become: true
  tasks:
    - name: Install Fail2ban
      ansible.builtin.package:
        name: fail2ban
        state: present

    - name: Configure Fail2ban jail
      ansible.builtin.copy:
        dest: /etc/fail2ban/jail.local
        content: |
          [DEFAULT]
          bantime = 3600
          findtime = 600
          maxretry = 5

          [sshd]
          enabled = true
          port = ssh
          filter = sshd
          logpath = /var/log/secure
          maxretry = 3
        mode: "0644"
      notify: Restart fail2ban

    - name: Start Fail2ban
      ansible.builtin.service:
        name: fail2ban
        state: started
        enabled: true

  handlers:
    - name: Restart fail2ban
      ansible.builtin.service:
        name: fail2ban
        state: restarted

10. Deploy SSL Certificates with Certbot

---
- name: Setup SSL with Certbot
  hosts: webservers
  become: true
  vars:
    domain: example.com
    email: admin@example.com
  tasks:
    - name: Install Certbot
      ansible.builtin.package:
        name:
          - certbot
          - python3-certbot-nginx
        state: present

    - name: Obtain SSL certificate
      ansible.builtin.command: >
        certbot --nginx -d {{ domain }} -d www.{{ domain }}
        --email {{ email }}
        --agree-tos
        --non-interactive
      args:
        creates: /etc/letsencrypt/live/{{ domain }}/fullchain.pem

    - name: Setup auto-renewal cron
      ansible.builtin.cron:
        name: "Certbot renewal"
        minute: "0"
        hour: "3"
        job: "certbot renew --quiet"

11. Configure NTP Time Sync

---
- name: Configure time synchronization
  hosts: all
  become: true
  vars:
    ntp_servers:
      - 0.pool.ntp.org
      - 1.pool.ntp.org
  tasks:
    - name: Install chrony
      ansible.builtin.package:
        name: chrony
        state: present

    - name: Configure chrony
      ansible.builtin.template:
        src: chrony.conf.j2
        dest: /etc/chrony.conf
        mode: "0644"
      notify: Restart chrony

    - name: Enable chrony service
      ansible.builtin.service:
        name: chronyd
        state: started
        enabled: true

  handlers:
    - name: Restart chrony
      ansible.builtin.service:
        name: chronyd
        state: restarted

12. Setup Log Rotation

---
- name: Configure log rotation
  hosts: all
  become: true
  tasks:
    - name: Configure application log rotation
      ansible.builtin.copy:
        dest: /etc/logrotate.d/myapp
        content: |
          /var/log/myapp/*.log {
              daily
              rotate 14
              compress
              delaycompress
              missingok
              notifempty
              create 0640 root root
              sharedscripts
              postrotate
                  systemctl reload myapp > /dev/null 2>&1 || true
              endscript
          }
        mode: "0644"

13. Deploy Application from Git

---
- name: Deploy application from Git
  hosts: webservers
  become: true
  vars:
    app_repo: https://github.com/myorg/myapp.git
    app_path: /var/www/myapp
    app_branch: main
  tasks:
    - name: Install Git
      ansible.builtin.package:
        name: git
        state: present

    - name: Clone/update repository
      ansible.builtin.git:
        repo: "{{ app_repo }}"
        dest: "{{ app_path }}"
        version: "{{ app_branch }}"
        force: true
      notify: Restart application

    - name: Set permissions
      ansible.builtin.file:
        path: "{{ app_path }}"
        owner: www-data
        group: www-data
        recurse: true

  handlers:
    - name: Restart application
      ansible.builtin.service:
        name: myapp
        state: restarted

14. Check Disk Space and Alert

---
- name: Check disk space
  hosts: all
  vars:
    disk_threshold: 80
  tasks:
    - name: Get disk usage
      ansible.builtin.shell: df -h / | tail -1 | awk "{print $5}" | tr -d "%"
      register: disk_usage
      changed_when: false

    - name: Alert if disk usage is high
      ansible.builtin.debug:
        msg: "WARNING: Disk usage is {{ disk_usage.stdout }}% on {{ inventory_hostname }}"
      when: disk_usage.stdout | int > disk_threshold

    - name: Fail if disk critically full
      ansible.builtin.fail:
        msg: "CRITICAL: Disk usage is {{ disk_usage.stdout }}%"
      when: disk_usage.stdout | int > 95

15. Configure Swap Space

---
- name: Configure swap space
  hosts: all
  become: true
  vars:
    swap_size: 2G
    swap_file: /swapfile
  tasks:
    - name: Check if swap exists
      ansible.builtin.stat:
        path: "{{ swap_file }}"
      register: swap_status

    - name: Create swap file
      ansible.builtin.command: fallocate -l {{ swap_size }} {{ swap_file }}
      when: not swap_status.stat.exists

    - name: Set swap file permissions
      ansible.builtin.file:
        path: "{{ swap_file }}"
        mode: "0600"
      when: not swap_status.stat.exists

    - name: Make swap
      ansible.builtin.command: mkswap {{ swap_file }}
      when: not swap_status.stat.exists

    - name: Enable swap
      ansible.builtin.command: swapon {{ swap_file }}
      when: not swap_status.stat.exists

    - name: Add to fstab
      ansible.builtin.lineinfile:
        path: /etc/fstab
        line: "{{ swap_file }} none swap sw 0 0"
        state: present

Quick Reference

ExampleUse Case
1-5Basic server setup
6Database provisioning
7-9Security hardening
10-11SSL and time sync
12-15Maintenance tasks

Conclusion

These playbook examples cover common Linux administration tasks. Customize them for your environment, store them in Git, and build your automation library over time. Remember to test in staging before production deployment.

Was this article helpful?

R

About Ramesh Sundararamaiah

Red Hat Certified Architect

Expert in Linux system administration, DevOps automation, and cloud infrastructure. Specializing in Red Hat Enterprise Linux, CentOS, Ubuntu, Docker, Ansible, and enterprise IT solutions.

🐧 Stay Updated with Linux Tips

Get the latest tutorials, news, and guides delivered to your inbox weekly.

Add Comment