Discussion:
Make WP more usable behind load balancers/proxies
Hauke
2013-10-15 17:52:50 UTC
Permalink
Hi there,

is it possible to change code lines like

$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] .
$_SERVER['REQUEST_URI'] );

into something like this:

if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$serverhost = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else {
$serverhost = 'http://' . $_SERVER['HTTP_HOST'];
}
$current_url = set_url_scheme( $serverhost . $_SERVER['REQUEST_URI'] );

In my case I changed that in wp-admin/includes/class-wp-list-table.php
(lines 494 and 651, WP 3.5.1 (same in WP 3.6.1).

I am not a developer, therefore that code isn't that nice. It's more like an
idea for you guys with a lot more knowledge than mine.

The reason why I need that code:

We use WP (and some other apps) under one domain, e.g. example.com.
In our case, we want to use (pseudo) subfolder domains for that different
apps, e.g. 'example.com/blog', 'example.com/shop' or 'example.com/foo'. At
the same time, we want to seperate these apps in one VHost per app (we
use Apache + fcgid for separating PHP too).
So we put a load balancer/caching proxy (Varnish) in front of our
webservers, which handles those URL rewriting stuff. It detects
example.com/blog and rewrites the HTTP HOST Header Field to something
internal like 'blog.example.local'. The Requests now reach the correct
VHosts on the backend webservers. We provide the original hostname in
the HTTP X_FORWARDED_HOST Header Field.
WP works good at all with that setting, but there are some things like
pagination or that list table one the 'All Pages' site in the WP backend,
that doesn't work because of producing URIs with the internal hostname.
--
Best regards,
Hauke
Nikola Nikolov
2013-10-15 17:59:54 UTC
Permalink
Why don't you just create an mu-plugin that will override the
$_SERVER['HTTP_HOST'] variable?

Simply do something like

if ( isset( $_SERVER['HTTP_X_FORWARDED_HOST'] )
&& $_SERVER['HTTP_X_FORWARDED_HOST'] && _is_valid_host(
$_SERVER['HTTP_X_FORWARDED_HOST'] ) ) {
$_SERVER['HTT_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}

Note that the "_is_valid_host()" function is not an actual function. You
will have to define a function that will check the value passed to it and
make sure that it's acceptable(for instance you can check it against an
array of your domains).
Post by Hauke
Hi there,
is it possible to change code lines like
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] .
$_SERVER['REQUEST_URI'] );
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$serverhost = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else {
$serverhost = 'http://' . $_SERVER['HTTP_HOST'];
}
$current_url = set_url_scheme( $serverhost . $_SERVER['REQUEST_URI'] );
In my case I changed that in wp-admin/includes/class-wp-list-table.php
(lines 494 and 651, WP 3.5.1 (same in WP 3.6.1).
I am not a developer, therefore that code isn't that nice. It's more like an
idea for you guys with a lot more knowledge than mine.
We use WP (and some other apps) under one domain, e.g. example.com.
In our case, we want to use (pseudo) subfolder domains for that different
apps, e.g. 'example.com/blog', 'example.com/shop' or 'example.com/foo'. At
the same time, we want to seperate these apps in one VHost per app (we
use Apache + fcgid for separating PHP too).
So we put a load balancer/caching proxy (Varnish) in front of our
webservers, which handles those URL rewriting stuff. It detects
example.com/blog and rewrites the HTTP HOST Header Field to something
internal like 'blog.example.local'. The Requests now reach the correct
VHosts on the backend webservers. We provide the original hostname in
the HTTP X_FORWARDED_HOST Header Field.
WP works good at all with that setting, but there are some things like
pagination or that list table one the 'All Pages' site in the WP backend,
that doesn't work because of producing URIs with the internal hostname.
--
Best regards,
Hauke
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Hauke
2013-10-15 20:16:45 UTC
Permalink
Hi Nikola,

thanks so far. I created a very basic plugin:
https://github.com/haukebruno/wp-xforwardedhost

It works for me now.

Cheers,
Hauke
--
Best regards,
Hauke
Post by Nikola Nikolov
Why don't you just create an mu-plugin that will override the
$_SERVER['HTTP_HOST'] variable?
Simply do something like
if ( isset( $_SERVER['HTTP_X_FORWARDED_HOST'] )
&& $_SERVER['HTTP_X_FORWARDED_HOST'] && _is_valid_host(
$_SERVER['HTTP_X_FORWARDED_HOST'] ) ) {
$_SERVER['HTT_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}
Note that the "_is_valid_host()" function is not an actual function. You
will have to define a function that will check the value passed to it and
make sure that it's acceptable(for instance you can check it against an
array of your domains).
Post by Hauke
Hi there,
is it possible to change code lines like
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] .
$_SERVER['REQUEST_URI'] );
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$serverhost = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else {
$serverhost = 'http://' . $_SERVER['HTTP_HOST'];
}
$current_url = set_url_scheme( $serverhost . $_SERVER['REQUEST_URI'] );
In my case I changed that in wp-admin/includes/class-wp-list-table.php
(lines 494 and 651, WP 3.5.1 (same in WP 3.6.1).
I am not a developer, therefore that code isn't that nice. It's more like an
idea for you guys with a lot more knowledge than mine.
We use WP (and some other apps) under one domain, e.g. example.com.
In our case, we want to use (pseudo) subfolder domains for that different
apps, e.g. 'example.com/blog', 'example.com/shop' or 'example.com/foo'. At
the same time, we want to seperate these apps in one VHost per app (we
use Apache + fcgid for separating PHP too).
So we put a load balancer/caching proxy (Varnish) in front of our
webservers, which handles those URL rewriting stuff. It detects
example.com/blog and rewrites the HTTP HOST Header Field to something
internal like 'blog.example.local'. The Requests now reach the correct
VHosts on the backend webservers. We provide the original hostname in
the HTTP X_FORWARDED_HOST Header Field.
WP works good at all with that setting, but there are some things like
pagination or that list table one the 'All Pages' site in the WP backend,
that doesn't work because of producing URIs with the internal hostname.
--
Best regards,
Hauke
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Nikola Nikolov
2013-10-15 22:38:49 UTC
Permalink
Yep - that's exactly what I had in mind.

You can shorten your code by simply changing your function to this:

function is_valid_host( $hosts, $xforwardedhost ) {
return in_array( $xforwardedhost, $hosts );
}


Not that having a loop would make a big difference - but you know being
minimalistic is sometimes cool :)

