SSD Nodes Learn Hosting plans →
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-08-07

Ansible-Tutorial: Erstes Playbook für einen VPS

Installieren Sie Ansible mit pipx unter Ubuntu 24.04, erstellen Sie Inventar und Playbook zur VPS-Absicherung. Lösungen für „Permission denied“ und sudo-Fehler.

Was Sie erstellen

Eine Steuerungsmaschine mit installiertem Ansible und ein oder mehrere neue Ubuntu-24.04-VPS mit ausschließlich dem Standard-Image. Am Ende verfügen Sie über eine Inventardatei mit den Namen Ihrer Server, einen Ad-hoc-Ping, der die durchgängige Authentifizierung bestätigt, und ein Playbook, das die vollständige Checkliste für neue VPS als Code ausführt: einen Benutzer für die Bereitstellung mit Ihrem SSH-Schlüssel, einen gehärteten sshd, fail2ban, unbeaufsichtigte Aktualisierungen und eine Firewall, die OpenSSH zulässt, bevor sie alles andere ablehnt. Richten Sie es auf einem Server oder auf zwanzig aus. Führen Sie es zweimal aus. Beim zweiten Durchlauf wird nichts geändert. Genau das ist der Zweck.

Nach fünfzehn Jahren bei der Bereitstellung von VPS kann ich das typische Muster ehrlich beschreiben: Jeder richtet die ersten fünf Server manuell ein. Beim sechsten Server geht dann ein ganzes Wochenende verloren, weil sich niemand daran erinnert, was bei den ersten fünf Servern gemacht wurde. Dieser Leitfaden vertieft die Übersicht zum Verwalten mehrerer Linux-Server. Lesen Sie ihn an dem Tag weiter, an dem Sie bemerken, dass Sie dasselbe apt install in drei Terminals eingeben.

Was Ansible tatsächlich ist, in einem Absatz

Ansible arbeitet agentenlos. Auf den verwalteten Servern muss kein Daemon installiert werden: Die Steuerungsmaschine verbindet sich über normales SSH, kopiert ein kleines Python-Modul auf das Zielsystem, führt es aus, liest das ausgegebene JSON und löscht es anschließend. Das Zielsystem benötigt lediglich python3, das bereits in jedem unveränderten Ubuntu-Image enthalten ist. Der entscheidende Begriff ist idempotent. Er bedeutet etwas Einfaches: Eine Aufgabe beschreibt einen Zustand, keine Aktion. state: present für ein Paket bedeutet „sicherstellen, dass es installiert ist“, nicht „das Installationsprogramm ausführen“. Ist der Zustand bereits hergestellt, nimmt Ansible keine Änderungen vor und meldet dies als ok statt als changed. Diese Eigenschaft ist der Kern des Produkts. Sie macht das erneute Ausführen eines Playbooks sicher. Sichere erneute Ausführungen machen aus einem Shell-Skript Infrastruktur.

Voraussetzungen und wichtige Fallstricke

  • Eine Steuerungsmaschine: Ihr Laptop oder ein kleiner VPS. Ich gehe von Ubuntu 24.04 aus; macOS funktioniert nach der Installation von pipx über Homebrew identisch.
  • Ein oder mehrere Ziel-VPS mit Ubuntu 24.04 auf KVM, die als root erreichbar sind. Auf ihnen wird nichts installiert.
  • SSH-Authentifizierung per key für jedes Ziel. Ansible verwendet exakt dieselbe Authentifizierung wie Ihr ssh-Befehl. Wenn ssh root@host nach einem Passwort fragt, schlägt Ansible fehl.
  • Unter Ubuntu 24.04 schlägt pip install ansible mit error: externally-managed-environment fehl. Das ist eine beabsichtigte Richtlinie der Distribution und kein Defekt. Verwenden Sie pipx.
  • Leerzeichen in YAML sind Syntax. Eine falsche Einrückung erzeugt mapping values are not allowed in this context, und ein Tabulatorzeichen an beliebiger Stelle ist fatal.
  • Lassen Sie auf jedem Ziel eine funktionierende SSH-Sitzung geöffnet, während das Playbook sshd absichert. Jede Sperrung, bei deren Behebung ich einem Kunden geholfen habe, entstand dadurch, dass die letzte Sitzung zum Testen aus einer "sauberen" Umgebung geschlossen wurde.

