最近「貪圖」便宜,將伺服器換到了阿里雲國際版香港VPS主機。搬過來後最大的感覺並不是速度的提升——因為原來用的韓國kdatacenter VPS在電信網路存取也是挺快的——而是阿里雲VPS主機的性能相對於同樣是1GB的其它VPS主機來說真的有點弱了。

稍微用工具一掃阿里雲香港VPS的系統負載就蹭蹭往上漲,有時剛在後台寫文章就發現打不開了。打開伺服器日誌一看,發現了不少的異常IP,例如掃描連接埠的,還有SQL注入的,還有「撿漏」網站備份檔案的,還有AB壓力測試的…總之,出現不少的非人為的訪問行為。

分析日誌中的IP行為是一個比較累人的苦力活,尤其是當日誌達到幾百MB以上時,用文字檔案開啟就非常地緩慢了。本篇文章就來分享兩個優秀的伺服器日誌分析工具:ngxtop和GoAccess。 ngxtop 是透過分析 Nginx 日誌文件,使用類似 top 指令的介面即時展示出來的。

ngxtop可以分析先前的日誌文件,也可以即時監控伺服器日誌,你可以像用Top指令一樣在連接埠中快速查出日誌中訪問最多的IP位址、403/500/404錯誤、要求的頁面排行等等。 ngxtop是一個輕量級的工具,而GoAccess則更像是強大的日誌統計工具。

GoAccess不僅圖文並茂,而且速度快,每秒8W 的日誌記錄解析速度,websocket每10秒刷新統計資料。 GoAccess不僅有命令列介面,也可以產生一個Html網頁,讓你直覺地看出來日誌中訪客數量、要求的檔案、404等錯誤、使用者位置、瀏覽器、作業系統、來路URL、Http狀態碼等。

伺服器日誌分析利器:ngxtop和GoAccess-即時監控視覺化管理快速找出異常來源

總之,ngxtop和GoAccess是兩款分析Apache、Nginx等伺服器日誌的利器,掌握好了這兩個軟體,那些對伺服器「潛在」的危險IP即可顯露「原形」。身為站長,你多學習一個軟體的使用,意味著你又可以節省一筆伺服器開支,例如:

  1. 利用Huginn抓取任何網站RSS和微信公眾號更新-打造一站式資訊閱讀平台
  2. Linux VPS掛載Google Drive與Dropbox-實作VPS主機資料同步備份
  3. 三大免費工具幫助你偵測VPS伺服器真偽-VPS主機效能與速度測試方法

PS:2017年10月21日更新,有興趣使用阿里雲香港VPS的朋友可以先看我的評測:阿里雲國際版香港機房速度與性能評測-速度快但磁盤IO和內存是瓶頸。如果你還想監控VPS伺服器網路的穩定性,可以使用這個工具:Smokeping安裝與設定-免費開源網路效能監控工具視覺化主/從部署。

一、ngxtop安裝與使用

1.1  ngxtop安裝

專案首頁:

  1. HTTPS://GitHub.com/樂賓虹/那小top

ngxtop適用於Nginx伺服器日誌。 ngxtop可用如下指令安裝:

Fedora:yum install python-pip
CentOS/RHEL需先安装EPEL,安装完后:yum install python-pip
Debian/Ubuntu:apt-get install python-pip

pip install ngxtop

或者也可以直接從原始碼安裝:

wget https://github.com/lebinh/ngxtop/archive/master.zip -O ngxtop-master.zip
unzip ngxtop-master.zip
cd ngxtop-master
python setup.py install

1.2  ngxtop用法

ngxtop的基本用法如下:

gxtop [选项]
ngxtop [选项] (print|top|avg|sum) <变量>
ngxtop info

選項有以下參數:

-l : 指定日誌檔案的完整路徑 (Nginx 或 Apache2)

-f : 日誌格式

–no-follow: 處理目前已經寫入的日誌文件,而不是即時處理新加入到日誌文件的日誌

-t : 更新頻率

-n : 顯示行號

-o : 排序規則(預設是存取計數)

-a …, –a …: 加入表達式(一般是聚合表達式如: sum, avg, min, max 等)到輸出中。

-v: 輸出詳細訊息

-i : 只處理符合規則的記錄

-c <file>或 –config <file> 指定nginx設定文件,自動分析日誌格式

-i <filter-expression>或 –filter <filter-expression> 滿足表達式的過濾將被處理

