Nginx – Nginx and Dynamic Content

How to Create a Droplet with DigitalOcean

This chapter will take your knowledge level deeper by providing insights into serving dynamic content. Please keep in mind that hosting dynamic content directly with Nginx is not possible. This is to say that Nginx worker processes will not load the processing modules in its own memory address space to serve the pages. The idea is to proxy the content to the components that do the actual processing of your requests. As limiting as it sounds, it has its own good side effects. The primary benefit is that the slowness caused by dynamic sites cannot directly affect Nginx. It has powerful routing and proxy capabilities that will tremendously benefit you as a web administrator.

This chapter might not appeal to you if you are not familiar with developer technologies and you can skip it if you like. However, you don’t need to be intimidated by the code and other details if you choose to read through, since the samples will be fairly straight forward for you to understand. The idea is not to dive too much into code but instead to show you just a few samples so that you get the gist of how Nginx can be helpful in accelerating your applications. For brevity, only CentOS-related directions are provided. Conceptually, it won’t be very different for other distros. Without further ado, let us begin.

Sudo Scare

In chapter 6 one of the things you learned about was not using the root account due to multiple reasons. To that effect, you created a user called user1. But this user is quite powerless at the moment. Check it out by doing the following:

  • Start by logging in as user1 like so: ssh -p 3026 user1@

  • Try running the following command and notice how it tries to scare you:

[user1@wfe1 ∼]$ sudo yum -y install php56
[sudo] password for user1:
user1 is not in the sudoers file. This incident will be reported.
  • It basically says that user1 is not allowed to do sudo.

  • Since you know you can trust user1, you can add him to the sudoers list by using visudo.

  • Type su and hit enter to get into the root prompt.

  • Type visudo and hit enter again. It will open the file ( /etc/sudoers) in vi editor and allow you to edit it.


Even though you can edit the file directly, you should avoid doing it, since visudo validates the file when you exit. If you choose to use any other editor, you may end up making a bad mistake and locking yourself out of the server. It is extremely important that you exercise caution while adding users to the sudoers list.

  • After the file is open, look for a line that says root ALL=(ALL) ALL and add your user in the next line.

## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
user1   ALL=(ALL)       ALL
  • Save the file and type exit to get back from the root prompt to the user1 prompt.

  • sudo should now work for the commands.

Installing MySQL

Now that the user is in the sudoers list, you can install some software to complete the LEMP (Linux, eNginx, MySQL, and PHP) stack
. Let us start with MySQL. MySQL is an open source relational database management system (RDBMS)
. In July 2013, it was the second most widely used RDBMS, just behind SQLite.


SQLite is deployed with every Android and iPhone device along with the Chrome and Firefox browsers. In the second quarter of 2013 alone, 213 million smartphones shipped, of which 200 million were Android and iOS.

Log in on to your wfe1.localdomain server using ssh -p 3026 user1@
. To install MySQL server, you need to first download the Yum repository. The following link contains information about different versions that are available:
. Visit the link and find the version you are interested in. For CentOS, you can pick RHEL 7’s download link which can be found here:



that these links might change over a period of time, and in future you will most likely have later versions, so it would be better to visit the page and get the latest links before you execute the commands that follow.

  1. Install wget so that you can download anything from the server directly instead of uploading the file using FTP.

    sudo yum install -y wget
  2. Now, use wget to download the repository and use the rpm (RPM Package Manager) utility to manage the file you just downloaded as follows:

    sudo wget
    sudo rpm -Uvh mysql57-community-release-el7-7.noarch.rpm
  3. Time to install MySQL. Execute the following command:

    sudo yum install -y mysql-community-server
  4. A bunch of files will be downloaded and installed for you due to the yum (and other package managers’) goodness that comes with Linux.

  5. Once the setup is done, you can start the MySQL service like so:

    sudo service mysqld start
    sudo service mysqld status
  6. During the installation the server is initialized and an SSL certificate and key files are generated in the data directory. Along with that, a superuser account ‘root’@’localhost is created. If you try to connect using mysql -u root command, you will get the following error (and you can easily figure out that it is because you haven’t provided any password):

    ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
  7. Since the install never really asked for a password, how would you know what the password is? The answer to this is simple. It is because there is a temporary password allocated during the installation process. You can retrieve that and as you can guess, change it immediately so that you have a strong password in place. To retrieve the password, use the following command:

    sudo grep 'temporary password' /var/log/mysqld.log
    --- 1 [Note] A temporary password is generated for root@localhost: gj>jwax<u0rT                  
  8. Connect to MySQL using mysql -u root -p and type in the temporary password. This will allow you to enter the MySQL console. To change the temporary password, use the following command:

    mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'P@ssword1!';
    Query OK, 0 rows affected (0.00 sec)
  9. Try typing simple commands and you can start talking to your MySQL server.

    mysql> show databases;
    | Database           |
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    4 rows in set (0.00 sec)
  10. Type quit; at the prompt and you will be back to your user prompt.

