Nginx Library

A repository of Nginx-related articles

Nginx 1.0.1 version has been released

Nginx 1.0.1 version has been released.

Download it : http://nginx.org/en/download.html

The changes include:

  • Change: now the “split_clients” directive uses MurmurHash2 algorithm because of better distribution. Thanks to Oleg Mamontov.
  • Change: now long strings starting with zero are not considered as false values. Thanks to Maxim Dounin.
  • Change: now nginx uses a default listen backlog value 511 on Linux.
  • Feature: the $upstream_… variables may be used in the SSI and perl modules.
  • Bugfix: now nginx limits better disk cache size. Thanks to Oleg Mamontov.
  • Bugfix: a segmentation fault might occur while parsing incorrect IPv4 address; the bug had appeared in 0.9.3. Thanks to Maxim Dounin.
  • Bugfix: nginx could not be built by gcc 4.6 without –with-debug option.
  • Bugfix: nginx could not be built on Solaris 9 and earlier; the bug had appeared in 0.9.3. Thanks to Dagobert Michelsen.
  • Bugfix: $request_time variable had invalid values if subrequests were used; the bug had appeared in 0.8.47. Thanks to Igor A. Valcov.

IP based country blocking

To block visitors from a specific country (or countries) using the IP addresses, Nginx needs to be compiled with the GeoIP module. This module was introduced in v0.7.63 and 0.8.6. In addition to that you need a Geo database. Install these packages under Debian :

apt-get install geoip-database libgeoip1

We now need to edit the configuration files. Put this code in the http block in /etc/nginx/nginx.conf. It can be also put in your vhosts config file outside of the server block.

geoip_country /usr/share/GeoIP/GeoIP.dat;
map $geoip_country_code $allow_visit {
    default yes;
    EG no;
    FR no;
    FI no;
}

This code sets the variable $allow_visit to yes or no, depending on the country of the visitor. In this example, we have set $allow_visit to no for Egypt, France and Finland, and yes for all other countries. Alternately, if you want to block all countries except for a few, set the default to no and set the variable to yes for a select few. A list of country codes can be found here.

Now we need to use the $allow_visit variable to block visitors. Inside your server block, add this :

if ($allow_visit = no) {
    return 403;
}

This will return the “403 Forbidden” page for all visitors from countries whose country code is set to no. You can also define a custom 403 page which is a bit more helpful than the default one.

error_page 403 /custom_403.html;

It is also possible to use this for redirecting users based on their country, but that’ll be explored in another post.

Running CGI scripts using thttpd

Nginx cannot run CGI scripts natively. You have to either use the Perl-FastCGI daemon to run your Perl scripts, or for a more “native” CGI environment, proxy the CGI scripts to a web-server that has the ability to execute them natively. Apache, surely, will be overkill for this purpose. Keeping in mind the low-memory requirements of most users who run Nginx, we’ll use thttpd. thttpd is a tiny, lightweight server (only around 800 kB RSS) which has the ability to execute CGI scripts natively.

First, let us install thttpd. thttpd hasn’t been in active development since late 2003 (v2.25b), but there isn’t any security issue with it. The only issue is that it doesn’t respect (or pass on) the X-Forwarded-For header. So, if you are using Debian 5.0.X Lenny, please build from source after applying this patch or install from the Squeeze repositories using apt-pinning (This issue was fixed in v2.25b-10) .

Assuming you are using Debian Squeeze,

apt-get install thttpd

Replace the thttpd configuration file with our own :

mv /etc/thttpd/thttpd.conf /etc/thttpd/thttpd.conf.orig
vi /etc/thttpd/thttpd.conf

Put this in the file :

host=127.0.0.1
port=8000
dir=/var/www  #change this to the $document_root from nginx config file
user=www-data
cgipat=**.cgi|**.pl
logfile=/var/log/thttpd.log
pidfile=/var/run/thttpd.pid

Now let us start thttpd.

invoke-rc.d thttpd start

We also need to configure nginx to pass on the requests for CGI scripts to thttpd. Add this to your configuration file :

location ~ \.cgi|pl$ {
     proxy_pass   http://127.0.0.1:8000;
     include proxy.conf;
}

We also need to create a file with some configuration parameters for nginx :

vi /etc/nginx/proxy.conf

Put this in the file :

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;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

Now let us reload the Nginx configuration :

nginx -s reload

CGI scripts should be now transparently proxied to and executed by thttpd running on port 8000.

Nginx 1.0.0 stable has been released

Nginx 1.0.0 stable version has been released.

Download it : http://nginx.org/en/download.html

The changes include :

  • Bugfix: a cache manager might hog CPU after reload. Thanks to Maxim Dounin.
  • Bugfix: an “image_filter crop” directive worked incorrectly coupled with an “image_filter rotate 180” directive.
  • Bugfix: a “satisfy any” directive disabled custom 401 error page.

Installing the latest version of Nginx on Ubuntu

The Nginx release on the Ubuntu repositories is often outdated. Igor pushes out new versions of Nginx quite frequently and it’s understandable that the Ubuntu package maintainers do not keep up. Also, Ubuntu only includes major version updates with new OS releases. So, if the Nginx development branch turns stable, and you plan on staying on your LTS (Long Term Support) version, you might not be able to get the newer version of Nginx unless you upgrade your OS.