-p <filter-expression>或 –pre-filter <filter-expression> in-filter expression to check in pre-parsing phase.

ngxtop的變數有:remote_addr、remote_user、time_local、request、request_path、status、body_bytes_sent、http_referer、http_user_agent。主要是用來分析出IP位址、請求路徑、Http狀態、referer、user_agent等等。

1.3  ngxtop範例

用ngxtop info可以查看本機的伺服器日誌地址還有設定檔所在路徑,不過,它只能顯示一些預設的日誌文件,有些自訂的日誌檔案不會顯示出來。

找出404錯誤前十的請求URL。 命令代碼:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow top request_path --filter 'status == 404'

效果如下圖:

找出訪問數最多的前十個IP位址。 命令代碼:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow --group-by remote_addr

效果如下圖:

找出流量前十的IP位址。 命令代碼:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow --order-by 'avg(bytes_sent) * count'

找出400錯誤碼以上的且顯示request、status、http_referer三項。 命令代碼:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow -i 'status >= 400' print request status http_referer

找出bytes_sent平均值且狀態碼為200且request_path以wzfou開頭的前10。 命令代碼:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow avg bytes_sent --filter 'status == 200 and request_path.startswith("wzfou")'

透過上面幾個指令,基本上很快就能鎖定一些異常請求的IP位址了。預設的ngxtop會顯示前10個記錄,你可以加上參數 –n xxx,這樣自己控制顯示的數量。命令如下:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow --group-by remote_addr -n 20

ngxtop實作監控伺服器日誌。要即時顯示Nginx日誌監控的情況,只需要去年–no-follow 參數即可,指令如下:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --group-by remote_addr

效果如下圖:

二、GoAccess安裝與使用

2.1  GoAccess安裝

GoAccess官網:

  1. HTTPS://go access.IO/

GoAccess支援Apache、Nginx、 Amazon S3、 Elastic Load Balancing、CloudFront等伺服器日誌的分析。安裝指令如下:

apt-get install libncursesw5-dev libgeoip-dev
wget http://tar.goaccess.io/goaccess-1.2.tar.gz
tar -xzvf goaccess-1.2.tar.gz
cd goaccess-1.2/
./configure --enable-utf8 --enable-geoip=legacy
make
make install

根據你自己的需要,你可以在安裝GoAccess 調整設定選項。如下:

--enable-debug 使用偵錯標誌編譯且關閉編譯器最佳化。
--enable-utf8 寬字元支援。依賴 Ncursesw 模組。
--enable-geoip=<legacy|mmdb> 地理位置支援。依賴 MaxMind GeoIP 模組。 legacy 將使用原始 GeoIP 資料庫。 mmdb 將使用增強版 GeoIP2 資料庫。
--enable-tcb=<memhash|btree> Tokyo Cabinet 儲存支援。 memhash 將使用 Tokyo Cabinet 的記憶體哈希資料庫。 btree 將使用 Tokyo Cabinet 的磁碟 B+Tree 資料庫。
–disable-zlib 禁止在 B+Tree 資料庫上使用 zlib 壓縮。
--disable-bzip 禁止在 B+Tree 資料庫上使用 bzip2 壓縮。
--with-getline 使用動態擴充行緩衝區用來解析完整的行請求,否則將使用固定大小(4096)的緩衝區。
--with-openssl 使 GoAccess 與其 WebSocket 伺服器之間的通訊能夠支援 OpenSSL。

2.2  GoAccess用法

GoAccess語法如下:

goaccess [filename] [ options ... ] [-c][-M][-H][-q][-d][...]

常用的參數說明如下:

-f –log-file=<logfile>

指定輸入日誌檔案的路徑。如果在設定檔中指定了輸入文件,則其優先權要高於在命令列中透過 -f 參數指定。

-l –log-debug=<filename>

發送所有調試資訊到指定文件。需要指定配置選項 --enable-debug

-p –config-file=<configfile>

指定使用自訂設定檔。如果設定了此參數,其優先權將高於全域設定檔(如果有)。

–invalid-requests=<filename>

記錄無效請求到指定檔案。

–no-global-config

禁止載入全域設定檔。可能的目錄應該是/usr/etc/, /etc//usr/local/etc/, 除非在執行./configure 時指定了--sysconfdir=/dir

-a –agent-list

開啟 UserAgent 清單。開啟後會降低解析速度。

-d –with-output-resolver

輸出 HTMLJSON 報告時開啟 IP 解析。

