The first version of the Apache HTTP server appeared in 1995. Today, more than 20 years later, the software continues to reign as the king of web servers – but not without com­pet­i­tion. In par­tic­u­lar, the Russian web server NGINX (pro­nounced “Engine-X”), also an open source project, is gaining market share – and at breakneck speed. What’s most harmful for the Apache Found­a­tion: Most of the websites that do well in the Alexa rankings today are already delivered via NGINX. You can see regularly-updated web server usage stat­ist­ics from W3Techs. It’s not just Russian internet giants, such as the search engines Ramblex and Yandex, the e-mail service Mail.RU, or the social network VK that rely on the light­weight web server; in­ter­na­tion­al providers such as Dropbox, Netflix, WordPress, and FastMail.com also use NGINX to improve the per­form­ance of their services. Will the Apache HTTP server be outdated soon?

Note

The Apache HTTP server is a software project operated under the spon­sor­ship of the Apache Found­a­tion. In the economic terms of the internet community, the name of web server is usually shortened to just “Apache”. We will also follow this con­ven­tion: In the following guide, “Apache” will be used to mean the software, not the man­u­fac­turer.

The challenge of Web 2.0

Owen Garrett, Head of Products at Nginx, Inc., describes the Apache web server in a blog post from October 9, 2015 as the “backbone” of Web 1.0 and em­phas­ises its sig­ni­fic­ance for the de­vel­op­ment of the internet around the turn of the mil­len­ni­um. The large success of the web server is primarily at­trib­uted to the simple ar­chi­tec­ture of the software. However, this is based on design decisions that cor­res­pond to a World Wide Web that can’t be compared with today’s decisions. Twenty years ago, websites were con­sid­er­ably more simply built, bandwidth was limited and expensive, and CPU computing time was com­par­at­ively cheap.

Today we’re dealing with a second-gen­er­a­tion World Wide Web, which is shown from a com­pletely different angle: The number of users and web traffic worldwide have mul­ti­plied. The same goes for the average size of websites on the internet and the number of com­pon­ents that a web browser needs to query and render to be able to present them. An in­creas­ing portion of the internet community has grown up with the pos­sib­il­it­ies of Web 2.0 since childhood. This user group is not familiar with waiting multiple seconds or even minutes for a website to download.

These de­vel­op­ments have re­peatedly posed chal­lenges to the Apache HTTP server in recent years. Owen Garrett blames the process-based ar­chi­tec­ture of Apache for this, as it can’t be scaled well in view of the rapidly in­creas­ing traffic volume. This dif­fi­culty was one of the main mo­tiv­a­tions for the de­vel­op­ment of NGINX in 2002, which takes a com­pletely different approach with its event-driven ar­chi­tec­ture. NGINX traces back to the Russian software developer Igor Sysoev who designed the software, which is used as a web server, reverse proxy and e-mail proxy, es­pe­cially for the needs of the Russian search engine Rambler.

We compare the two web servers side by side and look at their ar­chi­tec­tur­al dif­fer­ences, con­fig­ur­a­tion, and extension options, as well as com­pat­ib­il­ity, doc­u­ment­a­tion, and support.

Tip

You can find complete in­tro­duc­tions for both open source web servers in our com­par­is­on, as well as guides to their in­stall­a­tion and con­fig­ur­a­tion in our basics articles for Apache and NGINX.

Ar­chi­tec­tur­al dif­fer­ences

The web servers Apache and NGINX are based on fun­da­ment­ally different software ar­chi­tec­tures. Varying concepts are found in regard to con­nec­tion man­age­ment, con­fig­ur­a­tion, the in­ter­pret­a­tion of client requests, and the handling of static and dynamic web content.

Con­nec­tion man­age­ment

The open source web servers Apache and NGINX differ es­sen­tially in how they handle incoming client requests. While Apache runs on a process-based ar­chi­tec­ture, con­nec­tion man­age­ment with NGINX follows an event-driven pro­cessing algorithm. This makes it possible to handle requests resource-ef­fi­ciently, even if they’re received from a large number of con­nec­tions at the same time. This is cited – by the NGINX de­velopers, among others – as a big advantage over the Apache HTTP server. And from version 2.4 onwards, it also offers the pos­sib­il­ity of im­ple­ment­ing events. The dif­fer­ences, therefore, are in the details.

The Apache web server follows an approach where each client request is handled by a separate process or thread. With single-threading – the original operating mode of the Apache HTTP server – this is as­so­ci­ated with I/O blocking problems sooner or later: Processes that require read or write op­er­a­tions are executed in strict suc­ces­sion. A sub­sequent request will remain in the queue until the previous one has been answered. This can be avoided by starting several single-threading processes at the same time – a strategy as­so­ci­ated with high resource con­sump­tion.

