聊聊 nginx 的那些事

Nginx 目录介绍

  • conf : 配置文件
  • html : 网页文件
  • logs : 日志文件
  • sbin : 主要二进制程序

启动Nginx

  • 命令:cd /path/nginx

  • 启动:./sbin/nginx

    • 启动时有时会报错:80端口被占用。
    • 解决方法是,找到占用80端口的程序,并杀掉进程。
    • natstat -antp : 查看端口信息
  • 如果没有发现有程序占用80端口,并且nginx启动还是报错的话,有可能是 nginx 试图同时监听 ipv4 和 ipv6 的 80 端口导致的;

    解决方法:

    server {
        listen 80;
        listen [::]:80 ipv6only=on;
    }

    server {
        listen [::]:80;
    }

Nginx 常用命令

  • nginx -t : 检测配置文件是否正确,如果出错会报错误信息;
  • nginx -s reload : 加载最新配置
  • nginx -s stop : 立即停止
  • nginx -s quit : 优雅停止
  • nginx -s reopen : 重新打开配置文件

Nginx 配置段详解

# 全局区
# 有1个工作的子进程,可以自行修改,不需要太大,会消耗CPU资源,    

# 一般设置为 CPU数*核数

worker_processes 1; 

Events {
# 一般是配置nginx连接的特性
# 如1个worker能同时允许多少连接
 worker_connections  1024; # 这是指 一个子进程最大允许连1024个连接
}

http {  #这是配置http服务器的主要段

     Server1 { # 这是虚拟主机段

            Location {  #定位,把特殊的路径或文件再次定位 ,如image目录单独处理
                ...
            }           # 如.php单独处理

     }

     Server2 {
        ...
     }
}

Nginx 配置虚拟主机

  • 基于域名的虚拟主机
    server {
        listen 80;  #监听端口
        server_name a.com; #监听域名,如有多个,空格隔开

        location / {
                root /var/www/a.com;   #根目录定位
                index index.html; #默认索引页
        }
    }
  • 基于端口的虚拟域名
 server {
        listen 8080;
        server_name a.com;

        location / {
                root /var/www/html8080;
                index index.html;
        }
    }

Nginx 日志管理

  • 观察 server 段,可以看到如下的信息
   access_log  logs/access.log  main;
  • 说明 nginx 的请求日志保存在 logs/access.log 中,日志的保存格式是: main;

  • 什么是 main 格式?还有什么其他格式呢?

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
  • 还可以自定义格式
log_format  mylog  '$remote_addr [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent"';

server {
        listen 80;
        #下面声明a.com使用mylog格式日志,并保存在logs/a.com.log文件中
        access_log logs/a.com.log mylog;
        server_name a.com www.a.com;
 ....

}  

main 格式是自定义好的日志记录格式,自定义名称,便于引用; 以上示例中,main 格式中记录的信息有$remote_addr ....http_x_forwarded_for 等信息。

  • 日志格式 是指记录哪些选项

默认的日志格式: main

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

如默认的 main 日志格式,记录这么几项 远程IP- 远程用户/用户时间 请求方法(如GET/POST) 请求体body长度 referer来源信息 http-user-agent用户代理/蜘蛛 ,被转发的请求的原始IP http_x_forwarded_for : 在经过代理时,代理把你的本来IP加在此头信息中,传输你的原始IP

小应用

shell + 定时任务 + nginx信号管理,完成日志按日期存储

  • 分析思路: 凌晨00:00:01,把昨天的日志重命名,放在相应的目录下 再USR1信息号控制nginx重新生成新的日志文件
#!/bin/bash
base_path='/usr/local/nginx/logs'
log_path=$(date -d yesterday +"%Y%m")
day=$(date -d yesterday +"%d")
mkdir -p $base_path/$log_path
mv $base_path/access.log $base_path/$log_path/access_$day.log
#echo $base_path/$log_path/access_$day.log

/usr/local/nginx/sbin/nginx -s reopen
  • 定时任务
# Crontab 编辑定时任务
01 00 * * * /xxx/path/b.sh  # 每天0时1分(建议在02-04点之间,系统负载小)

Nginx 和 PHP

  • 通信原理:

apache一般是把php 当做自己的一个 模块 来启动的. 而nginx则是把http请求变量(如get,user_agent等)转发给 php 进程,即 php 独立进程,与 nginx 进行通信. 称为 fastcgi 运行方式. 因此,为 apache所编译的php,是不能用于nginx的.

  • nginx 和 PHP的配置

把请求信息转发到9000端口里的PHP进程,让PHP进程处理,指定目录下的php文件。

