James Gardner: Home > Blog > 2007 > Nginx Proxying to Pylons with SSL...

Nginx Proxying to Pylons with SSL on Debian Etch

Posted:2007-12-07 16:06
Tags:Pylons, Web, Debian, Hosting

The easy way to install Nginx is like this:

sudo aptitude install nginx

The problem is that this installs an old version (0.4) and doesn't have SSL support built in. Nginx is designed to be super fast so and modules need to be compiled in manually. This means you need remove the Nginx package if you want SSL support.

If you try sudo apt-get remove --purge nginx you get this error:

Reading package lists... Done
Building dependency tree... Done
The following packages will be REMOVED
  nginx*
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
Need to get 0B of archives.
After unpacking 524kB disk space will be freed.
Do you want to continue [Y/n]? y
(Reading database ... 26362 files and directories currently installed.)
Removing nginx ...
Stopping nginx: invoke-rc.d: initscript nginx, action "stop" failed.
dpkg: error processing nginx (--purge):
 subprocess pre-removal script returned error exit status 1
Starting nginx: 2007/12/07 14:45:03 [emerg] 29441#0: unknown directive "ssl" in /etc/nginx/nginx.conf:30
invoke-rc.d: initscript nginx, action "start" failed.
dpkg: error while cleaning up:
 subprocess post-installation script returned error exit status 1
Errors were encountered while processing:
 nginx
E: Sub-process /usr/bin/dpkg returned an error code (1)

The solution is to edit /var/lib/dpkg/info/nginx.prerm and comment out the line with invoke-rc.d which gives the stop statement for nginx. If you run the command again it will remove successfully, purging your nginx.conf config file too. If this isn't what you want make a backup first.

You can then remove your logs with:

sudo rm -rf /var/log/nginx/

Now to install Nginx 0.6 from source. Fisrt you will need some build tools:

sudo aptitude install build-essential

Then we need some libraries:

sudo aptitude install libpcre3 libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev

Check what the latest version is at http://nginx.net. At the time of writing the latest stable version is 0.5.33 so download that:

wget http://sysoev.ru/nginx/nginx-0.5.33.tar.gz
tar zxfv nginx-0.5.33.tar.gz
cd nginx-0.5.33

Now you are ready to compile Nginx. As mentioned earlier many of the options are set at compile time so have a look at the Compile Time Options page and decide which you need. We are going to set two options. The first is:

--with-http_ssl_module

This enables the SSL module. The second option is to customise where Nginx is installed to. The default is /usr/local/nginx but this means the Nginx binary will be /usr/local/nginx/sbin/nginx which isn't on the PATH. A better place is /usr/local/sbin where it is easily accessible by root or by users with sudo access:

--sbin-path=/usr/local/sbin

Now we are ready to configure:

./configure --sbin-path=/usr/local/sbin --with-http_ssl_module

There is a useful configuration summary:

nginx path prefix: "/usr/local/nginx"
nginx binary file: "/usr/local/sbin"
nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
nginx pid file: "/usr/local/nginx/logs/nginx.pid"
nginx error log file: "/usr/local/nginx/logs/error.log"
nginx http access log file: "/usr/local/nginx/logs/access.log"
nginx http client request body temporary files: "/usr/local/nginx/client_body_temp"
nginx http proxy temporary files: "/usr/local/nginx/proxy_temp"
nginx http fastcgi temporary files: "/usr/local/nginx/fastcgi_temp"

Then compile and install:

make
sudo make install

The first thing I do next is create a backup of the original file:

sudo cp /usr/local/nginx/conf/nginx.conf  /usr/local/nginx/conf/nginx.conf.bak

Then start the server:

sudo /usr/local/sbin/nginx

If you visit http://yourdomain.com you should see the Nginx welcome message Welcome to nginx!. If you don't it might be because you have another server such as Apache running.

To kill the server you can use the pid file:

sudo kill `cat /usr/local/nginx/logs/nginx.pid`

