Skip to content

Setup & Usage Guide

Requirements

Tool Version
Docker 24+
Docker Compose plugin 2.20+
Git any recent version
Go (local dev only) 1.22+
Node.js (local dev only) 20+

The recommended deployment path is Docker Compose. The worker image installs the configured scanner binaries from backend/configs/config.yaml, so you do not need to install ProjectDiscovery tools on the host for normal Docker usage.

Repository Directory

Clone the repository and enter the project directory:

git clone <repository-url>
cd hx0110-EASM

All commands below assume the current working directory is the repository root: hx0110-EASM/.

Quick Start With Docker Compose

  1. Create a local environment file:
cp .env.example .env
  1. Start the platform:
./scripts/up.sh

The script loads .env, validates the worker count, and runs:

docker compose up -d --build --scale worker=$WORKER_REPLICAS

If WORKER_REPLICAS is missing, empty, invalid, or less than 1, the script uses 1 worker.

Docker Compose healthchecks are configured for frontend, API, worker, PostgreSQL, Redis, and MinIO. After startup, inspect health status with:

docker compose ps

See healthchecks.md for the readiness checks and troubleshooting commands.

  1. Open the UI:
http://localhost:3000

Services exposed by the default Compose stack:

URL Purpose
http://localhost:3000 hxEASM UI and /api/ reverse proxy
http://127.0.0.1:3000 hxEASM UI and /api/ reverse proxy
http://<server-ip>:3000 hxEASM UI and /api/ reverse proxy from another machine
http://app.localhost:3000 Still works if it resolves to the frontend
http://<host>:3000/easm-files/... MinIO S3 API path used by presigned file URLs
http://<host>:3000/minio/ Optional dev-only MinIO console when HXEASM_EXPOSE_MINIO_CONSOLE=true

Only frontend Nginx publishes a host port. API, PostgreSQL, Redis, and MinIO are internal Docker-network services. The frontend accepts any Host header, so the application is no longer tied to app.localhost; use localhost, 127.0.0.1, a server IP address, or any hostname that points to the frontend host. Keep storage.public_base_url aligned with the browser-visible host used for presigned file URLs.

Persistent Host Data

Docker Compose stores hxEASM runtime data under the host directory:

~/.hxeasm/data/
├── postgres/
├── redis/
├── minio/
├── nuclei/
└── backups/

These paths are bind-mounted into the containers instead of Docker named volumes. This means data survives container removal, image rebuilds, upgrades, and docker compose down -v. Docker can remove containers, networks, and named volumes, but it will not delete these host files. Data is removed only when you explicitly delete files under ~/.hxeasm/data.

Run scripts/init-data-dirs.sh to create the directory structure manually, or use ./scripts/up.sh, which runs it automatically before starting containers. If you previously used Docker named volumes such as postgres_data, redis_data, minio_data, or nuclei_home, migrate them manually before deleting old volumes.

Optional Nginx Basic Auth

For public-facing deployments, you can add an extra browser Basic Auth prompt at the frontend Nginx layer. This is disabled by default and does not replace hxEASM users, JWTs, API keys, or RBAC.

Generate a bcrypt htpasswd line:

htpasswd -nbB hxeasm 'strong-password'

Set the generated user:hash line in .env:

HXEASM_NGINX_BASIC_AUTH_ENABLED=true
HXEASM_NGINX_BASIC_AUTH_HTPASSWD='hxeasm:$2y$05$...'

Restart the frontend container:

docker compose up -d --build frontend

If Basic Auth is enabled without HXEASM_NGINX_BASIC_AUTH_HTPASSWD, the frontend container exits during startup. Do not commit real htpasswd hashes. Basic Auth protects the web app shell through the single public Nginx entrypoint regardless of whether you open it with localhost, 127.0.0.1, a server IP address, or another hostname. /api/ remains protected by hxEASM Bearer tokens and backend RBAC, because applying Basic Auth there would conflict with the application Authorization: Bearer ... header. Presigned file downloads are not Basic Auth protected by default.

Worker Count

Set worker replicas in .env:

WORKER_REPLICAS=3

Then start or restart with:

./scripts/up.sh

Operational notes:

  • More workers allow multiple scan jobs to run in parallel.
  • Each worker runs plugin jobs and needs access to PostgreSQL, Redis, MinIO, and configured scanner binaries.
  • Keep worker count conservative on small hosts because scanners such as nuclei, nmap, katana, and screenshot collection can be CPU, memory, and network intensive.
  • You can also scale manually with docker compose up -d --scale worker=3, but scripts/up.sh is the preferred project command.

Test Mode

For scanner mock output, set this in .env:

TEST_MODE=true

Then run:

./scripts/up.sh

Docker Compose maps TEST_MODE into EASM_TEST_MODE for API and worker containers. Test mode is useful for development or demos because plugins return deterministic mock data instead of executing external scanner binaries.

For real scans, use:

TEST_MODE=false

Configuration Files

Main backend configuration lives in:

backend/configs/config.yaml

Important sections:

  • app.version: displayed by the app and Update Center.
  • storage: S3/MinIO artifact storage.
  • updates: Central Update API release metadata checks.
  • research: hxresearch mount paths.
  • scan_profiles: config-driven scan profile definitions.
  • tools: scanner binary installation configuration for workers.

After changing backend/configs/config.yaml, restart API and workers:

./scripts/up.sh

See Configuration for the full config reference.

First-Time Setup Flow

  1. Open http://localhost:3000 or another hostname/IP address that points to the frontend.
  2. Complete the First Administrator Setup flow.
  3. Create an organization.
  4. Add scope, for example domain = example.com.
  5. Approve the scope as an admin.
  6. Go to Scans, choose an approved scope and scan profile, then start a scan.
  7. Watch scan jobs, assets, vulnerabilities, files, and exposure changes populate.
  8. Use Asset Graph, Assets, Vulnerabilities, Files, Changes, and Reports to review results.

After the first admin exists, later registrations are created as pending users until an admin approves them.

Two-factor authentication is disabled by default. Administrators can enable optional or required 2FA after setup from:

Settings -> Administration -> Two-Factor Authentication

Email OTP requires SMTP configuration. Authenticator app enrollment works with Google Authenticator-compatible TOTP apps.

API Authentication

Protected endpoints require a Bearer token:

curl -X POST http://localhost:3000/api/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"admin@example.com","password":"password"}'

curl http://localhost:3000/api/v1/organizations \
  -H "Authorization: Bearer <access_token>"

Or use an API key:

curl http://localhost:3000/api/v1/organizations \
  -H "Authorization: Bearer easm_<key>"