How to Enable Two-Factor Auth (2FA) for WordPress

When running a WordPress site, security should be first and foremost at the front of your mind. One of the best ways to prevent malicious users from accessing your /wp-admin area is enabling two-factor auth (2FA) for WordPress.

The easiest way to enable two factor auth for WordPress is the use the Wordfence Security plugin freely available on the WordPress plugin directory.

Installing Wordfence

The first step to getting two-factor auth enabled for your WordPress site is to install Wordfence. To do that:

  1. Log in WordPress and go to Plugins.
  2. Click “Add New”.
  3. Search for “Wordfence”
  4. Install and activate Wordfence
Showing Wordfence installed in the WordPress admin.
Wordfence installed

Configuring Wordfence

Now that Wordfence is installed you’ll need to enable and configure two-factor auth. To do that click the “Wordfence” menu that appeared after activation and then go to the “Login Security” sub-menu.

Wordfence 2FA activation screen.
Login Security (local site, not this one)

Now you’ll need to choose two factor authentication. I personally use FreeOTP (iOS, Android). Once your authenticator application is installed, scan the code and create the authenticator entry on your phone. Be sure to download your recovery codes too, just in case your phone is bricked, lost, or otherwise unavailable.

Testing Two-Factor Auth Out

Now that two-factor authentication is enabled for your WordPress site, you need to try it out! Log out of your admin, and now when you log back in you’ll be presented with this screen:

Wordfence 2FA code entry
Two Factor Auth enabled

Go to your authenticate app, press the entry for your site, enter the code, and log in!


Wordfence makes is really easy to set up 2FA on WordPress. With it being this easy, it’s hard to justify not having it. After all, even if someone manages to get your password they still won’t be able to log in unless the can compromise your phone too. If you’re worried about performance, this feature of Wordfence doesn’t effect your site’s performance in a meaningful way (which can not be said about Wordfence’s other features). All in all, the Wordfence team has done a great job making this level of security accessible to the wider WordPress community.

Need automatic updates for your premium plugins & themes? Check out Kernl.

What’s New With Kernl – August 2020

Hello everyone! It’s been awhile since the last update message, but now that summer is nearly over in the northern hemisphere Kernl will again be receiving regular updates and enhancements.

This doesn’t mean that we weren’t busy though! Let’s dig in.

New Features

  • License Management Activated Domains – When viewing your license list, you can now see the domains that have activated the license. If you go into the license detail view, you can make changes to that list. This data will give you granular insight into who is using a specific license.
  • Kernl Update Checker Automatic Update Support – With the release of WordPress 5.5 we finally upgraded our update checker library. There are a few differences like it being multiple files now, and the instantiation code changing a bit, but the upgrade path is simple for those who want automatic updates.

Bug Fixes & Miscellaneous Changes

  • Package Upgrades (Analytics) – All supporting packages have been upgraded to their latest version for better performance and security.
  • Date Retention Bug (Analytics) – We weren’t cleaning up some tables we were supposed to be. This lead to holding onto some data for much longer than 365 days.
  • UX Improvements (Analytics) – The UX around selecting and comparing dates for Kernl Analytics was a little bit confusing. We made some changes that make it a lot easier to understand for a first-time customer.
  • Data collection issues (Load Testing) – There was an issue where load testing wasn’t collecting data from the master node after an upgrade to the underlying infrastructure. This was resolved.
  • UX Improvements (Load Testing) – Some load test templates are large and take awhile to return from the server. An indeterminate spinner was added here to let customers know that things are actually happening. The same situation was happening when long running, high volume tests load initially. There is a lot of data that takes some time to return from the server so an indeterminate spinner was added.
  • Infrastructure (Load Testing) – The Kernl WordPress Load Testing box was upgraded from 1vCPU+1GB RAM to 2vCPU+2GB RAM.
  • Meta Tag Parsing (Load Testing) – When you verify a site with Kernl, we look for a meta tag in your HTML. Initially we were attempting to find, capture, and validate this using regular expressions. As is tradition, we found this was a bad idea and switched to using an open-source library (Cheerio.js) instead.
  • All servers have had their packages upgraded to the latest available versions.

Blog Posts

That’s it for this month!

Hummingbird Cache for WordPress Performance Review

