Firefox and TLS

Firefox is weird. In a forum conversation (which went so off topic but that’s alright) the following was reported to me. When you visited my site in Firefox, you get a warning about being insecure.

Huh. That’s odd and a little embarrassing. I mean, I’m a network security professional so you can see how that would be awkward. 😉

So I looked at my site on the Qualys SSL Labs page and got this result.

Screen Shot 2016-08-07 at 9.35.58 AM

Which is good but Firefox still didn’t like my site.

A few weeks ago I was playing with my nginx config and something I did made Firefox unhappy. I’m pretty sure I munged the cypher suite in my poking and prodding.

Fair enough, I used the configs from a site that does work in that browser and tonight I’ll play around to see what I broke. In the meanwhile my site is encrypted and viewable in Firefox.

I Am NGINX! (And So Can You!)

A few months ago I switched my Apache2 installation for this blog from mod_php to php5-fpm. Using Ubuntu LTS this was as simple as running apt-get remove libapache2-mod-php5 ; apt-get install php5-fpm and adding /etc/apache2/conf-available/php5-fpm.conf with just a few lines.

I activated that config and it worked! Mostly. There was some more than that but it wasn’t hard. I did this because I wanted to play with mod_pagespeed and I needed php5-fpm to do that.

It didn’t exactly work as well as I’d have liked.

My Apache2 installation had become temperamental.

I couldn’t get the number of workers right and there was some sort of condition that was causing php5-fpm to break and generate 500 errors. The logs didn’t tell me what was going on and the problem was outside of WordPress. Restarting Apache2 every couple of days worked but that just sucked.

I like server based solutions that just work. This one was effecting all 7 sites in my network including Lily’s store.

This was a great time to switch to nginx!

I could not get my multisite /files/ and blogs.dir working on nginx. It just wasn’t doing what I thought it should and I think it was because of my 7+ years of carried database options and junk.

When I tried fix it I found many other things broken on my installation. So I ended up creating a brand new multisite installation, imported via XML all of the sites (I only had 7 so that wasn’t too bad) and after it all worked I globally searched and replaced all the references of the new sites with the old.

That took me almost a week. I worked on it after hours, November is a busy month at work. I did get Lily’s site working first so there’s that. I may write a post about that exercise. The search and replace worked well and so did the DNS part.

Here’s my Apache2 .htaccess bits and the nginx conf replacements. All of the nginx bits are in one file.

Redirecting an old URL to a new  one

Years ago my installation URL was different and I used a ReWriteRule to send visitors to the right place.

RewriteEngine on
RewriteCond %{HTTP_HOST} wp\.dembowski\.net [NC]
RewriteRule (.*) https://blog.dembowski.net/$1 [R=301,L]

This is long gone but incase you need it, here you go for the nginx equivalent.

server {
        listen 80;
        server_name wp.dembowski.net;
        return 301 https://blog.dembowski.net$request_uri;
}

Send all URLs to the SSL version (with exceptions)

I want WordPress to be SSL based but I am comfortable with my RSS feed being available via plain http.

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} blog\.dembowski\.net [NC]
RewriteCond %{SERVER_PORT} 80
RewriteCond %{REQUEST_URI} !^/feed/$
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteCond %{QUERY_STRING} !^feed=rss2$
RewriteRule ^(.*)$ https://blog.dembowski.net/$1 [R=301,L]
</IfModule>

On nginx that works out to these lines in my server section for plain http.

location /feed/ {
        try_files $uri $uri/ /index.php?q=$uri&$args;
}

location / {
        return 301 https://$http_host$request_uri;
}

Everything get’s handled by the “location /” part and exceptions like “/feed/” go above those lines. If I had any other exceptions then they would go between the two.

SSL all and SPDY

In my server section for the SSL based version, I have these lines.

listen 443 ssl spdy;

The nginx package I’m using is compiled to include SPDY 3.1 support. I haven’t put back PageSpeed but SPDY is fun to play with.

With Apache2 I used mod_ substitute change my http references to https in the HTML output. With nginx I use the HttpSubsModule.

subs_filter_types text/css text/xml;
#
# http host substitution for https versions
#
subs_filter 'href=\'http://$http_host/' 'href=\'https://$http_host/';
subs_filter 'href=\"http://$http_host/' 'href=\"https://$http_host/';
subs_filter href='https://fonts.googleapis.com href='https://fonts.googleapis.com;
#
# make http into protocol-relative URLs
#
subs_filter src=' src=';
subs_filter src="http: src=";

The Google Fonts was put in because one of my sites use it and the SSL page broke until I put that there. And I don’t yet have Jetpack’s infinite scroll working quite right. Meh.

While I’m at it, you should always set HTTP Strict Transport Security to tell web browsers not to downgrade from HTTPS to HTTP.

In Apache2 that’s this line.

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

In nginx in your server section add this line.

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

Redirecting client IPs

Sometimes I just don’t want some people to visit my site and 301 them to a YouTube video. IP blocking is a temporary solution but in Apache it’s easy.

