Intro


    # ----- /etc/nginx/nginx.conf
    user  nginx;
    worker_processes  1;
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    events {
      # ...
    }
    http {
      include       /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  /var/log/nginx/access.log  main;
      sendfile        on;
      #tcp_nopush     on;
      keepalive_timeout  65;
      #gzip  on;
      include /etc/nginx/conf.d/*.conf;
    }

    # ----- /etc/nginx/conf.d/example.com.conf
    # ----- /etc/nginx/sites-enabled/default
    server {

      listen         80 default_server; # where to listen for HTTP connections
      listen         [::]:80 default_server;
      # listen       127.0.0.16:80; # never listen hostname

      server_name    example.com www.example.com;
      # server_name   *.example.com;  # serve all sub-doamains
      # server_name   .example.com;   # serve all sub-doamains
      # server_name   example.*;      # all domain names beginning with example.

      root           /var/www/example.com; # avoid using / only, vulnerability !
      index          index.html; # which file to serve if none is specified

      try_files $uri /index.html;

      # initial location
      location / {
        # avoid root in initial location
        root /var/www/example.com;
        # index is already defined, no need, it is inherited ...
        index index.html index.htm;
      }

      location /bar {
          root /some/other/place; # root for THIS location, index already defined
          # [...]
      }

      # use $request_filename instead of $document_root$fastcgi_script_name,
      # usage of alias directive with $document_root$fastcgi_script_name,
      # $document_root$fastcgi_script_name will return the wrong path
      location /api/ {
        index  index.php index.html index.htm;
        alias /app/www/;
        location ~* "\.php$" {
          try_files      $uri =404;
          fastcgi_pass   127.0.0.1:9000;
          fastcgi_param  SCRIPT_FILENAME  $request_filename;
        }
      }

      # specific
      location /images/ { }
      location /blog/ { }
      location /planet/ { }
      # more specific
      location /planet/blog/ { }

      # RegEx, case-sensitive requests
      # case-sensitive
      location ~ IndexPage\.php$ { }
      location ~ ^/BlogPlanet(/|/index\.php)$ { } # /BlogPlanet/ and /BlogPlanet/index.php
      # case-insensitive
      location ~* \.(pl|cgi|perl|prl)$ { }
      location ~* \.(md|mdwn|txt|mkdn)$ { }
      # intercept and process
      location ^~ /images/IndexPage/ { }
      location ^~ /blog/BlogPlanet/ { }
      # exact
      location = / { }

    }

    # serve static first, then scripts
    server {
      server_name _;
      root /var/www/site;
      location / {
        try_files $uri $uri/ @proxy;
        # try_files $uri $uri/ /index.php;
      }
      location @proxy {
      # location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/tmp/phpcgi.socket;
      }
    }

    # serving static files
    server {
      server_name www.domain1.com;
      access_log logs/domain1.access.log main;
      error_log logs/domain1.error error;
      root /var/www/domain1.com/htdocs;
    }
    server {
      server_name www.domain2.com;
      access_log  logs/domain2.access.log main;
      error_log logs/domain2.error error;
      root /var/www/domain2.com/htdocs;
    }

    # catch all
    server {
      listen 80 default_server;
      server_name _; # This is just an invalid value which will never trigger on a real hostname.
      access_log logs/default.access.log main;
      server_name_in_redirect off;
      root  /var/www/default/htdocs;
    }

    # easy way to keep adding new subdomains
    server {
      # Replace this port with the right one for requirements
      listen 80 default_server;  #could also be 1.2.3.4:80
      # Multiple hostnames separated by spaces.  Replace these as well.
      server_name star.yourdomain.com *.yourdomain.com; # Alternately: _
      root /PATH/TO/WEBROOT;
      error_page 404 errors/404.html;
      access_log logs/star.yourdomain.com.access.log;
      index index.php index.html index.htm;
      # static file 404's aren't logged and expires header is set to maximum age
      location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
        access_log off;
        expires max;
      }
      location ~ \.php$ {
        include fastcgi_params;
        fastcgi_intercept_errors on;
        # By all means use a different server for the fcgi processes if you need to
        fastcgi_pass   127.0.0.1:YOURFCGIPORTHERE;
      }
      location ~ /\.ht {
        deny  all;
      }
    }

    # avoid IF clause, use:
    server {
      server_name www.example.com;
      return 301 $scheme://example.com$request_uri;
    }
    server {
      server_name example.com;
      # [...]
    }

    # avoid IF-file checking, use:
    server {
      root /var/www/example.com;
      location / {
        try_files $uri $uri/ /index.html;
      }
    }

    try_files $uri $uri/ /index.php?q=$uri&$args;
    # checking as url, then as directory/, then serve with default /index.php
    try_files $uri $uri/ /index.php;

    # process only specific files
    # + cgi.fix_pathinfo=0 in php.ini - to stop processing if the file is not found
    location ~* (file_a|file_b|file_c)\.php$ {
      fastcgi_pass backend;
      # [...]
    }

    # disable the execution of PHP files in any directory
    location /uploaddir {
      location ~ \.php$ {return 403;}
      # [...]
    }

    # filter out the problem condition
    location ~* \.php$ {
      try_files $uri = 404;
      fastcgi_pass backend;
      # [...]
    }
    # ... nested
    location ~* \.php$ {
      location ~ \..*/.*\.php$ {return 404;}
      fastcgi_pass backend;
      # [...]
    }

    # REWRITE

    # $request_uri for capturing
    # rewrite ^/(.*)$ http://example.com/$1 permanent; # BAD
    rewrite ^ http://example.com$request_uri? permanent;
    return 301 http://example.com$request_uri;

    # rewrites are relative unless you tell NGINX that theyre not
    # rewrite ^ example.com permanent; # BAD
    rewrite ^ http://example.com permanent;

    # it is advised to not use SSLv3
    # provide only the TLS protocols instead
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  