The Hummingbird Cache plugin is one of many different caching plugins available in the WordPress ecosystem. Enabling it will increase your site’s performance significantly, but by how much? In this review we’re going to use Kernl’s WordPress Load Testing tool to push our Hummingbird Cache WordPress installation to it’s limits.

HummingBird cache pushed to limits

Test System Setup

As with most of our cache reviews, we used a pretty standard PHP-FPM + Nginx setup.

  • DigitalOcean $5/month 1vCPU 1GB RAM machine
  • Ubuntu 20.04
  • PHP (FPM) 7.4
  • Nginx 1.18
  • MariaDB 10.3
  • Content – For this test I imported the contents of my personal blog and used it for testing.

The test system was located in San Francisco, CA, USA. Load test virtual users were located in New York, NY, USA along with some of the high volume tests spreading virtual users around Europe.

How did we test Hummingbird Cache?

To test the Hummingbird WordPress caching plugin ran 3 different load tests with Kernl WordPress Load Testing.

  1. Baseline – This is a 200 concurrent user test for 60 minutes with no caching enabled.
  2. Cache Enabled – The same test as the baseline run, but with caching enabled. This is the “apples to apples” comparison.
  3. Cache++ – After the “apples to apples” comparison, we pumped up the concurrent users to 400 to see how well the plugin would respond.

Baseline Load Test

The baseline load test is just the bare WordPress setup with no plugins enabled and the base TwentyTwenty theme. As expected performance isn’t great but it isn’t terrible either.

Hummingbird Cache - Baseline Request Throughput
Hummingbird Cache – Baseline Request Throughput

You can see from the throughput chart that the base WordPress installation with no caching enabled settled in at around 34 requests/s. Not too shabby, but what was the quality of those requests?

Hummingbird Cache - Baseline Response Times
Hummingbird Cache – Baseline Response Times

The average and median response times tell a story steady degradation of the user experience before finally settling at just shy of 5 seconds. If I were a reader of that blog, I would be extremely turned off by waiting for 5 seconds just to have the page load start.

Hummingbird Cache - Baseline Response Time Distribution
Hummingbird Cache – Baseline Response Time Distribution

The response time distribution is pretty awful here. 50% of requests finished in under 5s, and 99% of requests finished in under 5.5s. In most load tests we like to see the P50 number be a lot lower than the P99 number. In a perfect world they’re both really low, but that doesn’t happen in most cases.

Cache Enabled Load Test

Our next test was the same as the baseline test, but with HummingBird cache enabled. We went with all the default options making no changes to the settings.

Hummingbird Cache – Cache Enabled Request Throughput
Hummingbird Cache – Cache Enabled Request Throughput

As expected of a caching plugin, throughput goes up a lot and settles in at around 175 requests/second with zero errors. This is a nearly 6x improvement in throughput. But what about the response times? How did this look to the end user?

Hummingbird Cache – Cache Enabled Response Times
Hummingbird Cache – Cache Enabled Response Times

The response time results are extremely promising. The average response time was around 95ms and the median was around 75ms. Most performance best-practices hope for your site to respond within 100ms, which this plugin easily accomplishes even under incredibly heavy load. Let’s break the response time numbers down further.

Hummingbird Cache – Cache Enabled Response Time Distribution
Hummingbird Cache – Cache Enabled Response Time Distribution

For 50% of our users, the response time was 75ms or less. For 99% of our users, response time was less than 160ms. These are great numbers and just what I would expect from a WordPress caching plugin.

Cache++ Load Test

Now that we’ve established that Hummingbird Cache does a great job under (somewhat) normal circumstances, lets see what happens if we double the traffic (400 concurrent users -vs- 200 concurrent users).

Hummingbird Cache++ – Cache Enabled Request Throughput
Hummingbird Cache++ – Cache Enabled Request Throughput

Event at 2X the number of users, we don’t see any errors and we see the throughput settling at about 325 requests per second. If you do the math, this is about 28 million requests a day. On a $5 box. Obviously this test is fairly naive, but it does show that the plugin can handle some serious traffic when needed.

Hummingbird Cache++ – Cache Enabled Response Times
Hummingbird Cache++ – Cache Enabled Response Times

The best part about this test is that even with incredible load the response time average and median are still below 180ms. Most users visiting a site would be extremely happy with response times in that range.

Hummingbird Cache++ – Cache Enabled Response Time Distribution
Hummingbird Cache++ – Cache Enabled Response Time Distribution

