Files
Mr. The Plague d3b2fcfe79 docs: public-repo readiness — scrub private paths, fix links, CI notes
Remove personal OneDrive paths and wrong GitHub owner; document self-hosted
CI for external contributors; fix env prefix table, deploy lab script, UFW
guidance, pyproject URLs, and tighten gitignore for secrets.
2026-08-04 09:05:50 -04:00

11 KiB

SquidC5 Deployment

Lab (Docker) and production (CI binary) deployment. For day-2 operator procedures see operator-runbook.md. For features see user-guide.md.

Related Link
Docs index README.md
Prod readiness prod-readiness-plan.md
Threat model threat-model.md
Env template ../.env.example

Docker lab

Context

Primary lab path. Compose defaults to network_mode: host so reverse-shell/TCP listeners bind real host ports without republishing each port.

Configuration

  • Image/build via docker-compose.yml
  • Data volume -> /data (tokens, DB, TLS) - never commit
  • TLS on by default (self-signed)

Commands

docker compose up --build -d
docker exec squidc5 cat /data/admin_token.txt # once; store securely
curl -sk https://127.0.0.1:8443/api/v1/health

Host networking (default)

network_mode: host - process binds host ports directly. Trade-off: less isolation; fine for single-purpose C2 lab hosts.

Bridge networking alternative

If using bridge, publish every listener port you need:

ports:
 - "8443:8443"
 - "443:443"
 - "4444:4444"

Verify

curl -skf https://127.0.0.1:8443/api/v1/health
# Ops UI: https://127.0.0.1:8443/ops

See also


Privileged ports

Context

App user is non-root. Binding listeners on ports < 1024 requires host capability.

Configuration

sysctl -w net.ipv4.ip_unprivileged_port_start=0
echo "net.ipv4.ip_unprivileged_port_start=0" | sudo tee /etc/sysctl.d/99-squidc5.conf

Commands

Apply sysctl, then start/restart SquidC5 and create low-port listeners.

Verify

sc5 listeners create rev443 443 --kind reverse_shell
sc5 listeners start <id>
sc5 listeners list # status running

See also


Firewall

Context

Dedicated lab host: open only the ports you need for SSH, the teamserver, and any reverse-shell / OAST listeners. Never copy a wide-open firewall policy to an internet-facing production host.

Configuration

Hardened default (recommended):

ufw --force reset
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw allow 8443/tcp comment 'squidc5 teamserver'
# add listener ports as needed, e.g.:
# ufw allow 443/tcp comment 'rev shell / https front'
ufw --force enable

Lab-only permissive (isolated lab VMs — not for prod):

# DANGEROUS on the public internet — lab VMs only
ufw --force reset
ufw default allow incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw --force enable

Commands

ss -tulnp | grep -v 127.0.0

Disable unused host services that might bind ports. DNS (systemd-resolved) on 127.0.0.53 only is fine.

Verify

Public listeners are only expected services (sshd + squidc5).

See also


Cloud lab pattern

Context

Typical single-droplet lab (any cloud). Paths below match common SquidC5 installs.

Configuration

Item Suggested
Size 1 vCPU / 1 GB RAM minimum
Image Ubuntu LTS
Install path /opt/squidc5
SSH Operator key registered with provider - never commit private keys
Env SQUIDC5_* from .env.example

Commands

Follow Production binary deploy or Docker lab on the droplet.

Verify

curl -skf https://127.0.0.1:8443/api/v1/health

See also


OAST Collaborator (DNS + HTTP + SMTP)

Context

Authorized out-of-band interaction capture (Collaborator / Interactsh style). Values below are illustrative - use your own zone, host, and IP.

Configuration

Var Example (replace) Purpose
SQUIDC5_OAST_ZONE oast.example.com Authoritative OAST zone
SQUIDC5_PUBLIC_HOST oast.example.com Hostnames in payload URLs
SQUIDC5_PUBLIC_IP 203.0.113.10 A-record answers for DNS OAST
SQUIDC5_OAST_ENABLED true Gate feature
SQUIDC5_OAST_HTTP_PORT 80 Port shown in HTTP payload URLs

DNS delegation (subdomain only - do not change apex NS)

Example for oast.example.com -> teamserver 203.0.113.10:

Type Name Data
A ns1.oast 203.0.113.10 (glue)
A oast 203.0.113.10
NS oast ns1.oast.example.com
MX oast oast.example.com (priority 0)

Leave apex @ A (website) and apex NS (registrar) alone.

Firewall ports (teamserver)

Open at minimum for full OAST: 53/udp, 53/tcp, 25/tcp, 80/tcp, 443/tcp, 8443/tcp.

Port 53 needs root or ip_unprivileged_port_start=0. Port 25 is often blocked by cloud providers - use 2525 for lab SMTP OAST if needed.

Commands

# DNS OAST + beacon (mode both|oast|beacon)
sc5 --insecure listeners create oast-dns 53 --kind dns --zone oast.example.com --dns-mode both
sc5 --insecure listeners start <id>

# HTTP OAST catch-all
sc5 --insecure listeners create oast-http 80 --kind http
sc5 --insecure listeners start <id>

