Gotchas with HTTP and HTTPS

I recently installed a WordPress Network to provide blogs (and simple websites) for SANBI (the bioinformatics SANBI, not the biodiversity SANBI), with authentication provided by nginx’s auth_pam module (and thus linked to our site-wide authentication, so we don’t need to maintain separate WordPress users and passwords). The login page for WordPress is protected with SSL, but I was serving the rest of the site using plain HTTP. This led to a strange bug – when I wanted to edit a post, the editor was a very narrow column.

Like this, with all
the text cramped
together.

What the heck? I tried changing WordPress settings, but as someone said out there on the net “Before you waste hours switching off / on plugins, check the javascript debugger in your browser!”. Turns out that Chrome was blocking content because the combination of HTTP and HTTPS meant I had created a “mixed content” site, and modern browsers (including Chrome) frown on such behaviour. Melissa Koenig has a little blog post on mixed content for the curious. After much googling, I found a blog post by Ken Chen detailing how to set this up right: in the SSL config (but not in the main HTTP config) you serve the main WordPress content using HTTPS, ensuring that “mixed content” is avoided.

So here’s the nginx config file:


upstream php {
server unix:/var/run/php5-fpm.sock;
}

server {
listen 443;
ssl on;
server_name .wp.sanbi.ac.za *.wp.sanbi.ac.za blog.sanbi.ac.za *.blog.sanbi.ac.za;

ssl_certificate /etc/ssl/certs/sanbi.pem;
ssl_certificate_key /etc/ssl/private/sanbi.key;

root /usr/lib/wordpress;
index index.php index.html index.htm;

# Process only the requests to wp-login and wp-admin
location ~ /wp-(admin|login|includes|content) {
auth_pam "SANBI authentication";
auth_pam_service_name "nginx";
try_files $uri $uri/ \1/index.php?args;

location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php;
fastcgi_intercept_errors on;
}
}
# Redirect everything else to port 80
location / {
return 301 http://$host$request_uri;
}
}

server {
#listen 80; ## listen for ipv4; this line is default and implied
#listen [::]:80 default ipv6only=on; ## listen for ipv6

server_name wp.sanbi.ac.za *.wp.sanbi.ac.za blog.sanbi.ac.za *.blog.sanbi.ac.za;
root /usr/lib/wordpress;

index index.php;

location ~ /wp-(?:admin|login) {
return 301 https://$host$request_uri;
}

location = /favicon.ico {
log_not_found off;
access_log off;
}

location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}

location / {
# This is cool because no php is touched for static content.
# include the "?$args" part so non-default permalinks doesn't break when using query string
try_files $uri $uri/ /index.php?$args;
}

location ~ \.php$ {
#NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
location ~ /wp-(admin|login) {
return 301 https://$host$request_uri;
}
try_files $uri =404;
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_pass php;
}

location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off; log_not_found off; expires max;
}

location ~ /\. { deny all; access_log off; log_not_found off; }
}

 

Note that this uses a Unix socket for php5-fpm. I’ve found that I don’t need to use WordPress FORCE_SSL_ADMIN (or the WordPress SSL plugin) and since I had some issues with the SSL plugin (it created an invalid default SSL link for newly created network sites), I left out that bit of the config.Oh by the way I use the HTTP authentication plugin to provide an authentication dialog to users. And you can read this guide on the basics of a WordPress network setup on nginx. A quick note: when you add a new site to the network, make sure to go into the dashboard of the new site and enable the automatically create new users setting in the HTTP authentication settings, at least until the new site’s owner has created an account for themselves (by logging in).

Finally, the nginx auth_pam module is compiled into the nginx I installed on ubuntu (from the nginx-full package). I created a file /etc/pam.d/nginx that directed authentication to both our Kerberos setup and the Unix accounts on the local server (so that I could create ad-hoc users, e.g. for the default WordPress admin user):


auth [success=2 default=ignore] pam_krb5.so minimum_uid=1000 ignore_k5login
auth [success=1 default=ignore] pam_unix.so use_first_pass
auth requisite pam_deny.so
auth required pam_permit.so