1. nginx - configure

last update: 2020-12-01

目錄

  • nginx 常見的 Modules
  • 安裝
  • 使用入門
  • 設定
  • nginx.conf
  • MIME Types
  • Default Host
  • SSL
  • Environment Variables
  • Set Variables
  • Embedded Variables
  • set
  • header exists
  • location 的設定及順序
  • Other View
  • ulimit
  • nginx url redirect
  • root 與 alias 的分別
  • filter by $args
  • DOC

介紹

ngnix 是其中一個解決 C10K 問題的 Web Server 來

它用了 event-driven (asynchronous) architecture 來解決此問題.

功能

  • HTTP Server
  • reverse proxy
  • mail proxy(IMAP, POP3, SMTP)

 


Modules

 

Core modules:

  • Main ( configure, logging, processes )
  • Events (epoll)

HTTP modules:

  • Core
  • Access
  • Auth Basic
  • Auto Indexing
  • Rewrite
  • Gzip
  • Index
  • Limit Requests
  • Log
  • Proxy
  • Upstream
  • FastCGI
  • uWSGI

Mail modules

  • ngx_mail_core_module (not built by default, --with-mail)

Load module

/etc/nginx/nginx.conf

load_module "modules/ngx_http_fancyindex_module.so";
load_module "modules/ngx_http_echo_module.so";
http {}

 


安裝

 

Debian 安

apt-get install nginx

Centos6 安裝

repo:

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
priority=1

準備:

mkdir /var/spool/nginx
cd /var/spool/nginx
mkdir client_body_temp proxy_temp
chown www-data. client_body_temp proxy_temp
chmod 770 client_body_temp proxy_temp

人手 compile:

https://datahunter.org/build_by_source#nginx

Install from official website

http://nginx.org/en/linux_packages.html

/etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/OS/OSRELEASE/$basearch/
gpgcheck=0
enabled=1

Replace “OS” with “rhel” or “centos”, depending on the distribution used, and “OSRELEASE” with “6” or “7”, for 6.x or 7.x versions, respectively.

i.e.

baseurl=http://nginx.org/packages/centos/7/$basearch/

 


使用入門

 

Usage

nginx [options] <configuration file>

# check version

nginx -v

nginx version: nginx/1.2.1

# Help

nginx -h

# 查看 compile 了什麼入去

nginx -V

... --with-pcre-jit --with-debug --with-http_addition_module --with-http_dav_module ...

# 查看 status

service nginx status

[ ok ] nginx is running.

# 檢查 configure file 有無錯誤

nginx -t

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

# send signal to a master process (stop, quit, reopen, reload)

nginx -s reload

其他 signal:

  • USR2 (12) - upgrade by renaming the old .pid file and running the new binary
  • WINCH (28) - engage a graceful shutdown
  • QUIT - old worker processes are terminated

 


設定

 

/etc/nginx/nginx.conf

 


LOG Location

 

# Default 的 log 位置:

  • /var/log/nginx/access.log
  • /var/log/nginx/error.log

 


nginx.conf

 

結構

....
events {
    ....
}
http {
    ....
    server {
        ....
    }
    server {
        ....
    }
}

Global Setting:

daemon on;                     // Default on

master_process on              // default on, start multiple processes

#     user     group
user  www-data www-data;

# worker_processes auto; => set one worker per CPU core
# max_clients = worker_processes * worker_connections
# Default value: 1
worker_processes 2;


pid /var/run/nginx.pid;

# LOG
error_log /file/path level;    // debug, info, notice, warn, error, and crit
log_not_found on;              // log 404, default on

timer_resolution 100ms;        //  interval between system calls to gettimeofday()

thread_stack_size 1m;         

worker_cpu_affinity 01 10;      // xx: 2 cpu core
                                // xxx: 3 cpu core
                                // e.g.
                                // 001 010 100: 3 worker processe

worker_priority 0;              // 19~-20

working_directory /user/nginx;  //  location of core files, user 可以對它寫入


#### rlimit ####

# size of core files per worker process (RLIMIT_CORE)
worker_rlimit_core   100m;

