513 lines
14 KiB
YAML
Executable File
513 lines
14 KiB
YAML
Executable File
---
|
|
# Ubuntu/Debian LEMP WordPress installation
|
|
- name: "Install LEMP stack with WordPress (Ubuntu/Debian)"
|
|
hosts: all
|
|
become: yes
|
|
|
|
pre_tasks:
|
|
- name: Gather OS facts
|
|
setup:
|
|
gather_subset:
|
|
- '!all'
|
|
- '!min'
|
|
- 'distribution'
|
|
- 'distribution_version'
|
|
- 'os_family'
|
|
|
|
- name: Load Debian family variables
|
|
include_vars: "../vars/debian-family.yml"
|
|
|
|
- name: Debug OS information
|
|
debug:
|
|
msg: |
|
|
OS Family: {{ ansible_os_family }}
|
|
Distribution: {{ ansible_distribution }}
|
|
Version: {{ ansible_distribution_version }}
|
|
Supported: Ubuntu/Debian family systems
|
|
|
|
- name: Verify supported OS
|
|
fail:
|
|
msg: "This playbook only supports Ubuntu/Debian systems. Detected: {{ ansible_os_family }}"
|
|
when: ansible_os_family != "Debian"
|
|
|
|
# Environment Detection and Configuration
|
|
- name: Detect if running in Docker
|
|
stat:
|
|
path: /.dockerenv
|
|
register: docker_env
|
|
tags: always
|
|
|
|
- name: Check for deployment_environment override
|
|
set_fact:
|
|
environment_override: "{{ deployment_environment is defined }}"
|
|
tags: always
|
|
|
|
- name: Set deployment environment (auto-detect or override)
|
|
set_fact:
|
|
deployment_environment: >-
|
|
{{ deployment_environment | default('docker' if docker_env.stat.exists else 'bare_metal') }}
|
|
tags: always
|
|
|
|
- name: Set WordPress site URL with smart defaults
|
|
set_fact:
|
|
wp_site_url: "{{ wp_site_url | default(_auto_wp_url) }}"
|
|
vars:
|
|
_auto_wp_url: >-
|
|
{{ 'http://localhost:8080' if (deployment_environment == 'docker')
|
|
else 'http://' + (ansible_default_ipv4.address | default('localhost')) }}
|
|
tags: always
|
|
|
|
- name: Debug deployment configuration
|
|
debug:
|
|
msg: |
|
|
Environment: {{ deployment_environment }} ({{ 'overridden' if environment_override else 'auto-detected' }})
|
|
WordPress URL: {{ wp_site_url }}
|
|
Docker detected: {{ docker_env.stat.exists }}
|
|
tags: always
|
|
|
|
vars:
|
|
# Default PHP version (will be overridden by detection)
|
|
php_version: "8.4"
|
|
|
|
# WordPress Configuration
|
|
wordpress_path: "{{ web_root }}"
|
|
wordpress_url: "http://{{ ansible_default_ipv4.address | default('localhost') }}"
|
|
|
|
# Database Configuration (use inventory variables or these defaults)
|
|
default_mysql_root_password: "{{ mysql_root_password | default('secure_root_password_123') }}"
|
|
default_wordpress_db_name: "{{ wordpress_db_name | default('wordpress_db') }}"
|
|
default_wordpress_db_user: "{{ wordpress_db_user | default('wordpress_user') }}"
|
|
default_wordpress_db_password: "{{ wordpress_db_password | default('secure_wp_password_123') }}"
|
|
|
|
# WordPress Admin (use inventory variables directly)
|
|
# These variables come from inventory/production.yml
|
|
# wp_admin_user, wp_admin_password, wp_admin_email, wp_site_title
|
|
|
|
# Auto-Update Configuration
|
|
update_cron_enabled: true
|
|
|
|
tasks:
|
|
# IMPORTANT: Pre-flight checks - create basic directory structure FIRST
|
|
- name: Ensure /var/www exists
|
|
file:
|
|
path: /var/www
|
|
state: directory
|
|
mode: '0755'
|
|
tags: [preflight]
|
|
|
|
- name: Create web root directory
|
|
file:
|
|
path: /var/www/html
|
|
state: directory
|
|
owner: www-data
|
|
group: www-data
|
|
mode: '0755'
|
|
tags: [preflight]
|
|
|
|
- name: Create PHP-FPM log directory
|
|
file:
|
|
path: "/var/log/php{{ php_version }}-fpm"
|
|
state: directory
|
|
mode: '0755'
|
|
tags: [preflight]
|
|
|
|
# Package Installation
|
|
- name: Update package cache
|
|
apt:
|
|
update_cache: yes
|
|
cache_valid_time: 3600
|
|
tags: packages
|
|
|
|
- name: Install essential packages
|
|
apt:
|
|
name:
|
|
- gnupg
|
|
- nginx
|
|
state: present
|
|
tags: [packages, nginx]
|
|
|
|
- name: Detect available PHP version and set fallback
|
|
shell: |
|
|
if apt-cache show php8.4-fpm >/dev/null 2>&1; then
|
|
echo "8.4"
|
|
elif apt-cache show php8.3-fpm >/dev/null 2>&1; then
|
|
echo "8.3"
|
|
else
|
|
echo "none"
|
|
fi
|
|
register: php_version_detect
|
|
changed_when: false
|
|
tags: packages
|
|
|
|
- name: Set PHP version fact
|
|
set_fact:
|
|
php_version: "{{ php_version_detect.stdout }}"
|
|
tags: packages
|
|
|
|
- name: Install PHP with fallback (try 8.4, fallback to 8.3)
|
|
apt:
|
|
name:
|
|
- "php{{ php_version }}-fpm"
|
|
- "php{{ php_version }}-mysql"
|
|
- "php{{ php_version }}-curl"
|
|
- "php{{ php_version }}-gd"
|
|
- "php{{ php_version }}-intl"
|
|
- "php{{ php_version }}-mbstring"
|
|
- "php{{ php_version }}-soap"
|
|
- "php{{ php_version }}-xml"
|
|
- "php{{ php_version }}-xmlrpc"
|
|
- "php{{ php_version }}-zip"
|
|
state: present
|
|
register: php_install_result
|
|
tags: packages
|
|
|
|
- name: Install remaining packages
|
|
package:
|
|
name: "{{ packages | reject('search', '^php') | list }}"
|
|
state: present
|
|
tags: packages
|
|
|
|
- name: Display PHP version installed
|
|
debug:
|
|
msg: "Using PHP version {{ php_version }}"
|
|
tags: packages
|
|
|
|
- name: Set PHP FPM service name dynamically
|
|
set_fact:
|
|
php_fpm_service: "php{{ php_version }}-fpm"
|
|
tags: packages
|
|
|
|
# Service Management
|
|
- name: Start and enable Nginx
|
|
service:
|
|
name: "{{ nginx_service }}"
|
|
state: started
|
|
enabled: yes
|
|
tags: nginx
|
|
|
|
- name: Start and enable MySQL/MariaDB
|
|
service:
|
|
name: "{{ mysql_service }}"
|
|
state: started
|
|
enabled: yes
|
|
tags: mysql
|
|
|
|
- name: Start and enable PHP-FPM
|
|
service:
|
|
name: "{{ php_fpm_service }}"
|
|
state: started
|
|
enabled: yes
|
|
tags: php
|
|
|
|
# Firewall Configuration
|
|
- name: Configure firewall (UFW)
|
|
ufw:
|
|
rule: allow
|
|
port: "{{ item }}"
|
|
proto: tcp
|
|
loop:
|
|
- "22"
|
|
- "80"
|
|
- "443"
|
|
tags: firewall
|
|
|
|
# MySQL Security (Ubuntu 24.04 fix for auth_socket)
|
|
- name: Set MySQL root password (using auth_socket first)
|
|
mysql_user:
|
|
name: root
|
|
password: "{{ mysql_root_password }}"
|
|
plugin: mysql_native_password
|
|
login_unix_socket: /var/run/mysqld/mysqld.sock
|
|
state: present
|
|
become: true
|
|
tags: mysql
|
|
|
|
- name: Create MySQL configuration for root
|
|
template:
|
|
src: ../templates/my.cnf.j2
|
|
dest: /root/.my.cnf
|
|
mode: '0600'
|
|
tags: mysql
|
|
|
|
- name: Remove anonymous MySQL users
|
|
mysql_user:
|
|
name: ""
|
|
host_all: yes
|
|
state: absent
|
|
tags: mysql
|
|
|
|
- name: Remove MySQL test database
|
|
mysql_db:
|
|
name: test
|
|
state: absent
|
|
tags: mysql
|
|
|
|
# WordPress Database Setup
|
|
- name: Create WordPress database
|
|
mysql_db:
|
|
name: "{{ wordpress_db_name }}"
|
|
state: present
|
|
tags: mysql
|
|
|
|
- name: Create WordPress database user
|
|
mysql_user:
|
|
name: "{{ wordpress_db_user }}"
|
|
password: "{{ wordpress_db_password }}"
|
|
priv: "{{ wordpress_db_name }}.*:ALL"
|
|
host: localhost
|
|
state: present
|
|
tags: mysql
|
|
|
|
# WordPress Installation
|
|
- name: Create web root directory
|
|
file:
|
|
path: "{{ wordpress_path }}"
|
|
state: directory
|
|
owner: www-data
|
|
group: www-data
|
|
mode: '0755'
|
|
tags: wordpress
|
|
|
|
- name: Remove default nginx index file
|
|
file:
|
|
path: "{{ wordpress_path }}/index.nginx-debian.html"
|
|
state: absent
|
|
tags: wordpress
|
|
|
|
- name: Download WordPress
|
|
get_url:
|
|
url: https://wordpress.org/latest.tar.gz
|
|
dest: /tmp/wordpress.tar.gz
|
|
mode: '0644'
|
|
tags: wordpress
|
|
|
|
- name: Extract WordPress
|
|
unarchive:
|
|
src: /tmp/wordpress.tar.gz
|
|
dest: /tmp/
|
|
remote_src: yes
|
|
tags: wordpress
|
|
|
|
- name: Copy WordPress files
|
|
command: "cp -r /tmp/wordpress/. {{ wordpress_path }}/"
|
|
args:
|
|
creates: "{{ wordpress_path }}/wp-config-sample.php"
|
|
tags: wordpress
|
|
|
|
- name: Set WordPress file permissions
|
|
file:
|
|
path: "{{ wordpress_path }}"
|
|
owner: "{{ nginx_user }}"
|
|
group: "{{ nginx_user }}"
|
|
recurse: yes
|
|
tags: wordpress
|
|
|
|
# SSL Configuration (optional)
|
|
- name: Generate self-signed SSL certificate (if SSL enabled but no cert provided)
|
|
command: >
|
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048
|
|
-keyout {{ ssl_cert_key_path | default('/etc/ssl/private/nginx-selfsigned.key') }}
|
|
-out {{ ssl_cert_path | default('/etc/ssl/certs/nginx-selfsigned.crt') }}
|
|
-subj "/C=DE/ST=State/L=City/O=Organization/OU=OrgUnit/CN={{ domain_name }}"
|
|
when:
|
|
- ssl_enabled | default(false)
|
|
- not (ssl_cert_path is defined and ssl_cert_key_path is defined)
|
|
tags: ssl
|
|
|
|
# Nginx Configuration
|
|
- name: Configure Nginx for WordPress
|
|
template:
|
|
src: >-
|
|
../templates/{% if ssl_enabled | default(false) %}wordpress-ssl.nginx.j2{%
|
|
else %}wordpress.nginx.j2{% endif %}
|
|
dest: "{{ nginx_sites_available }}/wordpress"
|
|
notify: restart nginx
|
|
tags: nginx
|
|
|
|
- name: Enable WordPress site
|
|
file:
|
|
src: "{{ nginx_sites_available }}/wordpress"
|
|
dest: "{{ nginx_sites_enabled }}/wordpress"
|
|
state: link
|
|
notify: restart nginx
|
|
tags: nginx
|
|
|
|
- name: Remove default Nginx site
|
|
file:
|
|
path: "{{ nginx_sites_enabled }}/default"
|
|
state: absent
|
|
notify: restart nginx
|
|
tags: nginx
|
|
|
|
# PHP Configuration
|
|
- name: Configure PHP-FPM pool
|
|
template:
|
|
src: ../templates/www.conf.j2
|
|
dest: "{{ php_fpm_pool_path }}/www.conf"
|
|
backup: yes
|
|
notify: restart php-fpm
|
|
tags: php
|
|
|
|
- name: Configure PHP settings
|
|
lineinfile:
|
|
path: "{{ php_cli_config_path }}/php.ini"
|
|
regexp: "{{ item.regexp }}"
|
|
line: "{{ item.line }}"
|
|
backup: yes
|
|
loop:
|
|
- { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 64M' }
|
|
- { regexp: '^post_max_size', line: 'post_max_size = 64M' }
|
|
- { regexp: '^memory_limit', line: 'memory_limit = 256M' }
|
|
- { regexp: '^max_execution_time', line: 'max_execution_time = 300' }
|
|
notify: restart php-fpm
|
|
tags: php
|
|
|
|
# WordPress Configuration
|
|
- name: Configure WordPress
|
|
template:
|
|
src: ../templates/wp-config.php.j2
|
|
dest: "{{ wordpress_path }}/wp-config.php"
|
|
owner: www-data
|
|
group: www-data
|
|
mode: '0600'
|
|
tags: wordpress
|
|
|
|
# WP-CLI Installation
|
|
- name: Download WP-CLI
|
|
get_url:
|
|
url: https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
|
|
dest: /usr/local/bin/wp
|
|
mode: '0755'
|
|
tags: wp-cli
|
|
|
|
- name: Verify WP-CLI installation
|
|
command: wp --info
|
|
environment:
|
|
HOME: "{{ wordpress_path }}"
|
|
register: wp_cli_info
|
|
tags: wp-cli
|
|
|
|
- name: Display WP-CLI info
|
|
debug:
|
|
var: wp_cli_info.stdout_lines
|
|
tags: wp-cli
|
|
|
|
# WordPress Core Installation
|
|
- name: Install WordPress Core
|
|
command: >
|
|
wp core install
|
|
--url="{{ wp_site_url }}"
|
|
--title="{{ wp_site_title }}"
|
|
--admin_user="{{ wp_admin_user }}"
|
|
--admin_password="{{ wp_admin_password }}"
|
|
--admin_email="{{ wp_admin_email }}"
|
|
--path="{{ wordpress_path }}"
|
|
--allow-root
|
|
environment:
|
|
HOME: "{{ wordpress_path }}"
|
|
tags: wp-install
|
|
|
|
- name: Set WordPress file ownership after installation
|
|
file:
|
|
path: "{{ wordpress_path }}"
|
|
owner: "{{ nginx_user }}"
|
|
group: "{{ nginx_user }}"
|
|
recurse: yes
|
|
tags: wp-install
|
|
|
|
- name: Display WordPress installation success
|
|
debug:
|
|
msg: |
|
|
WordPress installation completed!
|
|
URL: {{ wp_site_url }}
|
|
Admin User: {{ wp_admin_user }}
|
|
Admin Password: {{ wp_admin_password }}
|
|
Admin Email: {{ wp_admin_email }}
|
|
tags: wp-install
|
|
|
|
# WordPress Auto-Update Setup
|
|
- name: Create update script directory
|
|
file:
|
|
path: /var/backups/wordpress
|
|
state: directory
|
|
mode: '0755'
|
|
tags: update
|
|
|
|
- name: Deploy WordPress update script
|
|
copy:
|
|
src: ../scripts/wp-update.sh
|
|
dest: /usr/local/bin/wp-update.sh
|
|
mode: '0755'
|
|
tags: update
|
|
|
|
- name: Configure WordPress auto-update settings
|
|
command: >
|
|
wp option update auto_update_core_minor enabled
|
|
--path="{{ wordpress_path }}"
|
|
--allow-root
|
|
tags: update
|
|
|
|
- name: Set up cron job for WordPress updates
|
|
cron:
|
|
name: wordpress-weekly-update
|
|
job: "/usr/local/bin/wp-update.sh --minor --no-backup >> /var/log/wp-update.log 2>&1"
|
|
minute: "0"
|
|
hour: "4"
|
|
weekday: "0"
|
|
user: "root"
|
|
when: update_cron_enabled | default(true) | bool
|
|
tags: update
|
|
|
|
# Fail2Ban Security
|
|
- name: Deploy Fail2Ban configuration
|
|
template:
|
|
src: ../templates/fail2ban.j2
|
|
dest: /etc/fail2ban/jail.local
|
|
mode: '0644'
|
|
notify: restart fail2ban
|
|
tags: fail2ban
|
|
|
|
- name: Deploy WordPress Fail2Ban filter
|
|
copy:
|
|
src: ../templates/fail2ban-wordpress-filter.conf
|
|
dest: /etc/fail2ban/filter.d/wordpress-login.conf
|
|
mode: '0644'
|
|
notify: restart fail2ban
|
|
tags: fail2ban
|
|
|
|
- name: Ensure Fail2Ban service is running
|
|
service:
|
|
name: fail2ban
|
|
state: started
|
|
enabled: yes
|
|
tags: fail2ban
|
|
|
|
- name: Display Fail2Ban status info
|
|
debug:
|
|
msg: |
|
|
Fail2Ban security enabled!
|
|
Jails: sshd, nginx-http-auth, nginx-botsearch, wordpress-login, recidive
|
|
Use: fail2ban-client status to see banned IPs
|
|
tags: fail2ban
|
|
|
|
handlers:
|
|
- name: restart nginx
|
|
service:
|
|
name: "{{ nginx_service }}"
|
|
state: restarted
|
|
|
|
- name: restart php-fpm
|
|
service:
|
|
name: "{{ php_fpm_service }}"
|
|
state: restarted
|
|
|
|
- name: restart fail2ban
|
|
service:
|
|
name: fail2ban
|
|
state: restarted
|
|
|
|
- name: restart mysql
|
|
service:
|
|
name: "{{ mysql_service }}"
|
|
state: restarted
|