Configuring, Installing, and Starting Nginx From Source Code

This post will go over the manual installation and configuration of Nginx source code on a Linux based system. Building from source code instead of directly installing from a pre-built package allows you to customize the modules that will be included in Nginx. Once the files are compiled, you cannot change the underlying structure of Nginx without having to rebuild it. Specifically in this post we will learn how to:

Installation prerequisites

Prerequisites for installing Nginx may vary depending on your operating system but a few common modules are OpenSSL, zlib, GCC, and PCRE. First we want to update our local copy of program we can install. We do this with sudo apt-get update. GNU Compiler Collection or GCC allows you to compile your source code to work on your particular operating system. You can test to see if GCC is already installed on your system with the GCC -v command on your terminal. If the command is not found then you need to install GCC. Install GCC with your package manager which will be apt for Ubuntu/Debian, yum for Red Hat, or yast for SuSE Linux. I am using Ubuntu 16.04 so my input will be sudo apt-get install build-essential. This will also install Make which allows us to automate the compiling process.

The next prerequisite is the zlib library used for gzip compression in Nginx. The main library along with its source need to be installed. Using the package manager apt in my example the command is sudo apt-get install zlib1g zlib1g-dev. Next, OpenSLL which is an open source system for HTTPS connections will be needed for securing your Nginx connections when serving web pages. This is not needed for Nginx to work but with free certificate authorities such as Let’s Encypt, there’s no reason not to secure your website. Google even recommends this for SEO rankings. Note though, certain countries do not allow strong encryption and it is up to you to know your local laws on SSL encryption. Again, the main library and its source need to be installed and can be done in apt with the command sudo apt install openssl libssl-dev. Finally, the Perl Compatible Regular Expression (PCRE) library which is required for Nginx to work will allow for the use of regular expressions in the Rewrite and HTTP modules in Nginx. The command in apt is sudo apt-get install libpcre3 libpcre3-dev. Putting it all together we have the line below. The -y flag is to automatically say yes to installing.

sudo apt-get install build-essential zlib1g zlib1g-dev openssl libssl-dev libpcre3 libpcre3-dev -y

Downloading and extracting Nginx

You can visit the official website, go to the wiki, or ask questions on the forum for more information installing Nginx on your Linux distribution. There are three groups of version available to install. Two of the groups are, stable version, which is recommended and the one I will be showing, and the mainline version which is the development build. This build is usually pretty stable but may contain bugs you need to watch out for. The last group is legacy (old) versions which can be found on the Nginx website.

To download Nginx, we are going to create a temporary directory for the source code for compiling. This is done my making a directory in a temporary folder and going into that new folder with the command mkdir /tmp/nginx && cd /tmp/nginx. Now we are going to get the current latest version on Nginx with wget that allows http and ftp file retrieval. I can see from here that the latest version is v1.11.1 so I will get that with the command wget http://nginx.org/download/nginx-1.11.1.tar.gz. This will download the file into the current folder we are in which should be /tmp/nginx.

Next, we must extract the file we downloaded. You will notice the file has two extensions tar and gz which are archiving and compression extensions. We can unarchive and decompress the file with the tar command. To let tar know we are going to extract we need the x flag. To use gzip and specify the file the z and f flags are used as well. Finally, we need to specify the actual file we will be using. The final command is tar xzf nginx-1.11.1.tar.gz just be sure to use the correct filename for your particular version. Once the file is extracted, move into the new folder with cd /tmp/nginx/nginx-1.11.1/. Make sure to replace the folder name with the correct Nginx version you downloaded. We now created the foolowing structure:

Auto Contains configuration options. A Modules file for modules installed by default and options file that include different configuration options.
confls Nginx configuration files nginx.conf and fastcgi.conf.
configure All configuration details and parameters required to compile Nginx. The output of configure file will create the Makefile.
contrib Contains the geo2nginx module.
Html Default index.html and 50x.html files.
Src Source code of nginx, html, mail, etc.
Man Manual pages for Nginx.

Now, we are going to configure the source code. All configuration is done by the ./configure command. This command allows you to pass flags that can change path configurations, add or remove modules, or change prerequisite options. Path configurations can change such things as the path of the Nginx installation, where configuration files are stored, and log file paths. Usually, these are not changed as they need to be reset when recompiling Nginx but the most common changes are Nginx installation and configuration paths which are by default in the /usr/local/nginx and /usr/local/nginx/conf paths respectively. You may want to specify a custom path for Nginx itself so when installing a newer version at a later time you do not have to overwrite the current installation while you are still in the process of setting the new version up. The same goes for configuration file path changes. To change the installation path and configuration path you use the --prefix and --conf-path flags. For example, to change the installation path to /usr/bin and the configuration files to /etc/nginx you would use the command ./configure --prefix=/usr/bin --conf-path=/etc/nginx. To make life easier in future updates, you can create a symbolic link from the original directory to the custom one. This can be done using the ln command which by default creates hard links. To specify a symbolic or soft link instead of the default hard link (not what we want), we use the -s flag in the command ln -s /usr/local/nginx /usr/local/nginx-1.11.1. This creates a symbolic link in the default directory /usr/local/nginx so when we update Nginx into a new folder and want to switch everything over to the new version all we have to do is update the symbolic link in the default folder to the new path containing the new version of Nginx. Going back to path configuration in general, to see the full list of paths that you can configure you can go the the Nginx documentation here.