Al­tern­at­ively, multi-threading mech­an­isms are used. As opposed to single-threading, where only one thread is available to answer client requests for each process, multi-threading offers the pos­sib­il­ity to run multiple threads in the same process. Since Linux threads require fewer resources than processes, multi-threading provides the ability to com­pensate for the large resource re­quire­ments of the process-driven ar­chi­tec­ture of the Apache HTTP server.

In­teg­ra­tion of mech­an­isms for parallel pro­cessing of client requests with Apache can be done using one of three multi-pro­cessing modules (MPMs): mpm_prefork, mpm_worker, mpm_event.

  • mpm_prefork: The Apache module “prefork” offers a multi-process man­age­ment on the basis of a single-threading mechanism. The module creates a parent process with an available supply of child processes. A thread runs in each child process that allows you to answer one client request at a time. As long as more single-thread processes are present than incoming client requests, the requests are processed sim­ul­tan­eously. The number of available single-threading processes are defined using the server con­fig­ur­a­tion options “Min­Spare­Serv­ers” and “Max­Spare­Serv­ers”. Prefork contains the per­form­ance drawbacks of single-threading that are mentioned above. One benefit, though, is the extensive in­de­pend­ence of the separate processes: If a con­nec­tion is lost due to a faulty process, it generally won’t affect the con­nec­tions being handled in the other processes.
  • mpm_worker: With the “worker” module, Apache users have an available multi-threading mechanism for parallel pro­cessing of client requests. How many threads can be started per process is defined using the server con­fig­ur­a­tion option “Thread­s­Per­Child”. The module provides one thread for each TCP con­nec­tion. As long as there are more threads available than incoming client requests, the requests are processed in parallel. The parent process (httpd) watches over idle threads.
    The commands “Min­SpareThreads” and “Max­SpareThreads” are available for users to define at which number of idle threads new threads will be created or running threads will be removed from the memory. The worker module has a much lower resource re­quire­ment than the prefork module. But since con­nec­tions aren’t handled in separate processes, a faulty thread can affect all con­nec­tions being processed in the same multi-thread process. Like prefork, worker is also sus­cept­ible to overload caused by so-called keep-alive con­nec­tions (see below).
  • mpm_event: With event, the Apache HTTP server has had a third multi-pro­cessing module available for pro­duct­ive use since version 2.4. This presents a variant of the worker module that dis­trib­utes the workload between started threads. A listener thread is used for each multi-threading process which receives incoming client requests and dis­trib­utes related tasks to worker threads.
    The event module was developed to optimise contact with keep-alive con­nec­tions, i.e. TCP con­nec­tions that are main­tained to allow the transfer of further client requests or server responses. If the classic worker module is used, worker threads usually maintain con­nec­tions that have been es­tab­lished once and so become blocked – even if no further requests are received. This can lead to an overload of the server with a high number of keep-alive con­nec­tions. The event module, on the other hand, out­sources the main­ten­ance of keep-alive con­nec­tions to the in­de­pend­ent listener thread. Then, worker threads are no longer blocked and are available to process further requests.

The following graphic shows a schematic rep­res­ent­a­tion of the process-based ar­chi­tec­ture of the Apache web server using a worker module:

Depending on which module is used, Apache solves the con­cur­rency problem (the sim­ul­tan­eous answer of multiple client requests) by adding either ad­di­tion­al processes or threads. Both solution strategies involve ad­di­tion­al resource expense. This becomes a limiting factor for the scaling of an Apache server.

The enormous resource appetite of the one-process-per-con­nec­tion approach results from the fact that a separate runtime en­vir­on­ment must be provided for each ad­di­tion­al process. This requires the al­loc­a­tion of CPU time and separate storage. Each Apache module that’s available to a worker process also has to be loaded sep­ar­ately for each process. Threads, on the other hand, share an execution en­vir­on­ment (the program) and address space in the memory. The overhead of ad­di­tion­al threads is therefore con­sid­er­ably less than that of processes. But multi-threading is com­pu­ta­tion-intensive, too, when context switches are used.

A context switch means the process of switching from one process or thread to another in a system. To do this, the context of the ter­min­ated process or thread must be saved and the context of the new process or thread must be created or restored. This is a time-intensive ad­min­is­trat­ive process, in which the CPU register as well as various tables and lists need to be loaded and saved.

The mpm_event module has an event mechanism available for the Apache HTTP server that transfers the pro­cessing of an incoming con­nec­tion to a listener thread. This makes it possible to terminate con­nec­tions that are no longer required (including keep-alive con­nec­tions) and so reduce resource con­sump­tion. This doesn’t solve the problem of com­pu­ta­tion-intensive context change that occurs when the listener thread passes requests to separate worker threads via its held con­nec­tions, though.

