iToverDose/Software· 16 JUNE 2026 · 00:03

Automate Server Hardening with This Ansible Playbook

Managing multiple servers manually risks inconsistencies and drift at scale. Discover how one playbook enforces baseline security across every new machine, ensuring identical, repeatable configurations in minutes.

DEV Community3 min read0 Comments

When spinning up a fresh server, the first hour often follows a familiar routine: create an admin user, disable root login, set up SSH key authentication, configure a strict firewall, and enable automated updates. For a single machine, these steps take less than an hour and seem trivial. But when you manage dozens—or even hundreds—of servers, manual execution introduces a new problem: inconsistency.

One server might enforce stricter SSH limits than another simply because the person who set it up was in a hurry. Over time, those small deviations add up, creating security gaps that are easy to overlook during audits. The solution? Turn that once-off checklist into an Ansible playbook that enforces the same baseline security configuration, every time, without fail.

Why a playbook beats manual server setup

The core advantage of automating server hardening isn’t speed on day one. Typing commands manually isn’t painfully slow for a single server. The real gain is consistency and repeatability. When you run the same playbook across every new machine, you eliminate human error and configuration drift. Six months after deployment, you can rerun the playbook and rest assured that every server meets the same baseline standards.

Ansible’s idempotency ensures that if a configuration is already in place, rerunning the playbook does nothing. If something is missing or misconfigured, it gets corrected automatically. No more guessing whether a particular server received the full treatment during a late-night incident response.

A minimal playbook for maximum security

This playbook focuses solely on foundational security—nothing more. It doesn’t install application stacks or customize project-specific settings. Instead, it establishes a reliable floor that every server must meet before anything else is layered on top. Keeping it separate from application-specific configurations ensures stability. A baseline that rarely changes is one you can trust without revisiting it constantly.

Below is the complete playbook. Each task enforces a specific security control, drawn from the same checklist used for manual setups but now executed consistently across every server.

---
- name: Baseline hardening for a new server
  hosts: new_servers
  become: true
  vars:
    admin_user: deploy
    ssh_public_key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"

  tasks:
    - name: Create admin user with sudo privileges
      user:
        name: "{{ admin_user }}"
        groups: sudo
        shell: /bin/bash
        create_home: true

    - name: Add SSH key for admin user
      authorized_key:
        user: "{{ admin_user }}"
        key: "{{ ssh_public_key }}"

    - name: Harden SSH configuration
      copy:
        dest: /etc/ssh/sshd_config.d/99-hardening.conf
        content: |
          PermitRootLogin no
          PasswordAuthentication no
          MaxAuthTries 3
        mode: '0644'
      notify: restart sshd

    - name: Install UFW and Fail2ban
      apt:
        name: [ufw, fail2ban]
        state: present
        update_cache: true

    - name: Configure UFW default policies
      ufw:
        direction: "{{ item.direction }}"
        policy: "{{ item.policy }}"
      loop:
        - { direction: incoming, policy: deny }
        - { direction: outgoing, policy: allow }

    - name: Allow essential ports through firewall
      ufw:
        rule: allow
        port: "{{ item }}"
        proto: tcp
      loop: ['22', '80', '443']

    - name: Enable UFW firewall
      ufw:
        state: enabled

    - name: Enable Fail2ban service
      systemd:
        name: fail2ban
        enabled: true
        state: started

    - name: Install unattended-upgrades for automatic security patches
      apt:
        name: unattended-upgrades
        state: present

  handlers:
    - name: Restart SSH service
      systemd:
        name: ssh
        state: restarted

Running the playbook: step by step

To deploy the playbook, start by adding the new server to your Ansible inventory file. The first run must connect as the root user because no other account exists yet on a fresh machine.

ansible-playbook -i inventory.ini baseline.yml -l new-server-01 -u root

Once the playbook completes, root login is disabled, and the deploy user becomes the designated entry point for all subsequent runs. Future executions no longer require root access.

ansible-playbook -i inventory.ini baseline.yml -l new-server-01 -u deploy

The first run performs all the work—creating the user, locking down SSH, setting up the firewall. The handler that restarts SSH only triggers if the configuration actually changes, so subsequent runs are fast and idempotent, confirming that nothing has drifted.

Maintaining a trusted baseline

This playbook is intentionally minimal. It focuses on the essentials: disabling root access, enforcing SSH key authentication, configuring a restrictive firewall, and enabling automatic security updates. By keeping it separate from application-specific configurations, you ensure that the baseline remains stable and reliable.

Over time, as you add more servers, the playbook scales effortlessly. Whether you manage two machines or two hundred, every new server receives the same hardened configuration, eliminating inconsistencies and reducing the risk of overlooked security gaps. With Ansible handling the repetitive work, you can focus on building and deploying applications with confidence, knowing that the foundation beneath them is rock solid.

AI summary

Yeni sunucularınıza hızlı ve tutarlı şekilde güvenlik ayarları uygulamak için basit bir Ansible Playbook hazırlayın. SSH, UFW, Fail2ban ve otomatik güncellemeler için adım adım rehber.

Comments

00
LEAVE A COMMENT
ID #GC0HKU

0 / 1200 CHARACTERS

Human check

9 + 5 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.