Skip to content

Deployment

blackbuble edited this page Oct 30, 2026 · 1 revision

Deployment Guide — Local Environment

Complete guide to deploying PentestAI in a local environment.


Option 1: Bare Metal (Legacy, explicit opt-in)

Suitable for: development only. Docker is the supported runtime; bare metal installs security tools on the host.

PENTESTAI_ALLOW_LOCAL_TOOLS=1 bash install.sh

Without that variable, install.sh runs in Docker-only mode and skips host security tools, Python dependencies, and Node docx.

# 1. Clone or extract the source
cd pentestai/

# 2. Install security tools
sudo bash install.sh

# 3. Configure
cp .env.example .env
nano .env
# → Fill in ANTHROPIC_API_KEY (or another provider)

# 4. Run (from inside the pentestai/ directory)
python3 __main__.py

# Or from the parent directory:
# python3 -m pentestai

Verification

PentestAI> llm
PentestAI> tools
PentestAI> scope add 10.0.0.1/32
PentestAI> target 10.0.0.1
PentestAI> recon

Option 2: Docker (Single Container)

Suitable for: isolated environments, reproducibility, team sharing.

Prerequisites

  • Latest Docker Desktop (tested on 4.96.0, Engine 29.9.1, Compose v5.6.0) or the latest Docker Engine on Linux
  • Disk space ≥ 20 GB (image includes Kali tools + Chromium; final image ≈7.8 GB)

Minimal Setup

cp .env.example .env
nano .env  # fill in API keys

# Build (Kali apt + Metasploit/Burp: 10-20 minutes on the first build)
docker build -t pentestai .

docker run -it --rm \
  --env-file .env \
  -v $(pwd)/sessions:/app/sessions \
  -v $(pwd)/logs:/app/logs \
  -v $(pwd)/reports/output:/app/reports/output \
  pentestai

Image notes:

  • Runs as the non-root user pentester.
  • .env is not included in the image — .dockerignore excludes all .env files. Credentials only enter at runtime via --env-file.
  • Tools already available: nmap, sqlmap, nikto, gobuster, ffuf, hydra, whatweb, msfconsole, node, python3.
  • Headless Chromium (Playwright) is available for JavaScript-heavy pages, authenticated flows, screenshots, and PDF export.

Setup with API Server

docker run -d \
  --name pentestai-api \
  --env-file .env \
  -p 8080:8080 \
  -v $(pwd)/sessions:/app/sessions \
  pentestai python3 __main__.py --api --host 0.0.0.0

# Test
curl http://localhost:8080/health

Option 3: Docker Compose (Full Stack, Recommended)

Suitable for: production-like setups, Neo4j + Qdrant + Metasploit.

# 1. Preparation
cp .env.example .env
nano .env

# 2. Build + start all services (including the msf profile)
docker compose --profile msf up -d

# 3. Wait until healthy (30-60 seconds on first start)
docker compose --profile msf ps

# 4. Attach to the running CLI
docker attach pentestai-pentestai-1
#    exit without stopping the container: Ctrl-p then Ctrl-q

docker-compose.yml uses two paths for .env:

Path Function
Compose interpolation ${ANTHROPIC_API_KEY}, ${NEO4J_PASS}, etc. in the environment: block
env_file: .env Passes all variables (15 LLM providers, PENTESTAI_MODE, REPORT_*, TEST_*) to the pentestai container

Without env_file, only the keys listed explicitly in environment: reach the container, and providers such as DeepSeek/Gemini/OpenRouter will not be detected.

Available Services

Service Container Port Description
pentestai pentestai-pentestai-1 - Main CLI shell (interactive, detached)
neo4j pentestai-neo4j-1 7474, 7687 Graph database (healthcheck enabled)
qdrant pentestai-qdrant-1 6333, 6334 Vector database
msf pentestai-msf-1 55553 Metasploit RPC (msf profile)

All services are on the pentestnet bridge network. Internal hostnames: neo4j, qdrant, msf.

API Mode via Compose

The pentestai service does not publish ports. Run a separate API instance:

