Skip to content

Instantly share code, notes, and snippets.

@xmrdsc xmrdsc/
Last active Jun 30, 2019

What would you like to do?
Monero RPC node bandwidth monitoring

In this document, $YOUR_IP refers to your public ip address.

Keeping track of bandwidth for Monero RPC nodes

First, we must make a clear distinction between RPC traffic and P2P traffic. As a node operator you might think "wow my node is doing so much traffic WTF where are all these bytes coming from and going to". Well, this is actually due to your P2P port being exposed, which is port 18080. This document does not cover the monitoring of P2P traffic. This document is specifically for the RPC port which runs on 18081 (or 18089).

As Monero RPC traffic is HTTP, we can use nginx to reverse proxy and record bandwidth passing through. This implies that monerod's RPC port stays on localhost

Where normally we would use:

./monerod --max-concurrency 2 --rpc-bind-ip YOUR.IP.GOES.HERE --rpc-bind-port 18089 --restricted-rpc

We would now use:

./monerod --max-concurrency 2 --rpc-bind-port 18089 --restricted-rpc

And let it bind to localhost:

netstat -tulpn | grep 18089
tcp        0      0*               LISTEN      11242/./monerod 

So that we have some room on $YOURIP:18089 for nginx.

Setting up Nginx

First install sudo apt install nginx nginx-extras (ubuntu).

Edit /etc/nginx/nginx.conf and add this code inside the http { block:

log_format monerod_custom '<ip> [$time_iso8601] "$request" $status $bytes_sent $request_length';

Create a new server config /etc/nginx/sites-enabled/monerod.conf

server {
    listen $YOURIP:18089;
    more_clear_headers Server; 

    access_log /var/log/nginx/monerod.log monerod_custom;
    error_log /var/log/nginx/monerod-err.log;

    root /var/www/html;
    index index.html;

    location / {
        allow all;
        add_header Server Epee-based always;
        proxy_hide_header Server;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;

    location ~ /\.ht {
            deny all;

Now restart nginx: sudo systemctl restart nginx

And observe the custom log format in /var/log/nginx/monerod.log.


To gather bandwidth statistics from the nginx logs, we can use the following hacky python3 script:

Edit: I repeat, a very hacky Python script. This is just for demonstration purposes

import sys
import re
import gzip
from glob import glob
from datetime import datetime

print("Monero RPC bandwidth")

NGINX_LOG_PATH = '/var/log/nginx/monerod.log'
DATE_FILTER = sys.argv[1]
DATE_FILTER = datetime.strptime(DATE_FILTER, '%Y-%m-%d')

def size_human(size, precision=2):
    suffixes = ['B', 'KB', 'MB', 'GB', 'TB']
    _index = 0
    while size > 1024 and _index < 4:
        _index += 1
        size = size / 1024.0
    return "%.*f%s" % (precision, size, suffixes[_index])

def read_nginx_log(fn, date_filter):
    lines = []
    _date_filter = date_filter.strftime('%Y-%m-%d')
    if fn.endswith('.gz'):
        with, 'rb') as f:
            for line in f:
                if not line:

                line = line.decode('utf8')
                if _date_filter not in line:

                line = line.strip()
        return lines

    with open(fn, 'r') as f:
        for line in f.readlines():
            if not line or _date_filter not in line:
    return lines

def parse_nginx_logs(date_filter):
    global NGINX_LOG_PATH
    data = []

    for logfile in glob("%s*" % NGINX_LOG_PATH):
        print('reading %s' % logfile)
        lines = read_nginx_log(logfile, date_filter)
        for line in lines:
            date = re.findall(r'\[(.*)\]', line)
            if not date:
            date = date[0]

                date = date[:date.find('+')]
                # date = datetime.strptime(date.strip(), '%d/%b/%Y:%H:%M:%S')
                date = datetime.strptime(date.strip(), '%Y-%m-%dT%H:%M:%S')
            except Exception as ex:

            if ']' not in line:

            line = line[line.find(']')+2:]
            bytes_sent, bytes_received = map(int, line.split(' ')[-2:])
                'date': date,
                'bytes_sent': bytes_sent,
                'bytes_received': bytes_received
    return data

data = parse_nginx_logs(DATE_FILTER)

# sort on date
data = sorted(data, key=lambda k: k['date'], reverse=False)
min_date = data[0]['date']
max_date = data[-1]['date']

bytes_received = sum([z['bytes_received'] for z in data])
bytes_sent = sum([z['bytes_sent'] for z in data])

print(min_date.strftime('%Y-%m-%d %H:%M:%S') + " <-> " + max_date.strftime('%Y-%m-%d %H:%M:%S'))
print("Bytes received: %s" % size_human(bytes_received))
print("Bytes sent: %s" % size_human(bytes_sent))


$ python3 2018-12-15

Where the first input is the date you want bandwidth of.

Example output:

Monero RPC bandwidth

reading /var/log/nginx/monerod.log
reading /var/log/nginx/monerod.log.2.gz
reading /var/log/nginx/monerod.log.1

2018-12-15 00:00:17 <-> 2018-12-15 19:21:59
Bytes received: 14.54MB
Bytes sent: 8.74GB

author: dsc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.