# amount of files per worker process (RLIMIT_NOFILE)
# 相當於在 /etc/security/limits.conf 加入
# "nginx soft nofile 4096" 及 "nginx hard nofile 4096"
worker_rlimit_nofile 4096;


events {
    # It should be kept in mind that this number includes all connections(connections with proxied servers),
    # not only connections with clients.
    worker_connections  1024;

    # on(Default): worker processes will accept new connections by turn
    # off: all worker processes will be notified about new connections
    accept_mutex on

    # 在 "accept_mutex on" 時 worker 多久"restart accepting new connections"
    accept_mutex_delay 500ms

    # Default: off. If multi_acceptis disabled, a worker process will accept one new connection at a time
    # on: tries to accept() as many connections as possible
    # Default: off
    multi_accept on;

    debug_connection 172.63.155.21;   # Writes detailed logs for clients matching this IP
    debug_connection 172.63.155.0/24;

    # nginx will normally select the most efficient method automatically.
    # kqueue — efficient method used on FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0, and macOS.
    # epoll — efficient method used on Linux 2.6+.
    use epoll;
}

http module 的 setting

http {

    # 不顯示 nginx version 在 error page 及 HTML header, Default ON
    server_tokens           off;

    # sendfile() is more efficient than the combination of read(2) and write(2)
    sendfile                on;

    # Enables or disables the TCP_CORK socket option on Linux. (Default off)
    # tcp_nopush is opposite to tcp_nodelay
    # The options are enabled only when sendfile is used.
    # off => attempt to send it's HTTP response headers in one packet on Linux
    #        package to wait until it gets its maximum size (MSS) before sending it to the client
    #        (for the last packet send it immediately)
    tcp_nopush              on;

    # don't buffer data-sends (disable Nagle algorithm). Good for sending
    # frequent small bursts of data in real time.
    tcp_nodelay on;

    # The server will close connections after this time.
    # Client 亦會收到 HTTP Header "Keep-Alive: timeout=timeKeep-Alive: timeout=timeKeep-Alive: timeout=time"
    keepalive_timeout       65;

    # Sets the maximum size of the types hash tables.
    types_hash_max_size     2048;

    include /etc/nginx/conf.d/*.conf;

    # gzip setting
    include snippets/gzip.conf;

    # 用來放 vhost 的設定
    include /etc/nginx/sites-enabled/*.conf;
}

server_name 的命中次序:

if name matches more than one of the specified variants

  1. exact name
  2. longest wildcard name starting with an asterisk, e.g. “*.example.org”
  3. longest wildcard name ending with an asterisk, e.g. “mail.*”
  4. first matching regular expression

listen

listen [address][:port] [additional options];

catch-all | wildcard

# default host 不是在 server_name 上設定的 !!

The default server is the first one

It can also be set explicitly which server should be default by default_server

listen       80  default_server;

# required to process requests without the “Host” header field

If no server_name is defined in a server block then nginx uses the empty name as the server name.

 => without the “Host” header field

server {
    listen       80;
    ...
}

OR

server {
    listen       80;
    server_name  example.org  www.example.org  "";
    ...
}

# 效能

if the most frequently requested names of a server are example.org and www.example.org,

it is more efficient to define them explicitly(*.example.org 放到最尾):

server {
    listen       80;
    server_name  example.org  www.example.org  *.example.org;
    ...
}

不再 www

server {
  server_name www.datahunter.org;
  return 301 $scheme://domain.com$request_uri;
}
server {
  server_name datahunter.org;
  [...]
}

http -> https

server {
       listen         80;
       server_name    my.domain.com;
       return         301 https://$server_name$request_uri;
}

try_files

Usage:

try_files file ... uri;

try_files file ... =code;

功能:

順序檢查文件是否存在, 返回第一個找到的文件

The path to a "file" is constructed from the file parameter according to the "root" and "alias" directives.

If none of the files were found, an "internal redirect" to the uri specified in the last parameter is made.

它功能相當於

location / {
  if (!-f $request_filename) {
    break;
  }
}

i.e.

[2]

# If none of the files were found, an internal redirect to the uri specified in the last parameter is made.
location /images/ {
    try_files $uri /images/default.gif;
}
location = /images/default.gif {
    expires 30s;
}

[2]

location ~* \.php$ {
    try_files $uri =404;
    ...
}

防止了 error

... [error] 14278#0: *17186 FastCGI sent in stderr: 
 "Primary script unknown" while reading response header from upstream,
 client: s.s.s.s, server: datahunter.org, request: "GET /test.php HTTP/1.1",
 upstream: "fastcgi://127.0.0.1:9056", host: "datahunter.org"

Special Wildcard name ("*")

“.example.org” = “example.org” and “*.example.org”.

server_name use a regular expression

must start with the tilde character:

server_name  ~^www\d+\.example\.net$;

gzip

snippets/gzip.conf

# 詳見 https://datahunter.org/nginx_gzip

gzip                on;

gzip_disable        "msie6";

gzip_comp_level     6;             # 1 -> 9

gzip_min_length     4k;

gzip_types          text/plain
                    text/css
                    text/javascript
                    application/javascript
                    application/x-javascript
                    application/x-font-woff
                    text/xml
                    application/xml;

gzip_proxied        any;

 


MIME Types (mime.types)

 

Format: mime.types

types {
  mimetype2 extension2 [extension3…];
  […]
}

i.e.

types {
        image/gif       gif;
        image/jpeg      jpeg jpg;
}

# force all files in a folder to be downloaded instead of being displayed:

location /downloads/ {
    # removes all MIME types
    types { };
    default_type application/octet-stream;
}

# force Content-Type (In case you have no file extension)

location ~ /share {
  add_header Content-Type application/xml;
}

i.e.

http://datahunter.org/404

 


Default Host & vhost

 

/etc/nginx/conf.d/default_vhost.conf

server {
    server_name _;
    listen 80 default_server;
    
    # for https
    #listen 443 ssl default_server;
    #ssl_certificate /etc/nginx/ssl/cacert.pem;
    #ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    
    log_not_found off;
    return 404;
    
    # mkdir -p /var/www/default
    #root /var/www/default;
}

/etc/nginx/sites-enabled/datahunter.org.conf

# vhost 設定
server {
    server_name datahunter.org www.datahunter.org;
    listen 80;
    

}

 


SSL

 

HTTPS

server {
       listen 443 ssl;
       server_name datahunter.org;;

       root html;
       index index.html index.htm;

       # The primary certificate comes first(Server), then the "intermediate certificates"
       ssl_certificate cert.pem;
       ssl_certificate_key cert.key;

       # Enable TLS session tickets (https://tools.ietf.org/html/rfc5077)
       ssl_session_tickets on;

       # builtin: a cache built in OpenSSL; used by one worker process only.(specified in sessions)
       # shared: a cache shared between all worker processes.(specified in bytes, 1m ~ 4000 sessions)
       # Both cache types can be used simultaneously,
       # for example: ssl_session_cache builtin:1000 shared:SSL:10m;
       ssl_session_cache shared:SSL:10m;

       # SSL session 的 cache 時間, Default: 5m;
       ssl_session_timeout 1d;

       # Default: "ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;"
       ssl_protocols TLSv1.1 TLSv1.2;

       # specified in the format understood by the OpenSSL library
       ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
       ssl_prefer_server_ciphers on;

       # Key Exchange
       # By default, Nginx will use the default DHE (Ephemeral Diffie-Hellman) paramaters provided by openssl.
       # This uses a weak key that gets lower scores. The best thing to do is build your own.
       # openssl dhparam 2048 > /etc/nginx/dhparam.pem
       ssl_dhparam /etc/nginx/dhparam.pem;

       # Force https on next visit
       # If you already visited the https version the next time your browser will directly visit the https site and not the http one.
       # Prevent man-in-the-middle-attacks:
       add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

       location / {
               try_files $uri $uri/ =404;
       }
}

* SSL 的 Path 不能用 Variables

Check ssl chain (intermediate certificate)

openssl s_client -connect www.x.y:443 | less

---
Certificate chain
 0 s:/OU=Domain Control Validated/OU=EssentialSSL Wildcard/CN=*.x.y
   i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
 1 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
   i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
 2 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
   i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
 3 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
   i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
---

由於 "3" 是 CA, 所以 "s" 及 "i" 都是一樣的.

因為 Device 已內置了 CA, 所以 "3" 是多餘的

intermediate certificate = "1" 及 "2"

 


Environment Variables

 

Context: main                                # 所以在 server {...} 不能用 !!

nginx removes all environment variables inherited from its parent process except the TZ variable.

env variable[=value];

 - allows preserving some of the inherited variables
 - changing variables values
 - creating new environment variables

 


Set Variables

 

set $variable value;

Sets a value for the specified variable.

The value can contain text, variables, and their combination.

 * only the variable $host allowed for access_log directives.

 


Embedded Variables

 

$http_name                      Arbitrary request header field;
                                         (converted to lower case with dashes replaced by underscores)

$cookie_name                  the name cookie

$content_type                   “Content-Type” request header field

$remote_addr

$scheme

$status

$time_local

$server_

  • $server_addr     # an address of the server which accepted a request
  • $server_name    # name of the server which accepted a request
  • $server_port      # Server's port which accepted a request

$https                       “on” if connection operates in SSL mode, or an empty string otherwise

URL

$host                         # host name from the "Host" request header field

              # in this order of precedence:
              #  host name from the request line, or
              #  host name from the “Host” request header field, or
              #  the server name matching a request

$hostname                 # host name

$request_uri               # full original request URI (with arguments)

$uri                           # current URI in request ("/path/to/file")

$scheme                    # Request scheme, "http" or "https"

ARG

$arg_name                # argument name in the request line

$args                         # arguments in the request line

$is_args                     # "?" if a request line has arguments, or an empty string otherwise

$host                         # in this order of precedence: 1. request line 2. "Host" request header field

 


Proxy Setting

 

302_problem:

 

nginx

proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;

proxy_set_header

redefining or appending fields to the request header passed to the proxied server.

These directives are inherited from the previous level

if and only if there are no proxy_set_header directives defined on the current level.

These directives are inherited from the previous level if and only if there are no proxy_set_header directives defined on the current level.

If the value of a header field is an empty string then this field will not be passed to a proxied server:

proxy_set_header Accept-Encoding "";

.htaccess

SetEnvIf X-Forwarded-Proto "https" HTTPS=on

 

主要是修正了以下問題:

<?
echo $_SERVER["REMOTE_ADDR"];
echo $_SERVER["HTTPS"];
?>

 


set

set $message "Hello Buddy";

 


header exists

 

if ($http_x_custom_header) {
    ....
}

map $http_x_header $is_ok {
    default "0";
    Value1  "1";
    Value2  "1";
    Value3  "1";
};

if ($is_ok) {
    return 405;
}

 


location 的設定及順序

 

A location can either be defined by a prefix string, or by a regular expression.

# 命中全部

location   =   PATH              # 精確匹配, 只有完全匹配上才能生效

location         FULL_PATH  # 沒有用 regex

# First matching expression stops

location  ^~  regex            # non-regular expression match

location  ~    regex             # case-sensitive regular expression

location  ~*  regex             # case-insensitive matching

# 命中部份

location        PATH             # prefix matching

解說

To find location matching a given request,

1. exact locations ( location = /xxx { } )

2. regexp locations ( location ~, location ~* ) - first match

3. prefix locations ( location /xxx { } ) - longest matching prefix is selected

i.e.

Config:

# mkdir /home/vhosts/test/public_html/images -p
root   /home/vhosts/test/public_html;
#### location test
location /                    { return 1; }
location = /                  { return 2; }
location ~* \.(gif|jpg|jpeg)$ { return 3; }
location ~ /                  { return 4; }
location ~ /images/           { return 5; }
location /img/                { return 6; }

Request:

"/"                               # 1, 2 or 4 ?     match 2, 原因: 精準("=")

"/index.html"                # 1 or 4 ?         match 4, 原因: regex

"/images/1.jpg"             # 3 or 4 ?        match 3, 原因: regex first match

"/img/1.png"                 # 1, 4 or 6 ?    match 4, 原因: regex

結論: 全部用 ~ 會一至許多.

Notes

if a "/" request happens frequently, defining "location = /" will speed up the processing of these requests

Nested locations

    location /test {
        location /test/1 { return 1;}
        location /test/2 { return 2;}
        return 3;
    }

測試

Mult path in one location

location ~ ^/(first/location|second/location)/ {
  ...
}

應用

# Protect admin panel
location ~ ^/(wp-admin|wp-login.php) {
    auth_basic             "Restricted";
    auth_basic_user_file    htpasswd;
}

 


regex captured groups

 

# use $1 for the first, \d+ and $2 for the second, and so on.

location ~/photos/resize/(\d+)/(\d+) {
    ...
}

# Named captures are a feature of PCRE and they have different syntax available in different versions.

location ~/photos/resize/(?<width>(\d+))/(?<height>(\d+)) {
    # so here you can use the $width and the $height variables
}

# test

location ~ ^/r/([0-9a-zA-Z]+) {
    echo $1;        
}

 


Other View

 

jemalloc:

http://datahunter.org/jemalloc

tengine:

http://datahunter.org/tengine

pagespeed:

http://datahunter.org/pagespeed

 


ulimit

 

Check

su - nginx -s /bin/bash

-, -l, --login                           # make the shell a login shell

ulimit -n

設定

/etc/security/limits.conf

nginx           hard    nofile          65535
nginx           soft    nofile          65535

OS limit

sysctl fs.file-max

202785

Solution

use the command ulimit in nginx start script

ulimit  -n 65536

 


nginx url redirect

 

# non-www to www

server {
    listen 80;
    server_name     example.com;
    return          301 http://www.example.com$request_uri;
}
server {
    listen 80;
    server_name     www.example.com;
    [...]
}

# Jump to subdirectory

location = /content/unique-page-name {
  return 301 /new-name/unique-page-name;
}

# Jump another link (By rewrite)

假設想實現以下 redirect

http://example.com/issue1 --> http://example.com/shop/issues/custom_issue_name1
http://example.com/issue2 --> http://example.com/shop/issues/custom_issue_name2
http://example.com/issue3 --> http://example.com/shop/issues/custom_issue_name3

[方法1]

location /issue {
   rewrite ^/issue(.*) http://$server_name/shop/issues/custom_issue_name$1 permanent;
}

[方法2]

location /issue1 {
   rewrite ^/.* http://$server_name/shop/issues/custom_issue_name1 permanent;
}
location /issue2 {
   rewrite ^.*  http://$server_name/shop/issues/custom_issue_name2 permanent;
}
......

List of redirect

On Apache

.htaccess

Redirect 301 /a/b http://1/2
Redirect 301 /c/d http://3/4
...

On Nginx

 

 

有關 Setting

map_hash_bucket_size size;          # Default: 32|64|128

map_hash_max_size size;              # Default: 2048

 


Error Page

 

自定 Error Page

#### Cust error page
#
error_page 500 502 503 504  /50x.html;
error_page 404              /404.html

location = /404.html {
    root   /usr/share/nginx/html/error;
}
location = /50x.html {
    root   /usr/share/nginx/html/error;
}

#### 
location / {
    # test 404
    return 404;
    error_page 404 @sorry;
}

 


root 與 alias 的分別

 

在這以下 Setting 下

location ~ /munin {
        autoindex off;
        root /var/cache/munin/www;
}

http://x.x.x/munin 時, 那 request 會去了 "/var/cache/munin/www/munin"

所以, 如果想 /munin 係直接拿 /www 內的東西,

那就要用 alias

location /munin {
        autoindex off;
        alias /var/cache/munin/www;
}

map file

以下兩個結果係一樣的

  • location /robots.txt { alias /home/www/static/any-filename.txt; }
  • location /robots.txt { root /home/www/static/; }

 


filter by $args

 

if ($args ~ mobile=1){
  return 405;
}

Or

if ($arg_mobile) {
    return 302 http://m.example.com/;
}

 


Doc

http://wiki.nginx.org/Configuration