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.

 

Share this page:

7 Comment(s)