#Nginx Basics for Ubuntu
Please see http://wiki.nginx.org/Main for more information. See http://arstechnica.com/gadgets/2012/11/how-to-set-up-a-safe-and-secure-web-server/ for a tutorial on how to install Nginx.
##Installation To install, you can install the version which is in the standard Ubuntu repositories but it is normally quite old and will not have the latest security patches. The best way is to update the repositories first:
apt-get update
apt-get install python-software-properties
apt-get upgrade
add-apt-repository ppa:nginx/development
apt-get install nginx
To check that it is installed:
nginx -v
##Configuration
The basic static site is located in /usr/share/nginx/html
. You can edit the default index.html
file or drop your own file in this folder and it will be instantly visible.
The nginx configuration files are located in /etc/nginx
. The main configuration file is nginx.conf
, which by default also includes any additional configuration files on the conf.d
directory and any virtual host files in the sites-enabled
directory. The standard practice is to use the main nginx.conf
for server-wide behaviour and to store information related to individual websites in an individual file per site in the sites-available
directory. The normal practice is then to symlink these individual site files from sites-available
into sites-enabled
. and the contents of the sites-enabled
directory are actually called from the main configuration file.
###Worker Processes
user www-data;
worker_processes 2;
The first lines of the nginx.conf
file show the username that it runs under (ie www-data) and the number of worker processes running. In general, you should have one worker_process per cpu. You should also ensure that the www-data user has access to the folders where you put site. The www-data users should only have access to the site location and nothing else to reduce the chance that a compromised server can do damage.
events {
worker_connections 768;
multi_accept on;
}
The worker_connections
define the number of connections allowed per worker process. The multi_accept setting controls how eager the nginx worker processes are to grab new connections—with it on, nginx grabs as many connections as it can out of the listen queue. There are some circumstances where you'd want this off but for a home server you're better off enabling it.
###Gzip Settings
Modern Web servers have the ability to compress the content that they're serving using gzip, and we want to provide some additional info to nginx to ensure that it's compressing everything that it possibly can. This uses a small amount of extra CPU power but it's more efficient and can save on bandwidth.
gzip on;
gzip_disable "msie6";
This turns on Gzip and disables it for Internet Explorer 6, which has issues dealing with zipped content. Below these two lines, add the following:
gzip_min_length 1100;
gzip_vary on;
gzip_proxied any;
gzip_buffers 16 8k;
gzip_types text/plain text/css application/json application/x-javascript
text/xml application/xml application/rss+xml text/javascript
image/svg+xml application/x-font-ttf font/opentype
application/vnd.ms-fontobject;
This sets some additional parameters to fine-tune the compression. Specifically, we're ensuring that only files over a certain size are compressed so as not to waste time on tiny files, helping to ensure browser caches work with the gzipped files, setting our gzip buffers appropriately, and ensuring we gzip as many applicable types of files as possible.
###Website Setup The default website's settings are stored in a file named, appropriately enough, default. It's probably a good idea to change this and leave the default file for reference, so let's take care of that right now.
Your nginx install can support far more than a single website and the files that define your server's sites live in the /etc/nginx/sites-available
directory. However, the files in this directory aren't "live"—you can have as many site definition files in here as you want but nginx won't actually do anything with them unless they're symlinked into the /etc/nginx/sites-enabled
directory (you could also copy them there, but symlinking ensures there's only one copy of each file to keep track of). This gives you a method to quickly put websites online and take them offline without having to actually delete any files—when you're ready for a site to go online, symlink it into sites-enabled and restart nginx.
First copy the default site:
cd /etc/nginx/sites-available
cp default www
Next, we need to activate our www virtual host file, which is done by creating a symbolic link for it in the sites-enabled directory. At the same time, we're going to deactivate the default virtual host by deleting its symbolic link:
cd /etc/nginx/sites-enabled
rm default
ln -s /etc/nginx/sites-available/www /etc/nginx/sites-enabled/www
Then reload the new settings
/etc/init.d/nginx reload
The site file will look like:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /usr/share/nginx/html;
index index.html index.htm;
# Make site accessible from http://localhost/
server_name localhost;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}
# Only for nginx-naxsi used with nginx-naxsi-ui : process denied reques$
#location /RequestDenied {
# proxy_pass http://127.0.0.1:8080;
#}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
#error_page 500 502 503 504 /50x.html;
#location = /50x.html {
# root /usr/share/nginx/html;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# fastcgi_split_path_info ^(.+\.php)(/.+)$;
# # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
#
# # With php5-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# # With php5-fpm:
# fastcgi_pass unix:/var/run/php5-fpm.sock;
# fastcgi_index index.php;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# root html;
# index index.html index.htm;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
# HTTPS server
#
#server {
# listen 443;
# server_name localhost;
#
# root html;
# index index.html index.htm;
#
# ssl on;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
#
# ssl_session_timeout 5m;
#
# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
# ssl_prefer_server_ciphers on;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
In essence, removing the comments this becomes:
server {
root /usr/share/nginx/html;
index index.html index.htm;
server_name localhost;
location / {
try_files $uri $uri/ /index.html;
}
location /doc/ {
alias /usr/share/doc/;
autoindex on;
allow 127.0.0.1;
allow ::1;
deny all;
}
}
The server
declaration indicates this file defines a specific virtual host. The root
directive indicates the actual path on your hard drive where this virtual host's assets (HTML, images, CSS, and so on) are located, ie /usr/share/nginx/html
. The index
setting tells Nginx what file or files to serve when it's asked to display a directory. If none of the files listed are found, Nginx will either reply with a listing of all the files in that directory (if configured to do so) or with an error.
The server_name
setting allows Nginx to server multiple virtual hosts running on one server (ie www.mysite.com, support.mysite.com, test.yoursite.com etc).
The locations
setting specifies different settings that apply to different paths. The second location is a hangover from Apache and can be deleted. Within the location there is a try_files
setting which tells Nginx what to do with each incoming request. The default is that Nginx should take each request and try and match it to a file with the same name or a directory index if the file does not exist. The try_files
setting is very flexible and can be used to handle a range of routing issues.
Change the try file to:
location / {
try_files $uri $uri/ =404;
}
This tells Nginx that when it cannot find something, it should show a 404 Not found error page.
##Security Edit the node.conf and in the Basic Settings set:
server_tokens off;
This stops Nginx from sending identifying information such as version number etc when it serves an error.
To further tighten the security add the following below server tokens off.
client_max_body_size 4096k;
client_header_timeout 10;
client_body_timeout 10;
keepalive_timeout 10 10;
send_timeout 10;
The first setting client_max_body_size
sets the max size of the upload file to 4096k. client_header_timeout
and client_body_timeout
set the maximum amount of time Nginx will wait around on the client to specify a request header or ask for an object to be served; keepalive_timeout
specifies that Nginx should hold open a keep-alive connection for no more than 10 seconds and also suggests to the client that it should close its connections after the same interval; and send_timeout tells Nginx to close its connection to a client if that client takes too long between successive requests.
These settings will limit the amount of resources Nginx spends responding to slow requests, so that it's considerably more difficult for an attacker to tie up the server's resources. Nginx's architecture makes it less vulnerable to this kind of denial of service attack than other Web servers, but it's perfectly possible to exhaust Nginx's resources with enough attacking machines. This will help mitigate that risk.
###Location Security
To Make the site only visible internally you can use:
location / {
try_files $uri $uri/ =404;
allow 192.168.1.0/24;
allow 127.0.0.1;
deny all;
}
This could be useful if you only want an api available internally.
You can also lock down individual directories or files (ie a personal folder):
location /personal/ {
allow 192.168.1.0/24;
allow 127.0.0.1;
deny all;
}
Nginx lets you use regular expressions to define locations, which gives you a huge amount of configurability. A location doesn't have to be a directory or a file—anything that matches a regex can be a location.
##Commands To start nginx (Linux)
sudo /etc/init.d/nginx start
To stop nginx (Linux)
sudo /etc/init.d/nginx stop
To reload nginx config (Linux)
sudo /etc/init.d/nginx reload
Location of sites (Linux)
/var/www/
To check to see if it is running
ps -ef | grep nginx
To edit the nginx Config File
sudo nano /etc/nginx/nginx.conf
##Sample file with virtual sites
http://www.test.com
http://www.example.com
http://www.nodeapp.com
http://localhost
The hosts file can be edited at:
sudo nano /etc/hosts
server {
listen 80;
listen [::]:80;
root /var/www/test.com;
server_name www.test.com;
location / {
index index.htm index.html;
}
}
server {
listen 80;
listen [::]:80;
root /var/www/example.com;
server_name www.example.com;
location / {
index index.htm index.html;
}
}
#Passthrough to node server application
server {
listen 80;
listen [::]:80;
root /var/www/nodeapp.com;
server_name www.nodeapp.com;
location / {
#proxy_pass http://127.0.0.1:3001/api;
proxy_pass http://127.0.0.1:8443;
}
server {
listen 80 default_server;
listen [::]:80 ipv6only=on default_server;
root /var/www/html;
index index.html index.htm;
# Make site accessible by specifying the wildcard servername
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ /index.html;
}
}
The server
declaration indicates this file defines a specific virtual host. The root directive indicates the actual path on your hard drive where this virtual host's assets (HTML, images, CSS, etc) are located ie /usr/share/nginx/html
. You can change this to a different location. The index directive tells Nginx what file or files to serve when it's asked to display a directory. Here, Nginx is told to first try to show that directory's index.html file, and if that file doesn't exist, try instead to show index.htm. You can add additional files here, too, like index.php if your site is using PHP. If none of the files listed are found, Nginx will either reply with a listing of all the files in that directory (if configured to do so) or with an error.
The server_name directive is a key setting. When you have multiple virtual hosts running on one server, server_name is how Nginx knows which site to serve up. If you had your www virtual host file and another virtual host file named, say, forum (because maybe you're hosting a Web forum), you could set the www virtual host as the virtual host that gets loaded when users request www.yoursite.com and the forum virtual host as the one that gets served when a user requests forum.yoursite.com, with Nginx keying off of the server name in the requested URL. For now, we can leave this alone.
Below this are "locations," which are the things your users are going to be interested in accessing. Defining locations gives you a way to apply different settings to different paths on the server. Right now, there are two locations: one at "/", called the "root location," and one at /doc/, which points at /usr/share/doc. This second location is another Apache legacy holdover and we can delete it—go ahead and remove this entire block:
##Permissions Nginx normally runs under the www-data group. This group needs to have read access to the folder.
##IP Blacklist/Whitelist Nginx can be configured to allow access only from specific ip addresses or to block specific ip addresses. This can be useful when you just want the application to be used internally or by specific customers.
location
{
allow 192.168.1.7;
deny all;
}
##Worker Processes By default the nginx server has 1 worker process. For every code on your nginx server you can add a worker process (ie 2 cpu's 2 nginx processes)
worker_processes 2;
You can also increase the number of worker_connections from the default of 1024 if you have a higher spec server.
events {
worker_connections 2000;
}
##More Advanced Sample from nginx site
user www www;
worker_processes 2;
pid /var/run/nginx.pid;
# [ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx.error_log info;
events {
worker_connections 2000;
# use [ kqueue | rtsig | epoll | /dev/poll | select | poll ] ;
use kqueue;
}
http {
include conf/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
log_format download '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_range" "$sent_http_content_range"';
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
output_buffers 1 32k;
postpone_output 1460;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
send_lowat 12000;
keepalive_timeout 75 20;
# lingering_time 30;
# lingering_timeout 10;
# reset_timedout_connection on;
server {
listen one.example.com;
server_name one.example.com www.one.example.com;
access_log /var/log/nginx.access_log main;
location / {
proxy_pass http://127.0.0.1/;
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;
client_body_temp_path /var/nginx/client_body_temp;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_send_lowat 12000;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_temp_path /var/nginx/proxy_temp;
charset koi8-r;
}
error_page 404 /404.html;
location /404.html {
root /spool/www;
charset on;
source_charset koi8-r;
}
location /old_stuff/ {
rewrite ^/old_stuff/(.*)$ /new_stuff/$1 permanent;
}
location /download/ {
valid_referers none blocked server_names *.example.com;
if ($invalid_referer) {
#rewrite ^/ http://www.example.com/;
return 403;
}
# rewrite_log on;
# rewrite /download/*/mp3/*.any_ext to /download/*/mp3/*.mp3
rewrite ^/(download/.*)/mp3/(.*)\..*$ /$1/mp3/$2.mp3 break;
root /spool/www;
# autoindex on;
access_log /var/log/nginx-download.access_log download;
}
location ~* ^.+\.(jpg|jpeg|gif)$ {
root /spool/www;
access_log off;
expires 30d;
}
}
}