Schritt 1: Installieren Sie Ansible mit pipx auf dem Steuerungscomputer, nicht mit pip

Der naheliegende Ansatz ist pip3 install ansible. Auf einem wirklich frischen 24.04-Image schlägt dieser Befehl einen Schritt vorher fehl: Command 'pip3' not found, but can be installed with: sudo apt install python3-pip. Die Installation von pip führt dann nur zur eigentlichen Blockade:

pip3 install ansible
error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.

Ubuntu 24.04 kennzeichnet das System-Python als extern verwaltet (PEP 668). Dadurch kann pip nicht mit apt um dieselben Dateien konkurrieren. Verwenden Sie nicht --break-system-packages. Der Name des Flags ist eindeutig. Die saubere Lösung ist pipx. Damit erhält Ansible eine eigene isolierte virtuelle Umgebung, und die Binärdateien werden in Ihren PATH aufgenommen:

sudo apt update && sudo apt install -y pipx
pipx ensurepath
pipx install --include-deps ansible

Öffnen Sie nach pipx ensurepath eine neue Shell, damit die PATH-Änderung wirksam wird. --include-deps ist keine überflüssige Angabe: Das Paket ansible stellt selbst keine Konsolenskripte bereit, ansible und ansible-playbook sind Einstiegspunkte seiner Abhängigkeit ansible-core. Ohne dieses Flag verweigert pipx die Installation mit No apps associated with package ansible or its dependencies. Installieren Sie außerdem das Paket ansible, nicht nur ansible-core. Das vollständige Paket enthält die Community-Collections, und dieses Playbook verwendet Module aus zwei davon (ansible.posix und community.general).

ansible --version

Das korrekte Ergebnis beginnt mit einer Zeile wie ansible [core 2.19.x] und nennt das Python, unter dem Ansible ausgeführt wird. Jede aktuelle Core-Version ist für alle folgenden Schritte geeignet. ansible: command not found bedeutet dagegen, dass ~/.local/bin noch nicht in Ihrem PATH enthalten ist. Öffnen Sie eine neue Shell oder führen Sie source ~/.bashrc aus.

Damit ist die Installation abgeschlossen. Auf den Zielsystemen wird nichts installiert.

Schritt 2: SSH-Schlüsselzugriff auf jedes Ziel

ssh-keygen -t ed25519 -C "ansible control"
ssh-copy-id root@10.0.0.10
ssh-copy-id root@10.0.0.20

Prüfen Sie das anschließend einmal pro Host:

ssh root@10.0.0.10 true && echo ok

Diese eine Zeile erfüllt zwei Aufgaben: Sie bestätigt, dass die Authentifizierung per Schlüssel ohne Passwort funktioniert, und sie speichert den Hostschlüssel in known_hosts. Führen Sie das jetzt aus, weil Ansible einen nicht gespeicherten Hostschlüssel als interaktive Eingabeaufforderung mitten in einem Lauf anzeigt. Das wirkt genau wie ein Hänger.

Schritt 3: Das Inventar, zuerst INI, YAML bei wachsendem Umfang

Das Inventar ist eine Textdatei, in der die Computer aufgeführt sind, die Ansible verwalten darf. Erstellen Sie inventory.ini in einem neuen Projektverzeichnis:

[vps]
web1 ansible_host=10.0.0.10
web2 ansible_host=10.0.0.20

[vps:vars]
ansible_user=root

web1 ist ein Alias Ihrer Wahl. Er erscheint in der Ausgabe und wird als Ziel mit --limit web1 verwendet. ansible_host ist die tatsächliche Adresse. [vps] ist eine Gruppe, und [vps:vars] legt Variablen für jeden Host in dieser Gruppe fest. ansible_user ist das Konto, mit dem sich Ansible anmeldet. Ergänzen Sie daneben ein ansible.cfg, damit Sie -i nicht erneut eingeben müssen:

[defaults]
inventory = inventory.ini

Ansible liest ansible.cfg aus dem aktuellen Verzeichnis. Das gleiche Inventar in YAML speichern Sie als inventory.yml und geben diesen Namen mit ansible.cfg an. Dieses Format ist die bessere Wahl, sobald jeder Host mehrere Variablen enthält:

vps:
  hosts:
    web1:
      ansible_host: 10.0.0.10
    web2:
      ansible_host: 10.0.0.20
  vars:
    ansible_user: root

Beide Formate sind gleichwertig. Bei zwei Servern lässt sich INI leichter überblicken. Bei zwanzig Hosts ist YAML besser skalierbar. Wählen Sie ein Format und verwenden Sie es konsequent.

Schritt 4: Ad-hoc-Befehle, der grüne Pong als Nachweis, dass alles funktioniert

ansible all -m ping

Dies ist kein ICMP. Das Modul ping ist eine vollständige Prüfung: SSH-Anmeldung, Kopieren des Moduls, Ausführung von Python auf dem Zielsystem und Bereinigung. Das korrekte Ergebnis ist grün, mit einem Block pro Host:

web1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

Grünes SUCCESS bedeutet, dass Authentifizierung, Python-Interpreter und Transport funktionieren. Auch das Playbook wird funktionieren. Rotes UNREACHABLE! bedeutet, dass der Transport fehlgeschlagen ist, bevor ein Modul ausgeführt wurde. Die genaue Zeichenfolge und die Lösung finden Sie im Abschnitt zu den Fehlerursachen weiter unten. Zwei weitere Ad-hoc-Befehle sollten Sie kennen:

ansible all -a "uptime"
ansible all -m apt -a "update_cache=true upgrade=dist" --become

Ad-hoc-Befehle sind für einmalige Aufgaben und Prüfungen gedacht. Alles, was Sie zweimal ausführen würden, gehört in ein Playbook.

Schritt 5: Das erste Playbook, die Checkliste für eine neue VPS als Code

Das entspricht allem, was Sie auf einem neuen Server in den ersten zehn Minuten manuell erledigen würden. Speichern Sie es als site.yml:

---
- name: Baseline a fresh Ubuntu VPS
  hosts: vps
  become: true

  vars:
    deploy_user: deploy
    deploy_pubkey: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
    baseline_packages:
      - fail2ban
      - unattended-upgrades
      - ufw
    baseline_services:
      - fail2ban
      - unattended-upgrades

  tasks:
    - name: Create the deploy user
      ansible.builtin.user:
        name: "{{ deploy_user }}"
        groups: sudo
        append: true
        shell: /bin/bash

    - name: Install the deploy user's SSH key
      ansible.posix.authorized_key:
        user: "{{ deploy_user }}"
        key: "{{ deploy_pubkey }}"

    - name: Passwordless sudo for the deploy user
      ansible.builtin.copy:
        dest: /etc/sudoers.d/deploy
        content: "{{ deploy_user }} ALL=(ALL) NOPASSWD:ALL\n"
        mode: "0440"
        validate: /usr/sbin/visudo -cf %s

    - name: Install baseline packages
      ansible.builtin.apt:
        name: "{{ baseline_packages }}"
        state: present
        update_cache: true

    - name: Enable and start baseline services
      ansible.builtin.service:
        name: "{{ item }}"
        state: started
        enabled: true
      loop: "{{ baseline_services }}"

    - name: Harden sshd with a drop-in
      ansible.builtin.copy:
        dest: /etc/ssh/sshd_config.d/00-hardening.conf
        content: |
          PasswordAuthentication no
          KbdInteractiveAuthentication no
          PermitRootLogin prohibit-password
          X11Forwarding no
        mode: "0644"
        validate: /usr/sbin/sshd -t -f %s
      notify: Restart ssh

    - name: Allow OpenSSH through ufw
      community.general.ufw:
        rule: allow
        name: OpenSSH

    - name: Enable ufw with default deny
      community.general.ufw:
        state: enabled
        policy: deny

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

Diese Zeilen sollten Sie verstehen und nicht nur kopieren:

Variablen stehen unter vars: und werden mit "{{ deploy_user }}" referenziert. Setzen Sie den gesamten Ausdruck in Anführungszeichen, wenn ein Wert mit einer geschweiften Klammer beginnt. Andernfalls interpretiert der YAML-Parser ihn falsch. lookup('file', ...) liest den öffentlichen Schlüssel zur Laufzeit vom Steuerungsrechner ein. Das Playbook enthält daher kein Schlüsselmaterial.