The response time distribution still tells a reasonable story. 50% of users see responses in 150ms or less and 99% see responses in 375ms or less. Solid performance from the Hummingbird Cache team.

Hummingbird Cache Conclusions

If you need a caching plugin for your site, Hummingbird Cache is a solid choice. It performs well, was easy to install, and was generally low friction. I found the user interface to be a little immature, but that doesn’t change the excellent performance we saw during our tests.

Want to run your own load tests? Sign up for Kernl!

UpCloud WordPress Hosting Review

If you spend time in the WordPress hosting space and few names constantly come up, and one of them is UpCloud. UpCloud is a European cloud provider with data centers all over the world that claims to have the world’s “fastest cloud servers”. In this review we’re going to take a look at how WordPress performs while hosted on UpCloud and also see how the reliability of the service is.

Want to run your own WordPress load tests? Sign up for Kernl.

Hardware Tested

For our test of WordPress running on UpCloud, we tested 3 different hardware configurations.

  • 1vCPU + 1GB RAM – This is the cheapest possible option for hosting WordPress on UpCloud at $5 / month.
  • 2vCPU + 4GB RAM – At $20 / month, this option is a nice balance of processing power and memory. If I were to host a few sites on UpCloud with moderate amounts of traffic I would probably start here.
  • 4vCPU + 8GB RAM – This machine was as expensive as I was willing to go for this review, coming in at $40 / month.

Software Used

The software used in this test was the latest available from the included repositories with Ubuntu 20.04.

  • Ubuntu 20.04 LTS
  • MariaDB
  • Nginx
  • PHP-FPM 7.4
  • Memcached

What was tested?

For each test we ran on UpCloud we used Kernl’s WordPress Load Testing service to generate load against each virtual machine. The content for the load tests was a copy of this blog. The load generators for each test lived in DigitalOcean’s SFO2 data center and ran against UpCloud’s Chicago data center.

UpCloud WordPress Load Tests

We ran a total of 6 WordPress load tests on UpCloud’s servers. For each machine we tested we ran a test where nothing was cached and a test where everything was cached (using W3 Total Cache backed by Memcached). Each test was for 1000 concurrent users for 45 minutes.

1vCPU + 1GB RAM (No Cache)

For this configuration the requests per second peaked at around 41/s before failure rates started to increase. Once failures started in earnest, successful requests leveled off at around 11/s.

UpCloud 1vCPU 1GB RAM - Requests/Failures
Not bad for no caching!

On the response time front, things weren’t great. As the request (and error) rate increased, the response times started to get pretty unwieldy.

UpCloud 1vCPU 1GB RAM - Response Time
Less than a 1000ms, then 2500-3000

A graph of median and average response times doesn’t always tell the whole story, so lets take a look at the response time distribution.

UpCloud 1vCPU 1GB RAM - Response Time Distribution
No great.

The response time distribution tells us that 50% of requests finished in under 5000ms, but that 99% finished in under 6000ms. Usually you want to see a large difference between 50th and 99th percentile. But here they’re awfully close, meaning that most request response times were pretty terrible.

1vCPU + 1GB RAM (Cached)

Now that we’ve looked at uncached performance, lets take a look at how this UpCloud server handled WordPress with caching enabled.

UpCloud 1vCPU 1GB RAM Cached – Requests/Failures Per Second

As you can see, performance is much better. We end up leveling off at around 436 request per second. The only issue here is that we still have quite a few failures. Certainly more failures than would be acceptable in a production situation.

UpCloud 1vCPU 1GB RAM Cached – Average / Median Response Time

Looking at response times you can see performance is a lot better, and much more in line with what you’d expect from a WordPress site that’s under heavy load. Average response time was a hair less than 1000ms, with the median response time (doesn’t include outliers) closer to 475ms. This is a bit less than an order of magnitude improve in performance just be turning on caching with W3 Total Cache.

UpCloud 1vCPU 1GB RAM Cached – Response Time Distribution

So far everything looked great (with the exception of the request failures) for this UpCloud configuration with caching enabled. However if we take a look at the response time distribution you can see that all is not what it seems. 80% of requests returned in less than 600ms, but the upper 20% too anywhere between 3000ms and 12000ms. 20% of your customers waiting more than 3 seconds for the page to load isn’t awesome.

2vCPU + 4GB RAM (No Cache)

