百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Nginx 解决error.log和access.log日志的改善总结

wxin55 2024-11-24 22:42 8 浏览 0 评论

1. 介绍

自从了解了error和access日志的重要性,并且学会阅读相关log文档之后。

通过调整nginx配置,解决error中的大量报错提示。通过过滤js等静态资源减少大量的access日志记录内容。

同时,经过使用阿里云安全组封禁大量国外ip地址的访问。我的access.log文件和error.log的尺寸得到了有效压缩管理。

access.log 从原先的12m左右的的文件,变成了现在的400KB。记录的访问数据也清晰了很多。

error.log也从原先的8M左右的文件,变成了现在的1KB,或者300Bytes的文件。甚至有时候还是0 Bytes。

日志文件的减少,也降低了服务器的IO读取的性能开支。可以将更多的内存资源用于处理正常的请求。

可以说是一个双赢的结局。

本篇作为一个回顾总结内容。具体的error文件内容配置可以参考:https://zinyan.com/?p=450 ,https://zinyan.com/?p=453。access.log的文件配置可以参考:https://zinyan.com/?p=445,https://zinyan.com/?p=444,以及爬虫屏蔽过滤返回444:https://zinyan.com/?p=454

2. 总结

现在error文件中,剩下的记录主要就是SSL: error:141CF06C:SSL routines:tls_parse_ctos_key_share:bad key share异常了。

处理这个异常,可以通过封禁ip地址的访问,也可以不用在意。

剩下的就是access.log文件了。

当我们配置UserAgent请求中带有爬虫关键字的请求直接返回444之后,例如:

Status:444,Bytes:0,IP:185.117.225.171,Time:[2022-11-24T04:18:36+08:00],Host:"zinyan.com",Request:"GET /robots.txt HTTP/1.1",Referer:"-",UserAgent:"python-requests/2.28.1"
Status:444,Bytes:0,IP:51.77.247.119,Time:[2022-11-24T04:57:39+08:00],Host:"47.101.47.241",Request:"POST /phpinfo HTTP/1.1",Referer:"-",UserAgent:"curl/7.64.0"

对比不同日期的access.log 可以发现,爬虫请的数量在不断变少。

因为当爬虫多次请求得到结果是444后,会渐渐降低我们网站的爬取级别,最终犹豫得不到数据而放弃爬取。

但是,也会有一些新增加的爬虫需要我们注意,并添加到过滤条件中。

而且也有一些过滤无法生效的情况,需要我们随时进行一些配置的修改例如:

Status:404,Bytes:177,IP:18.195.96.149,Time:[2022-11-24T04:58:10+08:00],Host:"zinyan.com",Request:"GET /s/.git/HEAD HTTP/1.1",Referer:"-",UserAgent:"RepoLookoutBot/1.0.0 (abuse reports to abuse@repo-lookout.org)"Status:404,Bytes:186,IP:18.195.96.149,Time:[2022-11-24T04:58:42+08:00],Host:"zinyan.com",Request:"GET /categories/.git/HEAD HTTP/1.1",Referer:"-",UserAgent:"RepoLookoutBot/1.0.0 (abuse reports to abuse@repo-lookout.org)"

我们需要新增:RepoLookoutBot 爬虫工具的过滤。还有通过CensysInspect 工具:

Status:400,Bytes:248,IP:167.248.133.62,Time:[2022-11-24T07:17:24+08:00],Host:"47.101.47.241:443",Request:"GET / HTTP/1.1",Referer:"-",UserAgent:"Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)"

同时在屏蔽过程中出现了有些能够屏蔽而有些无法屏蔽的问题:

Status:444,Bytes:0,IP:167.248.133.62,Time:[2022-11-24T07:17:20+08:00],Host:"47.101.47.241:443",Request:"GET / HTTP/1.1",Referer:"-",UserAgent:"-"
Status:400,Bytes:248,IP:167.248.133.62,Time:[2022-11-24T07:17:23+08:00],Host:"47.101.47.241:443",Request:"GET / HTTP/1.1",Referer:"-",UserAgent:"-"

两种访问从access.log中看到,可以说完全一样。但是却一个返回444,一个返回400 。返回444说明我的nginx过滤规则生效了。而400说明没有生效。

同时,还需要添加上Host为空的访问,将它们进行过滤,例如:

Status:400,Bytes:150,IP:167.248.133.62,Time:[2022-11-24T07:17:24+08:00],Host:"-",Request:"PRI * HTTP/2.0",Referer:"-",UserAgent:"-"

