Ansible
by @botond-rackhost
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.
clawhub install ansible-skillπ About This Skill
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
# Install Ansible
pip install ansibleOr on macOS
brew install ansibleVerify
ansible --version
Run Your First Playbook
# Test connection
ansible all -i inventory/hosts.yml -m pingRun playbook
ansible-playbook -i inventory/hosts.yml playbooks/site.ymlDry run (check mode)
ansible-playbook -i inventory/hosts.yml playbooks/site.yml --checkWith 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:
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:
# playbooks/site.yml - Master playbook
name: Configure all servers
hosts: all
become: yes
roles:
- common
- securityname: Setup OpenClaw servers
hosts: openclaw
become: yes
roles:
- nodejs
- openclaw
Roles
Reusable, modular configurations:
# 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:2. security
Hardening following CIS benchmarks:3. nodejs
Node.js installation via NodeSource:4. openclaw
Complete OpenClaw setup:Usage Patterns
Pattern 1: New VPS Setup (OpenClaw)
# 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"
EOF2. Run OpenClaw playbook
ansible-playbook -i inventory/hosts.yml playbooks/openclaw-vps.yml \
--limit newserver \
--ask-vault-pass3. 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
ansible-playbook -i inventory/hosts.yml playbooks/security.yml \
--limit production \
--tags "ssh,firewall"
Pattern 3: Rolling Updates
# Update one server at a time
ansible-playbook -i inventory/hosts.yml playbooks/update.yml \
--serial 1
Pattern 4: Ad-hoc Commands
# 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
# inventory/group_vars/all.yml
timezone: Europe/Budapest
deploy_user: asdbot
ssh_port: 22Security
security_ssh_password_auth: false
security_ssh_permit_root: false
security_fail2ban_enabled: true
security_ufw_enabled: true
security_ufw_allowed_ports:
- 22
- 80
- 443Node.js
nodejs_version: "22.x"
Vault for Secrets
# Create encrypted vars file
ansible-vault create inventory/group_vars/all/vault.ymlEdit encrypted file
ansible-vault edit inventory/group_vars/all/vault.ymlRun with vault
ansible-playbook site.yml --ask-vault-passOr use vault password file
ansible-playbook site.yml --vault-password-file ~/.vault_pass
Vault file structure:
# 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
# Good
name: Install nginx web server
apt:
name: nginx
state: presentBad
apt: name=nginx
2. Use FQCN (Fully Qualified Collection Names)
# Good
ansible.builtin.apt:
name: nginxAcceptable but less clear
apt:
name: nginx
3. Explicit State
# Good - explicit state
ansible.builtin.apt:
name: nginx
state: presentBad - implicit state
ansible.builtin.apt:
name: nginx
4. Idempotency
Write tasks that can run multiple times safely:# 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
# tasks/main.yml
name: Update SSH config
ansible.builtin.template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
notify: Restart SSHhandlers/main.yml
name: Restart SSH
ansible.builtin.systemd:
name: sshd
state: restarted
6. Tags for Selective Runs
- 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
# Test SSH connection manually
ssh -v user@hostDebug Ansible connection
ansible host -i inventory -m ping -vvvCheck inventory parsing
ansible-inventory -i inventory --list
Common Errors
"Permission denied"
chmod 600 ~/.ssh/id_*become: yes to playbook"Host key verification failed"
host_key_checking = Falsessh-keyscan -H host >> ~/.ssh/known_hosts"Module not found"
ansible.builtin.apt instead of aptansible-galaxy collection install community.generalDebugging Playbooks
# Verbose output
ansible-playbook site.yml -v # Basic
ansible-playbook site.yml -vv # More
ansible-playbook site.yml -vvv # MaximumStep through tasks
ansible-playbook site.yml --stepStart 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
# 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:
# Get password from vault cache
PASSWORD=$(.secrets/get-secret.sh "VPS - Eva")Use in ansible (not recommended - use ansible-vault instead)
ansible-playbook site.yml -e "ansible_ssh_pass=$PASSWORD"
Better: Store in Ansible Vault and use --ask-vault-pass.
References
references/best-practices.md - Detailed best practices guidereferences/modules-cheatsheet.md - Common modules quick referencereferences/troubleshooting.md - Extended troubleshooting guideExternal Resources
π‘ Examples
Prerequisites
# Install Ansible
pip install ansibleOr on macOS
brew install ansibleVerify
ansible --version
Run Your First Playbook
# Test connection
ansible all -i inventory/hosts.yml -m pingRun playbook
ansible-playbook -i inventory/hosts.yml playbooks/site.ymlDry run (check mode)
ansible-playbook -i inventory/hosts.yml playbooks/site.yml --checkWith specific tags
ansible-playbook -i inventory/hosts.yml playbooks/site.yml --tags "security,nodejs"
βοΈ Configuration
# Install Ansible
pip install ansibleOr on macOS
brew install ansibleVerify
ansible --version
Run Your First Playbook
# Test connection
ansible all -i inventory/hosts.yml -m pingRun playbook
ansible-playbook -i inventory/hosts.yml playbooks/site.ymlDry run (check mode)
ansible-playbook -i inventory/hosts.yml playbooks/site.yml --checkWith specific tags
ansible-playbook -i inventory/hosts.yml playbooks/site.yml --tags "security,nodejs"
π Tips & Best Practices
1. Always Name Tasks
# Good
name: Install nginx web server
apt:
name: nginx
state: presentBad
apt: name=nginx
2. Use FQCN (Fully Qualified Collection Names)
# Good
ansible.builtin.apt:
name: nginxAcceptable but less clear
apt:
name: nginx
3. Explicit State
# Good - explicit state
ansible.builtin.apt:
name: nginx
state: presentBad - implicit state
ansible.builtin.apt:
name: nginx
4. Idempotency
Write tasks that can run multiple times safely:# 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
# tasks/main.yml
name: Update SSH config
ansible.builtin.template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
notify: Restart SSHhandlers/main.yml
name: Restart SSH
ansible.builtin.systemd:
name: sshd
state: restarted
6. Tags for Selective Runs
- name: Security tasks
ansible.builtin.include_tasks: security.yml
tags: [security, hardening]name: App deployment
ansible.builtin.include_tasks: deploy.yml
tags: [deploy, app]