Before I get into modules, I wanted to go over an important configuration for user and group permissions with Nginx. These configurations are set by --user and --group respectively and control the default user account and user group that starts Nginx worker processes. These settings can be overwritten by configuration files used by Nginx when starting up but default values can be set before compiling. We can use a custom user and group to give Nginx least privileges needed to run. To ensure Nginx always runs under these permission settings, you use the command ./configure --user=nginx --group=nginx. The installation process should make this user and group for you but if it doesn’t you can always make they manually with:

sudo groupadd -r nginx && useradd -r nginx -g nginx

Next up are modules. There are many different types of modules that are already included, can be added from source code, or added from a third party. Modules give Nginx its ability to do things such as gzip compression, HTTP proxying, and SSL encryption. There are two main types of modules, static and dynamic. Static modules are always loaded when Nginx starts where as dynamic modules which are new to Nginx as of version 1.9.11, will only load when they are used in a configuration file. It is possible to convert static modules into dynamic modules but it’s not advised for certain modules such as ones that change the source code. These modules need to be added before compiling. You can view the list of modules already included with Nginx here. To disable a module that is builtin, you can use the --without flag. For example, to disable gzip, you use the command ./configure --without-http_gzip_static_module. To enable builtin modules, the --with command is used. Note, the flag begins with two dashes not one. A list of builtin modules that are disabled by default can be found here. A note when using third party modules, these are use at your own risk as they are not verified by Nginx for safe use. A list of relatively safe third party modules can be found here. Finally, various prerequisite options can be changed such as GCC compiling options and connection processing methods for Nginx’s asynchronous behavior such as polling and queues. More on these settings can be found here.

Whew. Okay, now that we have discussed configuring Nginx, let’s actually setup the configuration for compiling. The basic modules that you want to use are for SSL encryption, a module to allow passing of the client’s IP address through Nginx proxies, a stub status module allowing for status information, a module for IPv6 support, and support for HTTP/2. You may see older configuration settings use SPDY instead of HTTP/2 but Google has officially depreciated SPDY in favor of HTTP/2 and it will no longer be supported in future builds. These four modules along with permission settings can all be configured with the command ./configure --prefix=/usr/local/nginx-1.11.1 --conf-path=/etc/nginx-1.11.1 --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_stub_status_module --with-ipv6 --with-http_v2_module. We also need PCRE3, gzip compression, and ssl so we add the --with-pcre --with-http-gzip_static_module --with-openssl flags. I also want to add asyncronous I/O transfer and disable s/uw cgi (keeping fastcgi). I want all the output of this to be piped into a file so I can easily view it for errors so my final config command is:

./configure \
--user=nginx \
--group=nginx \
--prefix=/etc/nginx-1.11.1 \
--sbin-path=/usr/sbin/nginx-1.11.1 \
--conf-path=/etc/nginx-1.11.1/nginx.conf \
--pid-path=/var/run/nginx-1.11.1.pid \
--lock-path=/var/run/nginx-1.11.1.lock \
--error-log-path=/var/log/nginx-1.11.1/error.log \
--http-log-path=/var/log/nginx-1.11.1/access.log \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-pcre \
--with-file-aio \
--with-http_realip_module \
--with-http_v2_module \
--with-ipv6 \
--without-http_scgi_module \
--without-http_uwsgi_module \
> conf_output.txt

Once you are done with the configuration of the source code, we compile with the make command from the GCC installation we made earlier. Ensure that GCC along with PCRE, zlib, and OpenSSL libraries are installed that I mentioned above. When everything looks okay, execute the make command and if no errors are found the project source path should be displayed. If compilation was successful, then install Nginx with superuser permissions using sudo make install.

Running Nginx for the first time

Nginx runs as a daemon which means it runs in the background by default. Daemon programs usually are named with a letter ‘d’ at the end to mark it as a daemon. When starting Nginx, since it will automatically run as a daemon, you will not see any output when it successfully starts. This means everything went okay when starting the Nginx server. Note that Nginx itself must be started by the root user to ensure any ports 1024 and below can be accessed. Remember, the www-data settings above are for Nginx process workers that the parent Nginx process starts. These workers are what interact with clients and need to only have www-data permission settings. Before starting Nginx, ensure the symbolic link was created from the default folder to the custom version named folder. Once that is done, we can start Nginx with the command /usr/local/nginx. There are various command line arguments that can be passed when starting Nginx. A full list of arguments can be found here but the three most common ones you will be using are -s which passes signals to the Nginx process, -t which tests configuration files without starting Nginx to ensure they are correctly formatted, and -v which not only gives you the version number of Nginx, but any configurations we made earlier during compiling or passed when starting Nginx. Various signals exist for Nginx such as stop, reopen, quit, and reload. The reload signal will be important later on as it will reload configuration files without stopping any current client connections that exist. This argument can be used by the command /usr/local/nginx -s reload. Using the -t argument will test all configuration files but this does not ensure Nginx will start without errors such as invalid paths or socket issues. It is possible to run a test on a configuration file you are working on while a production configuration file is already in use. To test a configuration file without affecting the current one in use, we can use /usr/local/nginx -t -c /path/to/test.conf which specifies a path to the test configuration file. Once you feel that the new configuration file is okay, replace the old file with the new one and restart Nginx with the reload signal.

