Nginx – Upgrading and Migrating

How to install Chocolatey on Windows 10

Web technologies are evolving at a rapid pace and so is Nginx. Upgrading server-side software can be tricky, especially if the server is currently in use. If you have a web farm, you might not feel comfortable with the idea of upgrading the web servers while the visitors are still connected to it. However, with upgrades you get new features and bug fixes, and quite often the pain of upgrading is worth the effort. In this chapter you will learn about upgrading your web server in ways that shorten or remove the downtime. You will learn about the options available to you so that you can exercise them in different scenarios.

Controlling Nginx

To quickly reiterate, Nginx has one master process and one or more worker processes. If caching is enabled, the cache loader and cache manager processes also run at startup. The master process reads and evaluates the configuration files, and also maintains the worker processes. It is the worker process that does the actual processing of the requests. To stop or start Nginx, you send signals to the master process. When you run a command like nginx -s signal you basically tell the master process about your intentions.

There are four signals


  1. quit: Shut down Nginx gracefully.

  2. reload: Reload the configuration file in case you have made any changes and want them to come into effect. If the master process is not running, this command will simply error out because there is no process to honor this command. The reload command ensures a smooth completion of the old connections.

  3. reopen: Reopen the log files is useful in scenarios where you have want to move the write cursor to the end of the file. Now, why would you do that? There are utilities that regularly truncate the log files and create archives of what’s been truncated. So, if you use one such utility or you have edited the logs directly, you should reopen the log files to avoid any log corruption. Reopening puts the write marker to the end of the log file.

  4. stop: Shut down Nginx immediately. The difference between stop and quit is that quit is graceful but stop is not. When you say quit, Nginx finishes serving the open connections before it is shut down. stop, on the other hand, terminates all connections immediately.

The process id (PID) is written in a file called
nginx.pid, usually located in /var/run/nginx.pid. Execute a cat command as follows and notice that the PID

is same the running process.

$ cat /var/run/nginx.pid
$ ps -aux | grep nginx
root      9920  0.0  0.1  57792  1280 ?      Ss   06:55   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx     9922  0.0  0.1  58176  1964 ?      S    06:55   0:00 nginx: worker process
nginx     9923  0.0  0.1  57960  1708 ?       S    06:55   0:00 nginx: cache manager process

If you stop nginx ( nginx -s stop), the nginx.pid file gets deleted. But if you reload the configuration ( nginx -s reload), you will find that the file keep showing the old PID, proving that the master process was not recycled.

Command-Line Parameters

Before you could send a signal to Nginx, you must ensure that it is started. In the previous code block, you can see that nginx binary is located at /usr/sbin/nginx. To start Nginx use one of these methods:

  • /usr/sbin/nginx or nginx

  • /usr/sbin/nginx -t -c /some/other/config.conf -g “worker_processes 2;”

    • This command tells Nginx to test the configuration (-t) and load some other configuration file (-c). Apart from that, it also sets the worker_processes to 2 using the -g switch.

  • -? -h prints the help.

  • -v prints the version information.

  • -V prints the version information along with compiler information and configuration parameters.

If you try to use a global parameter that already exists in the configuration file

, you will get an error message like this:

sudo /usr/sbin/nginx -g "worker_processes 4;"
nginx: [emerg] "worker_processes" directive is duplicate in /etc/nginx/nginx.conf:2

The error message

tells you the file due to which it failed. Edit the file and remove the worker_processes directive. Try the commands now:

$ sudo kill nginx
$ sudo /usr/sbin/nginx -g "worker_processes 4;"
$ ps -aux | grep nginx
root     10846  0.0  0.1  57796  1244 ?      Ss   12:02   0:00 nginx: master process /usr/sbin/     nginx -g worker_processes 4;
nginx    10847  0.0  0.1  58176  1924 ?      S    12:02   0:00 nginx: worker process
nginx    10848  0.0  0.1  58176  1924 ?      S    12:02   0:00 nginx: worker process
nginx    10849  0.0  0.1  58176  1924 ?      S    12:02   0:00 nginx: worker process
nginx    10850  0.0  0.1  58176  1924 ?      S    12:02   0:00 nginx: worker process
nginx    10851  0.0  0.1  57960  1676 ?       S    12:02   0:00 nginx: cache manager process
nginx    10852  0.0  0.1  57960  1676 ?      S    12:02   0:00 nginx: cache loader process

