目录

「Nginx」你的后端由我守护

记录网络服务器Nginx使用技巧。

upstream
  • 轮询 average polling
upstream name1 {
    server 192.168.1.11:8888;
    server 192.168.1.22:8888;
    server 192.168.1.33:8888;
}
  • 权重 weighted polling
upstream name2 {
    server 192.168.1.11 weight=1;
    server 192.168.1.22 weight=2;
    server 192.168.1.33 weight=3;
}
  • IP散列 ip_hash

访问请求依据IP的Hash分配,则每个访客访问固定的后端服务,解决session一致性问题

upstream name3 {
    ip_hash;
    server 192.168.1.11:7777;
    server 192.168.1.22:8888;
    server 192.168.1.33:9999;
}
  • [fair]

「该策略由第三方支持,非原生」公平的依据后端响应时间(rt)分配,响应时间小的优先分配

upstream name4 {
    server 192.168.1.11:7777;
    server 192.168.1.22:8888;
    server 192.168.1.33:9999;
}
  • [url_hash]

「该策略由第三方支持,非原生」访问请求依据URL的Hash分配,则每个URL访问固定的后端服务,主要用于后端服务为缓存的场景

# 注意:此时server中不能添加weight参数
upstream name5 {
    server 192.168.1.11:7777;
    server 192.168.1.22:8888;
    server 192.168.1.33:9999;
    hash $request_uri;
    hash_method crc32;
}
location
proxy_pass
rewrite

案例

1. 反向代理
server
    {
        listen 80;
        #listen [::]:80;
        server_name store.yirami.cn ;
        index index.html index.htm index.php default.html default.htm default.php;
        root  /home/wwwroot/store.yirami.cn;
    		if ($scheme = http ) {
    			return 301 https://$host$request_uri;
    		}

        include rewrite/other.conf;
        #error_page   404   /404.html;

        # Deny access to PHP files in specific directory
        #location ~ /(wp-content|uploads|wp-includes|images)/.*\.php$ { deny all; }

        include enable-php.conf;

        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
        {
            expires      30d;
        }

        location ~ .*\.(js|css)?$
        {
            expires      12h;
        }

        location ~ /.well-known {
            allow all;
        }

        location ~ /\.
        {
            deny all;
        }

        access_log off;
    }

server
    {
        listen 443 ssl http2;
        #listen [::]:443 ssl http2;
        server_name store.yirami.cn ;

        ssl on;
        ssl_certificate /usr/local/nginx/conf/ssl/store.yirami.cn/fullchain.cer;
        ssl_certificate_key /usr/local/nginx/conf/ssl/store.yirami.cn/store.yirami.cn.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
        ssl_session_cache builtin:1000 shared:SSL:10m;
        # openssl dhparam -out /usr/local/nginx/conf/ssl/dhparam.pem 2048
        ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;

        location / {
            proxy_pass          https://store-1254299470.cos.ap-shanghai.myqcloud.com/;
            proxy_redirect      off;
            proxy_set_header    X-Real-IP       $remote_addr;
            proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        }


        access_log off;
    }
2. Nginx基于Stream模块的SNI分流
原理

https://store.yirami.xyz/review/nginx/nginx_sni_web_xtls.jpg

  1. 内部应用无需监听0.0.0.0,可以只监听回环地址127.0.0.1,流量均有stream模块转发
  2. 使用Proxy protocol转发获取真实IP
  3. 对于XTLS此类仅使用普通TCP的协议,在进入前去除Proxy protocol头
用法
  • nginx.conf
# events ...

