Site icon Mostly Harmless

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?

Exit mobile version