Minimal nginx configuration for front end development

Akshat Jiwan Sharma, Fri Mar 21 2014

nginx.conf

Recently I worked with my friend who is a web designer and I noticed that he served static html files directly from the file system. He did not make use of any web server. I understand the need for keeping things simple and I absolutely love minimal development setups. But I think that not having a static file server during the developmental phase can cause many problems :

  1. You have to specify fully formed links to anchor tags, css and javascript files etc. Links relative to your directory won't work.
  2. File system can't determine mime type of the file it has served. I have on many occasions seen chrome throw up a warning like "resource interpreted as script but transferred with a mime type of text/Plain".
  3. Some of the new html 5 features like webRTC are unavailable if you serve your files from the file system.
  4. You will be unable to run plugins like page speed insight or similar tools to benchmark your html page. Now this might not be that big of a deal for some but I like to test my page once I have designed it to see if I can make some performance related optimizations.

Sure it may take some effort to to set it up the first time but once you have configured it to your liking it will result in an overall faster development process. So I suggest that you serve your files using a fast static server like nginx ( pronounced as engine-x ). You might be asking your self why use nginx instead of dozens of static file servers available? Great question. Though I believe that any static file server is better than no server I will try to sell nginx to you.

  1. Nginx is fast and light on system. It uses a single threaded event driven model to serve up static files.
  2. Nginx is easy to set up. It makes use of simple, easy to understand configurations that can even be split into multiple files for easy maintenance.
  3. It is much more than just a static file server and can be used to load balance requests to your application.
  4. A single nginx server can act as a gateway to multiple servers. So you can have requests to your apache, iis or node js server all through nginx. This can be very handy as it allows for complex deployments in a very easy manner.
  5. It is good practice to have a static file server in front of your application server as it takes pressure away from it. Although serving static files sounds relatively simple there is a lot going under the hood : reading files, detecting their mime types, compressing them, sending the response, maintaining cache and checking the validity of etags etc. So in general you should always delegate the task of serving static files to a server that is designed for this specific purpose.
  6. Perhaps the most important advantage, at least for me, is that nginx allows you to change urls of the resources without having to change the routes of your application. It is not uncommon to find yourself in a situation where you may have to change the url scheme of your application. Rather than killing the old urls you can use nginx to permanently redirect them to the new scheme.
  7. Top notch documentation. You can learn everything there is to know about nginx by reading the official docs.

So while nginx has many uses we don't need to go in depth before making use of it in our simple scenario. Let us see how nginx can help us.

By default nginx configuration files are located in the directory in which you installed nginx. Go to the directory where you have installed nginx and look for nginx.conf(should be present in a folder called conf). Here's what a simple nginx configuration looks like :

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#pid   /run/nginx.pid;

events {
    worker_connections  1024;
}

