netnr/ nginx.conf 2018-08-28 22:47
nginx 配置文件
####### nginx.conf
user www www;

worker_processes auto;
worker_cpu_affinity auto;

error_log /home/wwwlogs/nginx_error.log crit;

pid /usr/local/nginx/logs/nginx.pid;

worker_rlimit_nofile 51200;

events {
    use epoll;
    worker_connections 51200;
    multi_accept off;
    accept_mutex off;
}

http {
    include mime.types;
    default_type application/octet-stream;

    server_names_hash_bucket_size 128;
    client_header_buffer_size 32k;
    large_client_header_buffers 4 32k;
    client_max_body_size 100m; # 文件上传大小限制
    client_body_buffer_size 32k; # 超过时日志 $request_body 将为空,过大占用存储空间

    sendfile on;
    sendfile_max_chunk 512k;
    tcp_nopush on;

    keepalive_timeout 60;

    tcp_nodelay on;

    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 256k;

    gzip on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_http_version 1.1;
    gzip_comp_level 2;
    gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
    gzip_vary on;
    gzip_proxied expired no-cache no-store private auth;
    gzip_disable "MSIE [1-6]\.";

    server_tokens off; # 关闭版本号
    # access_log off; # 关闭日志
    # 先定义日志格式,logf 是日志格式的名字
    log_format logf '[$time_local] $remote_addr "$request" $status $body_bytes_sent $request_body "$http_referer" "$http_user_agent"';
    access_log /package/log/access.log logf;

    # 引用配置文件
    include vhost/*.conf;
}


####### 日志
http {
    # 定义日志格式
    log_format main_json escape=json '{'
    '"time_local": "$time_local", '
    '"remote_addr": "$remote_addr", ' # client IP
    '"status": "$status", ' # response status code
    '"http_host": "$http_host", ' # request host
    '"request_method": "$request_method", ' # request method
    '"request_uri": "$request_uri", ' # full path and arguments if the request
    '"request_body": "$request_body", ' # request body
    '"request_length": "$request_length", ' # request length (including headers and body)
    '"body_bytes_sent": "$body_bytes_sent", ' # the number of body bytes exclude headers sent to a client
    '"bytes_sent": "$bytes_sent", ' # the number of bytes sent to a client
    '"http_referer": "$http_referer", ' # HTTP referer
    '"http_user_agent": "$http_user_agent", ' # user agent
    '"http_x_forwarded_for": "$http_x_forwarded_for", ' # http_x_forwarded_for
    '"request_time": "$request_time", ' # request processing time in seconds with msec resolution
    '"upstream_response_time": "$upstream_response_time", ' # time spend receiving upstream body
    '"upstream_response_length": "$upstream_response_length", ' # upstream response length
    '"ssl_protocol": "$ssl_protocol", ' # TLS protocol
    '"ssl_cipher": "$ssl_cipher", ' # TLS cipher
    '"scheme": "$scheme", ' # http or https
    '"server_protocol": "$server_protocol", ' # request protocol, like HTTP/1.1 or HTTP/2.0
    '"gzip_ratio": "$gzip_ratio"'
    '}';
    access_log /package/access.json main_json; # 存储位置


    # 定义日志格式,logf 是日志格式的名字
    log_format logf '[$time_local] "$remote_addr" "$host" "$request" '
    '$status $body_bytes_sent $request_body "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /package/access.log logf; # 存储位置


    # access_log off; # 关闭日志
}


####### 端口转发,322 => 192.168.1.188:22
stream {
    server {
        listen 322;
        proxy_pass 192.168.1.188:22;
    }
}


####### HTTP => HTTPS
server {
    listen 80;
    server_name *.netnr.com;
  
    return 301 https://$host$request_uri;
}


####### HTTP => HTTPS 非默认端口,自动跳转
server {
    listen 8080 ssl http2;
    listen [::]:8080 ssl http2;
    server_name *.netnr.com;
  
    error_page 497 https://$host$request_uri; # http => https 默认 302 临时
    error_page 497 =301 https://$host$request_uri; # 301 永久
    error_page 497 =307 https://$host$request_uri; # 临时重定向,不改变请求的方法(如post还是post)
}


####### proxy_method 改变到上游的请求方式
location = /path/api/list_post {
    proxy_method GET; # 指定到上游的请求方式
    
    proxy_pass http://192.168.7.13:713$request_uri;
}


####### @ => www
server {
    listen 80;
    server_name netnr.com;

    rewrite ^(.*) $scheme://www.$host$1 permanent;
}


####### IPv6
server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name netnr.com;

    # SSL
    ssl_certificate /package/ssl/netnr.com/fullchain.cer;
    ssl_certificate_key /package/ssl/netnr.com/private.key;

    # ...
}


####### SSL 证书
server {
    # add_header Strict-Transport-Security "max-age=31536000";
    ssl_certificate /package/ssl/netnr.com/fullchain.cer;
    ssl_certificate_key /package/ssl/netnr.com/private.key;

    ssl_session_timeout 60m;
    ssl_session_cache shared:SSL:10m;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers on;
}


####### 自定义错误 404 503
server {
    proxy_intercept_errors on;

    # 错误4
    error_page 403 404 408 413 414 /404.html;
    location /404.html {
        root html;
    }

    # 错误5
    error_page 500 501 503 504 /503.html;
    location /503.html {
        root html;
    }
}


####### 开启 nginx 状态
server {
    location /nginx_status {
        stub_status on;
        access_log off;
    }
}


####### upstream 负载均衡,注意:upstream 取名不要下划线_ 与 gzip 冲突
upstream lb-web {
    server 192.168.5.100:8080 weight=1 max_fails=2 fail_timeout=20s;
    server 192.168.5.101:8080 weight=2 max_fails=2 fail_timeout=20s;
}
location / {
    proxy_pass http://lb-web;
    proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    proxy_next_upstream_tries 3;
}


####### 上传、下载优化
location / {
    # 下载缓冲
    proxy_buffering on; # 流式响应需关闭
    proxy_buffer_size 4k;
    proxy_buffers 8 1M;
    proxy_busy_buffers_size 2M;
    proxy_max_temp_file_size 0;

    # 禁用上传缓冲(大文件上传实时写入上游,超出 client_max_body_size 会报错)
    proxy_request_buffering off;
    # 上传大小不限制
    client_max_body_size 0;
}


####### Header、Cookie 正常
location / {
    proxy_redirect http://$host/ http://$http_host/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE-HOST $remote_addr;    
    # proxy_set_header X-Forwarded-For $remote_addr;
    # XFF 是可以被伪造,所以第一层应该是 $remote_addr 后面才是 $proxy_add_x_forwarded_for
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Cookie $http_cookie;
}


####### CORS 跨域
location / {
    proxy_hide_header Access-Control-Allow-Origin; # 可隐藏反代,避免重复添加

    add_header Access-Control-Allow-Origin '*' always;
    add_header Access-Control-Allow-Methods 'GET,POST,PUT,DELETE,PATCH,OPTIONS' always;
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always;
}


####### FTP
location /ftp/ {
    alias /package/;

    index _index.html;

    autoindex on;
    autoindex_exact_size off;
    autoindex_localtime off;
}


####### SPA 项目刷新非主页路由出现 404 的问题
location / {
    root /package/site/www;
    try_files $uri $uri/ /index.html?$args;
}


####### 反代第三方域名
location /third-party/getip {
    resolver 114.114.114.114; # dns
    proxy_pass https://www.taobao.com/help/getip.php; # 代理目标 URL
    proxy_ssl_verify off; # 禁用证书校验
}


####### 默认访问 index.html,忽略 .html
location / {
    # 默认访问 index.html
    if ( $request_uri = "/" ) {
        rewrite ^(.*)$ /$1/index.html last;
    }

    # 默认访问 .html
    if (!-e $request_filename) {
        rewrite ^(.*)$ /$1.html last;
        break;
    }
}


####### 代理上游 https,自签证书:https://www.netnr.com/gist/code/5218147624476006375
location / {
    proxy_pass https://10.0.0.5:9951;

    proxy_ssl_certificate /package/ssl/local/server.crt;
    proxy_ssl_certificate_key /package/ssl/local/server.key;
    proxy_ssl_verify off;
    proxy_ssl_session_reuse on;
}


####### 禁 IP 访问
server {
    listen 80 default_server;
    listen 443 ssl default_server;
    listen [::]:80 default_server; # IPv6
    listen [::]:443 default_server; # IPv6
    server_name _;

    charset utf-8;
    
    ssl_certificate /package/ssl/netnr.com/fullchain.cer;
    ssl_certificate_key /package/ssl/netnr.com/private.key;

    # return 444;
    return 500 "Visit https://www.netnr.com";
}


####### 屏蔽 
server {

    # 屏蔽 HEAD 请求
    if ($request_method ~ ^(HEAD)$ ) {
        return 404;
    }

    location / {

        # cookie 无关键字字符阻断访问
        if ($http_cookie !~ 'access_token') {
            return 401;
        }

        # 白名单 IP 或使用 allow、deny 或使用 geo
        if ($remote_addr !~ ^(192.168.1.11|123.123.123.123)) {
            return 403 "No Access $remote_addr\n";
        }

        # 白名单 IP ,根据转发 $http_x_forwarded_for 来配置,注意 XFF 伪造
        if ($http_x_forwarded_for !~ ^(192.168.100.100)) {
            return 403 "No Access $http_x_forwarded_for\n";
        }
    }
}


####### 白名单IP,根据 $remote_addr 获取 IP ,不是转发 $http_x_forwarded_for
server {
    allow 192.168.100.100;
    deny all;
}

location / {
    allow 192.168.100.100;
    deny all;
}


####### geo 白名单
# 0 allow  1 deny
geo $not_allowed {
    192.168.100.100 0;
    default 1;
}

server {
    location / {
        if ($not_allowed) {
            return 403 "No Access $remote_addr\n";
        }
    }
}


####### 直接返回
location /404 {
    add_header Content-Type text/html;
    return 404 '<!DOCTYPE html><html><head><title>404</title></head><body><h1>404</h1></body></html>';
}

location /ip {
    add_header Access-Control-Allow-Origin '*' always;
    add_header X-Forwarded-List $http_x_forwarded_for;
    add_header X-real-IP $remote_addr;

    default_type text/plain;
    return 200 "$remote_addr\n";
}


####### 永久缓存 unpkg mirror
location ~* @ {
    root /data/mirror_unpkg; # 指定存放目录,需手动创建目录,nginx 进程用户有读写权限
    
    proxy_store on; # 开启本地缓存
    proxy_temp_path cache_temp; # 设置反向代理接受的数据临时存储文件的目录,配置生效时候会自动创建
    proxy_store_access user:rw group:rw all:r; # 设置缓存的读写规则

    proxy_set_header Accept-Encoding ''; # 不返回压缩内容,避免乱码
    proxy_set_header x-real-ip $remote_addr;
    proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;

    # 不存在则直接从后台web内容服务器调取
    if (!-e $request_filename) {
        proxy_pass https://unpkg.com;
    }
}


####### 1.25.1 变更 http2 配置
server {
    # 之前
    listen 443 ssl http2;

    # 之后
    listen 443 ssl;
    http2 on;
}


####### www.netnr.com
server {
    listen 443 ssl http2;
    server_name www.netnr.com;

    charset utf-8;

    # SSL
    #add_header Strict-Transport-Security "max-age=31536000";
    ssl_certificate /package/ssl/netnr.com/fullchain.cer;
    ssl_certificate_key /package/ssl/netnr.com/private.key;

    ssl_session_timeout 60m;
    ssl_session_cache shared:SSL:10m;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers on;

    # status
    location /nginx_status {
        stub_status on;
        access_log off;
    }

    location / {

        # 跨域
        proxy_hide_header Access-Control-Allow-Origin; # 可隐藏反代,避免重复添加

        add_header Access-Control-Allow-Origin '*' always;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;
        add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,tenant-id' always;

        proxy_redirect http://$host/ http://$http_host/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Cookie $http_cookie;

        proxy_pass http://localhost:51;

        # 默认访问.html
        if (!-e $request_filename) {
            rewrite ^(.*)$ /$1.html last;
            break;
        }
    }
}