picosnitch webui
browse and chart past connections
|
picosnitch tui
browse past connections in a terminal
|
picosnitch top
live event feed
|
More screenshots and short demo videos in the picosnitch screenshots gallery.
The recommended install is a system-wide pipx install. It works on every Linux distribution with Python >= 3.12 and a kernel new enough to run modern libbpf CO-RE programs.
sudo pipx install picosnitch --global
sudo picosnitch systemd
sudo systemctl enable --now picosnitch
pipx >= 1.5.0 (this is when the --global flag was added); see pipx installation if you don't already have itsudo picosnitch systemd writes /usr/lib/systemd/system/picosnitch.servicesudo pipx install 'picosnitch[sql]' --global for optional MariaDB / MySQL / PostgreSQL drivers for remote loggingsudo systemctl enable|disable picosnitch: autostart on rebootsudo systemctl start|stop|restart picosnitch: daemon lifecyclesudo picosnitch start|stop|restartsudo picosnitch start-no-daemonpicosnitch webui: web UI for browsing past connectionsPICOSNITCH_HOST / PICOSNITCH_PORT environment variablespicosnitch tui: terminal UI for browsing past connectionssudo picosnitch top: live event feed (requires root to read the daemon's event socket; starts and stops its own daemon if one isn't running)picosnitch status: show daemon pid and systemd service statepicosnitch help: full usageConfig is stored at /etc/picosnitch/config.toml and is created with defaults on first run.
[database]
enabled = true # write connection logs to /var/lib/picosnitch/picosnitch.db (SQLite)
retention_days = 30 # how many days to keep connection logs in the local database
# (the remote database is append-only; see [database.remote])
write_limit_seconds = 10 # minimum time between connection log entries
# increasing it groups traffic into larger time windows, decreasing
# disk writes, time precision, and database size
text_log = false # also write a CSV connection log to /var/log/picosnitch/conn.log
[database.remote] # optional: also write connection logs to an external SQL server
# used for off-system / tamper-evident logs (see Logging below).
# mirrors the local SQLite schema (connections, executables,
# domains, addresses).
# set `client` to "mariadb", "psycopg", "psycopg2", or "pymysql";
# add the rest of the connection parameters as key/value pairs and
# optionally `connections_table` to override the default; this lets
# multiple hosts share one server with a `connections` table each
# while reusing the shared `executables`/`domains`/`addresses`
[data]
owner = "root" # owner for files in /etc/picosnitch, /var/lib/picosnitch,
group = "root" # /var/log/picosnitch, and /var/cache/picosnitch
mode = "0644" # mode applied to those files (directories add execute bits)
[log]
addresses = true # log remote addresses for each connection
commands = true # log command line args for each executable
ports = true # log local and remote ports for each connection
ignore_ports = [] # list of ints; matching connections are omitted from the log
ignore_domains = [] # list of strings in reverse-dns notation (matches all subdomains)
ignore_ips = [] # list of IPs/CIDRs (e.g. "192.168.0.0/16")
ignore_sha256 = [] # list of executable sha256 hashes
# the process name, executable, and hash are still recorded
[desktop]
user = "" # username to send notifications to; defaults to $SUDO_UID
notifications = true # show desktop notifications via notify-send (libnotify)
geoip_lookup = true # annotate remote addresses with a country code in the TUI/webui
# uses the DB-IP Country Lite CSV cached under /var/cache/picosnitch
[monitoring]
every_exe = false # check every running executable, not just ones that open sockets
# these are treated as "connections" with a port of -1
# experimental; expect occasional errors for short-lived processes
# if you only want process logs (no hashes), see execsnoop / forkstat
perf_ring_buffer_pages = 256 # power of two pages for the exec and dns perf buffers
# network traffic is aggregated in-kernel, it does not use these
# only change this if you are seeing missed-event errors
conn_map_max_entries = 65536 # size of the in-kernel per-connection aggregation map
# only raise this if you see near-capacity eviction warnings
# rlimit_nofile = 65536 # optional int; raises RLIMIT_NOFILE for the daemon
# picosnitch caches one file descriptor per (device, inode);
# set this if you see "Too many open files" errors
# st_dev_mask = 0 # optional int; masks the device number reported for opened fds
# auto-detected at startup; only set this to override the default
# for filesystems that reuse inodes across subvolumes (e.g. btrfs)
[virustotal]
api_key = "" # VirusTotal API key, leave blank to disable
file_upload = false # upload the executable when its hash isn't already known
# leave false to only submit hashes
request_limit_seconds = 15 # seconds between requests (free-tier quota)
Restart picosnitch for any configuration changes to take effect.
Picosnitch splits its on-disk state across the FHS directories. All defaults assume the systemd unit (the unit also creates these on first start).
| Path | Contents |
|---|---|
/etc/picosnitch/config.toml |
configuration |
/var/lib/picosnitch/picosnitch.db |
SQLite connection log (read by picosnitch tui and picosnitch webui) |
/var/lib/picosnitch/state.json |
known executables + sha256 hashes, used to decide when to notify |
/var/log/picosnitch/exe.log |
history of new-executable notifications |
/var/log/picosnitch/error.log |
errors (also surfaced as desktop notifications) |
/var/log/picosnitch/conn.log |
optional CSV connection log (enable with [database].text_log = true) |
/var/cache/picosnitch/ |
DB-IP Country Lite database, refreshed monthly |
/run/picosnitch/picosnitch.pid |
pid file (world-readable, used by picosnitch status) |
/run/picosnitch/events.sock |
live event socket consumed by picosnitch top |
[database.remote] can be used to additionally ship every connection to a MariaDB, MySQL, or PostgreSQL server. It mirrors the local SQLite schema (connections, executables, domains, addresses); only the connections table name can be overridden (via connections_table), which lets multiple hosts share one server with a connections table each while reusing the shared reference tables. Picosnitch only ever issues INSERT against the remote (no retention, no garbage collection), so it is intended for keeping an off-system copy of your logs; grant INSERT only to prevent an adversary on the monitored host from deleting picosnitch's off-system logs.
conn.log is a CSV with these fields (commas, newlines, and NUL characters are stripped from values): entry time, sent bytes, received bytes, event count, executable path, process name, cmdline, sha256, parent executable, parent name, parent cmdline, parent sha256, grandparent executable, grandparent name, grandparent cmdline, grandparent sha256, user id, address family, protocol, local port, remote port, local address, remote address, domain, network namespace.
Entries in error.log are usually triggered by an unusually large burst of new processes or connections, by extremely short-lived processes that exit before picosnitch can open a file descriptor to them, or by suspending the system while a new executable is being hashed. Unexpected entries are worth investigating, since picosnitch is designed to surface an error whenever a process slips past its normal observation path.
[database.remote] for an off-system copy of the connection log, and consider corroborating with a separate router/firewall.st_dev_mask = 0).error.log.[monitoring].perf_ring_buffer_pages. A burst of new connections instead fills the in-kernel aggregation map, mitigated by raising [monitoring].conn_map_max_entries.$ claude mcp add picosnitch \
-- python -m otcore.mcp_server <graph>