Back to Skills
    šŸ¦ž

    ansible-skill

    Infrastructure automation with Ansible.

    By @botond-rackhost
    View on GitHub
    SKILL.md
    ---
    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)