I have a magento 1.9 installation About 100k products on a dedicated server with the below specs. I am curious if installing Nginx with Apache 2.4 will give performance gains? If so how should it be configured? I am not looking to uninstall Apache and only run Nginx in case anyone might suggest.

Server Specs/Software: Xeon E3-1271 v3 3.60GHz 250gb SSD raid 1 24gb ram CentOs 6 - 64Bit (v6.6) Apache (2.4) Percona (MySQL) (v5.6) PHP 5.5.25 (via PHP-FPM) Using Opcace fcgi


Most people run one or the other. Running them on the same server is a technical high jump and not for the faint of heart when it comes to SysAdmin issues.

The following is taken from a technical blog maintained at kbeezie.com:

Apache and Nginx Together

I’m not going to get into a lot of details about how to install and configure either http server from scratch. This article is primarily going to be food for thought for those who may want or need to configure nginx along side an existing apache (httpd) configuration. If you would rather ditch Apache all together, consider reading Martin Fjordvald’s Nginx Primer 2: From Apache to Nginx.

Side by Side

In some cases you may need to run both Apache (httpd) and Nginx on port 80. Such a situation can be a server running Cpanel/Whm and as such doesn’t support nginx, so you wouldn’t want to mess with the apache configuration at all.

To do this you have to make sure Apache and Nginx are bound to their own IP adddress, In the event of WHM/Cpanel based webserver, you can Release an IP to be used for Nginx in WHM. At this time I am not aware of a method of reserving an IP, and automatically forcing Apache to listen on a specific set of IPs in a control panel such as DirectAdmin or Plesk. But the link above will show you how with WHM/Cpanel.

Normally Apache will be listening on all interfaces, and such you may see a line like this in your httpd.conf file:

Port 80


Listen 80

Instead you’ll need to tell apache to listen on a specific IP (you can have multiple Listen lines for multiple IPs)


When you change Apache to listen on specific interfaces some VirtualHost may fail to load if they are listening on specific IPs themselves. The address option in only applies when the main server is listening on all interfaces (or an alias of such). If you do not have an IP Listed in your tag, then you do not need to worry bout this. Otherwise make sure to remove the addr:port from the VirtualHost tag.

Make sure to update the NameVirtualHost directive in Apache for name-based virtual hosts.

Once you have apache configured to listen on a specific set of IPs you can do the same with nginx.

server { listen; ... }

Now that both servers are bound to specific IPs, both can then be started up on port 80. From there you would simply point the IP of the domain to the server you wish to use. In the case of WHM/Cpanel you can either manually configure the DNS entry for the domain going to nginx in WHM, or you can use your own DNS such as with your registrar to point the domain to the specific IP. Using the latter may break your mail/ftp etc configurations if the DNS entries are not duplicated correctly.

Though normally if you are setting up Nginx side-by-side with apache, you’ll have your domain configurations separate from the rest of the system. The above paragraph only applies if the domain you are using has already been added by cpanel/whm and you wish to have it served by nginx exclusively. [Scroll down for PHP considerations]

Apache behind Nginx

If you are using a control panel based hosting such as cpanel/whm, this method is not advised. Most of the servers configuration is handled automatically in those cases, and making manual changes will likely lead to problems (plus you won’t get support from the control panel makers or your hosting provider in most cases).

Using Nginx as the primary frontend webserver can increase performance regardless if you choose to keep Apache running on the system. One of Nginx’s greatest advantage is how well it serves static content. It does so much more efficiently than Apache, and with very little cost to memory or processing. So placing Nginx in front will remove that burdern off Apache, leaving it to concentrate on dynamic request or special scenarios.

This method is also popular for those who don’t want to use PHP via fastcgi, or install a separate php-fpm process.

First thing that needs to be done is to change the interface apache listens on:


Above we bind Apache to the localhost on an alternate port, since only Nginx on the same machine will be communicating with Apache.

