Build/Test Tools: Make loopback requests work in the local Docker environment#12219
Build/Test Tools: Make loopback requests work in the local Docker environment#12219westonruter wants to merge 7 commits into
Conversation
…ironment. Inside the php/cli containers `localhost` is the container's own loopback, where nothing listens on the published web-server port, so WordPress loopback requests (Site Health, cron, `wp_remote_get( home_url() )`) fail with "cURL error 7: Could not connect to server". The `extra_hosts: localhost:host-gateway` mapping cannot fix this because Docker always writes `127.0.0.1 localhost` first in `/etc/hosts`, shadowing the gateway entry. Add a development-only mu-plugin that pins loopback requests to the Docker host gateway (via `host.docker.internal`) using `CURLOPT_RESOLVE`, and copy it into the gitignored mu-plugins directory from the php container on startup, mirroring the existing object-cache.php drop-in pattern. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update the mu-plugin description to explain that the docker-compose `extra_hosts: localhost:host-gateway` mapping has no effect when cURL resolves "localhost" via glibc's getaddrinfo() (which special-cases the name to loopback), and that the shim is therefore not always necessary -- resolvers that honor the mapping (e.g. a c-ares-based libcurl) already complete loopback requests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Convert the php service `command` to a YAML folded block scalar so the mu-plugin install and Memcached dropin steps each read on their own line. The folded newlines collapse back into single spaces, so the resolved command is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ipt. Lay the folded `command` out as an indented multi-line shell script and drop the note about YAML folding mechanics. The resolved command is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
This comment was marked as outdated.
This comment was marked as outdated.
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
Problem
Loopback HTTP requests fail in the local Docker environment. The Site Health "loopback request" test reports a failure, and any in-PHP loopback fails too:
The web server (nginx) runs in a separate container from
php/cli.home_url()ishttp://localhost:8000, but inside those containerslocalhostis the container's own loopback, where nothing listens on the published port — so the request is refused.The existing
extra_hosts: localhost:host-gatewaymapping (added in [a629d1c]) is meant to address this, but it has no effect when cURL resolveslocalhostvia glibc'sgetaddrinfo(), which special-cases that name to loopback and never consults the/etc/hostsgateway entry. (The legacygethostbyname()path does return the gateway, but the HTTP stack doesn't use it.) The host gateway itself is reachable —host.docker.internal:8000returns200— so only name resolution oflocalhostis broken.Fix
Add a development-only mu-plugin (
tools/local-env/mu-plugins/fix-docker-loopback.php) that, for requests aimed at the site's own host, pins the cURL handle to the Docker host gateway viaCURLOPT_RESOLVE(resolved at runtime throughhost.docker.internal). It is gated onwp_get_environment_type() === 'local'and no-ops where the gateway is unavailable.The
phpcontainer copies the shim into the (gitignored)wp-content/mu-pluginsdirectory on startup, mirroring the existingobject-cache.phpdrop-in pattern, so it covers Site Health, cron spawning, andwp_remote_get( home_url() )from bothphpandcli.The
extra_hostslines are left in place — they are the intended mechanism and remain effective on resolvers that honor them (e.g. a c-ares-based libcurl); this shim backs them up where they do not.composer.jsonis also updated to suggestext-curl, which the shim relies on.Testing
With the environment running:
wp_remote_get( home_url() )→HTTP 200WP_Site_Health::can_perform_loopback()→status=goodPHPCS and PHPStan (level 10, via
phpstan-diff) both pass on the new file.Trac ticket: https://core.trac.wordpress.org/ticket/65484
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 4.8
Used for: Diagnosing the loopback failure, drafting the mu-plugin and
docker-compose.ymlchanges, and verifying the fix end-to-end. All changes were reviewed and edited by me.This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.