Ansible ist das meistgenutzte Konfigurations-Management-Tool in der DevOps-Welt — und das aus gutem Grund.
Kein Agent, kein spezieller Server-Daemon, reines SSH. Wer heute Infrastruktur verwaltet,
kommt an Ansible kaum vorbei. Claude Code versteht Ansible nativ:
Playbooks, Inventory-Strukturen, Roles-Hierarchie, Vault-Verschlüsselung und Galaxy-Integration.
In diesem Artikel zeigen wir, wie du mit Claude Code im Jahr 2026 produktiv Ansible-Projekte
aufsetzt, idempotente Konfigurationen schreibst und komplexe Infrastruktur sicher verwaltest —
von einem einzelnen Server bis hin zu AWX/Tower-verwalteten Umgebungen mit Hunderten von Hosts.
1. Ansible Grundlagen: Inventory, ansible.cfg & erste Playbooks
Bevor Claude Code sinnvoll helfen kann, braucht es einen soliden Grundriss.
Ansible arbeitet ohne zentralen Server — alle Konfigurationen liegen als YAML-Dateien
in deinem Repository. Das macht es besonders gut für KI-gestützte Entwicklung geeignet:
Claude Code sieht den gesamten Kontext auf einmal.
Inventory-Struktur
Das Inventory definiert, welche Hosts Ansible verwaltet und wie diese gruppiert sind.
Ein gut strukturiertes Inventory ist das Fundament jedes Ansible-Projekts.
# inventory/hosts.ini
[webservers]
web01.beispiel.de ansible_user=deploy
web02.beispiel.de ansible_user=deploy
web03.beispiel.de ansible_user=deploy
[dbservers]
db01.beispiel.de ansible_user=dba ansible_port=2222
db02.beispiel.de ansible_user=dba ansible_port=2222
[monitoring]
mon01.beispiel.de
[production:children]
webservers
dbservers
monitoring
[production:vars]
ansible_ssh_private_key_file=~/.ssh/prod_key
ansible_python_interpreter=/usr/bin/python3
ansible.cfg — Projekt-Konfiguration
Die Datei ansible.cfg im Projektverzeichnis überschreibt globale Defaults.
Claude Code generiert diese automatisch basierend auf deiner Projektstruktur.
# ansible.cfg
[defaults]
inventory = ./inventory/hosts.ini
roles_path = ./roles:~/.ansible/roles
host_key_checking = False
retry_files_enabled= False
stdout_callback = yaml
callbacks_enabled = profile_tasks
forks = 10
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400
[ssh_connection]
pipelining = True
control_path_dir = /tmp/ansible-ssh-%%h-%%p-%%r
[privilege_escalation]
become = True
become_method = sudo
become_user = root
Ad-hoc Commands & erstes Playbook
Ad-hoc Commands sind ideal für schnelle Tests und Einmaltätigkeiten.
Für alles Wiederkehrende schreiben wir Playbooks.
# Ad-hoc: Ping alle Webserver
$ ansible webservers -m ping
# Ad-hoc: Paket installieren
$ ansible webservers -m apt -a "name=nginx state=present update_cache=yes"
# Ad-hoc: Service neu starten
$ ansible webservers -m service -a "name=nginx state=restarted"
# Ad-hoc: Freien Speicher anzeigen
$ ansible all -m shell -a "df -h | grep -v tmpfs"
# playbooks/site.yml — Haupt-Playbook
---
- name: Webserver einrichten
hosts: webservers
become: true
gather_facts: true
vars:
nginx_version: "1.26"
app_port: 8080
handlers:
- name: nginx neu starten
ansible.builtin.service:
name: nginx
state: restarted
- name: nginx neu laden
ansible.builtin.service:
name: nginx
state: reloaded
tasks:
- name: Systempakete aktualisieren
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
- name: Nginx installieren
ansible.builtin.apt:
name: nginx
state: present
notify: nginx neu starten
- name: Nginx-Konfiguration deployen
ansible.builtin.template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: nginx neu laden
- name: Nginx-Service aktivieren und starten
ansible.builtin.service:
name: nginx
state: started
enabled: true
Claude Code Prompt für Playbook-Erstellung
"Erstelle ein Ansible-Playbook, das auf Ubuntu 22.04 Webservern nginx installiert,
eine Virtual-Host-Konfiguration aus einem Jinja2-Template deployt und sicherstellt,
dass der Service nach jedem Reboot automatisch startet. Idempotenz ist Pflicht."
Claude Code generiert dabei automatisch Playbook, Handler, Template und Inventory-Einträge.
2. Tasks & Module: apt, copy, template, service, user & mehr
Ansible-Module sind die Bausteine jedes Playbooks. Claude Code kennt alle
gängigen Module auswendig — inklusive ihrer Parameter, Fallstricke und
Best Practices für Idempotenz.
apt / yum
copy
template
service
user
file
command vs shell
Paketverwaltung: apt & yum
# Pakete auf Debian/Ubuntu
- name: Mehrere Pakete installieren
ansible.builtin.apt:
pkg:
- git
- curl
- htop
- vim
- python3-pip
state: present
update_cache: yes
# Spezifische Version installieren
- name: PostgreSQL 16 installieren
ansible.builtin.apt:
name: postgresql-16
state: present
# Paket entfernen (inkl. Konfigurationsdateien)
- name: Apache entfernen
ansible.builtin.apt:
name: apache2
state: absent
purge: yes
# RedHat / CentOS / RHEL
- name: Pakete auf RHEL installieren
ansible.builtin.yum:
name:
- nginx
- firewalld
state: latest
Dateien & Templates: copy vs. template
# copy: Statische Datei deployen
- name: SSH-Konfiguration kopieren
ansible.builtin.copy:
src: files/sshd_config
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: '0600'
backup: yes
notify: sshd neu starten
# copy: Inline-Inhalt
- name: Motd setzen
ansible.builtin.copy:
content: |
Willkommen auf {{ inventory_hostname }}
Verwaltung durch Ansible — keine manuellen Aenderungen!
dest: /etc/motd
# template: Jinja2-Template mit Variablen
- name: Nginx Virtual Host deployen
ansible.builtin.template:
src: templates/vhost.conf.j2
dest: /etc/nginx/sites-available/{{ app_name }}.conf
owner: www-data
group: www-data
mode: '0644'
validate: nginx -t -c %s
notify: nginx neu laden
Benutzer, Dienste & Verzeichnisse
# user: Deploy-User erstellen
- name: Deploy-User anlegen
ansible.builtin.user:
name: deploy
uid: 1050
group: www-data
shell: /bin/bash
home: /home/deploy
create_home: yes
password_lock: yes
state: present
# file: Verzeichnis mit korrekten Rechten
- name: App-Verzeichnisse erstellen
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: deploy
group: www-data
mode: '0755'
loop:
- /var/www/app
- /var/www/app/releases
- /var/www/app/shared
- /var/log/app
# service: Dienst steuern
- name: PostgreSQL starten und aktivieren
ansible.builtin.service:
name: postgresql
state: started
enabled: true
Idempotenz-Regel: Immer command statt shell bevorzugen, wenn keine Shell-Features (Pipes, Wildcards, Redirects) benötigt werden. command ist schneller, sicherer und idempotenter. Nutze creates oder removes um Doppelausführungen zu verhindern.
# command: bevorzugt, kein Shell-Overhead
- name: Datenbankinitialisierung (einmalig)
ansible.builtin.command:
cmd: /opt/app/bin/db-init
creates: /opt/app/.db_initialized
# shell: wenn Pipes/Redirects noetig
- name: Benutzerliste in Datei schreiben
ansible.builtin.shell:
cmd: getent passwd | awk -F: '{print $1}' > /tmp/users.txt
changed_when: false
register: user_list
3. Variablen & Jinja2: group_vars, host_vars & Filter
Das Variablen-System ist eines der mächtigsten Features von Ansible.
Claude Code versteht die Precedence-Hierarchie mit ihren 22 Ebenen und
wählt automatisch den richtigen Ort für jede Variable.
Variablen-Struktur
# Projektstruktur fuer Variablen
ansible-projekt/
├── group_vars/
│ ├── all.yml # Gilt fuer ALLE Hosts
│ ├── all/
│ │ ├── common.yml # Aufgeteilt nach Themen
│ │ └── vault.yml # Verschluesselte Secrets
│ ├── webservers.yml # Gilt fuer webservers-Gruppe
│ └── dbservers.yml # Gilt fuer dbservers-Gruppe
└── host_vars/
├── web01.beispiel.de.yml # Host-spezifisch
└── db01.beispiel.de.yml
# group_vars/all.yml
---
company_name: "Beispiel GmbH"
admin_email: "ops@beispiel.de"
timezone: "Europe/Berlin"
ntp_servers:
- 0.de.pool.ntp.org
- 1.de.pool.ntp.org
ssh_allowed_users:
- deploy
- ansible
common_packages:
- vim
- curl
- wget
- htop
- jq
- unzip
# group_vars/webservers.yml
---
nginx_worker_processes: auto
nginx_worker_connections: 1024
app_port: 8080
ssl_enabled: true
certbot_email: "{{ admin_email }}"
domains:
- beispiel.de
- www.beispiel.de
Jinja2-Filter in der Praxis
Jinja2-Filter erlauben mächtige Transformationen direkt in YAML.
Claude Code kennt alle Built-in-Filter und Ansible-spezifischen Erweiterungen.
# Jinja2-Filter-Beispiele
# String-Filter
app_name_upper: "{{ app_name | upper }}"
hostname_short: "{{ inventory_hostname | regex_replace('\..*$', '') }}"
safe_filename: "{{ release_name | replace('/', '-') | lower }}"
# Listen-Filter
unique_users: "{{ all_users | unique | sort }}"
admin_ips: "{{ allowed_ips | select('match', '^10\\.') | list }}"
first_db: "{{ groups['dbservers'] | first }}"
# Default-Werte
log_level: "{{ custom_log_level | default('info') }}"
workers: "{{ nginx_workers | default(ansible_processor_vcpus) }}"
# Typ-Konvertierung
port_number: "{{ app_port | int }}"
debug_mode: "{{ enable_debug | bool }}"
config_json: "{{ config_dict | to_json }}"
parsed_config: "{{ config_string | from_yaml }}"
when-Bedingungen & Loops
# Bedingte Tasks
- name: UFW nur auf Ubuntu installieren
ansible.builtin.apt:
name: ufw
state: present
when: ansible_distribution == "Ubuntu"
- name: Firewall nur in Produktion konfigurieren
ansible.builtin.ufw:
rule: allow
port: "{{ item }}"
loop: ['80', '443', '22']
when:
- environment == "production"
- ansible_distribution_major_version | int >= 20
# Loop mit Dict
- name: Mehrere Datenbanken erstellen
community.postgresql.postgresql_db:
name: "{{ item.name }}"
encoding: "{{ item.encoding | default('UTF-8') }}"
state: present
loop:
- { name: app_production, encoding: UTF-8 }
- { name: app_analytics, encoding: UTF-8 }
- { name: app_reporting }
become_user: postgres
4. Ansible Roles: Struktur, Galaxy-Init & Dependencies
Roles sind das Herzstück wiederverwendbarer Ansible-Infrastruktur.
Claude Code erzeugt vollständige Role-Strukturen mit korrekten
defaults, tasks, handlers und templates in einem einzigen Prompt.
Role
Galaxy
Dependencies
meta
Role mit ansible-galaxy init erstellen
# Role-Struktur erstellen
$ ansible-galaxy init roles/nginx_vhost
# Ergebnis: vollstaendige Verzeichnisstruktur
roles/nginx_vhost/
├── defaults/
│ └── main.yml # Ueberschreibbare Standard-Variablen
├── files/
│ └── nginx.mime.types # Statische Dateien
├── handlers/
│ └── main.yml # Handler fuer Notifications
├── meta/
│ └── main.yml # Metadaten, Dependencies
├── tasks/
│ ├── main.yml # Einstiegspunkt
│ ├── install.yml # Installation
│ └── configure.yml # Konfiguration
├── templates/
│ ├── nginx.conf.j2 # Haupt-Konfiguration
│ └── vhost.conf.j2 # Virtual Host Template
├── tests/
│ ├── inventory
│ └── test.yml
└── vars/
└── main.yml # Interne (nicht ueberschreibbare) Vars
# roles/nginx_vhost/defaults/main.yml
---
nginx_user: www-data
nginx_worker_processes: auto
nginx_worker_connections: 1024
nginx_keepalive_timeout: 65
nginx_client_max_body_size: "50m"
nginx_gzip_enabled: true
nginx_ssl_protocols: "TLSv1.2 TLSv1.3"
nginx_ssl_ciphers: "ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512"
nginx_vhosts: []
nginx_remove_default_vhost: true
# roles/nginx_vhost/tasks/main.yml
---
- name: Nginx installieren
ansible.builtin.import_tasks: install.yml
- name: Nginx konfigurieren
ansible.builtin.import_tasks: configure.yml
- name: Virtual Hosts deployen
ansible.builtin.include_tasks: vhosts.yml
when: nginx_vhosts | length > 0
Role Dependencies & meta/main.yml
# roles/app_server/meta/main.yml
---
galaxy_info:
author: Beispiel GmbH DevOps
description: Vollstaendiger App-Server mit Nginx, Node.js und PM2
company: Beispiel GmbH
license: MIT
min_ansible_version: "2.15"
platforms:
- name: Ubuntu
versions: ['22.04', '24.04']
- name: Debian
versions: ['11', '12']
galaxy_tags: [web, nginx, nodejs, pm2]
dependencies:
- role: common_packages
- role: nginx_vhost
vars:
nginx_worker_processes: 4
- role: geerlingguy.nodejs
vars:
nodejs_version: "20.x"
# Playbook mit mehreren Roles
---
- name: App-Server vollstaendig einrichten
hosts: webservers
become: true
roles:
- role: common_packages
- role: security_hardening
- role: nginx_vhost
vars:
nginx_vhosts:
- name: beispiel.de
server_name: "beispiel.de www.beispiel.de"
root: /var/www/app/current/public
ssl: true
- role: app_server
- role: monitoring_agent
when: monitoring_enabled | default(true)
Claude Code-Prompt für vollständige Role
"Erstelle eine Ansible Role 'postgresql_server' mit defaults, tasks, handlers und templates.
Die Role soll PostgreSQL 16 installieren, pg_hba.conf aus einem Jinja2-Template konfigurieren,
einen dedizierten DB-User anlegen und Backups mit pg_dump einrichten. Idempotenz ist Pflicht."
Claude Code liefert die komplette Role-Struktur — alle Dateien, sofort einsatzbereit.
5. Ansible Vault: Secrets sicher in Git verwalten
Ansible Vault verschlüsselt sensible Daten (Passwörter, API-Keys, SSL-Zertifikate)
direkt in den YAML-Dateien. Die verschlüsselten Dateien sind git-safe —
du kannst sie gefahrlos committen.
Vault encrypt
Vault decrypt
vault_password_file
git-safe
Vault-Grundoperationen
# Ganze Datei verschluesseln
$ ansible-vault encrypt group_vars/all/vault.yml
New Vault password: ***
Confirm New Vault password: ***
Encryption successful
# Einzelnen Wert verschluesseln (inline)
$ ansible-vault encrypt_string 'supergeheim123' --name 'db_password'
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
38306461306239313630373736353966356230623065656337643336...
# Datei entschluesseln (temporaer anschauen)
$ ansible-vault view group_vars/all/vault.yml
# Datei bearbeiten (entschluesselt oeffnen, re-encrypt beim Speichern)
$ ansible-vault edit group_vars/all/vault.yml
# Passwort aendern
$ ansible-vault rekey group_vars/all/vault.yml
vault.yml & Playbook-Integration
# group_vars/all/vault.yml (VOR Verschluesselung)
---
vault_db_password: "P@ssw0rd_Supergeheim_2026!"
vault_app_secret_key: "aB3xK9mN2pQ7rS4tU6vW1yZ8"
vault_smtp_password: "smtp_secret_xyz"
vault_ssl_private_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA1234...
-----END RSA PRIVATE KEY-----
# group_vars/all/main.yml (Klartext, referenziert Vault-Vars)
---
db_password: "{{ vault_db_password }}"
app_secret_key: "{{ vault_app_secret_key }}"
smtp_password: "{{ vault_smtp_password }}"
# Playbook ausfuehren mit Vault-Passwort
$ ansible-playbook site.yml --ask-vault-pass
$ ansible-playbook site.yml --vault-password-file ~/.vault_pass.txt
vault_password_file & CI/CD-Integration
# .gitignore: Vault-Passwortdatei NIEMALS committen!
.vault_pass.txt
*.vault_pass
.ansible_vault_password
# ansible.cfg: vault_password_file konfigurieren
[defaults]
vault_password_file = ~/.vault_pass.txt
# GitLab CI/CD: Vault-Passwort als CI-Secret
# .gitlab-ci.yml
deploy:
script:
- echo "$ANSIBLE_VAULT_PASSWORD" > /tmp/.vault_pass.txt
- ansible-playbook site.yml --vault-password-file /tmp/.vault_pass.txt
- rm -f /tmp/.vault_pass.txt
variables:
ANSIBLE_VAULT_PASSWORD: ${ANSIBLE_VAULT_PASSWORD} # aus CI-Secrets
# Mehrere Vault-IDs fuer verschiedene Umgebungen
$ ansible-playbook site.yml \
--vault-id prod@~/.vault_prod.txt \
--vault-id staging@~/.vault_staging.txt
Sicherheitsregel: Vault-Passwortdateien niemals in Git committen. Nutze CI/CD-Secrets, AWS Secrets Manager, HashiCorp Vault oder ansible-vault-pass-client. Die verschlüsselten vault.yml-Dateien selbst dürfen committet werden — sie sind ohne das Passwort wertlos.
6. Ansible Galaxy & AWX/Tower: Community Roles & Enterprise Automation
Ansible Galaxy ist das öffentliche Repository für Community-Roles und Collections.
AWX (Open Source) bzw. Ansible Tower (Enterprise) sind Web-UIs für
zentral verwaltete Ansible-Ausführungen mit RBAC, Scheduling und Audit-Log.
Galaxy
Collections
requirements.yml
AWX/Tower
Galaxy: Roles & Collections installieren
# Einzelne Role installieren
$ ansible-galaxy role install geerlingguy.nginx
# Collection installieren
$ ansible-galaxy collection install community.postgresql
$ ansible-galaxy collection install community.docker
$ ansible-galaxy collection install community.general
# requirements.yml: alle Abhaengigkeiten in einer Datei
# requirements.yml
---
roles:
- name: geerlingguy.nginx
version: "3.2.0"
- name: geerlingguy.nodejs
version: "6.2.0"
- name: geerlingguy.postgresql
version: "3.4.0"
- src: https://github.com/meinefirma/ansible-role-custom.git
name: custom_app_role
version: main
collections:
- name: community.postgresql
version: ">=3.0.0,<4.0.0"
- name: community.docker
version: "3.10.0"
- name: amazon.aws
version: "7.0.0"
- name: community.general
# Alle Requirements installieren
$ ansible-galaxy install -r requirements.yml
$ ansible-galaxy collection install -r requirements.yml
# In CI/CD (z.B. GitHub Actions)
- name: Ansible Galaxy Requirements installieren
run: |
ansible-galaxy install -r requirements.yml --roles-path ./roles
ansible-galaxy collection install -r requirements.yml
AWX/Tower: Job Templates & CI/CD-Integration
# AWX-Konfiguration via Ansible (awx.awx Collection)
---
- name: AWX Job Template erstellen
hosts: localhost
gather_facts: false
collections:
- awx.awx
tasks:
- name: Job Template anlegen
awx.awx.job_template:
name: "Deploy Webserver"
organization: "Beispiel GmbH"
inventory: "Production"
project: "Infrastruktur-Repo"
playbook: "playbooks/webserver.yml"
credentials:
- SSH Production Key
- Vault Production
limit: "webservers"
survey_enabled: true
ask_limit_on_launch: true
become_enabled: true
state: present
controller_host: "https://awx.beispiel.de"
controller_username: "{{ awx_user }}"
controller_password: "{{ vault_awx_password }}"
# GitHub Actions: AWX Job per API triggern
name: Deploy via AWX
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: AWX Job Template starten
run: |
curl -s -X POST \
-H "Authorization: Bearer ${{ secrets.AWX_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{"limit": "webservers", "extra_vars": {"release_tag": "${{ github.sha }}"}}' \
https://awx.beispiel.de/api/v2/job_templates/42/launch/ \
| jq '.id'
- name: Auf Job-Abschluss warten
run: |
JOB_ID=$(cat job_id.txt)
while true; do
STATUS=$(curl -s -H "Authorization: Bearer ${{ secrets.AWX_TOKEN }}" \
https://awx.beispiel.de/api/v2/jobs/$JOB_ID/ | jq -r '.status')
echo "Job Status: $STATUS"
[[ "$STATUS" == "successful" ]] && break
[[ "$STATUS" == "failed" ]] && exit 1
sleep 10
done
Ansible-Versionsverwaltung mit pip
# Ansible in virtuelle Umgebung installieren (empfohlen)
$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install ansible==9.3.0 ansible-lint==24.2.0
# requirements.txt fuer Python-Abhaengigkeiten
ansible==9.3.0
ansible-lint==24.2.0
jinja2==3.1.4
pyyaml==6.0.1
boto3==1.34.0 # fuer AWS-Module
psycopg2-binary==2.9.9 # fuer PostgreSQL-Module
| Feature |
AWX (Open Source) |
Ansible Tower (Enterprise) |
CLI (lokal) |
| Kosten |
Kostenlos |
Abo-basiert |
Kostenlos |
| Web-UI |
Ja |
Ja (erweitert) |
Nein |
| RBAC |
Ja |
Ja (granular) |
Nein |
| Scheduling |
Ja |
Ja |
via Cron |
| Audit-Log |
Basis |
Erweitert |
Stdout/File |
| Support |
Community |
Red Hat |
Community |
Claude Code + Ansible-Idempotenz: Claude Code prüft bei jeder generierten Task automatisch auf Idempotenz. Es vermeidet shell wo command reicht, nutzt immer state: present statt ad-hoc-Befehle und empfiehlt changed_when / failed_when für sauberes Change-Tracking.
Zusammenfassung: Claude Code als Ansible-Copilot
Claude Code versteht Ansible auf semantischer Ebene — nicht nur die Syntax,
sondern auch Best Practices, Idempotenz-Prinzipien und die Feinheiten der
Variablen-Precedence. Das macht es zum idealen Partner für:
- Schnelleres Playbook-Schreiben — vollständige, sofort lauffähige Playbooks statt Trial & Error
- Role-Design — saubere Struktur mit defaults, vars, tasks, handlers nach Ansible Best Practices
- Vault-Integration — Claude Code erkennt sensible Daten und schlägt Vault-Verschlüsselung vor
- Jinja2-Templates — komplexe Templating-Logik mit Filtern, Conditions und Loops
- Fehlerdiagnose — Ansible-Fehlermeldungen erklären und Lösungen vorschlagen
- CI/CD-Integration — GitHub Actions, GitLab CI und AWX-Workflows generieren
Ansible
DevOps
Configuration Management
Playbooks
Ansible Vault
Ansible Galaxy
AWX
Jinja2
Claude Code
IaC
2026
Ansible-Automation mit Claude Code ausprobieren
Teste jetzt kostenlos, wie Claude Code deine Ansible-Playbooks, Roles und Vault-Konfigurationen
beschleunigt — keine Kreditkarte, sofort starten.
Kostenlos testen →