当前位置 : 首页 » 文章分类 :  开发  »  Nginx

Nginx

nginx官网文档
http://nginx.org/en/docs/

《深入理解nginx》在线支持网站
http://nginx.weebly.com/
http://taohui.org.cn/

1个master进程,n个worker进程,n对应CPU核的个数
master进程仅用于管理worker进程,不直接对用户请求服务
worker进程处理用户请求,并提供服务。
一个worker进程可同时处理的请求数只受限于内存大小。

pid文件:以ASC码存放master进程的ID


安装nginx

docker安装部署nginx

docker hub 的 nginx 官方页面里有比较全面的用法
https://hub.docker.com/_/nginx

Nginx 容器教程
https://www.ruanyifeng.com/blog/2018/02/nginx-docker.html

指定配置文件启动官方nginx镜像

还使用原始的 nginx 官方镜像,只不过在启动命令中加入自己的配置,很方便

docker run -d --rm \
--network host \
--name nginx \
-e TZ="Asia/Shanghai" \
-v /home/centos/git/hexo/nginx/nginx-centos.conf:/etc/nginx/nginx.conf:ro \
-v /home/centos/git/hexo/public:/home/centos/git/hexo/public \
-v /var/log/nginx:/var/log/nginx \
nginx

解释:

  • 以 host 网络模式启动容器,和宿主机完全共享网络,不需要再配置-p端口映射,否则容器内的nginx需要配置主机ip才能访问主机网络。
  • 容器中默认是 UTC 时区,比我们的时间慢8小时,改为 Asia/Shanghai 即东八区
  • 文件和文件夹映射
    把本地的配置文件 /home/centos/git/hexo/nginx/nginx-centos.conf 映射到容器中的 /etc/nginx/nginx.conf, 会自动覆盖容器的配置文件,注意必须用绝对路径。这两个文件可以不同名。
    把静态文件目录 /home/centos/git/hexo/public 映射到容器中的同名目录,由于容器中没有这个目录,会自动新建并将全部内容拷贝进去,而且,以后宿主机此文件夹的更新会完全反应到容器中。
    把容器中nginx的日志目录 /var/log/nginx 映射到本机的同名目录,由于本机没有 /var/log/nginx 目录,会自动创建,之后在本机即可看nginx日志
  • --rm表示停止容器时删除容器文件,因为nginx是无状态的即开即用服务,且配置文件和静态文件映射自宿主机文件,容器内不需要任何持久化,停止后删掉就行,下次再重新启动一个新容器。
  • --name nginx 指定一个容器名,方便之后的操作

RHEL/CentOS系统yum安装nginx

centos直接yum安装nginx
https://www.jianshu.com/p/0626bbd975f3

添加nginx yum源

RHEL/CentOS 7.x及以上版本中

sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

或者按照官方给的方式,直接创建 /etc/yum.repos.d/nginx.repo 文本文件

