2026年11月12日
2026年11月12日
Proxy Server Settings for WordPress, WP-CLI, and OS Commands
This article is a localized edition of the Japanese original. Read the Japanese original
If an internal network or an isolated server is set up so that "traffic going outside goes only through a proxy," you have to specify the proxy separately in each place: WordPress uses the WP_PROXY_* constants in wp-config.php, while OS commands use environment variables or each tool's own configuration file. If you set only one of them, the other tries to go straight out and fails. This article explains the settings for running WordPress itself, WP-CLI, apt/dnf, git, and Composer through a proxy, and how to tell what is wrong when it will not connect.
What is covered here is a forward proxy, which the server passes through when it goes outside. It is a different thing from a "reverse proxy" such as Nginx, which receives visitor traffic and relays it to WordPress; the place where you configure it and its purpose are different.
What to confirm first
Before you write the settings, get the following information from your network administrator. If you fill it in by guesswork, it becomes hard to isolate the cause when it will not connect.
- The proxy's hostname (or IP address) and port number (example:
proxy.example.local:3128) - Whether authentication is used and which kind (Basic authentication with a username and password, or no authentication with access allowed by the server's IP)
- Whether it inspects the contents of HTTPS traffic (TLS inspection). If it does, how the company CA certificate is distributed
- Destinations that are reached directly without going through the proxy (internal DB servers, monitoring servers, hosts in the same segment, and so on)
First, on the server, use curl to check whether you can get outside through the proxy. If this does not work, no amount of WordPress configuration will make it work.
# Specify the proxy explicitly and connect to the WordPress.org API (-v shows progress)
curl -v -x http://proxy.example.local:3128 -o /dev/null https://api.wordpress.org/core/version-check/1.7/
# For a proxy with authentication (the password stays in shell history, so clear the history after testing)
curl -v -x http://proxy.example.local:3128 --proxy-user 'proxyuser:your-proxy-password' -o /dev/null https://api.wordpress.org/
If the -v output shows CONNECT api.wordpress.org:443 followed by a 200, the HTTPS connection through the proxy (a CONNECT tunnel) has been established. If 407 Proxy Authentication Required comes back, the credentials are missing or wrong. The proxy URL itself is written with http:// in many environments even when the destination is HTTPS. This is because you talk to the proxy over HTTP and set up a TLS tunnel inside that connection.
Route WordPress itself through the proxy (wp-config.php)
WordPress's HTTP API (wp_remote_get() and so on) is used for all of the following: update checks for plugins, themes, and core, downloading translations, and communication with external APIs. This HTTP API goes through the proxy when wp-config.php has the following constants. Back up wp-config.php before you start, and add them above the line "That's all, stop editing."
// Forward proxy settings (wp-config.php)
define( 'WP_PROXY_HOST', 'proxy.example.local' );
define( 'WP_PROXY_PORT', '3128' );
// Only if authentication is required. Example of reading the values from the server's environment variables
define( 'WP_PROXY_USERNAME', getenv( 'WP_PROXY_USERNAME' ) ?: '' );
define( 'WP_PROXY_PASSWORD', getenv( 'WP_PROXY_PASSWORD' ) ?: '' );
// Destinations that skip the proxy (comma-separated, * wildcards allowed)
define( 'WP_PROXY_BYPASS_HOSTS', 'localhost, 127.0.0.1, *.internal.example.local' );
The behavior to keep in mind is as follows.
- The proxy is enabled only when both
WP_PROXY_HOSTandWP_PROXY_PORTare defined. If only one is defined, it is ignored. - The authentication header is added only when both
WP_PROXY_USERNAMEandWP_PROXY_PASSWORDare defined. - When the destination hostname is
localhost, or is the same host as the site URL (siteurl), the request automatically skips the proxy. This is so that requests to itself (loopback) made by WP-Cron and Site Health do not flow to the proxy.127.0.0.1is not excluded automatically, so if you use it, put it inWP_PROXY_BYPASS_HOSTS.
If you write the password directly in wp-config.php, it remains as is in file backups and repositories. As in the example above, it is safer to pass it as an environment variable, for example from the PHP-FPM pool settings (env[WP_PROXY_PASSWORD] = ...), and to give wp-config.php itself permissions that cannot be read from the web (for example, 600 or 640). Ideally, ask for a proxy account with narrowed permissions that is used only for WordPress.
If you want to route finely by destination, you can use the pre_http_send_through_proxy filter. Returning null leaves it to the normal decision, and returning true/false makes that the decision. If you place it in an mu-plugin rather than a child theme, the setting stays even when you switch themes.
<?php
// wp-content/mu-plugins/proxy-routing.php
add_filter( 'pre_http_send_through_proxy', function ( $result, $uri, $check, $home ) {
// Connect to the internal API directly, not through the proxy
if ( isset( $check['host'] ) && 'api.internal.example.local' === $check['host'] ) {
return false;
}
return $result; // Leave everything else to the normal decision
}, 10, 4 );
Check that the setting took effect
In the admin screen, go to "Tools" → "Site Health" and check that the items about communication with WordPress.org show no problems (the wording of the items varies by version). To check from the command line, WP-CLI's wp eval is a quick way.
# Connect to WordPress.org through the HTTP API and print the status code or the error
wp eval '$r = wp_remote_get( "https://api.wordpress.org/core/version-check/1.7/" ); echo is_wp_error( $r ) ? $r->get_error_message() : wp_remote_retrieve_response_code( $r ); echo PHP_EOL;'
If 200 is shown, it succeeded. If there is an error, you get a message such as cURL error 7 (cannot connect to the proxy), cURL error 28 (timeout), or cURL error 56 (failure to establish the tunnel; often the proxy is refusing the destination or port), and you can use it for the troubleshooting in the next chapter.
Route OS commands through the proxy
Environment variables (curl, wget, Composer, and others)
Many commands refer to the http_proxy, https_proxy, and no_proxy environment variables. Lowercase names are widely used, and curl by design does not read uppercase HTTP_PROXY for HTTP destinations, so it is safest to set the lowercase ones.
# Example of placing in /etc/profile.d/proxy.sh or similar
export http_proxy="http://proxy.example.local:3128"
export https_proxy="http://proxy.example.local:3128"
export no_proxy="localhost,127.0.0.1,.internal.example.local"
There are two points to note. One is that environment variables are often not carried over when you run with sudo. Use sudo -E, or add them to env_keep in sudoers. The other is that shell environment variables do not reach WordPress running under PHP-FPM. PHP-FPM is by default set not to inherit environment variables (clear_env), so for WordPress, specify the proxy with the wp-config.php constants from the previous chapter.
Composer refers to the proxy settings in environment variables. With WP-CLI, commands that run by loading WordPress (such as wp plugin install) use the wp-config.php constants. Which settings commands that run before WordPress is loaded, such as wp core download, refer to can differ depending on the WP-CLI version, so run them and check.
Package management (apt and dnf) and git
apt and dnf can take the proxy from configuration files, separately from environment variables. If you automate updates for the whole server, fixing the proxy here lets you avoid the sudo environment variable problem.
# apt (Debian / Ubuntu): /etc/apt/apt.conf.d/95proxy
Acquire::http::Proxy "http://proxy.example.local:3128/";
Acquire::https::Proxy "http://proxy.example.local:3128/";
# dnf (RHEL / AlmaLinux / Rocky Linux): add under [main] in /etc/dnf/dnf.conf
proxy=http://proxy.example.local:3128
# git (set as the deployment user)
git config --global http.proxy http://proxy.example.local:3128
Troubleshooting when it will not connect (most common first)
1. It is not reaching the proxy (cURL error 7 / 28): The cause is a wrong hostname or port, or outbound restrictions in the server's firewall. Connect to the same destination with curl -v -x and see whether a TCP connection to the proxy itself can be made. Also check with getent hosts proxy.example.local that the server can resolve the proxy's hostname.
2. Authentication is being rejected (407): Either the username or password is wrong, or only one of the WordPress constants is defined. If the password contains symbols, also check that the value has not changed because of how quotes are handled in environment variables or the shell. For a proxy that accepts only non-Basic authentication such as NTLM, the WordPress constants alone may not work, so the realistic option is to ask about a method that allows access by the server's IP.
3. The destination is not allowed (403 or cURL error 56): In environments where the proxy uses an allowlist of destination domains, you need to get api.wordpress.org, downloads.wordpress.org, the source that distributes translation files, and the external APIs that the plugins you use communicate with allowed one by one. The symptom where you can check for plugin updates but the download fails can occur because the domains for checking and downloading are different.
4. Certificate errors (cURL error 60 and others): With a proxy that performs TLS inspection, the certificate is swapped midway for one issued by the company CA. WordPress verifies by default with the CA certificate bundle that ships with it (wp-includes/certificates/ca-bundle.crt), so it does not know the company CA and errors out. In this case, avoid turning off verification by setting sslverify to false. It means tampering can no longer be detected. The appropriate way is to prepare a certificate bundle that includes the company CA and pass its path to sslcertificates with the http_request_args filter. For OS commands, register the company CA in the OS's certificate store (update-ca-certificates on Debian/Ubuntu, update-ca-trust on RHEL family).
5. Even requests to itself are flowing to the proxy: In a setup where the site accesses itself with a hostname different from the site URL (such as an internal hostname), the loopback is sent to the proxy and the checks by WP-Cron and Site Health fail. Add that hostname to WP_PROXY_BYPASS_HOSTS.
If you can view the proxy's access logs, check whether the request from WordPress is recorded at the time you sent it and what status the proxy returned; this lets you quickly tell whether the cause is on the server side or the proxy side.
Summary
- WordPress goes through the proxy with
WP_PROXY_HOSTandWP_PROXY_PORTin wp-config.php (plusWP_PROXY_USERNAMEandWP_PROXY_PASSWORDwhen authentication is needed). OS environment variables do not reach PHP-FPM localhostand the site URL's host are excluded automatically. Put127.0.0.1and internal hosts inWP_PROXY_BYPASS_HOSTS- OS commands use environment variables (lowercase recommended), and apt, dnf, and git use their own configuration files. Environment variables tend to disappear under
sudo - When it will not connect, try the same destination with curl's
-v -x, and narrow it down in this order: not reached, 407, destination refused, certificate - For certificate errors, do not disable verification; specify a bundle that includes the company CA
- The behavior of the constants and filters may change with WordPress versions, so check communication in Site Health again after updates (as of October 2026)
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)