DreamHost & Let’s Encrypt & WordPress

Mid-last year, Electronic Freedom Frontier announced Let’s Encrypt: free, automated, Open Source HTTPS Certificate Authority for everyone. That’s the padlock in the address bar. Supernaut and other sites of mine have either gone the parasitic paid route, or the “whole day lost and still not working” free route.

DreamHost, who has been my webhost for close to a decade (thanks Emile), announced in December they would be providing One-Click Let’s Encrypt setup for everyone, no matter what their hosting plan. Yesterday it arrived; It really is one-Click! Ok, two clicks, one checkbox, one select. Four things you have to do in DreamHost panel for what used to cost tens to hundreds of dollars/euros a year and hours of pain if you didn’t want to pay.

Awesome. Best thing that’s happened to the internet since ages.

Anyway, this isn’t about all that, it’s about “I have a WordPress site and how do I make the green padlock appear?” Cos that’s a couple more steps. Call it 15 minutes if you’re paying attention; an hour if you’re drinking.

So, you’ve already added the certificate in DreamHost Panel. No? To the DreamHost Wiki! Done that, wait for the confirmation email (might take a couple of hours), and on to your webserver.

I start with getting wp-admin all https-ified. Open your site in whatever FTP client you’re using, open wp-config.php and add:

define( 'FORCE_SSL_ADMIN', true );

Re-login to wp-admin, and check for the padlock in the address bar. Open Web Inspector (command-alt-i), select the Console tag and check for Mixed Content errors. Unless you’re doing weird things in wp-admin, that’s that side of things sorted.

In your site root directory, you’ll see a directory called “.well-known”. That’s added by Let’s Encrypt. Probably don’t want to delete that.

Open your root .htaccess and add two chunks of code:

# force redirect http to https
# ---------------------------------------------------------------

<IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteCond %{HTTPS} off
 RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>

# https security headers
# http strict transport security (hsts)
# X-Xss-Protection
# X-Frame-Options
# X-Content-Type-Options
# ---------------------------------------------------------------

<IfModule mod_headers.c>
 Header always set Strict-Transport-Security "max-age=16070400; includeSubDomains"
 Header always set X-Xss-Protection "1; mode=block"
 Header always set X-Frame-Options "SAMEORIGIN"
 Header always set X-Content-Type-Options "nosniff"
 #Header always set Content-Security-Policy "default-src https://website.tld:443;"
</IfModule>

The first force redirects any requests for http to https. The second does some fairly obtuse header security stuff. You can read about that on securityheaders.io. (The Content Security Policy stuff takes a lot of back-and-forth to not cause chaos. Even wp-admin requires specific rules as it uses Google Fonts. Expect to lose at least an hour on that if you decide to set that up.)

Other ways of doing this are possible. It’s kinda unclear what’s canonical and what’s depricated, but WordPress Codex and elsewhere have variations on these (definite rabbithole, this stuff):

SSLOptions +StrictRequire
SSLRequireSSL
SSLRequire %{HTTP_HOST} eq "yourwebsite.tld"
ErrorDocument 403 https://yourwebsite.tld

<IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteCond %{HTTPS} off
 RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

 RewriteBase /
 RewriteRule ^index\.php$ - [L]
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteRule . /index.php [L]
</IfModule>

Then go through the remainder of your .htaccess and change any specific instances of your old http://yourwebsite.tld to https://yourwebsite.tld.

Open robots.txt and do the same, http changed to https.

Now’s a good time to empty your cache and check your live site to see how it’s going. Everytime I’ve done this so far it’s been all green padlock and magic S. But there’s still a couple of things to do.

Off to your Theme directory, open functions.php, and add these chunks of code:

/* content over ssl
------------------------------------------------------ */
 
function themename_ssl_content( $content ) {
 if ( is_ssl() )
 $content = str_ireplace( 'http://' . $_SERVER[ 'SERVER_NAME' ], 'https://' . $_SERVER[ 'SERVER_NAME' ], $content );
 return $content;
}

