必须为每个VirtualHost单独配置CustomLog和ErrorLog的绝对路径,使用带域名前缀的日志名、%v字段日志格式、独立轮转机制,并确保HTTPS虚拟主机也配置独立ErrorLog。

Apache虚拟主机日志路径必须用CustomLog和ErrorLog单独声明
每个块里不显式写日志指令,Apache就默认复用主配置的CustomLog和ErrorLog,所有站点日志混在一起,查500错误时根本分不清是哪个域名出的问题。
必须为每个虚拟主机单独配日志路径,且路径要写绝对路径(相对路径会相对于ServerRoot,容易误判)。
-
CustomLog和ErrorLog指令必须放在对应块内部,不能只在全局配置里定义一次 - 路径推荐用
/var/log/apache2/example.com-access.log这类带域名前缀的命名,避免重名或权限冲突 - 目录得提前建好,Apache不会自动创建父目录;比如设了
/var/log/apache2/site-a/error.log,就得先mkdir -p /var/log/apache2/site-a - 确保 Apache 进程用户(通常是
www-data或apache)对日志目录有写权限,否则启动报Permission denied: could not open error log file
日志格式别直接用combined,加个%v字段更准确定位虚拟主机
默认combined日志格式不记录请求进来的Host头,而一个IP跑多个HTTPS站点时,Host才是区分流量的关键。光靠IP和端口看不出是哪个域名触发的异常。
- 定义新日志格式:在
httpd.conf或apache2.conf里加一行LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vcombined - 在虚拟主机里用这个格式:
CustomLog /var/log/apache2/example.com-access.log vcombined -
%v是实际匹配到的ServerName或ServerAlias,比%{Host}i更可靠(后者可能被客户端篡改)
rotatelogs或logrotate必须按虚拟主机粒度切分,否则日志轮转会出错
如果所有虚拟主机共用一个日志文件,logrotate切分后,Apache 还在往旧文件句柄写,新日志就丢了;用rotatelogs也一样,每个CustomLog得配独立的管道进程。
- 用
rotatelogs:写成CustomLog "|/usr/bin/rotatelogs -l /var/log/apache2/example.com-access.%Y%m%d.log 86400" vcombined - 用
logrotate:每个日志文件单独配一个/etc/logrotate.d/apache-example.com,里面指定create 644 www-data www-data,并带postrotate ... reload ... endscript - 别图省事把一堆日志路径塞进同一个
logrotate配置块——Apache 不支持单次 reload 刷新多个日志文件句柄
HTTPS虚拟主机要额外确认SSLEngine on不影响日志路径生效
有些人在里漏掉ErrorLog,以为HTTP和HTTPS能共用一个错误日志。实际上,SSL握手失败、证书过期这些错误只会记到该自己的ErrorLog里,主配置的ErrorLog完全收不到。
-
必须有独立的ErrorLog,且路径不能和*:80的重复(否则两个进程抢写同一文件) - 证书相关错误(如
SSL Library Error: error:140AD009:SSL routines:SSL_CTX_use_certificate_chain_file:PEM lib)只出现在对应 HTTPS 虚拟主机的ErrorLog中 - 如果用了 SNI,但客户端太老不支持,连接直接断开,这种连 access 日志都不会记——得靠
ErrorLog里的SSL handshake failed行定位
日志路径、格式字段、轮转机制、HTTPS隔离这四点只要漏一个,故障分析时就会卡在“到底是谁的日志”上。尤其注意ErrorLog在*:443块里不是可选项。









