{$SITE_DOMAIN} { encode gzip root * /var/www/html @no_cache path /cart* /checkout* /my-account* /wp-admin* /wp-login.php header @no_cache Cache-Control "no-store, no-cache, must-revalidate" request_body { max_size 32MB } # bookstore-core's tests/, vendor/, composer.json/.lock, and # phpunit.xml.dist ship in the repo (and are bind-mounted straight into # this container — see docker-compose.*.yml) so they exist under the # webroot, but nothing about a git-checkout deploy strips them before # they land here. 404 instead of 403 so their existence isn't confirmed. @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 log { output file /data/access.log { roll_size 50MiB roll_keep 10 } } }