Tor operators often want answers to two simple questions:

How much bandwidth is the relay using right now?

How much traffic has it contributed in total?

Tor exposes enough information through its control protocol to answer both.

Real-time counters are already available

The Tor control interface provides values equivalent to:

traffic/read
traffic/written
uptime

These counters describe bytes read and written by the Tor daemon since the current Tor process started.

A monitoring script can sample them twice:

counter at T1
      ↓
wait 1 second
      ↓
counter at T2
      ↓
difference ÷ elapsed time
      ↓
current bandwidth

For example:

RX : 2.4 Mbit/s
TX : 2.2 Mbit/s

The values can also be displayed in bytes per second:

0.300 MB/s
0.275 MB/s

Why RX and TX should both be shown

A Middle Relay usually receives encrypted traffic and forwards it.

Therefore a single relayed stream generally generates both:

RX
+
TX

If 1 GiB arrives and approximately 1 GiB leaves, the server has processed roughly 2 GiB of network traffic.

For this reason:

RX + TX

is useful for estimating physical network usage, but it should not be interpreted as unique user payload.

Protocol overhead, directory activity, control traffic, and retransmission may also be included.

A lightweight command-line dashboard

A useful local tool can provide:

===== TOR TRAFFIC =====

Current bandwidth
  RX : ...
  TX : ...
  SUM: ...

Current Tor process traffic
  RX : ...
  TX : ...
  SUM: ...

Permanent accumulated Tor traffic
  RX : ...
  TX : ...
  SUM: ...

Tor uptime : ...
Counter    : persistent

Two modes are particularly convenient:

tor-traffic

for a one-second snapshot, and:

tor-traffic -w

for continuous monitoring.

Use the alternate terminal screen

A continuous terminal monitor should not destroy existing shell output.

Programs such as:

top
htop
less
nyx

use the terminal’s alternate screen buffer.

The correct sequence is conceptually:

normal shell screen
        ↓
enter alternate screen
        ↓
display live dashboard
        ↓
refresh in place
        ↓
Ctrl+C
        ↓
leave alternate screen
        ↓
original shell screen restored

ANSI terminal control sequences can implement this behavior.

This is preferable to repeatedly running:

clear

because clearing before every refresh creates visible flicker.

Real-time monitoring does not require disk I/O

A real-time bandwidth monitor can read Tor counters entirely through a local Unix control socket.

The path may resemble:

/run/tor/control

The data flow is:

Tor memory counters
       ↓
Unix socket
       ↓
monitoring process
       ↓
terminal

This does not inherently write anything to disk.

CPU and memory overhead are extremely small.

Permanent counters require persistence

The Tor counters reset when the Tor daemon restarts.

To maintain lifetime statistics, an independent collector can store:

total_rx
total_tx
last_rx
last_tx
last_uptime
updated_at

in a tiny state file.

Example architecture:

Tor
 ↓
collector samples every second
 ↓
delta calculated in RAM
 ↓
periodic state save
 ↓
persistent JSON file

If Tor restarts and current counters return to small values, the collector recognizes the reset and adds the new values to the previously accumulated totals.

Avoid unnecessary disk writes

A naïve collector might write its state every second.

That is unnecessary.

The state file is tiny, but the filesystem operation itself can still generate:

  • metadata updates;
  • journal writes;
  • block flushes;
  • SSD or HDD activity.

A better design samples frequently but persists infrequently.

For long-term relay statistics:

sample interval: 1 second
disk save interval: 1 hour

is completely reasonable.

The collector continues calculating values in RAM, while storage is touched only periodically.

The tradeoff

With a one-hour save interval:

normal shutdown
→ state saved cleanly

collector restart
→ state saved cleanly

unexpected power failure
→ up to roughly one hour of unsaved totals may be lost

For operational statistics, this is often an acceptable compromise.

A relay processing traffic continuously for years does not need second-perfect lifetime totals.

Use atomic writes

Persistent state should not be overwritten directly.

A safer pattern is:

write temporary file
      ↓
fsync
      ↓
rename temporary file over state file

POSIX rename operations are atomic within the same filesystem.

This greatly reduces the chance of leaving a partially written JSON file after a crash.

Run the collector as an unprivileged service

The persistent collector only needs access to:

Tor Unix control socket
its own state directory

It does not need root.

A systemd service can therefore use:

User=<TOR_SERVICE_ACCOUNT>
Group=<TOR_SERVICE_GROUP>

NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict

with a dedicated state directory created by systemd.

The result is a very small monitoring service with minimal privileges.

Keep monitoring private

Detailed real-time relay traffic is operationally useful but should generally remain private.

A local SSH dashboard is appropriate:

administrator
   ↓ SSH
server
   ↓
tor-traffic -w

Publishing second-by-second ingress and egress graphs for an individual Tor relay provides unnecessary traffic-analysis information.

Public dashboards should favor coarse, aggregated historical statistics rather than precise live measurements.

A sustainable monitoring architecture

A clean long-term setup therefore looks like:

Tor daemon
   │
   ├── Nyx for interactive inspection
   │
   ├── tor-traffic for local snapshots
   │
   └── persistent collector
          ↓
       RAM updates every second
          ↓
       disk save every hour

This provides useful real-time visibility, permanent contribution totals, negligible resource usage, and very little additional disk activity.

For a volunteer relay intended to run continuously for years, that balance is usually far more useful than deploying a large monitoring stack.

Leave a Reply

Your email address will not be published. Required fields are marked *