Compiling the nginx Sticky Session Module in Ubuntu

Introduction

Using nginx as a load-balancer is pretty awesome, but when sticky sessions are needed a third-party module must be compiled in. The following instructions show one how to do this.

This tutorial is written for Ubuntu 13.10 but should work with 12.04 and newer with minimial changes. This tutorial assumes you do not already nginx installed.

Install Dependencies

sudo su -l
aptitude update && aptitude dist-upgrade 
aptitude install build-essential software-properties-common
# software-properties-common for ubuntu 13.10
# python-software-properties in ubuntu 12.04

Install official nginx PPA:

apt-add-repository ppa:nginx/stable

Make sure the deb-src line is uncommented:

# change saucy if using a different version of Ubuntu
nano /etc/apt/sources.d/nginx-stable-saucy.list

It should look like this when done:

# saucy will be named differently if using another version of Ubuntu
deb http://ppa.launchpad.net/nginx/stable/ubuntu saucy main
deb-src http://ppa.launchpad.net/nginx/stable/ubuntu saucy main

If you updated the sources.list, update the cached version in the package manager:

aptitude update

We should add the nginx code signing key to ensure the source code is not tampered with:

curl http://nginx.org/keys/nginx_signing.key | apt-key add - 

Compilation

Next, let's download the nginx source code:

cd /usr/src/
apt-get source nginx

And add the source code for the sticky module:

Note, as of this writing, the current version of the sticky module is 1.1. You should grab the latest version, which can be found here: https://code.google.com/p/nginx-sticky-module/

Modify the below commands if you're using a different version than 1.1.

As of this writing, nginx 1.4.4 is current. The version numbers below will may need to be updated, but the latest source code is automatically installed with the commands we typed earlier.

cd nginx-1.4.4/debian/modules
wget https://nginx-sticky-module.googlecode.com/files/nginx-sticky-module-1.1.tar.gz
tar zxvf nginx-sticky-module-1.1.tar.gz

So the source code we downloaded comes with build scripts and configuration for Ubuntu. We want to modify the compile settings to include the sticky module.

cd ..
nano rules

We'll add it to the bottom of each configuration block, config.status.full: config.env.full and config.status.light: config.env.light and config.status.extras: config.env.extras

So the end each of these blocks looks like:

...
        --add-module=$(MODULESDIR)/ngx_http_substitutions_filter_module \
        --add-module=$(MODULESDIR)/nginx-sticky-module-1.1 \
        $(CONFIGURE_OPTS) >[email protected]
    touch [email protected]

And once that's done, we'll install some dependencies.

cd /usr/src/nginx-x.y.z/
aptitude build-dep nginx
# if not on ubuntu 13.10, liblua5.1-0-dev may need to be changed to match
aptitude install liblua5.1-0-dev init-system-helpers

And lets compile

dpkg-buildpackage -b

Installation

Next comes manually installed the .deb files we created:

# again update the version numbers if they do not match
cd ..
dpkg -i nginx-common_1.4.4-1~saucy0_amd64.deb
dpkg -i nginx-full_1.4.4-1~saucy0_amd64.deb

And let's make sure it's installed:

nginx -V

You should get the following:

nginx version: nginx/1.4.4
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx 
....
--add-module=/usr/src/nginx-1.4.4/debian/modules/nginx-sticky-module-1.1

Note the nginx-sticky-module-1.1.

Next, let's make sure nginx runs:

service nginx start
service nginx status

It should show nginx running. You can also browse to http://your.ip.here to ensure it serves pages.

Next, we'll pin the nginx-full package so that it isn't automatically upgraded, overwriting our module:

 echo "nginx-full hold" | dpkg --set-selections

Configuration

Enable Websocket Proxying (Optional)

cd /etc/nginx/conf.d
nano upgrade.conf

and paste in the following code:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

save and exit.

Upstream Configuration

Next, edit the config file to add a set up upstream servers:

nano /etc/nginx/conf.d/upstream.conf

And paste in the following config (update the address and ports):

upstream backend {
    sticky;
    server 127.0.0.1:9000;
    server 127.0.0.1:9001;
    server 127.0.0.1:9002;
}

and save and exit.

Site Configuration

Finally, add a proxy directive and point it to our upstream server group. I'll show the basic configuration in default, but you should create a new file for each virtual host in /etc/nginx/sites-available and ln -s them into /etc/nginx/sites-enabled.

nano /etc/nginx/sites-enabled/default

and modify your configuration to match:

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    server_name localhost;

    location / {
        proxy_pass http://backend;
        #the following 3 lines are only needed if proxying websockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

Save and exit. Next, restart nginx to test the settings:

service nginx stop && service nginx start
service nginx status

And you should be told nginx is running. If not, check /var/log/nginx/error.log for hints as to what's wrong.

Conclusion

And there you go, you now have a websocket-enabled, load-balancing reverse proxy that uses sticky sessions.