SPOT Platform Deployment¶
Deploy SPOT (Spear-Phishing Overwatching Tool) on your server with automatic HTTPS.
Analyzers Required
SPOT requires external analyzer services to perform email analysis. The core platform provides orchestration only - without analyzers, all analysis jobs will fail with errors like:
No URL configured for analyzer: analyzer-nlpOnly 0 analyzers succeeded, minimum required: 2
See Installing plugins below for installation instructions.
Prerequisites¶
| Requirement | Version | Check |
|---|---|---|
| Docker | 20.10+ | docker --version |
| Docker Compose | 2.0+ | docker compose version |
| Git | 2.0+ | git --version |
A public domain pointed at the server is recommended for production (it's what lets Traefik issue real Let's Encrypt certificates), but strictly optional. For an evaluation install you can set DOMAIN=spot.local (or any non-public TLD) in .env, add a matching entry to /etc/hosts, and Traefik will fall back to its built-in self-signed cert — see the local DNS note under Quick Start.
System Requirements: 2GB RAM minimum (4GB recommended), 20GB disk space.
Quick Start¶
# Clone this repository
cd /opt
git clone https://codeberg.org/SPOT_Project/deploy.git spot
cd spot
# Configure domain and secrets
cp .env.example .env
vim .env # Set all required variables
# Start SPOT
docker compose up -d
Docker Desktop on macOS: share /opt/spot
On Linux servers (the supported deployment target) this Just Works. On macOS — useful for an evaluation install — Docker Desktop only shares the user's home directory by default, so the api-gateway's bind-mount of ./docker-compose.yml (used by the System Updates page to detect compose drift) fails with mounts denied: The path /opt/spot/docker-compose.yml is not shared from the host. Two fixes:
- Add
/opt/spotto Docker Desktop -> Settings -> Resources -> File Sharing and Apply & Restart, or - Clone the repo under
~/spotinstead of/opt/spot(Docker Desktop already shares$HOME). All other commands in this guide work the same; just substitute the path.
Production deployments belong on Linux; the macOS path is for quick evaluation only.
Local DNS (.local, .test, .localhost) and ACME
For an evaluation install pointed at a non-public domain (e.g. DOMAIN=spot.local resolved via /etc/hosts), Let's Encrypt refuses to issue with urn:ietf:params:acme:error:rejectedIdentifier :: Domain name does not end with a valid public suffix (TLD). Traefik logs the rejection on every router (traefik.${DOMAIN}, api.${DOMAIN}, the dashboard) and falls back to its built-in self-signed certificate, so the stack still serves over HTTPS — just expect a browser cert warning and the ACME error lines in docker compose logs traefik. Both are cosmetic on a non-public TLD; they go away once DOMAIN resolves to a real, publicly reachable name.
DNS Setup¶
Before starting, create DNS A and/or AAAA records pointing to your server:
| Record | Example |
|---|---|
DOMAIN | spot.example.com -> 1.2.3.4 |
api.DOMAIN | api.spot.example.com -> 1.2.3.4 |
Traefik will automatically obtain Let's Encrypt certificates.
Using self-signed certificate
If the application is not publicly reachable, Traefik will not be able to generate Let's Encrypt certificate and will fall back to using self-signed certificate.
Verify Installation¶
# Check services
docker compose ps
# Expected: 9+ services, all healthy
# spot-traefik
# spot-postgres
# spot-redis
# spot-rabbitmq
# spot-api-gateway
# spot-analyzer-orchestrator
# spot-mail-orchestrator
# spot-web-dashboard
# spot-knowledge
# ...
# Test API (replace with your domain)
curl https://api.spot.example.com/health
# Access Dashboard
# Open https://spot.example.com
Create Admin User¶
On first start, create an admin user by setting these in .env:
SPOT_BOOTSTRAP_ADMIN=true
SPOT_ADMIN_USERNAME=admin
SPOT_ADMIN_PASSWORD=your_secure_password_12chars+
SPOT_ADMIN_EMAIL=admin@example.com
If you change this after having created the stack, simply recreate the api-gateway:
Installing plugins¶
Required for Email Analysis
The SPOT platform is an orchestration layer that coordinates plugins. Without at least two analyzer plugins installed, no email analysis can be performed. Mail retriever and context provider plugins are optional.
SPOT has three kinds of plugins, all installed the same way:
| Kind | Purpose |
|---|---|
analyzer | Produces the phishing verdict. |
context_provider | Enriches emails with organisational data before analysis. |
mail_retriever | Pushes inbound mail into the platform. |
The recommended way to install a plugin is from the dashboard's catalog. The CLI / manual flow is documented further down as a fallback for air-gapped or scripted deployments.
Recommended: install from the dashboard¶
The official plugins are published on Docker Hub under the spotproject user (mirrored from Codeberg's SPOT_Project organisation). A fresh deployment seeds the Docker Hub source automatically on first start, so the catalog is populated as soon as the api-gateway is up ; no manual source registration and no auth required.
To install a plugin:
- Sign in to the dashboard as an admin.
- Go to Plugins -> Catalog.
- Pick a plugin (e.g.
analyzer-nlp), open its detail page, click Install. - SPOT pulls the container, registers the plugin in
spot.yaml, applies its default settings, and starts it. The plugin then appears under Plugins -> Installed with a status chip.
Disabling the default source
The seed only runs when the source registry is empty, so deleting or replacing the default source from the UI is permanent. To skip the seed entirely on a fresh install, set SPOT_BOOTSTRAP_DEFAULT_PLUGIN_SOURCE=false in .env before the first start (typical for air-gapped deployments or operators using a custom registry).
For day-to-day plugin operations (updates, settings, uninstall), see the dashboard's Operator guide.
Bundled official plugins
| Plugin | Kind | Description |
|---|---|---|
analyzer-nlp | analyzer | NLP-based analysis (DistilBERT, NER). |
analyzer-llm | analyzer | LLM-based analysis via Ollama. |
analyzer-rules | analyzer | Rule-based contextual analysis. |
provider-employee-dir | context_provider | LDAP / Entra ID employee directory enrichment. |
retriever-smtp | mail_retriever | Postfix content_filter integration. See Mail integration. |
Manual fallback (not recommended)¶
Use this only if the dashboard install is not an option
Manual install is for air-gapped deployments, custom registries, or pinning a plugin to a specific image tag outside the catalog. The dashboard flow is preferred because it tracks the install in spot.yaml, applies the plugin's settings schema, and integrates with update / uninstall.
The orchestrator finds plugins through the plugins: tree in core/config/spot.yaml. To add a plugin manually, edit that file:
Then run the analyzer container yourself on the spot-network so the orchestrator can reach it:
docker run -d --name analyzer-nlp \
--network spot-network \
--restart unless-stopped \
spotproject/analyzer-nlp:latest
The orchestrator re-reads spot.yaml per job, so no restart is needed.
Verify¶
The dashboard's Health page lists every installed plugin and its current status. From the command line:
A healthy install logs the analyzer URL on first job. No URL configured for analyzer means the entry under plugins.analyzers.<name> is missing or its enabled flag is false.
Related Documentation¶
| Project | Description | Link |
|---|---|---|
| SPOT Core | Platform architecture, CLI, API reference | Core Documentation |
| SPOT SDK | Analyzer development, API contracts, SDK usage | SDK Documentation |