I'm glad you were able to figure it out though.

Nikola
Post by Hauke
Hi Nikola,
https://github.com/haukebruno/wp-xforwardedhost
It works for me now.
Cheers,
Hauke
--
Best regards,
Hauke
Post by Nikola Nikolov
Why don't you just create an mu-plugin that will override the
$_SERVER['HTTP_HOST'] variable?
Simply do something like
if ( isset( $_SERVER['HTTP_X_FORWARDED_HOST'] )
&& $_SERVER['HTTP_X_FORWARDED_HOST'] && _is_valid_host(
$_SERVER['HTTP_X_FORWARDED_HOST'] ) ) {
$_SERVER['HTT_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}
Note that the "_is_valid_host()" function is not an actual function. You
will have to define a function that will check the value passed to it and
make sure that it's acceptable(for instance you can check it against an
array of your domains).
Post by Hauke
Hi there,
is it possible to change code lines like
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] .
$_SERVER['REQUEST_URI'] );
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$serverhost = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else {
$serverhost = 'http://' . $_SERVER['HTTP_HOST'];
}
$current_url = set_url_scheme( $serverhost . $_SERVER['REQUEST_URI'] );
In my case I changed that in wp-admin/includes/class-wp-list-table.php
(lines 494 and 651, WP 3.5.1 (same in WP 3.6.1).
I am not a developer, therefore that code isn't that nice. It's more
like
Post by Nikola Nikolov
Post by Hauke
an
idea for you guys with a lot more knowledge than mine.
We use WP (and some other apps) under one domain, e.g. example.com.
In our case, we want to use (pseudo) subfolder domains for that
different
Post by Nikola Nikolov
Post by Hauke
apps, e.g. 'example.com/blog', 'example.com/shop' or 'example.com/foo'.
At
Post by Nikola Nikolov
Post by Hauke
the same time, we want to seperate these apps in one VHost per app (we
use Apache + fcgid for separating PHP too).
So we put a load balancer/caching proxy (Varnish) in front of our
webservers, which handles those URL rewriting stuff. It detects
example.com/blog and rewrites the HTTP HOST Header Field to something
internal like 'blog.example.local'. The Requests now reach the correct
VHosts on the backend webservers. We provide the original hostname in
the HTTP X_FORWARDED_HOST Header Field.
WP works good at all with that setting, but there are some things like
pagination or that list table one the 'All Pages' site in the WP
backend,
Post by Nikola Nikolov
Post by Hauke
that doesn't work because of producing URIs with the internal hostname.
--
Best regards,
Hauke
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Hauke
2013-10-16 07:39:08 UTC
Permalink
Hi Nikola,

I shortened the code so far. Thank you pretty much for your help ;)
--
Best regards,
Hauke
Post by Nikola Nikolov
Yep - that's exactly what I had in mind.
function is_valid_host( $hosts, $xforwardedhost ) {
return in_array( $xforwardedhost, $hosts );
}
Not that having a loop would make a big difference - but you know being
minimalistic is sometimes cool :)
I'm glad you were able to figure it out though.
Nikola
Post by Hauke
Hi Nikola,
https://github.com/haukebruno/wp-xforwardedhost
It works for me now.
Cheers,
Hauke
--
Best regards,
Hauke
Post by Nikola Nikolov
Why don't you just create an mu-plugin that will override the
$_SERVER['HTTP_HOST'] variable?
Simply do something like
if ( isset( $_SERVER['HTTP_X_FORWARDED_HOST'] )
&& $_SERVER['HTTP_X_FORWARDED_HOST'] && _is_valid_host(
$_SERVER['HTTP_X_FORWARDED_HOST'] ) ) {
$_SERVER['HTT_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}
Note that the "_is_valid_host()" function is not an actual function. You
will have to define a function that will check the value passed to it and
make sure that it's acceptable(for instance you can check it against an
array of your domains).
Post by Hauke
Hi there,
is it possible to change code lines like
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] .
$_SERVER['REQUEST_URI'] );
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$serverhost = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else {
$serverhost = 'http://' . $_SERVER['HTTP_HOST'];
}
$current_url = set_url_scheme( $serverhost . $_SERVER['REQUEST_URI'] );
In my case I changed that in wp-admin/includes/class-wp-list-table.php
(lines 494 and 651, WP 3.5.1 (same in WP 3.6.1).
I am not a developer, therefore that code isn't that nice. It's more
like
Post by Nikola Nikolov
Post by Hauke
an
idea for you guys with a lot more knowledge than mine.
We use WP (and some other apps) under one domain, e.g. example.com.
In our case, we want to use (pseudo) subfolder domains for that
different
Post by Nikola Nikolov
Post by Hauke
apps, e.g. 'example.com/blog', 'example.com/shop' or
'example.com/foo'.
At
Post by Nikola Nikolov
Post by Hauke
the same time, we want to seperate these apps in one VHost per app (we
use Apache + fcgid for separating PHP too).
So we put a load balancer/caching proxy (Varnish) in front of our
webservers, which handles those URL rewriting stuff. It detects
example.com/blog and rewrites the HTTP HOST Header Field to something
internal like 'blog.example.local'. The Requests now reach the correct
VHosts on the backend webservers. We provide the original hostname in
the HTTP X_FORWARDED_HOST Header Field.
WP works good at all with that setting, but there are some things like
pagination or that list table one the 'All Pages' site in the WP
backend,
Post by Nikola Nikolov
Post by Hauke
that doesn't work because of producing URIs with the internal hostname.
--
Best regards,
Hauke
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Andrew Nacin
2013-10-16 04:32:19 UTC
Permalink
Post by Hauke
is it possible to change code lines like
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] .
$_SERVER['REQUEST_URI'] );
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$serverhost = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else {
$serverhost = 'http://' . $_SERVER['HTTP_HOST'];
}
$current_url = set_url_scheme( $serverhost . $_SERVER['REQUEST_URI'] );
Many load balancers and proxy servers forward HTTP headers for HTTPS, IP
addresses, and more. These typically take the form of HTTP_X_FORWARDED_FOR
(X-Forwarded-For), for remote IP addresses, and HTTP_X_FORWARDED_PROTO
(X-Forwarded-Proto), for whether traffic is going over the HTTPS protocol.
Occasionally other information needs to be forwarded, like the server port
or hostname.

