介绍

Nginx的日志管理是一个重要的功能,它允许用户跟踪和监控Nginx服务器的运行状态和性能。以下是Nginx日志管理的关键点:

  1. 日志类型:
    • 访问日志(Access Log):记录每个请求的信息,包括客户端IP、请求时间、请求方法、URI、状态码、发送字节数等。通过访问日志,得到用户地域来源、跳转来源、使用终端、某个URL访问量等相关信息。
    • 错误日志(Error Log):记录Nginx服务运行期间发生的错误信息和警告信息。通过错误日志,得到系统某个服务或server的性能瓶颈等信息。
  2. 日志配置:
    • 通过修改Nginx的配置文件(通常是nginx.conf)来定义日志的位置和格式。例如,使用access_log和error_log指令来分别指定访问日志和错误日志的文件路径。
    • Nginx还允许通过log_format指令定义自定义的日志格式。根据需要记录特定的信息。
    • Nginx允许我们根据需要定义自定义的日志变量和字段。记录与特定请求或响应相关的特定信息,以便后续分析和调试。
  3. 日志轮转、压缩与删除:
    • 为了管理旧的日志文件并节省磁盘空间,结合使用logrotate工具来定期压缩和删除旧的日志文件。
    • logrotate可以根据需求配置为每天、每周或每月执行一次压缩和删除操作。
    • Nginx支持日志轮转功能,这意味着它可以在达到一定的文件大小或时间限制时自动创建新的日志文件。这有助于防止日志文件变得过大并耗尽磁盘空间。
  4. 日志分析:
    • 可以使用各种日志分析工具(如ELK Stack、Graylog等)来分析和可视化Nginx的日志数据。
    • 这些工具可以让我们更好地理解Nginx的运行状态、性能瓶颈以及用户行为等。
  5. 安全性:
    • 确保Nginx的日志文件仅对需要访问它们的用户开放。不要将日志文件暴露给未经授权的用户或攻击者。
    • 使用适当的权限设置来保护日志文件,以防止未经授权的访问和修改。

总之,Nginx的日志管理功能非常强大和灵活,可以帮助我们更好地了解Nginx的运行状态、性能以及用户行为。通过合理配置和分析日志数据,可以及时发现和解决问题,优化Nginx的性能和安全性。

Nginx日志配置

  • 我们进入到nginx目录下的log目录中,可以看到里面存放着三个文件,分别是access.logerror.lognginx.pid文件,其中nginx.pid是用来记录当前nginx进程的pid号的,不属于日志文件。真正属于日志文件的是另外两个文件。

    1
    2
    3
    [root@RockyLinux9 ~]# ls /usr/local/nginx/logs/
    access.log error.log nginx.pid
    # 访问日志 错误日志
  • 访问日志(Access Log):记录每个请求的信息,包括客户端IP、请求时间、请求方法、URI、状态码、发送字节数等。通过访问日志,得到用户地域来源、跳转来源、使用终端、某个URL访问量等相关信息。

  • 错误日志(Error Log):记录Nginx服务运行期间发生的错误信息和警告信息。通过错误日志,得到系统某个服务或server的性能瓶颈等信息。

log_format日志格式

官方说明:http://nginx.org/en/docs/http/ngx_http_log_module.html#log_format

nginx自带了一些变量,让我们能够作为日志输出格式进行配置,方便我们对用户的请求进行查询和统计。当然了,nginx其实默认的日志输出格式其实就已经把一些重要的请求参数保存到访问日志里面了,基本满足我们日常使用了,如果有需要可以根据下面的表单自定义配置所需要的日志格式。

