2026-07-07 · 13 min read · Kendra Mazara
Leer en español →Connect Your First Machine: The Agent in 10 Minutes
Install the Achilles agent and make your first machine appear on the dashboard — Windows, Linux, or macOS, in 3 steps.
Series: Getting Started with Project Achilles — Part 2 of 6
Difficulty: Beginner 🟢
TL;DR
- The "agent" is a small program (~8 MB) you install on every machine you want to monitor
- One time only, you publish the agent binary on your server (
Settings → Agent → Build Binary); after that you enroll as many machines as you want - Enrollment takes 3 steps: generate a token → copy the command → run it on the machine
- Works on Windows, Linux, and macOS
- Once installed, the machine shows up as "online" in the dashboard in under 1 minute
- No ports to open, no firewalls to configure — the agent connects outbound (like a browser)
- If your server lives on a remote IP/domain (not
localhost), the agent requires HTTPS — you get it with a domain + Caddy, or with a static-domain tunnel (ngrok/Cloudflare). See the HTTPS section below
What Is the Agent?
The Achilles agent is a small program that lives on every machine you want to protect and validate. It does three things:
- Tells Achilles it's alive (every 60 seconds it sends an "I'm still here")
- Runs the attack simulations when its turn comes
- Reports the results back to the dashboard
It's a lightweight program. It doesn't consume noticeable resources. It doesn't affect the machine's performance. And to uninstall it, one command and done.
Prerequisite: Publish the Agent Binary (one time only)
Before you can enroll machines, your Achilles server needs at least one agent binary published for each platform you plan to use (Windows, Linux, macOS). The install command downloads that binary from your server — if none is published, the download fails with a 404: "No version available for this platform" error.
It's an administrator step you do once per platform (and repeat only when you release a new agent version). There are two ways to do it — use whichever works for you.
Option A — Build on the server (recommended)
From the dashboard:
Settings → "Agent" tab → "Build Agent Binary" card
Fill in the three fields and click Build Binary:
Version: 0.5.0 ← version number (the form suggests the next one)
Operating System: Windows ← Linux | Windows | macOS
Architecture: x86_64 (amd64) ← x86_64 (amd64) | ARM64
[ 🔨 Build Binary ]
The server cross-compiles the agent from source (it can take up to a minute). When it finishes, the binary appears in the "Registered Versions" card on the same page, ready to download.
If you deployed with the DigitalOcean installer (
scripts/deploy-do/), the droplet already has Go installed automatically (the deployer's Phase 10 does it), so "Build from Source" works out of the box — you don't need to install Go by hand. On servers where you set up Achilles yourself, the build requires Go (≥ the version inagent/go.mod) installed on the backend; if it's missing, the build fails withCommand failed: go ... spawn go ENOENTand you'll have to install it or use Option B.
Repeat the build for each platform you plan to enroll. If you have Windows and Linux machines, build
Windows / amd64andLinux / amd64separately. The ARM64 architecture only applies to servers with ARM CPUs (some cloud VMs, Apple Silicon Macs, Raspberry Pi).
Quick check: in the "Registered Versions" card you should see at least one row with your version, OS, and architecture. If it's empty, the build didn't complete — check the error message in the build card.
Option B — Build locally and upload (if the server build fails)
The server's "Build from Source" can fail for two reasons: on low-RAM servers (for example, a 1 GB droplet), Go's cross-compilation exhausts memory and the process dies; or if Go isn't installed on the backend (manual setup, without the DigitalOcean deployer) you'll see a spawn go ENOENT error. In either case the alternative is to compile the binary on your machine and upload it ready-made.
1) Compile the agent on your machine (you need Go installed, version ≥ the one in agent/go.mod):
cd agent
# Windows (x86_64)
make build-windows # produces dist/achilles-agent-windows-amd64.exe
# Other platforms, as needed:
make build-linux # dist/achilles-agent-linux-amd64
make build-darwin-arm64 # dist/achilles-agent-darwin-arm64 (Apple Silicon Mac)
make build-darwin-amd64 # dist/achilles-agent-darwin-amd64 (Intel Mac)
make build-all # all four platforms at onceThe version number comes from the
Makefile(theVERSION := ...line) — write it down, you need it when uploading.
2) Upload the binary in the dashboard:
Settings → "Agent" tab → "Upload Agent Binary" card
Version: 0.6.2 ← the same one from the Makefile
Operating System: Windows ← Linux | Windows | macOS
Architecture: x86_64 (amd64) ← x86_64 (amd64) | ARM64
File: achilles-agent-windows-amd64.exe
[ Upload ]
Just like Option A, it must show up in "Registered Versions".
Signing: a binary built this way ships unsigned unless you use
make sign-windows(requires a configured certificate). An unsigned agent can be blocked by Windows Defender on the target machine — see the troubleshooting at the end of this post.
Once the binary is published (via either option), continue with the 3 enrollment steps.
Prerequisite: HTTPS (if your server is not local)
For security, the agent refuses to enroll against a remote server over plain HTTP. Enrollment sends credentials (the token and the agent key), and the agent won't send them unencrypted. Its rule is:
http://localhost:3000 or http://127.0.0.1:3000 → allowed (same-machine testing only)
http://<remote-IP-or-domain>:3000 → REJECTED
https://<your-domain> → allowed
If your Achilles server lives on a cloud IP or VM (not your localhost), you need HTTPS or enrollment fails with:
refusing to enroll: server URL "http://203.0.113.10:3000" uses plaintext HTTP
to a remote host; use https:// or connect to localhost for development
There are two ways to put HTTPS on your server — choose based on whether you have a domain.
Option A — Domain + Caddy (recommended for production)
You point an A record of your domain (or a subdomain, e.g. achilles.yourdomain.com) at the server's IP, and Caddy obtains the Let's Encrypt certificate automatically. This is what the DigitalOcean deployer does (scripts/deploy-do/, caddy_tls phase), so if you deployed with it you already have HTTPS and a stable URL without touching anything. The agent talks to the server directly — no intermediate processes to babysit.
Option B — Tunnel with a static domain (no domain of your own)
If you don't have a domain, a tunnel gives you a public https:// URL pointing at your backend (localhost:3000 inside the server):
- ngrok (free): reserve 1 static domain in your account (
https://something.ngrok-free.dev) and run it as a systemd service on the server so it survives reboots. The URL never changes. - Cloudflare Tunnel:
cloudflared tunnel --url http://localhost:3000gives you atrycloudflare.comURL instantly (no account), but it's ephemeral (changes on every restart) — only useful for a quick test. For something stable use a named tunnel (requires a domain on Cloudflare).
On networks that block UDP,
cloudflaredfails to connect over QUIC — force TCP with--protocol http2.
Important: configure AGENT_SERVER_URL
Even if you pass --server https://... in the command, the server hands the agent its own public URL during enrollment. That URL comes from the backend's AGENT_SERVER_URL environment variable. If it still says http://..., the agent rejects it with:
server returned insecure URL: server URL "http://203.0.113.10:3000" uses plaintext HTTP...
The fix: on the backend, set AGENT_SERVER_URL to your https:// URL and restart it. With Docker Compose:
# on the server, inside the project folder
sed -i 's|^AGENT_SERVER_URL=.*|AGENT_SERVER_URL=https://your-url|' backend/.env
docker compose up -d --force-recreate backendWith the DigitalOcean deployer this already points at your domain. The dashboard also uses this variable to generate the install commands, so once it's set correctly, the commands you copy from the panel already come with the right https URL.
Step 1: Generate an Installation Token
The token is a unique code that tells the agent "you belong to this Achilles account".
From the dashboard:
Endpoints → Agents → "Enroll Agent" button (top right)
A form with two fields unfolds:
TTL (hours): 24 ← how many hours the token lives
Max Uses: 1 ← how many machines can use it
[ Generate Token ]
Leave the defaults (24 hours, 1 use) and click Generate Token.
The dashboard immediately shows the token and ready-to-copy install commands, one per platform. You don't need to download anything separately.
Step 2: Copy and Run the Command
When you generate the token, the dashboard shows the commands with the token and your server URL already filled in. You just copy the one for your platform and run it on the target machine.
Windows
Open PowerShell as Administrator and run the command shown under "Windows (PowerShell)":
Invoke-WebRequest -Uri "http://<your-server>/api/agent/download?os=windows&arch=amd64" `
-OutFile achilles-agent.exe; `
.\achilles-agent.exe --enroll <TOKEN> --server http://<your-server> --installNot sure what PowerShell as Administrator is? Right-click the Start menu → "Windows PowerShell (Admin)".
The command downloads the agent, registers it to your account, and installs it as a Windows service with automatic startup, all in one step.
Linux
Run the command under "Linux (amd64)" or "Linux (arm64)" depending on your architecture:
curl -fSL "http://<your-server>/api/agent/download?os=linux&arch=amd64" \
-o achilles-agent && \
chmod +x achilles-agent && \
sudo ./achilles-agent --enroll <TOKEN> --server http://<your-server> --installmacOS
Run the command under "macOS (Apple Silicon)" or "macOS (Intel)":
# Apple Silicon (M1/M2/M3)
curl -fSL "http://<your-server>/api/agent/download?os=darwin&arch=arm64" \
-o achilles-agent && \
chmod +x achilles-agent && \
sudo ./achilles-agent --enroll <TOKEN> --server http://<your-server> --install
# Intel
curl -fSL "http://<your-server>/api/agent/download?os=darwin&arch=amd64" \
-o achilles-agent && \
chmod +x achilles-agent && \
sudo ./achilles-agent --enroll <TOKEN> --server http://<your-server> --install
<your-server>is the URL you configured in QS-01:
- Local install:
http://localhost:3000- Remote server:
https://<your-domain>orhttps://<your-tunnel-url>— it must behttps(see the HTTPS section above). Barehttp://<IP>:3000only works if the agent runs on the same machine as the server.The dashboard fills this in automatically in the commands it shows (from
AGENT_SERVER_URL) — just copy and paste.
Step 3: Verify It Appeared in the Dashboard
Go back to the dashboard and open Endpoints → Agents:
AGENTS 1 online
Hostname System Version IP Status
─────────────────────────────────────────────────────────
MY-PC-01 Windows 1.4.2 192.168.1.45 🟢 Online
There it is! The machine shows up less than 60 seconds after installation.
If it doesn't appear within 2 minutes, check the troubleshooting section at the end of this post.
What Information Does Achilles See About My Machine?
A fair question. The agent reports:
✅ Machine name (hostname)
✅ Operating system and version
✅ IP address
✅ Installed agent version
✅ Results of executed tests (exit code + output)
❌ Does NOT report files or documents
❌ Does NOT report passwords or credentials
❌ Does NOT have access to your email or applications
❌ Does NOT record your screen or keystrokes
The agent only runs the tests you assign to it and reports whether they were detected or not.
Adding More Machines
Once you've seen it work on the first one, the process for the rest is identical:
- Generate a new token (each token has
Max Uses: 1by default) - Copy the command for that platform
- Run it on the target machine
- Repeat
For a large fleet (20+ machines), you can raise Max Uses when generating the token — one token then serves several machines without generating one per machine. Handy if you deploy with Ansible, SCCM, or similar.
Managing Your Machines
From Endpoints → Agents you can view each machine's detail:
Click on "MY-PC-01"
┌──────────────────────────────────────────────────────┐
│ MY-PC-01 🟢 Online │
├──────────────────────────────────────────────────────┤
│ System: Windows 11 Pro │
│ IP: 192.168.1.45 │
│ Agent: v1.4.2 │
│ Online since: 3 minutes ago │
├──────────────────────────────────────────────────────┤
│ Test history: (empty — you haven't run any yet) │
└──────────────────────────────────────────────────────┘
From here you can also:
- Unassign the machine if you no longer want to monitor it
- Force an agent update when a new version is available
- View the history of every test executed
Troubleshooting: If It Doesn't Show Up
The machine doesn't appear after 2 minutes:
Most common cause: the agent can't reach the Achilles server
Windows — check the service:
Get-Service AchillesAgent
→ If Status: Stopped, the service didn't start
View logs:
Get-EventLog -LogName Application -Source AchillesAgent -Newest 10
Linux — check the service:
systemctl status achilles-agent
macOS — check the service:
sudo launchctl list | grep achilles
Usual cause: the server URL is wrong, or a firewall is blocking
port 3000 between the machine and the Achilles server.
The download fails with "404: No version available for this platform":
Two possible causes:
1) You haven't published the binary for that platform yet.
Go to the prerequisite at the start of this post and publish it.
2) Wrong ARCHITECTURE: you published, say, windows/arm64
but the machine requests windows/amd64 (the command carries ?arch=amd64).
Most Windows machines/servers are x86_64 (amd64);
ARM64 is rare. In "Registered Versions" check that the row
matches BOTH the OS and the architecture in the command.
To find the target Windows machine's architecture:
echo $env:PROCESSOR_ARCHITECTURE (AMD64 → amd64 ; ARM64 → arm64)
Verify the correct row appears in "Registered Versions" before retrying.
The server build fails with "504" (timeout) or the process dies:
Low-RAM server (e.g. a 1 GB droplet): Go's cross-compilation
exhausts memory and the reverse proxy cuts off with a timeout (504).
Fix: compile the binary on YOUR machine and upload it (Option B of
the prerequisite) — it skips the server build entirely:
cd agent && make build-windows
→ Settings → Agent → Upload Agent Binary
(Optional: adding swap to the server lets the server build
complete, but on 1 GB you're better off with local build + upload.)
Enrollment fails with "refusing to enroll: ... plaintext HTTP" or "server returned insecure URL":
The agent requires HTTPS for remote servers. This is NOT fixed on the
target machine — it's fixed on the server. See the
"Prerequisite: HTTPS" section of this post:
- Put HTTPS on the server (domain + Caddy, or a static-domain tunnel)
- And set AGENT_SERVER_URL=https://... on the backend, then restart it
The --allow-insecure flag does NOT help here (it only relaxes
certificate verification on https URLs, it does not allow plain http).
The token says "invalid" or "expired" (HTTP 401):
Tokens expire per their TTL and are single-use by default
(Max Uses: 1). Careful: an attempt that reaches the server but fails
AFTERWARDS (e.g. the agent rejects the insecure URL) can still consume
the use. Generate a new one and use it right away:
Endpoints → Agents → "Enroll Agent" → Generate Token
In PowerShell the command "splits" (Missing argument for OutFile / --server, or ".\agent.exe not recognized"):
When pasting very long single-line commands, some terminals insert
a line break in the middle and break it. Fixes:
- Download with curl.exe (included in Windows 10/11), it's shorter:
curl.exe "https://<your-server>/api/agent/download?os=windows&arch=amd64" -o agent.exe
- And enroll using variables on short lines (they don't split):
$token = "acht_..."
$server = "https://<your-server>"
.\agent.exe --enroll $token --server $server --install
The agent was online and suddenly disconnected (after the server URL changed):
The agent stores the server URL it received when enrolling. If that URL
changes (typical with an EPHEMERAL tunnel like trycloudflare, which
changes on every restart), the agent is left talking to a dead URL.
Fix: use a STABLE URL (domain + Caddy, or an ngrok static domain)
and re-enroll against the new URL, on the target machine:
.\agent.exe --uninstall
$token = "acht_<new-token>"
$server = "https://<stable-url>"
.\agent.exe --enroll $token --server $server --install
Windows Defender blocked the executable:
This can happen because it's a new binary without a recognized signature.
Options:
1. Add a Defender exclusion for the folder where you saved the agent
2. Or use the signed version — requires configuring a certificate in
Settings → Tests → Certificates (covered in QS-04)
Note: Defender blocking the unsigned agent is itself useful
information — it means your defense detects unsigned binaries.
Key Takeaways
✅ 3 steps: generate a token → copy the command from the dashboard → run it on the machine ✅ The dashboard generates ready-to-copy commands with the token and URL already filled in ✅ The machine appears in the dashboard in under 60 seconds ✅ Works the same on Windows, Linux, and macOS ✅ The agent doesn't access your personal data or files
Next Post
QS-03: "A First Look at the Dashboard"
You now have a machine connected. We explore the Achilles dashboard: what each module shows and how to find your way around before running your first test.