0%

GoAccess: 实时分析Nginx日志的轻量级工具

十多年前我曾使用GoAccess搭建了一个NGINX日志分析工具,它以其轻量级、低资源消耗和实时更新的特性,非常适合个人和小站点使用。最近我的服务器做了次搬家,需要重新搭建日志分析系统,于是到网上查找GoAccess的用法时,发现官方站点的文档还是一如既往的晦涩,而其他站点介绍的用法则与我要搭建的架构不契合。所以干脆做了次总结,在这篇文章中,我将分享我如何搭建GoAccess,并使其通过Websocket协议提供实时日志分析。我的架构部署图如下所示:
GoAccess部署架构图
这么部署的原因是为了经过NGINX走全站SSL加密,毕竟在NGINX统一管理SSL证书还是方便点。

安装配置GoAccess

首先安装GoAccess,作为一个成熟的工具,可以直接在内置源里用yum或者apt-get安装:

1
yum install goaccess -y

其次需要明确当前输出的access.log日志的格式,比如NGINX默认的格式如下:

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

基于上述日志格式,可以生成/etc/goaccess.conf配置文件:

1
2
3
time-format %H:%M:%S
date-format %d/%b/%Y
log-format %h %^[%d:%t %^] "%r" %s %b "%R" "%u"

对日志格式中各项的替代符都是以%百分号为前缀,加上大小写敏感的字母做标识,如果你的日志格式与默认格式不同,可以参考如下含义修改:

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
%x:匹配time-format和date-format变量的日期和时间字段。当提供时间戳而不是两个独立的日期和时间变量时使用。
%t:匹配time-format变量的时间字段。
%d:匹配date-format变量的日期字段。
%v:根据规范名称设置(服务器块或虚拟主机)的服务器名称。
%e:根据HTTP认证确定请求文档的人的用户ID。
%C:服务器提供的对象的缓存状态。
%h:主机(客户端IP地址,可以是IPv4或IPv6)。
%r:客户端的请求行。这需要在请求周围使用特定的分隔符(单引号、双引号等)才能解析。否则,使用如%m、%U、%q和%H等特殊格式指示符来解析各个字段。注意:要么使用%r获取完整请求,要么使用%m、%U、%q和%H来形成你的请求,不要同时使用两者。
%m:请求方法。
%U:请求的URL路径。注意:如果查询字符串在%U中,则无需使用%q。然而,如果URL路径不包含任何查询字符串,你可以使用%q,查询字符串将被附加到请求中。
%q:查询字符串。
%H:请求协议。
%s:服务器发送回客户端的状态代码。
%b:返回给客户端的对象大小。
%R:"Referer" HTTP请求头。
%u:用户代理HTTP请求头。
%K:为连接选择的TLS加密设置。(在Apache LogFormat中:%{SSL_PROTOCOL}x)。
%k:为连接选择的TLS加密设置。(在Apache LogFormat中:%{SSL_CIPHER}x)。
%M:请求资源的MIME类型。(在Apache LogFormat中:%{Content-Type}o)。
%D:服务请求所花费的时间,以微秒为单位。
%T:服务请求所花费的时间,以秒为单位,带有毫秒分辨率。
%L:以小数形式表示的服务请求所花费的时间,以毫秒为单位。
%n:以小数形式表示的服务请求所花费的时间,以纳秒为单位。
%^:忽略这个字段。
%~:在日志字符串中向前移动,直到找到一个非空格字符(!isspace)。
~h:在X-Forwarded-For(XFF)字段中的主机(客户端IP地址,可以是IPv4或IPv6)。

接着启动GoAccess进程,如下的命令行可以在SHELL中分析日志:

1
goaccess -a -d -p /etc/goaccess.conf -f /usr/local/openresty/nginx/logs/access.log

这样你会在SHELL终端里看到如下可交互的页面:
GoAccess的SHELL界面

配置NGINX

如果我们想在浏览器上查看实时可变的页面,则需要生成HTML页面,并提供Websocket服务:

1
goaccess -a -d -p /etc/goaccess.conf -f /usr/local/openresty/nginx/logs/access.log -o /usr/local/openresty/nginx/html/goaccess_gen.html --real-time-html --daemonize --ws-url=wss://www.taohui.pub:10005 --addr=127.0.0.1 --port=7890

上面的命令行参数详细解释下:

  • -p显式指定了配置文件路径。
  • –daemonize表示以守护进程运行GoAccess。
  • –real-time-html指定生成可以实时变化的HTML页面。
  • -f表示进程分析的access.log则在/usr/local/openresty/nginx/logs/路径下。
  • -o指定了生成的HTML页面路径。
  • –addr和–port指定了websocket服务开启的地址与端口。

如果对外提供Web服务还需要我们在NGINX上配置一个静态资源服务,映射生成的HTML页面,比如在nginx.conf中新增如下配置:

1
2
3
4
5
6
server {
server_name www.taohui.pub;
location = /goaccess_gen.html {
root html;
}
}

注意上面我们启动GoAccess时会在7890端口上开启WebSocket服务:

1
2
# netstat -anp | grep 7890
tcp 0 0 0.0.0.0:7890 0.0.0.0:* LISTEN 24766/goaccess

这样在你不刷新页面时,GoAccess进程可以通过WebSocket协议给页面推送变化的监控数据。所以我们还要在NGINX上开启一个Websocket代理。这么做的原因是为了信息安全,毕竟全站加密才能防止第三方攻击者嗅探。为了防止端口冲突,所以在上面的命令行参数 –ws-url=wss://www.taohui.pub:10005要求HTML页面中使用10005端口建立基于SSL的Websocket连接,因此我们的nginx.conf中要加个WS代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
server_name www.taohui.pub;
listen 10005 ssl;
location / {
if ($http_upgrade != "websocket") {
return 404;
}
proxy_redirect off;
proxy_pass http://127.0.0.1:7890;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

ssl_certificate /etc/letsencrypt/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

现在我们已经可以访问 http://yourdomain/goaccess_gen.html 看到实时变化的监控数据了,页面大致如下图所示:
GoAccess的SHELL界面
你可以改变它的显示风格。

增加用户名密码认证

目前这个页面任何人都能访问,肯定存在隐私泄露,可以通过NGINX的auth_basic指令加一个简单的用户名、密码认证。
首先安装htpasswd工具:

1
yum install httpd-tools

接着生成密钥文件:

1
htpasswd -cb /etc/.htpasswd yourname yourpassword

然后在/goaccess_gen.html页面下加入auth_basic模块认证:

1
2
3
4
5
location = /goaccess_gen.html {
auth_basic "User";
auth_basic_user_file /etc/.htpasswd;
root html;
}

这样再访问页面时,就必须先输入正确的用户名和密码。虽然HTTP Authentication标准走的是明文,但HTTPS流量已经做过加密了,所以还是安全的。

扩展功能

GoAccess默认展示了15个面板,但它还支持更多的面板。比如,当你在access.log里配置$host访问域名后:

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

并且在goaccess.conf里添加了对应的%v,页面上就会多出一个Virtual Hosts面板,可以对比Nginx上配置的各域名的访问次数。

结束语

本文介绍了如何搭建GoAccess–一款为NGINX、Apache等Web服务设计的单机日志分析工具,它不仅部署简便、性能卓越,而且资源消耗极低。本文探讨了如何通过SSL实现全站加密,确保数据传输的安全性,并通过WebSocket协议推送实时变化的监控数据,此外还增加了HTTP authenticate认证,为数据访问提供了额外的安全层。GoAccess的图形化界面不仅美观,而且直观易用,值得每位需要高效日志分析解决方案的用户尝试和使用。