Full example 1

nginx.conf


    user       www www;  ## Default: nobody
    worker_processes  5;  ## Default: 1
    error_log  logs/error.log;
    pid        logs/nginx.pid;
    worker_rlimit_nofile 8192;

    events {
      worker_connections  4096;  ## Default: 1024
    }

    http {
      include    conf/mime.types;
      include    /etc/nginx/proxy.conf;
      include    /etc/nginx/fastcgi.conf;
      index    index.html index.htm index.php;

      default_type application/octet-stream;
      log_format   main '$remote_addr - $remote_user [$time_local]  $status '
        '"$request" $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for"';
      access_log   logs/access.log  main;
      sendfile     on;
      tcp_nopush   on;
      server_names_hash_bucket_size 128; # this seems to be required for some vhosts

      server { # php/fastcgi
        listen       80;
        server_name  domain1.com www.domain1.com;
        access_log   logs/domain1.access.log  main;
        root         html;

        location ~ \.php$ {
          fastcgi_pass   127.0.0.1:1025;
        }
      }

      server { # simple reverse-proxy
        listen       80;
        server_name  domain2.com www.domain2.com;
        access_log   logs/domain2.access.log  main;

        # serve static files
        location ~ ^/(images|javascript|js|css|flash|media|static)/  {
          root    /var/www/virtual/big.server.com/htdocs;
          expires 30d;
        }

        # pass requests for dynamic content to rails/turbogears/zope, et al
        location / {
          proxy_pass      http://127.0.0.1:8080;
        }
      }

      upstream big_server_com {
        server 127.0.0.3:8000 weight=5;
        server 127.0.0.3:8001 weight=5;
        server 192.168.0.1:8000;
        server 192.168.0.1:8001;
      }

      server { # simple load balancing
        listen          80;
        server_name     big.server.com;
        access_log      logs/big.server.access.log main;

        location / {
          proxy_pass      http://big_server_com;
        }
      }
    }
  

proxy.conf


    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;
  

fastcgi.conf


    fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_param  QUERY_STRING       $query_string;
    fastcgi_param  REQUEST_METHOD     $request_method;
    fastcgi_param  CONTENT_TYPE       $content_type;
    fastcgi_param  CONTENT_LENGTH     $content_length;
    fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
    fastcgi_param  REQUEST_URI        $request_uri;
    fastcgi_param  DOCUMENT_URI       $document_uri;
    fastcgi_param  DOCUMENT_ROOT      $document_root;
    fastcgi_param  SERVER_PROTOCOL    $server_protocol;
    fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
    fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
    fastcgi_param  REMOTE_ADDR        $remote_addr;
    fastcgi_param  REMOTE_PORT        $remote_port;
    fastcgi_param  SERVER_ADDR        $server_addr;
    fastcgi_param  SERVER_PORT        $server_port;
    fastcgi_param  SERVER_NAME        $server_name;

    fastcgi_index  index.php;

    fastcgi_param  REDIRECT_STATUS    200;
  

