Apache -vs- Nginx. 2015 Edition

In Web Servers by Aurimas Mikalauskas1 Comment

apache -vs- nginx
The choice used to be clear:

  • You want convenience – go with Apache
  • If you want speed – then it’s Nginx

Or lighttpd. Or whatever, but NOT Apache web server. Sometimes they were even used in conjunction – Nginx on the front, to spoon-feed slower client connections and serve static content (using almost no memory for that), and Apache at the back, to generate dynamic content.

Digital ocean has covered the practical considerations of running one or the other (or both) very nicely, so I’m not going to. What I am going to tell you though is that it is outdated. Long gone the days when Nginx had a significant advantage over Apache.

If you run a dynamic website, such as WordPress, Apache can now be just as good in terms of speed, so instead of rushing over to Nginx, I’d like to suggest an alternative approach.

Disclaimer: this article is mostly focused on websites running on PHP, it is however also relevant to those running dynamic websites using any other apache module, such as mod_python, mod_ruby, mod_perl etc.

What was wrong with Apache

You know what used to be the main problem with Apache? It’s that it was only possible to serve dynamic websites through Apache modules. For example, to serve a PHP-based website, Apache would use a module called mod_php (module, that many websites use to this day) and that module used heaps of memory (pun intended).

Yet the actual problem was that one httpd process was only able to handle one connection at a time (think of httpd process as a separate program on your server that doesn’t like sharing resources with other programs).

So even if you were only serving static files such as css files, javascripts or images, Apache used separate processes to serve them, and all the extra memory. Whereas Nginx used so called events-based architecture that allowed single process to handle hundreds of connections.

What you may not know though, is that in version 2.4 (which has been around since 2012), Apache can now use the same method to handle connections, which Nginx used to be famous for.

Yes, now a single Apache process can handle tens, hundreds or even thousands of connections.


To prove it, I want to share results from two sets of benchmarks I ran with each web server:

  1. Serving static content
  2. Serving dynamic content

Both benchmarks were done on the same 4-core machine with 7.5G of RAM, configured to best of my knowledge.

Serving static content

Let’s start with static files. For this test, I used the same 150kb jpeg image file and I just kept fetching it at an increasing number of parallel requests using ab.

One thing I was interested in was how many such requests each one will handle per second. Here’s a result that says it all:

0 req/s
@ 512 parallel requests
0 req/s
@ 512 parallel requests

I take it you’re laughing out loud right now. Clearly Nginx smashed Apache into pieces. Well laugh no more and here’s why: unless your server is only serving static content, this benchmark is pretty much irrelevant.

Let me say that again
The results of this bechmark are only interesting if you are using your server for static content mostly rather than generating PHP or some other dynamic content.

If you are indeed serving static content only, then by all means go with Nginx, especially if you’re either already running more than one server, or considering running one more because your current static content server can hardly keep up.

Otherwise, here’s one thing from this particular benchmark that did interest me: how much memory will the server consume during the test? Here’s the result:

Server memory usage with Apache
Server memory usage with Nginx

The reason it is interesting, is that with a typical Apache configuration (e.g. mod_php), such a test would have killed Apache almost instantly.

Apache would have used the entire server memory and the server would have slowed down to a crawl. As a safeguard, one would likely have configured it to only serve a hundred or so requests in parallel, but then a lot of the requests would’ve been queued up and, consequentially, they would’ve take even more time to complete.

To summarize the results of this first test, when configured properly, Apache is now capable of handling an impressive amount of concurrent requests with very low memory footprint and in that regard, it is an acceptable choice even if your server is only serving static files.

Serving dynamic content

This is where things get really exciting.

If you are considering Apache or Nginx for your dynamic website, be it WordPress, Joomla, Drupal or any other 3rd party or in-house web app, what your server will be doing most of the time is running code.

In fact, the amount of time spent serving static files will be disproportionally low compared to dynamic content, therefore it’s way more important to see how well can Apache handle dynamic content and how that compares to Nginx.

Drumroll, please!

0 req/s
@ 16 parallel requests
0 req/s
@ 16 parallel requests

Exactly! They’re the same.

And the reason results are the same is that both Apache and Nginx are pretty much sleeping during this test. All they do is pass the request on to php-fpm (we’ll talk about it more later), wait for a response and then send it back to the user. And while they wait, they can keep serving static files without any need to launch extra processes for that.

In terms of memory, both servers have used the same amount of memory too.

So, when it comes to dynamic websites, Apache is now just as good an alternative as Nginx or any other events-based web server. And the reason is exactly that – Apache can now use events-based approach too, as long as you configure it to do so.

Configuring Apache Properly

I mentioned in the beginning that Apache can be configured to use events instead of processes since version 2.4. Truth is, it has been available since 2.2, except that in version 2.2 it was considered experimental and in order to use this new approach, you would have to rebuild the server. Let’s not go down that path and switch to 2.4 instead (if you have not done so yet).

Before we configure Apache though, we must first set up php-fcgi. We’ll use php-fpm (which stands for PHP FastCGI Process Manager) that will act as a server that we’ll be forward requests to for PHP processing.


Depending on the OS and repository you are using, the actual command to get php-fpm installed will be different. I will assume CentOS/RHEL 6 but feel free to adapt it to your distribution of choice. On CentOS you would install it with:

There are several configuration files involved (could vary between different distributions):

We’ll use a stock configuration file /etc/php-fpm.d/www.conf and we’ll make a few small changes:

Also it’s good to know what the main php-fpm controls are:

Once you’re done with the changes, start it and configure to start during server startup:


First, check the version of Apache httpd server you are using (httpd -V should do it) and if you’re still on 2.2, let’s set up 2.4. One way to do it on CentOS 6 is through “CentOS Software Collections”:

It will install Apache 2.4 with all of the files and configuration under /opt/rh/httpd24/root/etc/httpd/. I’ll leave all of the standard configuration options for you to handle (there’s usually not much to change there anyways), but here’s what you want to do to start using events-based architecture:

Now create a new file, say, 05-php.conf to configure Apache to php-fpm interface:

And start the server:

If you’re upgrading from 2.2, it’s probably a good idea to first start this new Apache on an alternative port, say 81 (that’s maybe as simple as changing Listen directive) and test it before you commit to the change. Once you’re good with it though, stop the old apache and reconfigure the startup options:


Apache httpd is a great web server and the new mpm_event module takes it to entirely new heights. Nginx can still outdo Apache in some edge cases (i.e. serving static content only), but when it comes to dynamic websites, which most of the web 2.0 is built on, Apache is now just as good of a choice as Nginx. And if you are already running mpm_event based configuration, I’d recommend to focus your optimization efforts elsewhere rather than looking at Nginx as an opportunity.

Share this Post

Follow Speedemy

I believe that providing the best user experience is the key to business success. Big part of that is making online systems fast, stable and reliable. On Speedemy.com, I am sharing best practices and tested methods that I have used for the last 12 years working as an architect of scalable systems and database performance consultant.

If you too are looking to improve the speed and reliability of your system, let's stay in touch:

No spam, ever! Unsubscribe at any time. Powered by ConvertKit