🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

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.

Versionv0.1.0
Downloads3,486
TERMINAL
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 ansible

Or on macOS

brew install ansible

Verify

ansible --version

Run Your First Playbook

# 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:

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 - security

  • name: 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:
  • 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)

    # 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

    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: 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

    # 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:

    # 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: present

    Bad

  • apt: name=nginx
  • 2. Use FQCN (Fully Qualified Collection Names)

    # Good
    
  • ansible.builtin.apt:
  • name: nginx

    Acceptable but less clear

  • apt:
  • name: nginx

    3. Explicit State

    # 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:
    # 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 SSH

    handlers/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@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

    # 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

    # 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 guide
  • references/modules-cheatsheet.md - Common modules quick reference
  • references/troubleshooting.md - Extended troubleshooting guide
  • External Resources

  • Ansible Documentation
  • Ansible Galaxy - Community roles
  • geerlingguy roles - High quality roles
  • Ansible for DevOps - Book by Jeff Geerling
  • πŸ’‘ Examples

    Prerequisites

    # Install Ansible
    pip install ansible

    Or on macOS

    brew install ansible

    Verify

    ansible --version

    Run Your First Playbook

    # 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"

    βš™οΈ Configuration

    # Install Ansible
    pip install ansible

    Or on macOS

    brew install ansible

    Verify

    ansible --version

    Run Your First Playbook

    # 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"

    πŸ“‹ Tips & Best Practices

    1. Always Name Tasks

    # Good
    
  • name: Install nginx web server
  • apt: name: nginx state: present

    Bad

  • apt: name=nginx
  • 2. Use FQCN (Fully Qualified Collection Names)

    # Good
    
  • ansible.builtin.apt:
  • name: nginx

    Acceptable but less clear

  • apt:
  • name: nginx

    3. Explicit State

    # 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:
    # 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 SSH

    handlers/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]