I transitioned from Apache to Nginx a week or so ago, since words like “minimal” and “streamlined” are appealing to me ;). I was quite happy with Apache, but it's always nice to try something new. Anyhow here's a quick review my configuration.
On Gentoo, set the the modules you want to install by adding
the following lines to your /etc/make.conf
:
NGINX_MODULES_HTTP="access auth_basic autoindex charset fastcgi gzip gzip_static limit_req map proxy rewrite scgi ssi stub_status"
NGINX_MODULES_MAIL=""
Then install Nginx with:
# emerge -av nginx
Make any adjustments you like to /etc/nginx/mime.types
. I added:
types {
…
application/x-python py;
application/x-shell sh;
…
}
Now it's time to setup /etc/nginx/nginx.conf
. Poking about online
will give you lots of examples. Here are things that were useful to
me, in the order they appear in the http
block of my nginx.conf
.
Redirecting www.example.com
to example.com
This keeps people who accidentally add a www.
prefix to your URL
from matching the wildcard virtual host block defined below.
server {
# www.example.com -> example.com
listen 80;
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/ssl/nginx/www.example.com.pem;
ssl_certificate_key /etc/ssl/nginx/www.example.com-key.pem;
rewrite ^/(.*)$ $scheme://example.com/$1 permanent;
}
Gitweb (and general CGI approach)
gitweb server:
server {
listen 80;
server_name git.example.com;
access_log /var/log/nginx/git.example.com.access_log main;
error_log /var/log/nginx/git.example.com.error_log info;
root /usr/share/gitweb/;
index gitweb.cgi;
location /gitweb.cgi {
include fastcgi_params;
fastcgi_pass unix:/var/run/fcgiwrap.sock-1;
}
}
Because Nginx lacks built-in CGI support, we need some tricks to
get gitweb.cgi
working. We use the fcgi module to pass the
requests on to a FastCGI server which wraps gitweb.cgi
. On
Gentoo, I installed the following packages:
www-misc/fcgiwrap
, a FastCGI server for wrapping CGI scriptswww-servers/spawn-fcgi
, a FastCGI manager for spawningfcgiwrap
.
Configure spawn-fcgi
to launch fcgiwrap
with:
# cp /etc/conf.d/spawn-fcgi /etc/conf.d/spawn-fcgi.fcgiwrap
# emacs /etc/conf.d/spawn-fcgi.fcgiwrap
# cat /etc/conf.d/spawn-fcgi.fcgiwrap
FCGI_SOCKET=/var/run/fcgiwrap.sock
FCGI_ADDRESS=
FCGI_PORT=
FCGI_PROGRAM=/usr/sbin/fcgiwrap
FCGI_USER=nginx
FCGI_GROUP=nginx
FCGI_EXTRA_OPTIONS="-M 0700"
ALLOWED_ENV="PATH HOME"
HOME=/
FCGI_CHILDREN=1
FCGI_CHROOT=
# cd /etc/init.d/
# ln -s spawn-fcgi spawn-fcgi.fcgiwrap
Start fcgiwrap
with:
# /etc/init.d/spawn-fcgi.fcgiwrap start
Add it to the default runlevel with:
# rc-update add spawn-fcgi.fcgiwrap default
If you also want a virtual host serving Git over HTTP, you can add a virtual host like:
server {
# http-git.example.com
listen 80;
server_name http-git.example.com;
access_log /var/log/nginx/http-git.example.com.access_log main;
error_log /var/log/nginx/http-git.example.com.error_log info;
location / {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend;
fastcgi_param GIT_HTTP_EXPORT_ALL "";
fastcgi_param GIT_PROJECT_ROOT /var/git;
fastcgi_param PATH_INFO $document_uri;
fastcgi_pass unix:/var/run/fcgiwrap.sock-1;
}
}
This uses the same FastCGI server we used for gitweb, but this time
the backend CGI script is git-http-backend
.
Wildcard virtual hosts
To add support for virual hosts stored under /var/www/$host
, use:
server {
listen 80;
#listen 443 ssl;
server_name star.example.com *.example.com;
access_log /var/log/nginx/star.example.com.access_log main;
error_log /var/log/nginx/star.example.com.error_log info;
#ssl_certificate /etc/ssl/nginx/$host.pem;
#ssl_certificate_key /etc/ssl/nginx/$host.key;
root /var/www/$host/htdocs;
# deny access to .htaccess files
location ~ /\.ht {
deny all;
}
}
Then adding a new host is as simple as creating a new entry in
/var/www/
and updating your DNS to get the new name pointed at
your server. Unfortunately, SSL/TLS doesn't work with this
approach. It appears that certificates and keys are loaded when Nginx
starts up, but $host
is only defined after a request is received.
Nginx does support SNI though, so it will work if you write SSL
entries by hand for hosts that need them.
Main host
The configuration for my main host is more complicated, so I'll
intersperse some more comments. I setup both clear-text and SSL in
the same definition using the SSL module. The _
server name
is a special name that matches any requests which haven't already
matched and been handled by an earlier server
.
server {
# catchall virtual host (optional SSL, example.com)
listen 80 default_server;
listen 443 default_server ssl;
server_name _;
ssl_certificate /etc/ssl/nginx/example.com.pem;
ssl_certificate_key /etc/ssl/nginx/example.com-key.pem;
Nothing special with the logging or root.
access_log /var/log/nginx/example.com.access_log main;
error_log /var/log/nginx/example.com.error_log info;
root /var/www/example.com/htdocs;
Turn on SSI, and also use index.shtml
as index pages.
index index.html index.shtml;
ssi on;
Use the proxy module to pass requests for /cookbook/
and
subdirectories on to their underlying Django app.
location /cookbook/ {
proxy_pass http://localhost:33333/cookbook/;
proxy_set_header X-Real-IP $remote_addr;
}
Use the scgi module to pass requests for /gallery/
and
subdirectories on to their underlying SCGI app.
location /gallery/ {
include scgi_params;
scgi_pass localhost:4000;
}
Turn on autoindexing for /RAD/
and subdirectories using the
autoindex module.
location /RAD/ {
autoindex on;
}
Force SSL/TLS for /tree/
and subdirectories, redirecting plain-text
requests to the equivalent HTTPS page. Use the auth_basic
module for authentication, the SSL module for
$ssl_protocol
, and the rewrite module for the
redirection.
location /tree/ {
auth_basic "Family Tree";
auth_basic_user_file /home/jdoe/htpasswd;
if ($ssl_protocol = "") {
rewrite ^ https://example.com$request_uri? permanent;
}
}
Nothing special with the end of this server
block.
# deny access to .htaccess files
location ~ /\.ht {
deny all;
}
}