Scanners
A scanner runs discovery and vulnerability testing inside your network and reports results back to the CyberOptix CTEM Platform. You deploy it on your own infrastructure; it needs no inbound connectivity.
Deployment is two stages, and they are deliberately separate: install puts the package on the host, and link binds that host to one scanner group in your organization. A scanner that is installed but not linked is inert and harmless, which is what makes it safe to build hosts from an image.
Before you start
| Minimum | Recommended | |
|---|---|---|
| CPU | 4 cores | 4 cores |
| Memory | 8 GB | 16 GB |
| Disk | 120 GB | 150 GB |
Operating system: Ubuntu Server 24.04, with root or sudo access.
Network: outbound HTTPS (443) to your platform hostname and to the Purple Team Software package repositories, plus access to whatever the scanner is meant to reach in the zones you assign it. No inbound connections are required, so a scanner can sit behind NAT with no forwarded ports.
You will also need, from the platform:
- A scanner group to link into. Create one under Deployment if you have none.
- A license key, which gates vulnerability-test synchronization. Email [email protected] if you do not have one.
cyberoptix.scanner is the package name and optix is the service account. Both are
product-internal identifiers rather than branding, so they read the same on every
deployment regardless of which brand you access the platform under.
Install
Add the package repository:
sudo rm -f /usr/share/keyrings/purpleteamsoftware-archive-keyring.gpg
wget -O - https://apt.fury.io/purpleteamsoftware/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/purpleteamsoftware-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/purpleteamsoftware-archive-keyring.gpg] https://apt.purpleteamsoftware.com/ /" | sudo tee /etc/apt/sources.list.d/purpleteamsoftware.list
rm -f firstgpg --dearmor prompts before overwriting an existing keyring. On a re-run - which is
common, because this is the step people repeat after a typo - that prompt has nothing
attached to answer it, so the command appears to hang. Removing the old keyring first
makes the step idempotent.
Install the scanner:
sudo apt update && sudo apt install cyberoptix.scanner -y
Disable swap, and comment out the 127.0.1.1 entry so the host does not resolve its own
hostname to loopback during discovery:
sudo sed -i '/swap/ s/^/#/' /etc/fstab && sudo sed -i '/127\.0\.1\.1/ s/^/#/' /etc/hosts
sudo reboot
Configure and link
Add your user to the docker and optix groups:
sudo usermod -aG docker,optix $USER
New group membership does not apply to your current shell. Start a new session so it takes effect:
exec sudo -u $USER bash -l
su $USERsu can prompt for a password, which stalls an otherwise unattended build. sudo -u
re-initializes group membership from /etc/group without one.
Install the license key:
sudo bash -c 'echo YOUR_LICENSE_KEY > /etc/optix/license.key' && sudo chmod 600 /etc/optix/license.key
Pull and start the containers:
docker compose -f /etc/optix/docker-compose-optix.yml --profile disable pull
--profile disable doesTwo of the images, kali-linux and nmap, are tooling the scanner invokes on demand
rather than long-running services. They sit behind a compose profile named disable, so
they are never started. Including the profile in the pull means their images are
cached locally up front; without it, the first task that needs one pulls it mid-scan.
docker compose -f /etc/optix/docker-compose-optix.yml up -d
Synchronize vulnerability tests, and enable the timer that keeps them current:
sudo /usr/local/bin/sync-vulnerability-tests.sh && sudo systemctl enable --now optix-sync-tests.timer
Fix ownership:
sudo chown optix:optix -R /etc/optix/ && sudo chown optix:optix /var/lib/optix
Link the scanner
In the platform, open your scanner group and click the copy icon to copy its link command. Copy it rather than typing it: it arrives with your API hostname, scanner group ID and organization ID already filled in, and all three have to match exactly.
It looks like this:
sudo scanner-link -url https://<your-api-hostname>/ -scanner_group_id <id> -organization_id <id>
On success it prints Scanner linked successfully and writes credentials to
/etc/optix/scanner-config.json.
Finally, enable the services:
sudo systemctl enable --now \
scanner-active-discovery.service \
scanner-client-completed-tasks.service \
scanner-client-new-tasks.service \
scanner-task-manager.service \
scanner-vm.service \
scanner-dast.service
Verify
All six services and the sync timer should report active (running):
systemctl status --no-pager scanner-active-discovery scanner-client-completed-tasks scanner-client-new-tasks scanner-task-manager scanner-vm scanner-dast optix-sync-tests.timer
Two containers should be up, redis and owaspZap:
docker ps
The scanner polls for work every 30 seconds, so the clearest sign it is healthy is task traffic:
sudo journalctl -u scanner-client-new-tasks.service -f
Then confirm the scanner now appears in its group in the platform. If it does not, start with Troubleshooting.
What each service does
| Service | Purpose |
|---|---|
scanner-client-new-tasks | Retrieves new tasks from the platform, polling every 30s |
scanner-task-manager | Routes each task to the right queue by type |
scanner-active-discovery | Host and service discovery via Nmap |
scanner-vm | Network vulnerability scanning |
scanner-dast | Dynamic application security testing, via the OWASP ZAP container |
scanner-client-completed-tasks | Reports results back to the platform |
optix-sync-tests | Keeps vulnerability test definitions current |
Work moves between them through Redis queues, which is why redis being down stops
everything even though no scanning depends on it directly:
platform ──▶ new-tasks ──▶ NewScannerTasksQueue ──▶ task-manager
│
┌───────────────────────────┴──────────────────┐
▼ ▼
NmapTasksQueue NetworkVulnerabilityTasksQueue
│ │
▼ ▼
active-discovery scanner-vm
│ │
└───────────────────┬──────────────────────────┘
▼
CompletedScannerTasksQueue
│
▼
completed-tasks ──▶ platform
Files
| Path | Purpose | Permissions |
|---|---|---|
/etc/optix/scanner-config.json | Configuration and credentials | 600 |
/etc/optix/license.key | Vulnerability test sync license | 600 |
/etc/optix/docker-compose-optix.yml | Container definitions | 644 |
/var/lib/optix/vulnerability_tests/ | Test definitions | 755 |
/var/lib/optix/scanner.sock | Scanner daemon socket | optix:optix |
/var/log/optix/ | Log files | 755 |
Maintenance mode
Pause task processing without unlinking the scanner - use this before host maintenance so in-flight work is not abandoned:
scanner-cli -mode_maintenance
scanner-cli -mode_running
scanner-cli -version
Next
- Scanner groups and tasks - assigning work
- Zones, subnets, URLs, and tags - defining what gets scanned
- Troubleshooting - a scanner that is not reporting in