Install Nginx on Debian/Ubuntu

A complete guide to installing and configuring Nginx to serve static files for lightning fast websites.

I recently helped a friend set up his first Nginx server and in the process realized I didn’t have a good working reference for how I set up Nginx.

So, for myself, my friend and anyone else looking to get started with Nginx, here’s my somewhat opinionated guide to installing and configuring Nginx to serve static files. Which is to say, this is how I install and set up Nginx to serve my own and my clients’ static files whether those files are simply stylesheets, images and JavaScript or full static sites like this one. What follows is what I believe are the best practices of Nginx1; if you know better, please correct me in the comments.

[This post was last updated ]

Nginx Beats Apache for Static Content2

Apache is overkill. Unlike Apache, which is a jack-of-all-trades server, Nginx was really designed to do just a few things well, one of which is to offer a simple, fast, lightweight server for static files. And Nginx is really, really good at serving static files. In fact, in my experience Nginx with PageSpeed, gzip, far future expires headers and a couple other extras I’ll mention is faster than serving static files from Amazon S33 (potentially even faster in the future if Verizon and its ilk really do start throttling cloud-based services).

Nginx is Different from Apache

In its quest to be lightweight and fast, Nginx takes a different approach to modules than you’re probably familiar with in Apache. In Apache you can dynamically load various features using modules. You just add something like LoadModule alias_module modules/mod_alias.so to your Apache config files and just like that Apache loads the alias module.

Unlike Apache, Nginx can not dynamically load modules. Nginx has available what it has available when you install it.

That means if you really want to customize and tweak it, it’s best to install Nginx from source. You don’t have to install it from source. But if you really want a screaming fast server, I suggest compiling Nginx yourself, enabling and disabling exactly the modules you need. Installing Nginx from source allows you to add some third-party tools, most notably Google’s PageSpeed module, which has some fantastic tools for speeding up your site.

Luckily, installing Nginx from source isn’t too difficult. Even if you’ve never compiled any software from source, you can install Nginx. The remainder of this post will show you exactly how.

My Ideal Nginx Setup for Static Sites

Before we start installing, let’s go over the things we’ll be using to build a fast, lightweight server with Nginx.

  • Nginx.
  • SPDY — Nginx offers “experimental support for SPDY”, but it’s not enabled by default. We’re going to enable it when we install Nginx. In my testing SPDY support has worked without a hitch, experimental or otherwise.
  • Google Page Speed — Part of Google’s effort to make the web faster, the Page Speed Nginx module “automatically applies web performance best practices to pages and associated assets”.
  • Headers More — This isn’t really necessary from a speed standpoint, but I often like to set custom headers and hide some headers (like which version of Nginx your server is running). Headers More makes that very easy.
  • Naxsi — Naxsi is a “Web Application Firewall module for Nginx”. It’s not really all that important for a server limited to static files, but it adds an extra layer of security should you decided to use Nginx as a proxy server down the road.

So we’re going to install Nginx with SPDY support and three third-party modules.

Okay, here’s the step-by-step process to installing Nginx on a Debian 8 (or Ubuntu) server. If you’re looking for a good, cheap VPS host I’ve been happy with Vultr.com (that’s an affiliate link that will help support luxagraf; if you prefer, here’s a non-affiliate link: link)

The first step is to make sure you’re installing the latest release of Nginx. To do that check the Nginx download page for the latest version of Nginx (at the time of writing that’s 1.5.10).

Okay, SSH into your server and let’s get started.

While these instructions will work on just about any server, the one thing that will be different is how you install the various prerequisites needed to compile Nginx.

On a Debian/Ubuntu server you’d do this:

sudo apt-get -y install build-essential zlib1g-dev libpcre3 libpcre3-dev libbz2-dev libssl-dev tar unzip

If you’re using RHEL/Cent/Fedora you’ll want these packages:

sudo yum install gcc-c++ pcre-dev pcre-devel zlib-devel make

After you have the prerequisites installed it’s time to grab the latest version of Google’s Pagespeed module. Google’s Nginx PageSpeed installation instructions are pretty good, so I’ll reproduce them here.

First grab the latest version of PageSpeed, which is currently 1.9.32.2, but check the sources since it updates frequently and change this first variable to match the latest version.

NPS_VERSION=1.9.32.2
wget https://github.com/pagespeed/ngx_pagespeed/archive/release-${NPS_VERSION}-beta.zip
unzip release-${NPS_VERSION}-beta.zip

