Published June 2, 2014

I needed a way to manage Apache VirtualHosts and mod_rewrite rules. There are a handful of Ansible Roles available at Ansible Galaxy to manage Apache VirtualHosts, but none of them also manage mod_rewrite rules.

After figuring out how to include additional content in an Ansible Template file, I was able to quickly put together an Ansible Playbook and Ansible Template to manage my Apache VirtualHosts and their particular mod_rewrite rules.

Ansible Directory

My Ansible environment exists within directory ~/Development/ansible-lab/ on my workstation. Any files or directories created in this post will be created within this directory.

Ansible Inventory File

In my particular case, all of my websites run on two web servers with a load balancer in front of them, so I created file ~/Development/ansible-lab/hosts with the following contents:

[web-servers] webserver1.example.com webserver2.example.com

Ansible Files

The mod_rewrite rules are simple text files stored in directory ~/Development/ansible-lab/files/apache/mod_rewrite/. The files are named vhost1.example.com.conf, vhost2.example.com.conf (after the actual FQDN of the website) and each contains the following contents (these are just examples, the actual text files contain many more mod_rewrite rules):

vhost1.example.com.conf

RewriteEngine On RewriteRule /documentation/2013/01/03/example-post1.html http://vhost1.example.com/2013/01/03/example-post1.html [R=permanent,L] RewriteRule /documentation/2013/03/05/example-post2.html http://vhost1.example.com/2013/03/05/example-post2.html [R=permanent,L]

vhost2.example.com.conf

RewriteEngine On RewriteRule /documentation/2014/02/10/example-post3.html http://vhost2.example.com/2014/02/10/example-post3.html [R=permanent,L] RewriteRule /documentation/2014/05/20/example-post4.html http://vhost2.example.com/2014/05/20/example-post4.html [R=permanent,L]

vhost3.example.com.conf

In this example, the vhost3.example.com Apache VirtualHost never had any mod_rewrite rules, so file vhost3.example.com.conf will not exist in the ~/Development/ansible-lab/files/apache/mod_rewrite/ directory.

Ansible Template

I created Ansible Template ~/Development/ansible-lab/templates/apache_vhost.conf.j2 with the following contents:

NameVirtualHost *:80 <VirtualHost *:80> ServerName {{ item.servername }} DocumentRoot /var/www/html/{{ item.documentrootdir }} ServerAdmin {{ item.serveradmin }} ErrorLog logs/{{ item.errorlog }}-error_log CustomLog logs/{{ item.customlog }}-access_log common <Directory /var/www/html/{{ item.documentrootdir }}> Options None </Directory> {% include "files/apache/mod_rewrite/" + item.documentrootdir + ".conf" ignore missing %} </VirtualHost>

When Ansible is generating the Apache VirtualHost file for vhost1.example.com.conf, the include line (which is Jinja2 syntax) would check if there is a file named vhost1.example.com.conf in the ~/Development/ansible-lab/files/apache/mod_rewrite/ directory. If the file exists, its contents would be included in the generated Apache VirtualHost file, or, if the file does not exist, the Apache VirtualHost file would be generated without any additional content (the ignore missing parameters on the include line enables this).

Take note, the Ansible Playbook was originally stored in directory ~/Development/ansible-lab/playbooks/. But, for all of this to work, it had to be moved to ~/Development/ansible-lab/. There appears to be a path problem with Ansible Templates if the Ansible Playbook is in a directory other than the root Ansible directory. Supposedly this was fixed, but I have not investigated the issue further.

Ansible Playbook

The Ansible Playbook is the last piece to put together. Below are the contents of that playbook.

In this particular example, the Apache VirtualHost parameters are stored within the Ansible Playbook. As the number of Apache VirtualHosts increases, it would be better to move them out of the Ansible Playbook into their own variable file and reference that file within the Ansible Playbook as shown in the Example Playbook section in geerlingguy’s Ansible Apache Role.

Take note that the following Ansible Playbook is written to manage Apache on RHEL/CentOS. Some of the file paths and service names will need to be changed to make it work on Debian/Ubuntu.

--- - hosts: web-servers vars: apache_vhosts_enabled: - servername: "vhost1.example.com" serveradmin: "admin@example.com" documentrootdir: "vhost1.example.com" errorlog: "vhost1.example.com" customlog: "vhost1.example.com" - servername: "vhost2.example.com" serveradmin: "admin@example.com" documentrootdir: "vhost2.example.com" errorlog: "vhost2.example.com" customlog: "vhost2.example.com" apache_vhosts_disabled: - servername: "vhost3.example.com" serveradmin: "admin@example.com" documentrootdir: "vhost3.example.com" errorlog: "vhost3.example.com" customlog: "vhost3.example.com" tasks: - name: Install Apache yum: pkg={{ item }} state=present with_items: - httpd - name: Ensure httpd is running service: name=httpd state=started - name: Ensure httpd is enabled service: name=httpd enabled=yes - name: Create sites.d directory file: path=/etc/httpd/conf.d/sites.d state=directory owner=root group=root mode=0755 - name: Add sites.d Include to httpd.conf lineinfile: dest=/etc/httpd/conf/httpd.conf state=present line='Include conf.d/sites.d/*.conf' notify: - restart httpd - name: Create a VirtualHost file for each enabled VirtualHost template: src=templates/apache_vhost.conf.j2 dest=/etc/httpd/conf.d/sites.d/{{ item.documentrootdir }}.conf owner=root group=root mode=0644 with_items: apache_vhosts_enabled notify: - restart httpd - name: Create web directories for each enabled VirtualHost file: path=/var/www/html/{{ item.documentrootdir }} state=directory owner=apache group=apache mode=0755 with_items: apache_vhosts_enabled - name: Remove VirtualHost file for each disabled VirtualHost file: path=/etc/httpd/conf.d/sites.d/{{ item.documentrootdir }}.conf state=absent with_items: apache_vhosts_disabled notify: - restart httpd - name: Remove web directories for each disabled VirtualHost file: path=/var/www/html/{{ item.documentrootdir }} state=absent with_items: apache_vhosts_disabled handlers: - name: restart httpd service: name=httpd state=restarted

As Apache VirtualHosts are enabled or disabled or more mod_rewrite rules are needed, modify the Ansible Playbook and, if necessary, the mod_rewrite text files and re-run the playbook to apply all of the changes.

References