Nginx

Nginx

安装

官方 docker:Docker

卸载

启动

参考教程:Docker 容器部署 Nginx 服务 - 梦徒 - 博客园

docker 容器启动的必要参数

nginx.conf 配置文件的官方文档:nginx documentation

/opt/nginx/www 下需要留一个 index.html 来用作默认首页
最好使用 host 的网络模式

docker run --network host --name nginx -d  -v /appData/nginx/config/nginx.conf:/etc/nginx/nginx.conf -v /appData/nginx/www:/usr/share/nginx/html -v /appData/nginx/logs:/var/log/nginx  nginx

常用命令

Nginx 常用命令 - 程序员自由之路 - 博客园
nginx 启动

# nginx
# 当然我们可以只用-c选项制定配置文件,不指定的话就是使用默认的配置
# nginx -c [path]

nginx 关闭

# 立即停止
# nginx -s stop
或者
# 平滑停止
# nginx -s quit
或者
# kill TERM | INT | QUIT PID
或者(不建议这么停止服务)
# kill -9 PID

重启

# 平滑重启服务
# nginx -s reload

详解此命令

官方文档:Controlling nginx

关于这个问题的讨论:注释了部分 upstream 的 server 后 Nginx 明明 reload 了但是访问依然会连接到原来的 server - V2EX

Nginx 可以用信号控制。主进程的进程 ID 默认写入 /usr/local/nginx/logs/nginx.pid。这个名称可以在配置时修改,或者在 nginx.conf 中使用 pid 指令修改。例如在 /etc/nginx/nginx.conf

user root;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

主进程支持以下信号

信号 功能
TERM,INT fast shutdown
QUIT graceful shutdown
HUP changing configuration, keeping up with a changed time zone (only for FreeBSD and Linux), starting new worker processes with a new configuration, graceful shutdown of old worker processes
USR1 re-opening log files
USR2 upgrading an executable file
WINCH graceful shutdown of worker processes

单个工作进程也可以用信号来控制,尽管这不是必需的。支持的信号有

信号 功能
TERM, INT fast shutdown
QUIT graceful shutdown
USR1 re-opening log files
WINCH abnormal termination for debugging (requires debug_points to be enabled)

在更新配置(Changing Configuration)的场景中:
为了让 Nginx 重新读取配置文件,应该向主进程发送一个 HUP 信号(也就是 nginx -s reload 命令的作用)。主进程首先检查配置文件的语法有效性,然后尝试应用新的配置,即:打开日志文件和新的监听 socket 套接字。如果应用失败,它回滚更改并继续使用旧配置。如果应用成功,它将启动新的工作进程,并向旧的工作进程发送消息,要求它们优雅地关闭。旧的工作进程会关闭监听 socket 套接字并继续服务旧的客户端。在为所有客户机提供完服务之后,旧的工作进程也会关闭。
因此,执行完 nginx -s reload 之后,当前以及建立的连接不会断开,也不会应用新的配置,而是会保持原样。而且由于浏览器会重用 http/https 链接,因此你 reload 配置后刷新网站 ->浏览器重用老的链接 ->nginx 使用老配置;可能 nginx 服务看起来也不会有变化。如果 reload 配置后重启浏览器,再访问,这个时候就会建立新的连接,使用新的工作进程,nginx 的服务的表现应该就是新配置的表现了。
解决方法是使用 force-reload 的命令:service nginx force-reload,不过,force-reload 有个缺点,用户正在下载文件会被强制中断。
nginx 官方解决方法是使用健康度检查命令 health_check,是 nginx plus 的功能。也有第三方插件能实现类似功能。
upstream 节点的健康度处理,不推荐改配置然后 reload。建议用 nginx 的健康度检测功能或 nginx 第三方健康度检测插件

服务器上 Nginx 使用代理导致 获取不到 tokennginx 代理访问提示未提供 tokenℳ₯㎕ddzོꦿ࿐的博客-CSDN 博客

需要在 nginx.conf 的 http 部分添加配置 underscores_in_headers on;

