Shows realtime traffic flows for an nginx reverse proxy per server.
  • Python 63.7%
  • HTML 36.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-17 18:14:53 -05:00
app Accept logs without upstream timing 2026-09-17 18:14:53 -05:00
docs Build Nginx live traffic monitor 2026-09-17 17:47:16 -05:00
tests Accept logs without upstream timing 2026-09-17 18:14:53 -05:00
.gitignore Initial commit 2026-09-17 17:30:03 -05:00
LICENSE Initial commit 2026-09-17 17:30:03 -05:00
nginx-traffic-monitor.service Build Nginx live traffic monitor 2026-09-17 17:47:16 -05:00
pyproject.toml Build Nginx live traffic monitor 2026-09-17 17:47:16 -05:00
README.md Vendor dashboard frontend assets 2026-09-17 18:09:35 -05:00
requirements.txt Build Nginx live traffic monitor 2026-09-17 17:47:16 -05:00

Nginx Live Traffic Monitor

Dashboard screenshot

A small Python/FastAPI dashboard for seeing live traffic through an Nginx reverse proxy. It follows one dedicated access log, aggregates requests into bounded one-second in-memory buckets, and streams telemetry to browsers over Server-Sent Events. There is no database or persistent application telemetry.

Requirements and installation

Python 3.10+ is required. From a checkout:

python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt

Bulma and Chart.js are vendored under app/static/vendor, so the dashboard does not require browser access to a public CDN.

Nginx log format

Add the dedicated log (the application does not change Nginx configuration):

log_format traffic '$msec $host $request_method $status '
                   '$request_length $bytes_sent '
                   '$request_time $upstream_response_time';

access_log /var/log/nginx-traffic/traffic.log traffic;

The follower tolerates malformed lines, - upstream times, multiple upstream values, temporary disappearance, and rename/replacement rotation. It starts at the end of an existing file, like tail -F, so old log history is not mistaken for live traffic. The application keeps only configured rolling buckets (and bounded latency samples); totals are from application startup.

Running

python -m app.main

Open http://127.0.0.1:8080. Configuration is available through flags or environment variables:

Setting Flag Environment variable Default
Traffic log --log-path TRAFFIC_LOG_PATH /var/log/nginx-traffic/traffic.log
Listen address --host LISTEN_ADDRESS 127.0.0.1
Listen port --port LISTEN_PORT 8080
Retention seconds --retention TELEMETRY_RETENTION 3600

Example:

TRAFFIC_LOG_PATH=/var/log/nginx-traffic/traffic.log LISTEN_ADDRESS=0.0.0.0 LISTEN_PORT=8080 \
  python -m app.main --retention 3600

The visible window can be set to 1 minute, 5 minutes, 15 minutes, or 1 hour. A new browser receives enough current history to fill its selected graph window. Host names are discovered automatically and can be selected for breakout graphs. Theme selection (system, light, dark) is stored in browser local storage.

tmpfs and permissions

One possible tmpfs setup is:

sudo install -d -o nginx -g nginx -m 0750 /var/log/nginx-traffic
sudo mount -t tmpfs -o size=64M,mode=0750,uid=nginx,gid=nginx tmpfs /var/log/nginx-traffic

The service account needs search/read permission on the directory and read permission on traffic.log. If Nginx writes as another group, grant the monitor account group access or use an ACL, for example:

sudo setfacl -m u:nginx-monitor:rx /var/log/nginx-traffic
sudo setfacl -m u:nginx-monitor:r /var/log/nginx-traffic/traffic.log

systemd

Copy the included nginx-traffic-monitor.service to /etc/systemd/system/, adjust WorkingDirectory, virtualenv path, and the User/Group to match the installation, then:

sudo systemctl daemon-reload
sudo systemctl enable --now nginx-traffic-monitor
sudo systemctl status nginx-traffic-monitor

The service should run as an unprivileged account. Put a reverse proxy or firewall in front of it if it must be accessed beyond localhost; this utility intentionally has no authentication.

Development

Run the focused parser/aggregation tests with:

pytest -q

The server task follows the path by inode, drains currently available data from a renamed file, and reopens a replacement. A missing path is retried without busy polling. The publisher sends one compact snapshot per second to each SSE subscriber, and disconnecting clients are removed automatically.