Getting Started¶
In this tutorial, you install SPOT on a new host and analyze your first email. By the end, SPOT runs with its rules and NLP analyzers, and you have read a verdict in the dashboard, from the command line and through the API. It takes about half an hour, most of it spent pulling images.
Before you start¶
You need:
- a Linux host with 4 GiB of memory and 20 GiB free for Docker, where ports 80 and 443 are free;
- Docker Engine 25.0.4 or later, Docker Compose 2.24 or later, git, and
jqfor the API step; - a user that can run
docker: root, or a member of thedockergroup. The steps install SPOT in/opt/spot, as the other pages assume: as another user than root, create it first withsudo install -d -o "$USER" /opt/spot; - a domain for SPOT,
spot.example.comon this page, with DNS records that point it andapi.spot.example.comat the host.
Let's Encrypt issues the certificates when the host is reachable from the internet. For an evaluation on a private network, entries in /etc/hosts work too: Traefik then serves a self-signed certificate, your browser warns about it, and the curl commands below need -k (see Local DNS and ACME).
1. Install SPOT¶
Clone the spot repository, check out its latest release (main is development), then run setup from its deploy/ directory. Install from deploy/, never from the repository's root: the docker-compose.yml there is the development stack.
cd /opt
git clone https://codeberg.org/SPOT_Project/spot.git
cd spot
git checkout --detach "$(git describe --tags --abbrev=0)"
cd deploy
scripts/spot-cli setup --profile minimal --domain spot.example.com \
--acme-email ops@example.com --admin-email admin@example.com
Run on a terminal without options, scripts/spot-cli setup asks for each, the profile first, and prints this line before it starts.
setup checks the host and lists every problem it finds, with its fix, before it changes anything. Then it writes .env with every secret generated, starts SPOT and installs the minimal profile: analyzer-rules, analyzer-nlp and their workflow, minimal-workflow, which becomes the default. Last, it analyzes a test email, and fails unless the verdict is a real one: a class other than unknown, with every analyzer answering.
When it succeeds, it ends with:
[setup] SPOT runs with the minimal profile, set up in 14 min 2 s
[setup] Dashboard: https://spot.example.com
[setup] Admin: admin; its password is SPOT_ADMIN_PASSWORD in .env
[setup] Back up with spot-cli backup
The standard and full profiles add analyzer-llm on an NVIDIA GPU (Profiles). The GPU variant they run has only passed docker compose config: it has not run on a GPU host yet. Run every command below from /opt/spot/deploy.
2. Sign in to the dashboard¶
setup never prints the admin's password: it is SPOT_ADMIN_PASSWORD in /opt/spot/deploy/.env. Open the file in an editor and read it there, rather than printing it on your terminal.
Open https://spot.example.com and sign in as admin with it. The Analyses page lists one analysis: setup's test email, with its verdict and its score.
3. Analyze an email from the command line¶
Save this message as phish.eml. It is a textbook phishing attempt: a sender that spoofs PayPal with a lookalike domain (paypaI.com, with a capital I) and a link that harvests passwords.
cat > phish.eml <<'MESSAGE'
From: PayPal Security <security@paypaI.com>
To: user@example.com
Subject: URGENT: Verify Your Account
Date: Thu, 15 Jan 2026 10:00:00 +0000
Message-ID: <test@example.com>
Your account is limited. Click here within 24 hours to verify your password:
http://paypaI.com/verify
MESSAGE
Submit it and wait for its verdict. setup signed the CLI in as the admin, so no login is needed:
The CLI sees the directory you run it from, read-only: -f phish.eml reads ./phish.eml, and -f - reads the message from standard input. It prints the job, then its verdict once the workflow has decided. Your score may differ:
Submitted; job_id = 3f0e7c1a-..., email_id = 9b2d4e6f-...
job_id 3f0e7c1a-...
status completed
verdict suspicious
score 64
decided_by method:weighted_mean
workflow minimal-workflow
subject URGENT: Verify Your Account
sender security@paypaI.com
Add --verbose to scripts/spot-cli analyze status <job_id> to see the signals behind the verdict. If the CLI answers Not authenticated, its session has expired: sign in again with scripts/spot-cli auth login.
4. Analyze it through the API¶
Scripts and mail tools call the API at https://api.spot.example.com. Trade the admin's credentials for an access token. read -rs keeps the password off the screen and out of your shell history:
DOMAIN=spot.example.com
read -rs -p 'Admin password: ' password; echo
TOKEN=$(printf '%s' "$password" | curl -s https://api.$DOMAIN/auth/token \
--data-urlencode username=admin --data-urlencode password@- | jq -r .access_token)
Submit the raw message. SPOT parses and stores it, queues its analysis and answers at once with a job id:
JOB_ID=$(curl -s https://api.$DOMAIN/api/v1/analyze \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: message/rfc822" \
--data-binary @phish.eml | jq -r .job_id)
Read the job until its status is completed or failed, a few seconds later:
curl -s -H "Authorization: Bearer $TOKEN" https://api.$DOMAIN/api/v1/analyze/$JOB_ID \
| jq '{status, verdict, score, decided_by, workflow_id}'
{
"status": "completed",
"verdict": "suspicious",
"score": 64,
"decided_by": "method:weighted_mean",
"workflow_id": "minimal-workflow"
}
The Analyses page of the dashboard now lists your two analyses.
5. Read the verdict¶
Every analysis ends with one verdict, whichever way the email came in:
| Verdict | Meaning |
|---|---|
malicious | An attack: phishing, fraud, malware |
suspicious | Likely harmful: worth a review |
spam | Unwanted, not an attack |
benign | Nothing found |
unknown | SPOT could not decide: no analyzer answered, a required one did not, or the job failed. Never read it as benign |
scoreis 0 to 100: how likely the email is malicious.decided_bysays what decided: a decisive signal (signal:<name>), the workflow's method (method:<name>), or why the verdict is unknown (required_unknown,all_unknown,failed).signalsare the evidence behind the verdict, strongest first. Each names the analyzer that emitted it, its weight in score points, and where it was found in the email.
minimal-workflow runs analyzer-rules and analyzer-nlp at once and decides by the weighted mean of their scores: 80 or more is malicious, 50 or more suspicious. Workflows explains how a workflow turns the analyzers' answers into a verdict.
Next steps¶
You now have a running SPOT that analyzes the emails you submit. From here:
- How SPOT works explains the pipeline end to end.
- Mail integration connects your mail server, so SPOT sees every inbound message.
- Backup and restore sets up the nightly backup. Keep a copy of
.envapart: its keys protect the stored data. - Operator guide is the dashboard's playbook.
- API and spot-cli cover every call and command.