参数 说明 示例
$remote_addr 客户端地址 211.28.65.253
$remote_user 客户端用户名称
$time_local 访问时间和时区 18/Jul/2012:17:00:01 +0800
$request 请求的URI和HTTP协议 “GET /article-10000.html HTTP/1.1”
$http_host 请求地址,即浏览器中你输入的地址(IP或域名) www.wang.com 192.168.100.100
$status HTTP请求状态 200
$upstream_status upstream状态 200
$body_bytes_sent 从服务端响应给客户端内容大小 1547
$http_referer url跳转来源, 防盗链、用户行为分析 https://www.baidu.com/
$http_user_agent 用户终端浏览器等信息 “Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; SV1; GTB7.0; .NET4.0C;
$ssl_protocol SSL协议版本 TLSv1
$ssl_cipher 交换数据中的算法 RC4-SHA
$upstream_addr 后台upstream的地址,即真正提供服务的主机地址 10.10.10.100:80
$request_time 整个请求的总时间 0.205
$upstream_response_time 请求过程中,upstream响应时间 0.002
$http_x_forwarded_for http请求携带的http信息 可用来表示 HTTP请求端真实IP 101.251.xxx.192, 100.97.xxx.187 [用户真实ip,proxy ip]
  • log_format 有一个默认的无需设置的 combined 日志格式,相当于apache 的 combined 日志格式,如下所示:

    1
    2
    3
    4
    5
    6
    7
    log_format combined '$remote_addr - $remote_user [$time_local] '
    ' "$request" $status $body_bytes_sent '
    ' "$http_referer" "$http_user_agent" ';


    # 使用默认 combined 格式记录日志:
    access_log logs/access.log combined;

access.log日志文件

  • 官方说明:http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log

  • access文件用于存放每个用户访问网站的请求日志,开发运维人员通过访问日志来分析用户的浏览器行为。默认情况下,nginx会在log目录下生成该文件,无需用户配置。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    [root@RockyLinux9 nginx]# cat conf/nginx.conf
    ...
    #error_log logs/error.log;
    #error_log logs/error.log notice;
    #error_log logs/error.log info;
    ...
    http {
    ...
    #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 logs/access.log main;
    ...
    server {
    ...
    #access_log logs/host.access.log main;
    }
    }
  • 我们可以在$nginx_home/conf/nginx.conf配置文件中对nginx请求日志进行配置。配置的格式为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
        access_log    <FILE>    <NAME>;
    关键字 日志文件 格式标签


    关键字:其中关键字error_log不能改变
    日志文件:可以指定任意存放日志的目录
    格式标签:给日志文件套用指定的日志格式


    其他语法:

    access_log off; #关闭access_log,即不记录访问日志
    access_log path [format [buffer=size [flush=time]] [if=condition]];
    access_log path format gzip[=level] [buffer=size] [flush=time] [if=condition];
    access_log syslog:server=address[,parameter=value] [format [if=condition]];

    说明:
    buffer=size #为存放访问日志的缓冲区大小
    flush=time #为缓冲区的日志刷到磁盘的时间
    gzip[=level] #表示压缩级别
    [if = condition] #表示其他条件

    作用域(参数的标签段位置) : http, server, location, if in location, limit_except
    • access_log是关键字,表示接下来的配置是关于access日志的配置
    • path为该日志文件的存储路径,后面还可以对日志输出格式、是否压缩、日志刷新时间等设置进行配置。
    • 可能有读者会留意到,默认用例在path后面写上了main,其实这里的main并不是什么关键字,而是nginx默认定义好的一个日志格式名称,我们可以在log_format中看到,nginx默认定义了一个名为main的日志输出格式。
  • 关闭访问日志的记录 只需要配置access_logoff即可

    1
    2
    3
    4
    location / {
    root html;
    access_log off;
    }
  • 自定义一个日志输出格式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 在http标签下新增一个log_format格式
    http {
    log_format mine_format '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"'
    '$upstream_addr $upstream_response_time $request_time ';
    }


    # 在server标签中应用定义新的access_log配置
    server {
    listen 9600;
    location / {
    root html;
    access_log logs/mine_access.log mine_format;
    }
    }
  • 使用nginx -s reload重新加载配置文件, 访问 9000后,访问 logs/mine_access.log

    1
    192.168.61.1 - - [30/Oct/2024:00:44:47 +0800] "GET /favicon.ico HTTP/1.1" 404 555 "http://fulsun.top:9600/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0" "-"- - 0.000 
  • 刷新时间的配置: nginx默认情况下对访问日志是实时记录的,其实一定程度上来说是会占用cpu资源的,当然了大部分站点其实访问量并不大,所以实时记录日志所带来的性能消耗是可以忽略的。如果说对于访问量大且对性能要求较高的站点,可能会希望通过优化日志的输出频率来达到减少IO的效果。

  • 配置完flush和buffer后,其实我们就相当于是有两个记录日志的节点了,一个是缓冲区满了,另外一个是到刷新日志的时间点了。缓冲区的存在使得nginx不需要针对每一个请求都做一次IO,可以节省一点系统资源。当然了,我们还可以开启gzip压缩(可选等级为1-9,级别越高压缩级别越高)来进一步减轻磁盘压力。

    1
    access_log logs/mine_access.gz mine_format gzip buffer=32k flush=5s;

