Incorrect URLs in WordPress Admin Interface

TL;DR

You’re probably running WordPress behind a proxy and it needs to be reconfigured to fix an issue in WordPress core. See “The Fix” section below on how that’s done in NGINX.

The Problem

I recently ran into a strange issue when navigating my WordPress admin interface. Everything seemed to work properly (I could edit posts, modify themes, etc). Unfortunately, clicking to sort my list of posts caused a redirect to a URL like:

http://wordpress/wp-admin/edit.php?orderby=comment_count&order=asc

Note the “wordpress” hostname that clearly won’t resolve to anything useful. Here’s how to fix this the right way

Troubleshooting Process

First, after a bit of Googling, I found this VERY OLD TICKET describing the issue in WordPress core. To summarize, this is how some of the URLs in the admin interface are constructed:

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

They have no intention of fixing this simple issue anytime soon so I had to come up with a fix myself. There are references in that ticket to modifying the core code or applying patches but Homie don’t play that.

Ignoring the hard-coded http… ?, we can see from the PHP docs that $_SERVER[‘HTTP_HOST’] is:

Contents of the Host: header from the current request, if there is one.

And if you’re using a proxy to forward traffic to WordPress, this header may not be what you’d expect. When I first ran into this issue, I was using a very simple configuration in nginx:

location / {
  proxy_pass        http://wordpress;
}

The issue here is that the hostname “wordpress”, though perfectly resolvable for the proxy, gets passed along in the request to WordPress. To fix this, we need to populate that “Host” header mentioned in the PHP docs. This way the old WordPress code will use the correct hostname in its URLs.

To do this, I found I could set this header when proxying in nginx:

Syntax:   proxy_set_header field value;
Default:  proxy_set_header Host $proxy_host;
          proxy_set_header Connection close;Context:http, server, location

That excerpt also shows that by default nginx sets the Host header to the proxied hostname.

The Fix

And finally, to fix this in my nginx proxy:

location / {
  proxy_pass        http://wordpress;
  proxy_set_header  Host  $host;
}

This works because that $host variable is equal to:

in this order of precedence: host name from the request line, or host name from the “Host” request header field, or the server name matching a request