stream {
    # 绑定域名与流,即SNI分流
    map $ssl_preread_server_name $stream_map {
        yirami.xyz beforextls;
        loc.laus.yirami.xyz beforextls;
        default web;  # 不匹配的域名将走这里,即直接转发到回环地址`localhost`
    }
    upstream web {
        server 127.0.0.1:443;
    }

    # upstream ...

    upstream beforextls {  # 在流量到达XTLS之前,先用stream模块将Proxy protocol的外衣扒掉
        server 127.0.0.1:28985;
    }
    upstream xtls {
        server 127.0.0.1:28986;
        server 127.0.0.1:28981 backup;  # 当服务均失效时使用备用服务
    }

  server {
    # 仅监听公网443端口,127回环地址443端口留给内部服务监听
    listen 89.208.243.18:443    reuseport;  # 注意:及时修改公网IP
    proxy_pass                  $stream_map;
    ssl_preread                 on;  # 预读取以便分流
    proxy_protocol              on;  # 开启Proxy protocol,便于内部服务获取真实IP,而不是localhost
  }
#  server {
#    listen 127.0.0.1:28983 ssl proxy_protocol;
#    ssl_certificate /home/wwwroot/cert-ssl/yirami.xyz.pem;
#    ssl_certificate_key /home/wwwroot/cert-ssl/yirami.xyz.key;
#
#    any other ssl setting ...
#    注意:在stream模块中使用ssl的话,http模块中不能同步配置ssl
#      但似乎删去`ssl_session_cache builtin:1000 shared:SSL:10m;`就又可以
#      可能是内存分配方面的问题
#
#    proxy_protocol on;  # 开启Proxy protocol
#    proxy_pass rawweb_with_proxy_protocol;  # 带有Proxy protocol,可直接转发到`rawweb_with_proxy_protocol`
#  }

# server 127.0.0.1:28984 ssl proxy_protocol ...

  server {
    listen 127.0.0.1:28985 proxy_protocol;  # 开启Proxy protocol
    # 这步应该去除了`proxy_protocol`信息
    proxy_pass xtls;  # 以真实的XTLS作为上游,这一层是与XTLS交互的“媒人”
  }
}

# http ...
  • yirami.xyz.conf
# 启用SNI分流,对于80端口的http流量无影响
server
    {
        listen 80;
        #listen [::]:80;
        server_name *.yirami.xyz;
        if ($scheme = http ) {
            return 302 https://yirami.xyz;
        }
        access_log off;
    }
# 对于被正常转发到回环地址的443端口的https服务,可获取真实IP
server
    {
        listen 127.0.0.1:443 ssl http2 proxy_protocol;
        #listen [::]:443 ssl http2;

        # 从Proxy protocol获取真实IP
        set_real_ip_from 127.0.0.1;
        real_ip_header proxy_protocol;

        server_name store.yirami.xyz ;

        index index.html index.htm index.php default.html default.htm default.php;
        root  /home/wwwroot/yirami.xyz;

        ssl_certificate /home/wwwroot/cert-ssl/store.yirami.xyz.pem;
        ssl_certificate_key /home/wwwroot/cert-ssl/store.yirami.xyz.key;
        # any other ssl setting ...
        
        # any other config ...
    }
# 被去除了SSL加密的https请求与普通http相似,同时可搭配location进一步转发
server
    {
        listen 127.0.0.1:28980;
        listen 127.0.0.1:28982 proxy_protocol;
        server_name yirami.xyz loc.laus.yirami.xyz;
        index index.html index.htm index.php default.html default.htm default.php;
        root  /home/wwwroot/yirami.xyz;

        location /v2ray/yirami/ {
            proxy_redirect off;
            proxy_pass http://127.0.0.1:28990/v2ray/yirami/;
            proxy_http_version 1.1;
            proxy_set_header Host "yirami.xyz";
            proxy_set_header Connection "Upgrade";
            proxy_set_header Upgrade "WebSocket";
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_read_timeout 550;  # set for FCM, see also https://github.com/v2ray/v2ray-core/issues/885
            proxy_intercept_errors on;
        }

        # other location proxy_pass ...
        
        # any other config ...
    }
参考
  1. 使用Nginx进行SNI分流并完美和网站共存
  2. Nginx进行SNI分流实现多应用端口复用
  3. Xray与多个HTTPS站点(Nginx)共存,两种443端口复用方案