configuring nginx on joyent
This is our nginx configuration file in all of its glory. I've annotated it for the purpose of sharing what I've learned with the world.
intent
Our goals in using nginx as a front-end to our rails-based website were these: + to improve "user experience" (have quicker responses) + to improve security for the users and our website's software + to improve system resource allocation
To accomplish this, we deployed nginx as a lightweight web server to act as a proxy for the application server. Nginx handles all web requests, and passes on anything that has to be handled by the application server. Anything else it handles itself. These "other" requests are usually for "static" content (that's unchanging stuff like images and javascript files), which it serves directly. Bogus requests are passed on to a search engine URL that turns such requests into searches on our site.
The security and performance issues can't be overstated. Our website was partially removed from active service by someone (script kiddie) because I was still passing on too many requests to the application server. While that attempted intrusion attack didn't work, it certainly brought our application server to its knees. Part of the configuration you see below comes from an exhaustive description here. The GZIP configuration stuff I found here.
nginx.conf
In this file, SSLDIRECTORY and HOMEDIRECTORY are stand-ins for the real directories.
user www www;
worker_processes 1;
pid /var/spool/nginx/nginx.pid;
events {
worker_connections 256; # mod mw was 1024
user eventport;
}
http {
include /opt/local/etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr$remote_user [$time_local] $request '
'"$status" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /HOMEDIRECTORY/web/logs/nginx.access.log main;
error_log /HOMEDIRECTORY/web/logs/nginx.error.log;
sendfile on; # quicker file delivery
tcp_nopush on;
keepalive_timeout 20; # was 60
server_tokens off;# don't talk about being nginx
# fine-tuning GZIP behaviour
gzip on;
gzip_comp_level 2;
gzip_proxied any;
gzip_types text/plain text/css application/x-javascript
text/xml application/xml application/xml+rss text/javascript;
#
# Application server addresses
# + add more entries if necessary
upstream caritas_appserver {
server unix:/tmp/thin.caritas.0.sock;
}
#
# main webserver for caritas.co.jp
server {
# basic configuration
listen 80;
server_name caritas.co.jp www.caritas.co.jp;
charset utf-8;
root /HOMEDIRECTORY/web/public;
index index.html;
# security-specific stuff
#
# only accept requests to this website
if ($host !~ ^(caritas.co.jp|www.caritas.co.jp|blog.caritas.co.jp)$ ) {
return 444;
}
# only accept requests of this kind
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
}
# bad user agents
if ($http_user_agent ~* LWP::Simple|BBBike|wget) {
return 403;
}
# tuning for performance and security
client_body_buffer_size 1k;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
client_body_timeout 20;
client_header_timeout 20;
keepalive_timeout 5 5;
send_timeout 20;
# reject requests for things no one needs
location ~ /.ht { # .htusers and .htaccess files
deny all;
}
location ~ /.svn { # version management stuff
deny all;
}
# handle image requests and other static content
location ~* ^.+.(js|css|jpg|png)$ {
access_log off;
expires 30d;
}
#
# redirects
#
# On every website, things tend to move
location ~ /public/about* {
rewrite "^/public/about/(.*)$" /about/$1 permanent;
}
location ~ /howto* {
rewrite ^/howto(.*)$ http://blog.caritas.co.jp/post/532829816 redirect;
}
#
# how to handle special content
#
# user tracking software
location ~ /mint* {
rewrite ^/mint(.*)$ http://caritas.co.jp:8080/mint$1 redirect;
}
#
# pass these on to the SSL server
#
# order a sample ring
location ~ /store/sample.* {
rewrite ^/(.*)$ https://caritas.co.jp/$1 redirect;
}
# buying a ring
location ~ /checkout.* {
rewrite ^/(.*)$ https://caritas.co.jp/$1 redirect;
}
#
# Application server
#
# proxy configuration (for application server)
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
# rails code, send to proxy
location ~* ^/(store|public|about|advice) {
proxy_pass http://caritas_appserver;
break;
}
location / {
# if you can't find a file but (file).html exists,
# rename the requested object
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
if (!-f $request_filename) {
rewrite /(.*) http://www.google.co.jp/search?
hl=ja&q=site%3Acaritas.co.jp+$1 break;
}
}
}
server {
# SSL server configuration. Much the same as above.
listen 443;
server_name caritas.co.jp www.caritas.co.jp;
charset utf-8;
access_log /HOMEDIRECTORY/web/logs/nginx.access.log main;
error_log /HOMEDIRECTORY/web/logs/nginx.error.log;
root /HOMEDIRECTORY/web/public;
index index.html;
if ($host !~ ^(caritas.co.jp|www.caritas.co.jp|blog.caritas.co.jp)$ ) {
return 444;
}
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
}
if ($http_user_agent ~* LWP::Simple|BBBike|wget) {
return 403;
}
client_body_buffer_size 1k;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 5 5;
send_timeout 10;
location ~ /.ht {
deny all;
}
location ~ /.svn {
deny all;
}
location ~ /mint* {
deny all;
}
location ~* ^.+.(js|css|jpg|png)$ {
access_log off;
expires 30d;
}
#
# These requests should not be handled by the SSL server. They do
# not contain sensitive content and can be handled by the lighter
# non-SSL web server.
location ~ /advice.* {
rewrite ^/(.*)$ http://caritas.co.jp/$1 redirect ;
}
location ~* /store/show.* {
rewrite ^/(.*)$ http://caritas.co.jp/$1 redirect ;
}
location ~ /public.* {
rewrite ^/(.*)$ http://caritas.co.jp/$1 redirect ;
}
location ~ /about.* {
rewrite ^/(.*)$ http://caritas.co.jp/$1 redirect ;
}
#
# Application server content
#
# These URL's should be handled by the application server,
# which hides behind the nginx proxy server. Note that even
# though this is a SSL proxy server, you DO NOT use SSL
# to communicate with the application server.
location ~ /store/sample.* {
proxy_pass http://caritas_appserver;
break;
}
location ~ /checkout.* {
proxy_pass http://caritas_appserver;
break;
}
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For https;
ssl on;
ssl_certificate /SSLDIRECTORY/openssl.pem;
ssl_certificate_key /SSLDIRECTORY/openssl.pem;
ssl_prefer_server_ciphers on;
location / {
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
if (!-f $request_filename) {
return 404;
break;
}
}
}
}