By contrast, NGINX’s event-based ar­chi­tec­ture realises con­cur­rency without requiring an ad­di­tion­al process or threat for each new con­nec­tion. A single NGINX process can handle thousands of HTTP con­nec­tions at the same time. This is achieved by means of a loop mechanism called the event loop. This makes it possible to asyn­chron­ously process client requests within a threat.

Tip

The­or­et­ic­ally, NGINX only uses one single-threading process when pro­cessing con­nec­tions. To optimally utilise the hardware, though, the web server is usually started with one work process per processor core (CPU) of the un­der­ly­ing machine.

As opposed to the Apache web server, where the number of active processes or threads is only limited using minimum and maximum values, NGINX offers a pre­dict­able process model that’s precisely tailoured to the un­der­ly­ing hardware. This includes a master process, the cache loader and cache manager helper processes, as well as a number of worker processes tailoured to the number of processor cores precisely defined by the con­fig­ur­a­tion.

  • Master process: The master process is a parent process that performs all basic op­er­a­tions. These include, among others, importing the server con­fig­ur­a­tion, port binding, and creating all following process types.
  • Helper processes: NGINX uses two helper processes for cache man­age­ment: cache loader and cache manager.
    • Cache loader: The cache loader is re­spons­ible for loading the hard drive-based cache into the memory.
    • Cache manager: The task of the cache manager is to make sure that entries from the hard drive cache have the pre­con­figured size, and to trim them if necessary. This process occurs peri­od­ic­ally.
  • Worker process: Worker processes are re­spons­ible for pro­cessing con­nec­tions, read and write access to the hard drive, and com­mu­nic­a­tion with upstream servers (servers that provide services to other servers). This means that these are the only processes in the NGINX process model that are con­tinu­ously active.

The following graphic is a schematic rep­res­ent­a­tion of the NGINX process model:

All worker processes started by the NGINX master process during con­fig­ur­a­tion share a set of listener sockets. Instead of starting a new process of thread for each incoming con­nec­tion, an event loop is run in every worker process that enables the asyn­chron­ous handling of thousands of con­nec­tions within one thread without blocking the process. To do this, the worker processes at the listener sockets con­tinu­ously listen for events triggered by incoming con­nec­tions, accept them, and execute read and write processes on the socket during the pro­cessing of HTTP requests.

NGINX doesn’t have its own mechanism available for the dis­tri­bu­tion of con­nec­tions to worker processes. Instead, core functions of the operating system are used. Schemes on how to handle incoming requests are provided by separate state machines for HTTP, raw TCP, SMTP, IMAP, and POP3.

In general, NGINX can be described as an event handler which receives in­form­a­tion about events from the core and tells the operating system how to handle the as­so­ci­ated tasks. The asyn­chron­ous pro­cessing of tasks with the event loop is based on even no­ti­fic­a­tions, callbacks, and timers. These mech­an­isms make it possible for a worker process to delegate one operation after the other to the operating system without having to wait idly for the result of an operation or for client programs to respond. NGINX functions as an or­ches­trat­or for the operating system, and takes over the reading and writing of bytes.

This type of con­nec­tion man­age­ment only creates a minimal overhead for ad­di­tion­al con­nec­tions. All that’s needed is an ad­di­tion­al file descriptor (FD) and a minimum of extra memory in the worker process. Com­pu­ta­tion-intensive context switches, on the other hand, only occur if no further events occur within an event loop. This ef­fi­ciency in the pro­cessing of requests over a variety of con­nec­tions makes NGINX the ideal load dis­trib­ut­or for highly fre­quen­ted websites such as WordPress.com.

Summary

With its event-driven ar­chi­tec­ture, NGINX offers an al­tern­at­ive to the process-based con­nec­tion man­age­ment of the Apache HTTP server. But this isn’t enough to explain why NGINX performs so well in benchmark tests. Apache, since version 2.4, also supports an event-based pro­cessing mechanism for client requests. When comparing web servers, such as Apache vs. NGINX, always pay attention to which modules the web servers are used with in the test, how they’re con­figured, and which tasks have to be mastered.

Dealings with static and dynamic web content

When it comes to dynamic web content, NGINX also follows a different strategy than the Apache HTTP server.

In principle: To be able to deliver dynamic content, a web server needs to have access to an in­ter­pret­er that’s capable of pro­cessing a required pro­gram­ming language, such as PHP, Perl, Python, or Ruby. Apache has various modules available, including mod_php, mod_perl, mod_python, or mod_ruby, which make it possible to load the cor­res­pond­ing in­ter­pret­er directly into the web server. As a result, Apache itself is equipped with the ability to process dynamic web content created with the cor­res­pond­ing pro­gram­ming language. Functions for the pre­par­a­tion of static content are already im­ple­men­ted with the above-mentioned MPM module.