Now, before we compile pagespeed we need to grab psol, which PageSpeed needs to function properly. So, let’s cd into the ngx_pagespeed-release-1.8.31.4-beta folder and grab psol:

cd ngx_pagespeed-release-${NPS_VERSION}-beta/
wget https://dl.google.com/dl/page-speed/psol/${NPS_VERSION}.tar.gz
tar -xzvf ${NPS_VERSION}.tar.gz
cd ../

Alright, so the ngx_pagespeed module is all setup and ready to install. All we have to do at this point is tell Nginx where to find it.

Now let’s grab the Headers More and Naxsi modules as well. Again, check the Headers More and Naxsi pages to see what the latest stable version is and adjust the version numbers in the following accordingly.

HM_VERSION =v0.25
wget https://github.com/agentzh/headers-more-nginx-module/archive/${HM_VERSION}.tar.gz
tar -xvzf ${HM_VERSION}.tar.gz
NAX_VERSION=0.53-2
wget https://github.com/nbs-system/naxsi/archive/${NAX_VERSION}.tar.gz
tar -xvzf ${NAX_VERSION}.tar.gz

Now we have all three third-party modules ready to go, the last thing we’ll grab is a copy of Nginx itself:

NGINX_VERSION=1.7.7
wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
tar -xvzf nginx-${NGINX_VERSION}.tar.gz

Then we cd into the Nginx folder and compile. So, first:

cd nginx-${NGINX_VERSION}/

So now we’re inside the Nginx folder, let’s configure our installation. We’ll add in all our extras and turn off a few things we don’t need. Or at least they’re things I don’t need, if you need the mail modules, then delete those lines. If you don’t need SSL, you might want to skip that as well. Here’s the config setting I use (Note: all paths are for Debian servers, you’ll have to adjust the various paths accordingly for RHEL/Cent/Fedora/ servers):

./configure 
        --add-module=$HOME/naxsi-${NAX_VERSION}/naxsi_src 
        --prefix=/usr/share/nginx 
        --sbin-path=/usr/sbin/nginx 
        --conf-path=/etc/nginx/nginx.conf 
        --pid-path=/var/run/nginx.pid 
        --lock-path=/var/lock/nginx.lock 
        --error-log-path=/var/log/nginx/error.log 
        --http-log-path=/var/log/access.log 
        --user=www-data 
        --group=www-data 
        --without-mail_pop3_module 
        --without-mail_imap_module 
        --without-mail_smtp_module 
        --with-http_stub_status_module 
        --with-http_ssl_module 
        --with-http_spdy_module 
        --with-http_gzip_static_module 
        --add-module=$HOME/ngx_pagespeed-release-${NPS_VERSION}-beta 
        --add-module=$HOME/headers-more-nginx-module-${HM_VERSION}

There are a few things worth noting here. First off make sure that Naxsi is first. Here’s what the Naxsi wiki page has to say on that score: “Nginx will decide the order of modules according the order of the module’s directive in Nginx’s ./configure. So, no matter what (except if you really know what you are doing) put Naxsi first in your ./configure. If you don’t do so, you might run into various problems, from random/unpredictable behaviors to non-effective WAF.” The last thing you want is to think you have a web application firewall running when in fact you don’t, so stick with Naxsi first.

There are a couple other things you might want to add to this configuration. If you’re going to be serving large files, larger than your average 1.5MB HTML page, consider adding the line: --with-file-aio, which is apparently faster than the stock sendfile option. See here for more details. There are quite a few other modules available. A full list of the default modules can be found on the Nginx site. Read through that and if there’s another module you need, you can add it to that config list.

Okay, we’ve told Nginx what to do, now let’s actually install it:

make
sudo make install

Once make install finishes doing its thing you’ll have Nginx all set up.

Congrats! You made it.

The next step is to add Nginx to the list of things your server starts up automatically whenever it reboots. Since we installed Nginx from scratch we need to tell the underlying system what we did.

Make it Autostart

Since we compiled from source rather than using Debian/Ubuntu’s package management tools, the underlying stystem isn’t aware of Nginx’s existence. That means it won’t automatically start it up when the system boots. In order to ensure that Nginx does start on boot we’ll have to manually add Nginx to our server’s list of startup services. That way, should we need to reboot, Nginx will automatically restart when the server does.

Note: I have embraced systemd so this is out of date, see below for systemd version

To do that I use the Debian init script listed in the Nginx InitScripts page:

If that works for you, grab the raw version:

wget https://raw.githubusercontent.com/MovLib/www/develop/etc/init.d/nginx.sh
# I had to edit the DAEMON var to point to nginx
# change line 63 in the file to:
DAEMON=/usr/sbin/nginx
# then move it to /etc/init.d/nginx
sudo mv nginx.sh /etc/init.d/nginx
# make it executable:
sudo chmod +x /etc/init.d/nginx
# then just:
sudo service nginx start #also restart, reload, stop etc

Updated Systemd scripts

Yeah I went and did it. I kind of like systemd actually. Anyway, here’s what I use to stop and start my custom compiled nginx with systemd…

First we need to create and edit an nginx.service file.

sudo vim /lib/systemd/system/nginx.service #this is for debian

Then I use this script which I got from the nginx wiki I believe.

# Stop dance for nginx
# =======================
#
# ExecStop sends SIGSTOP (graceful stop) to the nginx process.
# If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control
# and sends SIGTERM (fast shutdown) to the main process.
# After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends
# SIGKILL to all the remaining processes in the process group (KillMode=mixed).
#
# nginx signals reference doc:
# http://nginx.org/en/docs/control.html
#
[Unit]
Description=A high performance web server and a reverse proxy server
After=network.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed

[Install]
WantedBy=multi-user.target

Save that file, exit your text editor. Now we just need to tell systemd about our script and then we can stop and start via our service file. To do that…

sudo systemctl enable nginx.service
sudo systemctl start nginx.service
sudo systemctl status nginx.service

I suggest taking the last bit and turning it into an alias in your bashrc or zshrc file so that you can quickly restart/reload the server when you need it. Here’s what I use:

alias xrestart="sudo systemctl restart nginx.service"

If you’re using systemd, congrats, you’re done. If you’re looking for a way to get autostart to work on older or non-systemd servers, read on…

End systemd update

Okay so we now have the initialization script all set up, now let’s make Nginx start up on reboot. In theory this should do it:

update-rc.d -f nginx defaults

But that didn’t work for me with my Digital Ocean Debian 7 x64 droplet (which complained that “insserv rejected the script header“). I didn’t really feel like troubleshooting that at the time; I was feeling lazy so I decided to use chkconfig instead. To do that I just installed chkconfig and added Nginx:

sudo apt-get install chkconfig
sudo chkconfig --add nginx
sudo chkconfig nginx on

So there we have it, everything you need to get Nginx installed with SPDY, PageSpeed, Headers More and Naxsi. A blazing fast server for static files.

After that it’s just a matter of configuring Nginx, which is entirely dependent on how you’re using it. For static setups like this my configuration is pretty minimal.

Before we get to that though, there’s the first thing I do: edit /etc/nginx/nginx.conf down to something pretty simple. This is the root config so I keep it limited to a http block that turns on a few things I want globally and an include statement that loads site-specific config files. Something a bit like this:

user  www-data;
events {
    worker_connections  1024;
}
http {
    include mime.types;
    include /etc/nginx/naxsi_core.rules;
    default_type  application/octet-stream;
    types_hash_bucket_size 64;
    server_names_hash_bucket_size 128;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;
    more_set_headers "Server: My Custom Server";
    keepalive_timeout  65;
    gzip  on;
    pagespeed on;
    pagespeed FileCachePath /var/ngx_pagespeed_cache;
    include /etc/nginx/sites-enabled/*.conf;
}

A few things to note. I’ve include the core rules file from the Naxsi source. To make sure that file exists, we need to copy it over to /etc/nginx/.

sudo cp naxsi-0.53-2/naxci_config/naxsi_core.rule /etc/nginx

Now let’s restart the server so it picks up these changes:

sudo service nginx restart

Or, if you took my suggestion of creating an alias, you can type: xrestart and Nginx will restart itself.

With this configuration we have a good basic setup and any .conf files you add to the folder /etc/nginx/sites-enabled/ will be included automatically. So if you want to create a conf file for mydomain.com, you’d create the file /etc/nginx/sites-enabled/mydomain.conf and put the configuration for that domain in that file.

I’m going to post a follow up on how I configure Nginx very soon. In the mean time here’s a pretty comprehensive guide to configuring Nginx in a variety of scenarios. And remember, if you want to some more helpful tips and tricks for web developers, sign up for the mailing list below.


  1. If you’re more experienced with Nginx and I’m totally bass-akward about something in this guide, please let me know. 

  2. In my experience anyway. Probably Apache can be tuned to get pretty close to Nginx’s performance with static files, but it’s going to take quite a bit of work. One is not necessarily better, but there are better tools for different jobs. 

  3. That said, obviously a CDN service like Cloudfront will, in most cases, be much faster than Nginx or any other server.