add_filter( 'the_content', 'themename_ssl_content' );

/* advanced custom fields over ssl
------------------------------------------------------ */

add_filter( 'wp_get_attachment_url', 'set_url_scheme' );

The first one makes sure your old http links in Posts and Pages are spat out as https. (Can probably extend that for excerpts and other things if you’re that way inclined.) The second was for me specifically dealing with Advanced Custom Fields plugin, and is part of a larger issue that’s been bashed around on Make WordPress Core. There’s a few other bits of code floating around for issues like this and the Media Library not behaving properly over https, but the next step I think deals with that, if you want to go that far.

Before that though, go through your theme for irksome hardcoded http strings. If you really can’t use proper WordPress functions (like get_template_directory_uri() or whatever), then change them to https.

Addendum:

Turns out WordPress’ responsive images support using src-set needs its own attention:

/* responsive images src-set
------------------------------------------------------ */

function ssl_srcset( $sources ) {
 foreach ( $sources as &$source ) {
 $source['url'] = set_url_scheme( $source['url'], 'https' );
 }

 return $sources;
}

add_filter( 'wp_calculate_image_srcset', 'ssl_srcset' );

If you fully commit to the next step though, these functions aren’t required.

(End of addendum.)

Database funtime! Backup your database, it’s time to search and replace. I’ve been using interconnect/it’s brilliant Search Replace DB for ages when I need to shift localhost websites to remote. Dump it in your WordPress folder, open it in a browser, and search-replace http://yourwebsite.tld to https://yourwebsite.tld. I do a dry run first, just to get an idea of what’s going to be changed. This step isn’t really necessary, and if you end up going back to http (dunno why), you’d need to reverse this process; it’s probably just that I like everything to be all orderly.

Another browser to make sure crap hasn’t fallen everywhere, and it’s cleanup time.

In wp-admin, check all the settings are showing https where they should (can even resave Permalinks if clicking buttons feels good). If you’re using a plugin like Yoast SEO, then checking the sitemaps are correct is good.

Caching plugins also need to be checked, and caches emptied. If you’re using W3 Total Cache and are manually minifying, check the file urls are all https, for some reason this was’t changed even with the database search replace. Also under Page Cache check “Cache SSL (https) requests”.

Then it’s checking in a couple of browsers with and without caching, particularly any pages that use plugins which embed or iframe content, or otherwise interact with stuff outside your website. Most sites like Vimeo, Twitter, YouTube etc that WordPress provides embeds for are already over https, but that doesn’t mean code in a plugin is up to date.

If you’re using Google Analytics or Webmasters or similar, you’ll need to set things up there for the new https version of your site as well.

Buncha caveats: Do some of this wrong and you will break things. At least backup your database before doing this. Some/all of this might be depreciated/incorrect/incomplete/not the best way to do it. Finding definitive, single ways to do things isn’t really how code works, so try and understand what the code does so you can ask if it’s doing what you want. For me to be able to do this in 15 minutes is because I’ve spent years scruffing around in stuff and breaking things horribly, and the best I can say is, this seems to work and cover the most common issues.

DreamHost. Let’s Encrypt. Excellent!

(I swear this is much quicker than it took to read.)

Redirection

Last week I set another website loose (Voices of Transition, for the documentary filmmaker, Nils Aguilar), which in part was being shunted off another domain, with some very messed up urls requiring quite a stack of redirection. I started using a plugin to deal with this, which  then made me think about supernaut, and all its incarnations and thousands of posts, tags, hundreds of categories, tens of thousands of images, and what kind of mess almost ten years of blogging would leave.