NGINX, on the other hand, only offers mech­an­isms for de­liv­er­ing static web content. The pre­par­a­tion of dynamic content is out­sourced to a spe­cial­ised ap­plic­a­tion server. In this case, NGINX only functions as a proxy between the client program and upstream server. The com­mu­nic­a­tion takes place via protocols like HTTP, FastCGI, SCGI, uWSGI, and Memcached. Possible ap­plic­a­tion servers for de­liv­er­ing dynamic content are offered by WebSphere, JBoss, or Tomcat. The Apache HTTP server can also be used for this purpose.

Both strategies for de­liv­er­ing static and dynamic content come with their benefits and drawbacks. A module like mod_php allows the web server to execute PHP code itself. A separate ap­plic­a­tion server isn’t needed. This makes the ad­min­is­tra­tion of dynamic website very simple. But the in­ter­pret­er modules for dynamic pro­gram­ming languages have to be loaded sep­ar­ately into each worker process that’s re­spons­ible for de­liv­er­ing content. With a large number of worker processes, this is as­so­ci­ated with a sig­ni­fic­ant overhead. This overhead is reduced by NGINX, since the out­sourced in­ter­pret­er is only called upon when required.

While NGINX is set to interact with an out­sourced in­ter­pret­er, Apache users can choose either of these two strategies. Apache can also be placed in front of an ap­plic­a­tion server that’s used to interpret dynamic web content. Usually, the protocol FastCGI is used for this. A cor­res­pond­ing interface can be loaded with the module mod_proxy_fcgi.

Summary

With both web servers in our com­par­is­on, dynamic content is delivered. But while Apache in­ter­prets and executes program code itself using modules, NGINX out­sources this step to an external ap­plic­a­tion server.

In­ter­pret­a­tion of client requests

To be able to sat­is­fact­or­ily answer requests from client programs (for example, web browsers or e-mail programs), a server needs to determine which resource is requested and where it’s found based on the request.

The Apache HTTP server was designed as a web server. On the other hand, NGINX offers web as well as proxy server functions. This dif­fer­ence in focus is reflected in the way that the software in­ter­prets client requests and allocated resources on the server.

Note

The Apache HTTP server can also be set up as a proxy server with the help of the mod_proxy module.

Apache HTTP server and NGINX both have mech­an­isms that allow incoming requests to either be in­ter­preted as physical resources in the file system or as URIs (Uniform Resource In­den­ti­fi­er). But while Apache works based on files by default, URI-based request pro­cessing is more prominent with NGINX.

If the Apache HTTP server receives a client request, it assumes by default that a par­tic­u­lar resource is to be retrieved from the server’s file system. Since Apache uses Vir­tu­al­Hosts to provide different web content on the same server under different host names, IP addresses, or port numbers, it must first determine which Vir­tu­al­Host the request is referring to. To do this, the web server matches the host name, IP address, and port number at the beginning of the request URI with the Vir­tu­al­Hosts defined in the main con­fig­ur­a­tion file httpd.conf.

The following code example shows an Apache con­fig­ur­a­tion where the two domains www.example.com and www.other-example.com are operated under the same IP address:

NameVirtualHost *:80
<VirtualHost *:80>
ServerName www.example.com
ServerAlias example.com *.example.com
DocumentRoot /data/www/example
</VirtualHost>
<VirtualHost *:80>
ServerName www.other-example.com
DocumentRoot /data/www/other-example
</VirtualHost>

The asterisk (*) serves as a place­hold­er for an IP address. Apache decides which Doc­u­ment­Root (the starting directory of a web project) the requested resource will be searched in by comparing the host name contained in the request with the Server­Name directive.

If Apache finds the desired server, then the request URI is mapped to the file system of the server by default. Apache uses the path spe­cific­a­tion contained in the URI for this. In com­bin­a­tion with the Doc­u­ment­Root, this amounts to the resource path.

For a request with the request URI "http://www.example.org:80/public_html/images/logo.gif", Apache would search for the desired resource under the following file path (based on the example above):

/data/www/example/public_html/images/logo.gif
Note

Since the standard port for HTTP is 80, this spe­cific­a­tion is usually left out.

Apache also matches the request URI with optional file and directory blocks in the con­fig­ur­a­tion. This makes it possible to define special in­struc­tions for requests that lead to the selected files or dir­ect­or­ies (including sub­dir­ect­or­ies).

In the following example, special in­struc­tions are defined for the directory public_html/images and the file private.html:

<VirtualHost *:80>
    ServerName www.example.com
    ServerAlias example.com *.example.com
    DocumentRoot /data/www/example
      <Directory var/www/example.com/public_html/images>
          Order Allow,Deny
          Allow from all
     </Directory> 
      <Files public.html>
          Order Allow,Deny
          Deny from all
      </Files>