Before you proceed with installing PHP and other Nginx configuration on WFE1, you may want to clean up what you might have done in the previous chapter. This is simply to avoid any confusion:

sudo rm -rf site1 site2 site3
sudo rm -f /etc/nginx/conf.d/site*.conf

Also remove the host name entries from your host file that you might have created during the previous chapter.

Installing PHP

Let us install PHP next. PHP originally stood for Personal Home Page, but of late it is referred to as Hypertext Preprocessor. It is a server-side scripting language designed for web development. It is one of the core standing pillars for the LAMP (Linux, Apache, MySQL, and PHP) or LEMP (Linux, Nginx, MySQL, and PHP) stack. Please keep in mind that there are multiple options for running PHP. The most common options available to you are mod_php

, FastCGI, and PHP-FPM


  • mod_php

    is the built-in version available only for Apache. Installing it is easy, and its ease of use coupled with tight integration is probably the most common reason to deploy mod_php. However, it forces every Apache child to use more memory and needs a restart of Apache to read an updated php.ini file.

  • FastCGI is a pretty generic protocol available on most platforms including Windows IIS. It is an improvisation over the earlier variation of Common Gateway Interface (CGI) that reduces the overheads by spinning up one process for multiple requests. You might be already aware that CGI used one process per request and it was not as scalable for extremely busy sites. FastCGI has a smaller memory footprint than mod_php and has more configuration options.

  • PHP-FPM is an alternative for PHP FastCGI implementation and is the newest kid on the block. It can be used with any web server that is compatible with FastCGI and plays well with Nginx too. It gives you a lot of configuration options and it really shines in multiple areas, especially related to availability. You can start different processes with different settings and different php.ini options. This means you can have multiple processes serving different versions of PHP in case your application is not compatible with a specific PHP version.

In this book, you will be using PHP-FPM. To install it, you will need to first add the yum repository followed with yum install like so:

sudo rpm -Uvh
sudo rpm -Uvh
sudo yum install -y php56w-fpm php56w-opcache php56w-mysql

This will install your php-fpm service, and you can start using it for applications that are written in PHP. To start, stop, or restart the service use the commands respectively:

sudo service php-fpm start
sudo service php-fpm stop
sudo service php-fpm restart

To view the status

, run the following command and notice how it shows a green circle to the left of service name:

sudo service php-fpm status
Redirecting to /bin/systemctl status  php-fpm.service
●php-fpm.service - The PHP FastCGI Process Manager
   Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; vendor preset: disabled)
   Active: active (running) since Tue 2016-03-08 02:10:35 EST; 1s ago
 Main PID: 2665 (php-fpm)
   Status: "Ready to handle connections"
   CGroup: /system.slice/php-fpm.service
           ├─2665 php-fpm: master process (/etc/php-fpm.conf)
           ├─2666 php-fpm: pool www
           ├─2667 php-fpm: pool www
           ├─2668 php-fpm: pool www
           ├─2669 php-fpm: pool www
           └─2670 php-fpm: pool www

To view the version of PHP, you can use the following command:

