├── .gitignore ├── README.md ├── ansible.cfg ├── hosts ├── provision.yml └── roles ├── common └── tasks │ └── main.yml ├── mysql ├── handlers │ └── main.yml └── tasks │ └── main.yml ├── nginx ├── handlers │ └── main.yml └── tasks │ └── main.yml ├── php ├── handlers │ └── main.yml └── tasks │ └── main.yml ├── ssh ├── handlers │ └── main.yml └── tasks │ └── main.yml ├── ufw ├── handlers │ └── main.yml └── tasks │ └── main.yml ├── user └── tasks │ └── main.yml └── wp-cli └── tasks └── main.yml /.gitignore: -------------------------------------------------------------------------------- 1 | provision.retry 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WordPress Ansible 2 | 3 | This repository contains a playbook for provisioning modern hosting environments geared towards WordPress. It's based on [How to Install WordPress on Ubuntu 20.04](https://deliciousbrains.com/hosting-wordpress-setup-secure-virtual-server/). The following is handled out of the box: 4 | 5 | * User setup 6 | * SSH hardening 7 | * Firewall setup 8 | 9 | It will also install the following software: 10 | 11 | * Nginx with HTTP/2 12 | * PHP 8.1 13 | * MySQL 14 | * Redis 15 | * WP-CLI 16 | * Fail2Ban 17 | * Git 18 | 19 | ## Usage 20 | 21 | Configure your [hosts file](https://github.com/deliciousbrains/wordpress-ansible/blob/master/hosts). 22 | 23 | ``` 24 | [production] 25 | 192.168.1.1 #sampledomain.com 26 | ``` 27 | 28 | Edit [provision.yml](https://github.com/deliciousbrains/wordpress-ansible/blob/master/provision.yml) to configure your default user, [hashed](https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#how-do-i-generate-encrypted-passwords-for-the-user-module) sudo password and local public key path. This will create a new user on the provisioned servers that you can use to gain SSH access. 29 | 30 | Run: 31 | 32 | `ansible-playbook provision.yml` 33 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory = hosts -------------------------------------------------------------------------------- /hosts: -------------------------------------------------------------------------------- 1 | # Add hosts here, one per line. Additional groups can be created using 2 | # [group] syntax. Hosts can join multiple groups. 3 | 4 | [production] 5 | server_hostname1 6 | 7 | [staging] 8 | server_hostname2 -------------------------------------------------------------------------------- /provision.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: production 3 | user: root 4 | vars: 5 | username: ansible 6 | password: $6$rlLdG6wd1CT8v7i$7psP8l26lmaPhT3cigoYYXhjG28CtD1ifILq9KzvA0W0TH2Hj4.iO43RkPWgJGIi60Mz0CsxWbRVBSQkAY95W0 7 | public_key: ~/.ssh/id_rsa.pub 8 | roles: 9 | - common 10 | - ufw 11 | - user 12 | - nginx 13 | - php 14 | - mysql 15 | - wp-cli 16 | - ssh -------------------------------------------------------------------------------- /roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Upgrade packages 3 | apt: 4 | upgrade: safe 5 | update_cache: yes 6 | cache_valid_time: 300 7 | become: yes 8 | 9 | - name: Install packages 10 | apt: 11 | name: 12 | - aptitude 13 | - jq 14 | - curl 15 | - git-core 16 | - at 17 | state: present 18 | update_cache: yes 19 | -------------------------------------------------------------------------------- /roles/mysql/handlers/main.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spinupwp/wordpress-ansible/f69ea0a6da5b0b4fef03a912398b57989bf4d860/roles/mysql/handlers/main.yml -------------------------------------------------------------------------------- /roles/mysql/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install MySQL 3 | apt: 4 | name: mysql-server 5 | state: present 6 | force: yes -------------------------------------------------------------------------------- /roles/nginx/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart nginx 3 | service: 4 | name: nginx 5 | state: restarted 6 | 7 | - name: reload nginx 8 | service: 9 | name: nginx 10 | state: reloaded -------------------------------------------------------------------------------- /roles/nginx/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Add Nginx repo 3 | apt_repository: 4 | repo: ppa:ondrej/nginx 5 | 6 | - name: Install Nginx 7 | apt: 8 | name: nginx 9 | state: present 10 | force: yes 11 | update_cache: yes 12 | 13 | - name: Symlink default site 14 | file: 15 | src: /etc/nginx/sites-available/default 16 | dest: /etc/nginx/sites-enabled/default 17 | state: link 18 | notify: reload nginx 19 | 20 | - name: Set Nginx user 21 | lineinfile: 22 | dest: /etc/nginx/nginx.conf 23 | regexp: "^user" 24 | line: "user {{ username }};" 25 | state: present 26 | notify: restart nginx -------------------------------------------------------------------------------- /roles/php/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: start php 3 | service: 4 | name: php8.1-fpm 5 | state: started 6 | 7 | - name: reload php 8 | service: 9 | name: php8.1-fpm 10 | state: reloaded 11 | 12 | - name: restart php 13 | service: 14 | name: php8.1-fpm 15 | state: restarted -------------------------------------------------------------------------------- /roles/php/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Add PHP repo 3 | apt_repository: 4 | repo: ppa:ondrej/php 5 | 6 | - name: Install PHP 7 | apt: 8 | name: 9 | - "php8.1-bcmath" 10 | - "php8.1-cli" 11 | - "php8.1-common" 12 | - "php8.1-curl" 13 | - "php8.1-fpm" 14 | - "php8.1-gd" 15 | - "php8.1-igbinary" 16 | - "php8.1-imagick" 17 | - "php8.1-mbstring" 18 | - "php8.1-mysql" 19 | - "php8.1-opcache" 20 | - "php8.1-redis" 21 | - "php8.1-soap" 22 | - "php8.1-xml" 23 | - "php8.1-xmlrpc" 24 | - "php8.1-zip" 25 | state: present 26 | force: yes 27 | update_cache: yes 28 | 29 | - name: Set PHP user 30 | lineinfile: 31 | dest: /etc/php/8.1/fpm/pool.d/www.conf 32 | regexp: "^user" 33 | line: "user = {{ username }}" 34 | state: present 35 | notify: restart php 36 | 37 | - name: Set PHP group 38 | lineinfile: 39 | dest: /etc/php/8.1/fpm/pool.d/www.conf 40 | regexp: "^group" 41 | line: "group = {{ username }}" 42 | state: present 43 | notify: restart php 44 | 45 | - name: Set PHP listen owner 46 | lineinfile: 47 | dest: /etc/php/8.1/fpm/pool.d/www.conf 48 | regexp: "^listen\\.owner" 49 | line: "listen.owner = {{ username }}" 50 | state: present 51 | notify: restart php 52 | 53 | - name: Set PHP listen group 54 | lineinfile: 55 | dest: /etc/php/8.1/fpm/pool.d/www.conf 56 | regexp: "^listen\\.group" 57 | line: "listen.group = {{ username }}" 58 | state: present 59 | notify: restart php 60 | 61 | - name: Set PHP upload max filesize 62 | lineinfile: 63 | dest: /etc/php/8.1/fpm/php.ini 64 | regexp: "^upload_max_filesize" 65 | line: "upload_max_filesize = 128M" 66 | state: present 67 | notify: reload php 68 | 69 | - name: Set PHP post max filesize 70 | lineinfile: 71 | dest: /etc/php/8.1/fpm/php.ini 72 | regexp: "^post_max_size" 73 | line: "post_max_size = 128M" 74 | state: present 75 | notify: reload php -------------------------------------------------------------------------------- /roles/ssh/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart ssh 3 | service: 4 | name: ssh 5 | state: restarted -------------------------------------------------------------------------------- /roles/ssh/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Disable root login 3 | lineinfile: 4 | dest: /etc/ssh/sshd_config 5 | regexp: "^PermitRootLogin" 6 | line: "PermitRootLogin no" 7 | state: present 8 | notify: restart ssh 9 | 10 | - name: Disable password authentication 11 | lineinfile: 12 | dest: /etc/ssh/sshd_config 13 | regexp: "^#?PasswordAuthentication" 14 | line: "PasswordAuthentication no" 15 | state: present 16 | notify: restart ssh -------------------------------------------------------------------------------- /roles/ufw/handlers/main.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spinupwp/wordpress-ansible/f69ea0a6da5b0b4fef03a912398b57989bf4d860/roles/ufw/handlers/main.yml -------------------------------------------------------------------------------- /roles/ufw/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Enable firewall 3 | ufw: state=enabled policy=deny 4 | 5 | - name: Allow HTTP 6 | ufw: rule=allow port=80 proto=tcp 7 | 8 | - name: Allow HTTPS 9 | ufw: rule=allow port=443 proto=tcp 10 | 11 | - name: Allow SSH 12 | ufw: rule=allow port=22 proto=tcp 13 | -------------------------------------------------------------------------------- /roles/user/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure sudo group is present 3 | group: 4 | name: sudo 5 | state: present 6 | 7 | - name: Ensure sudo group has sudo privileges 8 | lineinfile: 9 | dest: /etc/sudoers 10 | state: present 11 | regexp: "^%sudo" 12 | line: "%sudo ALL=(ALL:ALL) ALL" 13 | validate: "/usr/sbin/visudo -cf %s" 14 | 15 | - name: Create default user 16 | user: 17 | name: "{{ username }}" 18 | groups: sudo 19 | password: "{{ password }}" 20 | shell: /bin/bash 21 | update_password: always 22 | state: present 23 | 24 | - name: Add authorized key 25 | authorized_key: 26 | user: "{{ username }}" 27 | key: "{{ lookup('file', public_key) }}" -------------------------------------------------------------------------------- /roles/wp-cli/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install WP-CLI 3 | get_url: 4 | url: https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar 5 | dest: /usr/bin/wp 6 | mode: 0755 7 | 8 | - name: Install WP-CLI tab completions 9 | get_url: 10 | url: https://raw.githubusercontent.com/wp-cli/wp-cli/master/utils/wp-completion.bash 11 | dest: /etc/bash_completion.d 12 | mode: 0644 --------------------------------------------------------------------------------