Every now and then, I work on a site that absolutely must be secured 100% with SSL. This means the styles, scripts, images, and markup are all served over an https connection to prevent nefarious individuals from sitting in the middle and substituting their own versions (thus compromising the overall security of the site).
One of these such sites has been using Jetpack’s Photon service to offload image assets to WordPress.com’s powerful CDN. Up to a few days ago, this worked like a charm. Then, on New Year’s Eve, I got a report that things weren’t working any longer.[ref]Update: Since this post was written, the Photon team has fixed things on the server to allow images to be served via HTTPS once again. So while the suggestions below no longer apply to Photon directly, they’re still useful for other image compression/CDN services.[/ref]
How Things Used to Work
Originally, I configured the site to use standard HTTP for everything. This was fine during our beta period, but once we added purchasing I wanted to secure the payment pages. The site uses Stripe.JS to make sure no credit card data hits our server, but delivering that single HTTPS script on a non-HTTPS page isn’t really secure. Instead, I made the entire payment page require SSL.
As the product evolved, we began adding a persistent customer login indicator throughout the site. This little header widget eventually added a cart as well, allowing the customer to conceivably check out from anywhere. The day we allowed customers to purchase from anywhere was also the day I locked the entire site down with SSL. Every page, every asset, everything is now delivered over HTTPS.
Finally, we integrated Jetpack and Photon to deliver image assets from a CDN (rather than creating a bottleneck with our own, smaller server). Jetpack even detects that the site is secured and delivers resized/resampled images over HTTP as well. For a few weeks, things worked perfectly!
What Went Wrong
For new customers, images started disappearing on the website. A few would still be accessible (if the visitor had cached any of the images by visiting one of our other properties in the past, things would load just fine). For the most part, though, any image being served from Photon’s CDN was returning a 502 server error.
I dug around a bit more and found this error message was being returned by Photon:
We cannot complete this request, remote data could not be fetched
I searched a bit and found some chatter on the WordPress.org support forums about this same issue. As I suspected, HTTPS was at fault. Though the conversation on the forum seemed to indicate I had done things correctly – any request for an HTTP asset would be automatically redirected to its HTTPS counterpart.
According to a friend of mine in the know, this system I had working before … likely shouldn’t have worked in the first place:
@EricMann We will serve images over HTTPS, but we only fetch over HTTP. That's always been the case.
— Erick Hitter (@ethitter) December 31, 2013
Apparently I had been making use of a bug in the platform that has been fixed. Here’s hoping Photon is able to add images-over-SSL to its repertoire of features in 2014.
How I Fixed It
I am not about to open an already-secure site to regular HTTP traffic. Instead, I wanted to open just specific files – images – in a specific directory and continue to redirect everything else to the HTTPS version of the resource.
Our server is running Nginx, so this just required a minor tweak of the server configuration file. Where before I had:
server {
listen 80;
server_name example.com www.example.com;
return 307 https://example.com/$request_uri;
root /home/s1/html;
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;
}
I now have:
server {
listen 80;
server_name example.com www.example.com;
root /home/s1/html;
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;
location ~ ^/wp-content/(.*)\.(svg|svgs|jpg|jpeg|gif|png|bmp)$ {
access_log off;
log_not_found off;
expires max;
}
location / {
return 307 https://example.com/$request_uri;
}
}
As a result, any image requests from the [cci]/wp-content[/cci] directory (plugins, uploads, themes) will be served over both HTTP and HTTPS. All other requests will be rewritten to HTTPS automatically, keeping the site secure but allowing Photon to fetch our images and serve them from a (still-HTTPS) remote CDN.