Nginx 默认不支持下划线(underscore)开头的请求头是因为根据 HTTP 标准规范,下划线开头的请求头被认为是非标准的。根据 RFC 7230 规范,HTTP 头字段的命名只能包含 ASCII 字母、数字和连字符(hyphen),而不包括下划线。
因此,Nginx 默认配置中会忽略下划线开头的请求头。这是为了遵循 HTTP 标准规范,并确保与其他 HTTP 服务器和代理的兼容性。
如果您确实需要在 Nginx 中支持下划线开头的请求头,可以使用 Nginx 的 underscores_in_headers 指令来启用该功能。例如:
underscores_in_headers on;
但是,请注意,启用此功能可能会导致与其他 HTTP 服务器和代理的兼容性问题。因此,在使用下划线开头的请求头之前,请确保您的应用程序和其他组件能够正确处理和解析这些请求头。

nginx.conf 文件中可用的常量

Nginx Location 指令配置及常用全局变量_nginx location 变量-CSDN 博客

$args #这个变量等于请求行中的参数。
$content_length #请求头中的Content-length字段。
$content_type #请求头中的Content-Type字段。
$document_root #当前请求在root指令中指定的值。
$host #请求主机头字段,否则为服务器名称。
$http_user_agent #客户端agent信息
$http_cookie #客户端cookie信息
$limit_rate #这个变量可以限制连接速率。
$request_body_file #客户端请求主体信息的临时文件名。
$request_method #客户端请求的动作,通常为GET或POST。
$remote_addr #客户端的IP地址。
$remote_port #客户端的端口。
$remote_user #已经经过Auth Basic Module验证的用户名。
$request_filename #当前请求的文件路径,由root或alias指令与URI请求生成。
query_string #与args相同。
$scheme #HTTP方法(如http,https)。
$server_protocol #请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$server_addr #服务器地址,在完成一次系统调用后可以确定这个值。
$server_name #服务器名称。
$server_port #请求到达服务器的端口号。
$request_uri #包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
uri #不带请求参数的当前URI,uri不包含主机名,如”/foo/bar.html”。
document_uri #与uri相同。

nginx.conf 基础配置

Nginx 反向代理解决跨域问题 - 掘金

如果只是做反向代理的话,大部分情况只需要配置  http  模块下的  server  即可,一般初始文件,只有一个  server,如果你需要 Nginx 同时开启不同的端口或域名,就需要写多个  server

http {
    ......
    server {
            listen       80;   # 端口号
            server_name  localhost;   # server name 默认 localhost

            #access_log  logs/host.access.log  main;

            location / {   # 访问路径匹配规则
                root   html;
                index  index.html index.htm;
            }

            error_page   500 502 503 504  /50x.html;  # 错误处理
            location = /50x.html {
                root   html;
            }
    }
}

server 下的 location 是反向代理的重点,Location  配置项定义了一条访问  Nginx  服务某一路径时的匹配规则,location  后面紧跟的是匹配的路径,这个路径可以直接写绝对路径,可以写正则匹配:

关于 location 的官方文档如下:ngx_http_core_module location

要通过正则表达式匹配路径,location 后面应以 ~(使用正则表达式匹配路径且区分大小写) 或者 ~*(使用正则表达式匹配路径且不区分大小写),且这两个符号跟后面的正则表达式之间有一个空格,例如 location ~ ^/(api2/api3) 或者 location ~ ^/test/(\d+)$

我们可以在 Nginx location match tester 这个网站中,检测 location 的配置是否能匹配特定的 URL

location /api1 { # 当访问 http://localhost/api1 时命中
    # ...
}

location ~ ^/(api2/api3) { # 当访问 http://localhost/api2 和 http://localhost/api 3 时命中
    # ...
}

location 里有多个配置项,其中一个是 proxy_pass ,意思是将当前命中的 Nginx 接口(例如:http://localhost/api )代理到其他服务器的接口(注意,只替换域名 + 端口,不改变请求 URL 中域名和端口后面的请求路径),如下例子就是将 http://localhost/api 代理到 https://baidu.com/api

location /api {
    proxy_pass https://baidu.com;
}

需要注意的是,在写  proxy_pass  不能随便在目标地址后加  /,如果你在地址末尾加了  / ,则 http://localhost/api 最终将代理到 https://baidu.com/ ,后面没有 /api

location /api {
    proxy_pass https://baidu.com; # 将会代理到 https://baidu.com/api
}

location 配置中的 proxy_set_header 可以修改发送给被服务器的请求的消息头(对应下图的 2),比如 proxy_set_header header_name header_value;add_header 可以修改从 nginx 返回给客户端的响应的消息头(对应下图的 4),比如 add_header X-My-Header "Hello World";,需要注意的是,如果你想用相同的消息头名字设置多个值,你可以使用多此指令即可。如果要覆盖现有的请求头或响应头,可以在最后添加 always 参数。比如 add_header X-My-Header "Hello World" always;

Nginx 里 Header 修改 - 飞鸿影 - 博客园

这样做的好处是,我们可以将请求的请求头和响应的响应头设置(这其实是一个偏底层的操作)全都放到 nginx 来做,后端服务器只专注于于代码的编写,这样可以让我们的代码的维护变得简单:

比如设置缓存的过期时间

比如我们要下载文件的时候,需要设置响应头,我们就可以在 nginx 里配置一个专门的 location 用来做下载,同时只要是这个路径的请求,我们都在把响应头中添加 Content-Disposition 响应头,内容为 attachment;filename=downloadFile.txt

比如我们需要处理跨域问题,跨域问题首先需要服务器后端接口支持跨域访问,我们也可以在 nginx 里配置一个专门的 location 来允许跨域,在响应中添加 Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers 这些响应头的,具体配置请看 跨域问题 小节。

http {
    ......
    server {
        server_name 127.0.0.1;
        listen 80;
        location /header {
            default_type "text/plain";
            access_log /data/nginx/log/proxy_header.log api;
            proxy_redirect     off;
            proxy_set_header   iden    "student";
            proxy_set_header   age     "21";
            # $host 为向Nginx发起请求的客户端的IP;
            proxy_set_header   Host    $host;
            proxy_pass http://127.0.0.1:88;
         } 
    }
}

其他配置:理解 nginx 的配置 - 飞鸿影 - 博客园

高级自定义匹配

在 Nginx 中,你可以通过 rewrite 指令来实现路径修改,将三段路径中的第一段去掉后再转发到上游。以下是一个配置示例:

假设原始路径是 /first/second/third,你希望转发到上游时路径变成 /second/third

server {
    listen 80;
    server_name example.com;

    location ~ ^/[^/]+(/.*)$ {
        # 将路径的第一段去掉
        rewrite ^/[^/]+(/.*)$ $1 break;

        # 转发到上游服务器
        proxy_pass http://upstream_server;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

配置说明:

  1. location ~ ^/[^/]+(/.*)$
    • 匹配 URL 路径,确保包含三段或更多的路径。
    • [^/]+ 表示匹配第一段路径(不含 / 的部分)。
    • (/.*)$ 捕获其余部分(包括 / 起始)。
  2. rewrite ^/[^/]+(/.*)$ $1 break;
    • 将路径中的第一段忽略,仅保留后续部分。
    • 使用 break 终止 rewrite 的进一步处理。
  3. proxy_pass http://upstream_server;
    • 将修改后的路径转发到上游服务器。

你可以根据实际需要调整 server_nameupstream_server,以匹配你的具体场景。

server 模块下多个 location 配置的优先级问题

官方文档:Module ngx_http_core_module
StackOverflow:Nginx location priority - Stack Overflow

location 可以使用完整 URI 定义(通过 = 指定),也可以由路径前缀字符串定义,也可以由正则表达式定义。要通过正则表达式匹配路径,location 后面应以 ~(使用正则表达式匹配路径且区分大小写) 或者 ~*(使用正则表达式匹配路径且不区分大小写),且这两个符号跟后面的正则表达式之间有一个空格,例如 location ~ ^/(api2/api3) 或者 location ~ ^/test/(\d+)$

为了找到匹配给定请求的 location,如果路径正好跟通过 = 配置的 location 匹配,那么匹配停止,就使用这个 location 配置。如果没有,那就继续查找,nginx 会检查使用前缀字符串定义的 location。其中,会选择匹配前缀最长的 location(匹配的字符串越长,匹配越精确,这是一种很常见的匹配原则,我们在学习路由器转发的时候也使用过这个原则:从网线到网络设备 - 虾说全栈),并记住。注意,此时匹配还没有结束,再从用正则表达式定义的 location 中查找匹配,此时会按照其在配置文件中的出现顺序检查它们。在第一次匹配时终止搜索(按照前缀匹配的时候会匹配所有的,然后记住最长匹配的),并使用相应的配置。如果没有找到与正则表达式的匹配,则使用先前记住的前缀 location 的配置。

也就是说,通过 = 定义的 location 优先级最高,通过正则表达式定义的 location 的优先级比通过前缀字符串定义的 location 更高,正则表达式没找到,才会去使用通过前缀字符串定义的 location

我们可以在 Nginx location match tester 这个网站中,检测 location 的配置是否能匹配特定的 URL

实现简单的反向代理的配置

Nginx 集群(负载均衡) - 休耕 - 博客园

开始实践:

修改配置文件 nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


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;

    upstream web{    # 名为web的反向代理群组
        server 192.168.101.142:8080;
        server 192.168.101.143:8080;
    }
    server {
        listen       8080;
        server_name  localhost;
        location / {
            proxy_pass http://web;   # 去找反向代理
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

}

反向代理上游(upstream)web 服务到本机的 localhost:8080,对外提供服务(server),本机接收到对 localhost:8080 的请求之后,会转发到 192.168.101.142:8080192.168.101.143:8080 这两个地址,就这么简单。

如何理解上游的这个概念,水从源头流出,流向下游,网络资源从服务器发出,发送给客户端,因此,提供资源的服务器是上游,接收资源的客户端是下游,

跨域问题

参考文档:Nginx 反向代理解决跨域问题 - 掘金

算是一个比较完整的 Nginx 的讲解

Nginx 反向代理及 Cookie 相关问题 - 简书

跟 JWT 的整合

通过请求头传递 token

http {
    ......
    server {
        ......
        location /api {
            proxy_pass http://backend_server;
            proxy_set_header Authorization $http_authorization;
            proxy_set_header Host $host;
        }
    }
}

可能需要通过属性配置 proxy_cookie_domain

参数文档:Module ngx_http_proxy_module

参考博客:Nginx 反向代理理解误区之 proxy_cookie_domain

proxy_cookie_domain 参数的作用是转换被代理服务器的 response 的 set-cookie header 中的 domain 选项,由被代理服务器设置的域名 domain 转换成你的域名 replacement,来保证 cookie 的顺利传递并写入到当前页面中,注意 proxy_cookie_domain 负责的只是处理 response set-cookie 头中的 domain 属性,仅此而已。也就是第 4 步中做的事情

但是 response 在写 set-cookie 的时候,domain 是一个可选项,并不是必填项,这个时候由于 set-cookie 本身就没有 domain 内容,proxy_cookie_domain 也就不没有必要了,这也是为什么在部分项目中不配置 proxy_cookie_domain 依然正常的原因。

浏览器在发送请求的时候,会在 request header 中带上 cookie 项 (有内容的话),此时的 cookie 是一个字符串,一个 key=value 并用分号分割的字符串,其中并不包含任何域名信息。这是因为浏览器在设置 cookie 选项的时候,所选取的内容都是缓存在当前访问的域名下的,已经根据 domain 筛选过了。request 的 cookie 中包含的,只有 key=value,它只是一个普通的字符串,随便 proxy_pass 到任何位置,都会正常携带下去。因此在前端到后端的 request 的过程中,proxy_cookie_domain 是没用的,也就是第 1 步

而 server 端在做响应的时候,通过 set-cookie 的 domain 属性,可以控制 cookie 的生效域名目标,做到诸如二级域名 cookie 分离等等,如果前端接收到的 set-cookie 的 domain 和当前域名不一致,或者一级域名不一致 (二级域名可以共享一级域名下的 cookie),这个 cookie 在后续的通信中就是无效的,所以这里才需要去做 domain 的转换,也就是说response 中 set-cookie 的 domain 转换才是有意义的,这也正是 proxy_cookie_domain 的作用所在。
当 reseponse 的 set-cookie 中 domain 不去设置时,cookie 顺利传入浏览器中,浏览器会自动设置这个 cookie 的生效域名为当前域名。

和这个类似的还有 proxy_cookie_path 属性,同样的该属性仅作用在修改 response set-cookie 的 path 属性,而一般情况下,用的也比较少。

权限不够的问题

解决 Nginx 出现 403 forbidden (13: Permission denied) 报错的四种方法 - 听风。 - 博客园

突然有一天,nginx 代理的静态页面无法访问,同时在 /var/log/nginx/error.log 日志中报错:

2023/10/07 10:08:25 [error] 17369#17369: *20 "/XiaShuoBlog/index.html" is forbidden (13: Permission denied), client: 117.152.201.167, server: _, request: "GET / HTTP/1.1", host: "xiashuo.xyz"

后来搜索了一下之后,发现是因为启动用户和 nginx 工作用户不一致所致,将 /etc/nginx/nginx.confuser nginx; 改为 user root; 才解决问题。

但是很奇怪,之前一直都是以 user nginx; 运行的,也没报权限不够的问题啊。

限流

死磕 nginx 系列--nginx 限流配置 - biglittleant - 博客园

限制用户的请求到达服务器的速度,避免服务器被请求打爆。

Nginx 转发 WebSocket 请求

Nginx 转发 WebSocket 请求的时候,需要手动添加 ConnectionUpgrade 这两个请求头

为什么,请看《HTTP/1.x》中的 hop-by-hop 小节

Nginx 解决跨域问题

使用 Nginx 进行反向代理是一种常用的解决跨域问题的方法。下面是一种简单的配置方式:

http {
    ......
    server {
        listen       80;
        server_name  localhost;

        location /api/ {
            proxy_pass http://target.com; # 这里修改为你的目标地址
            proxy_set_header Host $host:$server_port;  # 设置Host头,不然可能会出现403错误等问题
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

这是一个简单的示例,它监听 80 端口,并代理所有以 /api/ 开头的请求到 http://target.com

在实际的前端代码中,你现在可以直接向你自己的服务器(即 Nginx 服务器)发起 API 请求,如 http://localhost/api/some-endpoint,由于这个请求是向同源服务器发出的,因此不存在跨域问题。

然后,Nginx 服务器会把这些 API 请求转发到目标服务器 http://target.com由于这个过程是在后端进行的,所以不受浏览器的同源策略限制

所以,使用 Nginx 进行反向代理可以有效地解决跨域问题。你需要确保将 Nginx 的配置修改为适合你的目标地址,并且可能需要进行其他配置,例如处理 cookies、添加额外的 HTTP 头等。

通过 stream 模块实现 SSH 请求转发

因为让 Nginx 代理 TCP、UDP 端口转发不能走 http 模块,而是要使用 stream 模块,

官方文档:Module ngx_stream_core_module

官方文档指出,在 1.9.0 版本后可以使用 stream 模块,但此模块不是默认编译进去的,所以需要我们在编译安装 nginx 的时候加上它 --with-stream。如果你已经安装你 Nginx 了,可以通过 nginx -V |grep with-stream  确定是否包含了 stream 模块。如果有输出则表示已经安装了 stream 模块。

stream 模块的官方文档示例

worker_processes auto;

error_log /var/log/nginx/error.log info;

events {
    worker_connections  1024;
}

stream {
    upstream backend {
        hash $remote_addr consistent;

        server backend1.example.com:12345 weight=5;
        server 127.0.0.1:12345            max_fails=3 fail_timeout=30s;
        server unix:/tmp/backend3;
    }

    upstream dns {
       server 192.168.0.1:53535;
       server dns.example.com:53;
    }

    server {
        listen 12345;
        proxy_connect_timeout 1s;
        proxy_timeout 3s;
        proxy_pass backend;
    }

    server {
        listen 127.0.0.1:53 udp reuseport;
        proxy_timeout 20s;
        proxy_pass dns;
    }

    server {
        listen [::1]:12345;
        proxy_pass unix:/tmp/stream.socket;
    }
}

我们现在的场景是:有三台服务器 A、B、C,AB 之间是互通的,BC 之间也是互通的,但 AC 不能互通,所以每次 A 想连接 C 时都需要先登录 B,比较麻烦,这是一个典型的内网穿透的场景,BC 可以成是在一个内网中。

如果 B 上安装了 nginx,那么就可以通过 Nginx 来转发 ssh 端口,实现 A 连接 C。

修改 B 的 Nginx 配置文件

http {
}
stream {
    upstream ssh {
        server <服务器C的IP>:22;
    }
    server {
        listen 9022;
        proxy_pass ssh;
        proxy_connect_timeout 1h;
        proxy_timeout 1h;
    }
}

现在从 A 指定端口 ssh 到 B 的 9022 端口,就可以连接到 C

通过 Nginx 将 HTTP 请求变成 HTTPS

方法很简单,效果非常好,直接转发即可,可见转发给 HTTP 的请求,是解密过后了的,而不是未解密的。而且代理也是双向的,既代理发送到上游的流量,也代理从上游发出的流量。

http {
    ......
    server {

        # 对外以 9090 提供 HTTPS 服务
        listen       9090 ssl ;
        listen       [::]:9090 ssl ;
        server_name  _;

        #  证书地址
        ssl_certificate "/etc/host_ssl/xiashuo.xyz.pem";
        ssl_certificate_key "/etc/host_ssl/xiashuo.xyz.key";
        #  SSL 配置
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;

        location / {
            # 被代理的,原本的 HTTP 服务
            proxy_pass http://localhost:90;
        }
    }

}

在集群系统中,一般我们都会通过 Nginx 对外统一提供服务,在集群内部服务与服务之间,都是通过 HTTP 相互提供服务,而当这些服务要通过 Nginx 对外提供服务的时候,会通过另一个带 TSL 证书的接口代理处理出去,以提供 HTTPS 服务,在集群内部通过 HTTP 相互通信的主要原因是 TSL 握手是很耗时的,而且加密解密也影响效率,而且集群内部都是相互信任的,没有必要加密。
比较完整的配置如下

# 添加https server
server{
    listen 443 ssl;
    # 下面的www.example.com替换成你自己网站的域名(注意这个域名一定要跟ssl证书的域名一致)
    server_name www.example.com;
    index index.php index.html index.htm default.php default.htm default.html;

    #SSL-START 这一段是ssl证书的配置
    ssl_certificate   /etc/nginx/cert/www.example.com.pem; # 这个目录需要替换成你自己证书的存放目录
    ssl_certificate_key  /etc/nginx/cert/www.example.com.key; # 这个目录需要替换成你自己证书的存放目录
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    #SSL-END SSL相关配置

    #让http请求重定向到https请求
    error_page 497  https://$host$uri?$args;

    #下面这些配置跟原本http的server里面的一样就可以了
    location / {
    }
}

其实一个 server 节点是可以通过监听多个端口的,也就是说你可以同时监听 80 和 443,然后代理同一个地址

server{
	listen 80;
    listen 443 ssl;
    # 下面的www.example.com替换成你自己网站的域名(注意这个域名一定要跟ssl证书的域名一致)
    server_name www.example.com;
    index index.php index.html index.htm default.php default.htm default.html;
    #SSL-START 这一段是ssl证书的配置
    ssl_certificate   /etc/nginx/cert/www.example.com.pem; # 这个目录需要替换成你自己证书的存放目录
    ssl_certificate_key  /etc/nginx/cert/www.example.com.key; # 这个目录需要替换成你自己证书的存放目录
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    #SSL-END SSL相关配置

    #让http请求重定向到https请求
    error_page 497  https://$host$uri?$args;

    #下面这些配置跟原本http的server里面的一样就可以了
    location / {
    }
}

配置 HTTP/2.0

以 Nginx 为例,首先需要支持配置好 SSL/TSL,然后就是加上一点配置即可

listen       443 ssl http2 ;

然后重启 Nginx 即可,真的非常方便。

为某个添加配置一个简单的账号密码验证

官网文档:Restricting Access with HTTP Basic Authentication | NGINX Documentation

http_auth_basic_module 的模块文档:Module ngx_http_auth_basic_module

参考教程:Nginx 中添加登录权限功能_auth_basic_user_file-CSDN 博客

http_auth_basic_module 模块实际上就两个配置

location / {
    auth_basic           "closed site";
    auth_basic_user_file conf/htpasswd;
}

这组参数也可以放在 server{}模块下,表示整个 server 下面的所有 location 都需要经过权限验证才可访问。

auth_basic:两种值,第一个 off 表示访问该 location 不需要认证,第二是任意的字符串值,例如上面的 "Restricted",这个字符串会在某些情况下展示给用户。

auth_basic_user_file:指向一个存储了用户名密码的文件,这个文件可以用 htpasswd 生成,生成的方式也很简单,执行 htpasswd -c 存放用户名密码的文件路径 用户名 即可,用户名可随意指定。指定同一存放用户名密码的文件路径使用不同的用户名多次执行 htpasswd,可将多个用户名密码放到同一个文件中

如果没有 htpasswd 命令,可以通过 yum -y install htpasswd 或者 yum install httpd-tools 来安装

最终的存放用户名密码的文件的格式如下

用户名:密码
用户名2:密码2:注释
用户名3:密码3

使用示例如下:

http {
    ......
    server {
       ...
        # private path
        location /posts/others/private {
            autoindex on;
            autoindex_exact_size off;
            autoindex_localtime on;
            auth_basic "Please input password";
            auth_basic_user_file conf.d/passwd;
            root /XiaShuoBlog;
        }
    }
}

效果是,只要访问路径中包含了 /posts/others/private,就需要输入密码,输入成功后,在路径前面拼上 /XiaShuoBlog,然后从本地的根路径开始找对应的文件,比如访问 https://xiashuo.xyz/posts/others/private/index.html

登录成功之后就会到根目录下查找 /XiaShuoBlog/posts/others/private/index.html

注意:http_auth_basic_module 模块是没有退出登录功能的,只要第一次访问的时候正确登录了,后续就不再需要输入账号密码,只有在关闭整个浏览器之后,此次登录会话才会失效。但是我们可以做一个地址,使用错误的用户名跟密码来使之前的登录会话失效。具体做法请参考 Nginx 中添加登录权限功能_auth_basic_user_file-CSDN 博客 中的做法。

你还可以 http_auth_basic_module 模块的基本认证功能与 IP 地址限制相结合,实现以下两种场景的验证需求:

先简单介绍一下如何实现 IP 限制,使用 allow 和 deny 指令允许或拒绝来自特定 IP 地址的访问

location /api {
    #...
    deny  192.168.1.2;
    allow 192.168.1.1/24;
    allow 127.0.0.1;
    deny  all;
}

以上配置会允许 192.168.1.1/24 网段的 IP 访问 /api,同时拒绝 192.168.1.2 这个 IP 访问 api,注意, allow  和  deny 指令是按照他们定义的顺序来生效的

下面我们将 IP 和 HTTP 认证的限制与 satisfy 指令结合起来。如果您将 satisfy 设置为 all,则只有当客户端同时满足这两个条件,则授予访问权限。如果将该 satisfy 设置为 any,则客户端只要满足一个条件,则授予访问权限,例如

location /api {
    #...
    satisfy all;

    deny  192.168.1.2;
    allow 192.168.1.1/24;
    allow 127.0.0.1;
    deny  all;

    auth_basic           "Administrator’s Area";
    auth_basic_user_file conf/htpasswd;
}

location 下 alias 和 root 的区别

参考:Nginx 虚拟目录 alias 和 root 目录 - 散尽浮华 - 博客园

nginx 是通过 alias 设置虚拟目录,在 nginx 的配置中,alias 目录和 root 目录是有区别的:

举例说明(比如 nginx 配置的域名是 xiashuo.xyz):

示例一

location /huan/ {
      alias /home/www/huan/;
}

在上面 alias 虚拟目录配置下,访问 http://xiashuo.xyz/huan/a.html 实际指定的是 /home/www/huan/a.html

注意:alias 指定的目录后面必须要加上 /,即 /home/www/huan/ 不能改成 /home/www/huan

上面的配置也可以改成 root 目录配置,如下,这样 nginx 就会去 /home/www/huan 下寻找 http://xiashuo.xyz/huan 的访问资源,两者配置后的访问效果是一样的!

location /huan/ {
       root /home/www/;
}

示例二

上面的例子中 alias 设置的目录名和 location 匹配访问的 path 目录名一致,这样可以直接改成 root 目录配置;那要是不一致呢?

再看一例:

location /web/ {
      alias /home/www/html/;
}

访问 http://xiashuo.xyz/web 的时候就会去 /home/www/html/ 下寻找访问资源。这样的话,还不能直接改成 root 目录配置。

如果非要改成 root 目录配置,就只能在 /home/www 下将 html->web(做软连接,即快捷方式),保持 /home/www/web/home/www/html 内容一致

ln -s /home/www/web /home/www/html
location /web/ {
     root /home/www/;
}

不过现在好像很少用 alias 了。

Nginx 实现在同一个端口下进行不同规则的转发

参考博客:Nginx 实现监听同一端口转发不同应用_nginx 中一个监听端口代理两个服务器中 ip-CSDN 博客

多个应用,一般是通过 IP 加端口加不同的请求路径的方式访问,如果两个应用都是不指定访问路径,直接通过 IP 加端口访问,且这两个应用需要通过同一端口访问(可能是因为端口紧缺),此时可以通过为不用的应用配置不同的域名,并在 Nignx 中为不同的域名配置不同的 server 来实现。

例如,当前服务器:192.168.0.109 唯一的对外开放的端口为 80,我们需要要通过这个端口访问两个应用,这两个应用一个在(内部的,不对外开放)81 端口,一个在 82 端口,此时为了实现需求,我们可以为 81 端口指定域名 music.proxy.com,为 82 端口指定域名 video.proxy.com

首先在 hosts 文件中配置域名

# localhost name resolution is handled within DNS itself.
#    127.0.0.1       localhost
#    ::1             localhost
192.168.0.109       music.proxy.com
192.168.0.109       video.proxy.com

然后这样配置 Nginx:

server {
    listen       80;
    server_name  music.proxy.com;
    location / {
        proxy_pass http://127.0.0.1:81;
    }
}

server {
    listen       80;
    server_name  video.proxy.com;
    location / {
        proxy_pass http://127.0.0.1:82;
    }
}

这样当我们在访问 music.proxy.com:80 的时候,实际跳转的就是 127.0.0.0:81,访问 video.proxy.com:80 的时候,实际跳转的就是 127.0.0.0:82

NGINX 上传文件大小限制

本质上是消息体大小的限制,nginx 控制这一大小的参数是 client_max_body_size,默认为 1m,如果设置为 0,表示不限制消息体的大小。此配置项可以在以下模块设置: http, server, location

server {
    listen       8080;
    server_name  video.proxy.com;
    client_max_body_size 10m;
    ...
}

然后重启 nignx

nginx -s reload