-
Notifications
You must be signed in to change notification settings - Fork 0
Session Accounting
session-report answers the questions occtl can't: when did each client connect and disconnect, how much data did the session move, and — the part unique to this image — how much of it went through the user's gateway versus each attached bypass pool.
docker exec <container> session-report # everything
docker exec <container> session-report -u alice # one user
docker exec <container> session-report --json # machine-readable, same dataOptions: -u NAME (one user) · -j/--json · --no-geo (skip client-IP geolocation, faster offline) · --no-rate (skip the 1-second throughput sampling of active sessions).
================================================================
ocserv-server SESSION REPORT : 2026-08-03T01:20:11+03:00
Collecting since : 2026-08-02 09:23:41 (container start, 15h57m ago)
================================================================
### Active sessions (2)
alice (online, connected 2026-08-03 00:59:34, up 20m37s)
assigned 10.20.0.37 client 198.51.100.7 (Amsterdam, NL - AS64496 ExampleNet) dev vpns3 gateway nl
total (forwarded) up 321.7K down 636.1K [now: up 12.4K/s down 1.1M/s]
pool ru -> direct up 21.7K down 96.1K
via gateway nl up 300.0K down 540.0K
...
### Completed sessions (newest first)
bob (connected 2026-08-02 09:24:02, disconnected 2026-08-03 00:58:47, duration 15h34m)
assigned 10.20.0.52 client 203.0.113.80 (Berlin, DE - AS64511 ExampleCom) dev vpns1 gateway us
total (ocserv) up 89.1M down 1.1G
total (forwarded) up 88.9M down 1.1G
pool ru -> direct up 12.1M down 220.4M
via gateway us up 76.8M down 0.9G
...
### Per-user totals (active + completed)
user sessions up down
bob 2 98.2M 1.2G
via gateway us up 76.8M down 0.9G
direct up 12.1M down 220.4M
blocked (rejected) up 45.1K down 0B
...
### Reconnect loops
[flap] alice: 4 sessions shorter than 2m in the last hour - client may be reconnect-looping
The gateway-mode connect/disconnect hook already runs for every session. It now additionally:
- on connect — records the connect time, the client's real IP and the tun device, and installs per-session nftables counters: one up/down pair for the session total and one pair per attached bypass pool (matching the pool's address sets, both families);
- on disconnect — snapshots the counters together with ocserv's own session totals into a history file, then removes everything it installed.
session-report reads the live counters for active sessions and the history file for completed ones. There is nothing to configure and no measurable overhead — accounting is active whenever gateway mode with a per-user map (VPN_USER_GATEWAY[_FILE]) is, i.e. whenever the hook runs. Without gateway mode there is no path split to report; use occtl show users / network-diagnostic for live state.
- up is client → world, down is world → client.
-
[now: up …/s down …/s]on active sessions is live throughput, sampled over one second at report time (--no-rateskips the sampling and the 1s wait). -
Client geolocation (
(Amsterdam, NL - …)after the client IP) is looked up over the network at report time and silently omitted when unreachable;--no-geoskips the attempt. - Reconnect loops: a user with 3 or more completed sessions shorter than 2 minutes within the last hour gets flagged — the classic signature of a router stuck in a reconnect loop.
-
Per-user totals are broken down by where the bytes went, aggregated across all of the user's sessions: one line per gateway used, one
directline (direct-target pools plus unmapped sessions), and oneblocked (rejected)line (attempts intoblock-target pools — upload only, since rejected traffic never returns). -
total (forwarded) counts traffic actually forwarded between the tunnel and the WAN — the numbers the per-path split is computed from (
via gateway= total − all pools). - total (ocserv) (completed sessions) is ocserv's own count of tunnel bytes. It also includes traffic that terminates in the container — tunneled DNS, for example — so it is normally slightly higher than the forwarded total.
- A pool's share counts traffic to/from that pool's addresses as attached at connect time; if you change a user's pools with
vpngw-reloadmid-session, routing follows immediately but the new pool's counters start with the next session. - Traffic that the kill switch rejects (fail-closed drops) is counted as "up" — the client did send it — but never produces "down" bytes.
By default everything lives on tmpfs (/run/ocserv-vpngw/): history covers the current container lifetime. Sessions cannot outlive the container anyway, and an ocserv-only restart inside a running container keeps the collected history. Collecting since in the header tells you the horizon.
For accounting that survives container recreations, point the history at the config volume:
environment:
- SESSION_HISTORY_FILE=/etc/ocserv/session-history| Variable | Default | Description |
|---|---|---|
SESSION_HISTORY_FILE |
(unset — tmpfs) | Where completed sessions are appended. Put it on a volume to keep history across container recreations. The file grows one line per session; rotate or truncate it yourself when needed. |
The format is stable and machine-parseable, one line per completed session:
connect-epoch disconnect-epoch user ip4 ip6 client-ip gateway device up down ocserv-in ocserv-out pool=up:down,...
(- marks an unknown field; --json serves the same data already parsed.)
Next: Gateway Mode · Destination Bypass · Troubleshooting
ocserv-server · MIT License · Built on ocserv + s6-overlay
Setup
Examples
- Basic Standalone
- Self-Signed
- SWAG Integration
- One Upstream for All
- Per-User Gateways
- Bypass and Blocklists
Operating
- User Management
- Camouflage Mode
- Reverse Proxy and Certificates
- Networking NAT and Routing
- Gateway Mode
- Destination Bypass
- Session Accounting
- Health Monitor
- Clients and Devices
Under the hood
Help