
Self-hosted network discovery and search engine with continuous port scanning, deep protocol probing across ~100 services, local CVE matching, and full-text search for infrastructure inventory and risk monitoring.
Self-hosted network discovery & search — your own Shodan, on your hardware.
TCP/UDP scanning · ~100 protocol probes · TLS/JARM fingerprints · CVE matching · full-text search · delta tracking · alerts
Quick start · Features · Architecture · Documentation · Production
Important. Scan only networks you own or have written authorization to scan. UltraViolet performs passive service reconnaissance — it does not exploit vulnerabilities.
| Use case | What you get |
|---|---|
| Perimeter & inventory | Continuous discovery of open ports and services across CIDR ranges |
| Infrastructure search | Full-text search over HTTP bodies, banners, TLS, DNS, and CVEs |
| Risk & compliance | Local NVD matching plus CISA KEV and EPSS — no cloud dependency |
| Air-gapped deployments | Offline archive with Docker images, CVE seed, and GeoIP MMDB on disk |
| Change tracking | Deltas between scans, WebSocket events, alerts on saved searches |
Single tenant, one Docker Compose stack, full control over your data.
Discovery
SCAN_ALLOWED_CIDRS with host and port limitsDeep probes (~100 protocols)
robots.txt, security.txt, tech stackEnrichment
CVE & risk
Operations
viewer / operator / admin), JWT + refresh tokens/metrics, optional Grafana profileflowchart TB
Browser["Browser"]
FE["service-frontend<br/>React + nginx"]
API["uv-api<br/>REST · WS · metrics"]
PG[("PostgreSQL 16")]
SCAN["uv-scanner<br/>probe pipeline"]
Browser --> FE
FE -->|"/api"| API
FE -->|"/realtime"| API
API <--> PG
SCAN <--> PG
API -.->|LISTEN/NOTIFY| API
The release UI image proxies /api/ and /realtime to uv-api — single origin, no frontend rebuild per API URL.
| Directory | Purpose |
|---|---|
service-api/ | Go: uv-api (HTTP API, WebSocket, workers) + uv-scanner (pipeline) |
service-frontend/ | React 19 + Vite + RTK — scans, hosts, search, dashboard |
service-documentation-frontend/ | VitePress — user and operator documentation |
service-env/ | docker-compose, secrets, install.sh / upgrade.sh / backup |
Backend development rules: CLAUDE.md.
Requirements: Go 1.25+, Docker Engine ≥ 24, ~4 GB RAM. Production images target Linux amd64.
Beginner path — pull published images with
service-env/docker-compose.registry.yml:
cd service-env
cp env.registry.example .env
# set POSTGRES_PASSWORD, AUTH_JWT_SECRET, AUTH_BOOTSTRAP_PASSWORD
mkdir -p geoip catalog-seed
docker compose -f docker-compose.registry.yml pull
docker compose -f docker-compose.registry.yml up -d
# UI → http://localhost:3000
See Docker Registry in the docs site.
The API/scanner images copy prebuilt binaries from service-api/bin/ (they are not compiled inside Docker). make dev runs make -C service-api build-linux before docker compose … --build.
git clone https://github.com/yakushstanislav/UltraViolet.git
cd UltraViolet/service-env
cp .env.example .env
mkdir -p secrets
openssl rand -hex 32 > secrets/postgres_password
openssl rand -hex 32 > secrets/auth_jwt_secret
cd ..
make dev
| URL | Purpose |
|---|---|
| http://localhost:3000 | UI (API via nginx /api/) |
| http://localhost:8080 | API directly |
| http://localhost:9090/metrics | Prometheus |
Dev bootstrap: admin / admin (only when APP_ENV≠production).
Full guide — VitePress in service-documentation-frontend/docs/:
make docs-dev # → http://localhost:5173
In production, enable the docs profile:
cd service-env && docker compose --profile docs up -d
# → http://localhost:${UV_DOCUMENTATION_PORT:-3002}
Key sections: installation · scanning · API · deployment · offline install.
make dev # build-linux → compose prod + dev override --build
Rebuild Go binaries after backend changes (make -C service-api build-linux), then restart or re-run make dev.
make dev-db # PostgreSQL only on :5432
cd service-api && make build
export LOGGER_NAME=uv-api LOGGER_DEBUG=true
export SERVER_ADDR=0.0.0.0 SERVER_PORT=8080
export METRICS_ADDR=0.0.0.0 METRICS_PORT=9090
export REALTIME_ADDR=0.0.0.0 REALTIME_PORT=8081
export POSTGRES_ADDR=localhost POSTGRES_PORT=5432
export POSTGRES_USERNAME=ultraviolet
export POSTGRES_PASSWORD="$(cat ../service-env/secrets/postgres_password)"
export POSTGRES_DATABASE=ultraviolet
export POSTGRES_SCHEMA_PATH="$(pwd)/deploy/migrations"
export AUTH_JWT_SECRET="$(cat ../service-env/secrets/auth_jwt_secret)"
./bin/uv-api