ansible-roles

Structure and reuse automation code with Ansible roles for modular, maintainable infrastructure.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "ansible-roles" with this command: npx skills add thebushidocollective/han/thebushidocollective-han-ansible-roles

Ansible Roles

Structure and reuse automation code with Ansible roles for modular, maintainable infrastructure.

Role Directory Structure

A well-organized Ansible role follows a standardized directory structure:

roles/ └── webserver/ ├── README.md ├── defaults/ │ └── main.yml ├── files/ │ ├── nginx.conf │ └── ssl/ │ ├── cert.pem │ └── key.pem ├── handlers/ │ └── main.yml ├── meta/ │ └── main.yml ├── tasks/ │ ├── main.yml │ ├── install.yml │ ├── configure.yml │ └── security.yml ├── templates/ │ ├── nginx.conf.j2 │ └── site.conf.j2 ├── tests/ │ ├── inventory │ └── test.yml └── vars/ └── main.yml

Basic Role Example

tasks/main.yml


Main task file for webserver role

  • name: Include OS-specific variables include_vars: "{{ ansible_os_family }}.yml"

  • name: Import installation tasks import_tasks: install.yml tags:

    • install
    • webserver
  • name: Import configuration tasks import_tasks: configure.yml tags:

    • configure
    • webserver
  • name: Import security tasks import_tasks: security.yml tags:

    • security
    • webserver
  • name: Ensure nginx is running service: name: "{{ nginx_service_name }}" state: started enabled: yes tags:

    • service
    • webserver

tasks/install.yml


Installation tasks for webserver role

  • name: Install nginx and dependencies (Debian/Ubuntu) apt: name: - nginx - nginx-extras - python3-passlib state: present update_cache: yes cache_valid_time: 3600 when: ansible_os_family == "Debian"

  • name: Install nginx and dependencies (RedHat/CentOS) yum: name: - nginx - nginx-mod-stream - python3-passlib state: present update_cache: yes when: ansible_os_family == "RedHat"

  • name: Create nginx directories file: path: "{{ item }}" state: directory owner: "{{ nginx_user }}" group: "{{ nginx_group }}" mode: '0755' loop:

    • "{{ nginx_conf_dir }}/sites-available"
    • "{{ nginx_conf_dir }}/sites-enabled"
    • "{{ nginx_log_dir }}"
    • "{{ nginx_cache_dir }}"
    • /var/www/html
  • name: Install certbot for SSL apt: name: certbot state: present when:

    • nginx_ssl_enabled
    • ansible_os_family == "Debian"

tasks/configure.yml


Configuration tasks for webserver role

  • name: Deploy main nginx configuration template: src: nginx.conf.j2 dest: "{{ nginx_conf_dir }}/nginx.conf" owner: root group: root mode: '0644' validate: 'nginx -t -c %s' backup: yes notify:

    • Reload nginx tags:
    • config
  • name: Deploy site configurations template: src: site.conf.j2 dest: "{{ nginx_conf_dir }}/sites-available/{{ item.name }}.conf" owner: root group: root mode: '0644' validate: 'nginx -t -c {{ nginx_conf_dir }}/nginx.conf' loop: "{{ nginx_sites }}" when: nginx_sites is defined notify:

    • Reload nginx
  • name: Enable sites file: src: "{{ nginx_conf_dir }}/sites-available/{{ item.name }}.conf" dest: "{{ nginx_conf_dir }}/sites-enabled/{{ item.name }}.conf" state: link loop: "{{ nginx_sites }}" when:

    • nginx_sites is defined
    • item.enabled | default(true) notify:
    • Reload nginx
  • name: Disable default site file: path: "{{ nginx_conf_dir }}/sites-enabled/default" state: absent when: nginx_disable_default_site notify:

    • Reload nginx
  • name: Configure log rotation template: src: logrotate.j2 dest: /etc/logrotate.d/nginx owner: root group: root mode: '0644'

tasks/security.yml


Security tasks for webserver role

  • name: Generate dhparam file command: openssl dhparam -out {{ nginx_conf_dir }}/dhparam.pem 2048 args: creates: "{{ nginx_conf_dir }}/dhparam.pem" when: nginx_ssl_enabled

  • name: Set secure permissions on dhparam file: path: "{{ nginx_conf_dir }}/dhparam.pem" owner: root group: root mode: '0600' when: nginx_ssl_enabled

  • name: Configure firewall rules (ufw) ufw: rule: allow port: "{{ item }}" proto: tcp loop:

    • "80"
    • "443" when:
    • nginx_configure_firewall
    • ansible_os_family == "Debian"
  • name: Configure firewall rules (firewalld) firewalld: service: "{{ item }}" permanent: yes state: enabled immediate: yes loop:

    • http
    • https when:
    • nginx_configure_firewall
    • ansible_os_family == "RedHat"
  • name: Create basic auth file htpasswd: path: "{{ nginx_conf_dir }}/.htpasswd" name: "{{ item.username }}" password: "{{ item.password }}" owner: root group: "{{ nginx_group }}" mode: '0640' loop: "{{ nginx_basic_auth_users }}" when: nginx_basic_auth_users is defined no_log: yes

Role Variables

defaults/main.yml


Default variables for webserver role

These can be overridden in playbooks or inventory

Package and service names

nginx_package_name: nginx nginx_service_name: nginx

User and group

nginx_user: www-data nginx_group: www-data

Directories

nginx_conf_dir: /etc/nginx nginx_log_dir: /var/log/nginx nginx_cache_dir: /var/cache/nginx nginx_pid_file: /var/run/nginx.pid

Main configuration

nginx_worker_processes: auto nginx_worker_connections: 1024 nginx_keepalive_timeout: 65 nginx_client_max_body_size: 10m

Performance tuning

nginx_sendfile: on nginx_tcp_nopush: on nginx_tcp_nodelay: on nginx_gzip: on nginx_gzip_types:

  • text/plain
  • text/css
  • application/json
  • application/javascript
  • text/xml
  • application/xml

Security

nginx_ssl_enabled: no nginx_ssl_protocols: "TLSv1.2 TLSv1.3" nginx_ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256" nginx_ssl_prefer_server_ciphers: on nginx_disable_default_site: yes nginx_configure_firewall: yes nginx_server_tokens: off

Sites configuration

nginx_sites: []

Example:

nginx_sites:

- name: example.com

server_name: example.com www.example.com

root: /var/www/example.com

enabled: yes

ssl: yes

Basic authentication

nginx_basic_auth_users:

- username: admin

password: secretpassword

vars/main.yml


Variables that should not be overridden

nginx_conf_path: "{{ nginx_conf_dir }}/nginx.conf" nginx_error_log: "{{ nginx_log_dir }}/error.log" nginx_access_log: "{{ nginx_log_dir }}/access.log"

OS-specific overrides loaded via include_vars

vars/Debian.yml


nginx_user: www-data nginx_group: www-data nginx_conf_dir: /etc/nginx nginx_service_name: nginx

vars/RedHat.yml


nginx_user: nginx nginx_group: nginx nginx_conf_dir: /etc/nginx nginx_service_name: nginx

Role Handlers

handlers/main.yml


Handlers for webserver role

  • name: Reload nginx service: name: "{{ nginx_service_name }}" state: reloaded listen: "reload nginx"

  • name: Restart nginx service: name: "{{ nginx_service_name }}" state: restarted listen: "restart nginx"

  • name: Validate nginx config command: nginx -t changed_when: false listen: "validate nginx"

  • name: Reload firewall service: name: ufw state: reloaded when: ansible_os_family == "Debian" listen: "reload firewall"

Role Templates

templates/nginx.conf.j2

{{ ansible_managed }}

user {{ nginx_user }}; worker_processes {{ nginx_worker_processes }}; pid {{ nginx_pid_file }};

events { worker_connections {{ nginx_worker_connections }}; use epoll; multi_accept on; }

http { ## # Basic Settings ## sendfile {{ nginx_sendfile | ternary('on', 'off') }}; tcp_nopush {{ nginx_tcp_nopush | ternary('on', 'off') }}; tcp_nodelay {{ nginx_tcp_nodelay | ternary('on', 'off') }}; keepalive_timeout {{ nginx_keepalive_timeout }}; types_hash_max_size 2048; server_tokens {{ nginx_server_tokens | ternary('on', 'off') }}; client_max_body_size {{ nginx_client_max_body_size }};

include {{ nginx_conf_dir }}/mime.types;
default_type application/octet-stream;

##
# SSL Settings
##

{% if nginx_ssl_enabled %} ssl_protocols {{ nginx_ssl_protocols }}; ssl_ciphers {{ nginx_ssl_ciphers }}; ssl_prefer_server_ciphers {{ nginx_ssl_prefer_server_ciphers | ternary('on', 'off') }}; ssl_dhparam {{ nginx_conf_dir }}/dhparam.pem; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; {% endif %}

##
# Logging Settings
##
access_log {{ nginx_access_log }};
error_log {{ nginx_error_log }};

##
# Gzip Settings
##
gzip {{ nginx_gzip | ternary('on', 'off') }};

{% if nginx_gzip %} gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types {{ nginx_gzip_types | join(' ') }}; {% endif %}

##
# Virtual Host Configs
##
include {{ nginx_conf_dir }}/sites-enabled/*;

}

templates/site.conf.j2

{{ ansible_managed }}

Site: {{ item.name }}

{% if item.ssl | default(false) %}

Redirect HTTP to HTTPS

server { listen 80; listen [::]:80; server_name {{ item.server_name }}; return 301 https://$server_name$request_uri; }

server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name {{ item.server_name }};

ssl_certificate {{ item.ssl_cert | default('/etc/letsencrypt/live/' + item.name + '/fullchain.pem') }};
ssl_certificate_key {{ item.ssl_key | default('/etc/letsencrypt/live/' + item.name + '/privkey.pem') }};

{% else %} server { listen 80; listen [::]:80; server_name {{ item.server_name }}; {% endif %}

root {{ item.root | default('/var/www/' + item.name) }};
index {{ item.index | default('index.html index.htm') }};

{% if item.access_log is defined %} access_log {{ item.access_log }}; {% endif %} {% if item.error_log is defined %} error_log {{ item.error_log }}; {% endif %}

{% if item.basic_auth | default(false) %} auth_basic "Restricted Access"; auth_basic_user_file {{ nginx_conf_dir }}/.htpasswd; {% endif %}

location / {

{% if item.proxy_pass is defined %} proxy_pass {{ item.proxy_pass }}; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; {% else %} try_files $uri $uri/ =404; {% endif %} }

{% if item.locations is defined %} {% for location in item.locations %} location {{ location.path }} { {% if location.proxy_pass is defined %} proxy_pass {{ location.proxy_pass }}; {% endif %} {% if location.alias is defined %} alias {{ location.alias }}; {% endif %} {% if location.return is defined %} return {{ location.return }}; {% endif %} } {% endfor %} {% endif %}

# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

}

Role Dependencies

meta/main.yml


galaxy_info: role_name: webserver author: Your Organization description: Install and configure nginx web server company: Your Company license: MIT min_ansible_version: 2.9

platforms: - name: Ubuntu versions: - focal - jammy - name: Debian versions: - buster - bullseye - name: EL versions: - 7 - 8 - 9

galaxy_tags: - web - nginx - webserver - http

dependencies:

  • role: common vars: common_packages: - curl - wget

  • role: firewall when: nginx_configure_firewall

allow_duplicates: no

Using Roles in Playbooks

Simple Role Usage


  • name: Configure web servers hosts: webservers become: yes

    roles:

    • webserver

Role with Variables


  • name: Configure web servers with custom settings hosts: webservers become: yes

    roles:

    • role: webserver vars: nginx_worker_processes: 4 nginx_ssl_enabled: yes nginx_sites: - name: example.com server_name: example.com www.example.com root: /var/www/example.com ssl: yes ssl_cert: /etc/ssl/certs/example.com.crt ssl_key: /etc/ssl/private/example.com.key

Role with Tags


  • name: Configure infrastructure hosts: all become: yes

    roles:

    • role: webserver tags:

      • web
      • nginx
    • role: database tags:

      • db
      • postgres

Pre and Post Tasks


  • name: Deploy web application hosts: webservers become: yes

    pre_tasks:

    • name: Announce deployment debug: msg: "Starting deployment to {{ inventory_hostname }}"

    • name: Check disk space command: df -h / register: disk_space changed_when: false

    roles:

    • webserver
    • monitoring

    post_tasks:

    • name: Verify nginx is responding uri: url: http://localhost status_code: 200 retries: 3 delay: 5

    • name: Notify completion debug: msg: "Deployment completed successfully"

Role Inclusion Methods

Static Import


  • name: Configure servers hosts: all

    tasks:

    • name: Import webserver role import_role: name: webserver vars: nginx_worker_processes: 2 tags:
      • webserver

Dynamic Include


  • name: Configure servers based on conditions hosts: all

    tasks:

    • name: Include webserver role for web servers include_role: name: webserver when: "'webservers' in group_names"

    • name: Include database role for db servers include_role: name: database when: "'databases' in group_names"

Import with Task Files


  • name: Custom installation workflow hosts: webservers

    tasks:

    • name: Run pre-installation checks import_role: name: webserver tasks_from: preflight

    • name: Install nginx import_role: name: webserver tasks_from: install

    • name: Configure nginx import_role: name: webserver tasks_from: configure

Creating Roles with Ansible Galaxy

Initialize a New Role

Create role structure

ansible-galaxy init roles/myapp

Create role with custom template

ansible-galaxy init --init-path roles/ myapp

List role files

tree roles/myapp

Install Roles from Galaxy

Install a role

ansible-galaxy install geerlingguy.nginx

Install specific version

ansible-galaxy install geerlingguy.nginx,2.8.0

Install from requirements file

ansible-galaxy install -r requirements.yml

requirements.yml


Install from Ansible Galaxy

  • name: geerlingguy.nginx version: 2.8.0

  • name: geerlingguy.postgresql version: 3.4.0

Install from Git repository

Install from local path

  • name: internal-role src: /path/to/roles/internal-role

Advanced Role Patterns

Role with Multiple Entry Points

roles/webserver/tasks/main.yml


  • name: Default task flow import_tasks: "{{ webserver_task_flow | default('standard') }}.yml"

roles/webserver/tasks/standard.yml


  • import_tasks: install.yml
  • import_tasks: configure.yml
  • import_tasks: security.yml

roles/webserver/tasks/minimal.yml


  • import_tasks: install.yml
  • import_tasks: configure.yml

Conditional Role Execution


  • name: Configure servers with conditional roles hosts: all become: yes

    roles:

    • role: webserver when:

      • ansible_os_family == "Debian"
      • inventory_hostname in groups['webservers']
    • role: webserver-nginx when: webserver_type == "nginx"

    • role: webserver-apache when: webserver_type == "apache"

Nested Role Dependencies

roles/application/meta/main.yml


dependencies:

  • role: webserver vars: nginx_sites: - name: "{{ app_name }}" server_name: "{{ app_domain }}" proxy_pass: "http://localhost:{{ app_port }}"

  • role: database vars: db_name: "{{ app_db_name }}" db_user: "{{ app_db_user }}"

  • role: monitoring vars: monitor_services: - nginx - "{{ app_name }}"

When to Use This Skill

Use the ansible-roles skill when you need to:

  • Structure reusable automation code across multiple playbooks and projects

  • Implement modular infrastructure as code with clear separation of concerns

  • Share automation logic between teams or projects

  • Create distributable automation packages for common infrastructure patterns

  • Organize complex playbooks into manageable, testable components

  • Implement role-based configuration management with variable precedence

  • Build layered infrastructure with role dependencies

  • Version control automation logic independently from playbooks

  • Create standardized infrastructure components for consistency

  • Implement security and compliance requirements through reusable roles

  • Build internal automation libraries for your organization

  • Contribute to or consume community automation from Ansible Galaxy

  • Test infrastructure components in isolation before integration

  • Implement different configurations for development, staging, and production

  • Create self-documenting infrastructure through role metadata

Best Practices

  • Follow standard directory structure - Use ansible-galaxy init to create roles with proper organization

  • Use defaults wisely - Place overridable variables in defaults/main.yml, non-overridable in vars/main.yml

  • Document thoroughly - Include comprehensive README.md with usage examples and variable documentation

  • Keep roles focused - Each role should have a single, well-defined purpose

  • Use role dependencies - Declare dependencies in meta/main.yml rather than in playbooks

  • Tag appropriately - Apply meaningful tags to tasks for selective execution

  • Implement idempotency - Ensure roles can be run multiple times safely

  • Version your roles - Use semantic versioning for role releases

  • Test roles independently - Include test playbooks in tests/ directory

  • Use templates for configuration - Prefer Jinja2 templates over static files for flexibility

  • Implement OS detection - Use ansible_os_family for cross-platform compatibility

  • Secure sensitive data - Use ansible-vault for passwords and secrets in role variables

  • Use handlers correctly - Only notify handlers when configuration changes

  • Validate configurations - Use validate parameter in template/copy modules

  • Name tasks clearly - Use descriptive names that explain what each task does

Common Pitfalls

  • Overly complex roles - Trying to make one role do too many things

  • Poor variable naming - Using generic names that conflict with other roles

  • Missing role prefix - Not prefixing role variables with role name

  • Ignoring variable precedence - Not understanding how Ansible resolves variable conflicts

  • Hard-coded values - Embedding environment-specific values instead of using variables

  • Missing dependencies - Not declaring role dependencies in meta/main.yml

  • No validation - Deploying configurations without validation checks

  • Skipping tests - Not including test playbooks or scenarios

  • Poor handler design - Restarting services unnecessarily or not at all

  • Missing OS support - Assuming all target systems are the same

  • No backup strategy - Not backing up configurations before changes

  • Ignoring idempotency - Using command/shell modules without proper guards

  • Missing tags - Not tagging tasks for selective execution

  • Poor template practices - Complex logic in templates instead of variables

  • No version control - Not versioning roles or tracking changes

Resources

  • Ansible Roles Documentation

  • Ansible Galaxy

  • Role Directory Structure

  • Variable Precedence

  • ansible-galaxy CLI

  • Best Practices

  • Role Dependencies

  • Testing Strategies

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

typescript-type-system

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

typescript-async-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

c-systems-programming

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

cpp-templates-metaprogramming

No summary provided by upstream source.

Repository SourceNeeds Review