http {
      include /etc/nginx/mime.types;
      gzip  on;
      gzip_http_version 1.1;
      gzip_comp_level 2;
      gzip_types text/plain text/html text/css
                      application/x-javascript text/xml
                      application/xml application/xml+rss
                      text/javascript;

server {
                listen       80;
                server_name  localhost;
                access_log  logs/localhost.access.log  main;
                location / {
                    root   html;
                    index  index.html index.htm;
                }
        include /etc/nginx/sites-enabled/*;
        }
}

Too big? Let us break it down and understand the blocks step by step. But before that a few things to note:-

  • First of all nginx interprets anything after # as a comment.
  • White spaces are not interpreted
  • statements end with a ';'

The configuration files are organized as a series of blocks. These blocks are interpreted top-down. That is the configuration parameters that are applied to the top level block affect the blocks that come after it unless they are overridden in the lower level block. For example if an http block contains a directive such as

gzip on;

that instructs nginx to turn gzip on. Then this instruction will be applied to all the blocks that are contained within http block. Okay so let's start now with the http block:-

http block

The http block contains a set of "global" directives for nginx. Let us take a look at a sample http block

http {

     include /etc/nginx/mime.types;

     gzip on;
     gzip_http_version 1.1;
     gzip_comp_level 2;
     gzip_types  text/plain text/html text/css
                      application/x-javascript text/xml
                      application/xml application/xml+rss
                      text/javascript;

include /etc/nginx/sites-enabled/*;

The the include directive tells nginx to load the contents of the specified path. This is useful when you find that you have added say lots of server blocks or configuration settings and want to take them out of the main file to keep it uncluttered. For instance the the first include directive in our example configuration above tells nginx to look for the file called 'mime.types' in the '/etc/nginx' directory. And sure enough if you open mime.types file in your editor you will see a list of supported mime types by nginx.

The second include directive '/etc/nginx/sites-enabled/_' tells nginx to include all the files in the '/etc/nginx/sites-enabled' directory. Notice the the special symbol * which is a shorthand for all. The command is interpreted by nginx as "everything within sites-enabled".

The http block also contains other useful directives. For instance the gzip directive we talked about before is used to instruct nginx to compress the files before sending it to the client. And you can probably guess that gzip_types specifies the types of files to be compressed and gzip_comp_level sets the level of compression for the file. Greater the level more resources will be required to compress it. A list of directives can be seen in the official documentation.

It is worth repeating here that every directive specified in parent block will be applied to the children blocks unless it is explicitly overridden in that block.

The most interesting part of the http block is the server block that contains configuration directives for a server. The basic configuration follows the same structure as that of http block

server {
//configuration of the server
}

There are a lot of directives that you can set within the server block. The server_name allows you to map your domain name to the server block. The location directive creates "routes" for your application etc. Consider an example

server{
listen localhost:9090;
location / {
root  /home/user/Desktop/Repo/Project
  }

}

The configuration defined above creates a server block that listens for connection on "localhost:9090". A location block marks the root directory of the server as " /home/user/Desktop/Repo/Project" which means that it will serve files from this directory. A request like " localhost:9090/about.html" will make nginx look up about.html file in "/home/user/Desktop/Repo/Project" directory. If it finds the file it will be served otherwise a 404 message will be returned.

You can have as many server blocks as you wish. You can move server blocks into a different file and include it with the include directive like we discussed above. Remember to reload nginx with nginx -s reload after you have edited the config file to make the changes available to nginx. Reload does not restart the ningx server (it just reloads the nginx configuration) so you can change the configurations even in a prodction environment without worrying about any downtime.

The location blocks besides pointing to a specific file can also direct requests to a server running on a different port using a proxy_pass directive. Like so

location /create{
proxy_pass http://localhost:3000/createUser
}

Now we have acquired the all knowledge necessary to create a minimal configuration for serving up static files let us see hwo we can use this information to our advantage. I like to keep all my projects under a single folder and then create sub folders within it for different projects. For me the following server configuration is enough

server{

listen localhost:9090;

location / {
root  /home/user/Desktop/Repo/Projects
  }

}

Now I can access my static websites by pointing browser to 'localhost:9090/project1', 'localhost:9090/project2/about.html' and so on. And with this I have a simple fast static file server. Easy no?

ADDENDUM

Keeping the configuration files separate

Up until this point we have been editing the nginx configuration files that come with the installation. Now if your use of nginx is small and you only need it to serve up your static files (which was the goal of this post) then it's fine to directly edit those files. However if you are a heavy user and need more flexibility then it's probably better to create config files on a project by project basis and then start nginx with a location to that file.

Suppose you have a config file called "test.config" in the "/home/akshat/Desktop" directory. So how do you tell nginx to load this configuration file? It's pretty simple. Create a folder called logs where in the directory where your configuration file is present and then type the command:-

nginx -p /home/akshat/Desktop -c ./test.config

The nginx command line utility comes with two switches

-p which tells it to look for the directory in which the configuration file is present and

-c which tells it the name of the configuration file to load.

Now you can even have a separate configuration file for each of your projects. You might be surprised by all the folders that suddenly appear in your directory--- but let them be nginx creates them automatically.

Do more with modules

nginx community has created a tonne of modules that extend nginx's behaviour. The docs contain a list of them under the heading "module reference". Which module you plan to use depends upon your use case.

But I will give you a small example of how I use it. Among the modules you will find one called autoindex. If there is no index file present in the directory then this module serves up all the files that are present in the directory. I've set up a location Pictures

    location /Pictures{
    root /home/akshat/;
    autoindex on;
    }

which serves up a list of all the photos in my pictures directory. When I feel like browsing I open up my terminal and start nginx and there they all are waiting to be clicked ---A lazy man's photo gallery. There are lots of other useful modules like this which you can use to further enhance what your nginx does.

Learn how to script nginx

Love nginx? Want to do more with it than modules and configuration files allow? Would you like to script it with an easy to use language,lua? Then learn openresty. I've also got a little guide that can definitely help you learn it quickly.


comments powered by Disqus