Hosting WordPress Yourself Part 3 – Setting Up Sites

#

In Part 2 of ‘Hosting WordPress Yourself’, I showed you how to install Nginx, PHP-FPM and MariaDB, which formed the foundations of a working web server. In this post I will guide you through the process of setting up individual sites within Nginx (known as server blocks or virtual hosts) and the process of installing WordPress via WP-CLI. At the end of this post I will also demonstrate how to connect to your server using Transmit (file management) and Sequel Pro (database management) for those who prefer to install WordPress manually. Let’s get started.

In order for your server to handle website traffic, you must perform two tasks:

  1. Create a DNS record for the domain name you wish to serve traffic, which points to your server.
  2. Setup a server block so that Nginx knows how to deal with the request. By default, Nginx will drop any connections it receives, as in the previous post you created a catch-all server block. This ensures that the server only handles traffic to domain names that you explicitly define.

DNS A Record

Login to your DNS control panel and add an A record that points to your server’s IP address. You can also add a CNAME record for the www subdomain, so that anyone who visits either domain.com or www.domain.com will be directed to your server.

DNS A Record

DNS changes can take up to 72 hours to propagate, therefore visiting the domain shortly after making any changes will more than likely yield an error or lead to unexpected results. Luckily, you can spoof your DNS to instantly use the new IP address, as detailed in this WPEngine article.

Nginx Server Block

As always, you are going to want to SSH to your server:

ssh ashley@pluto.ashleyrich.com

SSH

Once logged in you should be directed to your home directory, if not, go there now:

cd ~/

For simplicity’s sake, all of the sites that you host are going to be located in your home directory and have the following structure:

Directory Structure

The logs directory is where the Nginx access and error logs are stored, and the public directory is the site’s root directory which will be publicly accessible.

Begin by creating the required directories and setting the correct permissions:

mkdir -p ashleyrich.com/logs ashleyrich.com/public
chmod -R 755 ashleyrich.com

With the directory structure in place it’s time to create the server block in Nginx. Navigate to the sites-available directory:

cd /etc/nginx/sites-available

Create a new file to hold the configuration. Naming this the same as the site’s root directory will make server management much easier when hosting a large number of sites:

sudo nano ashleyrich.com

Copy and paste the following configuration, ensuring that you change the server_name, access_log, error_log and root directives to match your domain and file paths. Hit CTRL X followed by Y to save the changes.

