Scanning Isolated Networks from One Host
How to run multiple Scanopy daemon instances on a single machine, each scanning different isolated networks or interfaces.
This guide walks through running multiple daemon instances on a single host, each scanning different interfaces or network segments. For help deciding whether this is the right approach for your network, see Planning Daemon Deployment.
How config namespacing works
Every daemon instance has a name. The default is scanopy-daemon. When you pass --name, the daemon stores its configuration in a subdirectory named after that value:
| Name | Config path (Linux) |
|---|---|
| (default) | ~/.config/scanopy/daemon/config.json |
--name eth0 | ~/.config/scanopy/daemon/eth0/config.json |
--name iot | ~/.config/scanopy/daemon/iot/config.json |
Each named daemon gets its own config file with its own daemon ID, API key, server URL, and runtime state. They are fully independent — starting, stopping, or reconfiguring one does not affect the others.
Platform paths:
| Platform | Base directory |
|---|---|
| Linux | ~/.config/scanopy/daemon/ |
| macOS | ~/Library/Application Support/com.scanopy.daemon/ |
| Windows | %APPDATA%\scanopy\daemon\ |
Restricting daemons to specific interfaces
Use --interfaces to limit which network interfaces a daemon scans. Without it, the daemon scans all interfaces.
# Scan only eth0
scanopy-daemon --name eth0 --interfaces eth0
# Scan two interfaces
scanopy-daemon --name production --interfaces eth0,eth1The same setting works as an environment variable or in the config file:
# Environment variable
SCANOPY_INTERFACES=eth0,eth1
# config.json
{ "interfaces": ["eth0", "eth1"] }When --interfaces is set, the daemon only reports and scans subnets attached to those interfaces. This prevents overlap between daemon instances sharing the same host.
Configuring ports and bind addresses
Every daemon instance runs an HTTP server that binds to 0.0.0.0:60073 by default. Because 0.0.0.0 binds all interfaces, the first daemon claims port 60073 on every address — subsequent instances on the same host will fail with a port conflict.
To fix this, give each instance a unique --bind-address (the IP of its specific interface) and a unique --daemon-port:
# Daemon on eth0 (192.168.1.10) — uses default port
scanopy-daemon --name eth0 --interfaces eth0 \
--bind-address 192.168.1.10 --daemon-port 60073
# Daemon on eth1 (10.0.0.10) — different port
scanopy-daemon --name eth1 --interfaces eth1 \
--bind-address 10.0.0.10 --daemon-port 60074The same settings work as environment variables or in the config file:
# Environment variables
SCANOPY_BIND_ADDRESS=192.168.1.10
SCANOPY_DAEMON_PORT=60073
# config.json
{ "bind_address": "192.168.1.10", "daemon_port": 60073 }Both --bind-address and --daemon-port are required when running multiple daemons on one host. Even if each daemon uses a different bind address, using the same port on 0.0.0.0 will cause a conflict.
Setting up multiple daemons
Create a separate daemon entry in Discover > Scan > Daemons for each instance. Each daemon gets its own API key and can target the same or different networks. During setup, use the Advanced tab to configure interface restrictions under Network Discovery. The app provides platform-specific install and run commands with your settings included.
After first run, each daemon persists its settings to its namespaced config file. Subsequent starts only need the name:
sudo scanopy-daemon --name eth0
sudo scanopy-daemon --name eth1The bind address and port are persisted in each daemon's config file, so you only need to pass them on first run.
systemd template (Linux)
Scanopy provides a systemd template unit for running multiple instances. Download and install it:
sudo curl -o /etc/systemd/system/scanopy-daemon@.service \
https://raw.githubusercontent.com/scanopy/scanopy/main/scanopy-daemon%40.service
sudo systemctl daemon-reloadThe template uses the instance identifier as both --name and --interfaces. Each instance needs its own bind address and port — set these via environment overrides:
ExecStart=/usr/local/bin/scanopy-daemon --name=%i --interfaces=%i
SyslogIdentifier=scanopy-daemon-%iTo configure the bind address and port per instance, create a systemd override:
sudo systemctl edit scanopy-daemon@eth0[Service]
Environment="SCANOPY_BIND_ADDRESS=192.168.1.10"
Environment="SCANOPY_DAEMON_PORT=60073"sudo systemctl edit scanopy-daemon@eth1[Service]
Environment="SCANOPY_BIND_ADDRESS=10.0.0.10"
Environment="SCANOPY_DAEMON_PORT=60074"Enable and start instances by appending the interface name after @:
sudo systemctl enable --now scanopy-daemon@eth0
sudo systemctl enable --now scanopy-daemon@eth1Each instance gets separate journal logs:
journalctl -u scanopy-daemon@eth0
journalctl -u scanopy-daemon@eth1The template ties the instance name to a single interface. If a daemon needs multiple interfaces, create a custom service file that passes --interfaces eth0,eth1 and a descriptive --name.
Listing existing daemon configs
To see which named daemons are configured on a host, list the config directory:
# Linux
ls ~/.config/scanopy/daemon/
# macOS
ls ~/Library/Application\ Support/com.scanopy.daemon/
# Windows
dir %APPDATA%\scanopy\daemon\Each subdirectory corresponds to a named daemon instance. A config.json at the top level is the default (unnamed) daemon.
Upgrading and restarting
All daemon instances share the same binary. When the app shows an upgrade is available, it provides stop, install, and start commands. With multiple daemons you need to stop and restart each instance individually:
# systemd template instances
sudo systemctl stop scanopy-daemon@eth0
sudo systemctl stop scanopy-daemon@eth1
# replace the binary (use the install command from the app)
sudo systemctl start scanopy-daemon@eth0
sudo systemctl start scanopy-daemon@eth1Configuration is preserved across upgrades — each daemon reads its settings from its own config file on startup.
Docker
For Docker deployments, run a separate container per daemon instance. Use the install commands from the app for each daemon entry and add the SCANOPY_INTERFACES environment variable to restrict each container to its assigned interface. Both containers need network_mode: host to access host interfaces.