mime.types


    types {
      text/html                             html htm shtml;
      text/css                              css;
      text/xml                              xml rss;
      image/gif                             gif;
      image/jpeg                            jpeg jpg;
      application/x-javascript              js;
      text/plain                            txt;
      text/x-component                      htc;
      text/mathml                           mml;
      image/png                             png;
      image/x-icon                          ico;
      image/x-jng                           jng;
      image/vnd.wap.wbmp                    wbmp;
      application/java-archive              jar war ear;
      application/mac-binhex40              hqx;
      application/pdf                       pdf;
      application/x-cocoa                   cco;
      application/x-java-archive-diff       jardiff;
      application/x-java-jnlp-file          jnlp;
      application/x-makeself                run;
      application/x-perl                    pl pm;
      application/x-pilot                   prc pdb;
      application/x-rar-compressed          rar;
      application/x-redhat-package-manager  rpm;
      application/x-sea                     sea;
      application/x-shockwave-flash         swf;
      application/x-stuffit                 sit;
      application/x-tcl                     tcl tk;
      application/x-x509-ca-cert            der pem crt;
      application/x-xpinstall               xpi;
      application/zip                       zip;
      application/octet-stream              deb;
      application/octet-stream              bin exe dll;
      application/octet-stream              dmg;
      application/octet-stream              eot;
      application/octet-stream              iso img;
      application/octet-stream              msi msp msm;
      audio/mpeg                            mp3;
      audio/x-realaudio                     ra;
      video/mpeg                            mpeg mpg;
      video/quicktime                       mov;
      video/x-flv                           flv;
      video/x-msvideo                       avi;
      video/x-ms-wmv                        wmv;
      video/x-ms-asf                        asx asf;
      video/x-mng                           mng;
    }
  

Full example 2

nginx.conf


    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;
        }
      }
    }
  

ReverseProxy

nginx.conf


    server {
      listen 80;
      listen [::]:80;
      server_name example.com;
      location / {
          proxy_pass http://localhost:3000/;
      }
    }

    # + caching
    http {
      proxy_cache_path  /data/nginx/cache  levels=1:2    keys_zone=STATIC:10m
      inactive=24h  max_size=1g;
      server {
        location / {
          proxy_pass             http://1.2.3.4;
          proxy_set_header       Host $host;
          # proxy_set_header X-Real-IP $remote_addr;
          proxy_buffering        on;
          proxy_cache            STATIC;
          proxy_cache_valid      200  1d;
          proxy_cache_use_stale  error timeout invalid_header updating
          http_500 http_502 http_503 http_504;
        }
      }
    }
  

Load Balancing

nginx.conf


    http {
      upstream myproject {
        server 127.0.0.1:8000 weight=3;
        server 127.0.0.1:8001;
        server 127.0.0.1:8002;
        server 127.0.0.1:8003;
      }

      server {
        listen 80;
        server_name www.domain.com;
        location / {
          proxy_pass http://myproject;
        }
      }
    }
  

PHP FastCGI

php-fpm commands


      # FPM status
      systemctl status php7.0-fpm.service
      # locate PHP configuration files
      find / \( -iname "php.ini" -o -name "www.conf" \)
      # listen.owner and listen.group variables are set to www-data by default,
      # but they need to match the user and group NGINX is running as, verify
      ps -aux | grep nginx
      # output
      root      3448  0.0  0.0  32500  3516 ?        Ss   18:21   0:00 nginx: master process /        usr/sbin/nginx -c /etc/nginx/nginx.conf
      nginx     3603  0.0  0.0  32912  2560 ?        S    18:24   0:00 nginx: worker process
      nginx     3604  0.0  0.0  32912  3212 ?        S    18:24   0:00 nginx: worker process
      # change the listen variables
      sed -i 's/listen.owner = www-data/listen.owner = nginx/g' /etc/php/7.0/fpm/pool.d/www.conf
      sed -i 's/listen.group = www-data/listen.group = nginx/g' /etc/php/7.0/fpm/pool.d/www.conf
      # prevent processing unexistent files
      sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g' /etc/php/7.0/fpm/php.ini
      # restart
      systemctl restart php7.0-fpm.service
  

