WordPress configuration
Below is our standard approach to configuring WordPress and key plugins.
See also details about WordPress including standard plugins.
WordPress core
Localisation:
- Install English UK language
- Set timezone to 'London'
Wordfence
Documentation: Wordfence Help
Installation
Perform the following steps in the dev environment:
- Download the Wordfence plugin code (but don't activate the plugin yet)
- Commit the plugin files to version control
- Create a folder for log files
mkdir src/wordpress/wp-content/wflogs - Add line to
.gitignoreto ignore this folder/src/wordpress/wp-content/wflogs - Add volume for log files to all three
docker-compose.*.ymlservices: app: ... volumes: ... - wflogs:/var/www/html/wp-content/wflogs ... volumes: ... wflogs: ... - Restart the docker container with
docker compose up -d - Set permissions for volume
docker compose exec app chown civicrm:civicrm wp-content/wflogs - Activate the plugin
- Get a license (use system@thirdsectordesign.org email)
- Configure the firewall (Wordfence > Firewall > Manage WAF)
- click Optimize Firewall
- this enables extended protection
- this will alter
.htaccessand createwordfence-waf.php
- Commit the changed files to version control - this should include
src/wordpress/.htaccess src/wordpress/wordfence-waf.php .gitignore docker-compose.dev.yml docker-compose.prod.yml docker-compose.test.yml
Deployment
To deploy to test or prod follow the steps below - these can be copied and pasted into an issue.
- [ ] Merge and pull MR
- [ ] Run the following commands
```sh
# Create log folder (if required)
ls -al src/wordpress/wp-content
mkdir src/wordpress/wp-content/wflogs
# Restart container
docker compose up -d
# Set folder ownership
docker compose exec app ls -al wp-content
docker compose exec app chown civicrm:civicrm wp-content/wflogs
# Activate plugin
docker compose exec -u civicrm app wp plugin activate wordfence
```
- [ ] Add license
- [ ] Configure plugin
- [ ] Put firewall into learning mode
- [ ] Run a scan
- [ ] Ask 3SD team to configure 2FA
- [ ] Suggest client users configure 2FA
See below for details of how to configure this plugin
Configuration
Alter the setting below in Wordfence > All Options.
Wordfence Global Options
- Wordfence license
- copy license key from dev site (or create a new license key)
- General Wordfence Options
- Where to email alerts: system@thirdsectordesign.org
- How does Wordfence get IPs - check the detected IP is correct (may not be on dev site)
- Email Alert Preferences - select the following
- Email me if Wordfence is deactivated
- Email me if the Wordfence Web Application Firewall is turned off
- Alert me with scan results of this severity level or greater: High
- Alert when an IP address is blocked
- Alert me when there's a large increase in attacks detected on my site
- Maximum email alerts to send per hour = 10
Firewall
- Basic Firewall Options
- Put firewall into learning mode
- Automatically enable in one week - choose other date if this isn't convenient (i.e. if you are going on holiday)
- Brute Force Protection
- Prevent the use of passwords leaked in data breaches = For all users with 'publish posts' capability (ensure that staff that can access CiviCRM have 'publish posts' capability)
- Enforce strong passwords = Force all members to use strong passwords
- Participate in the Real-Time Wordfence Security Network - disable by default
We should discuss with the client if they want to enable the last option. This has data protection implications as it sends IP addresses to Wordfence.
Login security
Change the following settings under Wordfence > Login Security > Settings
- 2FA Roles
- enable for each role that uses CiviCRM - set as 'optional' or 'required' as appropriate
- Allow remembering device for 30 days = true
Configure 2FA for yourself and ask other 3SD staff to configure 2FA.
Scan
Run a scan on the site to check for any vulnerabilities.
WP Super Cache
Documentation: Initial WP Super Cache Setup and Configuration
Wiki: WP Super Cache
Preparation
Before configuring this plugin you should create a list of all pages that shouldn't be cached. This includes any pages that have CiviCRM content:
- the CiviCRM base page
- event pages
- contribution pages
- public CiviCRM forms - profiles or FormBuilder
We should add these pages to the list of 'Rejected URL Stings' in the advanced settings (see below). A simple way to do this is to ignore any URLs that contain the string 'civi'.
Installation and configuration
Perform the following steps in the dev environment:
Download the WP Super Cache plugin code (but don't activate the plugin yet)
Commit the plugin files to version control
Edit all three
docker-compose.*.ymlfiles to add the environment variablesservices: app: ... environment: ... - WP_CACHE=TRUE - WP_CACHE_SECRET - WP_CACHE_DEBUG_USERNAME - WP_CACHE_DEBUG_LOGFILEEdit
docker-compose.prod.ymlanddocker-compose.test.ymlto add a cache volumeservices: app: ... volumes: ... - cache:/var/www/html/wp-content/cache ... volumes: ... cache: ...Restart the docker container with
docker compose up -dAdd a line to
.gitignoreto ignore cache files/src/wordpress/wp-content/cacheEnsure the
wp-config.phpfile is writable (this is needed to activate the plugin but any changes made by the plugin should be reverted)docker compose exec -u civicrm app chmod +w wp-config.phpCreate a
wp-config-extra.phpfile with the following lines (or add to the existing file):<?php /** * Additional site specific WordPress config */ /** * WP Super Cache settings */ if ( getenv( 'WP_CACHE' ) === 'TRUE' ) { define( 'WP_CACHE', true ); define( 'WPCACHEHOME', '/var/www/html/wp-content/plugins/wp-super-cache/' ); }Activate the plugin
Configure the advanced settings
- Enable caching
- Cache delivery method = Expert
- Disable caching for logged in visitors = Yes
- Compress pages so they’re served more quickly to visitors = Yes
- Cache rebuild = Yes
- Extra homepage checks = Yes
Rejected URL Strings - don't cache any forms - see above
wp-.*\.php index\.php civiVisit the debug settings page - this generates the debug log filename and username
The configuration settings are saved to
wp-content/wp-cache-config.phpCopy secrets from
wp-cache-config.phpto.envWP_CACHE_SECRET= WP_CACHE_DEBUG_LOGFILE= WP_CACHE_DEBUG_USERNAME=Edit the
wp-cache-config.phpfile to use environment variables by replacing the secrets with the following lines - make sure you delete the existing variable definition so that these aren't overwritten$cache_page_secret = getenv( 'WP_CACHE_SECRET' ); $wp_cache_debug_log = getenv( 'WP_CACHE_DEBUG_LOGFILE' ); $wp_cache_debug_username = getenv( 'WP_CACHE_DEBUG_USERNAME' );Restart the docker container with
docker compose up -dCommit the changed files to version control - this should include
src/wordpress/wp-content/advanced-cache.php src/wordpress/wp-content/wp-cache-config.php src/wordpress/.htaccess src/wordpress/wp-config-extra.php .gitignore docker-compose.dev.yml docker-compose.prod.yml docker-compose.test.ymlDon't commit any changes to
src/wordpress/wp-config.php. Any changes made to this file by activating the plugin should be reverted.
Testing
To check that caching is working visit the site in an incognito window (caching is disabled for logged in users). Check the bottom of the HTML for a comment like this:
<!-- Dynamic page generated in 0.112 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2024-12-04 09:32:40 -->
<!-- Compression = gzip -->
The time shouldn't change when you reload the page.
Pages that have been excluded from caching shouldn't have this comment at the bottom.
Check that public forms are working correctly (caching can break CSRF tokens). To test this fully, you need to test the page twice with a break of at least five minutes - the first time you submit the form it may work as it has been freshly created, the second time might not work as it is using an old cached token.
Deployment
To deploy to test or prod follow the steps below - these can be copied and pasted into an issue.
- [ ] Add secrets to `.env` - copy from dev
```env
WP_CACHE_SECRET=
WP_CACHE_DEBUG_USERNAME=
WP_CACHE_DEBUG_LOGFILE=
```
- [ ] Merge and pull MR
- [ ] Run the following commands
```sh
# Create cache folder (if required)
ls -al src/wordpress/wp-content
mkdir src/wordpress/wp-content/cache
# Restart container
docker compose up -d
# Set folder ownership
docker compose exec app ls -al wp-content
docker compose exec app chown civicrm:civicrm wp-content/cache
# Activate plugin
docker compose exec -u civicrm app wp plugin activate wp-super-cache
```
Note: the configuration is committed to version control and will be read only on test and production. This means that it isn't possible to alter the settings via the UI.