The next machine we tested was far better provisioned than the first machine with twice the CPUs and 4x the RAM.

UpCloud 2vCPU 4GB RAM - Request / Failures per Second

As you can see request throughput peaked at around 50 per second, and then leveled off at 22 per second when the error rate elevated. I honestly expected the throughput to be better for this scenario given how much more hardware there was to work with.

UpCloud 2vCPU 4GB RAM - Average / Median Response Times

Response times slowly increased as load increased on the server, with average response times ending up near 5000ms and the median response times closer to 5500ms. At that point, 500ms probably doesn’t matter that much.

UpCloud 2vCPU 4GB RAM - Response Time Distribution

The response time distribution for this test was predictably bad. The difference between the lower 50% and upper 50% is only 1000ms, which doesn’t give me warm fuzzy feelings. If anything, this is a great example of how much you need caching in a WordPress installation. Throwing twice as much hardware at it barely even makes a difference uncached.

2vCPU + 4GB RAM (Cached)

Now lets take a look at the same machine, but this time with caching enabled via W3 Total Cache and Memcached.

UpCloud 2vCPU 4GB RAM Cached – Requests / Failures per Second

No we’re getting somewhere! Requests per second leveled out at around 600, which is actually quite high. We also didn’t start to see failures increase until around 300 per second, which is pretty amazing for a $20/month machine.

UpCloud 2vCPU 4GB RAM Cached – Average / Median Response Time

The response times for the cached version were pretty great until the failure started accumulating. Up until the failures started we were seeing response times right around the 60ms mark, which is excellent under heavy load. After that they leveled out at around 450ms, which still isn’t bad when you are serving ~600 requests/s.

UpCloud 2vCPU 4GB RAM Cached – Response Time Distribution

The response time distribution wasn’t terrible here either considering all the failures we were seeing. 95% of requests finished in under 1000ms and 50% finished in under 500ms.

4vCPU + 8GB RAM (No Cache)

Our final test was with a fairly robust machine (by my standards anyway).

4vCPU 8GB RAM – Requests / Failures Per Second

As you can see the results in an uncached situation were pretty solid until failures started in a major way. This machine was able to handle about 175 req/s uncached, and then leveled out at 215 req/s once the errors started. Obviously this number of errors isn’t great, but at the 175 req/s mark thats enough to serve 15 million requests a day.

UpCloud 4vCPU 8GB RAM – Average / Median Response Times

As expected in an uncached situation the response times weren’t great, but they weren’t terrible either given the amount of load the system was under. Prior to elevated error rates we were seeing response times around 100ms. Once errors picked up they leveled off at 2500ms.

4vCPU 8GB RAM – Response Time Distribution

The response time distribution is what we would expect from an uncached WordPress installation under heavy load. 50% of requests finished in 2500ms and 99% of requests finished in 3250ms. That’s not all bad considering there wasn’t any caching.

4vCPU + 8GB RAM (Cached)

Our final load test was a cached version of the previous test. Given drastic improvements we saw in the other tests, the same sort of results were expected here.

4vCPU 8GB RAM Cached – Requests / Failures Per Second

Now that we have a more robust machine + caching enabled, you can see that the server was able to process quite a few requests concurrently before errors started. Even once errors started they stayed relatively low. Initial errors didn’t show up until around 500 req/s and eventually we leveled off at 850 req/s. Not bad for $40/month.

4vCPU 8GB RAM Cached – Average / Median Response Times

The response times were also excellent in the cached scenario. Before errors and failures we were seeing 65ms and after we were stilling coming in at around 100ms. Not too shabby for the intense load the server was under.

UpCloud 4vCPU 8GB RAM Cached – Response Time Distribution

My favorite chart this time around is the response time distribution. 99% of all requests finished in under 300ms. With 1000 concurrent users.

UpCloud WordPress Reliability

An often overlooked metric when comparing VPS providers like UpCloud is reliability. To get some objective numbers on that, I ran a reliability test with Kernl for 30 consecutive hours. The test is low volume (25 concurrent users), but enough to make sure the server stays active and that we’ll notice is sometimes goes awry.

Reliability test

Over the course of 30 hours we saw one error spike that was quickly resolved. After that, no errors at all. Over the entire test we saw 400 requests fail, which is roughly 16 seconds of failures. I’ve done quite a few of these reliability tests with different hosts and this is pretty average.


