概要
LANポートが2つあるPCを使用してネットワークタップを構築し、ntopng、InfluxDB、Grafanaを組み合わせた監視システムの構築手順を紹介します。試しにYouTubeの通信量から利用時間を可視化してみました。
ダッシュボード上段のように今日の閲覧時間とバイト数(MB/min)を確認できます。
なお、本環境は一人でネットワークを利用しているため、プライバシーに関する問題はありません。
ネットワークタップとは
ネットワークタップとは、ネットワーク機器間に接続して通過するパケットを監視する装置です。 ネットワークタップ以外にもポートミラーリング機能を持ったスイッチやルータを使うこともできますが、今回はどちらも所有していなかったためPCを使用しました。
ntopngとは
ntopngは、ntop社がメンテナンスしているトラフィック収集、可視化、分析ができるソフトウェアです。インストールすることでパケットキャプチャした上でWebUIから通信状況を確認できます。 今回はWebUIを使わずntopngからInfluxDBに格納した上でInfluxDBをデータソースにGrafanaから確認しています。
ライセンスにコミュニティ版もあり無料で利用可能です。
ntopngにはnDPIというライブラリが含まれており、これによってアプリケーションレベルでの通信内容の分析もできます。今回はこちらの機能でYouTubeの閲覧時間を計測してみました(ちなみにこんなことをしなくてもYouTubeのアプリを使えば視聴動画を元にした閲覧時間を確認できます)。
PCについて
PCはCHUWI LarkBox Xを使っています。
- イーサネットインターフェースが2つ付いています
- Wi-Fiも利用可能なので、GrafanaのHTTPサーバはWi-Fi経由で接続します
- Ubuntu 24.04.2 LTSをインストールしています
構成図
ONUとWi-Fiルーターの間にタップとしてPCを設置し、キャプチャした内容を無線LAN経由でPCから確認します。 この構成にすることで、Wi-Fiルータに接続しているすべての機器の通信をキャプチャできます。
構築
Wi-Fiのネットワーク設定~SSH接続までは省略します。
ネットワーク設定
Netplanの設定ファイルを作成します(Wi-Fiの設定は別ファイルで管理しています)。
ルータとONU間に設置するため、IPv6を有効にする必要があります。
sudo vi /etc/netplan/60-ethernet-bridge.yaml
設定内容は以下のとおりです。IPアドレスを無効にしてブリッジとして接続します。
インターフェース名は ip a で確認しておきます。
network:
version: 2
renderer: networkd
ethernets:
enp1s0:
dhcp4: false
dhcp6: false
enp2s0:
dhcp4: false
dhcp6: false
bridges:
br0:
interfaces: [enp1s0, enp2s0]
dhcp4: false
dhcp6: false
accept-ra: true
parameters:
forward-delay: 0
stp: false
Netplanを適用します。
sudo netplan apply
カーネルパラメータの調整
カーネル設定を変更します。
sudo vi /etc/sysctl.conf
以下の設定を追加します。1Gbpsのため128MBに設定しました。
net.core.rmem_default = 4194304 # 4MB
net.core.rmem_max = 134217728 # 128MB
net.core.wmem_default = 4194304 # 4MB
net.core.wmem_max = 134217728 # 128MB
net.core.netdev_max_backlog = 10000
設定を反映します。
sudo sysctl -p
ntopngのインストール
以下のページを参考にします。
https://packages.ntop.org/apt-stable/
# リポジトリの追加
sudo apt-get install software-properties-common wget
sudo add-apt-repository universe
wget https://packages.ntop.org/apt-stable/24.04/all/apt-ntop-stable.deb
sudo apt install ./apt-ntop-stable.deb
# インストール
sudo apt-get clean all
sudo apt-get update
sudo apt-get install pfring-dkms nprobe ntopng n2disk cento
起動と起動設定を追加します(すでに両方有効でした)。
sudo systemctl start ntopng
sudo systemctl enable ntopng
sudo systemctl status ntopng
sudo systemctl is-enabled ntopng
InfluxDBのインストール
以下のページを参考にします。2025年5月現在で安定版のv2を利用します。
https://docs.influxdata.com/influxdb/v2/install/
# リポジトリの追加
curl --silent --location -O \
https://repos.influxdata.com/influxdata-archive.key
echo "943666881a1b8d9b849b74caebf02d3465d6beb716510d86a39f6c8e8dac7515 influxdata-archive.key" \
| sha256sum --check - && cat influxdata-archive.key \
| gpg --dearmor \
| sudo tee /etc/apt/trusted.gpg.d/influxdata-archive.gpg > /dev/null \
&& echo 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main' \
| sudo tee /etc/apt/sources.list.d/influxdata.list
sudo apt-get update
# インストール
sudo apt-get install influxdb2
起動と起動設定を追加します。
sudo systemctl start influxdb
sudo systemctl enable influxdb
sudo systemctl status influxdb
sudo systemctl is-enabled influxdb
ブラウザで[IPアドレス:8086]でアクセスし、ユーザーをセットアップします。
ntopngとInfluxDBを接続する
以下のページを参考にします。
https://www.ntop.org/ntop/ntopng-influxdb-and-grafana-a-step-by-step-guide-to-create-dashboards/
https://www.ntop.org/ntop/influxdb-v2-support-in-ntopng-is-now-partially-available/
ntopngはInfluxDB v2には完全には対応していませんが、v1互換のAPIを使えば連携できます。
InfluxDBのバケットとAPIトークンを作成後、以下のコマンドでv1互換のユーザーを作成します。
BUCKET_IDはバケットの一覧から取得できます(名前ではありません)。
InfluxDBは[IPアドレス:8086]でアクセスできます。
influx v1 auth create --read-bucket BUCKET_ID --write-bucket BUCKET_ID --username USERNAME_FOR_NTOPNG --password USERNAME_FOR_NTOPNG --org YOUR_ORGANIZATION --token REST_API_TOKEN_PROVIDED_BY_INFLUX
ntopngのWebUIからInfluxDBへの接続をします。
- 日本語設定ではサイドバーの「設定」→「設定」→「時系列」からアクセスできました
- 時系列ドライバーを「InfluxDB 1.x/2.x」に設定します
- InfluxDB URLは http://localhost:8086 のままにしました
- InfluxDBデータベースをバケット名のntopngにしました
- InfluxDB認証を有効にし、上記コマンドで作成したユーザー名とパスワードを設定しました
- 時系列の解像度を1mにしました
- タイムシリーズ/統計データの保持は60日にしました
Grafanaのインストール
以下のページを参考にします。
https://grafana.com/docs/grafana/latest/setup-grafana/installation/debian/
# リポジトリの追加(software-properties-commonとwgetはすでにインストール済み)
sudo mkdir -p /etc/apt/keyrings/
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
sudo apt-get update
# インストール
sudo apt-get install grafana
設定ファイルを修正します。
sudo vi /etc/grafana/grafana.ini
ポートがntopngと被るので変更します。ユーザー名とパスワードも設定しておきます。
http_port = 4000
admin_user = admin
admin_password = XXXXX
起動と起動設定を追加します。
sudo systemctl start grafana-server
sudo systemctl enable grafana-server
sudo systemctl status grafana-server
sudo systemctl is-enabled grafana-server
InfluxDBと接続します。
- ConnectionsからData sourcesでInfluxDBを追加します
- Query languageをFluxに設定します
- HTTPのURLを http://localhost:8086 に設定します
- 認証情報でOrganization、APIトークン、デフォルトバケットを指定しました
動作確認
ここまででntopng、InfluxDB、Grafanaの設定ができたので、タップとしてLANケーブルを挿してGrafanaから確認してみます。
YouTubeの通信量を確認するクエリです。iface:ndpiからYouTubeの通信のみフィルタし分毎に集計しています。
from(bucket: "ntopng")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "iface:ndpi")
|> filter(fn: (r) => r["_field"] == "bytes")
|> filter(fn: (r) => r["ifid"] == "2")
|> filter(fn: (r) => r["protocol"] == "YouTube")
|> aggregateWindow(every: 1m, fn: sum, createEmpty: false)
|> derivative(unit: 1m, nonNegative: true)
|> map(fn: (r) => ({ r with _value : r._value / 1000000.0 }))
今日のYouTube利用時間を確認するクエリです。
ここでは1分ごとの通信量が700KB以上であるときに利用中であるとして判定するようにしました。
import "date"
import "timezone"
option location = timezone.location(name: "Asia/Tokyo")
// 日本時間の今日の開始時刻を取得
today_start = date.truncate(t: now(), unit: 1d, location: timezone.location(name: "Asia/Tokyo"))
from(bucket: "ntopng")
|> range(start: today_start)
|> filter(fn: (r) => r["_measurement"] == "iface:ndpi")
|> filter(fn: (r) => r["_field"] == "bytes")
|> filter(fn: (r) => r["ifid"] == "2")
|> filter(fn: (r) => r["protocol"] == "YouTube")
|> aggregateWindow(every: 1m, fn: sum, createEmpty: false)
|> derivative(unit: 1m, nonNegative: true)
|> map(fn: (r) => ({ r with
is_active: if r._value / 1000.0 > 700.0 then 1.0 else 0.0
}))
|> filter(fn: (r) => r.is_active == 1.0)
|> count()
これらクエリにより画面上部の画像のようなダッシュボードが作成できました。
おわり
通信量を元に時間を測定しているので実際の閲覧時間とどの程度違いがあるかは今後確認します。
せっかくGrafanaのダッシュボードで表示するようにしたので、一定時間以上視聴すると通知するなども試してみたいと思います。