[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key

http://nginx.org/en/linux_packages.html#RHEL-CentOS

yum安装nginx

$ sudo yum install nginx
已加载插件:extras_suggestions, langpacks, priorities, update-motd
nginx                                                                       | 2.9 kB  00:00:00
nginx/x86_64/primary_db                                                     |  42 kB  00:00:00
21 packages excluded due to repository priority protections
正在解决依赖关系
--> 正在检查事务
---> 软件包 nginx.x86_64.1.1.14.2-1.el7_4.ngx 将被 安装
--> 解决依赖关系完成

依赖关系解决

===============================================================================================
 Package        架构         版本                     源                    大小
===============================================================================================
正在安装:
 nginx          x86_64      1:1.14.2-1.el7_4.ngx     nginx                754 k

事务概要
===============================================================================================
安装  1 软件包

总下载量:754 k
安装大小:2.6 M
Is this ok [y/d/N]: y
Downloading packages:
nginx-1.14.2-1.el7_4.ngx.x86_64.rpm                                           | 754 kB  00:00:01
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
警告:RPM 数据库已被非 yum 程序修改。
  正在安装    : 1:nginx-1.14.2-1.el7_4.ngx.x86_64                                             1/1
----------------------------------------------------------------------

Thanks for using nginx!

Please find the official documentation for nginx here:
* http://nginx.org/en/docs/

Please subscribe to nginx-announce mailing list to get
the most important news about nginx:
* http://nginx.org/en/support.html

Commercial subscriptions for nginx are available on:
* http://nginx.com/products/

----------------------------------------------------------------------
  验证中      : 1:nginx-1.14.2-1.el7_4.ngx.x86_64                                             1/1

已安装:
  nginx.x86_64 1:1.14.2-1.el7_4.ngx

完毕!

查看nginx安装路径

$ rpm -ql nginx
/etc/logrotate.d/nginx
/etc/nginx
/etc/nginx/conf.d
/etc/nginx/conf.d/default.conf
/etc/nginx/fastcgi_params
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/mime.types
/etc/nginx/modules
/etc/nginx/nginx.conf
/etc/nginx/scgi_params
/etc/nginx/uwsgi_params
/etc/nginx/win-utf
/etc/sysconfig/nginx
/etc/sysconfig/nginx-debug
/usr/lib/systemd/system/nginx-debug.service
/usr/lib/systemd/system/nginx.service
/usr/lib64/nginx
/usr/lib64/nginx/modules
/usr/libexec/initscripts/legacy-actions/nginx
/usr/libexec/initscripts/legacy-actions/nginx/check-reload
/usr/libexec/initscripts/legacy-actions/nginx/upgrade
/usr/sbin/nginx
/usr/sbin/nginx-debug
/usr/share/doc/nginx-1.14.2
/usr/share/doc/nginx-1.14.2/COPYRIGHT
/usr/share/man/man8/nginx.8.gz
/usr/share/nginx
/usr/share/nginx/html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/index.html
/var/cache/nginx
/var/log/nginx

yum删除nginx

sudo rpm -e nginx

nginx配置文件路径

我在 aws ec2 和 阿里云 ecs上都用yum装过 nginx,但两者安装完成后的配置文件位置却不一样
aws ec2 上是在 /usr/local/nginx/conf/nginx.conf
阿里云 ecs 上是在 /etc/nginx/nginx.conf
所以,具体安装后的配置文件位置可能还需要 find 搜索下 sudo find / -name nginx.conf

启动nginx

yum 安装的 nginx,会自动注册为系统服务
RHEL/CentOS 6.x及之前版本中,我们可以通过系统服务命令 service 来启动或停止

service nginx start   #启动 nginx 服务
service nginx stop    #停止 nginx 服务
service nginx restart #重启 nginx 服务
service nginx status  #查看 nginx 服务运行状态

如果是在 RHEL/CentOS 7.x及以上的话,用 systemctl 命令来启动和停止

systemctl start nginx.service # 启动nginx服务
systemctl stop nginx.service # 停止nginx服务
systemctl restart nginx.service # 重启nginx服务
systemctl status nginx.service # 查看nginx服务状态

service 启动的nginx 服务,一般来说都是读取的默认配置文件

设置开机启动nginx服务

RHEL/CentOS 6.x及之前版本中

$ sudo chkconfig |grep nginx
nginx              0:关闭    1:关闭    2:关闭    3:关闭    4:关闭    5:关闭    6:关闭
$ sudo chkconfig nginx on
$ sudo chkconfig |grep nginx
nginx              0:关闭    1:关闭    2:启用    3:启用    4:启用    5:启用    6:关闭

源码编译安装nginx

nginx服务器详细安装过程(使用yum 和 源码包两种安装方式,并说明其区别)
https://segmentfault.com/a/1190000007116797

Nginx 安装配置
http://www.runoob.com/linux/nginx-install-setup.html

yum安装缺少的依赖包

yum -y install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel

下载nginx源码

创建并进入源码目录:~/nginx
下载最新稳定版 nginx-1.14.2

sudo wget http://nginx.org/download/nginx-1.14.2.tar.gz

解压到当前目录

sudo tar -xzvf nginx-1.14.2.tar.gz

编译安装

进入 nginx-1.14.2 目录
执行configure命令,生成Makefile

sudo ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-pcre

configure结果:

Configuration summary
  + using system PCRE library
  + using system OpenSSL library
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/local/nginx/sbin/nginx"
  nginx modules path: "/usr/local/nginx/modules"
  nginx configuration prefix: "/usr/local/nginx/conf"
  nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
  nginx pid file: "/usr/local/nginx/logs/nginx.pid"
  nginx error log file: "/usr/local/nginx/logs/error.log"
  nginx http access log file: "/usr/local/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

注意:命令参数中间不要随意加空格,比如“–prefix”后和“=”号之间,否则会提示invalid option

然后,编译:

sudo make

以及,安装:

sudo make install

完成后进入 /usr/local/nginx/ 目录,可以看到已经有 conf, html, logs, sbin 四个目录。

查看nginx版本,进入sbin目录:

./nginx -v
nginx version: nginx/1.14.2

启动nginx:

sudo ./nginx

curl localhost 访问能返回nginx欢迎页面表示启动成功。

常用编译选项说明

--prefix=PATH : 指定 nginx 的安装跟目录,其他sbin、conf、error、pid目录都在此目录之下。默认 /usr/local/nginx
--conf-path=PATH : 设置nginx.conf配置文件的路径。nginx允许使用不同的配置文件启动,通过命令行中的-c选项。默认为conf/nginx.conf
--user=name : 设置nginx工作进程的用户。安装完成后,可以随时在nginx.conf配置文件更改user指令。默认的用户名是nobody。–group=name类似
--with-pcre : 设置PCRE库的源码路径,PCRE 作用是让 Nginx 支持 Rewrite 功能,如果已通过yum方式安装,使用--with-pcre自动找到库文件。使用--with-pcre=PATH时,需要从PCRE网站下载pcre库的源码(8.39)并解压,指定 pcre 的源码路径 ,比如:--with-pcre=/root/pcre-8.39/。perl正则表达式使用在location指令和 ngx_http_rewrite_module模块中。
--with-zlib=PATH : 指定 zlib(版本1.1.3 - 1.2.5)的源码解压目录。在默认就启用的网络传输压缩模块ngx_http_gzip_module时需要使用zlib 。
--with-http_ssl_module : 使用https协议模块。默认情况下,该模块没有被构建。前提是openssl与openssl-devel已安装
--with-http_stub_status_module : 用来监控 Nginx 的当前状态
--with-http_realip_module : 通过这个模块允许我们改变客户端请求头中客户端IP地址值(例如X-Real-IP 或 X-Forwarded-For),意义在于能够使得后台服务器记录原始客户端的IP地址
--add-module=PATH : 添加第三方外部模块,如--add-module=~/source/lua-nginx-module-0.9.14或缓存模块。每次添加新的模块都要重新编译(Tengine可以在新加入module时无需重新编译)

configure执行时和编译期间产生的临时文件默认存放在 源码目录/objs 中,包括产生的Makefile文件、c源文件、目标文件、可执行文件。

官方文档:Building nginx from Sources
http://nginx.org/en/docs/configure.html


yum安装和源码包编译安装的区别

yum 安装是在线安装,好处是:安装方式简单,不易出错;
源码包 安装是先将 nginx 的源码下载下来,在自己的系统里编译生成可执行文件,然后执行,好处是:因为是在自己的系统上编译的,更符合自己系统的性能,也就是说在自己的系统上执行 nginx 服务性能效率更好。

两种安装方式之间的区别
(1)安装位置不同
yum 在线安装会将 nginx 的安装文件放在系统的不同位置,可以通过命令 rpm -ql nginx 来查看安装路径
卸载的时候,只能通过 命令来卸载,否则挨个删除太麻烦,可以通过命令 rpm -e nginx 来卸载,这个命令一般不会报错,因为 nginx 不与其他的包有依赖关系,如果提示关于 依赖包的问题 ,可以尝试 rpm -e --nodeps nginx 来卸载,这个命令相当于强制卸载,不考虑依赖问题。

源码包 安装他的所有文件(包括配置文件,库文件,资源文件等)都在同一个目录下,我们想卸载的时候,直接将这个文件删除就可以,不会有任何垃圾文件存在。
通过源码包编译安装的软件,通常都放在 /usr/local/nginx 路径下

(2)启动方式不同
yum 安装的 nginx,会自动注册为系统服务,我们可以通过 系统服务命令 service 来启动或停止

service nginx start   #启动 nginx 服务
service nginx stop    #停止 nginx 服务
service nginx restart #重启 nginx 服务

如果是在 RHEL 7 或 centos 7 的话,还可以用 systemctl 命令来启动和停止

systemctl start nginx.service # 启动nginx服务
systemctl stop nginx.service # 停止nginx服务
systemctl restart nginx.service # 重启nginx服务
systemctl status nginx.service # 查看nginx服务状态

源码包 安装 nginx 启动的时候不能使用 service 来启动,需要执行 nginx 安装目录下的 sbin 目录下的 nginx 可执行程序才行,如下

$ /usr/local/nginx/sbin/nginx           #启动 nginx 服务
$ /usr/local/nginx/sbin/nginx -s stop   #停止 nginx 服务

个人更喜欢源码编译安装这种清爽绿色的方式。

nginx服务器详细安装过程(使用yum 和 源码包两种安装方式,并说明其区别)
https://segmentfault.com/a/1190000007116797


nginx命令行控制

nginx -t:在不启动nginx的情况下,测试配置文件是否有错误
nginx -t -c /home/test/conf/nginx.conf 验证指定的配置文件
nginx -v:显示nginx版本信息
nginx -V:显示nginx版本信息,以及配置编译阶段的信息,如gcc版本、linux内核版本、执行configure时的参数

nginx:以默认配置文件启动,默认配置文件是 conf/nginx.conf
nginx -c /tmp/nginx.conf:指定配置文件启动

nginx -s stop:强制停止nginx服务,nginx通过nginx.pid文件获得master进程ID,再向master进程发送TERM信号,等同于kill master-pid
nginx -s quit:优雅地停止服务,等同于kill -3 master-pid

nginx -s reload:在不停止服务的情况下重新加载配置项并生效
错误:nginx: [error] open() “/usr/local/sms/logs/nginx.pid” failed (2: No such file or directory)
原因:当前没有nginx进程,直接使用reload启动导致的,因为reload时需要去读取pid


nginx配置

默认配置文件位置 /usr/local/nginx

Nginx的配置文件是以block的形式组织的,一个block通常使用大括号 {} 表示。
block分为几个层级,整个配置文件为main层级,这是最大的层级;
在main层级下可以有event、http等层级,
而http中又会有server 层级,server中可以包含location层级。

每个层级可以有自己的指令(Directive),例如worker_processes是一个main层级指令,它指定Nginx服务的Worker进程数量。
若同一个命令既可以在外层配置,又可以在内层配置,则内层会继承外层的配置,若内层配置与外层不同则会覆盖外层配置。
在扩展模块开发时,可在解析配置项的模块中决定如何处理内外层配置冲突的问题。

配置文件可包含,例如:include mime.types,将配置文件mime.types包含进来

在http扩展模块开发过程中,需要特别注意的是main、server和location三个层级,因为扩展模块通常允许指定新的配置指令在这三个层级中。
一般来说,一个server块表示一个host,而里面的一个location则代表一个路由映射规则,这两个配置块可以说是http配置的核心。

配置项语法格式:
配置项名 配置项值1 配置项值2 …;
之间以空格分隔,若配置项值中有空格等特殊字符,需要用单引号或双引号括住配置项值

日志输出级别:debug、info、notice、warn、error、crit、alert、emerg,从左至右级别依次增大。
设定某个级别后,大于等于该级别的日志都会被输出

常用配置块:
server部分的指令主要用于指定虚拟主机域名、IP和端口;
upstream的指令用于设置一系列的后端服务器,设置反向代理及后端服务器的负载均衡;
location部分用于匹配网页位置(比如,根目录“/”,“/images”,等等)。
他们之间的关系是:server继承main,location继承server;upstream既不会继承指令也不会被继承。它有自己的特殊指令,不需要在其他地方的应用。


ngx_core_module

user 配置worker进程的用户和用户组

ngx_core_module.html/user
http://nginx.org/en/docs/ngx_core_module.html#user

Syntax:   user user [group];
Default:  user nobody nobody;
Context:  main

在nginx.conf文件的第一行一般是设置用户的地方(编译安装nginx时的参数--user=<user>也是指定用户的地方),如 user www www;
如不指定默认是nobody. 这里用户的设置又有什么意义呢?
user配置项主要是指定执行nginx的worker process的用户,linux里所有程序都是文件,都具有权限问题,这个指定的用户对特定的文件有没有权限访问或执行,就是这个用户的意义。

Nginx 主进程(master process)会以 root 权限运行,之后主进程会读取 /etc/nginx/nginx.conf 文件中的 user 模块的配置,nginx 会使用这个指定的用户启动工作进程( worker process)。

那为什么主进程需要使用 root?因为只有 root 可以监听小于1024的端口号,通常 webserver 使用 80/443 端口,这也就是为什么需要 root 来运行了。

nginx user 模块详解
https://segmentfault.com/a/1190000012403369

user配错导致403 Forbidden错误

一开始没有配置 user 项,是以默认的 nobody 用户启动的工作线程,没有读取 /home/ec2-user/git/madaimeng 的权限,虽然我把这个目录权限改为777了,但还是不行。
后来配置了 user ec2-user ec2-user; 就好了

getpwnam(“user”) failed

2019/12/23 03:49:40 [emerg] 1#1: getpwnam(“centos”) failed in /etc/nginx/nginx.conf:2
nginx: [emerg] getpwnam(“centos”) failed in /etc/nginx/nginx.conf:2
原因: nginx.conf 中 user user [group] 指定的用户不存在


worker_processes

http://nginx.org/en/docs/ngx_core_module.html#worker_processes

Syntax:    worker_processes number | auto;
Default: worker_processes 1;
Context:    main

worker_processes 表示工作进程的数量,一般情况设置成CPU核的数量即可,一个cpu配置多于一个worker数,对Nginx而言没有任何益处,另外不要忘了设置 worker_cpu_affinity ,这个配置用于将worker process与指定cpu核绑定,降低由于多CPU核切换造成的寄存器等现场重建带来的性能损耗。
grep processor /proc/cpuinfo | wc -l 这个命令会告诉你当前机器是多少核,输出为2即表示2核。


events

http://nginx.org/en/docs/ngx_core_module.html#events

Syntax:    events { ... }
Default:    —
Context:    main

worker_connections

http://nginx.org/en/docs/ngx_core_module.html#worker_connections

Syntax:    worker_connections number;
Default: worker_connections 512;
Context:    events

worker_connections 配置表示每个工作进程的并发连接数,默认设置为1024。


include

http://nginx.org/en/docs/ngx_core_module.html#include

Syntax:    include file | mask;
Default:    —
Context:    any

ngx_http_proxy_module

Module ngx_http_proxy_module
http://nginx.org/en/docs/http/ngx_http_proxy_module.html


配置实例

nginx+tomcat负载均衡

最常用的nginx+Tomcat负载均衡配置
通过nginx用于反向代理的服务器,并将请求转发给后端多台Tomcat服务器,从而达到负载均衡的目的。

http {
  upstream tomcats {
      server 127.0.0.1:9001;
      server 127.0.0.1:9002;
  }

  server {
      listen 80;
      server_name  www.lianggzone.com;
      location / {
          proxy_pass_header Server;
          proxy_set_header Host $http_host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Scheme $scheme;
          proxy_pass http://tomcats;
      }
  }
}

Nginx 反向代理详解
https://juejin.im/entry/57fb07b0816dfa0056c0ada8


根据不同path转发到不同后台服务

当在一台主机上部署了多个不同的web服务器,并且需要能在80端口同时访问这些web服务器时,可以使用 nginx 的反向代理功能: 用 nginx 在80端口监听所有请求,并依据转发规则(比较常见的是以 URI 来转发)转发到对应的web服务器上。

例如有 webmail , webcom 以及 webdefault 三个服务器分别运行在 portmail , portcom , portdefault 端口,要实现从80端口同时访问这三个web服务器,则可以在80端口运行 nginx, 然后将 /mail 下的请求转发到 webmail 服务器, 将 /com下的请求转发到 webcom 服务器, 将其他所有请求转发到 webdefault 服务器。

假设服务器域名为example.com,则对应的 nginx http配置如下:

http {
  server {
    server_name example.com;

    location /mail/ {
      proxy_pass http://example.com:protmail/;
    }

    location /com/ {
      proxy_pass http://example.com:portcom/main/;
    }

    location / {
      proxy_pass http://example.com:portdefault;
    }
  }
}

以上的配置会按以下规则转发请求( GET 和 POST 请求都会转发):
http://example.com/mail/ 下的请求转发到 http://example.com:portmail/
http://example.com/com/ 下的请求转发到 http://example.com:portcom/main/
将其它所有请求转发到 http://example.com:portdefault/

需要注意的是,在以上的配置中,webdefault 的代理服务器设置是没有指定URI的,而 webmail 和 webcom 的代理服务器设置是指定了URI的(分别为 / 和 /main/)。
如果代理服务器地址中是带有URI的,此URI会替换掉 location 所匹配的URI部分。
而如果代理服务器地址中是不带有URI的,则会用完整的请求URL来转发到代理服务器。

官方文档描述:

If the URI is specified along with the address, it replaces the part of the request URI that matches the location parameter.
If the address is specified without a URI, or it is not possible to determine the part of URI to be replaced, the full request URI is passed (possibly, modified).

以上配置的转发示例:

http://example.com/mail/index.html -> http://example.com:portmail/index.html
http://example.com/com/index.html -> http://example.com:portcom/main/index.html
http://example.com/mail/static/a.jpg -> http://example.com:portmail/static/a.jpg
http://example.com/com/static/b.css -> http://example.com:portcom/main/static/b.css
http://example.com/other/index.htm -> http://example.com:portdefault/other/index.htm

nginx实现请求转发
https://blog.csdn.net/tobacco5648/article/details/51099426


监听不同子域名转发到不同后台服务

比如我有个静态html博客,又有一个springboot后台api服务,都在一台服务器上。
但我只有一个域名,想要主域名 http://madaimeng.com 访问博客,子域名 http://api.madaimeng.com/ 访问api接口。

可以配置nginx监听两个不同的server_name,然后主域名转到静态文件目录,子域名转到对应的springboot服务,配置如下:

server {
    listen       80;
    server_name  api.masikkk.com api.madaimeng.com api.devgou.com;

    location / {
      proxy_pass http://localhost:8001; # 转发到本机spring boot接口
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

server {
    listen       80;
    server_name  devgou.com www.devgou.com;

    location / {
      root   /home/ec2-user/git/madaimeng; # 转发到博客静态目录
      index  index.html;
    }
}

nginx配置CORS跨域访问

如果是允许单域名跨域访问直接配置就行了,如下:

http {
  server {
        listen       80;
        server_name  api.masikkk.com

        location / {
            add_header Access-Control-Allow-Origin "http://masikkk.com";
            add_header Access-Control-Allow-Methods "POST, GET, PUT, OPTIONS, DELETE";
            add_header Access-Control-Max-Age "3600";
            add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept;
        }
  }
}

上面的配置只允许 http://masikkk.com 跨域访问。

如果要支持所有域名都可以跨域访问,可以配置为*,不过不推荐这样做,因为不安全

add_header Access-Control-Allow-Origin "*";

如果不想允许所有,但是又需要允许多个域名,那么就需要用到 map

http {
    map $http_origin $corsHost {
        default 0;
        "~http://madaimeng.com" http://madaimeng.com;
        "~http://devgou.com" http://devgou.com;
        "~http://masikkk.com" http://masikkk.com;
        "~http://localhost:4000" http://localhost:4000;
    }

    server {
        listen       80;
        server_name  api.masikkk.com api.madaimeng.com api.devgou.com;

        location / {
          add_header 'Access-Control-Allow-Origin' $corsHost;
          proxy_pass http://localhost:8001;
        }
    }
}

Nginx map 使用详解
http://blog.51cto.com/tchuairen/2175525

nginx通过CORS实现跨域
https://www.cnblogs.com/sunmmi/articles/5956554.html


proxy_pass

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

Syntax:    proxy_pass URL;
Default:    —
Context:    location, if in location, limit_except

proxy_set_header

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header

Syntax:    proxy_set_header field value;
Default: proxy_set_header Host $proxy_host;
         proxy_set_header Connection close;
Context:    http, server, location

允许重新定义或者添加发往后端服务器的请求头。value可以包含文本、变量或者它们的组合。
当且仅当当前配置级别中没有定义proxy_set_header指令时,会从上面的级别继承配置。

默认情况下,只有两个请求头会被重新定义:

proxy_set_header Host       $proxy_host;
proxy_set_header Connection close;

$proxy_add_x_forwarded_for

$proxy_add_x_forwarded_for 变量包含客户端请求头中的X-Forwarded-For,与$remote_addr两部分,他们之间用逗号分开。

$proxy_add_x_forwarded_for = X-Forwarded-For, $remote_addr

例如客户端请求要经过两个nginx转发,两台的配置都是:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

经过第一台nginx转发时,$proxy_add_x_forwarded_for变量的”X-Forwarded-For”部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,于是赋值以后,X-Forwarded-For变量的值就是用户的真实的ip地址了。
经过第二胎nginx转发时,$proxy_add_x_forwarded_for变量的”X-Forwarded-For”部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的X-Forwarded-For的值就变成了用户的真实ip,第一台nginx的ip

Nginx常见场景代理转发配置
https://blog.csdn.net/faye0412/article/details/75200607


ngx_http_core_module

http://nginx.org/en/docs/http/ngx_http_core_module.html

http

http://nginx.org/en/docs/http/ngx_http_core_module.html#http

Syntax:    http { ... }
Default:    —
Context:    main

default_type

http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type

Syntax:    default_type mime-type;
Default: default_type text/plain;
Context:    http, server, location

sendfile

http://nginx.org/en/docs/http/ngx_http_core_module.html#sendfile

Syntax:    sendfile on | off;
Default: sendfile off;
Context:    http, server, location, if in location

是否开启 Linux sendfile() 零拷贝

keepalive_timeout

http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout

Syntax:    keepalive_timeout timeout [header_timeout];
Default: keepalive_timeout 75s;
Context:    http, server, location

server

http://nginx.org/en/docs/http/ngx_http_core_module.html#server

Syntax:    server { ... }
Default:    —
Context:    http

listen

http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

Syntax:    listen address[:port] [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen port [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen unix:path [default_server] [ssl] [http2 | spdy] [proxy_protocol] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
Default: listen *:80 | *:8000;
Context:    server

server_name

http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name

Syntax:    server_name name ...;
Default: server_name "";
Context:    server

多个域名用空格分开,例如
server_name api.masikkk.com api.madaimeng.com api.devgou.com;


location配置

http://nginx.org/en/docs/http/ngx_http_core_module.html#location

Syntax:    location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
Default:    —
Context:    server, location

location指令是http模块当中最核心的一项配置,根据预先定义的URL匹配规则来接收用户发送的请求,根据匹配结果,将请求转发到后台服务器、非法的请求直接拒绝并返回403、404、500错误处理等。

Nginx之location 匹配规则详解
http://www.cnblogs.com/lidabo/p/4169396.html

基本语法

location指令分为两种匹配模式:
1、普通字符串匹配:以=开头或开头无引导字符()的规则
2、正则匹配:以~*开头表示正则匹配,~*表示正则不区分大小写

(1) =
精确匹配(严格匹配),即exact match,匹配上后立即停止,不再执行正则匹配。
例如 location = / {…} 只有当用户请求是http://host:port/时,才会使用该location下的配置

(2) ~
波浪线表示一个正则匹配,区分大小写

(3) ~*
表示一个正则匹配,不区分大小写

(4) ^~
表示普通字符匹配,即最大前缀匹配,且匹配上后立即停止,不再执行正则匹配
^表示“非”,表示“正则”,字符意思是:不要继续匹配正则
例如 location ^
/image/ {…} 以/images/开始的请求都会匹配上

(5) @
@表示仅用于nginx服务内部请求之间的重定向,带有@的location不直接处理用户请求,带@的location是named_location

location URI匹配规则

当nginx收到一个请求后,会截取请求的URI部份,去搜索所有location指令中定义的URI匹配模式。在server模块中可以定义多个location指令来匹配不同的url请求。
有多个不同location匹配模式时,总体的匹配原则是:先匹配普通字符串模式,再匹配正则模式。

注意:location匹配只识别URI部份,query串(?k=v)不在URI范围内,例如:/films.htm?fid=123 的URI 是/films.htm

例如请求为:/test/abc/user.do?name=xxxx, nginx匹配这个请求的流程如下:
1、先查找是否有=开头的精确匹配,如:location = /test/abc/user.do { … }
2、再查找普通匹配,以 最大前缀 为原则,如有以下两个location,则会匹配后一项
location /test/ { … }
location /test/abc { … }
3、匹配到一个普通格式后,搜索并未结束,而是暂存当前匹配的结果,并继续搜索正则匹配模式
4、所有正则匹配模式location中找到第一个匹配项后,就以此项为最终匹配结果
所有正则匹配项匹配规则,受定义的前后顺序影响,但普通匹配模式不会
5、如果未找到正则匹配项,则以3中缓存的结果为最终匹配结果
6、如果一个匹配都没搜索到,则返回404

正则location与普通location

例如
location ~* \.(gif|jpg|jpeg)$ {...}
匹配以.gif、.jpg、.jpeg结尾的请求

普通location与正则location

正则location匹配让步普通location的严格精确匹配结果;但覆盖普通location的最大前缀匹配结果。

(1) “普通location”与“正则location”之间的匹配规则是:先匹配普通location ,再匹配正则location 。
(2) “普通location”内部(普通location与普通location)是如何匹配的呢?简单的说:最大前缀匹配。
(3) 选择出“普通location ”的最大前缀匹配结果后,还需要继续搜索正则location。
(4) 普通location与顺序无关,而正则location还是与顺序有关的,并且只要匹配到一条正则location ,就不再考虑后面的。
(5) 如果继续搜索的“正则location”也有匹配上的,那么“正则location”覆盖“普通location”的最大前缀匹配;但是如果“正则location”没有能匹配上,那么就用“普通location”的最大前缀匹配结果。
(6) 当“最大前缀”匹配恰好就是一个“严格精确(exact match )”匹配,照样会停止后面的正则匹配。

location / {}

遵守普通location 的最大前缀匹配,由于任何URI 都必然以“/ ”根开头,所以对于一个URI ,如果有更specific 的匹配,那自然是选这个更specific 的,如果没有,“/ ”一定能为这个URI 垫背(至少能匹配到“/ ”),也就是说“location / {} ”有点默认配置的味道。

location =/ { … } 与 location / { … } 的差别:
前一个是精确匹配,只响应/请求,所有/xxx或/xxx/xxxx类的请求都不会以前缀的形式匹配到它
后一个是只要以 / 为前缀的请求都会被匹配到。如:/abc , /test/abc, /test/abc/aaaa

正则表达式语法

^ 匹配字符串的开始
$ 匹配字符串的结束

. 匹配除换行符以外的任意字符

\ 转义字符,可以转义. * ?

* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次

例如:

location ~ ^/prefix/.*\.html$ {
    deny all;
}

表示对于以/prefix/开头,并且以.html结尾的所有URI请求,都拒绝访问
分析 ^/prefix/.*\.html$
^/prefix/ 表示匹配以/prefix/开头的,
.* 表示任意字符重复0或多次,
\. 是对.进行转义,即无特别含义的小数点,
\.html$ 表示以.html结尾的

root 网站根目录

ngx_http_core_module.html/root
http://nginx.org/en/docs/http/ngx_http_core_module.html#root

Syntax:    root path;
Default: root html;
Context:    http, server, location, if in location

定义服务器的默认网站根目录位置。
root 是指定项目的根目录,适用与server和location。可以指定多个,如果locaiton没有指定,会往其外层的server或http中寻找继承。

1、对于匹配后的url地址,将匹配的location中的root路径替换访问url的host即得到文件的真实地址。(多个斜杠其实等价于一个斜杠)
2、如果不匹配location,则寻找更外层的root做替换。
3、root指令最后的斜杠可加可不加。

Nginx静态服务配置—详解root和alias指令
https://www.jianshu.com/p/4be0d5882ec5

404 Not Found错误

一开始我把root目录配置为 ~/git/madaimeng 每次都提示 404 ,后来改为 /home/ec2-user/git/madaimeng 绝对路径就不报这个错误了。

server {
    listen       80;
    server_name  devgou.com www.devgou.com;

    location / {
          root   ~/git/madaimeng;
          index  index.html;
    }
}

alias

http://nginx.org/en/docs/http/ngx_http_core_module.html#alias

Syntax:    alias path;
Default:    —
Context:    location

root和alias
alias后跟的指定目录是准确的,并且末尾必须加“/”,否则找不到文件
root后跟的指定目录是上级目录,并且该上级目录下要含有和location后指定名称的同名目录才行,末尾“/”加不加无所谓。
一般情况下,在location /中配置root,在location /other中配置alias是一个好习惯

error_page

http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page

Syntax:    error_page code ... [=[response]] uri;
Default:    —
Context:    http, server, location, if in location

client_body_buffer_size

Syntax:    client_body_buffer_size size;
Default: client_body_buffer_size 8k|16k;
Context:    http, server, location

此指令设置用于请求主体的缓冲区大小。
如果主体超过缓冲区大小,则完整主体或其一部分将写入临时文件。
如果NGINX配置为使用文件而不是内存缓冲区,则该指令会被忽略。
默认情况下,该指令为32位系统设置一个8k缓冲区,为64位系统设置一个16k缓冲区。
该指令在NGINX配置的http,server和location区块使用。
http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size

client_max_body_size

Syntax:    client_max_body_size size;
Default: client_max_body_size 1m;
Context:    http, server, location

此指令设置NGINX能处理的最大请求主体大小。
如果请求大于指定的大小,则NGINX发回 413 (Request Entity Too Large) 错误。
如果服务器处理大文件上传,则该指令非常重要。
默认情况下,该指令值为1m。

http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size


client_header_buffer_size

Syntax:    client_header_buffer_size size;
Default: client_header_buffer_size 1k;
Context:    http, server

此指令与 client_body_buffer_size 类似。 它为请求头分配一个缓冲区。
如果请求头大小大于指定的缓冲区,则使用 large_client_header_buffers 指令分配更大的缓冲区。
大部分情况1KB大小足够

http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_buffer_size

large_client_header_buffers

Syntax:    large_client_header_buffers number size;
Default: large_client_header_buffers 4 8k;
Context:    http, server

此指令规定了用于读取大型客户端请求头的缓冲区的最大数量和大小。
这些缓冲区仅在缺省缓冲区不足时按需分配。
当处理请求或连接转换到保持活动状态时,释放缓冲区。
http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers

先根据 client_header_buffer_size 配置的值分配一个buffer,如果分配的buffer无法容纳 request_line/request_header
那么就会再次根据 large_client_header_buffers 配置的参数分配large_buffer
如果large_buffer还是无法容纳,那么就会返回 414 (Request-URI Too Large)(处理request_line)/ 400 (Bad Request)(处理request_header)错误。

414 Request-URI Too Large

当http 的URI太长或者request header过大时会报414 Request URI too large或400 bad request错误。

解决方法有:
1、修改Nginx网关header大小
2、改用post方法查询,过长的入参放到body中
3、减少入参长度,改多次调用

<html>
    <head>
        <title>414 Request-URI Too Large</title>
    </head>
    <body bgcolor="white">
        <center>
            <h1>414 Request-URI Too Large</h1>
        </center>
        <hr>
        <center>openresty/1.13.6.1</center>
    </body>
</html>

在nginx的nginx.conf修改如下参数的:

# 客户端请求头缓冲区大小,如果请求头总长度大于小于128k,则使用此缓冲区,
# 请求头总长度大于128k时使用large_client_header_buffers设置的缓存区
client_header_buffer_size 128k;

# large_client_header_buffers 指令参数4为个数,128k为大小,默认是8k。申请4个128k。
large_client_header_buffers 4 128k;

ngx_http_index_module

index

Syntax:    index file ...;
Default: index index.html;
Context:    http, server, location

nginx的初始页选择策略

Nginx给了三种方式来选择初始页,三种方式按照顺序来执行:

  • ngx_http_random_index_module 模块,从给定的目录中随机选择一个文件作为初始页,而且这个动作发生在 ngx_http_index_module 之前,注意:这个模块默认情况下没有被安装,需要在安装时提供配置参数 --with-http_random_index_module
  • ngx_http_index_module 模块,根据index指令规则来选择初始页;
  • ngx_http_autoindex_module 模块,可以使用指定方式,根据给定目录中的文件列表自动生成初始页,这个动作发生在 ngx_http_index_module之后,即只有通过index指令无法确认初始页,此时启用后的自动生成模块才会被使用。

ngx_http_rewrite_module

http://nginx.org/en/docs/http/ngx_http_rewrite_module.html

rewrite

http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite

Syntax:    rewrite regex replacement [flag];
Default:    —
Context:    server, location, if

rewrite只是会改写uri,不会改动查询参数(?id=5&key=33),所以无需关心查询参数,rewrite会自动添加到uri之后

flag参数

last :相当于Apache里的(L)标记,表示完成rewrite;
break;本条规则匹配完成后,终止匹配,不再匹配后面的规则
redirect:返回302临时重定向,浏览器地址会显示跳转后的URL地址
permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
last和break用来实现URL重写,浏览器地址栏URL地址不变

捕获变量

如果regex中使用了某种匹配模式,并且模式串里面带括号,那么表示会捕捉(capture)括号括起来的模式匹配到的字符串,
并将捕捉到的字符串依次设为变量$1,$2,…,然后在replacement中就可以使用这些变量了。

rewrite后去掉参数或改变参数

http://blog.sina.com.cn/s/blog_64e2219d01018lbr.html

关键点就在于“?”这个尾缀,重定向的目标地址结尾处如果加了?号,则不会在目标地址后添加源url中问号后的参数。

例如:
http://example.com/test.php?para=xxx 重定向到http://example.com/new
若按照默认的写法:rewrite ^/test.php(.) /new permanent;
重定向后的结果是:http://example.com/new?para=xxx
如果改写成:rewrite ^/test.php(.
) /new? permanent;
那结果就是:http://example.com/new

保留特定参数
假如又想保留某个特定的参数,那又该如何呢?
可以利用Nginx本身就带有的$arg_PARAMETER参数自行补充来实现。
例如:
http://example.com/test.php?para=xxx&p=xx
重写向到 http://example.com/new.php?p=xx
可以写成:rewrite ^/test.php /new.php?p=$arg_p? permanent;


if语法

http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if

Syntax:    if (condition) { ... }
Default:    —
Context:    server, location

1、正则表达式匹配:
=:用来判断相等,用于字符串的比较
~:与指定正则表达式模式匹配时返回true,区分大小写;
~*:与指定正则表达式模式匹配时返回true,不区分大小写;
!~:与指定正则表达式模式不匹配时返回true,区分大小写;
!~*:与指定正则表达式模式不匹配时返回true,不区分大小写;

2、文件及目录匹配判断:
-f, !-f:判断指定的路径是否为存在且为文件;
-d, !-d:判断指定的路径是否为存在且为目录;
-e, !-e:判断指定的路径是否存在,文件或目录均可;
-x, !-x:判断指定路径的文件是否存在且可执行;


ngx_http_map_module

Module ngx_http_map_module
http://nginx.org/en/docs/http/ngx_http_map_module.html

map指令

Syntax:    map string $variable { ... }
Default:    —
Context:    http

map 指令是由 ngx_http_map_module 模块提供的,默认情况下安装 nginx 都会安装该模块。

map 的主要作用是创建自定义变量,通过使用 nginx 的内置变量,去匹配某些特定规则,如果匹配成功则设置某个值给自定义变量。 而这个自定义变量又可以作于他用。

例如:匹配请求 url 的参数 $args,如果参数是 debug 则设置 $foo = 1 ,默认设置 $foo = 0

map $args $foo {
    default 0;
    debug   1;
}

解释:$args 是nginx内置变量,就是获取的请求 url 的参数。 如果 $args 匹配到 debug 那么 $foo 的值会被设为 1 ,如果 $args 一个都匹配不到 $foo 就是default 定义的值,在这里就是 0

map 语法

map $var1 $var2 {...}

map 的 $var1 为源变量,通常可以是 nginx 的内置变量,$var2 是自定义变量。 $var2 的值取决于 $var1 在对应表达式的匹配情况。 如果一个都匹配不到则 $var2 就是 default 对应的值。

map 在 Nginx 配置文件中的作用段是 http{} ,注意不能写在 server{} 否则会报错

map 指令的三个参数:
1、default : 指定源变量匹配不到任何表达式时将使用的默认值。当没有设置 default,将会用一个空的字符串作为默认的结果。
2、hostnames : 允许用前缀或者后缀掩码指定域名作为源变量值。这个参数必须写在值映射列表的最前面。
3、include : 包含一个或多个含有映射值的文件。

一个正则表达式如果以 ~ 开头,表示这个正则表达式对大小写敏感。以 ~* 开头,表示这个正则表达式对大小写不敏感。

实例(二)
使用源变量(通常是 nginx 内置变量)匹配一些规则,创建自定义变量,然后在页面输出. 这通常在调试的时候非常有用

http {
  map $uri $match {
      ~^/hello/(.*) http://www.hello.com/;
  }
  server {
    listen       8080;
    server_name  test.hello.com;

    location /hello {
            default_type text/plain;
            echo uri: $uri;
            echo match: $match;
            echo capture: $1;
            echo new: $match$1;
    }
  }
}

Nginx map 使用详解
http://blog.51cto.com/tchuairen/2175525


可用的全局变量

Alphabetical index of variables
http://nginx.org/en/docs/varindex.html

args               #这个变量等于请求行中(GET请求)的参数,例如foo=123&bar=blahblah;

arg_PARAMETER      #这个变量包含GET请求中如果有变量PARAMETER时的值。
例如http://example.com/test.php?id=5&key=33
则arg_id的值为5,arg_key的值为33

binary_remote_addr #二进制的客户地址。
body_bytes_sent    #响应时送出的body字节数数量。即使连接中断,这个数据也是精确的。
content_length     #请求头中的Content-length字段。
content_type       #请求头中的Content-Type字段。
cookie_COOKIE      #cookie COOKIE变量的值
document_root      #当前请求在root指令中指定的值。
document_uri       #与uri相同。
host               #请求主机头字段,否则为服务器名称。
hostname           #Set to the machine’s hostname as returned by gethostname

http_HEADER
is_args            #如果有args参数,这个变量等于”?”,否则等于”",空值。
http_user_agent    #客户端agent信息
http_cookie        #客户端cookie信息
limit_rate         #这个变量可以限制连接速率。
query_string       #与args相同。
request_body_file  #客户端请求主体信息的临时文件名。
request_method     #客户端请求的动作,通常为GET或POST。
remote_addr        #客户端的IP地址。
remote_port        #客户端的端口。
remote_user        #已经经过Auth Basic Module验证的用户名。
request_completion #如果请求结束,设置为OK. 当请求未结束或如果该请求不是请求链串的最后一个时,为空(Empty)。
request_method     #GET或POST
request_filename   #当前请求的文件路径,由root或alias指令与URI请求生成。
request_uri        #包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。不能修改。
scheme             #HTTP方法(如http,https)。
server_protocol    #请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
server_addr        #服务器地址,在完成一次系统调用后可以确定这个值。
server_name        #服务器名称。
server_port        #请求到达服务器的端口号

问题

无/var/lib/nginx权限导致请求体较大时500

这个问题是我在给 git 添加 webhooks 时出现的。
添加后每次push代码总是回调 webhooks 接口失败,但我自己通过 curl 或浏览器访问就能成功, 看了看 nginx error 日志

2019/08/29 16:38:52 [crit] 9611#0: *6500 open() "/var/lib/nginx/tmp/client_body/0000000012" failed (13: Permission denied), client: 118.25.132.68, server: webhooks.devgou.com, request: "POST /pull/madaimeng HTTP/1.1", host: "webhooks.devgou.com"

网上搜了搜,原因大概是,我自己访问时没有请求体,coding上回调时请求体很大,貌似把整个diff内容都发过去了,估计 nginx 会用 /var/lib/nginx 这个目录存储较大的请求体,然后没权限就报错了。

解决方法
sudo chmod -R 775 /var/lib/nginx


上一篇 Spring-Data-Redis

下一篇 Spring-Test

阅读
评论
10,581
阅读预计44分钟
创建日期 2018-10-10
修改日期 2020-02-13
类别
标签

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论