A Practical Guide to Automating Daily Linux Tasks with Ansible

You know that feeling when you spend the first half of your day manually updating a dozen servers, only to realize you could have been sipping coffee instead? In 2024 the pressure to keep services up, secure, and fast is higher than ever, and the only realistic way to stay sane is to let the computer do the boring work. That’s why I’m pulling out my favorite tool – Ansible – and showing you how to turn everyday chores into a few lines of YAML.

Why Automation Matters Today

Most sysadmins wear many hats: you’re a troubleshooter, a security guard, a capacity planner, and sometimes even a coffee maker. When you add “manual patching” to that list, you’re setting yourself up for errors and burnout. Automation gives you three big wins:

  1. Consistency – The same command runs the same way on every host.
  2. Speed – What used to take an hour can be done in minutes.
  3. Traceability – Every change is recorded in a playbook, so you can audit it later.

Ansible fits right into that picture because it works over SSH, needs no extra agents, and reads like plain English. If you’ve never written a playbook, don’t worry – I’ll walk you through three common daily tasks and give you ready‑to‑run examples.

Getting Started: The Minimal Setup

Before we dive into playbooks, make sure you have the basics:

  • A control machine (your laptop or a bastion host) with Ansible installed. On most Linux distros you can get it with sudo apt-get install ansible or sudo yum install ansible.
  • Password‑less SSH access to the target servers. A quick ssh-copy-id user@host will set that up.
  • An inventory file that lists the hosts you want to manage. Keep it simple:
[webservers]
web01.example.com
web02.example.com

[dbservers]
db01.example.com

Save that as hosts.ini in the same folder as your playbooks.

Task 1 – Keep Packages Fresh

The Problem

Every day you run apt update && apt upgrade -y or the equivalent yum command on dozens of machines. Doing it by hand is a waste of time and you risk missing a host.

The Playbook

Create a file called update.yml:

---
- name: Update all packages on Linux hosts
  hosts: all
  become: true          # run as root
  tasks:
    - name: Update apt cache (Debian/Ubuntu)
      apt:
        update_cache: yes
      when: ansible_os_family == "Debian"

    - name: Upgrade all packages (Debian/Ubuntu)
      apt:
        upgrade: dist
      when: ansible_os_family == "Debian"

    - name: Update yum cache (RHEL/CentOS)
      yum:
        update_cache: yes
      when: ansible_os_family == "RedHat"

    - name: Upgrade all packages (RHEL/CentOS)
      yum:
        name: "*"
        state: latest
      when: ansible_os_family == "RedHat"

Run it with:

ansible-playbook -i hosts.ini update.yml

Why This Works

Ansible automatically gathers facts about each host, including the OS family. The when statements let the same playbook handle both Debian‑based and RedHat‑based systems without duplication. The whole run finishes in a few minutes, and you get a clean report of which hosts succeeded or failed.

Task 2 – Rotate Logs and Clean Disk Space

The Problem

Log files grow unchecked, filling up /var/log and eventually causing services to crash. You probably have a cron job that runs logrotate, but you still need to prune old archives and check disk usage.

The Playbook

Save this as log_cleanup.yml:

---
- name: Rotate logs and clean old files
  hosts: all
  become: true
  vars:
    log_dir: /var/log
    keep_days: 7
  tasks:
    - name: Run logrotate
      command: logrotate -f /etc/logrotate.conf
      args:
        warn: false

    - name: Find and delete old compressed logs
      find:
        paths: "{{ log_dir }}"
        patterns: "*.gz"
        age: "{{ keep_days }}d"
        recurse: yes
      register: old_logs

    - name: Remove old logs
      file:
        path: "{{ item.path }}"
        state: absent
      loop: "{{ old_logs.files }}"
      when: old_logs.matched > 0

    - name: Report free space
      command: df -h "{{ log_dir }}"
      register: df_output

    - name: Show free space
      debug:
        msg: "{{ df_output.stdout_lines }}"

Run it with:

ansible-playbook -i hosts.ini log_cleanup.yml

Why This Works

The find module lets you locate files older than a certain number of days, and the file module deletes them safely. The final debug step prints the disk usage so you can verify that you actually freed space. All of this replaces a handful of crontab lines with a single, auditable playbook.

Task 3 – Deploy a Simple Monitoring Agent

The Problem

You need a lightweight agent (like node_exporter) on every server to feed metrics to your Prometheus stack. Installing it manually on each host is tedious and error‑prone.

The Playbook

Create install_node_exporter.yml:

---
- name: Install node_exporter on Linux hosts
  hosts: all
  become: true
  vars:
    exporter_version: "1.6.1"
    download_url: "https://github.com/prometheus/node_exporter/releases/download/v{{ exporter_version }}/node_exporter-{{ exporter_version }}.linux-amd64.tar.gz"
    install_dir: /opt/node_exporter
  tasks:
    - name: Ensure install directory exists
      file:
        path: "{{ install_dir }}"
        state: directory
        mode: "0755"

    - name: Download node_exporter archive
      get_url:
        url: "{{ download_url }}"
        dest: "/tmp/node_exporter.tar.gz"
        mode: "0644"

    - name: Extract archive
      unarchive:
        src: "/tmp/node_exporter.tar.gz"
        dest: "{{ install_dir }}"
        remote_src: yes
        creates: "{{ install_dir }}/node_exporter"

    - name: Create systemd service file
      copy:
        dest: /etc/systemd/system/node_exporter.service
        content: |
          [Unit]
          Description=Prometheus Node Exporter
          Wants=network-online.target
          After=network-online.target

          [Service]
          ExecStart={{ install_dir }}/node_exporter-{{ exporter_version }}.linux-amd64/node_exporter
          Restart=always

          [Install]
          WantedBy=multi-user.target
        mode: "0644"

    - name: Reload systemd and start service
      systemd:
        daemon_reload: yes
        name: node_exporter
        state: started
        enabled: yes

Run it:

ansible-playbook -i hosts.ini install_node_exporter.yml

Why This Works

The playbook does everything: creates a folder, pulls the binary, unpacks it, writes a systemd unit, and starts the service. If you ever need to upgrade, just bump exporter_version and re‑run – Ansible will handle the rest.

Tips for Busy SysAdmins

  • Keep playbooks in version control. A Git repo gives you history, rollbacks, and easy sharing with teammates.
  • Use tags. Run ansible-playbook --tags update update.yml if you only want part of a larger playbook.
  • Test on a single host first. Add -l web01.example.com to limit the run; once you’re happy, expand to the whole group.
  • Schedule with cron or systemd timers. A one‑line cron entry like 0 2 * * * /usr/bin/ansible-playbook -i /path/hosts.ini /path/update.yml will keep your fleet fresh every night.

Wrap‑Up

Automation isn’t a magic wand, but with a few well‑written Ansible playbooks you can shave hours off your weekly routine. The three examples above cover the most common daily chores – patching, log cleanup, and agent deployment – and they’re easy to adapt for your own environment. Remember, the goal is to let the computer do the repetitive work so you can focus on designing better systems, learning new tools, or finally taking that lunch break you keep postponing.

Reactions