Skip to content
Search RunEntLinux

Searches general documentation on RunEntLinux. Each distribution has its own documentation search.

    Browse this documentation

    Ansible is an agentless IT automation tool that connects to remote hosts via SSH to perform configuration management, application deployment, and task orchestration. It uses YAML-formatted Playbooks with a gentle learning curve, making it one of the most popular automation solutions in Enterprise Linux environments.

    Ansible only needs to be installed on the control node (the machine from which you run commands). Managed remote hosts do not require any additional software — just SSH and Python.

    Terminal window
    # Method 1: Install via DNF (recommended)
    sudo dnf install -y epel-release
    sudo dnf install -y ansible-core
    # Method 2: Install via pip (for the latest version)
    sudo dnf install -y python3 python3-pip
    pip3 install --user ansible
    # Verify installation
    ansible --version

    Ansible modules are distributed as Collections:

    Terminal window
    # Install commonly used collections
    ansible-galaxy collection install ansible.posix
    ansible-galaxy collection install community.general
    ansible-galaxy collection install community.mysql
    # List installed collections
    ansible-galaxy collection list

    The Inventory file defines the hosts and groups that Ansible will manage.

    Create /etc/ansible/hosts or inventory.ini in your project directory:

    # Individual hosts
    10.0.0.100
    # Define groups
    [webservers]
    web01.example.com
    web02.example.com
    web03.example.com
    [dbservers]
    db01.example.com ansible_port=2222
    db02.example.com
    [appservers]
    app[01:05].example.com # app01 through app05
    # Group variables
    [webservers:vars]
    ansible_user=ops
    ansible_become=true
    http_port=80
    [dbservers:vars]
    ansible_user=dba
    ansible_become=true
    # Parent group (containing multiple child groups)
    [production:children]
    webservers
    dbservers
    appservers
    inventory.yml
    all:
    children:
    webservers:
    hosts:
    web01.example.com:
    web02.example.com:
    vars:
    ansible_user: ops
    http_port: 80
    dbservers:
    hosts:
    db01.example.com:
    ansible_port: 2222
    db02.example.com:
    vars:
    ansible_user: dba
    production:
    children:
    webservers:
    dbservers:
    Terminal window
    # List all hosts
    ansible-inventory -i inventory.yml --list
    # Display as a graph
    ansible-inventory -i inventory.yml --graph
    # View variables for a specific host
    ansible-inventory -i inventory.yml --host web01.example.com

    Ad-Hoc commands are suitable for one-off quick operations.

    Terminal window
    # Test connectivity to all hosts
    ansible all -i inventory.yml -m ping
    # View remote host information
    ansible webservers -i inventory.yml -m setup
    # Execute shell commands
    ansible all -i inventory.yml -m shell -a "uptime"
    ansible all -i inventory.yml -m shell -a "free -h"
    ansible all -i inventory.yml -m shell -a "df -h /"
    # Manage packages
    ansible webservers -i inventory.yml -m dnf -a "name=nginx state=present" --become
    ansible webservers -i inventory.yml -m dnf -a "name=* state=latest" --become
    # Manage services
    ansible webservers -i inventory.yml -m service -a "name=nginx state=started enabled=yes" --become
    # Copy files
    ansible webservers -i inventory.yml -m copy -a "src=/tmp/app.conf dest=/etc/app.conf owner=root mode=0644" --become
    # Manage users
    ansible all -i inventory.yml -m user -a "name=deploy state=present groups=wheel" --become
    # Reboot hosts
    ansible dbservers -i inventory.yml -m reboot --become
    # Limit execution scope
    ansible webservers -i inventory.yml -m shell -a "hostname" --limit web01.example.com
    # Parallelism control (default is 5 parallel)
    ansible all -i inventory.yml -m ping -f 20

    Playbooks are Ansible’s core configuration files, using YAML format to define an ordered series of tasks.

    # site.yml - Basic web server configuration
    ---
    - name: Configure web servers
    hosts: webservers
    become: true
    vars:
    http_port: 80
    doc_root: /var/www/myapp
    tasks:
    - name: Install required packages
    ansible.builtin.dnf:
    name:
    - nginx
    - firewalld
    - vim-enhanced
    state: present
    - name: Create website directory
    ansible.builtin.file:
    path: "{{ doc_root }}"
    state: directory
    owner: nginx
    group: nginx
    mode: '0755'
    - name: Deploy homepage
    ansible.builtin.copy:
    content: |
    <!DOCTYPE html>
    <html>
    <head><title>Welcome</title></head>
    <body><h1>Server: {{ ansible_hostname }}</h1></body>
    </html>
    dest: "{{ doc_root }}/index.html"
    owner: nginx
    group: nginx
    mode: '0644'
    - name: Start and enable Nginx
    ansible.builtin.service:
    name: nginx
    state: started
    enabled: true
    - name: Start and enable Firewalld
    ansible.builtin.service:
    name: firewalld
    state: started
    enabled: true
    - name: Open HTTP port
    ansible.posix.firewalld:
    service: http
    permanent: true
    state: enabled
    immediate: true
    Terminal window
    # Execute a Playbook
    ansible-playbook -i inventory.yml site.yml
    # Dry run (no actual changes)
    ansible-playbook -i inventory.yml site.yml --check
    # Verbose output
    ansible-playbook -i inventory.yml site.yml -v
    ansible-playbook -i inventory.yml site.yml -vvv
    # Limit to specific hosts
    ansible-playbook -i inventory.yml site.yml --limit web01.example.com
    # Start from a specific task
    ansible-playbook -i inventory.yml site.yml --start-at-task="Start and enable Nginx"
    # Step-by-step confirmation
    ansible-playbook -i inventory.yml site.yml --step
    # Pass extra variables
    ansible-playbook -i inventory.yml site.yml -e "http_port=8080"
    tasks:
    # Install a single package
    - name: Install Nginx
    ansible.builtin.dnf:
    name: nginx
    state: present
    # Install multiple packages
    - name: Install development tools
    ansible.builtin.dnf:
    name:
    - gcc
    - make
    - python3-devel
    state: present
    # Install a specific version
    - name: Install specific version
    ansible.builtin.dnf:
    name: nginx-1.20.1
    state: present
    # Update all packages
    - name: System update
    ansible.builtin.dnf:
    name: '*'
    state: latest
    # Install a package group
    - name: Install Development Tools group
    ansible.builtin.dnf:
    name: '@Development Tools'
    state: present
    # Remove a package
    - name: Remove old software
    ansible.builtin.dnf:
    name: httpd
    state: absent
    tasks:
    - name: Start and enable service
    ansible.builtin.service:
    name: nginx
    state: started
    enabled: true
    - name: Restart service
    ansible.builtin.service:
    name: nginx
    state: restarted
    - name: Reload service configuration
    ansible.builtin.service:
    name: nginx
    state: reloaded
    - name: Stop and disable service
    ansible.builtin.service:
    name: postfix
    state: stopped
    enabled: false
    tasks:
    # Copy a file from the control node
    - name: Copy configuration file
    ansible.builtin.copy:
    src: files/nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    backup: true
    notify: Reload Nginx
    # Write content directly
    - name: Write configuration
    ansible.builtin.copy:
    content: |
    server {
    listen 80;
    server_name {{ ansible_fqdn }};
    root /var/www/html;
    }
    dest: /etc/nginx/conf.d/default.conf
    owner: root
    group: root
    mode: '0644'

    Jinja2 templates are one of Ansible’s most powerful features, enabling dynamic configuration file generation based on variables.

    Create a template file templates/nginx.conf.j2:

    # Ansible managed - Do not edit manually
    worker_processes {{ ansible_processor_vcpus }};
    events {
    worker_connections {{ nginx_worker_connections | default(1024) }};
    }
    http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;
    {% for vhost in virtual_hosts %}
    server {
    listen {{ vhost.port | default(80) }};
    server_name {{ vhost.server_name }};
    root {{ vhost.doc_root }};
    {% if vhost.ssl | default(false) %}
    listen 443 ssl;
    ssl_certificate {{ vhost.ssl_cert }};
    ssl_certificate_key {{ vhost.ssl_key }};
    {% endif %}
    }
    {% endfor %}
    }

    Use the template in a Playbook:

    - name: Configure web servers
    hosts: webservers
    become: true
    vars:
    nginx_worker_connections: 2048
    virtual_hosts:
    - server_name: app.example.com
    doc_root: /var/www/app
    port: 80
    - server_name: api.example.com
    doc_root: /var/www/api
    port: 8080
    tasks:
    - name: Deploy Nginx configuration
    ansible.builtin.template:
    src: templates/nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    validate: nginx -t -c %s
    notify: Reload Nginx
    handlers:
    - name: Reload Nginx
    ansible.builtin.service:
    name: nginx
    state: reloaded
    tasks:
    # File and directory management
    - name: Create a directory
    ansible.builtin.file:
    path: /data/app
    state: directory
    owner: app
    group: app
    mode: '0755'
    - name: Create a symbolic link
    ansible.builtin.file:
    src: /data/app/current
    dest: /var/www/app
    state: link
    # Manage scheduled tasks
    - name: Add a backup cron job
    ansible.builtin.cron:
    name: "Database backup"
    minute: "0"
    hour: "2"
    job: "/usr/local/bin/backup.sh >> /var/log/backup.log 2>&1"
    user: root
    # Manage SELinux booleans
    - name: Allow Nginx network connections
    ansible.posix.seboolean:
    name: httpd_can_network_connect
    state: true
    persistent: true
    # Manage sysctl parameters
    - name: Set kernel parameters
    ansible.posix.sysctl:
    name: net.ipv4.ip_forward
    value: '1'
    sysctl_set: true
    reload: true
    # Download files from a URL
    - name: Download application package
    ansible.builtin.get_url:
    url: https://example.com/releases/app-1.0.tar.gz
    dest: /tmp/app-1.0.tar.gz
    checksum: sha256:abc123...
    # Extract archives
    - name: Extract application
    ansible.builtin.unarchive:
    src: /tmp/app-1.0.tar.gz
    dest: /opt/
    remote_src: true
    tasks:
    - name: Run only on AlmaLinux
    ansible.builtin.dnf:
    name: almalinux-release
    state: latest
    when: ansible_distribution == "AlmaLinux"
    - name: Run only on EL9
    ansible.builtin.debug:
    msg: "Running on EL9"
    when: ansible_distribution_major_version == "9"
    - name: Restart if service exists
    ansible.builtin.service:
    name: nginx
    state: restarted
    when: "'nginx' in ansible_facts.packages"
    tasks:
    - name: Create multiple users
    ansible.builtin.user:
    name: "{{ item.name }}"
    groups: "{{ item.groups }}"
    state: present
    loop:
    - { name: 'alice', groups: 'wheel' }
    - { name: 'bob', groups: 'developers' }
    - { name: 'charlie', groups: 'developers' }
    - name: Start multiple services
    ansible.builtin.service:
    name: "{{ item }}"
    state: started
    enabled: true
    loop:
    - nginx
    - firewalld
    - fail2ban

    Handlers are special tasks that only run when triggered by notify, and they execute after all tasks have completed:

    - name: Configure servers
    hosts: webservers
    become: true
    tasks:
    - name: Update Nginx configuration
    ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    notify:
    - Validate Nginx configuration
    - Reload Nginx
    - name: Update sysctl configuration
    ansible.builtin.copy:
    src: sysctl.conf
    dest: /etc/sysctl.d/99-custom.conf
    notify: Apply sysctl
    handlers:
    - name: Validate Nginx configuration
    ansible.builtin.command: nginx -t
    - name: Reload Nginx
    ansible.builtin.service:
    name: nginx
    state: reloaded
    - name: Apply sysctl
    ansible.builtin.command: sysctl --system

    Roles are the best practice for organizing Playbooks. They categorize related tasks, variables, templates, and files into a standardized directory structure.

    Terminal window
    # Use ansible-galaxy to create a role skeleton
    ansible-galaxy role init roles/webserver
    # Generated directory structure
    tree roles/webserver/
    # roles/webserver/
    # ├── defaults/
    # │ └── main.yml # Default variables (lowest priority)
    # ├── files/ # Static files
    # ├── handlers/
    # │ └── main.yml # Handlers
    # ├── meta/
    # │ └── main.yml # Role metadata and dependencies
    # ├── tasks/
    # │ └── main.yml # Main tasks
    # ├── templates/ # Jinja2 templates
    # └── vars/
    # └── main.yml # Role variables (higher priority)
    roles/webserver/defaults/main.yml
    ---
    nginx_port: 80
    nginx_worker_connections: 1024
    doc_root: /var/www/html
    roles/webserver/tasks/main.yml
    ---
    - name: Install Nginx
    ansible.builtin.dnf:
    name: nginx
    state: present
    - name: Deploy Nginx configuration
    ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    notify: Reload Nginx
    - name: Create website directory
    ansible.builtin.file:
    path: "{{ doc_root }}"
    state: directory
    owner: nginx
    group: nginx
    mode: '0755'
    - name: Start Nginx
    ansible.builtin.service:
    name: nginx
    state: started
    enabled: true
    roles/webserver/handlers/main.yml
    ---
    - name: Reload Nginx
    ansible.builtin.service:
    name: nginx
    state: reloaded
    site.yml
    ---
    - name: Configure web servers
    hosts: webservers
    become: true
    roles:
    - webserver
    - name: Configure database servers
    hosts: dbservers
    become: true
    roles:
    - role: database
    vars:
    db_port: 3306
    Terminal window
    # Search for a role
    ansible-galaxy role search nginx --platforms EL # 顶层 search 在 ansible-core 2.10 起已移除
    # Install a role
    ansible-galaxy role install geerlingguy.nginx
    # Batch install from a requirements file
    cat > requirements.yml << 'EOF'
    ---
    roles:
    - name: geerlingguy.nginx
    - name: geerlingguy.mysql
    collections:
    - name: community.general
    - name: ansible.posix
    EOF
    ansible-galaxy install -r requirements.yml
    ansible-project/
    ├── ansible.cfg # Ansible configuration
    ├── inventory/
    │ ├── production.yml # Production environment hosts
    │ └── staging.yml # Staging environment hosts
    ├── group_vars/
    │ ├── all.yml # Variables for all hosts
    │ ├── webservers.yml # Web server group variables
    │ └── dbservers.yml # Database group variables
    ├── host_vars/
    │ └── web01.example.com.yml
    ├── roles/
    │ ├── common/
    │ ├── webserver/
    │ └── database/
    ├── site.yml # Main Playbook
    ├── webservers.yml
    └── dbservers.yml
    # ansible.cfg
    [defaults]
    inventory = inventory/production.yml
    remote_user = ops
    roles_path = roles
    host_key_checking = False
    retry_files_enabled = False
    stdout_callback = yaml
    [privilege_escalation]
    become = True
    become_method = sudo
    become_ask_pass = False

    Ansible Vault for Encrypting Sensitive Data

    Section titled “Ansible Vault for Encrypting Sensitive Data”
    Terminal window
    # Encrypt a file
    ansible-vault encrypt group_vars/dbservers.yml
    # Edit an encrypted file
    ansible-vault edit group_vars/dbservers.yml
    # Decrypt a file
    ansible-vault decrypt group_vars/dbservers.yml
    # Run a Playbook with encrypted data
    ansible-playbook site.yml --ask-vault-pass
    # Use a password file
    ansible-playbook site.yml --vault-password-file ~/.vault_pass

    Ansible is a powerful tool for Enterprise Linux operations automation. From simple Ad-Hoc commands to complex multi-role Playbooks, it efficiently manages large-scale server clusters. Combining Cloud-Init for initial configuration with Ansible for subsequent deployment is a classic and proven workflow.