Navigation
« Using the Wordpress OpenID plugin for Evil | Main | More control over baddies: PHPIDS and WordPress »
Thursday
Aug052010

Enable Complete support for SSL on Wordpress

By 'complete' I mean: required SSL on the login and register pages as well as the entire admin section, and optional SSL for the entire blog for private reading. And when there is SSL, everything is transfered over SSL.

The first step is to enable SSL for administration. This is well documented within Wordpress, just add the following statement to your wp-config.php:

define('FORCE_SSL_ADMIN', true);

This will also force the links to the login, register, and forgot password pages to show up as 'https'. Wordpress will also force SSL if you navigate to the pages directory.

The second step is to set the relative options, settings, and constants to enable optional support for private browsing. Unfortunately Wordpress has no 'if https, only https' switch. Such that if you try to use 'https://yourblogurl.tld" the page may include images and plugin content over http causing a 'partial' SSL session (this is no good). We CANNOT enable private browsing if images are still transfered in clear-text.

This is a bit of a hack, and it looks a bit annoying. If you have a better engineered solution please let me know. Open your wp-config again and towards the top add:

define('WP_SITE_URI', ($_SERVER["HTTPS"]?"https://":"http://").$_SERVER["SERVER_NAME"]);
define('WP_SITEURI', ($_SERVER["HTTPS"]?"https://":"http://").$_SERVER["SERVER_NAME"]);

You could abstract out your domain if you'd like. This example assumes your blog is located in the top directory. Add a sub-directory at the end if you require. Then somewhere BEFORE the include for 'wp-settings' insert:

define("WP_CONTENT_URL", WP_SITE_URI . "/wp-content");

Then after the include of 'wp-settings' add:

wp_cache_set("siteurl_secure", "https://" . $_SERVER["SERVER_NAME"], "options");
wp_cache_set("home", WP_SITE_URI, "options");
wp_cache_set("siteurl", WP_SITE_URI, "options");

Yes, I know SERVER_NAME is repeated. I too feel dirty for having to add so much to Wordpress's configuration. The lead to rewrite the cache values was from noctis' blog (interesting that he does not support optional SSL).

Explanation: The optional part is the killer, since you want the ability to serve Wordpress in clear-text you need to make sure your 'siteurl' setting is set to use 'http://'. This setting is pulled from the database and used to set a constant called 'WP_CONTENT_URL'. Other constants will also inherit the 'http://' from WP_CONTENT_URL. Since constants are as they sound, you need to set it correctly before 'wp-settings' queries the database for the wrong value. However you must wait until 'wp-settings' includes the necessary functions to manipulate the cache. This is why we must wrap the include for 'wp-settings' to change all possible setting variables to support either HTTP or HTTPS.

Not done yet? Of course not! The last change is implemented as a plugin. (You could add it anywhere really.) We need to add a filter to replace all uploaded content to run over either HTTP or HTTPS. Whenever you insert an image into a post a corresponding <img src="http://" will be hard-coded into the post (if your saved 'siteurl' uses 'http://'). Create a plugin folder, name it something like 'content over ssl'. Inside create a like-named php file and inside include:

<?php
/* Plugin Name: Content over SSL
 * Description: Re-write content URIs to use the appropriate protocol
 * Author: Me
 * Version: .1
 */

add_filter('the_content', 'my_ssl');

function my_ssl($content) {
  if (isset($_SERVER["HTTPS"]))
    $content = ereg_replace("http://" . $_SERVER["SERVER_NAME"], "https://" . $_SERVER["SERVER_NAME"], $content);
  return $content;
}
?>

This will rewrite any hard-coded links in your post's content, to your domain name, to use HTTPS if the page is called using HTTPS. Remember to enable the plugin you just created in the Wordpress administration menus.

This was tested on Wordpress 3.0 running on Apache. Note: you'll need to setup SSL support yourself. :)

Reader Comments (8)

I've added the FORCE_SSL_ADMIN to the config file but I'm not sure what it's supposed to do. I can still go to http://domain.com/wp-login.php and login and run the admin interface over insecure HTTP.

It's only supposed to change the login link on the front page and such?

Please help :)
I'm running WP 3.0.1

Sep 28, 2010 at 10:09 | Unregistered CommenterDave

Dave: According to the documentation over at Wordpress.org, FORCE_SSL_ADMIN should redirect the login and admin pages to https.

The documentation suggests that Wordpress should not allow you to use the login portal over http (even if you navigate directly). "The constant FORCE_SSL_ADMIN can be set to true to force all logins and all admin sessions to happen over SSL." - From http://codex.wordpress.org/Administration_Over_SSL

So I'm not sure why you're running into trouble. Alternatively you can add a redirect in .htaccess that forces logins over SSL yourself. (not tested)

RewriteCond %{HTTP_HOST} ^domain.com/wp-login.php [NC]
RewriteRule ^(.*)$ http://domain.com/wp-login.php$1 [L,R=301]

Oct 2, 2010 at 9:11 | Unregistered CommenterTeddy

quick question... i am runnning a multi site with 2 networks... Network 1 has a ssl but network 2 does not..

I have forced ssl over admin and isolated it to network 1 only since that is the domain with the ssl.

I also need now to force ssl via the site url and home url of all newly created sites in network one without if affecting network2..

Can you tell me how to do this using nework1 and network2 as examles..

Can this all be done via the wp config file... I know how to do it via htaccess but it does it globably and I cant have it affecting network2

Thanks Scott

Nov 7, 2011 at 20:40 | Unregistered CommenterScott

ps.. this is what i used for the wp admin and login area.. just need something similiar to make this happen for all the pages and uploads.. I dont want to have to go into superadmin and manually change the site url and home url evertime someone creates a blog on my network

if ( $_SERVER["HTTP_HOST"] == "example.com" ) {
define('FORCE_SSL_ADMIN', true);
}

Nov 7, 2011 at 20:43 | Unregistered CommenterScott

Dave.. i believe you need a ssl cert on your domain to even use this !

Nov 7, 2011 at 20:44 | Unregistered CommenterScott
This can be done with an .htaccess file on the linux server. and redirect all of the traffic through https with a few simple lines of code.

performance will suffer due to the nature of HTTPS. It would be much wiser to place the secure content in a subdomain and secure the subdomain directory. Then bots and crawlers will not ding you for speed.

Just a thought. but a separate secure site is also a better idea for the shopping cart and other plug ins. marketing and seo plugins tend to conflict with cart, and other functional plugins
May 22, 2012 at 23:06 | Unregistered CommenterPatrick
Hi i done everything according to above instructions but it is not working for me can you please look where i am wrong? Here is my wp-config file https://gist.github.com/ombagrao22/5284556 I also added same plugin that you mentioned.

Thanks
Omprakash
Apr 1, 2013 at 6:05 | Unregistered CommenterOmprakash
Hi,

I tried what you've said and it's looking almost great!
One thing though, category links are always with https, no matter what. Even if I'm on http://myblog.tld, category URLs are alwasy https://myblog.tld/{categoryName}

Any idea why?

Thanks,
Adrian
Jul 21, 2014 at 6:59 | Unregistered CommenterAdrian

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
All HTML will be escaped. Hyperlinks will be created for URLs automatically.