Out of curiosity then, I installed the same plugin (in-between watching Person of Interest – which is another story) and turns out there are over 1000 404 Page not Found per day. A lot of these (around 3/4) are from Google’s Image Search trying to go directly from their site to the full-size image itself, bypassing the post the image lives in, which the server treats as hotlinking (due to the absence of a referrer) because of my anti-leeching rules. I’d love to be able to simply redirect those attempts to view the image to the actual post, but … prior to 2011 supernaut is a mess. Most of the remaining quarter are either weird errors trying to access images for the image viewer I need to deal with or spam searches looking for things that don’t exist (on the basis of “If image ‘n’ exists at path ‘p’, then ‘y’ is installed (plugin, theme, software, etc) that allows for hack ‘x’ to be tried). Which leaves real errors.

Which comprise wreckage from the days long ago when I used Movable Type instead of WordPress. Back in those days, all my images were in a folder called /images/ with subdirectories like 09dec for December, 2009. WordPress on the other hand has everything in /uploads/ with a year/month/ sub-directory structure, which I long ago imported all the images into (and which I am still very slowly dealing with). It also had a different url structure for posts, like post_name_truncated_somethi.html. Both of these are buried in search engine results, the former to quite a huge degree (about 5% of traffic is looking for those old images).

So I wrote (and am writing) a bunch of redirects – and a lot of regex. I could do this directly in .htaccess, but not knowing which urls are the problem, and having all of this logged by the plugin are both good reasons to do it directly in WordPress. It’s a bit messy and sometimes redirects for spam conflicted with genuine pages (like sub-pages of monthly archives), but probably useful for a while if people looking for something actually stand a good chance of finding it instead of “absence…”

https:// + supernaut (& WordPress)

Every month, I get a newsletter from my webhost, DreamHost. And I read it! That’s how I found out that supernaut could be SSL, have https:// in its URL and have that fancy lock in the address bar. Up there, ^.

Why would I want to do something like that? Well, because I can. Because it’s useful for a lot of reasons, especially now. Since the Snowdon NSA whistleblowing, which gets worse and more damning with each document release, it became obvious to me I should take the implementation of privacy and security as seriously as I do reading about it. Recently this has meant beginning the move off Google, which I use for so much; installing PiWik instead of using Google’s Analytics, installing GPGTools for email encryption (and badgering my friends to do the same); and obviously, if easy website encryption was possible, I’d give it a spin.

The first things I tried it out on have been my private server (running Pydio, formerly AjaXplorer) – my self-running DropBox, and for PiWik, then on a couple of small, low-traffic sites, to test how SSL would play with my standard-ish WordPress setup, which led to some rewriting of htaccess rules, and quick/easy code cleanup. So then I thought to try it on supernaut, which gets enough traffic and is complex enough to really show the horror.

WordPress make it reasonably simple – provided you have STFP/shell access – to make the switch. First the admin and login side of things can be SSL’d simply by adding:

define('FORCE_SSL_ADMIN', true);

to wp-config. Then in the Admin General Settings changing WordPress Address and Site Address to https. Then in the root .htaccess, editing the WordPress with two additional lines:

RewriteEngine On
RewriteCond %{SERVER_PORT} !^443$
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

This did the majority of the change; the remainder turned out to be annoying. Images in the content seemed very reluctant to make the jump. This is partly because they are effectively hardcoded via the process of inserting the using the Media Library. I tried several methods with varying degrees of success, and finally adding this to functions.php seemed to do the job, updated a bit to use WordPress’ inbuilt is_ssl() function, which is a wrapper for both isset($_SERVER[“HTTPS”]) and a check for server port 443, and uses str_ireplace() instead of the depreciated ereg_replace:

function supernaut_ssl_content($content) {
if ( is_ssl() )
$content = str_ireplace('http://' . $_SERVER['SERVER_NAME'], 'https://' . $_SERVER['SERVER_NAME'], $content);
return $content;
}
add_filter('the_content', 'supernaut_ssl_content');

