Configure a reverse proxy
A reverse proxy is a server that sits between the end-user requesting information from your site and the VIP application that serves the content. Most VIP applications do not require them, but if yours does, there are a few technical requirements and considerations to take into account before you implement one.
How to set up your server
The more you can tell us about your proxy server, the better we can support you in connecting it to VIP.
Our preferred method of implementing a reverse proxy setup is as follows:
- The VIP Go domain and URL structure matches the incoming request. That is, if the user requested example.com/blog the resource VIP will return is
example.com/blog
. - The reverse proxy should set a
True-Client-IP
HTTP request header with the IP of the end-user. - The reverse proxy should set an
X-VIP-Proxy-Verification
header with an agreed alphanumeric secret string as the value (contact us to agree on and set this string).
Sending the X-VIP-PROXY-VERIFICATION
header along with TRUE-CLIENT-IP
from the proxy will allow us to verify, via the secret key previously shared with us and saved in the site’s configuration on our end, that the request came via the reverse proxy server, and that the REMOTE_ADDR
value should be fixed with the TRUE-CLIENT-IP
value. This value is used in logs, and to identify proxied Automattic staff who need to support your site. Ensure that these headers are Incoming headers, not Outgoing. The following code must then be used in the site’s vip-config.php
file:
$proxy_lib = ABSPATH . '/wp-content/mu-plugins/lib/proxy/ip-forward.php';
if ( ! empty( $_SERVER['HTTP_TRUE_CLIENT_IP'] )
&& ! empty( $_SERVER['HTTP_X_VIP_PROXY_VERIFICATION'] )
&& file_exists( $proxy_lib ) ) {
require_once $proxy_lib;
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Validated in the function call.
Automattic\VIP\Proxy\fix_remote_address_with_verification_key(
$_SERVER['HTTP_TRUE_CLIENT_IP'],
$_SERVER['HTTP_X_VIP_PROXY_VERIFICATION']
);
// phpcs:enable
}
- Cloudflare Users: The
TRUE-CLIENT-IP
header is only available on Cloudflare Enterprise. If using Cloudflare, but not the Cloudflare Enterprise package, then you can use theCF-Connecting-IP
header instead, which is exactly the same value under a different key. Amend the above code snippet and change both instances of the stringHTTP_TRUE_CLIENT_IP
toHTTP_CF_CONNECTING_IP
. - Also ensure that any web application firewalls or other intermediary services allow access from VIP’s IP addresses, Jetpack’s IP addresses, and your application’s xmlrpc.php endpoint.
- Finally, if you would like to send custom headers to help you test the proxy application, you may do so. VIP will not reject these requests.
How VIP will set up your application
- Set the primary domain for the application to the production domain (
http://www.example.com
). This is so that requests returned back to the proxy server have the production domain. For multisite installations, see our documentation on special considerations for mapping domains. - Replace all instances of the VIP convenience domain with the production domain.
- Map and issue TLS Certificates for the domain you provided for the VIP application.
How it works
Using the scenario where you want to host a VIP application at http://www.example.com/blog
:
- A request comes to
http://www.example.com
for the path/blog/2019/hello-world/
. - The proxy server forwards the request to the VIP application’s IP address, setting the host header to
http://www.example.com
. - The VIP application returns the post as
http://www.example.com/blog/2019/hello-world/
. - The user’s browser displays the VIP powered content as
https://www.example.com/blog/2019/hello-world/
.
Alternate implementations
If a X-VIP-Proxy-Verification
header cannot be set, the proxy can be verified by using an IP allow list and passing the client IP in the header True-Client-IP
. Please note that the allow list must be kept up to date.
This implementation assumes a file vip-config/remote-proxy-ips.php
, which contains an array of proxy IP addresses. The contents of the file should be similar to the example below:
<?php
// A constant defining an array of allowed IP addresses and/or CIDRs
// which equate to the possible IP addresses of your Remote Proxy
define( 'MY_PROXY_IP_ALLOW_LIST', [
'1.2.3.4/20',
'5.6.7.8/20',
'2.3.4.5',
] );
The IPs can be provided as fully qualified IPv4 or IPv6 addresses, or in CIDR notation.
Then, the following code in vip-config/vip-config.php
checks the Reverse Proxy’s IP address matches the allowed list, extracts the end user’s IP address from the True-Client-IP
HTTP Header, and forwards the End User’s real IP address as REMOTEADDR
:
$proxy_lib = ABSPATH . '/wp-content/mu-plugins/lib/proxy/ip-forward.php';
if ( ! empty( $_SERVER['HTTP_TRUE_CLIENT_IP'] ) && file_exists( $proxy_lib ) ) {
require_once( __DIR__ . '/remote-proxy-ips.php' );
require_once( $proxy_lib );
Automattic\VIP\Proxy\fix_remote_address(
$_SERVER['HTTP_TRUE_CLIENT_IP'],
$_SERVER['HTTP_X_FORWARDED_FOR'],
MY_PROXY_IP_ALLOW_LIST
);
}
Validating your proxy configuration
We encourage you to test your proxy configuration extensively leading up to launch.
Using cURL
One way to validate the reverse proxy is to configure the proxy and use curl
to send a request to a URI that you expect to be forwarded to VIP and inspect the response headers. You should see x-hacker
, x-powered-by
, and other headers sent by VIP alongside the headers sent by the proxy server.
If example.com is your proxy server and the VIP application is at example.com/blog/ when you run curl -I https://example.com/blog/
you should see x-powered-by: WordPress VIP <https://wpvip.com>
and the headers identifying the proxy server.
Using a staging server
Another strategy for testing is to configure a staging proxy server for the routes you intend to set in production. If you have staging.example.com
you can point staging.example.com/blog/
to the VIP application. If you would like to do this please notify VIP with the following:
- The domain name of your staging server (staging.example.com)
- When you would like to begin testing
VIP will map the domain and configure TLS certificates once DNS records are in place. Once you’re ready to start testing we can search-replace for the go-vip.co
or go-vip.net
convenience domain. When you’re ready to launch, you need only to replicate the proxy configuration on your production server.
Obtaining a TLS certificate
Let’s Encrypt issues a TLS certificate after verifying a domain’s ownership using what’s known as an ACME challenge. If you are using a reverse proxy or otherwise not pointing your DNS directly to VIP, then your configuration may cause the ACME challenge to fail.
To meet the ACME challenge’s requirements, your reverse proxy must point requests for /.well-known/acme-challenge/*
(where *
is a wildcard representing any string) to VIP. You can confirm your proxy’s configuration using the curl command. Here’s an example of a positive response that would meet the ACME challenge:
$ curl -I http://www.example.com/.well-known/acme-challenge/fdfxcxvdz
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 22 Mar 2021 15:38:12 GMT
Content-Type: text/plain;charset=utf-8
Connection: keep-alive
Vary: Accept-Encoding
Vary: Cookie
Note that the reverse proxy must not add any query parameters on the end of the acme-challenge URL. For example, if the reverse proxy adds ?sslEnabled=true
to the end of the acme-challenge string, provisioning a Let’s Encrypt certificate will fail.
In addition to your proxy’s own security measures, validating the ACME challenge will ensure that the connection from your proxy to the VIP servers is secure. If you prefer to not adjust your proxy settings or to not use Let’s Encrypt, you may alternatively procure a custom TLS certificate from a third-party provider.