-e –exclude-ip <IP|IP-range>

排除一個 IPv4 或 IPv6 位址。 使用連接符號表示 IP 段(開始-結束)。

-H –http-protocol=<yes|no>

HTTP 請求協定開關。將建立一個請求欄位包含請求協定+真實請求。

-M –http-method=<yes|no>

HTTP 請求方法開關。將建立一個請求欄位包含請求方法+真實請求。

-o –output=<json|csv>

將給定檔案重定向到標準輸出,透過後綴名決定輸出格式:

-q –no-query-string

忽略請求的查詢字串。即: www.google.com/page.htm?query => www.google.com/page.htm
注意: 去掉查詢字串將大幅降低記憶體消耗,特別對有時間戳記的請求。

-r –no-term-resolver

在終端輸出時禁止 IP 解析。

–444-as-404

將非標準狀態 444 作為 404 處理。

–4xx-to-unique-count

將 4xx 用戶端錯誤數加到獨立訪客數中。

–all-static-files

統計包含查詢字串的靜態檔案。

–date-spec=<date|hr>

設定日期的顯示格式,一種是標準日期格式(預設),一種是日期後附加小時的格式。
僅在訪客面板上有效。對於在小時層級分析訪客資料很有幫助。顯示格式範例:18/Dec/2010:19

–double-decode

解碼雙重編碼的值。包括 UserAgent,Request 以及 Referer。

–enable-panel=<PANEL>

開啟指定面板。面板列表:

–hour-spec=<hour|min>

設定時間的顯示格式,一種是標準時間格式(預設),一種是時間後附加分鐘數(每十分鐘)的格式。
用於時間分佈面板。對於在特定時間段分析流量峰值很有用處。

–ignore-crawlers

忽略爬蟲。

–ignore-panel=<PANEL>

忽略指定面板。面板列表:

–ignore-referer=<referer>

忽略被統計的來路。支援通配符。例如: *.domain.com ww?.domain.*

–ignore-status=<STATUS>

忽略解析或顯示一個或多個狀態碼。如果有多個狀態碼,使用此參數每次指定一個。

–num-tests=<number>

設定測試行數,即使用給定的 日誌/日期/時間 格式測試存取日誌。預設值為 10 行。如果設定為 0 ,解析器不會做任何測試而是直接解析整個檔案。如果在達到number 之前,有一行匹配上了給定的日誌/日期/時間格式,則解析器會認為日誌檔案是有效的,否則GoAccess 會傳回EXIT_FAILURE 並顯示相關的錯誤訊息。

–process-and-exit

解析日誌,且退出時不輸出資料。主要用於僅希望往磁碟資料庫中新增資料而無需輸出報表時使用。

–real-os

顯示真實的作業系統名稱。例如: Windows XP, Snow Leopard.

–sort-panel=<PANEL,FIELD,ORDER>

S在初始化載入是對面板進行排序。排序選項使用逗號分隔。選項使用這樣的格式:PANEL,METRIC,ORDER

–static-file <extension>

新增靜態檔案後綴名。例如:.mp3。 後綴名區分大小寫。

-g –std-geoip

標準 GeoIP 資料庫,低記憶體佔用。

–geoip-database <geocityfile>

設定 GeoIP 資料庫路徑。例如:GeoLiteCity.dat。需要從 maxmind.com 上下載到本地。 IPv4 和 IPv6 均可用支援。注意:--geoip-city-data--geoip-database 的別名。
注意: 如果使用 GeoIP2,您需要從 MaxMind 下載 城市/國家 資料庫,並透過 --geoip-database 設定。

GoAccess日誌格式。 GoAccess還有一個參數是用來設定伺服器日誌格式的:–log-format <logformat>。 參數 log-format 後跟隨一個空格符或製表分隔符號(t),用於指定日誌字串格式。

如果你使用的是下表中的預先定義日誌格式名稱,可以直接當作GoAccess 日誌/日期/時間 格式的變數。

COMBINED     | 联合日志格式
VCOMBINED    | 支持虚拟主机的联合日志格式
COMMON       | 通用日志格式
VCOMMON      | 支持虚拟主机的通用日志格式
W3C          | W3C 扩展日志格式
SQUID        | Native Squid 日志格式
CLOUDFRONT   | 亚马逊 CloudFront Web 分布式系统
CLOUDSTORAGE | 谷歌云存储
AWSELB       | 亚马逊弹性负载均衡
AWSS3        | 亚马逊简单存储服务 (S3)