server {
    listen 80;
    listen [::]:80;

    server_name ashleyrich.com www.ashleyrich.com;

    access_log /home/ashley/ashleyrich.com/logs/access.log;
    error_log /home/ashley/ashleyrich.com/logs/error.log;

    root /home/ashley/ashleyrich.com/public/;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args; 
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

This is a bare-bones server block that informs Nginx to serve the ashleyrich.com domain and www subdomain. It also sets the directory that Nginx should use for the site root and where to store the server log files. The two location blocks essentially tell Nginx to pass any PHP files to PHP-FPM for interpreting.

By default Nginx won’t load this configuration file. If you take a look at the nginx.conf file you created in the previous post, you will see the following lines:

##
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

Only files within the sites-enabled directory are automatically loaded. This allows you to easily enable or disable sites by simply adding or removing a symlink.

To enable the newly created site, symlink the file that you just created into the enabled-sites directory:

sudo ln -s /etc/nginx/sites-available/ashleyrich.com /etc/nginx/sites-enabled/ashleyrich.com

In order for the changes to take effect, you must restart Nginx. However, before doing so you should check the configuration for any errors:

sudo nginx -t

If the test failed, recheck the syntax of the new configuration file. If the test passes, restart Nginx:

sudo service nginx restart

Restart Nginx

With Nginx configured to serve the new site, it’s time to create a new database for the WordPress installation.

Creating a Database

When hosting multiple sites on a single server, it’s good practice to create a separate user and database for each individual site. You should also lock down the user privileges so that the user only has access to the databases that they require. Here’s how to do just that.

Log into MariaDB with the root user. Although we’re using MariaDB the commands are exactly the same as if using MySQL, because it’s a drop in replacement. MariaDB and MySQL will be used interchangeably throughout the remainder of this post.

mysql -u root -p

You’ll be prompted to enter the password which you created when setting up MariaDB.

MySQL Command Line

Once logged in, create the new database:

CREATE DATABASE ashleyrich_com CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;

Next, create the new user using the following command, remembering to substitute the username and password for your own values:

CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';

You then need to add the required privileges. To keep things simple, you can grant all privileges but restrict them to the ashleyrich_com database only, like so:

GRANT ALL PRIVILEGES ON ashleyrich_com.* TO 'username'@'localhost';

Alternatively, you can have more granular control and explicitly define the privileges the user should have:

GRANT SELECT, INSERT, UPDATE, DELETE ON ashleyrich_com.* TO 'username'@'localhost';

Be very careful as not to overly restrict permissions. Some plugins and major WordPress updates require heightened MySQL privileges (CREATE, DROP, ALTER, etc), therefore revoking them could have adverse effects. The WordPress Codex has more information on the subject, which can be found here.

For the changes to take effect you must flush the MySQL privileges table:

FLUSH PRIVILEGES;

Finally, you can exit MySQL:

exit;

Now that you have Nginx configured and a new database table, it’s time to install WordPress, but before doing so you’ll need to install WP-CLI.

Installing WP-CLI

If you have never used WP-CLI before, it’s a command line tool for managing WordPress installations, and greatly simplifies the process of downloading and installing WordPress (plus many other tasks).

Navigate to your home directory:

cd ~/

Using cURL, download WP-CLI:

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar

You can then check that it works be issuing:

php wp-cli.phar --info

The command should output information about your current PHP version and a few other details.

In order to access the command line tool by simply typing wp you need to move it into your PATH and ensure that it has execute permissions:

chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp

You can now access the WP-CLI tool by typing wp.

WP-CLI Output

Installing WordPress

With everything in place it’s time to install WordPress. Start by navigating to the site’s public directory:

cd ~/ashleyrich.com/public

Then using WP-CLI, download the latest stable version of WordPress into the working directory:

wp core download

You now need to create a wp-config.php file. Luckily, WP-CLI has you covered:

wp core config --dbname=ashleyrich_com --dbuser=username --dbpass=password

Finally, with the wp-config.php file in place, you can install WordPress and setup the admin user in one fell swoop:

wp core install --url=http://ashleyrich.com --title='Ashley Rich' --admin_user=ashley --admin_email=hello@ashleyrich.com --admin_password=password

On success, you should be able to visit the domain name within the browser and be presented with a blank WordPress installation:

Blank WordPress Installation

Adding Additional Sites

Additional sites can be added to your server using the same procedure as above and you should be able to fire up new sites within a couple of minutes. Here’s a quick breakdown of how I personally add them:

  1. Add the relevant DNS records to the domain.
  2. Navigate to your home directory and create the required directory structure for the new site (logs and public).
  3. Navigate to the sites-available directory within Nginx and copy an existing config file for the new server block. Ensure you change the relevant directives.
  4. Symlink the config file to the sites-enabled directory to enable the site and restart Nginx.
  5. Create a new database and MariaDB user using either the command line, or Sequel Pro (see below).
  6. Navigate to the site’s public directory and download, configure and install WordPress using WP-CLI.

It’s as simple as that.

You are free to add as many additional sites to your server as you like, the only limiting factors are available system resources (CPU, RAM, etc) and bandwidth restrictions imposed by your VPS provider. Both of which can be overcome by upgrading your package. Caching will also greatly reduce system resource usage, which is something I will guide you through in the next post.

File and Database Management

File Management Via Transmit

If at any stage you need to upload files to your server, you can easily do so using SFTP. Using an FTP client is often the easiest option. I like to use Transmit.

Create a new connection and select SFTP as the protocol. Enter your server credentials and leave the password field blank as Transmit will automatically use the default key within your .ssh directory. You can click the key icon (next to the password field) to choose a custom key file, if you’re not using the default key.

Transmit Connection Details

Upon saving the settings and connecting to the server, you should be presented with your home directory. From there you can navigate to the site’s root directory.

Transmit File Browser

When uploading files to the server, you will not need to change ownership of them as you have configured Nginx and PHP-FPM to run under your user account. Super easy!

Database Management Via Sequel Pro

Managing MariaDB/MySQL from the command line can be a major pain, therefore it’s often easier to use a GUI. phpMyAdmin and Adminer are common choices, however they often involve setting up separate sites to host them. Instead, I like to use Sequel Pro, which is a native Mac app.

Setup is relatively straightforward, however, because you have configured MySQL to only allow connections from localhost (originating from your server) you need to tunnel the connection through SSH. Luckily, Sequel Pro makes this a breeze.

Create a new connection type of SSH and provide your server and database credentials. It’s advised to use the MariaDB root user so that you can manage all databases and create new users. As with Transmit, you do not need to provide a password as Sequel Pro will automatically use the default key from within your .ssh directory.

Sequel Pro Connection Details

Managing Users and User Privileges

As mentioned earlier, it’s best practice to lock down the privileges for each database user and only give them access to the databases they require. Sequel Pro greatly simplifies this process.

Open the Users panel.

Database View

From this panel you can create new users, change a user’s privileges and reset their password.

Users Panel

Restricting privileges is a trivial process. First remove the global privileges.

Global Privileges

You can then select each individual database that the user needs access to and add only the required schema privileges.

Schema Privileges

That’s all for part 3, if you have any questions please feel free to ask them below. In the next post I will guide you through the process of caching, performance optimization and server monitoring. Stay tuned!

About the Author

Ashley Rich

Ashley is a PHP and JavaScript developer with a fondness for solving complex problems with simple, elegant solutions. He also has a love affair with WordPress and learning new technologies.