nginx二三事

过去的项目一直使用windows,加上后台使用的是PHP,自然而然使用Wamp集成本地服务器开发环境。新公司项目用node写中间层,需要使用nginx搭建本地环境,之前对nginx的了解仅限于反向代理,现搭环境基本都是现查资料现学,因此简单整理,以做备忘。

<!--more-->

开发环境是Mac OS 10.12.6,参考:

  • 官方文档,网上有大量的nginx教程,但还是先看看官方文档吧
  • nginx教程,这个可以下载PDF快速浏览一遍,写得挺好的

1. 安装

通过brew安装

brew install nginx

由于遇见了一个很蛋疼的问题

Error: Cannot link pcre Another version is already linked: /usr/local/Cellar/pcre/8.41

貌似是brew权限的问题,参考解决方案

sudo chown -R $USER /usr/local

然后重新安装即可

2. 基本使用

安装完成后使用nginx -h查看对应指令。

# 启动服务
sudo nginx

启动完成后可以通过下面语法进行控制

sudo nginx -s signal

其中signal有下面四个选项

  • stop,快速关闭
  • quit,平滑关闭
  • reload,重新加载配置文件,这个命令在修改配置文件后经常使用
  • reopen,重新打开log文件

可以通过ps查看nginx进程状态

# 输出格式化的表格
ps axw -o pid,ppid,user,%cpu,vsz,wchan,command | egrep '(nginx|PID)'

可以发现有一个master process和多个worker process的情形 ,这跟nginx的进程管理模型有关,在Master 模型下

  • master 进程主要负责对外揽活(即接收客户端的请求),并将活儿合理的分配给多个worker,
  • 每个worker 进程主要负责干活(处理请求)。

也可以通过kill 杀掉master process的进程,实现nginx -s quit的功能。

3. 配置

文档里提到,nginx配置文件通过指令Directives来实现

  • 简单指令,以分号结尾
  • 块级指令,包含数条简单指令,以{}包围
  • 如果一个块级指令内部包含其他指令,就称为context,常见的如events, http, server, and location等

下面是安装后的nginx的配置文件的一部分

# /usr/local/etc/nginx/nginx.conf

user root staff; 
events {
    worker_connections  1024;
}

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

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }
    }
}

include /usr/local/etc/nginx/conf.d/*.conf

这个是nginx的主要配置文件,还可以通过include指令引入其他的子配置模块文件。

3.1. 指令

指令和指令之间是有层级和继承关系的,现在暂时只关注http和server等web相关的东西。

server server就是一个web服务器,可以简单理解为部署的一个网站。一个server常见的配置有

  • 端口号,web服务器默认端口号均为80,通过listen指定
  • 站点根目录,通过root指定
  • 站点根文件,通过index指定
  • 域名,通过server_name指定

那么下面就是一个server指令的配置,跟Apache的XML配置相比,nginx的配置要简洁很多

server {
    listen       80;
    server_name  localhost;
    root /usr/share/nginx/html;
    index index.html index.htm;
}

location 如果要访问server根目录下其他文件,可以通过location指令进行定位

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

location ~ \.php {
    fastcgi_pass localhost:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    inclue fastcgi_params;
}                    

下面是location的匹配规则

location [=|~|~*|^~] /uri/ { ... }
  • = 开头表示精确匹配
  • ^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)。
  • ~ 开头表示区分大小写的正则匹配
  • ~* 开头表示不区分大小写的正则匹配
  • !和!*分别为区分大小写不匹配及不区分大小写不匹配 的正则
  • / 通用匹配,任何请求都会匹配到。

关于location更详细的配置,可以参考这里

3.2. 代理服务器

考虑下面一个场景:用户A需要访问C服务器,但是由于某种原因限制,A只能访问B服务器而不能访问C服务器,一种解决办法是通过B访问C服务器,然后将请求结果返回给A服务器。这种处理方式被称做正向代理,正向代理一般由客户端设置,B作为代理服务器,其主要作用是转发请求

反向代理与正向代理相反,其中,由C提供真正的服务,A不知道也不需要知道C的存在,只需要访问B即可,B会作为C的代理服务器向用户提供服务。与正向区别的代理在于,客户端不需要手动设置代理服务器地址。

工作项目中,node开启的本地服务器运行在一个指定的端口上,而http默认端口号为80,因此需要将其他端口上的服务器通过nginx进行反向代理`

server {
    listen 80;
    server_name api.test.com;

    location / {
        proxy_pass http://127.0.0.1:3015;
    }
}

如果还需要转发请求信息,可以添加

proxy_set_header Host $host;  
proxy_set_header X-Real-IP $remote_addr;  
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  

3.3. gzip

开启gzip后会显著降低静态资源的尺寸,提高传输效率,当然这需要消耗一定的CPU资源用于压缩。

下面是关于gzip的配置

http {
    gzip on;
    # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
    gzip_min_length 1k;

    # gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
    gzip_comp_level 2;

    # 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
    gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;

    # 是否在http header中添加Vary: Accept-Encoding,建议开启
    gzip_vary on;

    # 禁用IE 6 gzip
    gzip_disable "MSIE [1-6]\.";

    server {
        listen 80;
        server_name static.test.com;

        location ~ ^/static/ {
            gzip_static on;
            expires max;
            add_header Cache-Control public;
        }
    }
}

4. 常见问题

下面是在开发过程中遇见的一些问题

4.1. 检测配置文件格式

如果nginx.conf文件语法错误,则会导致reload失败,可以通过

nginx -t

对配置文件进行校验

4.2. nginx.pid丢失

某次电脑重启导致nginx退出异常,使用nginx -s reload

nginx: [error] open() "/usr/local/var/run/nginx.pid" failed (2: No such file or directory)

错误原因是nginx.pid丢失。正常情况下,启动nginx后,会在/usr/local/var/run目录下生成nginx.pid文件,而nginx -s stop则会删除该文件。

遇见上面这种情况,则需要重新启动nginx,生成nginx.pid文件

sudo nginx

同理,在已启动nginx的情况下,再次启动nginx则会出现下面错误

nginx: [emerg] bind() to 0.0.0.0:80 failed (48: Address already in use)

这种情况下,只需要使用nginx -s reload即可。

4.3. nginx 静态资源403

本地有个静态资源服务器,配置站点root后访问,出现403错误。

参考解决办法,配置nginx.conf的user选项

  • 先查看目录的权限ls -la获取用户和所在分组
  • 然后配置user username [usergroup];

5. 小结

现在在工作中需要用node写中间层,以后接触到nginx的场景也比较多,因此还需要多多学习。不得不说,nginx确实比Apache更简洁一些。