It would be interesting to reuse the code that I wrote for the mass scaling in the future if ever needed, so I will just put it here on my blog.

In my test environment I have one ansible control node(alienship) and two more nodes as a target servers, servers are named mavder1(control),  mavder2(target) and mavder3(target).

My inventory file looks like this.

[servers]
mavder[2:3]

I have created directory structure for the role with the ansible-galaxy command.

ansible-galaxy init --init-path=/etc/ansible/roles apache

I have removed some unneeded folders from the folder(role) structure and this is how it looks like.

Screenshot_7

First I have defined some variables in the defaults directory, just in the main.yml file, that will be used against creation of virtual hosts and generation of SSL certificates, code is structured as Ansible dictionary, code right below.

---
 httpd_vars:
   - {directory: /web/www/alienship, servername: www.alienship.com, serveradmin: nemanja@alienship, domain: alienship.com}
   - {directory: /web/www/lucidforest, servername: www.lucidforest.com, serveradmin: nemanja@lucidforest, domain: lucidforests.com}

Next I have defined some handlers, specifically for firewalld and httpd services, both of them listening on the separate tagged name and on one common name, code right below, file to refer to – main.yml in handlers directory.

---
 - name: restart_firewall
   service:
     name: firewalld
     state: restarted
   listen: "restart services"
 - name: restart_apache
   service:
     name: httpd
     state: restarted
   listen: "restart services"

Next thing, I have created VirtualHosts Jinja2 template that will create vhosts with http to https redirection, it will use self signed SSL certificate that we will generate in one of the tasks, code right below, file to refer to – virtualhosts.conf.j2 in templates directory.

{% for item in httpd_vars %}
<VirtualHost *:80>
        ServerName {{ item.servername }}
        Redirect permanent / https://{{ item.servername }}
</VirtualHost>
<VirtualHost *:443>
        # General Section
        ServerName {{ item.servername }}
        ServerAdmin {{ item.serveradmin }}
        DocumentRoot {{ item.directory }}
        ErrorLog "/var/log/httpd/{{ item.servername }}-error_log"
        CustomLog "/var/log/httpd/{{ item.servername }}-access_log" common
        # SSL Section
        SSLEngine On
        SSLCertificateFile "/etc/pki/tls/certs/{{ item.servername }}.crt"
        SSLCertificateKeyFile "/etc/pki/tls/private/{{ item.servername }}.key"
        #Directory Section
        <Directory "{{ item.directory }}">
                AllowOverride None
                Options none
                Require all granted
        </Directory>
</VirtualHost>
{% endfor %}

In order to serve some content, we also need basic index.html file, I also completed this via Jinja2 template, file to refer to – index.j2 in templates directory.

This is index page of {{ ansible_hostname }}

It’s time to define a tasks, in the main.yml file in tasks directory I just included separate yaml file that actually contains everything, like this.

---
 - include: install_apache.yml

Now comes the code from install_apache.yml file.

---
 - name: Install required yum packages
   yum:
     name: "{{item}}"
     state: latest
   with_items:
     - httpd
     - mod_ssl
     - firewalld
     - libsemanage-devel
   tags:
     - install_yum_packages
 - name: Remove Python ssl package
   yum:
     name: "{{item}}"
     state: absent
   with_items:
     - pyOpenSSL
 - name: Install proper python ssl package
   shell: pip install pyOpenSSL
 - name: Ensure SELinux is configured
   selinux:
     policy: targeted
     state: enforcing
   when: ansible_selinux.config_mode != "enforcing"
 - name: Configure httpd service and firewall
   service:
     name: "{{item}}"
     enabled: yes
     state: started
   with_items:
     - httpd
     - firewalld
 - name: Configure firewall to allow https/https traffic
   firewalld:
     zone: public
     immediate: yes
     permanent: yes
     service: "{{item}}"
     state: enabled
   with_items:
     - http
     - https
   notify: restart_firewall
 - name: Configure apache directories
   file:
     state: directory
     mode: 0755
     owner: root
     group: root
     path: "{{item.directory}}"
   with_items: "{{httpd_vars}}"
 - name: Set appropriate SELinux label
   sefcontext:
     target: "{{item.directory}}(/.*)?"
     setype: httpd_sys_content_t
     state: present
   with_items: "{{httpd_vars}}"
 - name: Trigger restorecon
   shell: restorecon -R "{{item.directory}}"
   with_items: "{{httpd_vars}}"
 - name: Generate SSL key
   openssl_privatekey:
     path: "/etc/pki/tls/private/{{item.servername}}.key"
   with_items: "{{httpd_vars}}"
   tags:
     - generate_ssl
 - name: Generate SSL CSR.
   openssl_csr:
     path: "/etc/pki/tls/certs/{{item.servername}}.csr"
     privatekey_path: "/etc/pki/tls/private/{{item.servername}}.key"
     common_name: "{{item.servername}}"
   with_items: "{{httpd_vars}}"
   tags:
     - generate_ssl
 - name: Generate SSL certificate
   openssl_certificate:
     path: "/etc/pki/tls/certs/{{item.servername}}.crt"
     privatekey_path: "/etc/pki/tls/private/{{item.servername}}.key"
     csr_path: "/etc/pki/tls/certs/{{item.servername}}.csr"
     provider: selfsigned
   with_items: "{{httpd_vars}}"
   tags:
     - generate_ssl
 - name: Deploy VirtualHosts file
   template:
     src: virtualhosts.conf.j2
     dest: /etc/httpd/conf.d/virtualhosts.conf
   notify: restart_apache
 - name: Deploy simple index.html file
   template:
     src: index.j2
     dest: "{{item.directory}}/index.html"
   with_items: "{{httpd_vars}}"
   notify: restart_apache
...

Last but not least, we have to define our playbook that will execute the actual role against our hosts, code right below.

---
 - hosts: servers
   become: yes
   remote_user: user
   any_errors_fatal: yes
   roles:
     - role: apache

At the end, we have fully functional Apache web server serving two virtual hosts armed with self signed SSL, this shows how easy is to scale mass infrastructure with Ansible, thanks for reading.