docker compose run --rm -p 8080:8080 pentestai \
  python3 __main__.py --api --host 0.0.0.0

curl http://localhost:8080/health

Daily Commands

# View status
docker compose --profile msf ps

# Container logs
docker compose logs -f pentestai
docker compose logs msf | grep MSGRPC

# Separate shell inside the container (without disturbing the main CLI)
docker compose exec -T pentestai sh

# Run a single command
docker compose exec -T pentestai python3 -c "from core.llm import build_router_from_env; print(build_router_from_env().status())"

# Stop (data retained)
docker compose --profile msf down

# Stop + remove Neo4j/Qdrant volumes (graph & embedding data is lost)
docker compose --profile msf down -v

Environment Smoke Test

The scripts/env_test.py script checks all .env parameters from inside the container without printing secret values (masked):

docker cp scripts/env_test.py pentestai-pentestai-1:/tmp/env_test.py
docker compose exec -T pentestai python3 /tmp/env_test.py

What is checked:

  1. Presence/format of each variable
  2. Live auth probe of each LLM provider that has a key (HTTP status)
  3. Neo4j (Basic auth + bolt), Qdrant, Metasploit RPC
  4. config.settings — PENTESTAI_MODE → SKILL_MODE, REPORT_*
  5. Binary tools in the image
  6. TEST_LOGIN_URL: DNS + TCP only (never sends credentials)

Browser availability (should print True):

docker compose exec -T pentestai python3 -c "from tools.browser import BrowserTool; print(BrowserTool().available)"

Exit code 0 = all pass, 1 = something failed. Save machine-readable results: python3 /tmp/env_test.py --json → /tmp/env_test_report.json.

Deployment baseline 2026-10-20: 38/53 pass. All 15 failures are because keys in .env are still empty (see CONFIG.md).

Updating Docker Desktop (macOS)

# Check the installed version
defaults read /Applications/Docker.app/Contents/Info.plist CFBundleShortVersionString

# Docker Desktop must be RUNNING for this command
docker desktop update --check-only
docker desktop update

If the CLI update fails (e.g. brew requires interactive sudo), download the official DMG and replace the app manually:

# Get the latest DMG URL from the official appcast
DMG_URL=$(curl -s https://desktop.docker.com/mac/main/arm64/appcast.xml \
  | grep -oE 'https://[^"]*Docker\.dmg' | head -1)
echo "$DMG_URL"

curl -L -o /tmp/Docker.dmg "$DMG_URL"
hdiutil attach -nobrowse -mountpoint /tmp/dockerdmg /tmp/Docker.dmg
defaults read /tmp/dockerdmg/Docker.app/Contents/Info.plist CFBundleShortVersionString

rm -rf /Applications/Docker.app
ditto /tmp/dockerdmg/Docker.app /Applications/Docker.app
hdiutil detach /tmp/dockerdmg
rm -f /tmp/Docker.dmg
open -a Docker

brew upgrade --cask docker-desktop may fail at the old helper uninstall stage (com.docker.socket, com.docker.vmnetd) because sudo prompts for a password in an interactive terminal — run it manually in Terminal if you choose this path.

Full Reset & Rebuild from Scratch

Used when you want to discard all images/volumes or Docker is unstable:

# 1. Stop Docker Desktop (force if hung)
docker desktop stop || pkill -9 -f 'Docker Desktop'
pkill -9 -f 'com.docker'; pkill -9 -f 'docker-sandbox'

# 2. Delete all VM data: images, containers, build cache, volumes
rm -f ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw

# 3. Start again (a new VM disk is created)
open -a Docker
until curl -s --unix-socket ~/.docker/run/docker.sock http://localhost/_ping; do sleep 5; done

# 4. Rebuild the application image without cache
docker compose --profile msf build --no-cache

# 5. Pull supporting base images
docker compose --profile msf pull neo4j qdrant msf

# 6. Start stack
docker compose --profile msf up -d

# 7. Clean build cache (freed ±7 GB in this session)
docker builder prune -f

