Apache访问日志怎么配才查得清问题?LogFormat、CustomLog与CDN真实IP实战
本文目录
- Apache的访问日志和错误日志分别记的是什么?
- common和combined格式到底差在哪,该用哪个?
- 怎么自定义日志格式,多记几个有用的字段?
- 不想把图片、健康检查这些噪音也记进来,怎么过滤?
- 多个站点的日志怎么分开记?
- 站点挂在Cloudflare后面,日志里全是CDN的IP怎么办?
- 日志越积越大,怎么轮转才不丢数据、不用重启Apache?
- 配置访问日志时还有哪些坑和安全注意?
- 常见问题解答
- access log和error log我是不是只看一个就行?
- 我用的是宝塔面板或者一键环境,还需要自己配日志吗?
- 记 %D响应耗时会拖慢服务器吗?
- mod_remoteip配了之后,安全规则和访问控制会用真实IP吗?
- 日志轮转到底该用rotatelogs还是logrotate?
- 权威参考资料
站点出了问题想查日志,结果要么日志里全是图片、健康检查的噪音淹没了真正有用的行,要么挂了CDN之后每条记录的IP都是Cloudflare的、根本看不到真实访客,要么日志文件涨到几十G把磁盘撑爆、Apache直接写不进去整站挂掉。这些都不是日志分析的问题,而是Apache日志压根没配明白。
这篇只讲Apache这一层的日志配置:访问日志和错误日志分别记什么、common与combined格式怎么选、怎么自定义格式多记响应耗时这类有用字段、怎么用条件日志把噪音过滤掉、多站点日志怎么分开、挂了CDN怎么用mod_remoteip记回真实IP、日志怎么轮转才不丢数据又不用重启。把源头配对,后面拿日志做任何分析才有意义。
日志是服务器的黑匣子。站点慢了、有人在刷接口、某个页面老报错、搜索引擎抓取异常——这些问题的答案大多藏在日志里。但黑匣子能不能用,取决于它当初记没记对东西。保哥见过太多站点,真出事了打开日志一看,要么关键信息根本没记、要么有用的行被海量噪音埋掉、要么IP全是代理的假地址,黑匣子等于白装。
这篇要讲的,是Apache日志的“配置”这一层——记什么、用什么格式记、记到哪、怎么过滤、挂了CDN怎么记真实来访、文件大了怎么轮转。注意,这和“拿到日志之后怎么分析SEO、怎么揪爬虫”是两码事,那是日志分析做SEO那篇的活儿;也和“Linux系统层面怎么用logrotate、journald管所有服务的日志不爆盘”不同,那是服务器日志管理那篇的范围。本篇专攻Apache服务器自己这一层的日志怎么配,把源头配对了,上面那两件事才有干净的原料。
Apache的访问日志和错误日志分别记的是什么?
动手配置前,先分清Apache的两类日志,因为它们由不同的指令控制、记录的东西和用途都不一样,常被混为一谈。
第一类是访问日志(access log)。它记的是“谁、什么时候、请求了什么、服务器返回了什么”——每来一个请求记一行,包含来访IP、时间、请求的方法和地址、返回的状态码、响应大小等。它由mod_log_config模块提供的CustomLog和LogFormat两个指令控制,是流量分析、安全排查、SEO抓取分析的主要原料。
第二类是错误日志(error log)。它记的是“服务器运行中出了什么岔子”——PHP报错、模块加载失败、权限不对、配置警告、请求被拒等诊断信息。它由ErrorLog指令指定位置、由LogLevel指令控制记录的详细程度。出问题排障时,错误日志通常是第一个要看的地方,官方也称它是最重要的诊断文件。
两者的关键区别:访问日志是“正常业务流水账”,每个请求都记;错误日志是“异常报警”,出问题才记。配置时也分开设——访问日志关心“记哪些字段、过滤哪些噪音”,错误日志关心“记到多详细的级别”。这篇以访问日志为主线,错误日志的关键是LogLevel别设太啰嗦也别太简略,下文会捎带说。先记住这个二分,后面就不会把两套指令搞混。
common和combined格式到底差在哪,该用哪个?
访问日志长什么样,取决于LogFormat定义的格式。Apache预置了两个最常用的格式昵称:common和combined。先看它们的定义。
# 通用日志格式 Common Log Format
LogFormat "%h %l %u %t \"%r\" %>s %b" common
# 组合日志格式 Combined Log Format
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined那一串百分号是格式符,每个代表一个字段。逐个拆开看最常见的这几个:%h是来访的主机名或IP;%l是远程登录名(几乎总是一个短横线,没人用);%u是HTTP认证的用户名;%t是请求到达的时间;%r是请求行的第一行(方法、地址、协议,比如GET /index.html HTTP/1.1);%>s是最终返回给客户端的状态码(200、404、500那个);%b是响应体的字节数。
combined比common多了两个字段:%{Referer}i是来源页(访客从哪个链接点过来的),%{User-Agent}i是客户端标识(浏览器型号、或者是哪家搜索引擎的爬虫)。
该用哪个?几乎所有场景都该用combined,没有理由用common。原因是那多出来的两个字段太有用了:Referer能看出流量来源、能发现盗链;User-Agent能区分真人和爬虫、能识别是Googlebot还是别的bot在抓你的站。做SEO、做安全、做流量分析,全靠这两个字段。common砍掉它们等于自废武功,除非你有极特殊的精简需求,否则一律combined。下面要讲的自定义格式,也都是在combined的基础上再加料,把这两个有用字段保住的同时再补几个生产环境真正用得上的维度。
怎么自定义日志格式,多记几个有用的字段?
combined是个好起点,但生产环境往往还想多记几个字段,这就要自己写LogFormat。自定义其实很简单:把格式符按需拼起来,给它起个昵称,CustomLog引用这个昵称即可。看一个保哥常用的增强格式。
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D %v" myformat
CustomLog "/var/log/httpd/access_log" myformat这里在combined的基础上加了两个字段。%D是处理这个请求花了多少微秒——也就是响应耗时。这个字段极其有用:站点变慢时,按 %D排序就能立刻找出哪些请求是慢请求,是排查性能问题的利器。%v是处理请求的虚拟主机名,一台服务器跑多个站时,靠它区分这条日志属于哪个站。
还有几个值得知道的字段,按需取用:%a是客户端IP(和 %h的区别在于挂了代理时配合mod_remoteip取真实IP,下文细说);%I和 %O是请求和响应的总字节数(含头部,统计带宽用,需要mod_logio模块);%{Host}i是访客请求的域名;%T是响应耗时但单位是秒(%D是微秒,按需选一个);%p是服务端口。
原则是按你真正要分析的目标来加字段,别一股脑全塞进去。要查性能就加 %D,多站就加 %v,关心带宽就加 %I %O。字段加得越多每行越长、日志涨得越快,所以是“按需”而不是“越全越好”。定好一个适合自己站点的格式,全站统一用,后面分析才省事。
不想把图片、健康检查这些噪音也记进来,怎么过滤?
这是访问日志配置里最实用的一招,也是新手最不知道的功能:条件日志。默认情况下Apache把每个请求都记一行,包括每张图片、每个CSS/JS、每次负载均衡的健康检查探测。结果就是真正有价值的页面请求被海量静态资源和探测请求淹没,日志又大又难看。
解法是用SetEnvIf给特定请求打个标记,再让CustomLog用env= 条件决定记不记。看一个典型配置。
# 给不想记的请求打上 dontlog 标记
SetEnvIf Request_URI "\.(gif|jpg|jpeg|png|css|js|ico|woff2?)$" dontlog
SetEnvIf Request_URI "^/health$" dontlog
SetEnvIf Remote_Addr "^10\.0\.0\.5$" dontlog
# 只记没有 dontlog 标记的请求
CustomLog "/var/log/httpd/access_log" combined env=!dontlog逻辑是这样:前面几条SetEnvIf判断如果请求地址是图片、静态资源,或者是 /health健康检查路径,或者来自某个内部监控IP,就给这个请求设一个叫dontlog的环境变量。最后那行CustomLog的env=!dontlog意思是“只记录没有dontlog标记的请求”,于是图片、健康检查、内部探测全被排除,日志里只剩真正的页面访问,干净多了。
这招的价值不只是好看。日志小了,分析快了,磁盘省了,真出事时翻日志一眼就能看到关键行而不用在噪音里大海捞针。负载均衡的健康检查每几秒一次、CDN的回源探测、监控系统的探活,这些机器流量不过滤掉,能占到日志量的一大半。把它们挡在外面,是性价比极高的一步。
反过来也有“只记某类请求”的需求,比如只想单独记录所有404、或者只记某个接口的访问。同样用SetEnvIf打标记,CustomLog用env=(不带感叹号)就是“只记有这个标记的”。一正一反两个用法,配合起来能把日志切得很精细。
多个站点的日志怎么分开记?
一台Apache上跑好几个站是常态,这时日志最好分开,别让所有站的访问混在一个文件里。有两种思路。
第一种是每个虚拟主机各记各的,最清晰。在每个VirtualHost块里单独写一条CustomLog,指向不同的文件。
<VirtualHost *:443>
ServerName shop.example.com
CustomLog "/var/log/httpd/shop_access_log" combined
ErrorLog "/var/log/httpd/shop_error_log"
</VirtualHost>
<VirtualHost *:443>
ServerName blog.example.com
CustomLog "/var/log/httpd/blog_access_log" combined
ErrorLog "/var/log/httpd/blog_error_log"
</VirtualHost>这样shop和blog的访问日志、错误日志各自独立,查某个站的问题直接看那个站的文件,互不干扰。站点不多时,这是最推荐的方式,一目了然。
第二种是所有站记到一个大文件,但在格式里加上 %v(虚拟主机名)字段,事后再按 %v把大文件拆成各站的小文件。这种方式的好处是只有一个日志文件、轮转和管理简单;坏处是实时查看时得自己按域名筛。站点数量很多(几十上百个)时,统一记录加事后拆分反而更好管,因为不用维护几十条CustomLog、几十个文件的轮转。两种各有适用场景,按站点规模选。
提醒一点:错误日志也一样可以按vhost分开(每个VirtualHost里写ErrorLog)。排障时能直接定位到出错的那个站,比在一个混合错误日志里翻要快得多。访问日志和错误日志都分站记,是多站环境里很值的一点配置投入。
站点挂在Cloudflare后面,日志里全是CDN的IP怎么办?
这是挂了CDN或反向代理之后必踩的坑,也是本篇要重点讲的一个配置点。现象是:你站点前面套了Cloudflare(或者前面有台Nginx做反代、有负载均衡器),打开访问日志一看,%h记录的来访IP全是Cloudflare那几个回源IP,真实访客的IP完全看不到。
原因是请求不是访客直连你的Apache的,而是先到Cloudflare、再由Cloudflare转发到你的源站。从Apache的角度,连接它的就是Cloudflare,所以 %h记的是Cloudflare的IP。真实访客的IP被Cloudflare放在了一个叫X-Forwarded-For的请求头里。
解法是启用mod_remoteip模块,告诉Apache “真实IP在X-Forwarded-For头里,从那儿取”。配置如下。
RemoteIPHeader X-Forwarded-For
# 信任 Cloudflare 的回源 IP 段(示例,需用官方公布的完整列表)
RemoteIPTrustedProxy 103.21.244.0/22
RemoteIPTrustedProxy 103.22.200.0/22
RemoteIPTrustedProxy 173.245.48.0/20RemoteIPHeader X-Forwarded-For声明真实IP从这个头取。RemoteIPTrustedProxy列出你信任的代理IP段——这步至关重要,安全相关。只有来自这些受信代理的X-Forwarded-For才会被采信,从别处伪造的X-Forwarded-For头会被忽略。如果不限定受信代理,任何人都能伪造这个头来冒充别的IP,那就出大问题了。所以一定要填Cloudflare(或你的反代/负载均衡器)官方公布的真实IP段。
配好之后还有一步容易漏:mod_remoteip替换的是 %a取到的客户端IP,而combined格式里用的是 %h。所以日志格式里要把 %h换成 %a,或者直接用 %a,真实访客IP才会出现在日志里。
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" cdnlog
CustomLog "/var/log/httpd/access_log" cdnlog不做这步轮转影响SEO分析和安全排查极大:你以为在分析访客行为,其实记的全是CDN的几个IP,统计出来的独立访客数、地域分布、可疑IP全是错的。挂了CDN必配mod_remoteip,这是保哥反复提醒的一条。
日志越积越大,怎么轮转才不丢数据、不用重启Apache?
访问日志只增不减,一个有点流量的站,access_log几天就能涨到几个G。日志轮转(把当前日志切走、开新文件)是必须做的,否则迟早把磁盘撑满。从Apache这一层看,轮转有两条路,各有讲究。
第一条是Apache自带的rotatelogs,走管道日志(piped log)。做法是CustomLog不直接写文件,而是把日志通过管道交给rotatelogs程序,由它负责按时间或大小切割。
CustomLog "|/usr/bin/rotatelogs -l /var/log/httpd/access_log.%Y%m%d 86400" combined这行的意思是:日志交给rotatelogs,每86400秒(一天)切一个新文件,文件名按日期带后缀。rotatelogs的最大好处是切割时完全不用重启或重载Apache,它自己开新文件继续写,旧文件落地,丝毫不影响服务,也不丢日志。Apache还会在管道进程意外退出时自动把它重启,比较省心。这是Apache原生、最不容易出错的轮转方式。
第二条是用系统的logrotate工具(Linux上通用的日志轮转方案)。它的工作方式是定期把日志文件改名、压缩,然后要让Apache知道“该写新文件了”。这里有个经典大坑:logrotate把access_log改名后,Apache的进程还攥着原来那个文件的句柄继续往里写(写进了改名后的旧文件),新文件一直是空的。
破解这个坑有两种正确姿势。一是在logrotate配置里加postrotate脚本,轮转后给Apache发一个优雅重载信号(reload,不是重启),让它重新打开日志文件、写到新文件里。二是用copytruncate模式——先把日志复制一份,再把原文件清空(truncate)而不是改名,这样Apache的句柄还指向同一个文件,不用通知它,但缺点是复制和清空之间有极小概率丢几行日志。生产上更推荐postrotate + reload这种无损方式。
这一层和操作系统层的日志管理是衔接的:Apache负责把日志写出来、或交给rotatelogs切,系统层的logrotate、journald、监控告警则负责全局的归档、压缩、清理和报警,这部分保哥在前面提到的服务器日志管理那篇里有系统讲解,这里只聚焦Apache侧怎么配合不出错。两层配好,日志才能既留得住、查得到,又不至于把磁盘悄悄撑爆。
配置访问日志时还有哪些坑和安全注意?
最后把Apache日志配置里的坑和安全注意点集中列一下,照着躲。
日志目录权限是安全红线:Apache官方明确警告,任何能往日志目录写文件的用户,都可能借此拿到Apache主进程的权限(通常是root)。所以日志目录绝不能给普通用户写权限,存放日志的目录属主和权限要收紧,这是个容易被忽视但后果严重的安全点。
别把敏感信息记进日志:%r记的是完整请求行,如果你的站把密码、token、密钥放在URL查询串里(本就不该这么干),那它们会明晃晃地记进访问日志,谁能看日志谁就拿到了。敏感参数别走URL,万一历史遗留有这种设计,要么改造、要么在日志里把对应字段过滤掉。日志的安全和整个服务器的加固是一体的,更系统的加固清单可以看Apache安全加固那篇。
磁盘写满日志会拖垮整站:如果日志把磁盘写满了,Apache写不进日志,很多情况下会导致请求处理失败甚至服务异常。所以一定要配轮转加清理,并监控磁盘使用率,别等满了才发现。这也是为什么前面那么强调轮转。
BufferedLogs是性能与实时性的权衡:Apache有个BufferedLogs On选项,把日志先攒在内存里、攒够一批再写盘,能减少磁盘IO、对高并发站点的性能有帮助。代价是日志不是实时落盘,崩溃时可能丢最后一小段。流量很大、且不要求日志秒级实时的站可以开;要实时排障的别开。Apache整体性能怎么调,可以看Apache性能调优那篇。
日志里可能有恶意构造的内容:User-Agent、Referer这些字段是客户端可控的,恶意访客可能塞入控制字符、转义序列甚至攻击载荷。直接用cat看原始日志、或把日志喂给不设防的处理脚本时要当心,别被日志里的内容反过来坑了。处理日志时做好转义和清洗。
错误日志的LogLevel别走极端:LogLevel设太低(比如只记error以上)会漏掉有用的警告线索,设太高(debug)会刷屏且拖性能。生产上一般warn或info比较平衡,需要排查特定模块时可以临时给那个模块单独调高(比如LogLevel warn rewrite:trace3单独看重写规则)。
常见问题解答
access log和error log我是不是只看一个就行?
不行,两个都要,而且排查不同问题看不同的日志。访问日志记的是每一个请求的流水——谁来了、请求了什么、返回了什么状态码、花了多久,它回答的是流量类、行为类、状态码异常类的问题,比如“是不是有人在刷我的接口”“为什么404这么多”“哪些请求特别慢”“Googlebot都抓了哪些页面”。错误日志记的是服务器运行中的异常和诊断信息,比如PHP报错、模块加载失败、配置警告、权限问题,它回答的是“站点为什么挂了”“这个页面为什么500”这类问题。实战中两者往往要对照着看:访问日志发现某个URL老返回500,就去错误日志里找对应时间点的详细报错原因。只看访问日志你知道出错了但不知道为什么,只看错误日志你知道有错但不知道影响了哪些请求和访客。两个配合,才能把问题的来龙去脉拼完整。
我用的是宝塔面板或者一键环境,还需要自己配日志吗?
大多数面板和一键环境已经帮你配好了基础的访问日志和错误日志,通常用的是combined格式、按站点分开、也配了轮转,开箱就能用。所以你不一定要从零配,但了解这些配置在哪、记的是什么,依然很有必要。一是面板默认配置未必符合你的需求,比如你想加 %D响应耗时字段查性能、想过滤掉静态资源噪音、想调整轮转周期,这些都得自己改LogFormat和CustomLog。二是出问题时你得知道日志文件在哪(面板一般在站点目录的log子目录或 /www/wwwlogs之类),格式各字段什么意思,才看得懂。三是挂了CDN后要不要配mod_remoteip记真实IP,面板默认往往没配,得自己加。所以面板帮你省了从零搭建的活,但日志格式、过滤、CDN真实IP、轮转策略这些个性化的部分,理解了才能按需调整,真出事时也才查得明白。别当甩手掌柜,至少知道自己的日志长什么样、在哪。
记 %D响应耗时会拖慢服务器吗?
几乎不会,可以放心加。%D记录的是Apache处理这个请求花了多少微秒,这个时间值本来就是服务器在处理请求过程中顺手就能拿到的数据,记进日志只是多写几个字符,对性能的影响微乎其微,完全不在一个量级上。相比之下,它带来的排查价值巨大:站点变慢时,有了 %D你可以直接按响应耗时排序,立刻定位是哪些URL、哪些接口在拖后腿,是数据库慢查询、是某个外部API调用超时、还是某类页面本身就重,一目了然。没有这个字段,你就只能靠猜或者上更重的监控工具。真正会影响性能的不是多记一个字段,而是日志写盘这个动作本身在超高并发下的IO压力,那个用前面说的BufferedLogs缓冲写入来缓解,和加不加 %D无关。所以为了排查性能去加 %D,是笔很划算的买卖,强烈建议生产环境的日志格式里带上它。
mod_remoteip配了之后,安全规则和访问控制会用真实IP吗?
会,这正是mod_remoteip的价值之一,但前提是受信代理配置正确。启用mod_remoteip并正确设置RemoteIPHeader和RemoteIPTrustedProxy后,Apache会把连接的客户端IP替换成从X-Forwarded-For取到的真实访客IP,之后不仅日志(%a)用的是真实IP,基于IP的访问控制、限制规则、状态报告等也都会用这个真实IP。这意味着你想封某个真实访客IP、或者只允许某些真实IP访问后台,规则能正确生效,而不是错误地作用在CDN的回源IP上。但这里有个安全前提必须强调:RemoteIPTrustedProxy一定要严格只填你真正信任的代理IP段(比如Cloudflare官方IP列表)。如果配置不当、信任范围过宽,恶意访客就能伪造X-Forwarded-For头来冒充任意IP,绕过你的IP封禁、甚至冒充内网地址,这是个真实存在的攻击面。所以配mod_remoteip时,受信代理列表的准确和最小化,和功能本身一样重要。
日志轮转到底该用rotatelogs还是logrotate?
两个都能用,选哪个看你的环境和习惯。rotatelogs是Apache自带的、走管道日志的方式,最大优点是切割时完全不用重启或重载Apache,它自己开新文件继续写、旧文件干净落地,丝毫不影响服务、也不丢日志,配置就在CustomLog那一行里,简单可靠,对只关心Apache日志的场景很合适。
logrotate是Linux系统通用的日志轮转工具,好处是能统一管理服务器上所有服务的日志,还能顺手做压缩、保留天数、超期删除这些归档策略,运维统一管理更省心。但logrotate配Apache有个经典坑:改名后Apache还攥着旧文件句柄继续写、新文件是空的,必须在postrotate里给Apache发优雅reload信号让它重开日志,或者用copytruncate模式(但有极小概率丢几行)。保哥的建议是:只管Apache、想最稳省事就用rotatelogs;要和服务器上其他日志统一归档管理,就用logrotate但务必配好postrotate reload。两者别同时对同一个日志用,会打架。
权威参考资料
FAQPage + Article AI 引用友好版
站点出问题翻日志,却发现噪音淹没关键行、CDN后IP全是假的、日志撑爆磁盘?这些是Apache日志没配对。保哥讲access与error两类日志、common与combined怎么选、自定义格式加响应耗时、条件日志过滤噪音、mod_remoteip记真实IP、轮转不丢数据。
- 服务器日志
- Apache
- CDN
- 运维
title: Apache访问日志怎么配才查得清问题?LogFormat、CustomLog与CDN真实IP实战 author: 张文保 (Paul Zhang) — PatPat SEO 经理 url: https://zhangwenbao.com/apache-customlog-logformat-access-log-configuration-remoteip.html published: 2026-05-12 modified: 2026-05-12 source-type: First-hand expert commentary language: zh-CN license: CC BY-NC-SA 4.0 (要求保留原文链接与作者归属)
本文标题:《Apache访问日志怎么配才查得清问题?LogFormat、CustomLog与CDN真实IP实战》
本文链接:https://zhangwenbao.com/apache-customlog-logformat-access-log-configuration-remoteip.html
版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0