UpCloud is solid choice for VPS hosting though their claim to be the “fastest” may not be completely substantiated (with WordPress at least). If I wanted to use a VPS host based in Europe they would definitely be near the top of my list. The only odd thing about them is their billing model where you add “credits” to your account versus just having a credit card of file. This is likely to prevent fraud, but doesn’t really make for a great user experience.

What’s New With Kernl – May 2020

Hello everyone and welcome to the May 2020 edition of “What’s New with Kernl”! This month was relatively slow for us with little work on new features and more focus on bugs and refactoring. Let’s dive in.

  • We now have video tutorials for enabling Git deployments on your WordPress plugins and themes. You can see them on your Kernl dashboard, or in the Kernl documentation.
  • License Tab UX – The license tab in the plugin and theme edit interface was getting out of control. We collapsed the provider specific controls into an accordion to make it a little easier to digest.
  • Global CDN – Kernl now has the option to serve your updates via a global CDN powered by Vercel. If you have a geographically diverse customer base, this might be for you.
  • Analytics Date Selection Bug – There was an issue with date selection being wrong in some cases.
  • Mongoose Upgrade – Kernl used Node.js and MongoDB under the covers to deliver your updates. Our ORM is Mongoose and had been stuck on the 4.X version of it for a long time. We finally upgraded to the 5.x series and saw 40% reduction in queries to our database.
  • Analytics Database Maintenance – Removed 2 indexes that we didn’t need and dud a full vacuum on the largest and highest traffic table. Recovered 5Gb of hard disk space.
  • Kernl Blog Rebuild – Our blog is self-hosted and was running on some pretty ancient hardware/software. We rebuilt the machine to use Ubuntu 20.20 + Nginx & PHP-FPM.
  • Analytics Daily Aggregates Failure – For 2 days Kernl analytics daily aggregates were failing due to disk space space and memory issues (see Analytics Database Maintenance). This has been resolved.
  • Site Health SSL Certificate Expiration – We forgot to renew the WordPress Site Health SSL Certificate (oops!). This is now an automated process 🙂

That’s all for this month. I hope everyone has a great June!

DigitalOcean Spaces for Storing WordPress Static Assets

When hosting your WordPress site on DigitalOcean, storing your static assets nearby makes a lot of sense. Since the advent of DigitalOcean Spaces in 2017 this has become a much less arduous process. In this post we’ll go through step-by-step how to host your media (and static css/js if you want) in a DigitalOcean Space.

Setting up a DigitalOcean Space

Before you get started you need to set up your DigitalOcean space. To do that, log in to DigitalOcean and click the “Create” dropdown. From there, choose the “Space” option.

Creating DigitalOcean Spaces screenshot
Create a DigitalOcean Space

Select your region, ignore the CDN (for now. You should do this later though), leave the file listing as restricted, and then pick a name. It can be anything, but something descriptive is usually best. In our case, we’re going to use kernl-blog-space.

Once your space is created, you need to make a few minor changes in it’s settings to allow for file uploading. Under CORS Configuration we need to add the domain where files are going to be uploaded from. In our case, we added:

  • Origin – (this is my test domain)
  • Methods – I selected all of them, because I want the plugin that will be managing the files to be able to make all the modifications that it needs.

The other two options I left blank/default.

CORs configurations list
DigitalOcean Spaces CORs Configuration

Finally, you’ll need access keys. To generate those, look in the left menu on DigitalOcean, go down to the “Account” section, and click “API”. Now scroll down and click “Generate New Key”, pick a name, then click the check mark. Copy the access and secret key somewhere. You’ll need it for later.

WordPress Configuration for DigitalOcean Spaces

The next step is to set up WordPress to send and server media from your DigitalOcean space. First up, you need to install the WP Offload Media Lite plugin from the repository.

WP Offload Media Lite plugin screenshot
WP Offload Media Lite plugin

Once installed and activated, go to Settings -> Offload Media Lite. Select DigitalOcean Spaces, choose whether to store keys in the database or not, add your keys, and then click “Next”.

Storage provider list inside of Offload Media Lite being configured for DigitalOcean Spaces
Offload Media Lite Configuration

The next step is selecting the region where your space is located and then copying the name of that space into the “bucket” field. Once you’ve done that click “Save Bucket Settings”.

Testing it Out

