Appearance
Installation
NetVuln Tool supports macOS (development) and Linux/Debian (deployment, including Raspberry Pi). All scan logic is pure Bash with no compiled binaries, and a Python orchestrator (netvuln) drives the same pipeline with typed data models. There are two supported install paths:
install.sh(this page, deployment path): sets up netvuln-tool for use on a scanning host or agent. It runs a preflight dependency check, installs thenetvulnCLI, provisions a license key, scaffolds a per-engagement config, optionally installs the systemd daemon, and verifies portal connectivity.setup.sh(developer path): sets up a development checkout (git hooks, lint dependencies, editable pip install). Use this when you intend to modify the tool, not just run it.
If you want a container instead of a host install, jump to the Docker guide. For always-on edge scanners, see Raspberry Pi deployment.
Platform Support
| macOS | Linux (Debian/Ubuntu/Raspberry Pi OS) | |
|---|---|---|
| Scanning | Yes | Yes |
| systemd daemon | No (systemd is Linux-only; install.sh prints a notice) | Yes |
| Recommended role | Development | Deployment / agents |
Requirements
install.sh installs everything in this table unprompted by default (apt on Linux, Homebrew on macOS); pass --minimal to skip that and fall back to warn-only checks with install hints instead. The table is still the reference for what each tool is for and how to install it by hand.
| Dependency | Required | macOS | Linux (Debian/Ubuntu/Raspberry Pi) |
|---|---|---|---|
| Bash 4+ | Yes | brew install bash | Pre-installed (verify: bash --version) |
| nmap | Yes | brew install nmap | sudo apt-get install -y nmap |
| jq | Recommended | brew install jq | sudo apt-get install -y jq |
| python3 3.10+ | Recommended | brew install python | Pre-installed on Debian 12, Raspberry Pi OS Bookworm and Ubuntu 22.04 or later |
| dig | Optional | Pre-installed | sudo apt-get install -y dnsutils |
| whois | Optional | Pre-installed | sudo apt-get install -y whois |
| openssl | Optional | Pre-installed | Pre-installed |
| curl | Optional | Pre-installed | sudo apt-get install -y curl |
| ssh | Optional | Pre-installed | sudo apt-get install -y openssh-client |
| nc | Optional | Pre-installed | sudo apt-get install -y netcat-openbsd |
| traceroute | Optional | Pre-installed | sudo apt-get install -y traceroute |
| smbclient | Optional | brew install samba | sudo apt-get install -y smbclient |
| snmpwalk / snmpget | Optional | brew install net-snmp | sudo apt-get install -y snmp |
| wkhtmltopdf | Optional (PDF export) | brew install wkhtmltopdf | sudo apt-get install -y wkhtmltopdf |
| msmtp | Optional (email alerts) | brew install msmtp | sudo apt-get install -y msmtp |
| iw | Optional (WiFi, Linux only) | n/a | sudo apt-get install -y iw |
| rfkill | Optional (WiFi, Linux only) | n/a | sudo apt-get install -y rfkill |
| nmcli | Optional (WiFi, Linux only) | n/a | sudo apt-get install -y network-manager |
Missing optional tools are gracefully skipped with a warning. iw, rfkill and nmcli are Linux-only and are never auto-installed on macOS.
Dependencies by purpose
| Tool | Status | Purpose |
|---|---|---|
| nmap | Required | Core scanning engine (host discovery, port/service detection, vuln scripts) |
| jq | Recommended | JSON processing, required for HTML reports |
| python3 | Recommended | The netvuln orchestrator CLI (recon/scan/upload/push/diff/status/daemon) |
| dig / host / nslookup | Optional | DNS enumeration |
| whois | Optional | WHOIS / OSINT lookups |
| openssl | Optional | SSL/TLS analysis |
| curl | Optional | HTTP header checks, CVE CVSS lookups, session upload, license validation |
| ssh | Optional | SSH auth-method enumeration |
| nc / ncat | Optional | SSH banner grabbing |
| traceroute | Optional | Hop-distance / route discovery |
| smbclient | Optional | SMB share enumeration |
| snmpwalk / snmpget | Optional | SNMP enumeration |
| wkhtmltopdf | Optional | PDF export for executive summaries |
| msmtp | Optional | Email alerts and scan reminders (one of several accepted mail backends) |
| iw | Optional (WiFi, Linux only) | WiFi interface discovery |
| rfkill | Optional (WiFi, Linux only) | Unblocking a soft-blocked WiFi radio |
| nmcli | Optional (WiFi, Linux only) | WiFi network enumeration |
One-command install
On a Linux or macOS host with curl and git, run as a normal user with sudo rights (not as root):
bash
curl -fsSL https://netvulntool.com/install.sh | bashThe bootstrap clones the public Community Edition at the latest release tag (or at --version vX.Y.Z) into ~/netvuln-tool, checks the cloned commit against the release, and runs that tree's install.sh, which asks for what it needs on the terminal. See Deployment install: install.sh for what that installer does.
License key
Set the key in the environment first (the silent read below keeps it out of shell history), or paste it at install.sh's silent prompt (nothing is echoed):
bash
read -rs NV_LICENSE_KEY && export NV_LICENSE_KEY
curl -fsSL https://netvulntool.com/install.sh | bashThe key is never a command-line argument: the bootstrap refuses --license-key (exit 2) so a key cannot land in shell history or the process list. With no key and no terminal the install proceeds unlicensed. See License Provisioning for key formats and tiers.
Automation
Pass --yes (also -y or --non-interactive) together with NV_LICENSE_KEY in the environment. Other install.sh flags pass straight through (--api-url, --client-id, --targets, --service-user, --no-daemon, and so on):
bash
read -rs NV_LICENSE_KEY && export NV_LICENSE_KEY
curl -fsSL https://netvulntool.com/install.sh | bash -s -- --yes --client-id acme--yes makes install.sh run non-interactively, so it also runs its platform fixes in preflight. It never deletes anything (see Cleanup).
Upgrading an existing install
The bootstrap looks for an existing checkout in ~/netvuln-tool and /opt/netvuln-tool. When it finds one it offers an upgrade instead of installing, or takes --upgrade when there is no terminal. The upgrade uses the same git steps as the fleet update command (fetch tags, check out the release tag), then restarts the daemon only if it was running. It never re-runs install.sh and never touches your configs.
- A checkout cloned from another source, or one with local edits to tracked files, is refused (exit 6).
- Nothing changes without a yes: answer the prompt, or pass
--yesor--upgrade. - After an upgrade of an unlicensed install, the bootstrap offers to apply a license key with
scripts/set_license_key.shwhen that script is present in the tree.
Verification and cleanup
After an install or an upgrade the bootstrap runs its own local checks and prints each result, because install.sh treats several failures (a failed portal check, the CLI install) as warnings. A failed check exits 8.
On the nvt path (/opt/netvuln-tool, a Raspberry Pi by default or --service-user nvt), the home clone is a duplicate once the install is verified. If this run created it, the bootstrap offers to remove it, showing the exact path. Pass --cleanup to remove it without asking (this works without a terminal too). A ~/netvuln-tool that existed before the run is never removed.
Flags
| Flag | Purpose |
|---|---|
--version X.Y.Z | Install or move to this release (default: latest) |
--upgrade | Upgrade an existing checkout without asking |
--yes, -y, --non-interactive | Answer yes to prompts and run install.sh non-interactively |
--cleanup | Remove the temporary home copy this run created (nvt path, after verification) |
--help, -h | Show usage |
Any other flag is passed to the release's install.sh.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success, or nothing to do |
| 2 | Usage error, including --license-key |
| 3 | Preflight, version or fetch failure |
| 4 | Target is not a git checkout |
| 5 | Integrity mismatch against the release |
| 6 | Existing checkout refused (another source, or local edits) |
| 7 | install.sh, an upgrade step or the license key script failed |
| 8 | Verification failed |
| 9 | Daemon restart failed after the upgrade (the message gives the commands to go back) |
What you are trusting
curl | bash runs whatever the server returns, so this command trusts TLS to netvulntool.com and gitlab.com. To inspect first, clone the public repository, read it, and run the installer yourself:
bash
git clone https://gitlab.com/netvulntool/netvuln-tool.git
cd netvuln-tool
git checkout <release tag>
bash install.shA release tarball from the project's public releases page works the same way.
Deployment install: install.sh
install.sh (repo root) prepares a host to run scans, either interactively (an analyst laptop) or as an unattended agent. It is idempotent and safe to re-run.
What it does
- Preflight: detects the platform (macOS or Linux) and installs the full scanner toolchain unprompted, skipping any binary already on
PATH. On Linux it runs one batchedapt-get update && apt-get install -y <packages>, falling back to installing each package individually (warning on any that fails) if the batch fails; on macOS it installs the Homebrew-formula subset per formula (WiFi toolsiw,rfkillandnmcliare Linux-only and are only reported on macOS). Pass--minimalto skip all of this and fall back to the old warn-only nmap/jq check with install hints instead. - Service account (Linux only): resolves who the daemon runs as and where the tree lives, either the current user (default) or a dedicated
nvtaccount, always on Raspberry Pi and opt-in elsewhere with--service-user nvt. See Where things live below for the exact paths each choice produces. - Python CLI: installs the
netvulnconsole script (skip with--no-python). On an externally managed interpreter (see PEP 668 below) it builds a virtualenv and links the script into~/.local/bin; elsewhere it runspip install -e .directly. The venv path depends on step 2 (see Where things live). - License key: installs the provided key (mode
600); the destination depends on step 2 (see Where things live). See License Provisioning for key formats and tiers. - Config scaffold: creates a per-engagement config from
templates/report_config.conf.example, filling in the API URL, client ID, and targets you passed; the destination depends on step 2 (see Where things live). The portal URL defaults tohttps://portal.netvulntool.com/api/upload(see Portal URL below). - Systemd daemon (Linux only): installs and enables the
netvuln-daemonservice, but leaves scanning off until a config setsDAEMON_ENABLED=truewithTARGETS(the daemon stays up with scanning disabled and heartbeats once a key is set). As of 4.9.0,install-servicealways renders the unit from explicit--user/--group/--home/--install-dir/--base-dirflags (install.shsupplies them) and refuses to render an implicitUser=rootunit; the daemon runs as the user step 2 resolved (see Where things live) and is granted CAP_NET_RAW (AmbientCapabilities=CAP_NET_RAWon the unit, plus a supplementarysudo setcap cap_net_raw+eipon the nmap binary), so nmap OS fingerprinting (-O) and SNMP/UDP scans (-sU) work without running as root. An nmap package upgrade resets thatsetcapcapability, but this no longer needs a manual fix: the daemon's own scans keep working off the unit'sAmbientCapabilitiesgrant regardless, an apt post-invoke hook reapplies the file capability automatically after everyapt/dpkgrun, and the daemon self-checks the capability at startup and every heartbeat, logging a loud warning and reportingraw_scan_capable: falseif it is ever actually lost. See Daemon Mode for the full picture. On macOS it prints a notice that systemd is Linux-only (uselaunchdor run the daemon in the foreground). Skip with--no-daemon. - Portal verification: checks
/api/healthreachability and sends an authenticated heartbeat to confirm the license key and API URL are valid. - Summary: prints a
pi_validate.sh --jsonreadiness summary and the next steps.
Where things live
Every path above depends on which account the daemon runs as (step 2), decided by --service-user, --pi/--no-pi, or the interactive prompt; see Raspberry Pi for the account itself.
| Path | Default (current user) | nvt path (Raspberry Pi by default, or --service-user nvt) |
|---|---|---|
| Install tree | the checkout you ran install.sh from | /opt/netvuln-tool (owned nvt:nvt) |
| Python venv | ~/.netvuln/venv | /opt/netvuln-tool/venv |
| License key | ~/.netvuln/license.key | /home/nvt/.netvuln/license.key |
| Configs | ~/netvuln-tool/configs/<name>.conf | /opt/netvuln-tool/configs/<name>.conf |
| Daemon runs as | the invoking user | nvt |
PEP 668 and virtualenvs
Raspberry Pi OS (Bookworm and later), Debian 12+, Ubuntu 23.04+ and Homebrew Python mark their system interpreter as externally managed, which makes a system-wide pip install a hard error rather than a warning:
error: externally-managed-environmentinstall.sh detects this and installs into a virtualenv instead, so a stock Pi image needs no manual preparation:
| Path | Purpose |
|---|---|
~/.netvuln/venv | the virtualenv holding the netvuln package |
~/.local/bin/netvuln | symlink to the console script, no sudo required |
If ~/.local/bin is not already on your PATH, the installer says so and prints the line to add:
bash
export PATH="$HOME/.local/bin:$PATH"Debian packages the venv module separately. If the virtualenv cannot be created, install it and re-run:
bash
sudo apt-get install -y python3-venvThe netvuln CLI is optional. The Bash scan pipeline is self-contained, so a Python install that fails leaves scanning fully functional and only costs you the netvuln command.
Flags
| Flag | Purpose |
|---|---|
--license-key <key> | License key to install to ~/.netvuln/license.key (e.g. nvt_pro_<hex>) |
--api-url <url> | Portal upload endpoint. Defaults to https://portal.netvulntool.com/api/upload; pass none for no portal (see Portal URL) |
--client-id <id> | Client identifier injected into the config for portal multi-tenancy |
--targets <spec> | Comma-separated IPs, CIDRs, ranges, or domains for the scaffolded config |
--config-name <name> | Basename for the scaffolded config (see Where things live for the full path) |
--service-user <name> | Run the daemon as a dedicated account (nvt) instead of the current user. Prompted on non-Pi Linux when omitted; automatic (no prompt) on Raspberry Pi |
--pi | Force Raspberry Pi behavior (auto-detected via /proc/device-tree/model otherwise) |
--no-pi | Force non-Pi behavior on a host that looks like a Pi |
--migrate | Delegate to scripts/migrate_to_opt.sh (moves a hand-patched /home/nvt/netvuln-tool install onto the supported /opt/netvuln-tool layout) and exit |
--minimal | Skip the toolchain auto-install in preflight; only check for nmap/jq and print install hints (the pre-#208 behavior) |
--no-daemon | Skip installing/enabling the systemd service |
--no-python | Skip the pip install -e . step (bash-only install) |
--verify-only | Run the portal connectivity + readiness checks only, no install steps |
--full-verify | Run the extended verification (health + authenticated heartbeat + pi_validate) |
--offline | Skip the portal connectivity check (step 7/8). Preflight's toolchain install still runs; use --minimal to skip that too |
--non-interactive, --yes | Assume defaults and never prompt (agent/automation mode); the toolchain install already runs unprompted either way |
-h, --help | Show usage |
Portal URL
--api-url defaults to https://portal.netvulntool.com/api/upload, the hosted portal. The interactive prompt offers it, so Enter accepts it:
Portal upload URL ('none' for no portal) [https://portal.netvulntool.com/api/upload]:The same default applies to --non-interactive runs that pass no --api-url, so an unattended agent is portal-connected out of the box. Three ways to change that:
| You want | Do this |
|---|---|
| A self-hosted portal | Type the URL at the prompt, or pass --api-url <your-portal-host>/api/upload |
| No portal at all | Type none at the prompt, or pass --api-url none. The config gets an empty CONSULTATION_API_URL and step 7 is skipped |
| A portal, but no network calls during install | Pass --offline. The URL is still written to the config; only the verification is skipped |
Because a URL is now always configured by default, step 7 runs on every install rather than being skipped. Uploads still require an API key as well, so a config with a URL and no key does not send anything.
Example: unattended agent install
bash
bash install.sh --non-interactive \
--license-key nvt_pro_<hex> \
--api-url https://portal.netvulntool.com/api/upload \
--client-id acme \
--targets 192.168.1.0/24This installs the CLI, writes the license key, scaffolds ~/netvuln-tool/configs/acme.conf with the URL/client/targets pre-filled, installs the systemd daemon (Linux), verifies portal connectivity, and prints a readiness summary. The daemon runs no scans until you set DAEMON_ENABLED=true in that config, but it stays up with scanning disabled and, once a license key is set, heartbeats so the agent appears in the portal.
Enable scheduled scanning after install
install.sh installs the daemon but does not start scanning. Edit the scaffolded config, set DAEMON_ENABLED="true" with a SCAN_SCHEDULE and TARGETS, then reload the daemon. See Daemon Mode and Scheduling.
Only scan authorized networks
Provisioning targets in a config does not grant authorization. Only scan hosts and networks you are explicitly authorized to assess.
Developer install: setup.sh
The public repository and the download addresses go live with the first public release of 4.10.0; if a link does not resolve yet, the release has not been published.
Use setup.sh when you are working on netvuln-tool itself. The source is public: clone it directly, or download a release tarball and verify it against its checksum. Clone the repository and run setup.sh once:
bash
git clone https://gitlab.com/netvulntool/netvuln-tool.git
cd netvuln-tool
bash setup.shPrefer a release tarball over a git clone? Download and verify it (replace vX.Y.Z with the release you want; /download/latest and /download/latest.sha256 on the same host always resolve to the current release):
bash
curl -Lfo netvuln-tool-vX.Y.Z.tar.gz https://netvulntool.com/download/vX.Y.Z
curl -Lfo netvuln-tool-vX.Y.Z.tar.gz.sha256 https://netvulntool.com/download/vX.Y.Z.sha256
sha256sum -c netvuln-tool-vX.Y.Z.tar.gz.sha256 # Linux
shasum -a 256 -c netvuln-tool-vX.Y.Z.tar.gz.sha256 # macOSThe /download/ addresses resolve to the assets on the GitLab release page at gitlab.com/netvulntool/netvuln-tool/-/releases, where the same files can be fetched directly if an alias is not yet in place.
The tarball extracts into a single top-level netvuln-tool-vX.Y.Z/ directory.
See the open source boundary for the full license and functional boundary.
setup.sh performs a five-step developer bootstrap:
- Configures git hooks (
git config core.hooksPath .githooks) so the pre-commit ShellCheck lint and pre-push test suite run automatically. - Checks linting dependencies (
shellcheck,bats) and prints install hints for any that are missing. - Checks runtime dependencies (
nmap,jq). - Installs the Python orchestrator in editable mode with dev extras (
pip install -e ".[dev]"), putting thenetvulnCLI on your PATH. Unlikeinstall.sh, the developer path does not build a virtualenv for you: on an externally managed interpreter it prints pip's error and the venv command to run instead (python3 -m venv .venv && .venv/bin/pip install -e '.[dev]'). - Verifies the git hooks are executable.
It does not install a license, scaffold an engagement config, or install the systemd daemon; those belong to the deployment path (install.sh).
Dependency check
At any time, verify your environment with:
bash
bash scripts/dependency_check.shThis detects your platform (macOS or Linux) and prints the correct install command for each missing tool: brew install on macOS, apt-get install on Linux. It reports and prompts; it does not batch-install the way install.sh's default preflight does. Useful for a standalone check outside of a full install.sh run, or after --minimal.
Platform validation
For deployment readiness (especially on Raspberry Pi or other edge devices), use the platform validation script:
bash
bash scripts/pi_validate.sh # Run the deployment checks
bash scripts/pi_validate.sh --json # JSON output (used by install.sh's summary)
bash scripts/pi_validate.sh --fix # Attempt to install missing dependenciesIt checks disk space, memory, required tools, permissions, and portal (/api/health) reachability, and can emit JSON for monitoring integration. Combine flags, for example pi_validate.sh --fix --json.
Install snapshot
netvuln_snapshot.sh prints a read-only report of the local install: the host details the portal shows for the agent, where the install lives, the agent identity and license tier, the daemon state, and every file, account, unit and crontab line an uninstall would touch. Run it before an uninstall, or whenever you need to know what is on a host.
bash
# Service-account layout
/opt/netvuln-tool/scripts/netvuln_snapshot.sh
# Current-user layout
~/netvuln-tool/scripts/netvuln_snapshot.sh
# One JSON document, for automation
/opt/netvuln-tool/scripts/netvuln_snapshot.sh --json- It writes nothing, starts and stops nothing, and makes no network call. It may use
sudo -nto read files the service account owns, and never to change anything. - It never prints a key, a token or a full config file. The license appears as its tier prefix only, API-key environment variables show as set or unset, and config files contribute only their
DAEMON_ENABLEDandCLIENT_IDvalues. Credentials embedded in a git remote URL are masked. --install-dir DIRinspects one install when more than one is found.--operator USERnames the account whose home holds the CLI link and crontab, which matters only when you run it as root withoutsudo.- It exits 0 whenever it ran, including when it finds no install. Exit 2 means a bad argument or a missing
jq.
Uninstall
netvuln_uninstall.sh removes an install. It shows a plan first, asks one confirmation, then removes. It copies itself to a private temporary directory before it deletes the install.
By default it is a full removal. What goes depends on the layout:
- Service-account layout: the install directory
/opt/netvuln-tool(sessions, configs, logs and the virtualenv), thenvtaccount and its home/home/nvt(where the license lives), the systemd unit, the sudoers drop-in, the apt hook, the nmap capability, the operator'snetvulnCLI link and the netvuln-tool crontab lines. - Current-user layout:
~/netvuln-tool(sessions, configs, logs and the virtualenv), the whole~/.netvulndirectory (the license and the license cache), thenetvulnCLI link and the netvuln-tool crontab lines. The service-only steps (unit, sudoers drop-in, apt hook, nmap capability, account) are skipped.
It never removes packages, and it never kills a process. It stops the daemon itself (systemctl disable --now on the service layout, the daemon control script on the current-user layout). If processes remain after the stop, step 1 fails and the daemon stays stopped.
bash
# Dry run: print the plan and any blockers, change nothing
sudo /opt/netvuln-tool/scripts/netvuln_uninstall.sh --dry-run
# Real run: shows the plan, then asks you to type yes
sudo /opt/netvuln-tool/scripts/netvuln_uninstall.sh
# Keep a copy of sessions and configs first
sudo /opt/netvuln-tool/scripts/netvuln_uninstall.sh --keep-data /var/tmp/netvuln-exportA service-account host needs sudo (or passwordless sudo) for the plan to be complete: the license, the sessions and the checkout state sit in paths owned by root and nvt. On the current-user layout the same commands run without sudo, from ~/netvuln-tool/scripts/.
- Confirmation. The answer must be the literal text
yes, read from the terminal.--yesskips it, for automation. With no terminal and no--yesthe run exits 2. Anything other thanyesexits 4 and removes nothing. - Privilege. Run a service-account host's uninstall with
sudo. An unprivileged run is accepted only whensudo -nworks without a password (the run then re-runs itself undersudoafter you confirm). When it does not, the run is blocked with exit 2, in a dry run too, and prints thesudocommand to use, because a plan built without those reads would hide the license and the session count. --keep-data DIRexports sessions and configs toDIRbefore anything is removed. The path must be absolute with no.or..component, its parent must already exist, it must be empty or not yet exist, it must not be inside the install directory, and no part of it may be a symlink, and the operator must be able to write to it. The configs in the export drop their license key lines (NV_API_KEY,CONSULTATION_API_KEY,NV_LICENSE_KEY) unless you add--keep-license, which also copies the license file. The export keeps every other setting, including webhook URLs and SMTP settings with the SMTP password, so guard it like a credential.--keep-licenseis only accepted together with--keep-data.--install-dir DIRnames the install to remove. It is required when more than one install is found.--operator USERnames the account whose home holds the CLI link and crontab. It matters when you run as root withoutsudo. Without it, those steps are skipped and reported.--forceremoves a git checkout that is dirty, has unpushed commits, or cannot be read. It overrides that one check and no other.--dry-runprints the plan and any blockers and changes nothing.
Before anything is removed, the run is blocked (exit 2) when any of these holds:
- the checkout is dirty, has unpushed commits, or cannot be read (run with
sudofirst on a service host;--forceoverrides only this) - more than one install is found
- the
nvtaccount does not match what the installer creates - the install directory is unsafe, such as
/, a home directory, or a symlink - the install directory does not carry netvuln-tool's signature files
- the
--keep-datatarget fails the rules above, including a target that is not writable or exists and is not a directory - root is needed and
sudois not available, orsudoneeds a password (run the command withsudo)
If processes are still running after the daemon is stopped, step 1 fails and nothing is deleted. On the service layout that means any process owned by nvt, for example a sudo -u nvt shell, not only the daemon. Stop them yourself and run the command again. Every step resumes, so after a failure fix the cause and re-run.
Anything the uninstaller does not remove is listed under "not handled", in the plan and again after the run, and does not make the run fail:
- Files the installer did not create, such as a hand-copied
~/install_bootstrap.shor~/set_license_key.shin the operator's home, and other paths namednetvulnornvt. - The nmap capability when netvuln's apt hook is gone. The hook is the sign that netvuln set the capability, so without it the capability is not provably netvuln's (
netvuln_daemon_ctl.sh uninstall-serviceremoves the hook and keeps the capability). Remove it withsetcap -rif you want. - A
sessionsorconfigsdirectory that is a symlink. It is reported with its target, never followed, and the data it points to is not removed. The link itself goes with the install directory. - A partial export left by a failed
--keep-datarun, which is never deleted.
The install directory is removed without crossing into another filesystem (GNU rm --one-file-system). If a bind mount or another volume sits under it, step 7 fails and names the path: unmount it and run the command again. macOS rm has no such flag, so there the removal proceeds as before.
Portal deregistration is not part of an uninstall. The agent stops sending heartbeats and goes offline, and an admin removes it on the portal.
Exit codes
| Exit code | Meaning |
|---|---|
| 0 | Clean, nothing installed, or a dry run with no blockers |
| 1 | A step failed; run it again to resume |
| 2 | Blocked, a bad argument, or a refused real run (see below) |
| 3 | Removal finished with leftovers |
| 4 | You declined the confirmation |
A real run refuses with exit 2 when CI, GITEA_ACTIONS, GITHUB_ACTIONS or BATS_TEST_FILENAME is set in the environment, which can surprise you in a pipeline or an automation shell. Unset those variables to run it. --dry-run is not affected.
Next steps
- Quick Start: run your first scan in a few commands.
- Docker: run scans from a container with no host install.
- Raspberry Pi: stand up an always-on scanning appliance.
- Report Configuration: the per-engagement config file in depth.
- Daemon Troubleshooting: fixes for a daemon that fails to start, goes offline, or stops reporting to the portal.
