Restrict production wp-admin/wp-login to an IP allowlist (opt-in)

New WP_ADMIN_ALLOWED_IPS env var (space-separated CIDR ranges, matching
Caddy's remote_ip syntax directly). Defaults to 0.0.0.0/0 ::/0 (today's
open behavior) when unset, resolved at the Compose level rather than in
the Caddyfile so an unset var can never leave `remote_ip` with zero
arguments and fail Caddy's startup. admin-ajax.php stays exempt since
WooCommerce routes logged-out storefront AJAX through it. Production
only — staging is already LAN-only.

Verified live: a scratch Caddy instance on a Docker network, with a
sibling container's actual observed source IP used to prove both the
blocked (403 on wp-admin/wp-login, everything else unaffected) and
allowed (matching CIDR lets it through) cases, plus `docker compose
config` to confirm the unset-var default resolves correctly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MqhgnCRjjVLFnZ3Jpn93Vg
This commit is contained in:
twooeyandClaude Sonnet 5 committed 2026-08-28 11:15:55 -04:00
1 parent 3143128798
commit 8b149a672d
4 files changed
+39

No files matched your search

+13
View File
@@ -18,6 +18,19 @@
@dev_only path /wp-content/plugins/bookstore-core/tests/* /wp-content/plugins/bookstore-core/vendor/* /wp-content/plugins/bookstore-core/composer.json /wp-content/plugins/bookstore-core/composer.lock /wp-content/plugins/bookstore-core/phpunit.xml*
respond @dev_only 404
# WP_ADMIN_ALLOWED_IPS (.env.production) — defaults to 0.0.0.0/0 ::/0
# (unrestricted) in docker-compose.production.yml when unset. Excludes
# admin-ajax.php: WordPress/WooCommerce route logged-out-visitor AJAX
# (cart fragments, nonces, some add-to-cart flows) through that file
# even though it lives under /wp-admin/ — blocking it by IP would break
# the storefront for every visitor, not just admin access.
@blocked_admin {
path /wp-admin* /wp-login.php
not path /wp-admin/admin-ajax.php
not remote_ip {$WP_ADMIN_ALLOWED_IPS}
}
respond @blocked_admin 403
php_fastcgi wordpress:9000
file_server