On this page
Building Nginx From Source On Debian Squeeze
Version 1.0
Author: Michel Käser
This tutorial describes how you can build nginx from source on Debian Squeeze. Additionally, we will include some useful 3rd-party modules like the naxsi WAF (web application firewall), SPDY etc.
At the end you will have a fully function nginx installation.
I do not issue any guarantee that this will work for you!
1 Requirements
To follow this tutorial you will need the following:
- a dedicated server running Debian Squeeze
- about 30 minutes time to read carefully
2 Preliminary Notes
In this tutorial we will use development version of nginx as our source base. Please be aware that these versions may be unstable and are not recommended to run on production server.
Some modules like SPDY however require nginx version 1.3.1x or later - and personally I'd say that it's more or less safe to use development version of nginx as there aren't any known exploits.
3 Prerequisites
Since nginx is written in C programming language, we will need to install some packages that will help us building/compiling the source code. I'm a big fan of apt package manager, but you can use aptitude etc. as well:
apt-get -y install build-essential zlib1g-dev libpcre3 libpcre3-dev libbz2-dev libssl-dev tar unzip
This will install all required packages like gcc and make.
4 Downloading nginx source
The latest version of nginx can be found on the following website: nginx.org/en/download.html. At time of writting it's 1.3.12 - so we are going to download:
cd /tmp
wget http://nginx.org/download/nginx-1.3.12.tar.gz
and unpack the source:
tar -xzvf nginx-1.3.12.tar.gz
We won't build our version of nginx yet, as we are going to download some 3rd-party modules first that we will include later on.
5 Additional 3rd-party modules
In difference to Apache HTTPd, which supports dynamic loading of modules (that's why we can install them from repositories), nginx doesn't include such a feature - and from what I've read it's not something on the sooner roadmap.
We have to decide early therefor, what modules we want to include in our custom installation. There's a nice overview/table on the official nginx website listing the most popular ones: wiki.nginx.org/3rdPartyModules.
Since it does not include all available modules, I recommend you to run a Google query like: nginx redis module github if you are looking for a particular module - a lot of them are hosted over at Github.
5.1 Downloading the modules
For this tutorial we are going to download some really great modules like naxsi, SPDY and a few less known ones.
headers_more
Let's start with headers_more. You can use it to completely hide webserver information for example, to enhance server security:
mkdir /tmp/nginx-modules
cd /tmp/nginx-modules
wget https://github.com/agentzh/headers-more-nginx-module/archive/v0.19.tar.gz
tar -xzvf v0.19.tar.gz
This will download the most recent version and unpack it. Make sure to checkout the official repository from time to time to see if there is a new version around (counts for all other modules as well).
Cache Purge
You may not need this module for your setup. If you however have nginx in front of Apache, acting as a reverse proxy and caching the results of proxy_pass this might be a winner! Otherwise, skip it:
wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.0.tar.gz
tar -xzvf 2.0.tar.gz
naxsi
Naxsi is an open source, high performance, low rules maintenance, web application firewall module for nginx - very equal to mod_security in functionality. We will use it to secure our customers web applications:
wget http://naxsi.googlecode.com/files/naxsi-core-0.49.tgz
tar -xzvf naxsi-core-0.49.tgz
SPDY
SPDY is a module that allows your web server to take advantage of SPDY features like stream multiplexing and header compression and lot of people are taking about it to be a new standard (what it seems to be).
Upgrading OpenSSL
It requires OpenSSL 1.0.1+, something we don't have on our Squeeze machine by default. We will be using testing repository of Debian in this tutorial to install it. You can however compile it from source or check for other repositories as well.
nano /etc/apt/sources.list
and pase the following lines:
deb http://ftp.debian.org/debian/ testing main contrib non-free deb http://security.debian.org/ testing/updates main contrib non-free
We should now prevent our server from upgrading other packages to testing version. We can do so by creating/editing the file `/etc/apt/apt.conf.d/releases:
nano /etc/apt/apt.conf.d/releases
and paste:
APT::Default-Release "squeeze";
Attention: If you refer to stable repositories with stable in your sources.list, you should replace squeeze with stable in above text.
Now we can safely run:
apt-get update
apt-get -t testing install openssl
which will upgrade/install existing OpenSSL version.
Applying the patch
Currently there is no way to include it like other modules, instead, it's provided as a patch for the nginx source code. Official readme can be found here: nginx.org/patches/spdy/README.txt
cd /tmp/nginx-1.3.12
wget http://nginx.org/patches/spdy/patch.spdy.txt
patch -p1 < patch.spdy.txt
should do all the magic for us.
6 Building nginx
Until now we have downloaded the nginx source, some additional 3rd-party modules for it and applied the SPDY patch. It's time to build our nginx installation now.
It's like with all C applications - a 3-steper. We're going through the first step in more detail:
./configure --help
This will show you a list of all available configuration options for the build like what modules can be disabled, enabled and so on. Mine looks like this (shorten):
--help print this message --prefix=PATH set installation prefix --sbin-path=PATH set nginx binary pathname --conf-path=PATH set nginx.conf pathname --error-log-path=PATH set error log pathname --pid-path=PATH set nginx.pid pathname --lock-path=PATH set nginx.lock pathname --user=USER set non-privileged user for worker processes --group=GROUP set non-privileged group for worker processes --builddir=DIR set build directory --with-rtsig_module enable rtsig module --with-select_module enable select module --without-select_module disable select module --with-poll_module enable poll module --without-poll_module disable poll module --with-file-aio enable file AIO support --with-ipv6 enable IPv6 support --with-http_ssl_module enable ngx_http_ssl_module [...] --with-http_stub_status_module enable ngx_http_stub_status_module --without-http_charset_module disable ngx_http_charset_module [...] --without-http_browser_module disable ngx_http_browser_module --without-http_upstream_ip_hash_module disable ngx_http_upstream_ip_hash_module --without-http_upstream_least_conn_module disable ngx_http_upstream_least_conn_module --without-http_upstream_keepalive_module disable ngx_http_upstream_keepalive_module --with-http_perl_module enable ngx_http_perl_module --with-perl_modules_path=PATH set Perl modules path --with-perl=PATH set perl binary pathname --http-log-path=PATH set http access log pathname --http-client-body-temp-path=PATH set path to store http client request body temporary files --http-proxy-temp-path=PATH set path to store http proxy temporary files --http-fastcgi-temp-path=PATH set path to store http fastcgi temporary files --http-uwsgi-temp-path=PATH set path to store http uwsgi temporary files --http-scgi-temp-path=PATH set path to store http scgi temporary files --without-http disable HTTP server --without-http-cache disable HTTP cache --with-mail enable POP3/IMAP4/SMTP proxy module [...] --without-mail_smtp_module disable ngx_mail_smtp_module --with-google_perftools_module enable ngx_google_perftools_module --with-cpp_test_module enable ngx_cpp_test_module --add-module=PATH enable an external module --with-cc=PATH set C compiler pathname [...] --with-cpu-opt=CPU build for the specified CPU, valid values: pentium, pentiumpro, pentium3, pentium4, athlon, opteron, sparc32, sparc64, ppc64 --without-pcre disable PCRE library usage [...] --with-pcre-jit build PCRE with JIT compilation support --with-md5=DIR set path to md5 library sources --with-md5-opt=OPTIONS set additional build options for md5 --with-md5-asm use md5 assembler sources --with-sha1=DIR set path to sha1 library sources --with-sha1-opt=OPTIONS set additional build options for sha1 --with-sha1-asm use sha1 assembler sources --with-zlib=DIR set path to zlib library sources --with-zlib-opt=OPTIONS set additional build options for zlib --with-zlib-asm=CPU use zlib assembler sources optimized for the specified CPU, valid values: pentium, pentiumpro --with-libatomic force libatomic_ops library usage --with-libatomic=DIR set path to libatomic_ops library sources --with-openssl=DIR set path to OpenSSL library sources --with-openssl-opt=OPTIONS set additional build options for OpenSSL --with-debug enable debug logging
This will help you a lot deciding what modules you want to include/exclude, as well as what else can be defined.
We are going to use the following configure command:
./configure \ --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 \ --without-http_fastcgi_module \ --without-http_uwsgi_module \ --without-http_scgi_module \ --without-http_memcached_module \ --with-ipv6 \ --with-http_ssl_module \ --with-http_spdy_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --add-module=/tmp/nginx-modules/headers-more-nginx-module-0.19 \ --add-module=/tmp/nginx-modules/naxsi-core-0.49/naxsi_src \ --add-module=/tmp/nginx-modules/ngx_cache_purge-2.0
which will exclude everything related to mail and handlers we don't need (you might need them if not running as a reverse proxy!) and include our downloaded 3rd-party modules and SPDY patch.
I've used Debian standard paths here, but feel free to change them.
Next, we can compile the source:
make
Attention: If this throws any errors, you should carefully read them to see where the problem is, and what it is.
Finally, install the compiled source:
make install
This will copy all the files to correct locations. Done!
7 Enable autostart
Debian uses init scripts through which you can control service behavior. I'm using the one from official nginx package - all credits belong to it's maintainer:
#!/bin/sh ### BEGIN INIT INFO # Provides: nginx # Required-Start: $local_fs $remote_fs $network $syslog # Required-Stop: $local_fs $remote_fs $network $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts the nginx web server # Description: starts nginx using start-stop-daemon ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/nginx NAME=nginx DESC=nginx # Include nginx default if available if [ -f /etc/default/nginx ]; then . /etc/default/nginx fi test -x $DAEMON || exit 0 set -e . /lib/lsb/init-functions test_nginx_config() { if $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1; then return 0 else $DAEMON -t $DAEMON_OPTS return $? fi } case "$1" in start) echo -n "Starting $DESC: " test_nginx_config # Check if the ULIMIT is set in /etc/default/nginx if [ -n "$ULIMIT" ]; then # Set the ulimits ulimit $ULIMIT fi start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON -- $DAEMON_OPTS || true echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON || true echo "$NAME." ;; restart|force-reload) echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON || true sleep 1 test_nginx_config # Check if the ULIMIT is set in /etc/default/nginx if [ -n "$ULIMIT" ]; then # Set the ulimits ulimit $ULIMIT fi start-stop-daemon --start --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true echo "$NAME." ;; reload) echo -n "Reloading $DESC configuration: " test_nginx_config start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON || true echo "$NAME." ;; configtest|testconfig) echo -n "Testing $DESC configuration: " if test_nginx_config; then echo "$NAME." else exit $? fi ;; status) status_of_proc -p /var/run/$NAME.pid "$DAEMON" nginx && exit 0 || exit $? ;; *) echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2 exit 1 ;; esac exit 0
Don't forget to chmod
:
chmod 755 /etc/init.d/nginx
We can also create Debian style default file:
nano /etc/default/nginx
and paste:
# Note: You may want to look at the following page before setting the ULIMIT. # http://wiki.nginx.org/CoreModule#worker_rlimit_nofile # Set the ulimit variable if you need defaults to change. # Example: ULIMIT="-n 4096" #ULIMIT="-n 4096"
Last but not least, if you like to autostart nginx on boot you can run:
update-rc.d nginx defaults
8 Special modul directives
We won't go through nginx configuration and vhost files here, but the following directives from our modules are interesting:
# SPDY module (vhost) listen 443 ssl spdy; # more_headers module (http) more_clear_headers 'Server'; # removes server information
naxsi
naxsi is a bit more complex. First, the global configuration rules should be included in http section of nginx config file:
nano /etc/nginx/nginx.conf
and paste:
http { [...] include /etc/nginx/naxsi_core.rules; [...] }
Attention: Make sure this file exists. You can copy naxsi configuration files from downloaded archive (see: Additional 3rd-party modules).
Next, you have to include the default rules within your vhost template:
[...] location / { include /etc/nginx/naxsi.rules; [...] } [...]
and a location for blocked requests:
[...] location /blocked { return 403; #proxy_pass http://127.0.0.1:4242; # learning mode } [...]
Attention: Make sure the location for blocked requests matches the one from configuration file /etc/nginx/naxsi.rules:
LearningMode; SecRulesEnabled; #SecRulesDisabled; DeniedUrl "/blocked"; [...]
As you can see naxsi has some strange options, but they aren't strange. Youd should head over to their documentation to read how to make it work best. A hint I searched very long for: You have to run a python script and pass blocked request to it during learning-mode to create a whitelist for false alerts.