Now let’s test it out! Go to your media library and upload a few images. Once uploaded, click into the image detail view, and checkout out the source.

Screenshot of the test image successfully being served from DigitalOcean Spaces
Image served from DigitalOcean Spaces!

And just like that, we’re done! Images are now served from DigitalOcean spaces. A next step you should take it to configure to the CDN so your media is globally distributed, but this is a great start.

What’s New With Kernl – April 2020

Kernl had another great month, with some bug fixes, blog entries, and a few new features.

Most importantly we’re announcing a limited beta of our new global update CDN! With our new global CDN powered by Vercel, every Kernl update request is cached at edge nodes around the world. This means <= 50ms response times for updates globally.

Reach out to if you’d like to give it a try!

Features, Bugs, and Performance

  • Docs – Added more descriptions to the “Understanding Graphs” portion of the Kernl documentation.
  • Analytics Date Selection – The flow for selecting dates and products in analytics has changed. You can now only select dates in the range that the selected product has data.
  • Examples – The Kernl API Examples repo has been updated to include a license management example.
  • WHMCS License Validation – Kernl now supports WHMCS license validation for plugins and themes. This integration works similarly to our other 3rd party license validation integrations.
  • Performance – We added a few database indexes to our load testing database. In situations where a lot of load tests existed performance was abysmal.
  • Tutorial – On the main dashboard page of Kernl there is now video tutorials for getting started with plugin and/or theme updates.
  • License Expiration Date Bug – There was a bug in Kernl license management where date editing didn’t work correctly when the saved date started with a leading zero.
  • License Domain Restriction Bug – An edge case existed where license validation would fail with a server error if domain restrictions are set but no domain was passed in to be validated.
  • Download Increment Bug – Incrementing download count was being handled in a very naive way. It was originally developed when Kernl wasn’t expected to reach the scale it has. This has been resolved by using the $inc operator in MongoDB instead of a find -> increment -> upsert.
  • Load Test Infrastructure Bar – The progress bar when you create a load test didn’t have a very good default state (it looked like nothing was happening). Now when below 3% complete, the bar will show 3% so you can actually see that things are progressing.
  • Site Health Edit – You can now edit your site health entries.
  • Envato License Validation Bug – Due to the deprecation of an API endpoint we were using, users of our Envato license validation need to regenerate their Envato access token that is saved with Kernl.
  • Envato License Tied to ID – You can now verify that an Envato license that is being used is tied to a specific plugin or theme.

Blog Posts

DigitalOcean Marketplace WordPress Review

For a few years now the DigitalOcean Marketplace WordPress image has been available for installation on their droplets. If you want to use WordPress but don’t want to go through the trouble of configuring it, this is a great place to get started.

Ease of Installation

The DigitalOcean Marketplace WordPress image installation isn’t one click, but it is easy. It takes a few steps, including:

  1. Sign up for DigitalOcean or log in.
  2. Click “Create” then “Droplet”.
  3. Select the image
  4. Pick your droplet size
  5. Select your region for deployment
  6. Add your SSH Keys (optional)
  7. Name your VM
  8. Create the droplet

Overall, the UX for creating the droplet with the WordPress image installed on it is super easy to follow. DigitalOcean has done a great job removing friction from the process.

What’s Included?

Compared the to Vultr One-Click WordPress installation the DigitalOcean image has less included out of the box, but this isn’t necessarily a bad thing. The DigitalOcean marketplace WordPress image is configured with the following software:

  • Ubuntu 18.04 LTS
  • Apache 2.4
  • MySQL 8
  • PHP 7.4
  • Fail2ban 0.10
  • Postfix 3.3
  • Certbot 0.26

Most of this is fairly self-explanatory with the exception of Fail2ban and Certbot. Fail2ban scans Apache logs for malicious patterns and bans those IP addresses. Certbot provides free SSL certificates for your site.

In addition to installing the packages above, the DigitalOcean Marketplace WordPress makes some common sense security changes to help keep you secure.

  • Enables UFW firewall to allow SSH, HTTP, and HTTPS.
  • Sets the MySQL root password and runs mysql_secure_installation.
  • Creates an initial WordPress config file and sets up the salt keys.
  • Disables XML-RPC to prevent DDOS and brute force attacks.
  • Modifies PHP settings to increase max file size and execution time.
  • Enables Apache rewrite module for WordPress permalinks

What’s WordPress Running On?

For our tests, we used to smallest / cheapest DigitalOcean droplet that we could get.

  • $5 / month
  • 1GB RAM
  • 1 vCPU
  • 25GB SSD Disk
  • 1000GB network transfer

For the vast majority of WordPress sites, this will be plenty of power for you.

DigitalOcean Marketplace WordPress Performance

So you’ve installed this WordPress image from the DigitalOcean Marketplace and you want to see what kind of punishment it can take. Cool. Kernl’s got your back.

DigitalOcean Marketplace WordPress requests / failures per second (no caching)
Requests / Failures per second

The requests per second performance of the baseline image isn’t terrible, but it isn’t great either. Right around 14 requests/s the wheels fall off and error rates spike. Eventually the application failed to response to any requests.

DigitalOcean Marketplace WordPress average / median response time (no caching)
Average / Median Response time

You can see the response time average and median stay right around 150ms until the server becomes overwhelmed. The numbers here are misleading though because this chart only takes in to account successful requests.

DigitalOcean Marketplace WordPress response time distribution (no caching)
Response time distribution

The final chart is the response time distribution. Of all requests, 50% finished in under 500ms. 100% finished in 5000ms. The 5000ms mark is interesting because that’s the timeout that was configured by DigitalOcean on the WordPress image. Just because requests finished, doesn’t mean they were successful.

DigitalOcean Marketplace WordPress Performance with Caching

Most people run some sort of caching with their WordPress site. For this test we used W3 Total Cache with all caching features enabled.

requests / failures per second (with caching)
Requests / Failures Per Second

You can see that the throughput of the site increased quite a lot once caching was enabled. Failures didn’t start to see and uptick until around 60 requests/s and then stayed relatively consistent at around 10 failures/s with requests leveling out at 130 req/s. To be clear, 130 req/s is a lot of traffic.

average / median response time (with caching)
Average / Median Response Times

The average response time leveled off at around 110ms, with the median coming in at around 80ms. The difference between the two is interesting because it means we had some pretty big outliers.

response time distribution (with caching)
Response time distribution

The response time distribution gives an interesting take on the average/median response time graph. We can see that 99% of our requests finished in under 250ms, but that last 1% took up to 9000ms. That explains the difference between the median and the average.


In general the performance of the $5 droplet with the DigitalOcean Marketplace WordPress image on it was acceptable. Once caching was enabled it became quite good. The best part about this image is that it takes care of basic security things for you and doesn’t try to guess what you want.

In short, give this image a try. It might save you some time.

Vultr One-Click WordPress Review

If you want to host your own copy of WordPress but don’t want to go through all the trouble of setting it up, it might be worth your time to explore using “one-click” installs from some of the major cloud providers. In this article, we’re going to explore the Vultr One-Click WordPress install and see what it’s all about.

Ease of Installation

Before anything else you need to get a WordPress box spun up on Vultr. Overall, the experience was pretty easy:

  1. Log in / sign up for Vultr
  2. Click “Deploy new server”
  3. Select your server type (we used “Cloud Compute”) and server location (Atlanta for us).
  4. Click the “Application” tab and then select WordPress.
  5. Select your server size (25GB SSD $5/month for this test)
  6. Add your SSH key
  7. Fill out your host name
  8. Click “Deploy Now”

So obviously this isn’t a single click to install, but it is a lot easier than setting up and configuring a WordPress installation from scratch.

Whats included?

Aside from the obvious stuff (WordPress, MySQL, etc) which we’ll cover in the next section, what else is included with your One-Click Vultr WordPress installation?

  • XHProf – XHProf is a tool for profiling PHP applications. This could be very helpful if you find your site getting real slow after installing a plugin or theme. It could help you determine the source of the slowness.
  • PHPMyAdmin – The classic MySQL database administration tool for the web. If you haven’t used it before, its a great way to browse your database and make changes.
  • Maldet – Maldet is a Linux malware detection tool that runs periodically on your system to see if it has been infected. This is disabled by default, but can easily be enabled with the directions included with your new server.
  • Cockpit – Cockpit is a web based interface for your server. You can easily see how your server is configured, what resource usage looks like, and update packages all without even SSHing into your server.

What’s WordPress Running On?

