You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add documentation for the opt-in runtime hardening feature from
roots/trellis#1649, covering PHP-FPM identity separation, writable
path allowlisting, and per-site configuration.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: trellis/security.md
+70-2Lines changed: 70 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
---
2
-
date_modified: 2023-01-27 13:17
2
+
date_modified: 2026-03-05 00:00
3
3
date_published: 2015-09-06 07:42
4
-
description: Secure Trellis WordPress servers by disabling root SSH login, creating admin users with sudo access, and configuring secure password authentication.
4
+
description: Secure Trellis WordPress servers by disabling root SSH login, creating admin users with sudo access, configuring secure password authentication, and hardening WordPress runtime file permissions.
5
5
title: WordPress Security Features in Trellis
6
6
authors:
7
7
- ben
@@ -24,3 +24,71 @@ The first provision via the `server.yml` playbook will create the `admin_user` a
24
24
## Admin user sudoer password
25
25
26
26
If `root` login is disabled and the `server.yml` playbook connects as the `admin_user`, it will invoke `sudo` using the password in `vault_users` (`group_vars/<environment>/vault.yml`). If you run the playbook with `--ask-become-pass`, Trellis will use the password you enter via the CLI. You are strongly encouraged to protect the sensitive `vault_users` information by enabling Ansible [Vault](vault.md).
27
+
28
+
## WordPress runtime hardening
29
+
30
+
Trellis supports an opt-in hardening mode that separates the PHP-FPM runtime identity from the deploy user. When enabled, PHP runs as a dedicated user with write access limited to explicitly allowlisted paths. This reduces the impact of a compromised WordPress site by preventing PHP from modifying application code.
31
+
32
+
By default, hardening is disabled and Trellis behaves as it always has — PHP-FPM runs as the `web_user`.
33
+
34
+
### Enabling hardening
35
+
36
+
Add the following to `group_vars/all/main.yml` (or an environment-specific file like `group_vars/production/main.yml`):
| `wordpress_runtime_user` | `www-data` | OS user that PHP-FPM runs as when hardened |
48
+
| `wordpress_runtime_group` | `www-data` | OS group that PHP-FPM runs as when hardened |
49
+
| `wordpress_runtime_writable_paths` | `["shared/uploads"]` | Paths the runtime user can write to (relative to the site root) |
50
+
| `wordpress_runtime_cron_as_runtime_user` | `false` | Run WP-CLI cron as the runtime user instead of `web_user` |
51
+
52
+
### Using a custom runtime user
53
+
54
+
For stronger isolation, use a dedicated user instead of `www-data`. The user and group must exist on the server before hardening is enabled — the playbook will fail fast if they don't.
55
+
56
+
Define the user in `group_vars/all/users.yml`:
57
+
58
+
```yaml
59
+
users:
60
+
- name: php-app
61
+
groups:
62
+
- php-app
63
+
keys: []
64
+
```
65
+
66
+
Then configure the runtime variables:
67
+
68
+
```yaml
69
+
wordpress_runtime_hardened: true
70
+
wordpress_runtime_user: php-app
71
+
wordpress_runtime_group: php-app
72
+
```
73
+
74
+
### Per-site writable paths
75
+
76
+
The global `wordpress_runtime_writable_paths` applies to all sites by default. You can override it for individual sites in your [WordPress Sites](/trellis/docs/wordpress-sites/) configuration:
77
+
78
+
```yaml
79
+
wordpress_sites:
80
+
example.com:
81
+
runtime_writable_paths:
82
+
- shared/uploads
83
+
- current/web/app/cache
84
+
```
85
+
86
+
### Cron user
87
+
88
+
By default, WP-CLI cron jobs continue to run as the `web_user` even when hardening is enabled. To run cron as the runtime user instead:
89
+
90
+
```yaml
91
+
wordpress_runtime_cron_as_runtime_user: true
92
+
```
93
+
94
+
This only takes effect when `wordpress_runtime_hardened` is also `true`.
Copy file name to clipboardExpand all lines: trellis/wordpress-sites.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -145,4 +145,5 @@ example.com:
145
145
- `secure_auth_salt`- Generate (*required* in `vault.yml`)
146
146
- `logged_in_salt`- Generate (*required* in `vault.yml`)
147
147
- `nonce_salt`- Generate (*required* in `vault.yml`)
148
+
- `runtime_writable_paths`- list of paths (relative to the site root) the PHP-FPM runtime user can write to when [runtime hardening](/trellis/docs/security/#wordpress-runtime-hardening) is enabled (default: global `wordpress_runtime_writable_paths`)
148
149
- `deploy_keep_releases` - number of releases to keep for rollbacks (default: 5)
0 commit comments