We've got a Web server. We've got SSL/TLS. We've got PHP. We've got a database. Now, finally, it's time to do something with them: we're going to set up self-hosted WordPress, one of the Internet's most popular blogging platforms.

Certainly, WordPress isn't the only choice. There are many blogging platforms out there, ranging from big and full-featured content management systems (like WordPress, Drupal, or Joomla) to static site generators like Jekyll (and its customized variant Octopress, which I use on my own blog). However, WordPress is extremely popular, and it also has a wealth of themes and plugins available with which you can customize its behavior. So, because it's the platform that first comes to mind when people think of "blogging," we're going for it.

Disclosure, and a word on security

This isn't the first time I've talked about setting up WordPress. Some parts of this article will be taken from my previous blog post on the subject, though the instructions here will contain a number of improvements.

We also need to talk about security. WordPress gets kind of a bad rap about being absolutely riddled with security holes. That's not entirely fair—vulnerabilities in the base platform are rarely the cause of WordPress blog compromises. Rather, WordPress's huge library of add-ons is both its greatest asset and also its greatest weakness: security issues in WordPress are more often due to a hole in a plugin than a hole in WordPress itself.

What can we do to help keep things secure? I've said it before in this guide and I'll continue to say it: no system is completely secure, but there are things that can be done to mitigate risk. The first, and most obvious, is to minimize the plugins you use with WordPress. Use what you need and no more. Next, keep your WordPress installation and your installed plugins up to date. Finally, lean on your Nginx configuration to guard against common attack vectors. This last point is one we'll focus heavily on.

A note on root shells I use sudo /bin/bash in this piece and in others to launch a shell with root privilege, but there are other, more "correct" ways to do it, including sudo -i . sudo -i launches a root shell without carrying with it any of the current user's environment variables and configuration choices, whereas sudo /bin/bash simply launches a new instance of bash with root privilege. I usein this piece and in others to launch a shell with root privilege, but there are other, more "correct" ways to do it, including This page gives a fair overview of the differences, but the short version is thatlaunches a root shell without carrying with it any of the current user's environment variables and configuration choices, whereassimply launches a new instance ofwith root privilege. I prefer the latter, precisely because it brings my aliases and prompt and other things with me. However, there are strong arguments to be made for using sudo -i instead, not the least of which is that it's a "best practice" kind of thing. In this guide, we're going to use sudo /bin/bash , but you're free to use whichever lifts your luggage.

Predownload configuration choices

One important choice needs to be made before we download anything: do you want to serve WordPress off of its own virtual host, or out of a subdirectory on your current virtual host? The former would mean that your blog's URL would be something like http://blog.yourdomain.com , whereas the latter would mean the URL would be http://www.yourdomain.com/blog (or just http://yourdomain.com/blog , depending on how you've configured Nginx).

For this guide, we're going to go with the second choice and serve WordPress out of a subdirectory. It's a little easier to set things up this way with the configuration choices we've made with Nginx so far. Serving WordPress out of its own virtual host is also quite doable, but it would require us to set up a second virtual host file. For the sake of brevity, we're going to skip that and just serve it out of a subdirectory on your existing virtual host.

Getting WordPress

WordPress has an excellent set of installation instructions which we're going to follow pretty closely, but it won't get us all the way there. That's OK, though, because the parts it doesn't cover (namely, Web server configuration) are parts we'll get pretty detailed on.

Download WordPress directly from its download page. The easiest way to do this is to get the zipped installation file directly from your Web server, so ssh into your server. We're going to launch a root shell so that we don't have to keep prefacing commands with sudo , and then we'll use wget to download the current WordPress package:

sudo /bin/bash cd /usr/share/nginx/html wget https://wordpress.org/latest.zip

After WordPress has been downloaded to your Web root directory, we want to decompress it using the command line. We already have the unzip utility downloaded from when we installed SQL Buddy last time, so use the same tool to uncompress it to its own directory:

unzip latest.zip

This will create a wordpress directory underneath your Web root and stuff all of WordPress's files there. Delete the downloaded zip file with rm latest.zip to keep your Web root nice and tidy.

We're also going to rename wordpress to blog . It's a bit shorter, and your site by default will have enough WordPress branding on it without also needing it in the URL. To rename the directory, use the mv (move) command:

mv /usr/share/nginx/html/wordpress /usr/share/nginx/html/blog

Lastly, since we've been doing all this as root, we need to change the ownership on the blog directory so that our Nginx user owns it instead:

chown -R www-data:www-data /usr/share/nginx/html/blog

Prepping your database

In order to actually use WordPress, we need to prepare a database for it to use. For this, we're going to use SQL Buddy, though you can use the command line if you're more comfortable with that. You can also use any other Web SQL administration utility, including the tiny and light Adminer or the powerful (but complex) phpMyAdmin.

Log into SQL Buddy as your root user (using whatever account name you renamed root to in part 4). The third section in the SQL Buddy home page is called "Create a new database," and that's where we're going to start. In the "Name" field, give your WordPress database a name (I'm using "wordpressdb"), and change the "charset" drop-down list to "utf8" and then hit "submit."

The WordPress database will be created. Next, we need to create a SQL user that only has access to the WordPress database. This will make sure that WordPress can only do things inside of its own database and can't interfere with any other databases. It also reduces the amount of potential damage an attacker could do in the event of a system compromise; if they gain access to the WordPress SQL user, they won't be able to do more than trash your WordPress database.

To create a WordPress user, click the "Users" menu item at the left of the browser window. Leave the "host" field set to "localhost," and give your user a name in the "Name" field. I'm using "wordpressdb" as the user name, so that there's a direct correlation between the user name and the name of the database to which we're going to grant the user access. Give the user a complex password. You won't be entering this password regularly, so it can be complicated.

Toggle the "Allow access to" radio button to "Selected databases," and then ensure only "wordpressdb" is checked. This constrains which databases the user can do things to. Leave the "Give user" radio button set to "all privileges," in order to ensure that WordPress has the ability to alter its own database according to its needs. Leave the "Grant option" box unchecked (this option would give the wordpressdb user the ability to grant other accounts permissions on the WordPress database, and we don't want that). Finally, click "Submit."

Listing image by Ralf Skjerning, flickr