---
name: ansible
description: "Infrastructure automation with Ansible. Use for server provisioning, configuration management, application deployment, and multi-host orchestration. Includes playbooks for OpenClaw VPS setup, security hardening, and common server configurations."
metadata: {"openclaw":{"requires":{"bins":["ansible","ansible-playbook"]},"install":[{"id":"ansible","kind":"pip","package":"ansible","bins":["ansible","ansible-playbook"],"label":"Install Ansible (pip)"}]}}
---
# Ansible Skill
Infrastructure as Code automation for server provisioning, configuration management, and orchestration.
## Quick Start
### Prerequisites
```bash
# Install Ansible
pip install ansible
# Or on macOS
brew install ansible
# Verify
ansible --version
```
### Run Your First Playbook
```bash
# Test connection
ansible all -i inventory/hosts.yml -m ping
# Run playbook
ansible-playbook -i inventory/hosts.yml playbooks/site.yml
# Dry run (check mode)
ansible-playbook -i inventory/hosts.yml playbooks/site.yml --check
# With specific tags
ansible-playbook -i inventory/hosts.yml playbooks/site.yml --tags "security,nodejs"
```
## Directory Structure
```
skills/ansible/
āāā SKILL.md # This file
āāā inventory/ # Host inventories
ā āāā hosts.yml # Main inventory
ā āāā group_vars/ # Group variables
āāā playbooks/ # Runnable playbooks
ā āāā site.yml # Master playbook
ā āāā openclaw-vps.yml # OpenClaw VPS setup
ā āāā security.yml # Security hardening
āāā roles/ # Reusable roles
ā āāā common/ # Base system setup
ā āāā security/ # Hardening (SSH, fail2ban, UFW)
ā āāā nodejs/ # Node.js installation
ā āāā openclaw/ # OpenClaw installation
āāā references/ # Documentation
āāā best-practices.md
āāā modules-cheatsheet.md
āāā troubleshooting.md
```
## Core Concepts
### Inventory
Define your hosts in `inventory/hosts.yml`:
```yaml
all:
children:
vps:
hosts:
eva:
ansible_host: 217.13.104.208
ansible_user: root
ansible_ssh_pass: "{{ vault_eva_password }}"
plane:
ansible_host: 217.13.104.99
ansible_user: asdbot
ansible_ssh_private_key_file: ~/.ssh/id_ed25519_plane
openclaw:
hosts:
eva:
```
### Playbooks
Entry points for automation:
```yaml
# playbooks/site.yml - Master playbook
---
- name: Configure all servers
hosts: all
become: yes
roles:
- common
- security
- name: Setup OpenClaw servers
hosts: openclaw
become: yes
roles:
- nodejs
- openclaw
```
### Roles
Reusable, modular configurations:
```yaml
# roles/common/tasks/main.yml
---
- name: Update apt cache
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Install essential packages
ansible.builtin.apt:
name:
- curl
- wget
- git
- htop
- vim
- unzip
state: present
```
## Included Roles
### 1. common
Base system configuration:
- System updates
- Essential packages
- Timezone configuration
- User creation with SSH keys
### 2. security
Hardening following CIS benchmarks:
- SSH hardening (key-only, no root)
- fail2ban for brute-force protection
- UFW firewall configuration
- Automatic security updates
### 3. nodejs
Node.js installation via NodeSource:
- Configurable version (default: 22.x LTS)
- npm global packages
- pm2 process manager (optional)
### 4. openclaw
Complete OpenClaw setup:
- Node.js (via nodejs role)
- OpenClaw npm installation
- Systemd service
- Configuration file setup
## Usage Patterns
### Pattern 1: New VPS Setup (OpenClaw)
```bash
# 1. Add host to inventory
cat >> inventory/hosts.yml << 'EOF'
newserver:
ansible_host: 1.2.3.4
ansible_user: root
ansible_ssh_pass: "initial_password"
deploy_user: asdbot
deploy_ssh_pubkey: "ssh-ed25519 AAAA... asdbot"
EOF
# 2. Run OpenClaw playbook
ansible-playbook -i inventory/hosts.yml playbooks/openclaw-vps.yml \
--limit newserver \
--ask-vault-pass
# 3. After initial setup, update inventory to use key auth
# ansible_user: asdbot
# ansible_ssh_private_key_file: ~/.ssh/id_ed25519
```
### Pattern 2: Security Hardening Only
```bash
ansible-playbook -i inventory/hosts.yml playbooks/security.yml \
--limit production \
--tags "ssh,firewall"
```
### Pattern 3: Rolling Updates
```bash
# Update one server at a time
ansible-playbook -i inventory/hosts.yml playbooks/update.yml \
--serial 1
```
### Pattern 4: Ad-hoc Commands
```bash
# Check disk space on all servers
ansible all -i inventory/hosts.yml -m shell -a "df -h"
# Restart service
ansible openclaw -i inventory/hosts.yml -m systemd -a "name=openclaw state=restarted"
# Copy file
ansible all -i inventory/hosts.yml -m copy -a "src=./file.txt dest=/tmp/"
```
## Variables & Secrets
### Group Variables
```yaml
# inventory/group_vars/all.yml
---
timezone: Europe/Budapest
deploy_user: asdbot
ssh_port: 22
# Security
security_ssh_password_auth: false
security_ssh_permit_root: false
security_fail2ban_enabled: true
security_ufw_enabled: true
security_ufw_allowed_ports:
- 22
- 80
- 443
# Node.js
nodejs_version: "22.x"
```
### Vault for Secrets
```bash
# Create encrypted vars file
ansible-vault create inventory/group_vars/all/vault.yml
# Edit encrypted file
ansible-vault edit inventory/group_vars/all/vault.yml
# Run with vault
ansible-playbook site.yml --ask-vault-pass
# Or use vault password file
ansible-playbook site.yml --vault-password-file ~/.vault_pass
```
Vault file structure:
```yaml
# inventory/group_vars/all/vault.yml
---
vault_eva_password: "y8UGHR1qH"
vault_deploy_ssh_key: |
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
```
## Common Modules
| Module | Purpose | Example |
|--------|---------|---------|
| `apt` | Package management (Debian) | `apt: name=nginx state=present` |
| `yum` | Package management (RHEL) | `yum: name=nginx state=present` |
| `copy` | Copy files | `copy: src=file dest=/path/` |
| `template` | Template files (Jinja2) | `template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf` |
| `file` | File/directory management | `file: path=/dir state=directory mode=0755` |
| `user` | User management | `user: name=asdbot groups=sudo shell=/bin/bash` |
| `authorized_key` | SSH keys | `authorized_key: user=asdbot key="{{ ssh_key }}"` |
| `systemd` | Service management | `systemd: name=nginx state=started enabled=yes` |
| `ufw` | Firewall (Ubuntu) | `ufw: rule=allow port=22 proto=tcp` |
| `lineinfile` | Edit single line | `lineinfile: path=/etc/ssh/sshd_config regexp='^PermitRootLogin' line='PermitRootLogin no'` |
| `git` | Clone repos | `git: repo=https://github.com/x/y.git dest=/opt/y` |
| `npm` | npm packages | `npm: name=openclaw global=yes` |
| `command` | Run command | `command: /opt/script.sh` |
| `shell` | Run shell command | `shell: cat /etc/passwd \| grep root` |
## Best Practices
### 1. Always Name Tasks
```yaml
# Good
- name: Install nginx web server
apt:
name: nginx
state: present
# Bad
- apt: name=nginx
```
### 2. Use FQCN (Fully Qualified Collection Names)
```yaml
# Good
- ansible.builtin.apt:
name: nginx
# Acceptable but less clear
- apt:
name: nginx
```
### 3. Explicit State
```yaml
# Good - explicit state
- ansible.builtin.apt:
name: nginx
state: present
# Bad - implicit state
- ansible.builtin.apt:
name: nginx
```
### 4. Idempotency
Write tasks that can run multiple times safely:
```yaml
# Good - idempotent
- name: Ensure config line exists
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
line: 'PasswordAuthentication no'
# Bad - not idempotent
- name: Add config line
ansible.builtin.shell: echo "PasswordAuthentication no" >> /etc/ssh/sshd_config
```
### 5. Use Handlers for Restarts
```yaml
# tasks/main.yml
- name: Update SSH config
ansible.builtin.template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
notify: Restart SSH
# handlers/main.yml
- name: Restart SSH
ansible.builtin.systemd:
name: sshd
state: restarted
```
### 6. Tags for Selective Runs
```yaml
- name: Security tasks
ansible.builtin.include_tasks: security.yml
tags: [security, hardening]
- name: App deployment
ansible.builtin.include_tasks: deploy.yml
tags: [deploy, app]
```
## Troubleshooting
### Connection Issues
```bash
# Test SSH connection manually
ssh -v user@host
# Debug Ansible connection
ansible host -i inventory -m ping -vvv
# Check inventory parsing
ansible-inventory -i inventory --list
```
### Common Errors
**"Permission denied"**
- Check SSH key permissions: `chmod 600 ~/.ssh/id_*`
- Verify user has sudo access
- Add `become: yes` to playbook
**"Host key verification failed"**
- Add to ansible.cfg: `host_key_checking = False`
- Or add host key: `ssh-keyscan -H host >> ~/.ssh/known_hosts`
**"Module not found"**
- Use FQCN: `ansible.builtin.apt` instead of `apt`
- Install collection: `ansible-galaxy collection install community.general`
### Debugging Playbooks
```bash
# Verbose output
ansible-playbook site.yml -v # Basic
ansible-playbook site.yml -vv # More
ansible-playbook site.yml -vvv # Maximum
# Step through tasks
ansible-playbook site.yml --step
# Start at specific task
ansible-playbook site.yml --start-at-task="Install nginx"
# Check mode (dry run)
ansible-playbook site.yml --check --diff
```
## Integration with OpenClaw
### From OpenClaw Agent
```bash
# Run playbook via exec tool
exec command="ansible-playbook -i skills/ansible/inventory/hosts.yml skills/ansible/playbooks/openclaw-vps.yml --limit eva"
# Ad-hoc command
exec command="ansible eva -i skills/ansible/inventory/hosts.yml -m shell -a 'systemctl status openclaw'"
```
### Storing Credentials
Use OpenClaw's Vaultwarden integration:
`
... (truncated)AI advertising agents that automates ad campaigns across Google Ads, Meta Ads, LinkedIn Ads, and TikTok Ads. Creates campaigns, reads live performance data, researches keywords with real CPC data, optimizes budgets, and manages ads through natural language via the Adspirer MCP server. 103 tools across 4 ad platforms.
Self-orchestrating multi-agent development workflows.
Complete guide for creating and deploying browser automation functions
Comprehensive guide for building AI workflows, agents