2.3  如何設定日誌格式

首先看看你的log_format是什麼,log_format指令如下:

語法: log_format name string …;
預設值: log_format combined “…”;
配置段: http

name表示格式名稱,string表示等義的格式。 log_format有一個預設的無需設定的combined日誌格式,相當於apache的combined日誌格式,如下所示:

log_format  combined  '$remote_addr - $remote_user  [$time_local]  '
                                   ' "$request"  $status  $body_bytes_sent  '
                                   ' "$http_referer"  "$http_user_agent" ';

當然,你也可以根據自己的需求來新增伺服器日誌所需取得的資訊。以下是日誌格式允許包含的變數:

remote_addr, $http_x_forwarded_for 记录客户端IP地址
remote_user 记录客户端用户名称
request 记录请求的URL和HTTP协议
status 记录请求状态
body_bytes_sent 发送给客户端的字节数,不包括响应头的大小; 该变量与Apache模块mod_log_config里的“%B”参数兼容。
bytes_sent 发送给客户端的总字节数。
connection 连接的序列号。
connection_requests 当前通过一个连接获得的请求数量。
msec 日志写入时间。单位为秒,精度是毫秒。
pipe 如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。
http_referer 记录从哪个页面链接访问过来的
http_user_agent 记录客户端浏览器相关信息
request_length 请求的长度(包括请求行,请求头和请求正文)。
request_time 请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
time_iso8601 ISO8601标准格式下的本地时间。
time_local 通用日志格式下的本地时间。

以下是log_format設定實例:

http {
 log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                                        '"$status" $body_bytes_sent "$http_referer" '
                                        '"$http_user_agent" "$http_x_forwarded_for" '
                                        '"$gzip_ratio" $request_time $bytes_sent $request_length';
 
 log_format srcache_log '$remote_addr - $remote_user [$time_local] "$request" '
                                '"$status" $body_bytes_sent $request_time $bytes_sent $request_length '
                                '[$upstream_response_time] [$srcache_fetch_status] [$srcache_store_status] [$srcache_expire]';
 
 open_log_file_cache max=1000 inactive=60s;
 
 server {
 server_name ~^(www.)?(.+)$;
 access_log logs/$2-access.log main;
 error_log logs/$2-error.log;
 
 location /srcache {
 access_log logs/access-srcache.log srcache_log;
 }
 }
}

這是GoAccess日誌格式與伺服器log-format對應關係:

%t 匹配time-format格式的时间字段

%d 匹配date-format格式的日期字段

%h host(客户端ip地址,包括ipv4和ipv6)

%r 来自客户端的请求行

%m 请求的方法

%U URL路径

%H 请求协议

%s 服务器响应的状态码

%b 服务器返回的内容大小

%R HTTP请求头的referer字段

%u 用户代理的HTTP请求报头

%D 请求所花费的时间,单位微秒

%T 请求所花费的时间,单位秒

%^ 忽略这一字段

GoAccess日誌修改範例:

log_format access '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $http_x_forwarded_for $request_time $upstream_response_time';

GoAccess預設的設定檔goaccess.conf放置於/usr/local/etc路徑中,預設的格式是:log-format %h %^[%d: %t %^] "%r" %s %b "%R" "%u"。 觀察上面的伺服器日誌格式,發現多了回應時間$request_time和upstream的回應時間$upstream_response_time。

我們可以修改如下:

原来:log-format %h %^[%d:%t %^] "%r" %s %b "%R" "%u"
修改:log-format %h %^[%d:%t %^] "%r" %s %b "%R" "%u" %^ %^ %T

最後三個元素%^ %^ %T%^表示忽略,%T表示“以秒為單位的反應時間,精確到毫秒” 。透過修改GoAccess的格式就與我們的伺服器日誌格式對應上了。

2.4  GoAccess範例

如果你的伺服器用的是通用日誌格式,聯合日誌格式,包含虛擬主機,W3C 格式以及亞馬遜 CloudFront(分散式下載)等,就不需要修改日誌格式,直接使用即可。 LNMP和Oneinstack都是用的COMBINED格式。

GoAccess在終端機在分析日誌指令:

goaccess -d -f /data/wwwlogs/wzfou.com_nginx.log --log-format=COMBINED

在上述指令中,-f 指定要分析的日誌/path/to/log;–log-format 日誌的格式,LNMP預設格式為:COMBINED。運行後效果如下圖:

操作熱鍵如下:

F1h主幫助頁面。

F5重繪主視窗。

q退出程序,目前視窗或崩潰了的模組。

oENTER擴充選取的模組或開啟視窗。

0-9Shift + 0啟動選取的模組。

j在已擴充模組中向下捲動。

k在已擴充模組中向上捲動。

c設定或改變配色方案。

^ f在目前模組中向前捲動一屏。

^ b在目前模組中向後捲動一螢幕。

TAB切換模組(向前)。

SHIFT + TAB切換模組(向後)。

s給予活躍模組的選項排序。

/在所有模組中搜尋(支援正規)。

n找到下次發生事件的位置。

g移動到第一個選項或螢幕頂部。

G移動到第最後一個選項或螢幕底部。

如果你想查看訪問數前十的IP位址,按下數字鍵5,就可以開啟該模組詳情了。如下圖:

其它的幾個數字對應模組如下:

按 1 定位到“按天訪問量”

按 2 定位到“最多次被要求的 URL”

按 3 定位到“最多次被要求的靜態文件”

按 4 定位到“最多次被要求的 404”

按 5 定位到“最多次要求的用戶 IP”

按 6 定位到“使用者的作業系統”

按 7 定位到“使用者的瀏覽器”

按 8 定位到“按小時的統計”

GoAccess輸出。 指令如下:

產生一份 HTML 報告:

# goaccess access.log -a -o report.html

產生一份 JSON 報告:

# goaccess access.log -a -d -o report.json

產生一份 CSV 檔案:

# goaccess access.log --no-csv-summary -o report.csv

GGoAccess 非常靈活,支援即時解析和過濾。例如:需要透過監控即時日誌來快速診斷問題:

# tail -f access.log | goaccess -

更厲害的是,還可以使用 tail -f 和一個模式匹配工具一起工作,例如: grep, awk, sed 等等

# tail -f access.log | grep -i --line-buffered 'firefox' | goaccess --log-format=COMBINED -

又或者可以在管道打開的狀態下從頭開始解析文件,並同時應用一個過濾器:

# tail -f -n +0 access.log | grep --line-buffered 'Firefox' | goaccess -o out.html --real-time-html -

例如:

將GoAccess輸出Html,然後用瀏覽器訪問,可用以下命令:

goaccess -d -f /data/wwwlogs/wzfou.com_nginx.log --log-format=COMBINED -a > /data/wwwroot/howsvps.com/wzfou.html

用瀏覽器存取效果如下圖(點擊放大):

GoAccess輸出的圖表非常漂亮,你也可以在圖表中查看詳細的選項。詳情還可以看看官網的Demo:https://rt.goaccess.io/

將GoAccess輸出Html並即時刷新,指令如下:

goaccess -d -f /data/wwwlogs/howsvps.com_nginx.log --log-format=COMBINED -a > /data/wwwroot/howsvps.com/wzfou.html --real-time-html --port=9870 --daemonize

以上是守護程序啟動 GoAccess 後,使用 Websocket 建立長連接,它預設監聽 7890 端口,可以透過--port參數指定端口號。

指定連接埠號碼後,記得在你的VPS防火牆中開啟:

iptables -A INPUT -p tcp -m tcp --dport 9870 -j ACCEPT

三、總結

ngxtop適合簡單的查找需要,GoAccess偏重於整體分析,甚至可以當成統計使用。如果你的網站使用的SSL,那麼在GoAccess輸出即時監控的HTML頁面時,記得在在設定檔goaccess.conf中設定ssl-certssl- key項。

當然,我們也可以使用crontab定時讓GoAccess產生統計html頁面,這樣也等於即時線上監控伺服器日誌了。程式碼如下(每5分鐘產生一次HtmL頁面):

*/5 * * * * goaccess -d -f /data/wwwlogs/wzfou.com_nginx.log --log-format=COMBINED -a > /data/wwwroot/wzfou.com/wzfou.html

對於不知道如何設定GoAccess日誌格式的朋友,你可以直接使用線上轉換工具:https://github.com/stockrt/nginx2goaccess。命令:

用法: ./nginx2goaccess.sh '<log_format>'

./nginx2goaccess.sh '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'

輸出的結果你就可以直接用在GoAccess日誌格式設定中了:

- Generated goaccess config:

time-format %T
date-format %d/%b/%Y
log_format %h - %^ [%d:%t %^] "%r" %s %b "%R" "%u"

發表評論