[ OK ]Kernel wird initialisiert...
~/im/blog
Kontakt aufnehmen

Lass uns reden

Interesse an einer Zusammenarbeit oder eine Frage? Ich bin immer offen für neue Projekte.

Kontakt aufnehmen

Vernetzen

Finden Sie mich in sozialen Medien und auf beruflichen Netzwerken.

DatenschutzerklärungNutzungsbedingungen
© 2026 Irfan MiralEntwickelt vonirfanMiral.com
StartÜber mich/LebenslaufBlogKontakt
2026-02-05• 5 Min. Lesezeit

Das Ansible-Playbook, das auf jedem neuen Server läuft

DevOps Ansible Automatisierung Linux-Administration

Ich habe schon einmal über die Checklist geschrieben, die ich bei jedem neuen Server durchgehe: ein Non-Root-Benutzer, SSH nur mit Key, eine Default-Deny-Firewall, Fail2ban, unbeaufsichtigte Updates. Das von Hand zu machen dauert unter einer Stunde und ist nicht schwer. Aber "unter einer Stunde, von Hand, für jeden Server" summiert sich schnell, sobald man mehr als zwei oder drei davon betreut, und manuelle Schritte sind genau die Stelle, an der sich kleine Inkonsistenzen einschleichen, ein Server bekommt MaxAuthTries 3, ein anderer nicht, weil derjenige, der ihn aufgesetzt hat, an dem Tag in Eile war.

Die Lösung ist, die Checklist in ein Playbook zu verwandeln. Dieselben Schritte, dieselbe Reihenfolge, jedes Mal, und idempotent genug, dass ein erneuter Lauf auf einem bereits konfigurierten Server nichts verändert.

Das Playbook

---
- name: Baseline-Härtung für einen neuen Server
  hosts: new_servers
  become: true

  vars:
    admin_user: deploy
    ssh_public_key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"

  tasks:
    - name: Admin-Benutzer anlegen
      user:
        name: "{{ admin_user }}"
        groups: sudo
        shell: /bin/bash
        create_home: true

    - name: SSH-Key für Admin-Benutzer hinterlegen
      authorized_key:
        user: "{{ admin_user }}"
        key: "{{ ssh_public_key }}"

    - name: Root-Login und Passwort-Auth deaktivieren
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: "{{ item.regexp }}"
        line: "{{ item.line }}"
      loop:
        - { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
        - { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
        - { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
      notify: sshd neu starten

    - name: UFW und Fail2ban installieren
      apt:
        name: [ufw, fail2ban]
        state: present
        update_cache: true

    - name: UFW-Standardregeln setzen
      ufw:
        direction: "{{ item.direction }}"
        policy: "{{ item.policy }}"
      loop:
        - { direction: incoming, policy: deny }
        - { direction: outgoing, policy: allow }

    - name: Benötigte Ports erlauben
      ufw:
        rule: allow
        port: "{{ item }}"
        proto: tcp
      loop: ['22', '80', '443']

    - name: UFW aktivieren
      ufw:
        state: enabled

    - name: Fail2ban aktivieren
      systemd:
        name: fail2ban
        enabled: true
        state: started

    - name: unattended-upgrades installieren
      apt:
        name: unattended-upgrades
        state: present

  handlers:
    - name: sshd neu starten
      systemd:
        name: ssh
        state: restarted

Ausführen

Ein frischer Server kommt ins Inventory, und das Playbook läuft gezielt gegen genau diesen Host:

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

Der erste Lauf macht die ganze Arbeit, legt den Benutzer an, sperrt SSH ab, richtet die Firewall ein. Der Handler startet sshd nur neu, wenn sich die Config tatsächlich geändert hat, das passiert also nur beim allerersten Lauf, jeder Lauf danach ist eine Bestätigung, dass nichts abgedriftet ist.

Warum Idempotenz der eigentliche Punkt ist

Der eigentliche Wert liegt nicht in der gesparten Zeit am ersten Tag, die Befehle von Hand zu tippen ist nicht langsam. Er liegt darin, dass ich sechs Monate später, wenn ich nicht mehr sicher bin, ob ein bestimmter Server die volle Behandlung bekommen hat oder während eines Incidents in Eile aufgesetzt wurde, das Playbook einfach noch einmal laufen lassen kann. Wenn alles schon passt, meldet Ansible null Änderungen, und ich mache weiter. Fehlt etwas, wird es direkt behoben, ohne dass ich mich erinnern muss, welcher der vier oder fünf manuellen Schritte ausgelassen wurde.

Dieses Playbook ist bewusst klein gehalten. Es installiert keine Anwendungs-Stacks und konfiguriert nichts Projektspezifisches, es ist die Basis, auf der jeder Server steht, bevor irgendetwas anderes darauf aufgebaut wird. Diese Trennung von Anwendungs-Playbooks hält die Basis stabil, und eine Baseline, die sich selten ändert, ist eine, der man vertrauen kann, ohne sie bei jedem Mal neu zu lesen.

VorherigerEine GitLab-CI/CD-Pipeline, die für die meisten kleinen Projekte reichtNächster Warum Server-Configs in Git gehören, nicht in den Kopf