# 碰到以 `php` 结尾的文件(碰到php文件)
location ~ \.php$ {
    # 把根目录定位到 html
    root html;
    # 把请求上下文转交给9000端口PHP进程
    fastcgi_pass   127.0.0.1:9000;
    # 并告诉PHP进程,当前的脚本是 
    fastcgi_index  index.php;
    # $document_root$fastcgi_scriptname PHP会去找这个脚本并处理,这个脚本的位置不能错误
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;

}

Nginx 与 Rewrite 规则

  • rewrite 语法

Rewrite 正则表达式 定向后的位置 模式

# 原理
# goods-3.html ---->goods.php?goods_id=3
# goods-([\d]+)\.html ---> goods.php?goods_id = $1  

location / {
    index index.php;
    rewrite goods-([\d]+)\.html$ /shop/goods.php?id=$1;
}

注意:用url重写时, 正则里如果有 {} ,正则要用双引号包起来

pathinfo 支持

# 典型配置
location ~ \.php$ {
    root           html;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $DOCUMENT_ROOT$fastcgi_script_name;
    include        fastcgi_params;
}
  • 第一种修改方式

# 修改第1,5,6行,支持pathinfo

location ~ \.php(.*) { # 正则匹配.php前后的script_name和pathinfo部分
    root html;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $DOCUMENT_ROOT$fastcgi_script_name;
    fastcgi_param PATH_INFO $1; # 把pathinfo部分赋给PATH_INFO变量
    include        fastcgi_params;
}
  • 可以通过rewrite方式代替php中的PATH_INFO
#实例:thinkphp的pathinfo解决方案
#设置URL_MODEL=2
location / {
    if (!-e $request_filename){
        rewrite ^/(.*)$ /index.php?s=/$1 last;
    }
}
  • nginx配置文件中设置PATH_INFO值

请求的网址是 /abc/index.php/abc

PATH_INFO 的值是 /abc SCRIPT_FILENAME 的值是 $doucment_root/abc/index.php SCRIPT_NAME /abc/index.php

  • nginx 可以使用 fastcgi_split_path_info指令来设置 PATH_INFO,在 location 段添加如下配置。
location ~ ^.+.php {
  (...)
  fastcgi_split_path_info ^((?U).+.php)(/?.+)$;
  fastcgi_param SCRIPT_FILENAME /path/to/php$fastcgi_script_name;
  fastcgi_param PATH_INFO $fastcgi_path_info;
  fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
  (...)
}
  • try_files : 配置laravel 项目时需要使用改配置;

    • try_files 指令也放在 serverlocation 上下文中。

    • try_files 指令的参数是 一个或多个文件或目录的列表以及最后面的 URI 参数

    • Nginx 会按顺序检查文件及目录是否存在(根据 root 和 alias 指令设置的参数构造完整的文件路径),并用找到的第一个文件提供服务。在元素名后面添加斜杠 / 表示这个是目录。如果文件和目录都不存在,Nginx 会执行内部重定向,跳转到命令的最后一个 uri 参数定义的 URI 中。

    • 要想 try_files 指令工作,必须定义一个 location 块捕捉内部重定向。最后一个参数可以是命名过的 location,由初始符号(@)指示。

    • try_files 指令通常使用 $uri 变量,表示 URL 中域名之后的部分。

location /images/ {
    try_files $uri $uri/ /images/default.gif;
}

location = /images/default.gif {
    expires 30s;
}

Nginx 动静分离和反向代理

  • 动静分离

    • 用nginx 做反向代理使用 poxy_pass
    • 以反向代理为例,nginx 不自己处理一些图片资源,而是把图片的请求转发给另一台机器进行处理
location ~ \.(jpg|jpeg|png|gif)$ {
        proxy_pass HTTP://IP:port;
}
  • 可以通过代理服务器使用设置头信息字段,把用户真正的IPIP传到后台服务器去.
location ~ \.(jpg|jpeg|png|gif)$ {
        proxy_set_header X-Forwarded-For $remote_addr;
        
        proxy_pass HTTP://IP:port;
}

反向代理+负载均衡

  • 在nginx中做集群与负载均衡,步骤都是一样的 Upstream {} 模块 把多台服务器加入到一个组, 然后 memcached_pass, fastcgi_pass, proxy_pass ==> upstream

具体配置步骤:

  • 1:配置 upstream
# 创建一个负载均衡组
upstream imageserver {
    server 192.168.1.204:8080 weight=1 max_fails=2 fail_timeout=30s;
    server 192.168.1.204:8081 weight=1 max_fails=2 fail_timeout=30s;
}
  • 2: 下游调用
location ~ \.(jpg|jpeg|png|gif)$ {
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        # 在这里使用创建的负载均衡组
        proxy_pass http://imageserver;
}
登录后进行讨论