The Vultr One-Click WordPress system that we decided to use had the following hardware and software:

  • Hardware
    • 1 vCPU
    • 1GB RAM
    • 25GB SSD
    • 1TB Bandwidth
  • Software
    • Ubuntu 18.04 LTS
    • Nginx
    • PHP 7.2
    • MySQL 5.7

Overall the software is a pretty standard LEMP setup and the hardware is as performant as you would expect for $5 per month. It’s also worth noting that the installation script for this one click install might need some updating because it installs the previous version of WordPress.

Performance Out of the Box

So you’ve spun up your new Vultr One-Click WordPress server, but what sort of performance can you get out of it? Using Kernl’s WordPress Load Testing we can easily see the performance that this $5 per month server gives you.

For both this test and the cached test (next section) we attempted to have 200 concurrent users browse the WordPress site for 30 minutes. The traffic was generated from Digital Ocean’s NYC3 datacenter.

Vultr One-Click WordPress Requests / Failures per second
Requests / Failures per second

As you can see we get up to about 20 requests per second before the server starts returning failures. For a $5 machine this isn’t bad at all. 20 req/s over the course of 24 hours is ~1.7 million requests.

Vultr One-Click WordPress Response Times
Response Times

Initially response times are pretty good, but as resource contention on the server increases the average and median response times start to go up. Even when under full load, the pages returned in under 5 seconds. Not terrible, but you definitely aren’t winning friends with that sort of performance.

Vultr One-Click WordPress Response Time Distribution
Response Time Distribution

The response time distribution is mostly what you would expect after seeing the error rate and the average response time. 99% of requests return in under 5.5 seconds. In general you want to see your 99th and 100th percentiles be low, but given the duress the server was under this isn’t surprising at all.

Overall the system performed well and was configured well enough to handle a small-ish load test.

Performance with Caching

The test above is almost silly in that most people will definitely be using some form of caching on their WordPress site. For a more realistic test, I enabled W3 Total Cache on the WordPress installation. There wasn’t any Memcached or Redis installation available, so all cache settings were tuned to “Disk (enhanced)”.

Requests / Failures per second

As you can see the difference in performance with caching enabled is quite good. We didn’t see any errors at all for the duration of the test and the maximum concurrent requests per second peaked at 160. Over a 24 hour period, that would be 13.8 million requests.

Average / Median Response Time

The response time over the course of the test was also quite good. Initially it hovered around 35ms on average, but as resource contention on the server increased it leveled out at around 140ms. Not too bad for $5 and nearly zero configuration.

Response Time Distribution

Finally we come to the response time distribution. You can see here that 50% of requests finished in under 100ms, 99% finished in under 700ms, and all requests finished by 1800ms. These are good numbers.

Final Thoughts

If you need to host a WordPress site and don’t want to much around with configuration, the Vultr One-Click WordPress service is pretty good. In the long-term you’ll still need to know a little about system administration to apply updates, but it is definitely a great place to start and gets you a lot of the way to a fully functioning WordPress site.

What’s New With Kernl – March 2020

With all the uncertainty in the world right now due to COVID-19, we are intentionally keeping things boring at Kernl. Bug fixes, new docs, and increased capacity are all we did this month.

Stay safe out there everyone!

Features, Bugs, Updates

  • NEW DOCUMENTATION! – After 5 years we finally moved to a real documentation generator! In the process of moving docs to the new system, all of the docs were updated and checked for accuracy. Check it out at
  • Site Health – You can now change you wp-json root. Some people change this for security reasons. Site Health needs it for some of the more advanced functionality.
  • Site Health Timezone Bugs – Timezones are hard and our Site Health service wasn’t using them correctly.
  • Analytics VM Changes – The Kernl Analytics service was starting to get bogged down with increased traffic. It now has 2 vCPUs and 2GB of RAM (up from 1 vCPU and 1GB).
  • Analytics Bug – We were logging analytics data for customers that aren’t paying for it. This is no longer the case.
  • Plugin/Theme Git Status – The plugin and theme list pages were displaying inconsistent results for the Git status of plugins/themes. There was an error in our Mongo query that populated this data which has been resolved.
  • Load Testing Remain Resources – The remaining resources page can take a while to load sometimes because we have to call out to external services. An indeterminate loading spinner was added to let customers know that it’s still working.
  • System Updates – All operating system level packages have been upgraded to their latest available version.
new documentation by docsify
New documentation by Docsify