ScanopyScanopy
Networking & Deployment

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 multiple daemons coexist

Each scanopy-daemon install on a host takes its own slot — an independent install with its own config file, service, and log file. The first install takes the default slot (scanopy-daemon); each additional install takes the next number (scanopy-daemon-2, scanopy-daemon-3, …). The installer allocates the slot for you — you don't name it.

SlotServiceConfig (Linux)
scanopy-daemonscanopy-daemon/etc/scanopy/daemon/scanopy-daemon/config.json
scanopy-daemon-2scanopy-daemon-2/etc/scanopy/daemon/scanopy-daemon-2/config.json
scanopy-daemon-3scanopy-daemon-3/etc/scanopy/daemon/scanopy-daemon-3/config.json

Each slot's config holds its own daemon ID, API key, server URL, and runtime state. Slots are fully independent — starting, stopping, or reconfiguring one does not affect the others. A slot is not the daemon's name: the name is assigned by the server and shown in the app, and can be changed there without moving the slot.

A daemon's display name comes from the server, so you never pass it at install time. Run scanopy-daemon list on the host to see each installed slot, its service, and its config path.

System config locations by platform (service installs):

PlatformBase directory
Linux/etc/scanopy/daemon/
macOS/Library/Application Support/Scanopy/daemon/
Windows%ProgramData%\Scanopy\daemon\
FreeBSD/usr/local/etc/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 --interfaces eth0

# Scan two interfaces
sudo scanopy-daemon install --interfaces eth0,eth1

The 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.

Ports and bind addresses

Every daemon instance runs an HTTP server, bound 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 — a second daemon can't reuse it.

The installer handles this for you: when you install another daemon and don't ask for a specific port, it picks the next free one (60074, 60075, …) so the new instance doesn't collide with one already on the host. You only need to set --daemon-port when you want a specific port — most importantly for a ServerPoll daemon, where the port is the one the server dials, so the install command already carries it and the installer leaves it alone.

To pin a daemon's listener to one interface, give it that interface's IP with --bind-address:

sudo scanopy-daemon install --interfaces eth0 --bind-address 192.168.1.10

The 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 }

Setting up multiple daemons

Create a separate daemon entry in Discover > Scan > Daemons for each instance. Each is provisioned with its own API key and can target the same or different networks. During setup, use the Advanced tab to set that instance's interface restrictions, bind address, and port under Network Discovery — they're baked into the install artifact the wizard gives you, so you don't have to add them by hand.

Run each daemon's own install artifact on the host. Each run takes a fresh slot, so you can install several without them overwriting each other — no per-instance flags to remember:

# First daemon — takes the scanopy-daemon slot
sudo scanopy-daemon install --interfaces eth0

# Second daemon — takes the scanopy-daemon-2 slot automatically
sudo scanopy-daemon install --interfaces eth1

Each install registers a per-slot background service that starts immediately and on every reboot, and writes that slot's config. Manage each by its service — for example sudo systemctl restart scanopy-daemon-2 (Linux) or sc.exe stop scanopy-daemon-2 (Windows), where the service id matches the slot. On macOS the launchd label is com.scanopy.daemon.<slot> (for example sudo launchctl kickstart -k system/com.scanopy.daemon.scanopy-daemon-2). Run scanopy-daemon list to see each slot's exact service id. Interface, bind address, and port are persisted in each slot's config, so restarting or re-running install doesn't need them again.

To re-run against an existing slot — reconfigure it, or re-key it after rebuilding the host — pass --instance <selector>, where the selector is the daemon's name, its slot, its service id, or its daemon id (all shown by scanopy-daemon list). Without a selector on a multi-daemon host, a non-interactive install allocates a new slot rather than guessing which one you meant, and an interactive one asks. The reconfigure command the app generates already includes the right --instance.

systemd template (Linux, manual)

Prefer scanopy-daemon install above — it registers a per-slot 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-reload

The template uses the instance identifier as --interfaces. Each instance needs its own bind address and port — set these via environment overrides:

ExecStart=/usr/local/bin/scanopy-daemon --interfaces=%i
SyslogIdentifier=scanopy-daemon-%i

To 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@eth1

Each instance gets separate journal logs:

journalctl -u scanopy-daemon@eth0
journalctl -u scanopy-daemon@eth1

The 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.

Listing installed daemons

To see which daemons are installed on a host — their slots, services, config paths, and IDs — run:

scanopy-daemon list

Each line is one installed slot. Use any of the values it prints as the --instance selector for install or the --name selector for uninstall.

Upgrading and restarting

All daemon slots share the same binary. Download the latest binary once (the app's Update button provides the command), then restart each slot's service:

# Slots installed with `scanopy-daemon install`
sudo systemctl restart scanopy-daemon
sudo systemctl restart scanopy-daemon-2

# 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@eth1

Configuration is preserved across upgrades — each slot 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.

On this page