# WordPress 7.1.2 with the ActivityPub plugin 9.3.1: posts as Articles (or Notes when short), comments as replies, each # author an actor and the blog one too, likes and boosts kept as comments of their kind. On a shared MySQL 8.4 (database # wordpress). The plugin federates from WP-Cron, so a sidecar runs the due events every few seconds. WordPress sends its # requests through its own CA bundle (wp-includes/certificates), to which Caddy's root is appended; its URL guard refuses # private addresses with no switch, which the pasture's public-looking subnet passes. The admin is wpuser; the town's # accounts are authors with application passwords for the REST API. Its automatic updates are off: one (core 7.1.2, # 2026-10-05) wrote a new CA bundle over the one Caddy's root was appended to, and nothing reached PrivaPub after it. WORDPRESS_IMAGE=${WORDPRESS_IMAGE:-docker.io/library/wordpress:7.1.2-apache} WORDPRESS_CLI_IMAGE=${WORDPRESS_CLI_IMAGE:-docker.io/library/wordpress:cli} WORDPRESS_ACTIVITYPUB=9.3.1 WORDPRESS_PASSWORD=Wordpress-Pasture-1 . "$here/peers/shared.sh" # wp : wp-cli against the site, sharing its files wp() { podman run --rm --network $net --volumes-from pasture-wordpress --user 33:33 -e HOME=/tmp \ -e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_USER=pasture -e WORDPRESS_DB_PASSWORD=pasture -e WORDPRESS_DB_NAME=wordpress \ "$WORDPRESS_CLI_IMAGE" wp "$@" } wordpress_up() { shared_mysql_up mysql_db wordpress podman volume exists pasture-wordpress-html || podman volume create --label pasture=1 pasture-wordpress-html >/dev/null # behind Caddy: https as the proxy says, and the site's own address local extra="if (isset(\$_SERVER['HTTP_X_FORWARDED_PROTO']) && \$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { \$_SERVER['HTTPS'] = 'on'; } define('WP_HOME', 'https://wordpress.test'); define('WP_SITEURL', 'https://wordpress.test'); define('DISABLE_WP_CRON', true); define('FS_METHOD', 'direct'); define('AUTOMATIC_UPDATER_DISABLED', true); define('WP_AUTO_UPDATE_CORE', false);" podman run -d --replace --name pasture-wordpress --network $net \ -e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_USER=pasture -e WORDPRESS_DB_PASSWORD=pasture -e WORDPRESS_DB_NAME=wordpress \ -e WORDPRESS_CONFIG_EXTRA="$extra" -v pasture-wordpress-html:/var/www/html -v "$ca:/pasture/ca:z,ro" \ "$WORDPRESS_IMAGE" >/dev/null for _ in $(seq 1 60); do podman exec pasture-wordpress test -f /var/www/html/wp-config.php 2>/dev/null && break; sleep 2; done if ! wp core is-installed >/dev/null 2>&1; then wp core install --url=https://wordpress.test --title="Pasture WordPress" --admin_user=wpuser \ --admin_password="$WORDPRESS_PASSWORD" --admin_email=wpuser@wordpress.test --skip-email >/dev/null fi wp rewrite structure '/%postname%/' --hard >/dev/null wp plugin is-installed activitypub 2>/dev/null || wp plugin install activitypub --version=$WORDPRESS_ACTIVITYPUB >/dev/null wp plugin activate activitypub >/dev/null # both the blog and its authors are actors wp option update activitypub_actor_mode actor_blog >/dev/null podman exec pasture-wordpress sh -c 'grep -q "Caddy Local Authority" wp-includes/certificates/ca-bundle.crt || { echo; cat /pasture/ca/root.crt; } >> wp-includes/certificates/ca-bundle.crt' podman run -d --replace --name pasture-wordpress-cron --network $net --volumes-from pasture-wordpress --user 33:33 -e HOME=/tmp \ -e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_USER=pasture -e WORDPRESS_DB_PASSWORD=pasture -e WORDPRESS_DB_NAME=wordpress \ --entrypoint sh "$WORDPRESS_CLI_IMAGE" -c 'while :; do wp cron event run --due-now >/dev/null 2>&1; sleep 5; done' >/dev/null wait_http https://wordpress.test:6443/ 1 >/dev/null 2>&1 || true for _ in $(seq 1 60); do site wordpress.test -s -o /dev/null -w '%{http_code}' "https://wordpress.test:6443/.well-known/webfinger?resource=acct:wpuser@wordpress.test" 2>/dev/null | grep -q 200 && break sleep 2 done wordpress_app_password wpuser > "$here/.state/wordpress.token" echo "wordpress: https://wordpress.test:6443" } # wordpress_user : an author (who publishes, and so is an actor) wordpress_user() { wp user get "$1" >/dev/null 2>&1 || wp user create "$1" "$1@wordpress.test" --role=author --user_pass="$WORDPRESS_PASSWORD" >/dev/null } # wordpress_app_password : "name:password" for the REST API's basic authentication wordpress_app_password() { echo "$1:$(wp user application-password create "$1" pasture --porcelain)" }