Sure enough, it works and you can see all the processes. You can send signals to the master process or worker process in special cases:

sudo kill -SIGNAL $( cat /var/run/nginx.pid )

The -SIGNAL can be one of the following:

  • TERM, INT: Fast Shutdown

  • QUIT: Graceful Shutdown

  • HUP: Start new worker processes with a new configuration, and gracefully shut down the existing worker processes. Notice the following commands. The command spawns 2 worker processes and the HUP signal

    kills all processes except master process. The PID 2405 doesn’t change, but every other PID changes.

    $ sudo kill nginx
    $ sudo /usr/sbin/nginx -g "worker_processes 2;"
    $ ps -aux | grep nginx
    root      2405  0.0  0.1  57796  1140 ?        Ss   22:29   0:00 nginx: master process /usr/sbin/nginx -g worker_processes 2;
    nginx     2406  0.0  0.1  58176  1920 ?        S    22:29   0:00 nginx: worker process
    nginx     2407  0.0  0.1  58176  1920 ?        S    22:29   0:00 nginx: worker process
    nginx     2408  0.0  0.1  57960  1672 ?        S    22:29   0:00 nginx: cache manager process
    nginx     2409  0.0  0.1  57960  1672 ?        S    22:29   0:00 nginx: cache loader process
    $ sudo kill -HUP $( cat /var/run/nginx.pid )
    $ ps -aux | grep nginx
    root      2405  0.0  0.2  57920  2692 ?        Ss   22:29   0:00 nginx: master process /usr/sbin/nginx -g worker_processes 2;
    nginx     2415  0.0  0.2  58300  2048 ?        S    22:29   0:00 nginx: worker process
    nginx     2416  0.0  0.2  58300  2048 ?        S    22:29   0:00 nginx: worker process
    nginx     2417  0.0  0.1  58084  1796 ?        S    22:29   0:00 nginx: cache manager process
    nginx     2418  0.0  0.1  58084  1796 ?        S    22:29   0:00 nginx: cache loader process

You should note that this behavior happens only when the new configuration is found valid. To test this, edit your nginx.conf file and purposely introduce some junk text so that the configuration file is corrupt. Try sending the HUP signal again followed with ps -aux as shown below. The kill command appeared to have worked correctly, but the ps command shows that all the worker processes has the same PID as before. Clearly, the kill command didn’t kill the running worker processes and this is good. The reason is because the configuration file is faulty and you wouldn’t want a faulty configuration bringing the existing processes down. Nginx is smart and it kills the existing set of worker processes only when it is convinced that the new worker processes have spun and started taking requests.

$ sudo kill -HUP $( cat /var/run/nginx.pid )
$ ps -aux | grep nginx
root      2405  0.0  0.2  57920  2700 ?        Ss   22:29   0:00 nginx: master process /usr/sbin/nginx -g worker_processes 2;
nginx     2415  0.0  0.2  58300  2048 ?        S    22:29   0:00 nginx: worker process
nginx     2416  0.0  0.2  58300  2048 ?        S    22:29   0:00 nginx: worker process
nginx     2417  0.0  0.1  58084  1796 ?        S    22:29   0:00 nginx: cache manager process

There is a small problem with the approach, though. Since the kill command didn’t throw any error message, it becomes tricky to find out whether it actually worked and did what was intended. You can test the configuration with nginx -t before sending signals. Another approach would be to use
nginx -s reload:

$ sudo nginx -s reload
nginx: [emerg] unknown directive "aslkdj" in /etc/nginx/nginx.conf:6
  • USR1: Reopen log files.

  • USR2: You can upgrade to a new binary on the fly using USR2 signal. This approach is quite fascinating and effective. It is good that Nginx has this feature since the Nginx binaries are monolithic. If you remember, you have to compile the binaries with different switches since Nginx cannot load the modules dynamically. If you need to add a new module or upgrade to a later version, it becomes easier to test with this approach.

    Note Ensure that you have fixed the invalid configuration you introduced just a while ago.

    • At first, replace the old binary with a new one after taking the backup of the existing one.

    • Send USR2 signal sudo kill -HUP $( cat /var/run/nginx.pid ):

    $ sudo kill -USR2 $( cat /var/run/nginx.pid )
    • If you run the ps command again, you will find an output similar to the following. Notice how the previous configuration was used to launch another set of master processes and worker processes. The previous master process with the PID 2405 continues to run in parallel with PID 2519. The second master process launches another set of worker process, cache manager and the cache loader

      . This makes it possible to run two instances of Nginx in parallel, handling the incoming requests together.

    $ ps -aux | grep nginx
    root      2405  0.0  0.2  57920  2700 ?        Ss   22:29   0:00 nginx: master process /usr/sbin/nginx -g worker_processes 2;
    nginx     2415  0.0  0.2  58300  2048 ?        S    22:29   0:00 nginx: worker process
    nginx     2416  0.0  0.2  58300  2048 ?        S    22:29   0:00 nginx: worker process
    nginx     2417  0.0  0.1  58084  1796 ?        S    22:29   0:00 nginx: cache manager process
    root      2518  0.0  0.3  57796  3700 ?        S    22:58   0:00 nginx: master process /usr/sbin/nginx -g worker_processes 2;
    nginx     2519  0.0  0.1  58176  1920 ?        S    22:58   0:00 nginx: worker process
    nginx     2520  0.0  0.1  58176  1920 ?        S    22:58   0:00 nginx: worker process
    nginx     2521  0.0  0.1  57960  1672 ?        S    22:58   0:00 nginx: cache manager process
    nginx     2522  0.0  0.1  57960  1672 ?        S    22:58   0:00 nginx: cache loader process
  • WINCH: Now that you have a new instance running, you can check the requests and test the new configuration. If all is well, you may proceed to kill the original set of worker processes by sending the WINCH signal

    . Notice how the worker processes are killed but the master process is not. At this point only the new worker processes are running with the new configuration.

    $ sudo kill -WINCH 2405
    $ ps -aux | grep nginx
    root      2405  0.0  0.2  57920  2700 ?        Ss   22:29   0:00 nginx: master process /usr/sbin/nginx -g worker_processes 2;
    root      2518  0.0  0.3  57796  3700 ?        S    22:58   0:00 nginx: master process /usr/sbin/nginx -g worker_processes 2;
    nginx     2519  0.0  0.1  58176  1920 ?        S    22:58   0:00 nginx: worker process
    nginx     2520  0.0  0.1  58176  1920 ?        S    22:58   0:00 nginx: worker process
    nginx     2521  0.0  0.1  57960  1672 ?        S    22:58   0:00 nginx: cache manager process
    • But what about the old master process – PID 2405? Well, it still exists because Nginx allows you to thoroughly test the new configuration before you kill the older one, which served you well.

    • Successfully Upgraded: In this case, you can safely send the QUIT signal

      : sudo kill -QUIT 2405. Shortly, you will be left with only one master process that will be your upgraded Nginx binary.

    • Upgraded with Issues: Revert back to the original configuration. Send the HUP signal: sudo kill -HUP 2405 and the previous configuration will come back to life. You should now have the previous configuration back up and running. You can send TERM or QUIT signal to the new one: sudo kill -QUIT 2518. You should remove the new binary and replace with the older one now and you will be good.

Migrating from Apache to Nginx

There is a stark difference between the architectures of Nginx and Apache

. From the configuration files to the underpinning of processes and threads, the architectural differences make Nginx shine. The Nginx configuration files are simpler to manage and read. Generally, you can get more throughputs from the same hardware using Nginx.

If you are running Apache, you can adopt Nginx in two different ways. The first way is to use Nginx as a reverse proxy and gradually move toward full adoption. The other way is to migrate the configuration from Apache to Nginx at one shot. The second approach requires more planning and work, but gives the dividend right away. Based on the complexity of your setup, you may choose to take one route or the other.

Feature Comparison

In Table 11-1, you can find the core functional differences between Nginx and Apache. Before even trying to migrate, you must be aware of all functionalities required by your application and what is available in Nginx out of the box. If everything that you use in Apache is available in Nginx, then it is a no-brainer and a full configuration migration is more suitable. However, if there are certain components that are available only in Apache, it makes more sense to use Nginx as a reverse proxy and get the best of both worlds.

Table 11-1. Feature comparision of Nginx and Apache





Synchronous: Each request is handled by a separate thread or process and uses synchronous sockets. It is a blocking architecture. The resources are not released unless the data is consumed by the client. If there are a lot of clients connected, Apache will need to spawn more threads in order to process the requests.