⚠️ Step 2 deletes all volumes, including the Neo4j graph and Qdrant embeddings. Files on the host (sessions/, logs/, reports/) are untouched because they are mounted as bind volumes.

The commands above are macOS-specific (Docker Desktop). On Linux: docker system prune -a --volumes (equivalent, without deleting VM files).

Disk Requirements

Item Size
Image pentestai:latest 7.83 GB (Kali tools + Chromium)
Base images (neo4j + qdrant + msf) ±4.8 GB
Build cache during --no-cache ±8 GB (can be pruned)
Docker.raw before reset 29 GB (sparse, maximum size 228 GB)

Leave at least 10 GB free on the host. Docker Desktop on macOS will hang / return EOF from the API if the host disk is full — see TROUBLESHOOTING.md.


Directory Structure

After setup, these are the directories that matter:

pentestai/
├── sessions/           ← Saved sessions (*.json)
│   └── llm_fleet.json  ← LLM model configuration
├── logs/               ← Audit logs (*.jsonl)
├── reports/
│   └── output/         ← Generated reports (*.html)
├── wordlists/          ← Wordlists for gobuster/hydra
└── .env                ← Configuration (DO NOT commit to git!)

Running as an API Server

# Default port 8080
python3 __main__.py --api

# Custom port
python3 __main__.py --api --port 9090

# Bind to all interfaces (for network access)
python3 __main__.py --api --host 0.0.0.0

Create the First API Key

curl -X POST http://localhost:8080/api/v1/auth/keys \
  -H "Content-Type: application/json" \
  -d '{"name": "admin"}'

Save the returned key.


Integration with External Tools

Burp Suite

BURP_API_URL=http://localhost:8090
BURP_API_KEY=your_burp_key

Metasploit (standalone)

# Start Metasploit RPC
msfrpcd -P yourpassword -S false -f -a 127.0.0.1

# Configuration
MSF_HOST=127.0.0.1
MSF_PORT=55553
MSF_PASSWORD=yourpassword

Ollama (local LLM)

curl -fsSL https://ollama.ai/install.sh | sh
ollama pull llama3.1:8b
ollama pull mistral:7b

# Set in .env
OLLAMA_BASE_URL=http://localhost:11434

Troubleshooting

"No LLM configured"

# Verify the env var is available
echo $ANTHROPIC_API_KEY

# Or in the shell
llm add  # interactive wizard

"nmap not found"

sudo apt-get install nmap    # Debian/Ubuntu
brew install nmap            # macOS

"Permission denied" when running nmap

sudo chmod u+s $(which nmap)  # setuid for raw socket

Neo4j cannot connect

# Check status
docker compose ps neo4j

# Check logs
docker compose logs neo4j

# Test connection
curl http://localhost:7474

Port 8080 already in use

python3 __main__.py --api --port 8081


Node.js — Word Report (.docx)

Node.js is required for report docx and orchestrate → ReportSubAgent → Word export.

# Install Node.js
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# Verify
node --version   # ≥ 16.x

# Install docx package (from the pentestai/ directory)
cd reports && npm install docx

Without Node.js: report docx and ptes (Markdown) still work. Only Word export fails.


Phase 6 Dependencies

Plugin system

The plugin dir (plugins/) already exists. No additional setup needed. Plugins are installed automatically via marketplace install <id>.

PTES + ISO 27001

No additional dependencies — only the Python standard library.

Multi-agent orchestrator

No additional dependencies — uses the threading stdlib.


Security Hardening

For a more secure deployment:

# Do not expose the API to the internet without auth
# Use a reverse proxy (nginx/caddy) with TLS

# Restrict API access by IP (nginx example)
location /api/ {
    allow 10.0.0.0/8;
    deny all;
    proxy_pass http://localhost:8080;
}

# Rotate API keys periodically
curl -X DELETE http://localhost:8080/api/v1/auth/keys/{old_key_id} \
  -H "X-API-Key: $ADMIN_KEY"

# Back up sessions and logs
tar -czf backup-$(date +%Y%m%d).tar.gz sessions/ logs/

Clone this wiki locally