RewriteCond %{REMOTE_HOST} 192.168.111.75 [OR]
RewriteCond %{REMOTE_HOST} 10.22.33.230 [OR]
RewriteCond %{REMOTE_HOST} 172.16.11.132
RewriteRule .* https://www.youtube.com/watch?v=NN75im_us4k [R=301,L]

Easy to accomplish with nginx with these lines. The 403 isn’t the same code but the results are the same.

location / {
        include /var/www/vhosts/block_ip.txt;
        try_files $uri $uri/ /index.php?q=$uri&$args;
}

The block_ip.txt file contains these lines.

# Deny these IPs
error_page 403 https://www.youtube.com/watch?v=NN75im_us4k;
deny 192.168.111.75;
deny 10.22.33.230;
deny 172.16.11.132;
allow all;

So no .htaccess live changes?

With Apache2 when you make a .htaccess file change it is live immediately. Each http request that hits the server parses the content of that (and other) files.

That’s not true with nginx and any configuration changes need a “service nginx reload” as root or via sudo. I don’t make frequent configuration changes so that’s not a problem for me.

What’s with the Stephen Colbert thing?

I like Stephen Colbert. You don’t get the reference for the blog post title do you?

StartSSL and Nginx

I converted this blog from Apache2 to Nginx but forgot a step for SSL. With Apache2 to correctly install the SSL cert, you need to include in your config ca.pem and sub.class1.server.ca.pem. See here for more information.

I didn’t realize I had a problem until I pointed my iPhone at my SSL enabled web site.

With Nginx you’ve got

 ssl  on;
 ssl_certificate  /etc/nginx/ssl/blog.crt;
 ssl_certificate_key  /etc/nginx/ssl/blog.key;

Nginx doesn’t do SSL certificate chaining like Apache2 does. In order to get the ca.pem and sub.class1.server.ca.pem onto your install just append the two files to your certificate file.

curl http://www.startssl.com/certs/sub.class1.server.ca.pem >>blog.crt
curl http://www.startssl.com/certs/ca.pem >>blog.crt

I restarted my Nginx server and had no problems since. I continue to be impressed with StartSSL and at some point I will want to purchase a wild card cert for my domain.

So far so good with Nginx

This blog is running on a VPS provided by Slicehost. It’s the 512MB package and I have no complaints. The network connectivity is pretty good too.

512MB is not what it used to be. When I run out of ram, mysql and Apache2 both go insane. My VPS becomes unusable and I end up hitting the remote hard reboot button. There is even a Slicehost iPhone app for that (which I have installed).

I can upgrade to 1GB of RAM but I’d prefer to create a smaller memory footprint. I am constantly floating between 1MB and 90MB free and adding a whole 512MB seems like overkill. Switching to Nginx is my attempt to take care of that. And besides, they have a really cool logo.

Installing it was a breeze. Go over to Donncha O Caoimh’s blog and read up on how to get WordPress, Nginx, and WP Super Cache working. I used his notes but made some changes to my installation. The only thing I did was disable the /etc/nginx/sites-available/default and created virtual server specific files. Also I don’t use WP Super Cache, I just don’t have the traffic. I started with a copy of the default file and added a few lines.

For example, blog.dembowski.net’s file looks like this:

server {
        listen   80;
        server_name  blog.dembowski.net;

        access_log  /var/log/nginx/blog.dembowski.net-access.log;

        # Hot-linking bad, expect when I let it.
        location ~* (.jpg|.png)$ {
                root   /srv/www/vhosts/$server_name;
                valid_referers server_names blocked none
                        *.dembowski.net
                        *.google.com
                        *.feedburner.com
                        *.pingdom.com;

                if ($invalid_referer) {
                        return 403;
                }
        }

        location / {
                root   /srv/www/vhosts/$server_name;
                index  index.php index.html index.htm;

        # if the requested file exists, return it immediately
               if (-f $request_filename) {
                       break;
               }
        # all other requests go to WordPress
               if (!-e $request_filename) {
                       rewrite . /index.php last;
               }

        }

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
                root   /var/www/nginx-default;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ .php$ {
                fastcgi_pass   127.0.0.1:9000;
                fastcgi_index  index.php;
                fastcgi_param  SCRIPT_FILENAME  /srv/www/vhosts/$server_name$fastcgi_script_name;
                include fastcgi_params;
        }

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        location ~ /.ht {
                deny  all;
        }
}

I am lazy efficient enough that all I need to do is replace the server_name and access_log lines for each virtual web host. I tried to use $server_name in the access_log line too, but it didn’t take. That created a file name called $server_name-access.log.

Each of my virtual hosts were already setup in Apache2 this way. All I had to do was get php5-cgi working, shutdown Apache2 and bring up Nginx. I made it permament by running these commands as root:

# update-rc -f apache2 remove
# update-rc -f nginx defaults

This hasn’t really made a big difference in my memory footprint but my blog is more responsive. See this Pingdom report for performance numbers. I may yet upgrade to the next size slice.