Building a VPS with WordPress on a LEMP Stack
With site performance a key metric in Google’s ranking algorithms, more WordPress users are turning to dedicated, managed WordPress hosting such as WP Engine, Media Temple or SiteGround.
However, these can be expensive solutions for some, with costs starting at ~$30/site per month.
If you’re comfortable with basic server administration and WordPress, it’s possible to setup your own, inexpensive hosting for small WordPress websites, that matches the performance of managed WordPress hosting providers using a LEMP Stack (Linux, nginx, MySQL, PHP).
Creating a DigitalOcean Virtual Private Server (VPS)
This article uses DigitalOcean, but you can equally use services such as Linode, Vultr or a number of other providers. The other sections of this guide will equally apply, regardless of who you’re using.
First, register an account at https://cloud.digitalocean.com/registrations/new.
Once completed, click the Create Droplet button:
We’ll use the following settings for our VPS:
- Droplet Hostname: Enter something meaningful – perhaps your company or website name
- Select Image: Choose Ubuntu 14.04 x64 – this should be selected by default
- Select Size: We’ll start with the $5/month option, which comes with 512 MB, 1 CPU, 20 GB SSD and 1000 GB Transfer
- Select Region: Choose a region appropriate to your business. If you’re US based, select a USA region. If you’re UK based, select a UK region.
- Available Settings: Enabling the Backups option is recommended, as it’ll take nightly snapshots of your server. If something goes wrong, you can then roll back to the previous day’s backup.
Click the Create Droplet button, and you’ll then see on screen progress whilst your VPS (Droplet) is created.
Once completed, you’ll see your VPS on screen. Make a note of the IP address:
You’ll also receive an email with your root password, which you’ll need as well.
Logging into Your VPS
Next, let’s login to our VPS.
NOTE: In our example, to keep things simple, we’ll be using a password to login to our server. I’d recommend looking into using SSH keys for additional security.
Windows
For Windows users, download PuTTY. Once downloaded, run PuTTY and enter the following information into the dialog box that appears:
- Host Name: Enter the IP address you made a note of above
- Connection type: SSH
Click ‘Open’, and you should be presented with a security alert. This tells us that the server’s host key is new, and therefore asking us if we want to trust it. Click ‘Yes’.
Next, let’s login as the root user. Enter root
for login as, and press ‘Enter’. You’ll then be prompted to enter your password; enter the password that was emailed to you. Don’t worry if you can’t see the password as you type it – this is for security. Press ‘Enter’ when done.
Mac OS X
For Mac OS X users, open Terminal and enter the following command, replacing 123.123.123.123
with the IP address above:
ssh root@123.123.123.123
You’ll be asked to accept the server key – type yes
and press ‘Enter’:
Next, enter your password and press ‘Enter’.
Changing the Root Password
The first time you login to your server, you may be prompted to change the root password:
Enter the current password, and then enter a new password when prompted.
Installing the LEMP Stack on Ubuntu
WordPress requires Apache or nginx, PHP and MySQL, as well as a few other components to get things working.
Ubuntu uses a package manager, which can be thought of as a command line based app store. Before we start downloading and installing components from it, we need to update its catalog by entering the following command:
sudo apt-get update
Once completed, we can then install our components:
sudo apt-get install nginx mysql-server php5-fpm php5-mysql php5-curl php5-gd php5-cgi
You’ll be asked if you want to continue – type in Y, and press enter.
Configuring MySQL
During the installation process, MySQL will ask you to set a new password for the root database user. Note that this is different from the root login for the server. For security, I’d strongly recommend making this a different password than the root login to your server.
Once the installation has completed, we need to run two more commands to complete the MySQL installation.
First, enter:
sudo mysql_install_db
Then, enter:
sudo mysql_secure_installation
- Type in your current MySQL root password, which you set above.
- Enter
n
when asked to change the root password (as we’ve already done this, no need to do it again). - Enter
Y
when asked to remove anonymous users. - Enter
Y
when asked to disallow root login remotely. - Enter
Y
when asked to remove the test database and access to it. - Enter
Y
when asked to reload privilege tables.
Finally, we need to create a MySQL user and database:
mysql -u root -p
Enter your MySQL password when prompted, and if correct, you’ll be presented with the MySQL prompt:
Let’s create our new database and user – replace ‘password’ with a unique password:
CREATE DATABASE wordpress;
CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON * . * TO 'wordpress'@'localhost';
FLUSH PRIVILEGES;
exit
Configuring PHP
We need to make a slight alteration to get PHP working with nginx:
sudo nano /etc/php5/fpm/php.ini
Hold down the Ctrl
key and press W
, and you’ll be asked to type into a Search field. Enter:
fix_pathinfo
and press Enter:
Change the following line:
;cgi.fix_pathinfo=1
to:
cgi.fix_pathinfo=0
To save our changes, hold down the Ctrl
key and press X
, followed by Y
and then the Enter key.
Configuring nginx
We need to change nginx’s configuration to get things working with WordPress:
sudo nano /etc/nginx/sites-available/default
Let’s remove the current configuration. Keep pressing Ctrl
and K
to cut each line of the configuration file, until it’s blank:
Next, copy the nginx configuration below and paste it into your Terminal/PuTTY window, remembering to change domain.com to your domain name:
server {
# Listen on port 80
listen 80 default_server;
Document Root
root /usr/share/nginx;
Domain(s)
server_name www.domain.com;
Index
index index.php;
GZIP Compression
gzip on;
gzip_types text/plain image/svg+xml text/javascript application/x-javascript text/xml text/css;
gzip_vary on;
Cache Static Files
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff)$ {
expires 1y;
}
Load File
location / {
try_files $uri $uri/ /index.php?q=$uri&$args;
}
# Pass the PHP scripts to FastCGI server
location ~ \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
To save our changes, hold down the Ctrl
key and press X
, followed by Y
and then the Enter key.
Creating a SSH Login
For security reasons, we don’t want to run WordPress as the root user. Let’s go ahead and create a new server user for that purpose:
sudo adduser wordpress
Enter a password for this user, and then just press ‘Enter’ on the other fields.
Next, add our new wordpress
user to the www-data
group. This is the group used by PHP, so when we go to upload WordPress files, they’ll correctly run:
sudo usermod -a -G wordpress www-data
We need to tell PHP which user and group can run PHP files:
sudo nano /etc/php5/fpm/pool.d/www.conf
Scroll down until you find the user = www-group
line, and change this to:
user = wordpress
To save our changes, hold down the Ctrl
key and press X
, followed by Y
and then the Enter key.
Restart the Server
To make sure everything’s working, let’s restart the server:
reboot
Login and Install WordPress
To install WordPress, let’s log back into the server and then enter the following commands:
cd /usr/share/nginx
wget http://wordpress.org/latest.tar.gz
tar xfz latest.tar.gz
mv wordpress/* ./
rm latest.tar.gz
rmdir wordpress
The above commands download WordPress from wordpress.org, extract/unzip it into the /usr/share/nginx/wordpress
folder. We then move the contents of that folder back into /usr/share/nginx
before removing the original download file and WordPress directory.
To avoid file permission issues when trying to install Plugins or upload images, let’s recursively set permissions on nginx’s web accessible root folder to the wordpress
user and www-data
groups that PHP is configured to use:
sudo chmod g+w /usr/share/nginx -R
sudo chown -R wordpress:www-data /usr/share/nginx
Next, in your web browser, load http://123.123.123.123
(or http://www.domain.com
, if you’ve set your domain’s A name record to point to your server’s IP address).
If everything worked, you’ll see the familiar WordPress configuration screen. Click Let’s go!, and then enter the following information on the next screen:
- Database Name: wordpress
- User Name: wordpress
- Password: [the password you entered when setting up MySQL]
- Database Host: localhost
Click Submit, and if the details are correct, you’ll be asked to run the installation:
Enter your ‘Site Title’, ‘Username’, ‘Password’ and ‘Email Address’ before clicking Install WordPress
That’s it!
Conclusion
We’ve successfully created a VPS on DigitalOcean, and logged into it over SSH. We’ve then installed nginx, PHP and MySQL, and configured each to work with WordPress.
We’ve also setup a server user, and granted them permissions on our WordPress installation.
Finally, we confirmed everything worked by running through the WordPress installation process.