php -v
PHP 5.6.18 (cli) (built: Feb  4 2016 22:08:11)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

Even though Nginx+Apache+mod_php combination works, Nginx+PHP-FPM happens to be more performant due to architectural differences of PHP-FPM. It is a good idea to evaluate your application against the latter technology combination to gain high performance from your web servers.

Let’s configure Nginx to test if PHP works by default. As discussed in chapter 6, start by creating a configuration file for the test site by copying the /etc/nginx/conf.d/default.template:

sudo cp /etc/nginx/conf.d/default.template /etc/nginx/conf.d/test.conf

Modify the test.conf file

so that it looks like the following:

server {
    listen       80;
    server_name  localhost;

    root   /usr/share/nginx/html;

    location / {
        index  index.html index.htm;

    # pass the PHP scripts to FastCGI server listening on
    location ∼ \.php$ {
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;

In the previous configuration block, the last location block is what does the real magic from PHP perspective.

  • The location route matches all routes that end with a .php.

  • The
    fastcgi_pass directive

    tells Nginx to pass on the request to the specified address. If you like, you can have another server just to serve PHP requests. In this configuration however, since the php_fpm service is running locally, the request gets routed to that process on the same server instead on port 9000.

  • fastcgi_index directive

    sets a file name that will be appended after a URI that ends with a slash, in the value of the $fastcgi_script_name variable.

  • fastcgi_paramsets the parameter for the SCRIPT_FILENAME. In the current block if the request is for /page.php the SCRIPT_FILENAME variable will be $document_root/page.php, but if the request is just for / the SCRIPT_FILENAME will be $document_root/index.php. $document_root variable is equal to the root directive set inside your location or server block.

  • The include directives initialize a bunch of other parameters and is set in a file located at /etc/nginx/fastcgi_params. It is a good idea to keep all parameters related to fastcgi grouped in a single file.

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

Now it’s time to test if PHP is working. Create a file at /usr/share/nginx/html/test.php and paste the following code in it. The first line reads the server variables and the second line displays tabular information about PHP itself.

<?php var_export($_SERVER)?>
<?php phpinfo() ?>

Browse to http://localhost:8006/test.php and you should be able to see a page that looks similar to Figure 7-1.

Figure 7-1. Output of test.php

This is great! Your server can now host PHP pages and output dynamic pages for you.

Notice the USER is Apache in Figure 7-4. Why would that be so? Well, the reason is that by default the configuration file for php-fpm is configured so that the process is executed as
apache. Run the command ps -aux | grep php and you will find that the php-fpm process is running as apache.

ps -aux | grep php
root      2665  0.0  1.9 393584 20292 ?        Ss   02:10   0:00 php-fpm: master process (/etc/php-fpm.conf)
apache    2666  0.0  0.4 393584  4908 ?        S    02:10   0:00 php-fpm: pool www
apache    2667  0.0  0.4 393584  4908 ?        S    02:10   0:00 php-fpm: pool www
apache    2668  0.0  0.4 393584  4908 ?        S    02:10   0:00 php-fpm: pool www
apache    2669  0.0  0.4 393584  4908 ?        S    02:10   0:00 php-fpm: pool www
apache    2670  0.0  0.4 393584  4908 ?        S    02:10   0:00 php-fpm: pool www
user1     2702  0.0  0.0 112612   736 pts/0    S+   02:17   0:00 grep --color=auto php

In contrast
ps -aux | grep nginxwill tell you that the process for Nginx is running as nginx.

ps -aux | grep nginx
nginx      953  0.0  0.1  48268  1904 ?        S    Mar07   0:00 nginx: worker process
user1     2705  0.0  0.0 112612   736 pts/0    R+   02:20   0:00 grep --color=auto nginx

To change the user, you can edit the configuration file sudo vi /etc/php-fpm.d/

and change the line that reads user = apache to user = nginx and group = apache to group = nginx. Restart the service by typing the following command.

sudo service php-fpm restart                                    

If you refresh the page, you will now see that the settings have taken affect and you are being served a page with ‘USER’=>’nginx’. You can also check the output of ps -aux | grep php and confirm that the process is indeed running as nginx.

wfe1.localdomain server

can be considered fully setup as a LEMP stack
server. You can now set up dynamic applications on it.


Once you have tested the test.php, it is a good practice to remove the file since it can be used by malicious users for gathering system information.

Configure Nginx for WordPress

WordPress is the world’s most commonly used content management system based on PHP and MySQL. More than 60 million websites use WordPress as their content management system. It is open source and the application files are installed on a web server. You can also host your blog or site using, but in our context we will be dealing only with the self-hosting option of WordPress.

In the previous chapter you have already downloaded the zipped version of the repository from Github located at
. You will find a folder called /dynamic/wordpress-4.4.2. This folder contains version 4.4.2 of WordPress. WordPress is known for easy installation steps. So, let us quickly install WordPress and see it in action by following these steps:

  1. Log in to the MySQL prompt using mysql -u root –p.

  2. To create a database, use the following command where wpsite is the name of the database:

                            CREATE DATABASE wpsite                                                                
  3. Grant all privileges to a user account using the following command where wpuser is the name of the user and P@ssword1! is your strong password. Change the password as you deem fit and run the command:

    GRANT ALL PRIVILEGES on wpsite.* TO wpuser@localhost IDENTIFIED BY "P@ssword1!";
  4. Upload the files using an FTP client as shown in Figure 7-2. Create a new folder called WordPress and upload all the content from /dynamic/wordpress-4.4.2.

    Figure 7-2. Uploading content

    to WFE1 server

  5. Remove your test.conf file that you created from the default.template a while ago in this chapter:

    sudo rm -f /etc/nginx/conf.d/test.conf
  6. Create a copy of the default.template file like so:

    sudo cp /etc/nginx/conf.d/default.template /etc/nginx/conf.d/wpsite.conf
  7. Make your look as follows and reload using
    sudo nginx -s reload:

    server {
        listen       80;
        server_name  localhost;
        root   /usr/share/nginx/html/wordpress;
        location / {
            index  index.php index.html index.htm;
        # pass the PHP scripts to FastCGI server listening on
        location ∼ \.php$ {
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
  8. Although not mandatory, it is a good idea to check if your database is up and connecting well from PHP. It is actually fairly simple. Create a file in your /usr/share/nginx/html/wordpress directory called
    dbtest.phpand write the following text:

      $db=mysql_connect('localhost', 'wpuser', 'P@ssword1!');
      if (!$db) echo "connection failed";
      else echo "connection succeeded";
  9. If you browse to http://localhost:8006/dbtest.php you should see “connection succeeded” message. If you don’t see it, something is missing and you are advised to cross check before proceeding ahead.

  10. Time for some cool stuff. Type http://localhost:8006/index.php in your browser. It should take you to the famous 5-minute WordPress installation page, which looks similar to Figure 7-3:

    Figure 7-3. WordPress installation page

    . Click Let’s go!

  11. You will be presented a screen that will ask for the parameters that you have already set up. Provide the details as you see in Figure 7-4 and click Submit.

    Figure 7-4. WordPress installation parameters

  12. When you click on Submit, a config file text will be created for you with the details you have previously filled in (see Figure 7-5).

    Figure 7-5.
    Configuration file

    created by WordPress installation

  13. Copy the entire text and paste it in a file created at /usr/share/nginx/html/wordpress/wp-config.php.


    There is another way in which you can do the previous few steps related to WordPress. All you will need is to create a copy of the wp-config-sample.php as wp-config.php and make the necessary changes in the file. If you do that, your WordPress setup will start with the step you see in Figure 7-5.

  14. After that, click on Run the install button (Figure 7-5). And you will be presented the final screen for WordPress setup. It is that simple!

  15. Click on Install WordPress and you are all set with your website. To login to your website, you now have to go to http://localhost:8006/wp-admin/index.php and type in the Username and Password that you have configured in Figure 7-6.

    Figure 7-6. WordPress setup

    – Final Step

Create your posts and try browsing to http://localhost:8006 and you will be glad to see your website online. Often the WordPress administrators change the Settings ➤ Permalink in the WordPress Administration Dashboard to Post Name or one of the other options as shown in Figure 7-7.

Figure 7-7. Changing Settings

to get cleaner URL in WordPress

The moment you change the settings here, your home will continue to work but the cleaner URIs (for example, http://localhost:8006/test-post-1
) will fail. This is because of the way the URI is mapped in the Nginx configuration. To fix such issues, change your /etc/nginx/nginx.conf file to look like the following:

user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/;

events {
    worker_connections  1024;

http {
    include            /etc/nginx/mime.types;
    default_type       application/octet-stream;
    log_format         main  '$remote_addr - $remote_user - [$time_local] - $document_root - $document_uri - '
                       '$request - $status - $body_bytes_sent - $http_referer';

    access_log         /var/log/nginx/access.log  main;
    sendfile           on;
    keepalive_timeout  65;
    client_max_body_size 13m;
    index              index.php index.html index.htm;
    upstream php {
    include /etc/nginx/conf.d/*.conf;

In your
/etc/nginx/conf.d/wpsite.confmake the necessary changes so it looks like the following (the following text is courtesy of


   listen           80;
   server_name localhost;
   root /usr/share/nginx/html/wordpress;

   # This order might seem weird - this is attempted to match last if rules below fail.
   location / {
      try_files $uri $uri/ /index.php?$args;

   # Add trailing slash to */wp-admin requests.
   rewrite /wp-admin$ $scheme://$host$uri/ permanent;

   # Directives to send expires headers and turn off 404 error logging.
   location ∼* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
       access_log off;
       log_not_found off;
       expires max;

    # Uncomment one of the lines below for the appropriate caching plugin (if used).
    #include global/wordpress-wp-super-cache.conf;
    #include global/wordpress-w3-total-cache.conf;

    #Pass all .php files onto a php-fpm/php-fcgi server.
    location ∼ [^/]\.php(/|$) {
       fastcgi_split_path_info ^(.+?\.php)(/.*)$;
       if (!-f $document_root$fastcgi_script_name) {
           return 404;
       include fastcgi_params;
       fastcgi_index index.php;
       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       fastcgi_pass php;

Quite a number of new directives have come to play in the configuration just covered. In Table 7-1, let us look at the ones that have not yet been discussed.

Table 7-1. Important Directives

at play in the mysite.conf file




Sets the maximum number of simultaneous connections that can be opened by a worker process. This number includes all connections like connection with proxied servers as well as clients. Also remember that simultaneous connections cannot exceed the current limit on the maximum number of open files (worker_rlimit_nofile).


This directive defines the default MIME type of a response. It is set to application/octet-stream by default in this case. This implies that the server can send any binary file. For example, the server can emit a zip file and it will be appropriately handled by the client since it knows that the type of the file is binary.


Defines the maximum size allowed for the request body. If the size increases the configured limits, it sends an error code 413, which means Request Entity Too Large. In this configuration it is set to 13MB. Depending on your content type, you should tweak it.


This directive is used to group servers in a block making your configuration more readable and manageable. If you provide multiple servers, the requests get distributed in a round-robin load balanced fashion. In this configuration, a php upstream is defined with just one server inside it.


Tells Nginx to try finding the files in specified order. In the current configuration it searches for $uri, $uri/, /index.php?$args.


Checks for a specific regular expression and redirects if found. Here, it checks for /wp-admin$ and appends a forward slash ($scheme://$host$uri/ permanent;) whenever the URI contains wp-admin.


Since it turned to off in this configuration, Nginx won’t log errors if files are not found.


This directive enables Nginx to send an Expires and Cache-Control response header. This is a very crucial directive since you can save a lot of bandwidth if the directive is enabled and set to max. By setting it max, you are effectively telling the client and proxy servers to cache the files for as long as possible.


This directive defines a regular expression based on which the request gets split. The former part of the split string becomes $fastcgi_script_name and the latter becomes $fastcgi_path parameter, which can be subsequently used. If the URI is /page.php/post/001, $fastcgi_script_name will contain /page.php while $fastcgi_path_info will be equal to /post/001.


This directive sets the address of a FastCGI server. It can be a domain name or an IP address. In this case it sets it to php, which is the name of the upstream block.

The MEAN Stack

A stack called MEAN (Mongo, Express, Angular, and Node)

is becoming increasingly popular among the full-stack web developers. These web developers are often called full-stack developers
because the entire technology stack, from database (MongoDB) to back end (Node.JS + Express.JS) to front end (Angular.JS) uses JavaScript. Even though they can use the MEAN stack to handle all requests, it often makes sense to accelerate the entire application using Nginx as front end. In the remainder of this chapter you will see how to set up a MEAN stack and start a sample web application.

Installing MongoDB

MongoDB is a very popular database choice these days. It is a cross-platform and document-oriented database. In the NoSQL database world, MongoDB absolutely shines. Since WFE1 has been allocated for MySQL, you can use WFE2 for MongoDB. In production, you will most likely have dedicated database servers. For the lab setup however, you should be good to go. To install MongoDB, use the following steps:

  1. Create a file called /etc/yum.repos.d/mongodb-org-3.2.repo and write the following text in it:

    name=MongoDB Repository
  2. Execute the following command to install MongoDB:

    sudo yum install -y mongodb-org

    Again, covering all topics about Mongo, or MEAN for that matter, is outside the scope of this book, but there is a bare minimum you need to know so that at least you can start up the server and fire away some commands.

  3. MongoDB comprises of multiple components, but for testing the waters, you need to learn just a couple of them. mongod is the daemon that can be considered as the Mongo server. The mongo command, often known as mongo shell, is the client that connects to the mongo server and is very similar to MySQL command line conceptually. You can start the mongo server using this:

    sudo service mongod start
  4. Now, simply type mongo and you should be able to connect to the server. Typing mongo invokes the mongo shell, which is fairly simple to use once you learn it.


    Note that it is possible that you get the following error while trying to invoke Mongo. The error happens if your locale settings are broken.

    Failed global initialization: BadValue Invalid or no user locale set. Please ensure LANG and/or LC_* environment variables are set correctly.                  

    You can fix this error by manually setting the variable ( export LC_ALL=C) before you start the Mongo shell.

  5. You can view the version of MongoDB by typing version() in the mongo shell. Try the following commands in order and you can see how intuitive it is:

    > use foo
    switched to db foo
    > db
    > db.users.insert({"name":"mongo", "about":"rocks!"})
    WriteResult({ "nInserted" : 1 })
    > db.users.find()
    { "_id" : ObjectId("56e7f53b569a00edf1c98a9b"), "name" : "mongo", "about" : "rocks!" }
    > quit()

You can learn more about MongoDB at http://
. In fact, they even run regular courses for free where you can learn about it and get certified if you wish to. For more information about their courses, please visit

Installing Node.JS

Node.js is an extremely powerful, open source, cross-platform runtime environment for developing server-side web applications. Although it is not a JavaScript framework, many of its modules are written in JavaScript. The runtime environment interprets JavaScript using Google’s V8 JavaScript engine. Of late, it has become very popular among web developers. Learn more at

Installing Node is much more straightforward. Run the following command one by one, and by the end of the third command, you will have NodeJS installed on your server.

sudo curl --silent --location | sudo bash -
sudo yum -y install nodejs
sudo yum -y install gcc-c++ make

You can test if Node is installed correctly by running the following command:

node -v

Installing Express.JS

They say Express and Node are like twins that are joined at the hip. Technically though, consider Express.js as a Node.js web application server framework. It serves as the back end for Node.js and comes with a plethora of plug-ins for various aspects, like parsing a cookie or a request body, authentication and much more. It can be installed by executing npm (Node Package Manager) commands. To install it globally on the server, type sudo npm install express -g. Learn more at

Installing Angular.JS

This portion is usually done in the application side using the npm install command. The npm install command reads the dependencies and installs everything that is needed by the server. Angular, as such, is not something that is installed. Consider it a JavaScript framework for the client side. It is simply downloaded at the client side and provides a huge amount of functionality like data binding, routing and a lot more. To learn more about it visit


a MEAN Application

Building a MEAN application is fun. So, instead of giving you a sample, this section will show you how you can type a few more commands and set up an application with basic scaffolding.

  1. To ensure that npm is the latest version, install it using the following command:

    sudo npm -g install npm
  2. Next, install express generator. This will help you start an application quickly with basic scaffolding.

    sudo npm install express-generator -g
  3. Create an application and run using the following commands. Yes, it is that simple!

    express myapp
    cd myapp
    npm install
  4. You can very well run the application using npm start at this moment. But that is not a good idea since the process runs as a foreground application. Running this application using a package called
    pm2helps in production scenarios. Install it by using the following command:

    sudo npm install pm2 -g
  5. Once done, you can now execute your application using the following:

    pm2 start bin/www.
    [PM2] Starting bin/www in fork_mode (1 instance)
    [PM2] Done.
    • To view all applications hosted using pm2, you can use pm2 list. (see Figure 7-8).

      Figure 7-8.
      PM2 List

  6. The App name can be used to view details about the application. As you can see in Figure 7-9, the PID is 12927 and the application name is www. You can redeploy your code and simply run pm2 restart www to restart this application. It keeps running the application in background mode.

  7. To view the application details, use pm2 show www.

  8. To stop the application, use pm2 stop www.

  9. To learn more about pm2, visit


Okay, so now that the application is running in the background, you can do curl localhost:3000 to view the output. It will be a very html output on the command line.

Configure Nginx

for MEAN Stack

The Node application that is running needs to be exposed using Nginx. Recall that this application is just the beginning of the MEAN stack. It doesn’t even use MongoDB or Angular yet. But for the purpose of this book, it should suffice. You simply need to know the pattern for managing and hosting such applications. Typically, the application files will be given to you just like you have them in the myapp directory.

  1. For simplicity clean up any other conf file in /etc/nginx/conf.d and create a new configuration file as follows:

    sudo cp /etc/nginx/conf.d/default.template /etc/nginx/conf.d/node.conf
  2. Edit the node.conf file so that it looks like so:

    upstream nodeapp {
    server {
        listen       80;
        server_name  localhost;
        root         /usr/share/nginx/html;
        location / {
           proxy_pass http://nodeapp;
    • Notice the usage of upstream directive. The Express application was listening on port 3000, hence server directive inside upstream will route the traffic there.

    • Inside the server block, there is location directive that uses proxy_pass to redirect the traffic upstream using the http://nodeapp address. You will learn more about these directives in chapter 8.

    • Try browsing http://localhost:8007 and instead of getting the page you might get an error saying 502 Bad Gateway. The error in the error.log is typically like the following:

    [crit] 13535#0: *43 connect() to failed (13: Permission denied) while connecting to upstream, client:, server: localhost, request: "GET / HTTP/1.1", upstream: "", host: "localhost"
    • If you don’t get this error, you are good to go! However, in case you get the error, most likely it is happening due to SELinux. To troubleshoot this, install setroubleshoot, using: sudo yum install setroubleshoot.

  3. After the package installs, execute the following command:

    sudo cat /var/log/audit/audit.log | grep nginx | grep denied | audit2allow -M mynginx

    Finally, execute sudo semodule -i mynginx.pp and the problem should be resolved. Check by browsing http://localhost:8007.


In this chapter you have learned various important things about hosting dynamic applications with Nginx. The chapter started with setting up a LEMP stack by installing the appropriate packages for MySQL and PHP. Post that, you learned about installation, configuration, and some finer nuances of WordPress administration on Nginx. Later in this chapter, you learned about the basics of MEAN stack and how easy it is to configure it using Nginx. You will be learning more about performance fine-tuning for dynamic applications and load balancing in the coming chapters.

Comments are closed.