Nginx Note

References

Note

Note for Nginx 教程

1 - 基本介绍和配置

安装

Ubuntu

$ sudo apt-get install nginx

macOS

$ brew install nginx

在 macOS 上安装完后会告诉你 doc root 目录在哪,默认配置在哪,如何启动:

Docroot is: /usr/local/var/www

The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that nginx can run without sudo.

nginx will load all files in /usr/local/etc/nginx/servers/.

To have launchd start nginx now and restart at login:

brew services start nginx

Or, if you don't want/need a background service you can just run:

nginx

默认 index.html 在 /usr/local/var/www,默认配置文件在 /usr/local/etc/nginx/nginx.conf,默认端口 8080。

启动 nginx 的几种办法,可以用 init.d 脚本启动,可以用 service,也可以直接用 nginx 命令启动。

$ sudo /etc/init.d/nginx [start|stop|restart]

# or
$ sudo service nginx [start|stop|restart]

# or
$ sudo nginx [-s quit|reload]

通过 brew 安装则还可以用 brew services 命令启动,在上面 brew install nginx 后的输出里有提示,也可以通过 brew info nginx 重新获取这个信息。

$ brew services start nginx

启动 nginx 后访问 http://locahost:8080,将显示 /usr/local/var/www/index.html 的内容。

配置文件语法

(这是关键,但是有点失望,这篇文章其实讲得并不是很清楚。)

需要补充看这篇 - Nginx 的配置系统

Ubuntu 上 nginx 的配置文件默认放在 /etc/nginx/nginx.conf。

nginx 是模块化系统,每个模块负责不同的功能。比如 http_gzip_static_module 就是负责压缩的,http_ssl_module 就是负责加密的。

在配置文件中,每个模块都有自己不同的指令,同时 nginx 内置了一些指令,比如 events, http, server, location 等。

配置文件基本就是由这样一条一条指令组成的。(像是一种 DSL 一样,看着很像 gradle)

每个配置项由配置指令和指令参数 2 个部分构成。指令参数也就是配置指令对应的配置值。

默认内容 (Linux 上的版本,mac 上有些不同):

user www-data;
worker_processes 1;
pid /run/nginx.pid;

events {
  worker_connections 768;
}