If WordPress blindly listened to these headers — especially for protocols —
there is a risk of infinite redirects and general breakage. To make matters
worse, these are not formal standards, and are rather freeform. As a
result, many web server and configurations do this differently. For
example, one configuration might prepend “HTTP_”, resulting in HTTP_HTTPS.
What should be done instead is a server should either pass properly mapped
headers to PHP, or some code can do the mapping in wp-config.php. For
example:

if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' ===
$_SERVER['HTTP_X_FORWARDED_PROTO'] ) )
$_SERVER['HTTPS'] = 'on';

See also:
http://core.trac.wordpress.org/ticket/9235
http://core.trac.wordpress.org/ticket/15009
http://core.trac.wordpress.org/ticket/15733
http://core.trac.wordpress.org/ticket/19337
http://core.trac.wordpress.org/ticket/24394
etc.

Nacin
Hauke
2013-10-16 07:40:27 UTC
Permalink
Hi Nacin,

thanks for your advices. I will have a look at it.
--
Best regards,
Hauke
Post by Andrew Nacin
Post by Hauke
is it possible to change code lines like
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] .
$_SERVER['REQUEST_URI'] );
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$serverhost = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else {
$serverhost = 'http://' . $_SERVER['HTTP_HOST'];
}
$current_url = set_url_scheme( $serverhost . $_SERVER['REQUEST_URI'] );
Many load balancers and proxy servers forward HTTP headers for HTTPS, IP
addresses, and more. These typically take the form of HTTP_X_FORWARDED_FOR
(X-Forwarded-For), for remote IP addresses, and HTTP_X_FORWARDED_PROTO
(X-Forwarded-Proto), for whether traffic is going over the HTTPS protocol.
Occasionally other information needs to be forwarded, like the server port
or hostname.
If WordPress blindly listened to these headers — especially for protocols —
there is a risk of infinite redirects and general breakage. To make matters
worse, these are not formal standards, and are rather freeform. As a
result, many web server and configurations do this differently. For
example, one configuration might prepend “HTTP_”, resulting in HTTP_HTTPS.
What should be done instead is a server should either pass properly mapped
headers to PHP, or some code can do the mapping in wp-config.php. For
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' ===
$_SERVER['HTTP_X_FORWARDED_PROTO'] ) )
$_SERVER['HTTPS'] = 'on';
http://core.trac.wordpress.org/ticket/9235
http://core.trac.wordpress.org/ticket/15009
http://core.trac.wordpress.org/ticket/15733
http://core.trac.wordpress.org/ticket/19337
http://core.trac.wordpress.org/ticket/24394
etc.
Nacin
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Loading...