Which just left data in custom fields, which I use primarily for video. These look like they are best edited by hand in supernaut, though it’s possible I could use the WordPress HTTPS (SSL) plugin … I’d rather bash around in the code so I understand what’s going on. (edit) well obviously I can just wrap any code in the template with the above function, and just replace $content with $variable that pulls the post meta, no? (edit 2) And also for situations where I’m using Advanced Custom Fields (sadly not here), adding this to functions.php takes care of the rest:

add_filter( 'wp_get_attachment_url', 'set_url_scheme' );

This just leaves changing the WordPress Address and Site URLs in General Settings to https://, and that’s it (I think).

The last thing then is my own certificate. While Chrome is reasonably calm about the fact my SSL is an unsigned certificate (i.e. I haven’t spent up to $1500 on one from a trusted vendor), and Safari drops down a fairly innocuous warning – which admittedly is enough to make most people anxious, FireFox turns on all the alarms and does a mad freakout that’s impossible to simply bypass. Horrible, no? I figured that $15 a year for a secure certificate was probably worth it, for the experiment alone.

supernaut on SSL then! Most Excellent!

And for those reading for whom this was all WTFBBQ?, here’s what DreamHost said:

SNI – SSL Without a Unique IP!

“Server Name Indication,” or SNI, is a biiiig deal in the world of web hosting.

Every site on the web is tied to a specific IP (v4) address, but a single address can be shared across several different domains. In fact that’s one feature that’s helped to keep the Internet from bursting apart at the seems up ’till now.

IPv4 addresses are the Brettcoins of the shared hosting world in that they are both EXTREMELY valuable and that there are only a finite number of them gifted to humanity by the Gods.

While IPs can be shared among websites, they cannot be shared among SSL-enabled (secure) websites. If you want to handle secure web transactions on your own without the use of a specialized third party payment platform you’ll need to lease (and pay for,) a unique IP address for your own personal use.

Or at least…that’s how things USED to work.

SNI extends the protocols used to process secure web transactions to allow for the usage of a single IP address across several different SECURE websites. And, as of not too long ago, we support it!

You can still obtain a unique IP address and tie your secure hosting to it if you’d prefer – but it’ll cost ya ($3.95/month.)

To add or modify the secure hosting settings on any of your domains, visit the “Domains/Secure Hosting” section of your control panel, and click to “Add” or “Edit” services on your domains.

https://panel.dreamhost.com/index.cgi?tree=domain.secure

For a little background on setting up secure hosting in general, including some caveats of SNI, check out our wiki!

http://wiki.dreamhost.com/Secure_Hosting

referrer hell

Being quite committed to wasting time, I like to read my referrer logs. Actually, I’ve found some pretty cool websites through that, and it’s kinda nice to see that people and not robots/spiders/scripts are reading me, and occasionally even say something about me. I don’t enjoy however, endless scrolling like Obi-Wan reading the blinding screeds of data on the Death Star that comprises most of my referrer log. Anyone who hangs around their own stats pages will be familiar with all the referrer spammers, so I won’t mention them by name.

My other pet hate is people who think it’s acceptable to link to an image here. I do make a point of using images that are of reasonable web quality, and usually around 600px square and 60-100kb, the kind of size that gets bumped into Google’s ‘medium’ or ‘large’ image sizes, perfect for dragging to my scrapbook, emailing to Emile or Paul, and also perfect for hotlinking. Something that happens when sub-normal intellects trawl Google’s image search, and copy-pastes the image link into their own mediocre presence on the internet. Kinda like someone coming into your house, drinking all your coffee, and in a diuretic spasm, pissing on the carpet on the way out.

So having a spare evening this morning once I got home, drunk, happy, well-fed from an evening of superlative company, I decided to make a mess of my blog by doing nasty things to my .htaccess file. The result of this is that you might not be able this, you might not see any images, nothing has changed, or in the unlikely event that it worked, everything is peachy for you, and referrer spammers and hotlinkers (of whom impulsos are currently the worst offender) are not having a good day. Knowing my coding skills, it’s probably one of the first two.