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
- Create a local environment file:
cp .env.example .env
- 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.
- 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, butscripts/up.shis 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
- Open
http://localhost:3000or another hostname/IP address that points to the frontend. - Complete the First Administrator Setup flow.
- Create an organization.
- Add scope, for example
domain = example.com. - Approve the scope as an admin.
- Go to Scans, choose an approved scope and scan profile, then start a scan.
- Watch scan jobs, assets, vulnerabilities, files, and exposure changes populate.
- 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>"