http {
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 65;
  types_hash_max_size 2048;

  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  gzip on;
  gzip_disable "msie6";

  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-enabled/*;
}

配置项有两种,简单配置项和复杂配置项。前三行,以及 {} 中的都是简单配置项,只有一行,用 ; 结束。

复杂配置项,用 {} 包围,形成一个 block,内含多条简单配置项。

events {
}
http {
}
# 常见的还有 mail block
mail {
}

block 可以嵌套

http {
  server {
  }
}

通过 include 指令来包含其它配置文件,所以 /etc/nginx/nginx.conf 是顶层配置文件,一般各个网站自己的配置都以一个独立配置文件的形式放在 sites-enabled 目录下。

常见配置大致都长这样:

...
http {
  ...
  # 这部分可能存在于/etc/nginx/conf.d/目录下
  upstream {
  }

  server {
    listen 8080;
    root /data/up1;

    location / {
    }
  }

  server {
    listen 80;
    root /data/up2;

    location / {
    }
  }

  ...
}

在一个 http block 中有多个 server block。

指令和指令之间是有层级和继承关系的。比如 http 内的指令会影响到 server 的。

http 那部分除非必要,我们不动它,假如你现在要部署一个 web 服务,那就在 /etc/nginx/conf.d/ 目录下新增一个文件就好了。

http 和 events 还有 mail 是同级的。http 就是跟 web 有关的。

server,顾名思义就是一个服务,比如你现在有一个域名,要部署一个网站,那就得创建一个 server 块。

一般我们需要做的就是配置 server block,而在 server block 中最需要我们配置的是 location block。来看一个例子:

server {
    listen      80;
    server_name example.org www.example.org;
    root        /data/www;

    location / {
        index   index.html index.php;
    }

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

    location ~ \.php$ {
        include /usr/local/etc/nginx/fastcgi.conf;
        fastcgi_intercept_errors on;
        fastcgi_pass   127.0.0.1:9000;
    }
}

这个配置表示我们新增了一个域名为 example.org 的网站,server_name 指令用来表示域名,listen 指令用来表示监听的端口,root 表示这个项目的根目录。

当用户通过浏览器访问 http://example.org 时,这时 path 为 /,将匹配到 location / 规则,因此,nginx 会先去找 /data/www/index.html,如果它不存在,则继续找 /data/www/index.php,如果仍然没有,那么访问就会失败 (测试后发现显示的是一个文件列表)。

假如找到了 index.html,那么因为它已经是一个静态文件,且没有其它 location 规则来处理 .html 格式的文件,那么它会被 nginx 直接返回给客户端。

假如找到的是 index.php,因为后面还有 location ~ \.php$ 的规则匹配它,那么它会进一步由这个规则来处理,这个规则说,所有的 .php 文件,转给给 localhost:9000 端口上的服务处理 (这个服务是 php-fpm 服务),php-fpm 解析并执行 php 文件,将得到的结果返回给 nginx,再由 nginx 返回给客户端。

如果用户访问 http://example.org/about.gif,nginx 就会去找 /data/www/about.gif,并设置 30 天过期的 http header。

location 就是用来设置静态文件匹配的各种规则的,注意 Nginx 只能处理静态文件,没有匹配上的路径,才会交给后面的 web app 来动态处理。

匹配规则要理解,但在这篇文章里没有说 ...

2 - 反向代理

反向代理为何叫反向代理?

假设客户为 A,代理服务器为 B,真正提供服务的服务器为 C。

正向代理和反向代理,都是客户端 A 把请求交给代理服务器 B,代理服务器交给真正提供服务的服务器 C 实现功能,再通过代理返回客户端,看似流程是一样,但本质是完全不同的。

  • 正向代理

    客户端 A 本想直接和服务器 C 通信,但由于某种原因,无法直接通信,但服务器 B 可以和 C 通信。

    于是 A 通过正向代理服务器 B 来和 C 通信。

    它代理的是客户端,它向真正提供服务的服务器隐藏了客户端的身份。在正向代理中,客户端知道真正提供服务的服务器的身份。

  • 反向代理

    B 宣称它能完成某个功能,于是 A 直接请求 B,B 收到请求后,转发给 C 来实现,然后再发回给 A,整个过程中 A 并不知道 C 的存在。

    它代理的是真正提供服务的服务器,它向客户端隐藏了真正提供服务的服务器的身份。在反向代理中,客户端不知道真正提供服务的服务器的身份,它还以为是代理服务器做的呢。

在反向代理中,真正提供服务的服务器 C 称为代理服务器 B 的上游 (upstream)。

反向代理服务器背后往往是一个 Web 集群,反向代理服务器的一个重要功能是负载均衡。

现实生活中往往是这样的:客户端 A 通过正向代理服务器 B 访问服务器 C,但实际服务器 C 是一台反向代理服务器,它访问服务器 D/E/F 实现最终功能。

示例

毫无疑问,Nginx 就是一个反向代理。

Nginx 的反向代理是依赖于 ngx_http_proxy_module 这个 module 来实现的,指令是 proxy_pass

反向代理服务器能代理的请求的协议包括 http(s),FastCGI,SCGI,uwsgi,memcached 等。我们这里主要集中在 http(s) 协议。

这里举了一个反向代理 http 到 https 的例子,很有用。

一个 https 的网站里是不允许 http 的资源的,否则浏览器上表示安全的绿色标志就没有了。比如 https://example.org 中引用了 http://image.sinajs.cn/test.gif。

首先,我们要修改我们的网页代码,把引用了 http://image.sinajs.cn/test.gif 的地方改成 https://example.org/test.gif,这样改了以后,那这个资源实际在我们网站上是不存在的呀,这时候,我们可以通过 Nginx 把这个资源指向原始的 http://image.sinajs.cn/test.gif

如下所示:

# https
server {
  server_name www.example.com;
  listen       443;

  location /test.gif {
    proxy_pass http://image.sinajs.cn/test.gif;
  }
  ...
}

got it!

转发动态请求到 Web App,这里举了 Rails 的例子:

upstream rails365 {
    # Path to Unicorn SOCK file, as defined previously
    server unix:///home/yinsigan/rails365/shared/tmp/sockets/unicorn.sock fail_timeout=0;
}
server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    server_name www.rails365.net;
    root         /home/yinsigan/rails365/current/public;

    try_files $uri/index.html $uri @rails365;
    location @rails365 {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://rails365;
    }
}

try_files $uri/index.html $uri @rails365 这句话的意思是,请求任意一个 url,如果 url 是 /,则找 root 目录下的 index.html,否则找相应的静态文件,比如请求 /about.html 则找根目录下的 about.html,如果都没找到,通过 location @rails365 规则找。在 location @rails365 规则中,则是将请求转发给 upstream rails365 处理。

3 - gzip 模块

用 gzip 模块可以压缩静态资源,加快传输速度。使用 ngx_http_gzip_module module。

需要浏览器支持,浏览器的请求头要带上 Accept-Encoding: gzip

示例:

http {
    gzip on;
    gzip_disable "msie6";

    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    server {
        location ~ ^/assets/ {
            gzip_static on;
            expires max;
            add_header Cache-Control public;
        }
    }
}

在 http block 中,gzip ongzip_types 是必须设置的,其余可选,在 server block 中的三个选项都是必须设置的。

其它

剩下章节都是一些使用示例及一些模块的介绍,挑一些看吧。

ngxtop,一个监控 nginx 状态的命令行工具。

使用 acme.sh 安装 Let’s Encrypt 提供的免费 SSL 证书。

nginx 的日志切割,使用 logrotate 这个服务即可。

nginx 作为负载均衡器,在 upstream 中多指定一些 server 就行了,当然,还有一些其它可用的参数。

upstream rails365 {
    # Path to Unicorn SOCK file, as defined previously
    server unix:///home/yinsigan/rails365/shared/tmp/sockets/unicorn.sock;
    server unix:///home/yinsigan/rails365_cap/shared/tmp/sockets/unicorn.sock;
}

OK,到目前为止,已经理解 nginx 的使用了。需要时再详细看文档吧。

一些关于 location 区配规则的补充,还没仔细看,先把链接放在这,需要时再看。

results matching ""

    No results matching ""