Using Systemd to control autostart of Nginx

My last topic is auto starting Nginx on system boot or when Nginx crashes. There are three major processes that handle this (SystemV, Upstart, and systemD) but SystemD is the newest and most common way today. If you want an overview of how SystemD works you can see this digital ocean article which gives a good run down of SystemD in my opinion. To sum up SystemD in one sentence though, it uses configuration files which are broken up into sections, that have variables called directives that set certain settings when controlling a process. To illustrate, the ‘Unit’ section of a SystemD configuration file will have directive variables such as ‘Description’ and ‘After’ which specify a description of the process being started and when the process should be started in the booting process of the operating system. There are various processes that need to be started before Nginx can work but the most obvious one is the network connection which is denoted by network.target. So, the first section of the Nginx SystemD file will be:

[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

This tells the system a small description (which you can put anything here) and four different processes including network.target that must be active first for Nginx to start. The next section in this file is the ‘Service’ section which specifies various commands to be executed when starting, stopping, or reloading Nginx. These directive variables are denoted by ExecStartPre, ExecStart, ExecReload, and ExecStop. There are a few other Exec based directives but these are the basic ones needed for Nginx. Notice for ExecStartPre which is a command executed before start, the -t argument is ran to ensure correct configuration files. We will also specify the ‘type’ directive which in this scenario we will tell Nginx to ‘fork’. This tells SystemD that Nginx creates child processes. We will also use the ‘PIDfile’ directive which needs to be set when using the ‘fork’ setting to tell SystemD which process is the main parent process of Nginx. Luckily, Nginx provides a file for SystemD to read although if you changed the path of this file during compiling, you need to make sure the SystemD configuration files reflects the new path to the PIDfile of Nginx. We will also specify a ‘PrivateTmp’ directive which allows Nginx to use a private folder for temporary files. This heightens security and is easy to implement by setting the directive to true. Without further ado, The settings for the ‘Service’ section is:

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

In the ‘Service’ section, HUP and QUIT are signals for configuration reload and proper shutdown of a process. The KILL signal can also be used to forcefully shutdown if Nginx is not responding. The $MAINPID variable is just the process identification number of the main Nginx process that was set from the PIDfile directive. These signals are called with the ‘kill’ command to emit signals to the operating system. Don’t get the command ‘kill’ and the signal ‘KILL’ confused here in this example as they are two separate things. The last section we are going to use in SystemD is the ‘Install’ section and is used for the behavior of enabling or disabling Nginx. The only directive we will use in here is the ‘WantedBy’ directive which tells SystemD that Nginx is ‘wanted by’ a certain process before that process is started. This isn’t needed for the automatic start to work but ensures Nginx is started before a user can log into the system. This is done by setting WantedBy to ‘multi-user.target’. There are various targets or ‘checkpoints’ that the operating system passes while booting called system run levels. If you are interested in learning more about the internals of Linux, I highly recommend the book How Linux Works which goes into detail of the many basic parts of a Linux operating system. The entire SystemD file needs to be saved in the default SystemD folder for services to automatically start and is in the directory /lib/systemd/system/nginx.service. Once the file is created and saved in the SystemD folder, you can start Nginx and the operating system will from now on handle restarting Nginx on boot or process crash. Here is the final SystemD configuration file:

[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.targ
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=tr
[Install]
WantedBy=multi-user.target

There is a lot we covered for the manual installation of Nginx. First, we needed to make sure any required libraries such as GCC and OpenSSL are installed. Once we did that, we downloaded the Nginx source code and decompressed all the files into a temporary folder for us to work in. We then configured the source code files adding modules such as SSL support and HTTP/2 and changed default file paths for easy future Nginx version updates. We also set default permissions for child (not the parent!) processes for security. Once all the configurations were set and modules added, we compiled the source code with GCC make command. We then learned about starting Nginx and using arguments to control the Nginx process. Finally, we learned a little bit about SystemD and configured SystemD to automatically start Nginx upon system boot and process crash. I hope this article has given you a deep insight into how to get started with Nginx. Most of these things you do not need to know to get a basic web server up with Nginx but if you are looking to become proficient with the capabilities of Nginx then this is your first step. Next, I will be talking about configuration files to setup a HTTP server, proxies, and SSL encryption. Nginx has an insane amount of configuration variables (also called directives) as you can see from this list. I wont be going over most of these but will go over the most common to get started with various web development technologies.

Leave a Reply

Your email address will not be published. Required fields are marked *