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
sudo scanopy-daemon install --name eth0 --interfaces eth0
# Scan two interfaces
sudo scanopy-daemon install --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
sudo scanopy-daemon install --name eth0 --interfaces eth0 \
--bind-address 192.168.1.10 --daemon-port 60073
# Daemon on eth1 (10.0.0.10) — different port
sudo scanopy-daemon install --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.
Run scanopy-daemon install --name <name> for each instance. Each one registers its own background service — named scanopy-daemon-<name> — and writes its namespaced config, so it starts immediately and on every reboot:
sudo scanopy-daemon install --name eth0 --interfaces eth0 \
--bind-address 192.168.1.10 --daemon-port 60073 \
--server-url https://scanopy.example.com --daemon-api-key <key-for-eth0>
sudo scanopy-daemon install --name iot --interfaces eth1 \
--bind-address 10.0.0.10 --daemon-port 60074 \
--server-url https://scanopy.example.com --daemon-api-key <key-for-iot>Manage each instance by its service name — for example sudo systemctl restart scanopy-daemon-eth0 (Linux), sudo launchctl kickstart -k system/com.scanopy.daemon.eth0 (macOS), or sc.exe stop scanopy-daemon-iot (Windows). The bind address and port are persisted in each daemon's config file, so re-running install or restarting the service doesn't need them again.
systemd template (Linux, manual)
Prefer scanopy-daemon install --name <name> above — it registers a per-instance service for you. The systemd template below is the manual alternative, kept for older daemons or hand-managed setups.
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. Download the latest binary once (the app's Update button provides the command), then restart each instance's service:
# Instances installed with `scanopy-daemon install` (services named scanopy-daemon-<name>)
sudo systemctl restart scanopy-daemon-eth0
sudo systemctl restart scanopy-daemon-iot
# Legacy systemd-template instances (scanopy-daemon@<name>): stop, replace the binary, start
sudo systemctl stop scanopy-daemon@eth0 scanopy-daemon@eth1
sudo systemctl start scanopy-daemon@eth0 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.