Create wp-cron-supercronic-deploy.md via n8n

This commit is contained in:
herbygitea 2026-04-15 11:00:32 +00:00
parent c1179fdf3e
commit 94c08c20a5

View File

@ -0,0 +1,142 @@
---
project: wp-cron-supercronic-deploy
type: session-notes
status: completed
path: Tech/Sessions
tags:
- pbs
- wordpress
- traefik
- docker
- cron
created: 2026-04-15
updated: 2026-04-15
---
# WP-Cron → Supercronic Sidecar Deployment
Session notes captured retroactively from March 7 work, before the n8n
email pipeline was in place.
## Problem
Uptime Kuma status checks were triggering WordPress's built-in WP-Cron on
every HTTP request, causing cron jobs to fire unpredictably on page load
instead of on a proper schedule. Added unnecessary load and made cron
behavior non-deterministic.
## Solution
Three-part fix:
1. **Disable WP-Cron on page load** via `wp-config.php`
2. **Block external access to `wp-cron.php`** at the Traefik middleware
layer
3. **Deploy a Supercronic sidecar container** that calls wp-cron on a real
schedule via the internal Docker network
## Implementation
### 1. wp-config.php
```php
define('ALTERNATE_WP_CRON', false);
define('DISABLE_WP_CRON', true);
```
`wp-config.php` is bind-mounted from the host so Ansible can manage it:
```yaml
volumes:
- wordpress_data:/var/www/html
- ./wp-config.php:/var/www/html/wp-config.php
```
To pull a fresh copy out of a running container:
```bash
docker cp wordpress:/var/www/html/wp-config.php
/opt/docker/wordpress/wp-config.php
```
### 2. Traefik middleware — block external `wp-cron.php`
```jinja
- traefik.http.routers.wordpress.middlewares=www-redirect,block-wpcron
- traefik.http.middlewares.block-wpcron.redirectregex.regex=^/wp-cron\.php.*
- traefik.http.middlewares.block-wpcron.redirectregex.replacement=/
```
The router definition must include `block-wpcron` in the middlewares chain
or Traefik silently does not apply it.
Verify:
```bash
curl -Lv https://plantbasedsoutherner.com/wp-cron.php 2>&1 | grep -E
"HTTP|Location"
# Expected: HTTP/2 302 + Location: https://plantbasedsoutherner.com
```
### 3. Supercronic sidecar
Project structure:
```
/opt/docker/wpcron/
Dockerfile
crontab
docker-compose.yml
```
`crontab` (set to every minute — Wordfence and Jetpack schedule events at
this frequency):
```
* * * * * curl -s http://wordpress/wp-cron.php?doing_wp_cron
```
`Dockerfile`:
```dockerfile
FROM alpine:latest
ARG SUPERCRONIC_VERSION=v0.2.29
ARG SUPERCRONIC_ARCH=amd64
RUN wget -q
https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-${SUPERCRONIC_ARCH}
\
-O /usr/local/bin/supercronic && \
chmod +x /usr/local/bin/supercronic && \
apk add --no-cache curl
COPY crontab /etc/crontab
CMD ["/usr/local/bin/supercronic", "/etc/crontab"]
```
The sidecar lives in its own compose project. To reach the WordPress
container, the wpcron compose file declares the WordPress network as
`external: true`.
## Bonus Fix — Redis Auth on Production
Discovered during the deploy that the production WordPress container was
missing the Redis password env var. Env vars had been moved to an `.env`
file on staging but the change never made it back to production. Fixed and
now part of the standard env handoff between environments.
## Key Learnings
- **Traefik `redirectregex` matches path only**, not the full URL — design
regex accordingly
- **`depends_on` only works within the same Docker Compose project** — for
cross-project dependencies, declare the network as `external: true`
- **`docker compose up -d --force-recreate `** is the right
command to pick up compose file changes (not `restart`, which reuses the
old config)
- **Cron interval matters:** Plugins like Wordfence and Jetpack schedule
per-minute events, so a 5-minute cron will leave them perpetually behind.
Every minute is the right default for this stack.
## Status
Deployed to staging then promoted to production. Running cleanly since.
...sent from Jenny & Travis