Event based: Asynchronous sockets listen for the requests and the resources are released as quickly as possible. Once the client is ready for more data, another event triggers and the processing resumes. Inherently, Nginx doesn’t like blocking its resources due to client’s slowness. The intention is to serve as many requests, as quickly as possible.


Response times are slower and with more requests, it tends to get even slower.

Response times are much faster than Apache and wins hands down. It is one of the primary reasons why people switch to Nginx.


Apache is more portable and runs under almost all major OS, including Linux, OSX, Windows, Unix, BSD, Solaris, and more.

Nginx is less portable than Apache. It shines best on *nix platform. It is available on Windows but not suitable for production.




Language used


C & C++


Modules can be loaded dynamically in Apache and it makes it easier to add/remove/test different modules.

Modules require a recompile of the binary. Before version 1-9-11, it couldn’t be dynamically loaded, but this is changing fast. With the latest versions of Nginx, you will have more support for dynamic modules. You can read about it at

Hardware Requirement

Due to the architecture, lesser RAM can create a bottleneck for processing requests since the requests are not released quickly.

RAM requirement is comparatively lower due to more efficient request handling. You can get a lot more mileage from commodity hardware.

CGI Support

Most CGI protocols work with Apache because of module architecture.

Supports FastCGI, uWSGI, SCGI via modules that are included by default at compile time.

Configuration Files

XML based.

Text based.

Application Configuration

Allows individual configuration file per folder using .htaccess. This has its benefits as well as problems since the .htaccess files have to be individually managed.

No support for .htaccess files. The configuration is done using server blocks. As discussed earlier in this book, you can create and load multiple server blocks from the main configuration file. This approach is very effective, since every server block can be maintained as a separate file with as much configuration details as needed. It makes portability easier.

Modules Ecosystem

Apache has been around for a longer time and has a definite edge here. It has hundreds of modules.

Nginx has around 100+ modules available for your use. But there is still room for improvement.

General Ecosystem and Documentation

Apache has the edge here too. It has a large number of useful software that is extremely straightforward to use for Apache. An example is WordPress.

It requires a little extra work to set up and configure most third-party software that became wildly successful, like WordPress. Although possible, the process is sometimes painful due to a variety of platforms available and lack of documentation.


Apache is a wildly successful product and the community is vibrant. There is hardly anything that you can ask and not get a decent answer.

Nginx is becoming more popular every day and the community is growing. The overall support, however, is still weaker in comparison to Apache due to the sheer number of Apache users out there. Don’t let this discourage you, since there is an official support available with Nginx PLUS and the community is growing every day.

Configuration Comparison

You have already been working with Nginx configuration files

in this book. A typical Apache configuration file, in contrast, looks similar to the following:

Listen 80
Listen 8080

    ServerName www.example.com
    DocumentRoot "/www/domain-80"

    ServerName www.example.org
    DocumentRoot "/www/otherdomain-80"

Based on the previous code, you must have already noticed that Apache uses XML format. The XML files are not very human readable, especially if it gets nested. Nginx provides a welcome change to this.

VirtualHostin Apache can be migrated to the server blocks with ease. PHP is handled in a different manner in Nginx and has been already explained in chapter 7. The glaring absence that causes the most amount of work during migration is .htaccess. Apache allows you to set folder level settings using a file that is called .htaccess. This file can be found at various levels and the last ones read are given precedence. Consider Figure 11-1. The .htaccess at /app/images will be read after /app. If the same setting is defined at both /app and /app/images, the latter would be given priority.

Figure 11-1. Directory heirarchy with .htaccess files

In Apache, the .htaccess file is used for multiple purposes:

  • Access and authentication rules for specific directories

  • Setting flags for various modules

  • Define rewriting rules

There is no equivalent to .htaccess in Nginx. That said, you can always find solutions by using different directives in different Nginx blocks.


Nginx has a very effective and robust upgrade method. If you plan properly you can have zero downtime for your web servers. When it comes to migrating, there is unfortunately no direct path available to migrate from Apache. But the thumb rule of migration is quite simple. Migrate whatever you can, and use Nginx to augment the rest. It doesn’t matter if you use Apache, Express.js, Node.js, or IIS. Nginx can easily do the front-end job and route the traffic as per your requirements to the back end using its reverse proxy capabilities. With respect to comparing with Apache, let’s wrap up with a famous quote from Chris Lea, “Apache is like Microsoft Word, it has a million options but you only need six. NGINX does those six things, and it does five of them 50 times faster than Apache.”

Comments are closed.