So, in view of all this, Michael Lustfield and a bunch of other cool folks maintain a Launchpad PPA where they provide the latest versions of Nginx from both the stable and development branch. To get the latest version of Nginx from the PPA, follow these steps :

add-apt-repository ppa:nginx/stable
apt-get update && apt-get install nginx

Use ppa:nginx/development to get the latest development version.

If you want to do it manually, you’ll need to edit your sources.list, import the appropriate key, and then install/upgrade Nginx.

echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu $(lsb_release -cs) main" >> /etc/apt/sources.list
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C
apt-get update && apt-get install nginx

Here too you can use deb http://ppa.launchpad.net/nginx/development/ubuntu $(lsb_release -cs) main to get the latest development version.

You now have the latest version of Nginx on your server. Ubuntu will also automatically pull down and install updates for Nginx if they are available.

Setting up Perl FastCGI with Nginx

This article assumes that you are running on Debian Lenny (or above) and uses aptitude/apt-get for fetching and installing packages.

Install these packages :

apt-get install nginx libfcgi-perl wget

Now we replace Nginx’s package maintainer’s vhosts file with our own.

mv /etc/nginx/sites-available/default /etc/nginx/sites-available/default.old
vi /etc/nginx/sites-available/default

Put these as the file contents :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
  listen   80;
  server_name  example.com www.example.com;
  root   /var/www/example.com;
  access_log  /var/www/logs/example.com.access.log;  

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

  location ~ \.pl|cgi$ {
      try_files $uri =404;
      gzip off;
      fastcgi_pass  127.0.0.1:8999;
      fastcgi_index index.pl;
      fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
      include fastcgi_params;
      } 
}

Now let us create the directory where the site will reside and assign proper ownership to it.

mkdir /var/www/example.com
chown -R www-data:www-data /var/www/example.com

Next, we should download and configure a FastCGI wrapper script (credit: Denis S. Filimonov), a Debian init script to start/stop the FastCGI process, give them the necessary permissions to be executed and set the init script to start up the FastCGI daemon automatically.

wget http://nginxlibrary.com/downloads/perl-fcgi/fastcgi-wrapper -O /usr/bin/fastcgi-wrapper.pl
wget http://nginxlibrary.com/downloads/perl-fcgi/perl-fcgi -O /etc/init.d/perl-fcgi
chmod +x /usr/bin/fastcgi-wrapper.pl
chmod +x /etc/init.d/perl-fcgi
update-rc.d perl-fcgi defaults
insserv perl-fcgi

Now that everything is done, let us start Nginx and test out a sample Perl script.

/etc/init.d/nginx start
/etc/init.d/perl-fcgi start
vi /var/www/example.com/index.pl

Put the following in the file :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/perl

print "Content-type:text/html\n\n";
print <<EndOfHTML;
<html><head><title>Perl Environment Variables</title></head>
<body>
<h1>Perl Environment Variables</h1>
EndOfHTML

foreach $key (sort(keys %ENV)) {
  print "$key = $ENV{$key}<br>\n";
}

print "</body></html>";

Let us make the script executable by issuing the following command :

chmod a+x /var/www/example.com/index.pl

Now, go to example.com and you’ll see a list of Perl environment variables if everything was done correctly.

Denying access to a directory

Similar to Apache’s Deny from all, nginx has the deny all directive.

To deny access to a directory called ‘dirdeny’ and return a “403 Forbidden” header, use this code within your configuration file:

location /dirdeny {
        deny all;
        return 403;
}

Password protect a directory

Unlike Apache, nginx does not have any .htaccess file. Password protection is achieved by using the Nginx HttpAuthBasic module directives in the configuration file.

To password protect a directory called secret_folder, use the following directives inside the server block in the configuration file for your website.

location ^~ /secret_folder/ {
auth_basic            "Restricted Area";
auth_basic_user_file  conf/htpasswd;
}

This will password protect the directory, it’s sub folders and the files inside it. Change auth_basic_user_file directive to point to your htpasswd file. If your are using nginx version 0.6.7 or higher, note that the filename path is relative to directory of nginx configuration file, nginx.conf, rather than nginx prefix directory. So, if your nginx.conf is in /etc/nginx folder, the above code will use the htpasswd file in /etc/nginx/conf folder.

Here’s the format of the htpasswd file :

user:pass
user2:pass2:comment
user3:pass3

Passwords must be encoded by the crypt(3) function if Apache is not installed. If Apache is installed, you can use the htpasswd program to generate the htpasswd file:

htpasswd -b htpasswd NewUser NewPassword

If you want to use a web based utility to generate your htpasswd file, I’d recommend the excellent .htaccess Password Generator utility from Dynamic Drive.

In order to password protect the whole site, use the same code within location / block.

location / {
........................................
........................................
auth_basic            "Restricted Area";
auth_basic_user_file  conf/htpasswd;
}

Enable directory listing

Enabling directory listing in a folder in nginx is simple enough with just an autoindex on; directive inside the location directive. You can also enable sitewide directory listing by putting it in the server block or even enable directory access for all sites by putting it in the http block.

An example config file:

server {
        listen   80;
        server_name  domain.com www.domain.com;
        access_log  /var/...........................;
        root   /path/to/root;
        location / {
                index  index.php index.html index.htm;
        }
        location /somedir {
               autoindex on;
        }
}

A live example can be found here.