generated from bisco/codex-bootstrap
feat: add internal WordPress cron runner
This commit is contained in:
@@ -17,10 +17,12 @@ classic theme for exact semantic markup and responsive design. Store homepage fi
|
||||
sanitized theme modifications, while a must-use plugin owns Shows and Gallery custom
|
||||
post types so structured content is not lost when changing themes.
|
||||
|
||||
NGINX is the only public entry point. WP-CLI provides an idempotent opt-in bootstrap;
|
||||
Certbot provides opt-in direct TLS. Docker networks isolate the database. Runtime state
|
||||
uses host-based bind mounts with a preparation script for ownership/mode, while
|
||||
functional tests use separate Docker volumes.
|
||||
NGINX is the only public entry point. Public `wp-cron.php` requests stay blocked, while
|
||||
an internal WP-CLI based `wp-cron` service runs due scheduled events over the private
|
||||
data network. WP-CLI provides an idempotent opt-in bootstrap; Certbot provides opt-in
|
||||
direct TLS. Docker networks isolate the database. Runtime state uses host-based bind
|
||||
mounts with a preparation script for ownership/mode, while functional tests use
|
||||
separate Docker volumes.
|
||||
|
||||
## Consequences
|
||||
|
||||
@@ -30,6 +32,8 @@ functional tests use separate Docker volumes.
|
||||
- Core/theme/plugin patches require an image rebuild in production.
|
||||
- Fixed participation cards remain code until editorial requirements justify another
|
||||
structured content type.
|
||||
- Scheduled WordPress jobs depend on the internal `wp-cron` service instead of visitor
|
||||
traffic.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
@@ -43,8 +47,9 @@ functional tests use separate Docker volumes.
|
||||
|
||||
The architecture inherits WordPress's public CMS attack surface. The implementation
|
||||
reduces it with network isolation, no direct application port, disabled file editing
|
||||
and XML-RPC, production immutability, sanitization/escaping, rate limiting, security
|
||||
headers, and fail-closed TLS. Admin MFA and allowlisting remain external controls.
|
||||
and XML-RPC, production immutability, sanitized/escaped rendering, no bundled demo
|
||||
plugins, internal-only scheduled jobs, rate limiting, security headers, and fail-closed
|
||||
TLS. Admin MFA and allowlisting remain external controls.
|
||||
|
||||
## Operational impact
|
||||
|
||||
|
||||
@@ -12,10 +12,13 @@ structured editorial content survives a theme change. These custom post types ar
|
||||
editorial data sources for the homepage, not standalone public routes or REST
|
||||
collections. Images use WordPress featured images with local SVG fallbacks.
|
||||
|
||||
WP-CLI is an opt-in tools-profile service. Its idempotent bootstrap installs WordPress,
|
||||
activates the theme, configures the site, and creates realistic demo content. Certbot is
|
||||
another optional service, enabled only for direct deployments. It shares challenge and
|
||||
certificate volumes with NGINX but has no container-control access.
|
||||
`wp-cron` is an internal WP-CLI runner on the `data` network. It executes due scheduled
|
||||
events with `wp cron event run --due-now` and keeps public `wp-cron.php` requests
|
||||
blocked. WP-CLI is also available as an opt-in tools-profile service. Its idempotent
|
||||
bootstrap installs WordPress, activates the theme, configures the site, and creates
|
||||
realistic demo content. Certbot is another optional service, enabled only for direct
|
||||
deployments. It shares challenge and certificate volumes with NGINX but has no
|
||||
container-control access.
|
||||
|
||||
Apache includes a small defense-in-depth hardening file that denies uploaded PHP files,
|
||||
direct `wp-config.php` requests, and direct access to selected internal WordPress PHP
|
||||
|
||||
@@ -11,6 +11,8 @@ docker compose --profile tools run --rm wp-cli /scripts/bootstrap.sh
|
||||
|
||||
NGINX binds to loopback ports 8080/8443. WordPress and MariaDB remain private. The
|
||||
bootstrap is safe to rerun and does not duplicate demo records.
|
||||
The internal `wp-cron` service runs scheduled WordPress events after the bootstrap
|
||||
completes.
|
||||
|
||||
The default persistent paths are host-based bind mounts under `./runtime`. Before the
|
||||
first start, run:
|
||||
@@ -37,6 +39,9 @@ Required controls:
|
||||
- either direct Let's Encrypt termination or a trusted external load balancer;
|
||||
- off-host database/file backups and monitoring.
|
||||
|
||||
The default `wp-cron` service handles scheduled WordPress events internally and should
|
||||
remain enabled unless another controlled cron runner replaces it.
|
||||
|
||||
When a load balancer terminates TLS, Certbot stays disabled. `TRUST_PROXY_HEADERS=1`
|
||||
is safe only when firewall/network policy makes the load balancer the sole NGINX
|
||||
caller and it overwrites `X-Forwarded-*` headers.
|
||||
|
||||
+9
-7
@@ -5,9 +5,10 @@
|
||||
```bash
|
||||
docker compose up --build -d
|
||||
docker compose ps
|
||||
docker compose logs -f proxy wordpress db certbot
|
||||
docker compose logs -f proxy wordpress wp-cron db certbot
|
||||
./scripts/prepare-host-volumes.sh
|
||||
docker compose --profile tools run --rm wp-cli -c 'wp core version'
|
||||
docker compose --profile tools run --rm wp-cli -c 'wp cron event list'
|
||||
docker compose down
|
||||
```
|
||||
|
||||
@@ -37,10 +38,11 @@ docker compose restart wordpress proxy
|
||||
Do not use the maintenance override for routine bootstrap or inspection commands that
|
||||
do not need outbound network access.
|
||||
|
||||
External `wp-cron.php` requests are blocked to reduce public attack surface. If future
|
||||
content scheduling, maintenance jobs, or plugin features require WordPress cron, run it
|
||||
from a controlled host/container cron against the private WordPress service instead of
|
||||
leaving the public trigger enabled.
|
||||
External `wp-cron.php` requests are blocked to reduce public attack surface. The
|
||||
default `wp-cron` service runs due scheduled events internally through WP-CLI every
|
||||
`WP_CRON_INTERVAL_SECONDS` seconds, defaults to 300, and joins only the internal `data`
|
||||
network. If a scheduled job is late, inspect `docker compose logs wp-cron wordpress db`
|
||||
and run `docker compose --profile tools run --rm wp-cli -c 'wp cron event list'`.
|
||||
|
||||
## Backup and restore
|
||||
|
||||
@@ -61,8 +63,8 @@ the database and file volume together, restart, and verify the homepage, media,
|
||||
owner or mode; run `./scripts/prepare-host-volumes.sh` after changing paths or image
|
||||
user IDs.
|
||||
- SMTP is not configured; WordPress password-reset email needs an external mail service.
|
||||
- WordPress cron is not publicly triggerable; scheduled jobs need an operator-managed
|
||||
cron runner if that feature becomes necessary.
|
||||
- WordPress cron is not publicly triggerable; scheduled jobs depend on the internal
|
||||
`wp-cron` runner being healthy.
|
||||
- Admin MFA and network allowlisting are deployment concerns and are not bundled.
|
||||
- WordPress plugins expand the attack surface; install only reviewed, maintained,
|
||||
necessary plugins.
|
||||
|
||||
@@ -50,6 +50,39 @@ docker compose restart wordpress proxy
|
||||
If DNS still fails with the maintenance override, inspect the host/container DNS
|
||||
configuration and firewall rules before retrying the update.
|
||||
|
||||
## Scheduled WordPress events are late
|
||||
|
||||
The public `/wp-cron.php` trigger is intentionally blocked. Scheduled jobs are executed
|
||||
by the internal `wp-cron` service.
|
||||
|
||||
1. Confirm the runner is present:
|
||||
|
||||
```bash
|
||||
docker compose ps wp-cron
|
||||
```
|
||||
|
||||
2. Inspect due events:
|
||||
|
||||
```bash
|
||||
docker compose --profile tools run --rm wp-cli -c 'wp cron event list'
|
||||
```
|
||||
|
||||
3. Inspect runner logs without printing `.env` values:
|
||||
|
||||
```bash
|
||||
docker compose logs --tail=100 wp-cron wordpress db
|
||||
```
|
||||
|
||||
4. If needed, run due events manually:
|
||||
|
||||
```bash
|
||||
docker compose --profile tools run --rm wp-cli -c 'wp cron event run --due-now'
|
||||
```
|
||||
|
||||
The Site Health loopback test may still report a blocked public loopback while the edge
|
||||
continues to deny `/wp-cron.php`; that is an expected trade-off of the hardened public
|
||||
configuration.
|
||||
|
||||
## Uploaded image does not appear on the public page
|
||||
|
||||
1. Confirm the image was selected in **Appearance > Customize**, not only uploaded in
|
||||
|
||||
+5
-1
@@ -11,6 +11,8 @@
|
||||
collections.
|
||||
- File editing is always disabled. Production also disables web-based core, theme, and
|
||||
plugin changes; patched images are rebuilt and redeployed instead.
|
||||
- The WordPress image removes the bundled Akismet and Hello Dolly plugins, and the
|
||||
entrypoint also removes them from existing persistent volumes on startup.
|
||||
- XML-RPC and comments are disabled. NGINX blocks PHP execution below uploads, dotfiles,
|
||||
direct `wp-config.php` requests, the WordPress readme/license files, direct
|
||||
installation entry points, public mu-plugin directory probing, and external
|
||||
@@ -28,7 +30,9 @@
|
||||
WordPress/Apache retains the capabilities needed by the official image internally,
|
||||
but no WordPress port is published. A containerized security test fails if the
|
||||
WordPress service is configured with host-published ports.
|
||||
- WP-CLI normally joins only the internal data network. The maintenance override
|
||||
- `wp-cron` runs WordPress scheduled events through WP-CLI on the internal data network
|
||||
only; public `wp-cron.php` remains blocked. WP-CLI normally joins only the internal
|
||||
data network. The maintenance override
|
||||
attaches WP-CLI to the web network for operator-triggered commands that require
|
||||
outbound internet access, such as WordPress core downloads; do not use it for routine
|
||||
bootstrap or inspection commands.
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@ cover content and section order, contact actions, mobile overflow/navigation, se
|
||||
landmarks, image alternatives, admin routing, security headers, blocked sensitive
|
||||
routes, blocked uploaded PHP requests, and unknown virtual hosts. Security checks also
|
||||
assert that WordPress does not publish host ports and that Apache hardening remains
|
||||
installed in the WordPress image.
|
||||
installed in the WordPress image. They also assert that the default demo plugins are
|
||||
removed and that the internal `wp-cron` service has no public network exposure.
|
||||
|
||||
Subjective visual review and a real-device accessibility audit remain manual release
|
||||
checks.
|
||||
|
||||
Reference in New Issue
Block a user