同时,我们也可以检查静态资源是否全部都过滤的情况,例如我的资源用到了jfif,webp文件。我就需要添加到过滤规则中去。

PS:可能存在部分的过滤失败,但是整体上来说。提高了网站的安全性,降低了大量的非法请求。

在收获上来说,这一些配置的付出是值得的。

3. 改进 nginx过滤规则

基于发现的问题,再次改进access的过滤规则。以及非法请求返回444的判断逻辑。

3.1 修改access_log 记录

在/etc/nginx/nginx.conf文件中修改如下:


 http {
    ...
     log_format  main  'Status:$status,Bytes:$body_bytes_sent,IP:$remote_addr,Time:[$time_iso8601],Host:"$http_host",Request:"$request",Referer:"$http_referer",UserAgent:"$http_user_agent"';
     map $uri $zinyanloggable {
         default 1;
         ~^(.*\.(ico|gif|jpg|jpeg|png|bmp|swf|js|css|svg|woff|ttf|jfif|webp)$) 0;
     }
     access_log  /var/log/nginx/access.log  main if=$zinyanloggable;
     ...
 }

这样,access文件中就不会添加ico|gif|jpg|jpeg|png|bmp|swf|js|css|svg|woff|ttf|jfif|webp 作为后缀结尾的日志内容了。

3.2 map实现爬虫屏蔽

老版本写法为:

 server{
     ...
     if ($http_user_agent ~ ^$){
         return 444;
     }
     if ($http_user_agent ~* "scrapy|python|curl|java|wget|httpclient|okhttp|MJ12bot|Expanse|ahrefsbot|seznambot|serpstatbot|sindresorhus|zgrab"){
         return 444;
     }
     ...
 }

效率比较低,如果是多个server那么得写多遍。所以修改为map的规则进行

但是如果改为map的话,需要在http{}之中先创建map规则,然后再到server中使用就可以了。示例如下:

 http {
    ...
    # 创建一个屏蔽规则zinyanUA,而它的取值从$http_user_agent 中获取。
     map $http_user_agent $zinyanUA {
         default 0;
         ~*(scrapy|python|curl|java|wget|httpclient|okhttp|MJ12bot|Expanse|ahrefsbot|seznambot|serpstatbot|sindresorhus|zgrab|censys|RepoLookoutBot) 1;
         ~ ^$ 1;
     }
     ...
 }

语法解释:

~ 表示正则表达式对大小写敏感。

~* 表示正则表达式对大小写不敏感。

后面跟着的内容就是正则表达式了

在正则表达式中^代表开头,$代表结尾,^$就代表开头和结尾中间没有字符。也就是字符串为空的。

配置完毕后,在需要的server{}段中添加:

server{
     ...
     if ($zinyanUA){
         return 444;
     }
     ...
 }

因为在nginx 的if判断中,参数值0或者为空字符串,会判断为false,其他判断为true。

而我在上面创建的map对象中,规范了,如果匹配就返回1,不匹配返回0。所以if ($zinyanUA)为true的就是需要返回444的请求了。

nginx: [emerg] unknown directive "if($http_host)" in /etc/nginx/conf.d/zinyan.conf:49 nginx: configuration file /etc/nginx/nginx.conf test failed

如果你出现了这个if命名错误的提示,并不是所谓的缺乏if命名的依赖库,而是Nginx中的if命名和括号中间需要有空格。

nginx -t 检测通过后,通过service nginx reload刷新配置就可以生效了。

PS:如果实在过滤不了的,建议直接封IP地址,特别是国外的访问。国内也有不少的攻击



相关推荐

ES6中 Promise的使用场景?(es6promise用法例子)

一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...

JavaScript 对 Promise 并发的处理方法

Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...

Promise的九大方法(promise的实例方法)

1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...

360前端一面~面试题解析(360前端开发面试题)

1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...

前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?

Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...

最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式

看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...

前端分享-Promise可以中途取消啦(promise可以取消吗)

传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...

手写 Promise(手写输入法 中文)

前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...

什么是 Promise.allSettled()!新手老手都要会?

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...

前端面试-关于Promise解析与高频面试题示范

Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...

宇宙厂:为什么前端离不开 Promise.withResolvers() ?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...

Promise 新增了一个超实用的 API!

在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...

一次搞懂 Promise 异步处理(promise 异步顺序执行)

PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...

Promise 核心机制详解(promise机制的实现原理)

一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...

javascript——Promise(js实现promise)

1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...

取消回复欢迎 发表评论: