instruction: Create an Ansible playbook for setting up a web server with SSL certificates
output: Here's a comprehensive Ansible playbook for web server setup with SSL:
  
  ```yaml
  # site.yml - Main playbook
  ---
  - name: Setup Web Server with SSL
   hosts: web_servers
   become: yes
   gather_facts: yes
   vars:
   domain_name: "{{ ansible_fqdn | default('example.com') }}"
   web_user: www-data
   web_group: www-data
   ssl_cert_path: "/etc/ssl/certs"
   ssl_key_path: "/etc/ssl/private"
   nginx_conf_path: "/etc/nginx"
   certbot_email: "admin@{{ domain_name }}"
   
   pre_tasks:
   - name: Update package cache
   apt:
   update_cache: yes
   cache_valid_time: 3600
   when: ansible_os_family == "Debian"
   
   - name: Update package cache (RHEL)
   yum:
   update_cache: yes
   when: ansible_os_family == "RedHat"
  
   roles:
   - common
   - nginx
   - ssl
   - firewall
   - monitoring
   
   post_tasks:
   - name: Verify web server is running
   uri:
   url: "https://{{ domain_name }}"
   method: GET
   validate_certs: yes
   delegate_to: localhost
   run_once: true
   
   - name: Send notification
   mail:
   to: "{{ certbot_email }}"
   subject: "Web server {{ domain_name }} deployed successfully"
   body: "Web server has been deployed and is accessible at https://{{ domain_name }}"
   delegate_to: localhost
   run_once: true
   ignore_errors: yes
  
  # roles/common/tasks/main.yml
  ---
  - name: Install base packages
   package:
   name:
   - curl
   - wget
   - unzip
   - git
   - htop
   - vim
   - fail2ban
   state: present
  
  - name: Configure timezone
   timezone:
   name: "{{ timezone | default('UTC') }}"
   
  - name: Setup log rotation
   template:
   src: logrotate.j2
   dest: /etc/logrotate.d/webserver
   mode: '0644'
   
  - name: Create web user
   user:
   name: "{{ web_user }}"
   group: "{{ web_group }}"
   system: yes
   shell: /bin/false
   home: /var/www
   create_home: no
   
  - name: Create web directories
   file:
   path: "{{ item }}"
   state: directory
   owner: "{{ web_user }}"
   group: "{{ web_group }}"
   mode: '0755'
   loop:
   - /var/www
   - /var/www/html
   - /var/log/nginx
   - /etc/nginx/ssl
  
  # roles/nginx/tasks/main.yml
  ---
  - name: Install Nginx
   package:
   name: nginx
   state: present
   
  - name: Remove default nginx config
   file:
   path: "{{ nginx_conf_path }}/sites-enabled/default"
   state: absent
   notify: restart nginx
   
  - name: Create nginx main config
   template:
   src: nginx.conf.j2
   dest: "{{ nginx_conf_path }}/nginx.conf"
   backup: yes
   validate: 'nginx -t -c %s'
   notify: restart nginx
   
  - name: Create nginx security config
   template:
   src: security.conf.j2
   dest: "{{ nginx_conf_path }}/conf.d/security.conf"
   notify: restart nginx
   
  - name: Create site configuration
   template:
   src: site.conf.j2
   dest: "{{ nginx_conf_path }}/sites-available/{{ domain_name }}.conf"
   validate: 'nginx -t'
   notify: restart nginx
   
  - name: Enable site configuration
   file:
   src: "{{ nginx_conf_path }}/sites-available/{{ domain_name }}.conf"
   dest: "{{ nginx_conf_path }}/sites-enabled/{{ domain_name }}.conf"
   state: link
   notify: restart nginx
   
  - name: Create default index page
   template:
   src: index.html.j2
   dest: /var/www/html/index.html
   owner: "{{ web_user }}"
   group: "{{ web_group }}"
   mode: '0644'
   
  - name: Start and enable nginx
   systemd:
   name: nginx
   state: started
   enabled: yes
   daemon_reload: yes
  
  # roles/nginx/templates/nginx.conf.j2
  user {{ web_user }};
  worker_processes auto;
  pid /run/nginx.pid;
  
  events {
   worker_connections 1024;
   use epoll;
   multi_accept on;
  }
  
  http {
   # Basic Settings
   sendfile on;
   tcp_nopush on;
   tcp_nodelay on;
   keepalive_timeout 65;
   types_hash_max_size 2048;
   server_tokens off;
   client_max_body_size 64M;
   
   # MIME Types
   include /etc/nginx/mime.types;
   default_type application/octet-stream;
   
   # SSL Settings
   ssl_protocols TLSv1.2 TLSv1.3;
   ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
   ssl_prefer_server_ciphers on;
   ssl_session_cache shared:SSL:10m;
   ssl_session_timeout 10m;
   
   # Logging
   log_format main '$remote_addr - $remote_user [$time_local] "$request" '
   '$status $body_bytes_sent "$http_referer" '
   '"$http_user_agent" "$http_x_forwarded_for"';
   
   access_log /var/log/nginx/access.log main;
   error_log /var/log/nginx/error.log warn;
   
   # Gzip Compression
   gzip on;
   gzip_vary on;
   gzip_min_length 1024;
   gzip_types
   text/plain
   text/css
   text/xml
   text/javascript
   application/javascript
   application/xml+rss
   application/json;
   
   # Rate Limiting
   limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;
   limit_req_zone $binary_remote_addr zone=api:10m rate=1r/s;
   
   # Include configurations
   include {{ nginx_conf_path }}/conf.d/*.conf;
   include {{ nginx_conf_path }}/sites-enabled/*;
  }
  
  # roles/nginx/templates/site.conf.j2
  server {
   listen 80;
   server_name {{ domain_name }};
   return 301 https://$server_name$request_uri;
  }
  
  server {
   listen 443 ssl http2;
   server_name {{ domain_name }};
   
   root /var/www/html;
   index index.html index.htm;
   
   # SSL Configuration
   ssl_certificate {{ ssl_cert_path }}/{{ domain_name }}.crt;
   ssl_certificate_key {{ ssl_key_path }}/{{ domain_name }}.key;
   ssl_trusted_certificate {{ ssl_cert_path }}/{{ domain_name }}-chain.crt;
   
   # HSTS
   add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
   
   # Security headers
   add_header X-Frame-Options DENY always;
   add_header X-Content-Type-Options nosniff always;
   add_header X-XSS-Protection "1; mode=block" always;
   add_header Referrer-Policy "strict-origin-when-cross-origin" always;
   add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;" always;
   
   # Main location
   location / {
   try_files $uri $uri/ =404;
   
   # Cache static files
   location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
   expires 1y;
   add_header Cache-Control "public, immutable";
   }
   }
   
   # API rate limiting
   location /api/ {
   limit_req zone=api burst=5 nodelay;
   proxy_pass http://backend;
   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;
   }
   
   # Health check endpoint
   location /health {
   access_log off;
   return 200 "OK";
   add_header Content-Type text/plain;
   }
   
   # Hide sensitive files
   location ~ /\. {
   deny all;
   access_log off;
   log_not_found off;
   }
   
   # Custom error pages
   error_page 404 /404.html;
   error_page 500 502 503 504 /50x.html;
   
   location = /50x.html {
   root /var/www/html;
   }
  }
  
  # roles/ssl/tasks/main.yml
  ---
  - name: Install certbot
   package:
   name:
   - certbot
   - python3-certbot-nginx
   state: present
   
  - name: Check if certificate exists
   stat:
   path: "{{ ssl_cert_path }}/{{ domain_name }}.crt"
   register: cert_exists
   
  - name: Generate self-signed certificate (temporary)
   block:
   - name: Create private key
   openssl_privatekey:
   path: "{{ ssl_key_path }}/{{ domain_name }}.key"
   size: 2048
   mode: '0600'
   
   - name: Create certificate signing request
   openssl_csr:
   path: "{{ ssl_cert_path }}/{{ domain_name }}.csr"
   privatekey_path: "{{ ssl_key_path }}/{{ domain_name }}.key"
   common_name: "{{ domain_name }}"
   subject_alt_name:
   - "DNS:{{ domain_name }}"
   - "DNS:www.{{ domain_name }}"
   
   - name: Create self-signed certificate
   openssl_certificate:
   path: "{{ ssl_cert_path }}/{{ domain_name }}.crt"
   privatekey_path: "{{ ssl_key_path }}/{{ domain_name }}.key"
   csr_path: "{{ ssl_cert_path }}/{{ domain_name }}.csr"
   provider: selfsigned
   mode: '0644'
   when: not cert_exists.stat.exists
   
  - name: Obtain Let's Encrypt certificate
   command: >
   certbot --nginx 
   --email {{ certbot_email }} 
   --agree-tos 
   --no-eff-email 
   --domains {{ domain_name }},www.{{ domain_name }} 
   --non-interactive
   register: certbot_result
   failed_when: certbot_result.rc != 0 and 'Certificate not yet due for renewal' not in certbot_result.stdout
   changed_when: certbot_result.rc == 0 and 'Certificate not yet due for renewal' not in certbot_result.stdout
   
  - name: Setup certificate auto-renewal
   cron:
   name: "Renew Let's Encrypt certificates"
   minute: "0"
   hour: "2"
   job: "/usr/bin/certbot renew --quiet && /bin/systemctl reload nginx"
   user: root
   
  - name: Test certificate renewal
   command: certbot renew --dry-run
   register: renewal_test
   failed_when: renewal_test.rc != 0
   changed_when: false
  
  # roles/firewall/tasks/main.yml
  ---
  - name: Install UFW
   package:
   name: ufw
   state: present
   
  - name: Reset UFW to defaults
   ufw:
   state: reset
   
  - name: Set UFW default policies
   ufw:
   direction: "{{ item.direction }}"
   policy: "{{ item.policy }}"
   loop:
   - { direction: 'incoming', policy: 'deny' }
   - { direction: 'outgoing', policy: 'allow' }
   
  - name: Allow SSH
   ufw:
   rule: allow
   name: OpenSSH
   
  - name: Allow HTTP
   ufw:
   rule: allow
   port: '80'
   proto: tcp
   
  - name: Allow HTTPS
   ufw:
   rule: allow
   port: '443'
   proto: tcp
   
  - name: Enable UFW
   ufw:
   state: enabled
   
  - name: Configure fail2ban
   template:
   src: jail.local.j2
   dest: /etc/fail2ban/jail.local
   backup: yes
   notify: restart fail2ban
   
  - name: Start and enable fail2ban
   systemd:
   name: fail2ban
   state: started
   enabled: yes
  
  # roles/monitoring/tasks/main.yml
  ---
  - name: Install monitoring tools
   package:
   name:
   - htop
   - iotop
   - nethogs
   - ncdu
   state: present
   
  - name: Setup log monitoring script
   template:
   src: monitor_logs.sh.j2
   dest: /usr/local/bin/monitor_logs.sh
   mode: '0755'
   
  - name: Setup log monitoring cron
   cron:
   name: "Monitor web server logs"
   minute: "*/5"
   job: "/usr/local/bin/monitor_logs.sh"
   user: root
   
  - name: Create status check script
   template:
   src: health_check.sh.j2
   dest: /usr/local/bin/health_check.sh
   mode: '0755'
   
  # handlers/main.yml
  ---
  - name: restart nginx
   systemd:
   name: nginx
   state: restarted
   
  - name: reload nginx
   systemd:
   name: nginx
   state: reloaded
   
  - name: restart fail2ban
   systemd:
   name: fail2ban
   state: restarted
  
  # inventory/hosts.yml
  ---
  all:
   children:
   web_servers:
   hosts:
   web1.example.com:
   ansible_host: 192.168.1.10
   domain_name: api.example.com
   web2.example.com:
   ansible_host: 192.168.1.11
   domain_name: app.example.com
   vars:
   ansible_user: ubuntu
   ansible_ssh_private_key_file: ~/.ssh/id_rsa
   timezone: America/New_York
  ```
  
  This Ansible playbook provides:
  - Complete web server setup with Nginx
  - SSL certificate management with Let's Encrypt
  - Security configuration with firewall and fail2ban
  - Monitoring and logging setup
  - Automated certificate renewal
  - Security headers and best practices
  - Modular role-based structure