error_log 指令

官方说明:

open_log_file_cache指令

参考资料:http://nginx.org/en/docs/http/ngx_http_log_module.html

对于每一条日志记录,都将是先打开文件,再写入日志,然后关闭。可以使用 open_log_file_cache 来设置日志文件缓存(默认是 off)。

1
2
3
4
5
6
7
语法格式:   open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
默认值: open_log_file_cache off;
作用域: http, server, location

# 设置缓存最多缓存1000个日志文件描述符,20s内如果缓存中的日志文件描述符至少被被访问2次,才不会被缓存关闭。每隔1分钟检查缓存中的文件描述符的文件名是否还存在。
eg:open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
  • max:设置缓存中的最大文件描述符数量,如果缓存被占满,采用LRU算法将描述符关闭。
  • inactive:设置存活时间,默认是10s
  • min_uses:设置在inactive时间段内,日志文件最少使用多少次后,该日志文件描述符记入缓存中,默认是1次
  • valid:设置检查频率,默认60s
  • off:禁用缓存

log_not_found 指令

是否在 error_log 中记录不存在的错误。默认是。

1
2
3
4
5
6
7
8
语法:
log_not_found on | off;

默认值:
log_not_found on;

配置段:
http, server, location

log_subrequest 指令

是否在 access_log 中记录子请求的访问日志。默认不记录。

1
2
3
4
5
6
7
8
语法:
log_subrequest on | off;

默认值:
log_subrequest off;

配置段:
http, server, location

rewrite_log 指令

由 ngx_http_rewrite_module 模块提供的。用来记录重写日志的。对于调试重写规则建议开启。启用时将在 error log 中记录 notice 级别的重写日志。

1
2
3
4
5
6
7
8
语法:
rewrite_log on | off;

默认值:
rewrite_log off;

配置段:
http, server, location, if

Nginx日志运维优化

按指定时间分割

nginx默认是不会进行日志文件的分割操作的,也就是所有访问日志会一直往access.log文件里面追加,时间一长的话这个文件就会变得很大,而且运维人员在查看当天文件的也很不方便。所以一般来说,我们都会选择按日对日志文件进行切割。
常见的处理方案有2种:(1)直接在nginx配置文件中配置(2)通过linux的crontab配置定时任务,自己手动写一下定时处理的脚本。

  • 在nginx配置文件中配置:

    • 这里需要注意的是,error_log日志文件可能会由于nginx版本的原因,无法使用变量来动态切割每天的日志,所以感觉这种方法并不完全适用。
    • 在Nginx配置文件中,可以使用$time_local$time_iso8601变量来获取当前时间,然后将其作为日志文件名的一部分。所以我们可以这样配置我们的日志文件名。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 在http标签块中按照我们需要的日期格式yyyy-MM-dd定义变量$logdate

    http {
    ...
    map $time_iso8601 $logdate {
    '~^(?<ymd>\d{4}-\d{2}-\d{2})' $ymd;
    default 'date-not-found';
    }
    ...
    }

    # 在对应的站点中使用变量来动态生成日志文件

    location / {
    root html;
    access_log /opt/nginx/logs/mine_access.$logdate.log mine_format;
    error_log /opt/nginx/logs/mine_error.log warn;
    }
  • 结合crontab定时任务来完成日志的切割效果(更推荐)

    • 根据年/月生成对应的目录,然后把日志文件重命名后放入到对应月份的目录中,最后再通过nginx -s reopen命令重新启动日志

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      # nginx_log_split.sh
      #!/bin/bash
      nginx_home=/opt/nginx/
      nginx_log_path=${nginx_home}logs/
      current_date1=$(date +%Y-%m-%d)
      access_log_file_name=access.log
      error_log_file_name=error.log

      history_file_path=${nginx_home}logs/history_log/$(date +%Y)/$(date +%m)


      # check if the nginx server alive
      if [ -e ${nginx_log_path}nginx.pid ];then

      # create log folder for nginx log file
      if [ ! -e ${history_file_path} ];then
      mkdir -p ${history_file_path}
      echo "$(date) create folder success"
      fi


      # rename the log file with current date
      if [ -e $nginx_log_path$access_log_file_name ];then
      mv ${nginx_log_path}${access_log_file_name} ${history_file_path}/access-${current_date1}.log
      echo "$(date) rename access.log successfully"
      else
      echo "$(date) access.log file no exist,skip"
      fi


      if [ -e $nginx_log_path$error_log_file_name ];then
      mv ${nginx_log_path}${error_log_file_name} ${history_file_path}/error-${current_date1}.log
      echo "$(date) rename error.log successfully"
      else
      echo "$(date) error.log file no exist,skip"
      fi

      # reopen the nginx server log
      ${nginx_home}/sbin/nginx -s reopen
      echo "$(date) reload log file success"

      else
      echo "$(date) nginx server is close,skip"
      fi
    • 配置crontab定时器
      1
      2
      3
      4
      # 给脚本授权
      chmod 774 nginx_log_split.sh
      # 让系统每天晚上23:59分的时候跑一次我们的脚本,生成分割当天的日志文件
      59 23 * * * /opt/nginx/logs/nginx_split_log.sh > /opt/nginx/logs/history_log/execute.log 2>&1

