pmacct
Overview
This guide covers deploying and using pmacct on Ubuntu 24.04 on Azure, with the SecureAnyCloud Azure Marketplace image.
pmacct is a mature, widely deployed suite of passive network monitoring tools. Its collector daemon nfacctd receives NetFlow v5, NetFlow v9 and IPFIX exports from the routers, switches and firewalls on your network. sfacctd does the same for sFlow, and pmacctd can account traffic directly from a captured interface.
Every flow is aggregated in memory by the primitives you choose, such as source and destination host, source and destination port, IP protocol and autonomous system. The running totals of packets and bytes are periodically written to a backend. This turns a firehose of raw flow records into compact, queryable accounting: who talked to whom, over which ports and protocols, and how much traffic each conversation carried.
A local PostgreSQL database is bundled on the same VM as the accounting backend. On its own, pmacct only aggregates flow in memory, so it needs somewhere to write the results. This image ships PostgreSQL bound to the loopback interface, with the collector writing aggregated records into a table called acct_v9. You do not have to keep that backend. pmacct can also write to files, and the change is a couple of lines of configuration, covered later in this guide.
A flow generator is bundled so the appliance proves itself out of the box. A collector with nothing exporting to it is idle, so this image also runs softflowd. It reads this VM's own network interface and exports NetFlow to the collector on the loopback address, so nfacctd accounts real traffic from the first boot. A second tool, pmacct-flowgen, was authored by SecureAnyCloud. It injects a synthetic flow with a known signature, so you can prove the whole pipeline end to end before you point a single router at it.
pmacct has no web interface. It is a collector: flow records in, aggregated accounting out. You work on the command line and query the accounting table with psql.
Security by design. A flow collector with a database behind it is only as safe as its exposure, so this image is locked down by default.
Exactly one port is open to the network, and it is the collector's legitimate ingress. UDP 2055 is where nfacctd receives NetFlow, sFlow and IPFIX. By protocol design, NetFlow has no application-level authentication, so restrict access at the network layer. Open 2055 in your Network Security Group (NSG) only to the subnet your routers and switches export from.
The database is bound to the loopback interface. PostgreSQL listens on 127.0.0.1 only and refuses connections on the VM's routable address. The accounting data and the database credential are never reachable from the network. Query the database from the VM itself or over an SSH tunnel.
Nothing is baked into the image. The captured image contains no database credential and no collector configuration. First boot generates the per-VM database password and writes it into the collector configuration and into a root-only credentials file. The collector cannot start until first boot has created them, so no password is shared between customers.
What you get:
- pmacct 1.7.9, built from the official upstream release and verified against a pinned SHA 256 checksum at build time. It provides
nfacctd,sfacctd,pmacctdand thepmacctclient, and runs under systemd asnfacctd.service - PostgreSQL from Ubuntu, bound to loopback, as the accounting backend holding the
acct_v9table - softflowd 1.1.0, running as
softflowd.serviceand exporting this VM's own interface traffic to the collector, so it accounts real flow from first boot pmacct-flowgen, a bundled synthetic NetFlow generator, andpmacct-selfcheck, a command that proves the whole pipeline end to end- A per-VM PostgreSQL credential, generated on first boot and written to a root-only credentials file
Prerequisites
You need:
- An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region
- A subscription to this listing on Azure Marketplace
- An NSG that allows TCP 22 for administration and UDP 2055 for the flow collector
In production, restrict 2055 to the subnet your routers, switches and exporters send from. No other port needs to be opened, because the database is bound to the loopback interface.
Recommended virtual machine size: Standard_B2s with 2 vCPU and 4 GB RAM suits development and moderate flow volumes. For high export rates or many exporters, choose Standard_D2s_v5 or above.
Deploy the virtual machine
Deploy from the Azure Portal. Select the image from Azure Marketplace, choose your VM size, and supply your SSH public key for the azureuser account. Alternatively, deploy from the Azure CLI.
Run these commands on your own workstation, not on the VM:
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:pmacct-ubuntu-24-04:default:latest
az vm create \
--resource-group my-resource-group \
--name my-pmacct-vm \
--image sac1647283583153:pmacct-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
az vm open-port --resource-group my-resource-group --name my-pmacct-vm --port 2055 --protocol UdpWhen the VM is running, connect over SSH:
ssh azureuser@<vm-ip>Confirm the collector is healthy
The database, the collector and the flow source all start automatically on boot. Check their status and confirm the version:
systemctl is-active postgresql nfacctd softflowd nfacctd -V | head -1Expected output
active active active NetFlow Accounting Daemon, nfacctd 1.7.9 [RELEASE]Next, confirm the network posture. Exactly one port is bound to all interfaces, the flow collector. The database is bound to the loopback address only:
ss -tuln | grep -E ':(2055|5432) 'Expected output
udp UNCONN 0 0 0.0.0.0:2055 0.0.0.0:* tcp LISTEN 0 200 127.0.0.1:5432 0.0.0.0:*This is the shape you want. UDP 2055 is reachable from your routers so they can export flow. PostgreSQL on 5432 is bound to loopback and unreachable from outside the VM.
Retrieve your per-VM credentials
First boot generates the database password uniquely on your VM and writes it to a root-only file, along with the connection details for the collector and the backend:
sudo cat /root/pmacct-credentials.txtThe file lists the collector endpoint your routers export to, and the loopback PostgreSQL connection: db_host, db_port, db_name, db_user, db_password and db_table. Keep the password safe. It is the credential for the accounting database.
Prove the accounting pipeline end to end
Before you point any router at the collector, prove that the whole pipeline works on this one VM. The bundled pmacct-flowgen injects a synthetic NetFlow v5 flow into the collector on the loopback address. The flow has a recognisable signature: source 198.51.100.10 and destination 203.0.113.20.
sudo pmacct-flowgenExpected output
pmacct-flowgen: sent NetFlow v5 flow 198.51.100.10:40001 -> 203.0.113.20:443 proto=6 packets=7 bytes=4200 to 127.0.0.1:2055Wait a few seconds for the collector to aggregate and flush to the database. Then query the accounting table for that flow. The command reads the per-VM database password from the credentials file, so the password never appears on the command line:
sleep 16
PW=$(sudo grep -E '^pmacct.db_password=' /root/pmacct-credentials.txt | cut -d= -f2-) PGPASSWORD="$PW" psql -h 127.0.0.1 -U pmacct -d pmacct \
-c "SELECT ip_src, ip_dst, port_src, port_dst, ip_proto, packets, bytes FROM acct_v9 WHERE ip_src='198.51.100.10' AND ip_dst='203.0.113.20';"Expected output
ip_src | ip_dst | port_src | port_dst | ip_proto | packets | bytes ---------------+--------------+----------+----------+----------+---------+------- 198.51.100.10 | 203.0.113.20 | 40001 | 443 | 6 | 7 | 4200 (1 row)The result is the flow you injected. nfacctd received it, aggregated it by source, destination, port and protocol, and wrote it to the database with its packet and byte counts.
Run pmacct-flowgen again and repeat the query. The counters accumulate for the same flow key, because nfacctd aggregates repeated flows into a single running total.
Run the bundled self check
Run pmacct-selfcheck at any time to re-verify the whole appliance. It checks that the collector is listening, that the per-VM database credential authenticates, that an injected flow lands aggregated in the table, and that the database refuses connections off the loopback interface:
sudo pmacct-selfcheckExpected output
pmacct appliance self-check [ok] nfacctd is listening on UDP 2055 (NetFlow ingress) [ok] per-VM PostgreSQL credential authenticates on 127.0.0.1:5432 [ok] injected synthetic NetFlow v5 flow 198.51.100.10 -> 203.0.113.20 ... waiting for nfacctd to aggregate + flush to PostgreSQL [ok] acct_v9 shows the injected flow aggregated: 198.51.100.10 -> 203.0.113.20 = 7/4200 (packets/bytes) [ok] acct_v9 holds 1 aggregated flow row(s) in total (incl. real interface traffic) [ok] PostgreSQL refuses connections on <vm-ip> — SQL surface is loopback only SELFCHECK OK — pmacct is collecting NetFlow and producing aggregated accounting output.Point your own exporters at the collector
To account real traffic from your network, configure your routers, switches or firewalls to export NetFlow, sFlow or IPFIX to this VM's IP on UDP 2055. Make sure your NSG allows 2055/udp from those devices.
On Cisco IOS, for example, create a flow exporter with destination <vm-ip> and transport udp 2055. nfacctd detects the flow version per packet, so v5, v9 and IPFIX exporters can all send to the same port.
The appliance also accounts its own traffic out of the box. softflowd reads this VM's primary interface and exports NetFlow to the collector, so the acct_v9 table fills with the VM's real conversations before you add external exporters.
Query the aggregated accounting table
The accounting table is ordinary PostgreSQL, so you analyse it with SQL. The command reads the password from the credentials file to keep it off the command line:
PW=$(sudo grep -E '^pmacct.db_password=' /root/pmacct-credentials.txt | cut -d= -f2-) PGPASSWORD="$PW" psql -h 127.0.0.1 -U pmacct -d pmacct \
-c "SELECT ip_src, ip_dst, port_src, port_dst, ip_proto, packets, bytes FROM acct_v9 ORDER BY bytes DESC LIMIT 10;"The query returns the top talkers by bytes. Because the data is a normal SQL table, you can group by host, port or protocol and join it to your own reference tables. You can also point Grafana's PostgreSQL data source at it over an SSH tunnel to build dashboards.
Reach the database over an SSH tunnel
The database is bound to loopback. To reach it from your workstation, for a GUI client or Grafana, forward the port over SSH:
ssh -L 5432:127.0.0.1:5432 azureuser@<vm-ip>Then connect your client to 127.0.0.1:5432, using database pmacct, user pmacct and the password from the credentials file.
Change what is aggregated
pmacct aggregates by the primitives named on the aggregate line of its configuration. The shipped default is src_host, dst_host, src_port, dst_port, proto. To account by autonomous system, or to add more primitives, edit the collector configuration and reload:
sudo sed -n '/^aggregate:/p' /etc/pmacct/nfacctd.confThe upstream documentation under /usr/share/doc/pmacct/ lists every primitive. After you change the aggregate line, reload the collector with sudo systemctl restart nfacctd.
The SQL table schema must contain the columns for the primitives you aggregate by. The shipped acct_v9 schema, from /usr/share/pmacct/sql/pmacct-create-table_v9.pgsql, already covers the common set.
Server components
- pmacct 1.7.9 (
/usr/local/sbin/nfacctd,sfacctd,pmacctd, and the/usr/local/bin/pmacctclient), GPL 2.0, built from source with the PostgreSQL and Jansson plugins - PostgreSQL (Ubuntu package), the accounting backend, bound to
127.0.0.1 - softflowd 1.1.0 (
/usr/sbin/softflowd), BSD licensed, the bundled flow source - pmacct-flowgen and pmacct-selfcheck (/usr/local/sbin/), tooling authored by SecureAnyCloud
Filesystem layout
/etc/pmacct/nfacctd.conf: the collector configuration, written at first boot,0640 root:pmacct/usr/share/pmacct/sql/: pmacct's own PostgreSQL schema scripts/root/pmacct-credentials.txt: the per-VM database credential,0600 root:root/var/lib/sac/data/pmacct-firstboot.done: the first-boot sentinel/var/log/sac/sac-firstboot.log: the first-boot log
Network ports
- UDP 2055: the NetFlow, sFlow and IPFIX collector, bound to all interfaces. This is the only port open to the network. Restrict it in your NSG to your exporters.
- TCP 5432: PostgreSQL, bound to
127.0.0.1only. Reach it over an SSH tunnel. - TCP 22: SSH administration.
Managing the services
sudo systemctl status nfacctd
sudo systemctl restart nfacctd
sudo systemctl status softflowd
sudo systemctl status postgresqlScripts and log files
sudo pmacct-selfcheck: prove the whole pipeline end to endsudo pmacct-flowgen: inject a synthetic test flowjournalctl -u nfacctd: read the collector log/var/log/sac/sac-firstboot.log: the first-boot log
On startup
On the first boot, pmacct-firstboot.service waits for PostgreSQL and generates the per-VM database password. It creates the pmacct role and database, loads the acct_v9 schema, writes the collector configuration, and starts nfacctd and softflowd. It then writes the credentials file and disables itself, so it runs exactly once.
On every later boot, the collector, the database and the flow source start normally.
Troubleshooting
The collector is not listening on 2055. Check sudo systemctl status nfacctd and journalctl -u nfacctd. On a brand new VM, confirm that first boot completed. Read sudo cat /var/log/sac/sac-firstboot.log and check that /var/lib/sac/data/pmacct-firstboot.done exists.
No rows appear in the table. Confirm that something is exporting flow. Check sudo systemctl status softflowd for the built-in source, or verify that your router exports to this VM's IP on 2055/udp and that the NSG allows it. Inject a known flow with sudo pmacct-flowgen to isolate the collector from the exporters.
psql cannot connect. The database listens on loopback only. Connect from the VM itself with -h 127.0.0.1, or forward the port over SSH. The password is in /root/pmacct-credentials.txt.
Run the self check. sudo pmacct-selfcheck exercises every part of the pipeline and reports exactly which step fails.
Security recommendations
- Restrict UDP
2055in your NSG to the subnet your routers, switches and firewalls export from. NetFlow is unauthenticated at the application layer, so network-level restriction is your control. - Keep the database on the loopback interface. If you must reach it remotely, use an SSH tunnel rather than opening
5432. - Keep the credentials file root-only, and rotate the database password if you ever expose the VM more widely.
- Apply operating system updates regularly. The image ships with unattended security upgrades enabled.
Support
SecureAnyCloud provides this image with 24/7 support. For assistance, contact sales@secureanycloud.com or visit https://secureanycloud.com.
Deploy on Azure
Launch pmacct 1.7.9 NetFlow, sFlow and IPFIX Network Traffic Accounting Collector on Ubuntu 24.04 on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com