How to Automate Daily Server Backups with Ansible

If you’ve ever woken up to a missing database file and a panicked ticket queue, you know why a reliable backup routine is not a nice‑to‑have, it’s a must‑have. The good news? With Ansible you can set it up once and forget about it—until you need it, of course.

Why Backups Matter Every Day

A daily backup is the safety net that turns a “whoops” into a quick restore. It protects you from hardware glitches, human error, and the occasional rogue script. For busy sysadmins, the goal is to make the backup process invisible: no manual ssh, no copy‑paste of tar commands, just a reliable playbook that runs while you sip your coffee.

Prerequisites

Before we dive into the playbook, make sure you have:

  • A control node with Ansible installed (any recent 2.9+ version works).
  • SSH key‑based access to the target servers.
  • A backup destination—could be an NFS share, an S3 bucket, or another server you trust.
  • Basic familiarity with Ansible inventory and playbooks.

If any of those sound unfamiliar, pause and get them sorted. Trying to automate without a solid foundation is like building a house on sand.

Step 1 – Define Your Inventory

Create a simple inventory file, hosts.ini, that lists the servers you want to back up.

[webservers]
web01.example.com
web02.example.com

[databases]
db01.example.com

Group the hosts by role if you need different backup strategies later. Keep the file in a version‑controlled directory so you can track changes.

Step 2 – Choose What to Back Up

Decide which directories or databases need protection. For this guide we’ll back up:

  • /var/www/html – website files
  • /etc – configuration files
  • MySQL databases (using mysqldump)

You can always add more later; the playbook is modular.

Step 3 – Write the Backup Playbook

Create a file called daily_backup.yml. Below is a stripped‑down version that does the job.

---
- name: Daily server backup
  hosts: all
  become: true
  vars:
    backup_dir: "/tmp/backup_{{ ansible_date_time.iso8601_basic_short }}"
    remote_backup: "[email protected]:/backups/{{ inventory_hostname }}"
  tasks:

  - name: Ensure backup directory exists
    file:
      path: "{{ backup_dir }}"
      state: directory
      mode: '0755'

  - name: Archive website files
    archive:
      path: /var/www/html
      dest: "{{ backup_dir }}/www_html.tar.gz"
      format: gz

  - name: Archive configuration files
    archive:
      path: /etc
      dest: "{{ backup_dir }}/etc.tar.gz"
      format: gz

  - name: Dump MySQL databases
    mysql_db:
      state: dump
      target: "{{ backup_dir }}/mysql_dump.sql"
      login_user: backup_user
      login_password: "{{ vault_mysql_password }}"
    when: "'databases' in group_names"

  - name: Transfer backup to remote storage
    synchronize:
      src: "{{ backup_dir }}/"
      dest: "{{ remote_backup }}/"
      mode: push
      rsync_opts:
        - "--delete"
    delegate_to: localhost

  - name: Clean up local temp files
    file:
      path: "{{ backup_dir }}"
      state: absent

What the Playbook Does

  1. Creates a temporary folder on each host with a timestamped name. This keeps each run isolated.
  2. Archives the website and config directories into gzipped tar files. The archive module handles compression for you.
  3. Dumps MySQL only on hosts that belong to the databases group. The when clause checks the group membership.
  4. Pushes the backup files to a remote storage server using synchronize, which is a thin wrapper around rsync. Running this from the control node avoids opening extra ports on the target.
  5. Deletes the temporary folder to keep the servers tidy.

Step 4 – Secure Your Secrets

Never hard‑code passwords. Store them in Ansible Vault and reference them with {{ vault_mysql_password }} as shown. Create the vault file with:

ansible-vault create vault.yml

Add the variable inside, then encrypt it. When you run the playbook, add --ask-vault-pass or configure a vault password file.

Step 5 – Schedule the Playbook

The magic of automation shines when you let cron handle the timing. On your control node, add a cron entry:

0 2 * * * /usr/bin/ansible-playbook -i /path/to/hosts.ini /path/to/daily_backup.yml --vault-password-file /path/to/.vault_pass

This runs the backup at 2 AM every day—quiet hours for most environments. Adjust the time to fit your maintenance window.

Step 6 – Verify and Test

A backup that you never test is just a false sense of security. After the first run:

  1. Check the remote directory for the expected tar and sql files.
  2. Pick one file and try to extract it on a test machine.
  3. Restore a small database from the dump to confirm the mysqldump worked.

If anything looks off, tweak the playbook and re‑run. The good thing about Ansible is that it’s idempotent—running the same playbook again won’t break anything.

Step 7 – Keep an Eye on Logs

Ansible writes a concise report to stdout, but for long‑term tracking you might want to log the output to a file:

0 2 * * * /usr/bin/ansible-playbook -i /path/to/hosts.ini /path/to/daily_backup.yml --vault-password-file /path/to/.vault_pass >> /var/log/ansible/backup.log 2>&1

Rotate the log with logrotate so it doesn’t grow forever. A quick glance at the log after a week will tell you if any host missed its backup.

Personal Note: My First Failed Backup

I still remember my first “automated” backup attempt. I wrote a one‑liner shell script, crontabbed it, and went home. The next morning the web server was down because the script had accidentally deleted /var/www/html. Lesson learned: let a tool like Ansible handle the file operations, and always test on a non‑production host first. Since then, I’ve never looked back.

Wrap‑Up

Automating daily backups with Ansible boils down to three things: a clear inventory, a reliable playbook, and a scheduled run. Once you have those pieces in place, you can sleep a little easier knowing your data is safe, and you can spend more time on the fun stuff—like building new services or finally cleaning up that old Docker swarm.

Happy automating!

Reactions
Do you have any feedback or ideas on how we can improve this page?