按模块区分访问日志

对于站点较多,且都部署在同一台nginx服务器(或者同一个nginx集群)的企业,一般我们会习惯性的将不同站点的日志分开管理,避免所有的站点日志都输出在同一个access.log文件中,导致后续统计或者排查问题的时候容易混淆。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 9600;
location / {
root html;
access_log /opt/nginx/logs/mine_access1.log mine_format;
error_log /opt/nginx/logs/mine_error.log warn;
}
}

server {
listen 9601;
location / {
root html;
access_log /opt/nginx/logs/mine_access2.log mine_format;
}
}

日志轮转、压缩与删除

  • 检查并安装logrotate

    1
    2
    3
    4
    5
    [root@RockyLinux9 nginx]# whereis logrotate
    logrotate: /usr/sbin/logrotate /usr/share/man/man8/logrotate.8.gz

    # 安装
    [root@RockyLinux9 nginx]# dnf install -y logrotate
  • 编写nginx的logrotate配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@RockyLinux9 nginx]# cat /etc/logrotate.d/nginx
    /usr/local/nginx/logs/*.log {
    daily # 每天轮转
    missingok # 如果日志文件丢失,不报错
    rotate 7
    # 保留7个备份
    compress # 使用 gzip 压缩旧日志文件
    delaycompress # 延迟压缩,直到下一次轮转周期
    notifempty # 如果日志文件为空,不轮转
    create 640 nginx nginx
    # 创建新日志文件,并设置权限和所有权
    sharedscripts # 如果有多个日志文件,只运行一次 postrotate 脚本
    postrotate
    /usr/sbin/nginx -s reload > /dev/null # 或者使用 systemctl reload nginx
    endscript
    }
  • 测试logrotate配置文件

    1
    2
    # 使用-d选项来测试配置文件是否正确,执行后显示操作,但不会实际进行任何修改。
    [root@RockyLinux9 ~]# logrotate -d /etc/logrotate.d/nginx
  • 手动运行logrotate, 测试配置文件正确后,可以手动运行logrotate

    1
    [root@RockyLinux9 ~]# logrotate /etc/logrotate.d/nginx
  • 检查cron服务

    1
    2
    3
    4
    5
    [root@RockyLinux9 ~]# which crond
    /usr/sbin/crond
    # 若没有,请安装
    [root@RockyLinux9 ~]# dnf install -y cronie
    [root@RockyLinux9 ~]# systemctl enable crond --now
  • 编写cron脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [root@RockyLinux9 ~]# cat /etc/cron.daily/logrotate
    #!/bin/bash

    # 调用 logrotate 命令
    /usr/sbin/logrotate /etc/logrotate.conf

    # 检查 logrotate 的退出状态
    EXITVALUE=$?
    if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
    fi
    exit 0

    [root@RockyLinux9 ~]# chmod +x /etc/cron.daily/logrotate
  • 配置计划任务(可选)

    1
    2
    3
    [root@RockyLinux9 ~]# crontab -e
    # 添加内容,每天0点执行logrotate
    0 0 * * * /usr/sbin/logrotate /etc/logrotate.d/nginx
  • 自定义bash脚本进行日志备份与删除(可选)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@RockyLinux9 ~]# cat /usr/local/nginx/logs/log_backup.sh
    #!/bin/bash

    # 定义Nginx日志目录
    base_path='/usr/local/nginx/logs'

    # 移动日志文件
    mv $base_path/access.log $base_path/access-$(date -d yesterday +"%Y%m%d").log
    mv $base_path/error.log $base_path/error-$(date -d yesterday +"%Y%m%d").log

    # 发送USR1信号给Nginx
    kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`

    # 找到日志目录下超过7天的log文件并删除
    find $base_path/*.log -type f -mtime +7 -exec rm -rf {} \;
  • 配置bash的crontab定时任务(可选)

    1
    2
    3
    [root@RockyLinux9 ~]# crontab -e
    # 添加内容,每天0点执行log_backup.sh
    0 0 * * * /bin/bash /usr/local/nginx/logs/log_backup.sh

日志分析

Nginx日志分析是管理和维护Nginx服务器的重要部分。Nginx的访问日志(access log)和错误日志(error log)提供了关于服务器性能、用户访问模式以及任何潜在问题的关键信息。分析步骤如下:

访问日志分析

  • 了解Nginx访问日志的格式。在Nginx的配置文件(/etc/nginx/nginx.conf/usr/local/nginx/conf/nginx.conf)中的log_format指令中找到。

  • 使用基本工具

    • grep:用于搜索特定的字符串或模式。
    • awk 和 sed:用于文本处理和转换。
    • sort 和 uniq:用于排序和去重。
  • 分析示例

    1
    2
    3
    4
    5
    6
    7
    8
    # 查看最频繁的请求:
    cat access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head -n 10

    # 这将显示按数量排序的最常见的请求路径(URL)。查看特定IP的请求:
    grep '192.168.61.1' access.log

    # 分析用户代理:这将显示最常见的用户代理(浏览器和其他客户端)。
    cat access.log | awk '{print $11}' | sort | uniq -c | sort -nr | head -n 10

错误日志分析

  • 查看错误日志:错误日志通常包含关于服务器配置错误、权限问题、内部错误等的详细信息。你可以使用cat、tail、grep等工具来查看和分析它。

  • 分析示例

    1
    2
    3
    4
    5
    # 查看最近的错误:
    tail -n 10 error.log

    # 搜索特定错误或警告:
    grep 'error' error.log
  • 使用专门的日志分析工具: 除了基本工具外,还有许多专门的日志分析工具可以更深入地分析Nginx日志。这些工具通常提供图形界面、实时分析、报告和警报等功能。例如:

    • GoAccess:一个快速、实时的Web日志分析器,可以生成HTML报告。
    • ELK Stack(Elasticsearch、Logstash和Kibana):一个强大的日志分析平台,可以处理和分析各种类型的日志数据。

安全性

Nginx日志的安全性配置涉及多个方面,以确保日志文件的完整性和保密性。以下是Nginx日志安全性配置:

  • 限制日志文件的访问权限:

    • 确保Nginx日志文件(如access.log和error.log)的访问权限受到限制,只允许必要的系统用户(如Nginx运行的用户)进行读写操作。
    • 使用chmod命令设置适当的文件权限,例如chmod 640 /usr/local/nginx/logs/access.log,确保只有所有者(Nginx运行的用户)和特定的组(如nginx组)可以读写日志文件。
  • 加密传输日志文件:

    • 如果需要将Nginx日志文件传输到远程服务器进行分析或备份,请确保使用加密传输方式(如SFTP、SCP或rsync over SSH)来传输日志文件,以防止数据在传输过程中被窃取或篡改。
  • 使用安全的日志格式:

    • 在Nginx配置中,使用安全的日志格式,避免在日志中记录敏感信息(如密码、密钥等)。
    • 使用log_format指令自定义日志格式,确保只记录必要的信息,并避免记录过多的敏感数据。
  • 监控和审计:

    • 定期检查和审计Nginx日志文件,以发现任何异常或潜在的安全威胁。
  • 物理安全:

    • 确保存储Nginx日志文件的服务器或设备位于安全的物理位置,以防止未经授权的访问或窃取。
    • 限制对服务器或设备的物理访问权限,确保只有授权人员能够接触和访问日志文件。
  • 备份和恢复策略:

    • 定期备份Nginx日志文件,以防止数据丢失或损坏。
    • 制定恢复策略,以便在需要时能够迅速恢复丢失的日志文件或数据。
    • 请根据具体环境和需求或采取其他安全措施来确保Nginx日志的安全性。