</VirtualHost>

In addition to this standard procedure for in­ter­pret­ing client requests, Apache offers the alias directive, which allows you to specify an alternate directory to search for the requested resource instead of the Doc­u­ment­Root. With mod_rewrite, the Apache HTTP server also provides a module that allows users to rewrite or forward URLs.

Tip

Find out more about the server module mod_rewrite in our basics article on the topic rewrite engine.

If you want Apache to retrieve resources that are stored outside of the server’s file system, use the location directive. This allows the defin­i­tion of in­struc­tions for specific URIs.

What rep­res­ents the exception for Apache is the standard case for NGINX. First, NGINX parses the request URI and matches it with server and location blocks in the web server con­fig­ur­a­tion. Only then (if necessary) does a mapping to the file system and com­bin­a­tion with the root (com­par­able to the Doc­u­ment­Root of the Apache server) take place.

Using the server directive, NGINX de­term­ines which host is re­spons­ible for answering the client request. The server block cor­res­ponds to a Vir­tu­al­Host in the Apache con­fig­ur­a­tion. To do this, the host name, IP address, and port number of the request URI are matched with all server blocks defined in the web server con­fig­ur­a­tion. The following code example shows three server blocks within the NGINX con­fig­ur­a­tion file nginx.conf:

server {
    listen 80;
    server_name example.org www.example.org;
    ...
}
server {
    listen 80;
    server_name example.net www.example.net;
    ...
}
server {
    listen 80;
    server_name example.com www.example.com;
    ...
}
Note

Each server block usually contains a row of location blocks. In the current example, these are replaced with the place­hold­er (…).

The request URI isn’t matched with the location blocks within a server block until the requested server has been found. For this, NGINX reads the specified location blocks and searches for the location that best matches the request URI. Each location block contains specific in­struc­tions that tell NGINX how the cor­res­pond­ing request is to be processed.

Locations can be set to be in­ter­preted as a prefix for a path, as an exact match, or as a regular ex­pres­sion (RegEx). In the syntax of the server con­fig­ur­a­tion, the following modifiers are used:

No modifier The location is in­ter­preted as a prefix. All requests whose URIs have the prefix defined in the location directive are con­sidered a match with the location. If no specific location is found, the request is processed according to the in­form­a­tion in the location block.
= The location is in­ter­preted as an exact match. All requests whose URIs match exactly with the string specified in the location directive are processed according to the in­form­a­tion in the location block.
 ~ The location is in­ter­preted as a regular ex­pres­sion. All requests whose URIs match the regular ex­pres­sion are processed according to the in­form­a­tion in the location block. Upper- and lower-case letters are evaluated for the match (case-sensitive).
~* The location is in­ter­preted as a regular ex­pres­sion. All requests whose URIs match the regular ex­pres­sion are processed according to the in­form­a­tion in the location block. Upper- and lower-case letters are not evaluated for the match (case-in­sens­it­ive).

The following example shows three location blocks which display how the in­form­a­tion for the domains 'example.org' and 'www.example.org' are to be processed:

server {
    listen 80;
    server_name example.org www.example.org;
    root /data/www;
    location / {
        index index.html index.php;
    }
    location ~* \.(gif|jpg|png)$ {
        expires 30d;
    }
location ~ \.php$ {
        fastcgi_pass localhost:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

Based on a client request with the request URI 'http://www.example.org:80/logo.gif', NGINX would proceed as follows to interpret the requests and deliver the desired resource:

http://www.example.org:80/logo.gif
http://www.example.org:80/index.php

First, NGINX de­term­ines the specific prefix location. To do this, the web server reads all locations with modifiers in sequence and stops at the first location that matches the request. Then all locations are read out that are marked with the RegEx modifier (~). The first match is also used here. If no matching RegEx location is found, then the web server uses the pre­vi­ously de­term­ined prefix location as a fallback.

The request URI 'http://www.example.org:80/logo.gif' matches, for example, with the prefix location / as well as with the regular ex­pres­sion \.(gif|jpg|png)$. NGINX would therefore map the request in com­bin­a­tion with the root to the file path /data/www/logo.gif and deliver the cor­res­pond­ing resource to the client. The expired header indicates when an answer is con­sidered obsolete – in the current example, it’s after 30 days: expires 30d.

The request for the PHP page with the URI 'http://www.example.org:80/index.php' also matches the prefix location / and the RegEx location ~ \.php$, which receives pref­er­en­tial treatment. NGINX forwards the request to a FastCGI server that listens on localhost:9000 and is re­spons­ible for the pro­cessing of dynamic web content. The fastcgi_param directive sets the FastCGI parameter SCRIPT_FILENAME to /data/www/index.php. Then the file is run on the upstream server. The variable $document_root cor­res­ponds to the root directive, and the variable $fastcgi_script_name cor­res­ponds to the part of the URI that follows the host name and port number: /index.php.

This seemingly com­plic­ated procedure for in­ter­pret­ing client requests is due to the different fields of ap­plic­a­tion in which NGINX is used. As opposed to the primarily file-based approach of the Apache HTTP server, the URI-based request in­ter­pret­a­tion enables more flex­ib­il­ity with the pro­cessing of different request patterns. This is required, for example, when NGINX is being run as a proxy or mail-proxy server instead of as a web server.

Summary

Apache is mainly used as a web server, and in­ter­prets client requests with a primarily file-based method. NGINX, on the other hand, works with URIs by default and so is also suited to other request patterns.

Con­fig­ur­a­tion

NGINX is said to have a tre­mend­ous speed advantage over the Apache HTTP server when it comes to de­liv­er­ing static web content. This is partly due to dif­fer­ence in con­fig­ur­a­tion. In addition to the main con­fig­ur­a­tion file httpd.conf, the Apache web server gives ad­min­is­trat­ors the option of directory-level man­age­ment. This uses .htaccess files. In principle, these de­cent­ral­ised con­fig­ur­a­tion files can be im­ple­men­ted in any server directory that you want. In­struc­tions, which are defined in an .htaccess, indicate which directory the con­fig­ur­a­tion file contains as well as its sub­dir­ect­or­ies. In practice, .htaccess files are used to restrict directory access to specific user groups, set up password pro­tec­tion, or define reg­u­la­tions for directory browsing, error messages, for­ward­ing, or alternate content. Note that this can also be con­figured centrally in the httpd.conf file. But .htaccess becomes relevant in web hosting models such as shared hosting, where access to the main con­fig­ur­a­tion file is reserved for the hosting service provider. The de­cent­ral­ised con­fig­ur­a­tion via .htaccess makes it possible to allow users to permit ad­min­is­tra­tion for par­tic­u­lar areas of the server file system – for example, for selected project dir­ect­or­ies – without giving access to the main con­fig­ur­a­tion. Changes also take effect im­me­di­ately without requiring a restart. NGINX, on the other hand, only offers central con­fig­ur­a­tion pos­sib­il­it­ies. All in­struc­tions are defined in the nginx.conf file. With access to this file, a user gains control over the entire server. In contrast to apache, the ad­min­is­trat­ive access is not limited to selected dir­ect­or­ies. This has ad­vant­ages as well as dis­ad­vant­ages. The central con­fig­ur­a­tion of NGINX is less flexible than the concept used by the Apache HTTP server, but it offers a clear security advantage: Changes to the con­fig­ur­a­tion of the web server can only be made by users who are given root per­mis­sions. More important than the security argument, though, is the per­form­ance dis­ad­vant­age of using a de­cent­ral­ised con­fig­ur­a­tion via .htaccess. The developer has already re­com­men­ded in the Apache HTTP server doc­u­ment­a­tion re­frain­ing from using .htaccess if access to httpd.conf is possible. The reason for this is the procedure that Apache uses to read and interpret con­fig­ur­a­tion files. As pre­vi­ously mentioned, Apache follows a file-based scheme for answering client requests by default. Since the Apache ar­chi­tec­ture allows a de­cent­ral­ised con­fig­ur­a­tion, the web server searches through every directory along the file path on the way to the requested resource for an .htaccess file. All con­fig­ur­a­tion files that it passes are read and in­ter­preted – a process that sig­ni­fic­antly slows down the web server.

Note

In principle, Apache ad­min­is­trat­ors are free to choose whether to use the de­cent­ral­ised con­fig­ur­a­tion options of the web server and accept the as­so­ci­ated ad­vant­ages and dis­ad­vant­ages. In the doc­u­ment­a­tion, the developer stresses that all .htaccess con­fig­ur­a­tions can also be un­der­taken in the main con­fig­ur­a­tion httpd.conf using directory blocks.

Users who want to disable or limit the de­cent­ral­ised con­fig­ur­a­tion on Apache can use the directive Al­lo­wOver­ride in the directory blocks of the main con­fig­ur­a­tion file httpd.conf and set them to None. This allows the web server to ignore all .htaccess files in the cor­res­pond­ing con­figured dir­ect­or­ies.

<VirtualHost *:80>
    ServerName example.com;
    ...
    DocumentRoot /data/www/example
      <Directory /data/www/example>
        AllowOverride None
        ...
      </Directory>
    ...
</VirtualHost>

The example con­fig­ur­a­tion indicates to the web server that all .htaccess files for the host example.com should be ignored.

Summary

As opposed to NGINX, which is only centrally con­figured, Apache offers the option with .htaccess for de­cent­ral­ised, directory-based con­fig­ur­a­tion. If .htaccess files are used, however, the web server loses speed.

Extension pos­sib­il­it­ies

Both web servers in our com­par­is­on run on a modular system in which the core system can be extended with ad­di­tion­al com­pon­ents as needed. Up to version 1.9.10, though, NGINX pursued a fun­da­ment­ally different strategy for dealing with modules than the competing product. The Apache HTTP server has two available options for extending the core software. Modules can either be compiled into the Apache binary files during de­vel­op­ment or they can be loaded dy­nam­ic­ally during runtime. There are three cat­egor­ies of Apache modules:

  • Basic modules: The Apache basic modules include all com­pon­ents that provide the core func­tion­al­it­ies of the web server.
  • Extension modules: These ex­ten­sions are modules of the Apache Found­a­tion that are included as part of the Apache dis­tri­bu­tion. An overview of all modules contained in the Apache 2.4 standard in­stall­a­tion is available in the Apache doc­u­ment­a­tion.
  • Third-party modules: These modules are not from the Apache Found­a­tion, but instead provided by external service providers or in­de­pend­ent pro­gram­mers.

NGINX, on the other hand, limited the mod­u­lar­ity for a long time to static extension com­pon­ents that had to be compiled into the binary file of the software core. This type of software extension sig­ni­fic­antly re­stric­ted the flex­ib­il­ity of the web server, es­pe­cially for users who weren’t used to managing their own software com­pon­ents without the package manager of the re­spect­ive dis­tri­bu­tion. The de­vel­op­ment team made massive im­prove­ments in this respect: Since version 1.9.11 (Release 09 Feb 2016), NGINX supports mech­an­isms that make it possible to convert static modules to dynamic so that they can be loaded via the con­fig­ur­a­tion file during runtime. In both cases, the module API of the server is used. Please note that not all NGINX modules can be converted into dynamic modules. Modules that patch the source code of the server software shouldn’t by dy­nam­ic­ally loaded. NGINX also limits by default the number of dynamic modules that can be loaded at the same time to 128. To increase this limit, set the NGX_MAX_DYNAMIC_MODULES constant to the desired value in the NGINX source code. In addition to the official modules of the NGINX doc­u­ment­a­tion, various third-party modules are available to users.

Summary

Both web servers can be modularly extended. Dynamic modules are available as well as static modules, which can be loaded into the running program as required.

Doc­u­ment­a­tion and support

Both software projects are well doc­u­mented and provide users with first-hand in­form­a­tion about wikis and blogs.

While the NGINX doc­u­ment­a­tion is only available in English and Russian, the Apache project has in­form­a­tion material in various language versions. Some of these are outdated, though, so a look at the English doc­u­ment­a­tion is necessary here too. Users can get help with problems for both open source projects through the community. For this purpose, mailing lists function as dis­cus­sion forums.

Trans­par­ent release plans and roadmaps give users the pos­sib­il­ity to adapt for future de­vel­op­ments. Software errors and security gaps for both projects are processed and recorded in a public bug report.

In addition to the NGINX open source project, Nginx, Inc. also offers the com­mer­cial product NGINX Plus. For an annual usage fee, users receive ad­di­tion­al functions as well as pro­fes­sion­al support from the man­u­fac­turer. A com­par­is­on matrix of both programs is found on the NGINX website. A com­mer­cial edition of the Apache HTTP serve doesn’t exist. Paid support services can be obtained from various third parties, though.

Summary

Both the Apache HTTP server and NGINX are ad­equately doc­u­mented for pro­fes­sion­al use on pro­duc­tion systems.

Com­pat­ib­il­ity and ecosystem

The Apache HTTP server has dominated the World Wide Web for more than two decades and, due to its market share, is still con­sidered the de facto standard for preparing web content. NGINX also has a 15-year success story to look back on. Both web servers are char­ac­ter­ised by wide platform support. While Apache is re­com­men­ded for all unix-like operating systems as well as for Windows, the NGINX doc­u­ment­a­tion cites the following systems as tested: FreeBSD, Linux, Solaris, IBM AIX, HP-UX, macOS, and Windows. As a standard server, Apache features broad com­pat­ib­il­ity with third-party projects. All relevant web standards can be in­teg­rated using modules. Most players on the web are also familiar with the concepts of Apache. Ad­min­is­trat­ors and web de­velopers usually implement their first projects on af­ford­able shared hosting platforms. These, in turn, are mostly based on Apache, and its pos­sib­il­ity of de­cent­ral­ised con­fig­ur­a­tion via .htaccess. The Apache HTTP server is also part of various open source program packages for de­vel­op­ment and software tests, such as XAMPP or AMPPS. A large ecosystem of modules is also available to NGINX users. In addition, the de­vel­op­ment team cul­tiv­ates part­ner­ships with various open source and pro­pri­et­ary software projects, as well as with in­fra­struc­ture service providers such as Amazon Web Services, Windows Azure, and HP.

Summary

Both web servers are es­tab­lished. Users can rely on a large ecosystem. Compared to NGINX, Apache has the advantage that a large user community has input itself into the basics of the web server over the years. The fact that thousands of ad­min­is­trat­ors have tested and improved the source code of the software doesn’t only speak for the security of the web server. New users also profit from the large number of ex­per­i­enced Apache ad­min­is­trat­ors who are available to help the community with problems via forums or mailing lists.

NGINX vs. Apache: an overview of the dif­fer­ences

Despite their large dif­fer­ences in software ar­chi­tec­ture, both web servers offer similar functions. Apache and NGINX are used in com­par­able scenarios, but use their own strategies and concepts to meet re­quire­ments. The following table compares both software projects based on their central features and shows their sim­il­ar­it­ies and dif­fer­ences.

Feature Apache NGINX
Function Web server Proxy server Web server Proxy server Email proxy Load balancer
Pro­gram­ming language C C
Operating system All unix-like platforms Windows FreeBSD Linux Solaris IBM AIX HP-UX macOS Windows
Release 1995 2002
Licence Apache Licence v2.0 BSD licence (Berkeley Software Dis­tri­bu­tion)
Developer Apache Software Found­a­tion Nginx, Inc.
Software ar­chi­tec­ture Process-/thread-based Event-driven
Con­cur­rency Multi-pro­cessing Multi-threading Event loop
Static web content Yes Yes
Dynamic web content Yes No
In­ter­pret­a­tion of client requests Primarily file-based URI-based
Con­fig­ur­a­tion Central con­fig­ur­a­tion via httpd.conf Decentral con­fig­ur­a­tion via .htaccess Central con­fig­ur­a­tion via nginx.conf
Extension pos­sib­il­it­ies Static modules Dynamic modules Static modules Dynamic modules
Doc­u­ment­a­tion German English Danish Spanish French Japanese Korean Por­tuguese Turkish Chinese German English
Developer support No Yes (Paid via Nginx, Inc.)
Community support Mailing lists Wiki Mailing lists Wiki

Summary

With Apache and NGINX, users have two stable, secure open source projects available to them. But after the com­par­is­on, neither of the web servers is the clear winner. Both projects are based on fun­da­ment­ally different design decisions that can be either an advantage or a dis­ad­vant­age, depending on how the software is used.

The Apache HTTP server offers an immense rep­er­toire of modules which, together with the flexible con­fig­ur­a­tion options, open numerous fields of ap­plic­a­tion for the software. The web server can also be a standard software for shared hosting scenarios and will continue to stand its ground in its field against light­weight web servers such as NGINX. The ability to directly integrate in­ter­pret­ers for pro­gram­ming languages such as PHP, Perl, Python, or Ruby into the web server using modules allows for dynamic web content to be delivered without the use of a separate ap­plic­a­tion server. This makes the Apache HTTP server a com­fort­able solution for small and medium-sized websites where content is dy­nam­ic­ally created during retrieval.

NGINX, on the other hand, doesn’t offer any pos­sib­il­it­ies to natively process dynamic web content or integrate cor­res­pond­ing in­ter­pret­ers via modules. A separate ap­plic­a­tion server is always required. This may seem like un­ne­ces­sary extra effort for small to medium-sized websites. However, such an ar­chi­tec­ture shows its strength for large web projects and in­creas­ing traffic volumes.

In general, NGINX is used as a load balancer in front of a group of ap­plic­a­tion servers. The load balancer accepts incoming requests and decides, depending on the type of request, whether it needs to be forwarded to a spe­cial­ised server in the back­ground. Static web content is delivered directly by NGINX. If a client requests dynamic content, then the load balancer gives the request to a dedicated ap­plic­a­tion server. This in­ter­prets the pro­gram­ming language, assembles the requested content into a webpage, and gives it back to the load balancer, which delivers it to the client. In this way, high traffic volumes can ef­fect­ively be managed.

NGINX caches already deliver content for a certain amount of time, so that newly requested dynamic content can be delivered directly by the load balancer without NGINX having to access an ap­plic­a­tion server again.

The out­sourcing of in­ter­pret­ers to one or multiple separate backend servers has the advantage that the server network can easily be scaled if ad­di­tion­al backend servers need to be added, or systems that are no longer necessary can be switched off. In practice, many users rely on a com­bin­a­tion of NGINX and Apache for such a setup, and use the strengths of both servers.

Go to Main Menu