Die Schleife. loop: "{{ baseline_services }}" führt die Service-Aufgabe einmal pro Element aus. Die Ausgabe zeigt jedes Element in einer eigenen Zeile. Beachten Sie, dass die apt-Aufgabe die gesamte Paketliste auf einmal verarbeitet. Eine apt-Transaktion ist schneller und für Pakete das bevorzugte Muster. Schleifen sind für Module gedacht, die tatsächlich jeweils nur eine Sache verarbeiten.

Der Handler ist das Konzept, das Sie verinnerlichen sollten. notify: Restart ssh bedeutet nicht „ssh jetzt neu starten“. Die Anweisung stellt den Handler in eine Warteschlange. Er wird einmal am Ende des Plays ausgeführt, und zwar nur, wenn die auslösende Aufgabe tatsächlich changed gemeldet hat. Führen Sie das Playbook morgen erneut aus: Die Drop-in-Datei ist bereits korrekt, die Kopieraufgabe meldet ok, und sshd wird nicht neu gestartet. Die Zeile validate: sorgt für Sicherheit beim Auslösen. sshd prüft die Datei, bevor es die alte ersetzt. Ein Tippfehler schlägt dadurch bei der Aufgabe fehl, anstatt den Daemon zu beschädigen.

PermitRootLogin prohibit-password, nicht no, absichtlich. Dieses Playbook meldet sich mit einem Schlüssel als root an. prohibit-password deaktiviert Root-Anmeldungen per Passwort und lässt Ihre bestehende Anmeldung aktiv. Sobald der Deploy-Benutzer nachweislich funktioniert (ssh deploy@10.0.0.10 sudo true, die einfache Adresse, da web1 nur ein Alias ist, den Ansible kennt), ändern Sie ansible_user=deploy im Inventory und setzen es bei einem späteren Lauf auf no. Führen Sie die Absicherung in einer Reihenfolge durch, in der Sie sich nicht aussperren können.

Das Präfix 00- ist wichtig. Bei den meisten Schlüsselwörtern verwendet sshd das erste Vorkommen, das es einliest. Ubuntu's sshd_config bindet sshd_config.d/*.conf in lexikalischer Reihenfolge vor dem eigenen Inhalt ein. Ubuntu-24.04-Cloud-Images enthalten in diesem Verzeichnis bereits ein 60-cloudimg-settings.conf. Provider, die Anmeldungen per Passwort über cloud-init aktivieren, fügen außerdem ein 50-cloud-init.conf mit PasswordAuthentication yes hinzu. Wenn Sie unsere Datei 00-hardening.conf nennen, wird sie zuerst sortiert und setzt sich gegen beide Dateien durch.

Die Reihenfolge der Aufgaben sorgt für die Firewall-Sicherheit. Allow OpenSSH wird vor Enable ufw mit einer Deny-Richtlinie ausgeführt. Ansible führt Aufgaben strikt in der angegebenen Reihenfolge aus. Die erforderliche Öffnung ist daher vorhanden, bevor die Sperre aktiviert wird. fail2ban benötigt hier keine Konfiguration, um nützlich zu sein. Die Ubuntu-Standards überwachen sshd sofort. Was die Jails tatsächlich tun und welche Einstellungen Sie anpassen sollten, wird im fail2ban-on-Ubuntu-24.04-Handbuch behandelt.

Schritt 6: Zuerst mit --check testen, anschließend tatsächlich ausführen

ansible-playbook site.yml --check

Der Check-Modus stellt die Verbindung her, ermittelt die geplanten Änderungen und nimmt keine Änderungen vor. Lesen Sie den changed= im PLAY RECAP am Ende. Er gibt an, wie viele Tasks jeden Host ändern würden. Ein wichtiger Hinweis: Der Check-Modus hat eine strukturelle Einschränkung, wenn ein späterer Task von den Änderungen eines früheren Tasks abhängt. Das standardmäßige Ubuntu-Server-Image enthält ufw bereits. Daher läuft dieser Probelauf dort ohne Fehler durch. Bei einem minimalen Image ohne ufw schlagen die ufw-Tasks im Check-Modus jedoch fehl. Der Check-Modus installiert das Paket nicht tatsächlich, und das Modul kann anschließend nichts aufrufen. Das ist eine Einschränkung von Probeläufen und kein Fehler in Ihrem Playbook. Wenn der Plan korrekt aussieht:

ansible-playbook site.yml

Jeder Task gibt eine Zeile pro Host aus: gelb changed, grün ok. Die Zusammenfassung sollte folgendermaßen aussehen:

PLAY RECAP *********************************************************************
web1 : ok=10  changed=9  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
web2 : ok=10  changed=9  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0

Die zehn ok bestehen aus dem Ermitteln von Fakten, acht Tasks und dem Handler. Ihr changed darf um ein oder zwei von meinem abweichen. Das standardmäßige Ubuntu-Image enthält ufw und unattended-upgrades bereits, und fail2ban startet sich unmittelbar nach der Installation durch apt selbst. Daher kann ein Task beim ersten Durchlauf berechtigt ok melden, weil der deklarierte Zustand bereits vorhanden ist. Die Werte für unreachable und failed müssen null sein. Ein Hinweis zu become: true: Solange Sie sich als root verbinden, ist es nur eine Formalität. Sobald Sie ansible_user auf deploy umstellen, wird sudo tatsächlich verwendet. Die von diesem Playbook installierte NOPASSWD-sudoers-Datei verhindert, dass -K in der Befehlszeile erforderlich ist. Ohne diese Datei erhalten Sie Missing sudo password. Das wird weiter unten behandelt.

Schritt 7: zweimal ausführen – so sieht Idempotenz aus

Führen Sie denselben Befehl sofort erneut aus:

web1 : ok=9  changed=0  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0

changed=0 und ok wurden um eins verringert, weil der nicht benachrichtigte Handler nicht ausgeführt wurde. Es wurde nichts neu installiert, sshd wurde nicht neu gestartet und ufw wurde nicht verändert. Das macht das Playbook ebenso zu einem Audit wie zu einem Provisioner: Fügen Sie nächsten Monat web3 zum Inventory hinzu und führen Sie das Playbook erneut aus. Der neue Server wird eingerichtet, die vorhandenen Server werden überprüft. Ein Wert ungleich null für changed auf einem Server, den Sie nicht verändert haben, weist auf eine Abweichung hin. Er zeigt, dass jemand manuell geändert hat, was im Playbook hätte geändert werden müssen.

Von hier an lässt sich das Muster erweitern. Als Nächstes lohnt sich ein Playbook, das ein WireGuard-VPN auf demselben VPS einrichtet und die ufw-Regel so verschärft, dass SSH nur über den Tunnel erreichbar ist. Danach folgt ein Playbook, das Docker und Compose auf jedem Anwendungsserver installiert. Wenn site.yml mehr als drei Bildschirme umfasst, teilen Sie es in Rollen auf, aber nicht vorher.

Fehlerbilder und die dabei angezeigten Meldungen

UNREACHABLE with Permission denied.

web1 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: root@10.0.0.10: Permission denied (publickey).",
    "unreachable": true
}

Der SSH-Transport ist fehlgeschlagen, bevor ein Modul ausgeführt wurde: ansible_user ist falsch, der Schlüssel wurde nie auf diesen Host kopiert oder es wird der falsche Schlüssel angeboten. Reproduzieren Sie den Fehler mit einfachem ssh root@10.0.0.10. Verwenden Sie anschließend ssh -v, um zu sehen, welche Schlüssel angeboten wurden. Wenn SSH mit einem Passwort funktioniert, Ansible jedoch nicht, fehlt ssh-copy-id.

Missing sudo password.

web1 | FAILED! => {
    "msg": "Missing sudo password"
}

Sie haben become: true gesetzt, sich als Benutzer ohne root-Rechte verbunden und dieser Benutzer benötigt für sudo ein Passwort. Fügen Sie entweder -K (--ask-become-pass) zur Befehlszeile hinzu oder geben Sie dem Benutzer einen NOPASSWD-Eintrag in sudoers. Genau deshalb installiert das Playbook vor dem Wechsel zu deploy einen solchen Eintrag.

error: externally-managed-environment. Sie haben pip für das System-Python unter Ubuntu 24.04 ausgeführt. Dies wurde in Schritt 1 behandelt: pipx statt pip und nicht --break-system-packages.

