Before ‘the great harddrive fire of 2011’ we had FastCGI running on the server for some small projects. With everything else using Apache it was rather refreshing to see that there were faster, more lightweight alternatives.
Starting from a fresh slate, we’ve waved off the slow and clunky httpd for Nginx but in exchange for the shiner newer model there’s a bit of a learning curb in how the new kid does things. In addition, an upgrade in blog/CMS was in consideration – now things were running faster perhaps there was some forgiveness in using PHP and WordPress. My starting point was aged a little, so this post documents my time with installing and securing WordPress 3.2.1.
Step 1: Installing the dependencies
With Nginx and FastCGI installed, the necessities of WordPress dictate the required installs:
- MySQL
- A requirement for the base install. Easier to avoid complications with alternate databases (and these days it’s improved in performance)
- PHP 5
- For the latest (and probably most secure) versions of WordPress
- MySQL module for PHP 5
- You need to talk to the the database somehow..
- FastCGI PHP init.d script
- A great example is here
- GD module for PHP 5
- Generate multiple sizes of your assets (like thumbnails), save yourself the trouble and install it right away. For Debian/ubuntu:
apt-get install php5-gd
, which automatically replaceslibgd2-noxpm
withlibgd2-xpm
Step 2: Securing your site.conf
Coming from a .htaccess perspective, there is a little work to the Nginx configuration. There are plenty of examples, but only recently I have come across a great article in creating a better config file.
It has been stressed that ‘if’s are evil but when used optimally it can produce a more secure environment for WordPress to run. In particular, the uploads
directory is prone to executing rogue PHP files..
location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; include /etc/nginx/fastcgi_params; if ($uri !~ "^/path-to-wordpress/wp-content/uploads/") { fastcgi_pass 127.0.0.1:9000; } fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_intercept_errors on; }
This snippet in your config means that any .php
files are executed normally by PHP unless they are found in the WordPress uploads directory. Note that the above fastcgi_pass may differ if you are running PHP on a different port or if you are using a Unix domain socket.
Step 3: A 5 minute install with caution
There is an excellent set of guidelines in securing your install. Some fairly basic rules you can easily follow are:
- Avoid having an administrator with user name admin
- Set a non-default prefix for your WordPress tables
- Ensure your passwords aren’t too short
- If you can, obscure
wp-admin
with basic authentication
Installing in a sub-directory from root htdocs
I like to keep a website that isn’t completely run by WordPress. I also prefer an uncluttered htdocs
, so I’ve kept my WordPress install in a sub-directory. However, with the instructions on integrating WordPress with your website failing to work with my setup as it kept causing 404 errors, I had to seek alternate methods.
If you still want the look and feel of your blog at root level without the clutter, just place a index.php
file in your root htdocs with:
1 2 3 4 5 6 7 8 | <?php require_once('/PATH/TO/WORDPRESS/wp-load.php'); $themebase = get_theme_root().'/'.get_stylesheet(); query_posts(null); require_once($themebase.'/index.php'); ?> |
This generates the index page of your WordPress install regardless of the subdirectory location.
If you want a slightly customized index, then you will need to deal with ‘The Loop’. I have used the structure of this to generate ‘splash pages’ that contain snippets of the last few stories.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php define('WP_USE_THEMES', false); require_once('/PATH/TO/WORDPRESS/wp-load.php'); // Do header stuff here before posts.. can use get_header() to use the current theme header // Start of 'The Loop' // For this example, the top 10 entries are obtained $posts = get_posts('numberposts=10'); foreach ($posts as $post) : start_wp(); ?> // Do stuff with the individual posts here.. customize as needed <?php the_date(); echo "<br />"; ?> <?php the_title(); ?> <?php the_excerpt(); ?> <?php endforeach; // End of 'The Loop' // Do footer stuff here after posts.. can use get_footer() to use the current theme footer ?> |
Creating a unified look and feel for external pages
Notice the require
pattern? If you wish to produce a unified look and feel by reusing the current theme’s header and footer, you can use the following (for most current themes that have separated their header/footer). A common use for such things are custom error pages.
1 2 3 4 5 6 7 8 9 10 11 | <?php define('WP_USE_THEMES', false); require_once('/PATH/TO/WORDPRESS/wp-load.php'); get_header(); // Do your custom content here get_sidebar(); get_footer(); ?> |