Notice this uses the ` character (normally underneath Esc) not the ' character. Obviously it is nicer to have an init.d setup so you can start and stop Nginx the same way as Apache and other servers. We'll use the script from Slicehost which is itself based on the Debian package:

wget http://articles.slicehost.com/assets/2007/10/19/nginx
sudo chmod +x nginx
sudo mv nginx /etc/init.d

Now we can add this script to the runlevels:

sudo /usr/sbin/update-rc.d -f nginx defaults

Now you can start, stop and restart Nginx with these commands as normal:

sudo /etc/init.d/nginx start
sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx restart

Now let's setup Nginx to proxy to a Pylons application. Replace these lines in /usr/local/nginx/conf/nginx.conf:

location / {
    root   html;
    index  index.html index.htm;
}

with these:

location / {
    proxy_redirect          off;
    proxy_set_header        Host $host;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Host $host;
    proxy_set_header        X-Forwarded-Port $server_port;
    client_max_body_size    10m;
    client_body_buffer_size 128k;
    proxy_connect_timeout   90;
    proxy_send_timeout      90;
    proxy_read_timeout      90;
    proxy_buffer_size       4k;
    proxy_buffers           4 32k;
    proxy_busy_buffers_size 64k;
    proxy_temp_file_write_size 64k;
    proxy_pass  http://127.0.0.1:5000;
    proxy_redirect  default;
}

Update: Added X-Forwarded-Port and X-Forwarded-Host to the above since I use them both so much.

This will proxy all requests to another server running on port 5000, for example a running Pylons application. To test this you should start your Pylons application (making sure debug is set to false if this is a production setup):

paster serve development.ini

Now restart Nginx:

sudo /etc/init.d/nginx restart

and f you visit the site you should see your Pylons application.

Now for the SSL:

sudo aptitude install openssh-server

First create a the key, pem and certificate files:

openssl genrsa 1024 > host.key
chmod 400 host.key
openssl req -new -x509 -nodes -sha1 -days 365 -key host.key > host.cert
cat host.cert host.key > host.pem
chmod 400 host.pem

Make sure the Common Name is the same as the domain name the certificate is for.

Now we need to setup SSL on Nginx. This is described in detail here but it really just requires making the server section look like this:

worker_processes 1;
http {
    ...
    server {
        listen               443;
        ssl                  on;
        ssl_certificate      /path/to/host.pem;
        ssl_certificate_key  /path/to/host.key;
        keepalive_timeout    70;
    }
}

Restart Nginx again:

sudo /etc/init.d/nginx restart

Now if you visit http://yourdomain.com you'll get no response but if you visit https://yourdomain.com you'll get a certificate warning because the SSL certificate is not signed by a certificate authority. Click OK and you will have access to your application.

The final part of the setup is to setup a static file which redirects from the http version of the site to the https version. The easy way to do this is by setting up another server listening on port 80 and creating an error 404 page which redirects to the https version. Add this to the nginx config just before the existing server:

server {
    listen 80;
    server_name  yourdomain.com;
    error_page  404              /404.html;
    location = /404.html {
        root   /path/to/directory/containing/404/doc/;
    }
}

Then create a 404.html file which looks something like this but adjusted for your URL instead of yourdomain.com:

<html>
<head>
<meta http-equiv="refresh" content="2;URL=https://yourdomain.com/">
<title>Redirecting</title>
</head>
<body>
<h2>Redirecting</h2>
<p>You are being redirected to the <a href="https://yourdomain.com/">secure version of this site.</a></p>
</body>
</html>

Then restart Nginx again.

You should now have a secure Pylons app on the https port and a redirect page on the http port.

Further Reading:

http://articles.slicehost.com/2007/10/19/debian-etch-installing-nginx http://ubuntuforums.org/showthread.php?t=453053 http://sudhanshuraheja.com/2007/09/remove-nginx-from-ubuntu-fiesty-fawn.html http://www.rkblog.rk.edu.pl/w/p/pylons-and-nginx/

Comments

Sudhanshu

Posted:2007-12-11 05:14

Great article. And thanks for the link :) :URL: http://sudhanshuraheja.com

lynton

Posted:2008-01-10 19:05

this doesn't work for me on latest debian stable. needs lib6c upgrading to a later version see here http://technokracy.net/nginx/.

I followed the instructions from the english nginx wiki here http://wiki.codemongers.com/InstallingFromDebianRepositories?highlight=%28debian%29 but that pushes apache up to version 2.2 and all sorts of other stuff I'd rather not mess with.

I presume that i wont have any problems compiling the latest version now but id rather keep other componants as per debian stable. any ideas? :URL: http://d3r.com

thejimmyg

Posted:2008-01-11 12:15

You can't install the latest version on Debian stable because it isn't in the repository. Don't install anything which isn't in the stable repository from a .deb file onto a stable installation as it will cause all manner of dependency problems such as the ones you described. Absolutely do not follow the instructions in those two links for a stable system.

As I showed in the above entry, compiling Nginx from scratch is actually very easy and this is the correct way to install more recent versions on Debian stable without breaking all the dependencies. :URL: http://jimmyg.org

(view source)

James Gardner: Home > Blog > 2007 > Nginx Proxying to Pylons with SSL...