Skip to content

Instantly share code, notes, and snippets.

@eon01
Forked from leommoore/nginx_basics.md
Created April 17, 2016 11:08
Show Gist options
  • Save eon01/15f0ec9db2568a0036a8a69d69986c0d to your computer and use it in GitHub Desktop.
Save eon01/15f0ec9db2568a0036a8a69d69986c0d to your computer and use it in GitHub Desktop.
Nginx Basics

#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;
      }
    }
  }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment