summaryrefslogtreecommitdiff
path: root/src/published/2014-02-10_install-nginx-debian-ubuntu.txt
blob: e6cc835bde217d80f8be12f84e33882590ffa904 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
---
title: Install Nginx on Debian/Ubuntu
pub_date: 2014-02-10 11:35:31
slug: /blog/2014/02/install-nginx-debian-ubuntu
tags: Web Servers
metadesc: A complete guide to installing and configuring Nginx to serve static files (on a Digital Ocean or similar VPS)
code: True
tutorial: True

---

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 Nginx[^1]; if you know better, please correct me in the comments.

[This post was last updated <span class="dt-updated updated" datetime="2014-11-05T12:04:25" itemprop="datePublished"><span>05 November 2014</span></span>]

## Nginx Beats Apache for Static Content[^2]

I've written before about how static website generators like [Jekyll](http://jekyllrb.com), [Pelican](http://blog.getpelican.com) and [Cactus](https://github.com/koenbok/Cactus) are a great way to prototype websites in a hurry. They're also great tools for actually managing sites, not just "blogs". There are in fact some very large websites powered by these "blogging" engines. President Obama's very successful fundraising website [ran on Jekyll](http://kylerush.net/blog/meet-the-obama-campaigns-250-million-fundraising-platform/).

Whether you're just building a quick live prototype or running an actual live website of static files, you'll need a good server. So why not use Apache? Simply put, 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 S3[^3] (potentially even faster in the future if Verizon and its ilk [really do](http://netneutralitytest.com/) start [throttling cloud-based services](http://davesblog.com/blog/2014/02/05/verizon-using-recent-net-neutrality-victory-to-wage-war-against-netflix/)).

## 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](http://nginx.org).
* [SPDY](http://www.chromium.org/spdy/spdy-protocol) -- 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](https://developers.google.com/speed/pagespeed/module) -- 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](https://github.com/agentzh/headers-more-nginx-module/) -- 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](https://github.com/nbs-system/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 7 (or Ubuntu) server. If you're looking for a good, cheap VPS host I've been happy with [Digital Ocean](https://www.digitalocean.com/?refcode=3bda91345045) (that's an affiliate link that will help support LongHandPixels; if you prefer, here's a non-affiliate link: [link](https://www.digitalocean.com/))

The first step is to make sure you're installing the latest release of Nginx. To do that check the [Nginx download page](http://nginx.org/en/download.html) 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:

~~~.language-bash
$ 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:

~~~.language-bash
$ 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](https://developers.google.com/speed/pagespeed/module/build_ngx_pagespeed_from_source) 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 cariable to match the latest version.

~~~.language-bash
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`:

~~~.language-bash
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](https://github.com/agentzh/headers-more-nginx-module/) and [Naxsi](https://github.com/nbs-system/naxsi) pages to see what the latest stable version is and adjust the version numbers in the following accordingly.

~~~.language-bash
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:

~~~.language-bash
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:

~~~.language-bash
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):


~~~.language-bash
./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](https://github.com/nbs-system/naxsi/wiki/installation) 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](https://calomel.org/nginx.html) for more details. There are quite a few other modules available. A [full list of the default modules](http://wiki.nginx.org/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:

~~~.language-bash
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. 

To do that I use the [Debian init script](https://github.com/MovLib/www/blob/master/bin/init-nginx.sh) listed in the [Nginx InitScripts page](http://wiki.nginx.org/InitScripts): 

If that works for you, grab the raw version:

~~~.language-bash
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
~~~

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:

~~~.language-bash
alias xrestart="sudo service nginx restart"
alias xreload="sudo service nginx reload"
~~~

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:

~~~.language-bash
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:
   
~~~.language-bash
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:

~~~.language-bash
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/`.

~~~.language-bash
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:

~~~.language-bash
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](https://calomel.org/nginx.html) 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.