/etc/nginx/fastcgi_params


    fastcgi_param   QUERY_STRING            $query_string;
    fastcgi_param   REQUEST_METHOD          $request_method;
    fastcgi_param   CONTENT_TYPE            $content_type;
    fastcgi_param   CONTENT_LENGTH          $content_length;

    fastcgi_param   SCRIPT_FILENAME         $document_root$fastcgi_script_name;
    fastcgi_param   SCRIPT_NAME             $fastcgi_script_name;
    fastcgi_param   PATH_INFO               $fastcgi_path_info;
    fastcgi_param   PATH_TRANSLATED         $document_root$fastcgi_path_info;
    fastcgi_param   REQUEST_URI             $request_uri;
    fastcgi_param   DOCUMENT_URI            $document_uri;
    fastcgi_param   DOCUMENT_ROOT           $document_root;
    fastcgi_param   SERVER_PROTOCOL         $server_protocol;

    fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
    fastcgi_param   SERVER_SOFTWARE         nginx/$nginx_version;

    fastcgi_param   REMOTE_ADDR             $remote_addr;
    fastcgi_param   REMOTE_PORT             $remote_port;
    fastcgi_param   SERVER_ADDR             $server_addr;
    fastcgi_param   SERVER_PORT             $server_port;
    fastcgi_param   SERVER_NAME             $server_name;

    fastcgi_param   HTTPS                   $https;

    # PHP only, required if PHP was built with --enable-force-cgi-redirect
    fastcgi_param   REDIRECT_STATUS         200;
  

nginx.conf


    # proxy requests to PHP FPM via the FCGI protocol

    location ~ [^/]\.php(/|$) {
      fastcgi_split_path_info ^(.+?\.php)(/.*)$;
      if (!-f $document_root$fastcgi_script_name) {
          return 404;
      }

      # Mitigate https://httpoxy.org/ vulnerabilities
      fastcgi_param HTTP_PROXY "";

      fastcgi_pass 127.0.0.1:9000;
      fastcgi_index index.php;

      # for unix socket change fastcgi_pass
      # fastcgi_pass unix:/var/run/php-fpm.sock;

      # include the fastcgi_param setting
      include fastcgi_params;

      # SCRIPT_FILENAME parameter is used for PHP FPM determining
      #  the script name. If it is not set in fastcgi_params file,
      # i.e. /etc/nginx/fastcgi_params or in the parent contexts,
      # please comment off following line:
      # fastcgi_param  SCRIPT_FILENAME   $document_root$fastcgi_script_name;
    }
  

correct output for http://lemp.test/test.php/foo/bar.php?v=1


    array (
      'USER' => 'www-data',
      'HOME' => '/var/www',
      'FCGI_ROLE' => 'RESPONDER',
      'QUERY_STRING' => 'v=1',
      'REQUEST_METHOD' => 'GET',
      'CONTENT_TYPE' => '',
      'CONTENT_LENGTH' => '',
      'SCRIPT_FILENAME' => '/var/www/test.php',
      'SCRIPT_NAME' => '/test.php',
      'PATH_INFO' => '/foo/bar.php',
      'REQUEST_URI' => '/test.php/foo/bar.php?v=1',
      'DOCUMENT_URI' => '/test.php/foo/bar.php',
      'DOCUMENT_ROOT' => '/var/www',
      'SERVER_PROTOCOL' => 'HTTP/1.1',
      'GATEWAY_INTERFACE' => 'CGI/1.1',
      'SERVER_SOFTWARE' => 'nginx/1.4.0',
      'REMOTE_ADDR' => '192.168.56.1',
      'REMOTE_PORT' => '44644',
      'SERVER_ADDR' => '192.168.56.3',
      'SERVER_PORT' => '80',
      'SERVER_NAME' => '',
      'HTTPS' => '',
      'REDIRECT_STATUS' => '200',
      'HTTP_HOST' => 'lemp.test',
      'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0',
      'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
      'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.5',
      'HTTP_ACCEPT_ENCODING' => 'gzip, deflate',
      'HTTP_CONNECTION' => 'keep-alive',
      'PHP_SELF' => '/test.php/foo/bar.php',
      'REQUEST_TIME' => 1367829847,
    )
  

Recompile


Back to Main Page