Note: Since Nginx needs to access the same files that Apache serves, you need to make sure that Nginx is setup to run as the same user as apache, or to make sure that the Nginx’s selected user:group has permission to read the web documents. Often times the webroot is owned by nobody or www-data and Nginx likewise can be setup to run as those users

Then in Nginx listening on port 80 (either on all interfaces such as or to specific IPs, your choice) we would need to configure Nginx to serve the same content. Take for example this virtual host in an apache configuration:

DocumentRoot "/usr/local/www/mydomain.com" ServerName mydomain.com ServerAlias www.mydomain.com CustomLog /var/log/httpd/mydomain_access.log common ErrorLog /var/log/httpd/mydomain_error.log ... In Nginx the equivalent server configuration would be:

server { root /usr/local/www/mydomain.com; server_name mydomain.com www.mydomain.com;

  # by default logs are stored in nginx's log folder
  # it can be changed to a full path such as /var/log/...
  access_log logs/mydomain_access.log;
  error_log logs/mydomain_error.log;


The above would serve all static content from the same location, however PHP will simply come back as PHP source. For this we need to send any PHP requests back to Apache.

server { root /usr/local/www/mydomain.com; server_name mydomain.com www.mydomain.com;

  access_log logs/mydomain_access.log;
  error_log logs/mydomain_error.log;

  location / { 
        # this is the location block for the document root of this vhost

  location ~ \.php {
        # this block will catch any requests with a .php extension
        # normally in this block data would be passed to a FastCGI process

        # these two lines tell Apache the actual IP of the client being forwarded
        # Apache requires mod_proxy (http://bit.ly/mod_proxy) for these to work
        # Most Apache 2.0+ servers have mod_proxy configured already

        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;

        # this next line adds the Host header so that apache knows which vHost to serve
        # the $host variable is automatically set to the hostname Nginx is responding to

        proxy_set_header Host $host;

        # And now we pass back to apache
        # if you're using a side-by-side configuration the IP can be changed to
        # apache's bound IP at port 80 such as


   # if you don't like seeing all the errors for missing favicon.ico in root
   location = /favicon.ico { access_log off; log_not_found off; }

   # if you don't like seeing errors for a missing robots.txt in root
   location = /robots.txt { access_log off; log_not_found off; }

   # this will prevent files like .htaccess .htpassword .secret etc from being served
   # You can remove the log directives if you wish to
   # log any attempts at a client trying to access a hidden file
   location ~ /\. { deny all; access_log off; log_not_found off; }

} In the case of rewriting (mod_rewrite) with apache behind nginx you can use an incredibly simple directive called try_files. Here’s the same code as above, but when changes made so that any files or folder not found by nginx gets passed to apache for processing (useful for situations like WordPress, or .htaccess based rewrites when the file or folder is not caught by Nginx)

server { root /usr/local/www/mydomain.com; server_name mydomain.com www.mydomain.com;

  access_log logs/mydomain_access.log;
  error_log logs/mydomain_error.log;

  location / { 
        # try_files attempts to serve a file or folder, until it reaches the fallback at the end
        try_files $uri $uri/ @backend;

  location @backend {
        # essentially the same as passing php requests back to apache

        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
  # ... The rest is the same as the configuration above ... 

} With the above configuration, any file or folder that exists will be served by Nginx (the php block will catch files ending in .php), otherwise it will be passed back to apache on the backend.

In some cases you may wish for everything to be passed to Apache unless otherwise specified, in which case you would have a configuration such as this:

server { root /usr/local/www/mydomain.com; server_name mydomain.com www.mydomain.com;

  access_log logs/mydomain_access.log;
  error_log logs/mydomain_error.log;

  location / {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;

        proxy_set_header Host $host;


  # Example 1 - Specify a folder and it's content
  # To serve everything under /css from Nginx-only
  location /css { }

  # Example 2 - Specify a RegEx pattern such as file extensions
  # Serve certain files directly from Nginx
  location ~* ^.+\.(jpg|jpeg|gif|png|css|zip|pdf|txt|js|flv|swf|html|htm)$
        # this will basically match any file of the above extensions
        # course if the file does not exist you'll see an Nginx error page as opposed
        # to apache's own error page. 

} Personally I prefer to leave Nginx to handle everything, and specify exactly what needs to be passed back to Apache. But the last configuration above would more accurately allow .htaccess to function during almost-every request since almost everything gets passed back to apache. The css folder or any files found by the other location block would be served directly by nginx regardless if there’s an .htaccess file there, since only Apache processes .ht* files.

PHP Considerations If you are not familiar with Nginx, then it should be noted that Nginx does not have a PHP module like apache’s mod_php, instead you either need to build PHP with FPM (ie: php-fpm/fastcgi), or you need to pass the request to something that can handle PHP.

In the case of using Nginx with Apache you essentially have two choices:

1) Compile and Install PHP-FPM, thus running a seperate PHP process to be used by Nginx. This option is usually good if you want to keep the two webserver configurations separated from each other, that way any changes to one won’t affect the other. But of course it adds additional memory usage to the system.

2) Utilize Apache’s mod_php. This option is ideal when you will be passing data to apache as a backend. Even in a side-by-side scenario, you can utilize mod_php by proxying any php request to Apache’s IP. But in the side-by-side scenario you have to make sure that Apache is also configured to serve the same virtualhost that Nginx is requesting.

Speed-wise both methods are about the same when PHP is configured with the same set of options on both. Which option you choose depends solely on your needs. Another article that may be of interest in relations to this one would be Nginx as a Proxy to your Blog, which can be just as easily utilized on a single server (especially if you get multiple IP ranges like I do).

  • this example has no cache zone, just proxy. so useless. – user2857 Jun 6 '15 at 9:50

apache + nginx is an old way. the only gain you will get if you configure your server with nginx as caching proxy, and point your subdomain like //cdn.myshop.com. then use it in magento admin for media|skin|js, this way you can even unset cookies..

but in this case even Varnish is better. so forget about this...

btw with your server specs, you should clarify what problems you actually have.

  • I wanted to decrease my time to first byte. Currently its around 2.5 seconds and I did not want to use Varnish just yet as I know it can cause problems and I don't have a dedicated developer yet. – Dan Jun 6 '15 at 13:08
  • so you are looking wrong way, TTFB is about optimizing php and mysql, not static assets – user2857 Jun 6 '15 at 14:20
  • I have did some SQL changes to my.cfn screenshot here: screencast.com/t/6G36z0npr But what other way can I optimize php than just increasing the memory limit? – Dan Jun 6 '15 at 16:30

I'm just posting my findings of reducing TTFB for your Magento store (I'm using Magento 1.9CE with a custom theme)

The best way to reduce your TTFB is caching, Lesti FPC is a good free Magento full page cache. Typically on my main store, I see 200ms TTFB with this enabled, and 1.2s TTFB without. Be careful of calling things such as additional product->load functions in things like your list.phtml - this significantly increases response time.

NGINX can be ran in front of apache, Plesk 12 uses this as it's default method of using NGINX. This does work, but you may experience issues under high requests. During load testing, I found 30 req/s was the max apache using mod-fastcgid, but with NGINX and PHP-FPM the max was around 90 req/s. Note that with an FPC enabled, we didn't see these sort of req/s with google analytics showing 400 active users on site (these tests are from loader.io, on a catalog page showing 40 products).

Also, the mod_fcgid / NGINX method used a lot more CPU load than the PHP-FPM / NGINX method under high traffic request periods, under low traffic mod_fcgid worked fine.

Cloudflare can also help with high traffic, it caches your images and static content, reducing the amount of requests directly to your server.

The main limitation of Magento beyond this, is CPU power. We don't experience any issues on front-end load after the forementioned cache methods, but the admin can be slower at times (~5-10s to save products) with the resultant PHP-FPM processes being under full CPU load in this period. We're using a dedicated server with E5-1620 v2 (3.9GHz 4cores)

Hope my ramblings assist you - many people conflict each other on here and other sites with what actually makes Magento faster, these are the only things that have worked for me so far

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.