WordPress LEMH Server on Ubuntu 15.04 Tutorial

Supercharge your hosting server using this complete Ubuntu 15.04 LEMH Stack setup guide.       Last Updated: 06/10/2016

Nginx Compiled from Source, HHVM, MariaDB 10, FastCGI Cache, and CloudFlare SSL with a Self-Signed Certificate

We’re going to walk through a basic LEMH stack install for hosting WordPress sites. As you might have heard as of late, Nginx, HHVM, and MariaDB make WordPress faster than using just about anything else. Using a setup like this ensures that you’re getting the most bang for your hosting buck.

In addition we’ll also include FastCGI Cache, a rather unique method of file caching which is built right into Nginx. By using FastCGI Cache, we’re bypassing the more resource intensive solutions based off PHP and WordPress, such as W3 Total Cache or WP Super Cache.

We won’t be covering various types of security for your system, such as Uncomplicated Firewall, Fail2Ban, or creating new user accounts besides root. If you don’t want to get hacked, you should probably read up on securing your new VPS before using it on a production website.

Configuration File Locations
For your reference, these are the configuration files we’re creating or altering, and their corresponding locations. There’s no need to do anything with the files now, as everything will be covered in the tutorial below.
Application Location Filename
Nginx /etc/nginx/ fileheaders.conf
Nginx /etc/nginx/conf.d/ default.conf

Ubuntu Basics

Initial setup
Removing Stuff We Don’t Need
Changing SSH Port



Since HTTP2 requires an OpenSSL version of 1.0.2 or greater to fully run on modern browsers, we’re going to compile Nginx from source so we can take advantage of this. While it is possible to get HTTP2 running on Ubuntu 15.04’s default OpenSSL 1.0.1f , support for this method is being phased out of browsers currently.


First we’ll need to download the latest versions of Nginx and the various modules we’re using. You’ll want to check their sites to ensure you’re downloading the latest version.

Get the latest versions of: Nginx, OpenSSL, Headers More Module, and Nginx Cache Purge Module.

Installing Nginx

Now it’s time to compile Nginx using the parts we’ve downloaded. If you downloaded different versions of any modules, don’t forget to change the OpenSSL, cache purge, and more headers module versions inside of the  ./configure command.

Using the  checkinstall command tells the server to package our compiled source into a more easily managed .deb package file. Move through the prompts, you can tell it not to list the installation files, and yes to exclude them from the package. Since Nginx updates quite frequently, doing this allows us to easily upgrade later on. To upgrade to the latest version, double check Nginx and module versions (as this guide may not be up to date), then simply repeat the installation process above. Restart Nginx and you should be running the latest version

Double check that we’ve got everything installed correctly by using the nginx -Vv command. This will also list all installed modules, and your OpenSSL version.

Creating Directories and Setting Permissions

Here we’re going to ensure that the right folders are in place for our config. In addition, since we might be hosting multiple domains on this server, we’ve told our yourdomain.com.conf files to log to a dedicated folder inside /var/log, just like Nginx or HHVM.

Automatically Starting Nginx

Now that we’ve installed Nginx, we’ll need to make it start up automatically each time the server reboots. Ubuntu 15.04 uses SystemD to handle bootup processing, so that’s what we’ll be working with.

Paste the content below, then save.

Finally, let’s double check that it’s working, and then turn on Nginx.

In the future, you can restart Nginx by typing
sudo service nginx restart



NOTE: install_fastcgi.sh can sometimes be unreliable for a number of reasons, resulting in an error. If this happens, simply add  include hvm.conf; to yourdomain.com.conf. Our versions of yourdomain.com.conf and default.conf already reflect that step, so you can feel free to skip it.
Setting HHVM to Load at Boot
Set HHVM to Use Unix Sockets

Since Unix sockets are faster, and we like that, we’re going to want to make 2 quick changes to switch over to using sockets instead of TCP.

Replace hhvm.server.port = 9000  with hhvm.server.file_socket=/var/run/hhvm/hhvm.sock.

Since our hhvm.conf file already has sockets enabled, we don’t need to edit anything else. But on another server you’d need to replace fastcgi_pass; with fastcgi_pass unix:/var/run/hhvm/hhvm.sock;.

PHP.ini Settings

Let’s set some quick variables so that HHVM has good timeout and file size limits for WordPress. Feel free to adjust these based on your needs.

Paste this under ; php options.

Get Your PHP Installation Info

The latest version of HHVM now supports the phpinfo command, so you’ll be able to get a lot of useful info about your installation. Here we’re going to write a very basic php file that will give us this information. We’re going to send it straight to your server’s default folder, which will be /var/www/html. By contrast, domains will be using /var/www/yourdomain.com/html .

Point your browser to http://ipa.ddr.ess/phpinfo.php.

Making Things Work

Now it’s time to move nginx.conf, wpsecurity.conf , fileheaders.conf, and hhvm.conf into /etc/nginx.

You’ll also want to move default.conf into /etc/nginx/conf.d.

Then restart HHVM and Nginx.

Set Worker Processes

Set worker processes to the number of CPUs you have available. We can find this information by using the lscpu  command and editing the nginx.conf file. Enter whatever value lscpu lists under CPU(s):


MariaDB 10

We’re using MariaDB instead of MySQL, as the performance is great with WordPress.

Editor’s Note (05/25/2016): Unfortunately, MariaDB’s support for Ubuntu 15.04 Vivid ended with version 10.1.12. This puts us in a bit of a tricky place currently, as many VPS providers aren’t supporting 15.10, and also aren’t currently running OpenVZ versions of Ubuntu 16.04. When this situation changes, we’ll update accordingly.

Add MariaDB Repo
Installing MariaDB

At the end of this installation, MariaDB will ask you to set your password, don’t lose this!

Make sure that MariaDB has upgraded to the latest files by running this again. For whatever reason, sometimes MariaDB has an update available immediately after installation.

Securing MariaDB

MariaDB includes some test users and databases that we don’t want to be using in a live production environment. Now that MariaDB is installed, run this command. Since we’ve already set the admin password, we can hit N to the first option. You’ll want to hit Y  to the rest of the questions.

Finally, you can make sure MariaDB is installed and working correctly by logging using the following command.

Log into MariaDB
You can exit MariaDB by typing exit.



Installing phpMyAdmin

Since phpMyAdmin is already available through the default Ubuntu 15.04 repos, this part is really easy. We’re pointing our phpMyAdmin location to /var/www/html, which will make it available at your server’s IP address. Alter the lines below to reflect a different location, such as a behind a domain.

During the installation, just hit the tab key and press enter when the script prompts you to choose apache or lighttpd. We’re not using either, but it’s going to install apache and php5 anyway. So we’ll need to disable both from starting when the server restarts.

Here we’re going to make a symbolic link from the phpMyAdmin folder to our default domain’s public facing folder. Using this setup, phpMyAdmin will only be viewable by visiting your server’s IP address directly.

Point your browser to http://ipa.ddr.ess/phpmyadmin.



Creating a MySQL Database

We’re going to create the database by command line because we’re cool. You can also do this directly though phpMyAdmin, if you’re not as cool. Replace the database, user, and password variables in the code below.

Install WordPress

We’re going to create a few directories needed for WordPress, set the permissions, and download WordPress. We’re also going to just remove the Hello Dolly plugin, because obviously.

Note: We’re installing files to yourdomain.com. In all of the commands below, change yourdomain.com to the name of your site.

It’s time to upload any files you might have (themes, plugins, uploads, etc, wp-config, etc).

Secure WordPress

Once you’re done uploading files, we’ll want to secure WordPress’ directory and file permissions.

Install Nginx Site File

Now that we’ve got the directory structure of your domain squared away, we’ll need to enable it in Nginx.

Add yourdomain.com.conf to /etc/nginx/conf.d. This folder may hold as many virtual domains as you’d like, just make a new file with a different name for each domain you want to host.

Tell Nginx what domain you want to serve by starting up nano and replacing all instances of yourdomain.com with your actual domain. This needs to match the commands you entered just a few lines above, otherwise it won’t work.

Self-Signed SSL Certificate

Here we’re going to generate a self-signed SSL certificate. Since we’re using CloudFlare anyway, we’re going to use a FREE SSL certificate through them. You’ll need to set CloudFlare’s SSL certificate status to Full.

FastCGI Cache Conditional Purging

You’ll want a way to purge the cache when you make changes to the site, such as editing a post, changing a menu, or deleting a comment.

Nginx Cache WordPress Plugin

We like RTCamp’s Nginx Helper Plugin. You’ll want to go to the WordPress Dashboard, then Settings/Nginx Helper. Turn on purging, and select the conditions you want to trigger the purge. Finally, select the timestamp option at the bottom to display your page’s build time in the source code.

Download: Nginx Helper.

Checking FastCGI Cache

It’s always a good idea to make sure that what you think is working is in fact actually working. Since we don’t want to serve cached versions of every page on the site, inside hhvm.conf we’ve added a list of pages and cookies that we want to avoid caching. To help shed light on things a bit, we’ve added the line add_header X-Cached $upstream_cache_status;  inside /etc/nginx/hhvm.conf. This will tell us with certainty whether or not the page being served is the cached version.

We can check the status of any page by viewing the headers that are sent along when you visit it. To do this, you can use a variety of methods. You can use the curl command inside your terminal by typing curl -I https://yourdomain.com. Plugins exist for Mozilla FireFox and Google Chrome that will make things a bit easier. we prefer Live HTTP Headers for Google Chrome.

You’ll encounter 4 different messages based on the cache type: X-Cached: HIT, X-Cached: MISS, X-Cached: EXPIRED, or  X-Cached: BYPASS.

X-Cached: HIT

You’re being served a cached version of the page.

X-Cached: MISS

The server did not have a cached copy of that page, so you’re being fed a live version instead. Initially all pages will show as  X-Cached: MISS. Once they’ve been visited, Nginx will store a copy of that code for future visitors.


The version that was stored on the server is too old, and you’re seeing a live version instead. You can set the amount of time a cached copy is valid by changing the various  fastcgi_cache_valid variables inside fastcgicache.conf.

X-Cached: BYPASS

We’ve told Nginx skip caching a page if it matches a set of criteria. For example, we don’t want to cache any page beginning with wp-, or any page visited by a logged in user or recent commenter. Depending on the plugins you’re running, there may be additional things you’ll want to set to avoid being cached.

Optional Stuff


WooCommerce and FastCGI Cache

We really don’t want Nginx to cache anything related to WooCommerce, as this could result in a customer’s information being fed to others. So we’re going to tackle this 3 different ways. Our hhvm.conf file reflects these changes already, just uncomment the stuff you want to enable by removing the # from those lines.

As you can see below, we’re checking a number of locations for pages that we don’t want Nginx to cache. The variables /shop.<em>|/cart.</em>|/my-account.<em>|/checkout.</em>  reflect WooCommerce’s default page structure. If you’ve changed these pages to different locations, you’ll need to adjust the code below.

We’ll want to add the variable wp_woocommerce_session_[^=]*=([^%]+)%7C. This avoids most woocommerce sessions.

We’ll also want to to turn on a check to see if a visitor has an item in their cart.


Naturally, this tutorial is always subject to change, and could include mistakes or vulnerabilities that might result in damage to your site by malicious parties. We make no guarantee of the performance, and encourage you to read and thoroughly understand each setting and command before you enable it on a live production site.

At this point, if you’ve given up and want to hire a consultant to set this up for you, Contact Us

One thought on “WordPress LEMH Server on Ubuntu 15.04 Tutorial

  1. Thank you for this tutorial! I finally got it working! (4 tries)
    2 tips to pass on:
    1. do all this stuff BEFORE you do the basic server security stuff. i.e. do this from root. Secure the server after its working….
    2. if you dont listen to tip 1 above (I learned this the hard way) you need to edit a bunch of the commands to add sudo:
    example: in the hhvm section
    replace: echo deb http://dl.hhvm.com/ubuntu vivid main | tee /etc/apt/sources.list.d/hhvm.list
    with: echo deb http://dl.hhvm.com/ubuntu vivid main | sudo tee /etc/apt/sources.list.d/hhvm.list

    Finally a question: can you post how to edit this config for wordpress multisite?

    Thanks again!

Leave a Reply