# SMTP OAST (enable feature first; never relays)
# PUT /api/v1/features {"features":{"smtp_oast":true}}
sc5 --insecure listeners create oast-smtp 25 --kind smtp

Verify

sc5 --insecure login --url https://TEAM:8443 --token sc5_...
sc5 --insecure oast token create --note "xss"
# TOKEN=... from response
dig @8.8.8.8 "$TOKEN.oast.example.com" A
curl -sS "http://oast.example.com/$TOKEN/"
# optional: swaks --to "$TOKEN@oast.example.com" --server TEAM_IP
sc5 --insecure oast hits --token "$TOKEN"

CLI: global --insecure / config verify_ssl: false for self-signed API TLS.

See also


TLS (HTTPS) default on new instances

Context

On first start, SquidC5 generates a unique self-signed certificate under the data dir and serves ops UI, REST API, and MCP over HTTPS.

$SQUIDC5_DATA_DIR/tls/server.crt
$SQUIDC5_DATA_DIR/tls/server.key
$SQUIDC5_DATA_DIR/tls/instance_id

Configuration

Env Default Meaning
SQUIDC5_TLS_ENABLED true Serve TLS
SQUIDC5_TLS_CERT_FILE / SQUIDC5_TLS_KEY_FILE unset Use auto paths under data/tls/
SQUIDC5_TLS_FORCE_NEW false Regenerate cert/key on next start
SQUIDC5_PUBLIC_HOST empty Added to cert SAN when set

Browsers warn on self-signed certs - expected. For production, put a real cert on a redirector or override cert/key paths with CA-issued material. Ops Admin -> TLS certificate library can upload/activate PEMs; restart the process after activate.

Disable only for lab debugging: SQUIDC5_TLS_ENABLED=false (plaintext - not recommended).

Commands

curl -k https://127.0.0.1:8443/api/v1/health
# Ops: https://HOST:8443/ops (accept warning)

Verify

curl -skf https://127.0.0.1:8443/api/v1/health
openssl s_client -connect 127.0.0.1:8443 -servername HOST </dev/null 2>/dev/null | openssl x509 -noout -subject -dates

See also


Production binary-only deploy

Context

Prod is not updated from a local working tree or Docker rebuild of WIP.

Pipeline:

  1. Open PR -> CI tests must pass
  2. Merge to main / master
  3. Main CI builds standalone binaries (sc5, squidc5) and publishes a GitHub Release
  4. Download Linux squidc5-linux-x64 from that Release
  5. Deploy only that executable; keep data/ intact

Forbidden on prod: rsync of WIP source, docker compose up --build from dirty checkout, feature-branch-only binaries.

Allowed: install/restart main-built binary; preserve data dir; SQUIDC5_* env.

Configuration

Commands

First install

install -d /opt/squidc5/bin /opt/squidc5/data
install -m 755 squidc5-linux-x64 /opt/squidc5/bin/squidc5
cp packaging/squidc5.service /etc/systemd/system/squidc5.service
# Optional drop-ins: /etc/systemd/system/squidc5.service.d/*.conf
systemctl daemon-reload
systemctl enable --now squidc5

Binary upgrade (preserve data)

# 1. Download latest Linux squidc5 from GitHub Release (main CI)
# 2. Backup DB
sc5 backup /opt/squidc5/backups/pre-upgrade.db --data-dir /opt/squidc5/data

scp -i <key> squidc5-linux-x64 root@HOST:/opt/squidc5/bin/squidc5.new
ssh -i <key> root@HOST '
 set -e
 systemctl stop squidc5
 install -m 755 /opt/squidc5/bin/squidc5.new /opt/squidc5/bin/squidc5
 rm -f /opt/squidc5/bin/squidc5.new
 systemctl start squidc5
 curl -skf https://127.0.0.1:8443/api/v1/health
'

Listeners marked running are restored after restart. Prefer stopping via systemd (not operator listeners stop) when you want auto-restore.

# /etc/systemd/system/squidc5.service.d/rate.conf
[Service]
Environment=SQUIDC5_RATE_LIMIT_PER_MINUTE=600
Environment=SQUIDC5_AUTH_FAIL_LIMIT_PER_MINUTE=60
# /etc/systemd/system/squidc5.service.d/tls.conf (real certs)
[Service]
Environment=SQUIDC5_TLS_ENABLED=true
Environment=SQUIDC5_TLS_CERT_FILE=/etc/letsencrypt/live/HOST/fullchain.pem
Environment=SQUIDC5_TLS_KEY_FILE=/etc/letsencrypt/live/HOST/privkey.pem

Verify

systemctl is-active squidc5
curl -skf https://127.0.0.1:8443/api/v1/health

See also


Secrets hygiene

Context

Tokens, DB files, and API keys must never enter git or public artifacts.

Configuration

Never commit:

  • data/admin_token.txt
  • data/*.db
  • data/tls/*.key
  • ~/.config/squidc5/config.json
  • .env with real tokens
  • LLM API keys

Commands

Rotate bootstrap admin token after first login by creating a new admin-scoped token and revoking the bootstrap id if desired.

sc5 tokens create admin2 --scopes "admin"
sc5 tokens revoke <bootstrap_id>

Verify

git status # no data/ or .env secrets
git check-ignore -v data/admin_token.txt

See also