mapping values are not allowed in this context.

ERROR! Syntax Error while loading YAML.
  mapping values are not allowed in this context

Fast immer liegt ein Einrückungsfehler vor: Ein Schlüssel befindet sich auf der falschen Ebene oder nach einem Doppelpunkt fehlt ein Leerzeichen. Die angegebene Zeilennummer zeigt auf eine Stelle in der Nähe des Fehlers, nicht unbedingt auf den Fehler selbst. Prüfen Sie daher auch die vorherige Zeile. Die verwandte Meldung found character '\t' that cannot start any token bedeutet, dass ein Tabulatorzeichen enthalten ist. YAML erlaubt keine Tabulatoren. Führen Sie vor jedem Lauf routinemäßig ansible-playbook site.yml --syntax-check aus. Konfigurieren Sie außerdem Ihren Editor für eine Einrückung von zwei Leerzeichen in YAML.

/usr/bin/python3: not found. Bei standardmäßigen Ubuntu-24.04-Images ist dieser Fehler selten, bei minimalen Images oder Netboot-Images jedoch häufig. Die Modulausführung schlägt fehl, weil auf dem Zielsystem kein Python vorhanden ist. Installieren Sie Python mit dem Modul raw. Dieses Modul benötigt als einziges kein Python auf dem Zielsystem: ansible all -m raw -a "apt-get update && apt-get install -y python3" --become. Führen Sie danach das Playbook erneut aus.

FAQ

Muss ich Ansible auf den von ihm verwalteten Servern installieren?

Nein. Ansible arbeitet agentenlos: Der Steuerungsrechner überträgt kleine Python-Module über SSH, führt sie aus und entfernt sie anschließend. Auf dem Zielsystem werden nur python3 und ein SSH-Zugang benötigt. Beides ist in den Standard-Images von Ubuntu bereits vorhanden. Die einzige Installation in dieser gesamten Anleitung erfolgt auf Ihrem Steuerungsrechner.

Warum meldet Ansible „Permission denied (publickey)“?

Der UNREACHABLE!-Block mit Permission denied (publickey) bedeutet, dass die SSH-Authentifizierung fehlgeschlagen ist, bevor Ansible etwas ausgeführt hat. Prüfen Sie, ob ansible_user im Inventory mit dem Konto übereinstimmt, das Sie tatsächlich eingerichtet haben, ob Sie ssh-copy-id auf diesem Host ausgeführt haben und ob sich ssh user@host ohne Passwort anmeldet. Was den normalen ssh-Befehl repariert, behebt auch das Problem in Ansible, da beide denselben Transport verwenden.

Was bedeutet idempotent in Ansible?

Eine Aufgabe beschreibt einen gewünschten Zustand: „Dieses Paket ist vorhanden“ oder „Diese Zeile steht in dieser Datei“, statt eine auszuführende Aktion vorzugeben. Wenn der Zustand bereits erfüllt ist, führt Ansible nichts aus und meldet ok statt changed. Deshalb zeigt die zweite Ausführung eines Playbooks changed=0, und deshalb ist eine erneute Ausführung eine sichere Prüfung und keine riskante Neuinstallation.

Sollte ich Ansible unter Ubuntu 24.04 mit pip oder pipx installieren?

Mit pipx. Ubuntu 24.04 kennzeichnet das System-Python als extern verwaltet. Daher schlägt pip install ansible absichtlich mit error: externally-managed-environment fehl. pipx install --include-deps ansible installiert Ansible in einer isolierten virtuellen Umgebung und stellt ansible, ansible-playbook und die übrigen Komponenten sauber in Ihrem PATH bereit.

Was ist der Unterschied zwischen den Paketen ansible und ansible-core?

ansible-core ist die Ansible-Engine und enthält nur die ansible.builtin-Module. Das Paket ansible enthält zusätzlich zum Kern die ausgewählten Community-Collections, darunter ansible.posix (das authorized_key-Modul) und community.general (das ufw-Modul), die beide in dieser Anleitung verwendet werden. Beginnen Sie mit dem vollständigen Paket. Wechseln Sie nur dann zu core mit ausgewählten Collections, wenn es dafür einen konkreten Grund gibt.