Ansible Playbooks
Harden Existing WordPress Installation
Welcome
This playbook enhances the security of an existing WordPress installation by setting secure file and directory permissions, securing the WordPress configuration file, hardening MySQL, configuring fail2ban to protect against brute force attacks, and setting up a firewall to allow only necessary traffic.
The file and directory permissions set for the WordPress files and directories (owner: www-data, group: www-data) are commonly used for web servers like Apache and Nginx on Debian-based systems (including Ubuntu), but if you are using alternative ownership/group, you will need to adjust, as well as other portions as necessary.
* Please be aware, the coding on this site is meant to guide. Testing these scripts in a non-production environment is strongly encouraged. I take no responsibility for use of any scripts on this site or on my github repositories.
Playbook:
---
# Ansible Playbook for Hardening an Existing WordPress Installation
# This playbook secures an existing WordPress installation by setting appropriate file permissions,
# securing the wp-config.php file, configuring a firewall, securing the database, and enabling fail2ban.
# Ansible Infrastructure Playbook - JW 6.12.24
- name: Harden Existing WordPress Installation
hosts: wordpress_servers
become: yes
vars:
wordpress_root: "/var/www/html/wordpress" # Path to the WordPress installation
mysql_root_password: "your_secure_mysql_root_password" # MySQL root password
mysql_wordpress_user: "wordpress_user" # MySQL WordPress user
mysql_wordpress_password: "your_secure_wordpress_password" # MySQL WordPress user password
mysql_wordpress_db: "wordpress_db" # MySQL WordPress database
tasks:
- name: Set file permissions for WordPress
find:
paths: "{{ wordpress_root }}"
recurse: yes
file_type: file
register: wordpress_files
- name: Set directory permissions for WordPress
find:
paths: "{{ wordpress_root }}"
recurse: yes
file_type: directory
register: wordpress_directories
- name: Set proper file permissions
file:
path: "{{ item.path }}"
owner: www-data
group: www-data
mode: '0644'
loop: "{{ wordpress_files.files }}"
- name: Set proper directory permissions
file:
path: "{{ item.path }}"
owner: www-data
group: www-data
mode: '0755'
loop: "{{ wordpress_directories.files }}"
- name: Secure wp-config.php file
file:
path: "{{ wordpress_root }}/wp-config.php"
owner: www-data
group: www-data
mode: '0600'
- name: Ensure MySQL is secured
shell: |
mysql -u root -p{{ mysql_root_password }} -e "DELETE FROM mysql.user WHERE User='';"
mysql -u root -p{{ mysql_root_password }} -e "DROP DATABASE IF EXISTS test;"
mysql -u root -p{{ mysql_root_password }} -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';"
mysql -u root -p{{ mysql_root_password }} -e "FLUSH PRIVILEGES;"
- name: Restrict MySQL access to localhost
lineinfile:
path: /etc/mysql/mysql.conf.d/mysqld.cnf
regexp: '^bind-address'
line: 'bind-address = 127.0.0.1'
notify: Restart MySQL
- name: Install fail2ban
apt:
name: fail2ban
state: present
update_cache: yes
- name: Configure fail2ban for WordPress
copy:
dest: /etc/fail2ban/jail.d/wordpress.conf
content: |
[wordpress]
enabled = true
filter = wordpress
action = iptables-multiport[name=WordPress, port="http,https"]
logpath = {{ wordpress_root }}/wp-content/debug.log
maxretry = 5
notify: Restart fail2ban
- name: Create fail2ban filter for WordPress
copy:
dest: /etc/fail2ban/filter.d/wordpress.conf
content: |
[Definition]
failregex = ^<HOST> .* "POST .*wp-login.php
notify: Restart fail2ban
- name: Configure UFW firewall
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
comment: "Allow HTTP and HTTPS traffic"
loop:
- "80"
- "443"
state: enabled
handlers:
- name: Restart MySQL
service:
name: mysql
state: restarted
- name: Restart fail2ban
service:
name: fail2ban
state: restarted