Nginx – Protecting WordPress Admin interface on an alternate port

MySQLnginxWordpress

I have a self-hosted WordPress blog. Whenever possible, I try to protect admin interfaces to web apps using SSL and X.509 client certificate authentication. I have all of this working properly for things like phpMyAdmin, so the technical bits with the web server are all in place.

My hosting setup is:

  • nginx 0.7.x
  • PHP 5.2.10 with the fpm patch
  • MySQL 5.x

I'm running all of this on a VPS, so I just have one external IP. I have several other SSL websites running on the box: one on the default port and all the others on alternate ports (so that each can have a different certificate matched to their hostname).

My intent was to have two server configuration blocks:

  1. one serving blog.domain.com port 80 which returned 404 if you tried to get to anything under /wp-admin
  2. another running on port 8443 with SSL with no URL restrictions but which required that a valid X.509 client certificate be presented.

The problem I'm facing is that WordPress doesn't like being accessed on two different ports. Whenever I attempt to go to https://blog.domain.com:8443, it redirects me to https://blog.domain.com, which is a different vhost entirely (the main site on the server, running on the default port). I then get a certificate name error in the browser, and even if I override the warning, I'm no longer talking to the wordpress site.

The main URL of the blog is stored in the wp_options table:

mysql> select option_value from wp_options where option_name = 'siteurl';
+------------------------------+
| option_value                 |
+------------------------------+
| http://blog.domain.com       |
+------------------------------+
1 row in set (0.00 sec)

mysql>

so it's not like I could just make a second copy of the blog files with the main URL set to https://blog.domain.com:8443 and access the admin interface that way.

Any ideas?

UPDATE

Ater playing for some time with the suggested answers, I've come to the conclusion that it isn't possible to do precisely what I want. Enabling the features in wordpress result in users making SSL requests to /wp-(admin|login|register), which they can't do if I require X.509 client certs on the SSL side.

The best solution I came up with was to set up an SSL frontend with certificate authentication that just proxied requests back to the non-SSL nginx. Even then, I can't entirely cut off non-SSL access to /wp-admin because much of the CSS and Javascript used in user registration and profile management come from that directory.

I can allow access to the CSS, images and Javascript under /wp-admin over HTTP and just require SSL access for the PHP scripts, but then users can't modify their profile (colour schemes, display names, etc.) The next step would be to identify the subset of PHP scripts required for normal users and let those pass over HTTP while rejecting the rest, but then I'm a slave to the wordpress development team should they reorganize things.

I guess this one comes down to training myself to only manage the blog over SSL, even though the server will allow me to do so over plain HTTP.

Best Answer

This might help you, as of wordpress 2.6 you can force the admin and login areas to be ssled.

http://codex.wordpress.org/Administration_Over_SSL

  define('FORCE_SSL_LOGIN', true);
  define('FORCE_SSL_ADMIN', true);

Sometimes, you want your whole wp-admin to run over a secure connection using the https protocol. Conceptually, the procedure works like this:

Set up two virtual hosts with the same url (the blog url), one secure, the other not. On the secure virtual host, set up a rewrite rule that shuttles all non-wp-admin traffic to the insecure site. On the insecure virtual host, set up a rewrite rule that shuttles all traffic to wp-admin to the secure host. Put in a filter (via a plugin) that filters the links in wp-admin so that once activated, administrative links are rewritten to use https and that edits cookies to work only over encrypted connections.

The plugin they mention is called admin ssl.