# ============================================================================= # ProjectAchilles — server deployment config # ============================================================================= # Copy to deploy.config.env and fill in. Then run: # # ./scripts/deploy-server.sh # install on THIS machine # ./scripts/deploy-remote.sh user@host # install on a remote SSH host # ./scripts/deploy-do.sh # create a DO droplet + install # # The deploy script is HYBRID: any value left blank below is prompted for # interactively. Provide everything here for a fully unattended run (ideal for # driving from an LLM / agentic coding tool). # # This file contains secrets once filled — it is gitignored. Never commit it. # ============================================================================= # --------------------------------------------------------------------------- # Public address # --------------------------------------------------------------------------- # The fully-qualified domain users and agents will reach. Single-origin: the # UI is at https://$ACHILLES_DOMAIN/ and the API at .../api. One A record must # point this name at the server's IP (public droplet) or its internal IP # (on-prem split-horizon DNS). ACHILLES_DOMAIN=achilles.example.com # Email for Let's Encrypt account + expiry notices. Required for acme-* modes. ACME_EMAIL=admin@example.com # --------------------------------------------------------------------------- # Organization (optional) # --------------------------------------------------------------------------- # The organization this deployment serves, printed on the execution report's # cover and page headers. Leave blank and the report says "All organizations". # This file is read by bash, so quote a name with spaces: "Acme Corp". ORGANIZATION_NAME= # Console identity: code is 2-6 letters/digits; name falls back to ORGANIZATION_NAME. # Colour: violet|indigo|blue|cyan|fuchsia|pink|orange|silver|none. Quote names with spaces. # CONSOLE_ORG_CODE=ACME # CONSOLE_ORG_NAME="Acme Financial Group" # CONSOLE_ORG_COLOR=violet # Display names for organization UUIDs in Analytics and reports, as JSON keyed # by org UUID (a short name, or {"shortName","fullName"}). Single-quote it here: # ORG_NAMES='{"":{"shortName":"ACME","fullName":"Acme Corporation"}}' ORG_NAMES= # --------------------------------------------------------------------------- # Compose project (optional) # --------------------------------------------------------------------------- # Prefix of the stack's container and volume names. Blank = achilles-server on # a new install; an existing install keeps the name it already runs under, # which the installer stores in the root .env. Set it only for a second stack # on the same host. It cannot be changed after the first install. # COMPOSE_PROJECT_NAME= # --------------------------------------------------------------------------- # TLS strategy — choose ONE # --------------------------------------------------------------------------- # acme-http Public droplet. Let's Encrypt HTTP-01. Needs inbound 80/443 and # public DNS pointing at this host. Publicly-trusted, zero client setup. # acme-dns Internal host with a public domain. Let's Encrypt DNS-01 (no # inbound needed). Requires CADDY_DNS_* below. Publicly-trusted. # internal Caddy's local self-signed CA. No domain/internet needed. You must # distribute the exported root CA to browsers + agents. # byo Bring your own cert: drop cert.pem + key.pem in deploy/caddy/certs/. # achilles-ca On-prem LAN. The installer generates a name-constrained # root + intermediate CA (see CA_ZONE below); Caddy serves leaf # certs from it. Needs CADDY_BIND_IP and CA_ZONE. TLS_MODE=acme-http # --- achilles-ca / on-prem LAN (optional for other modes) ------------------ # LAN IP Caddy binds ports 80/443 to. Blank = every IPv4 and IPv6 address. # An IPv6 address may be written bare (fd00::1) or bracketed ([fd00::1]). CADDY_BIND_IP= # Comma-separated CIDRs allowed to reach 80/443 (firewall), e.g. 10.0.0.0/24,192.168.1.0/24 LAN_SUBNETS= # --- achilles-ca only ------------------------------------------------------ # DNS zone the CA may issue for (name constraint), e.g. lan.example.com. CA_ZONE= # true = also permit the CADDY_BIND_IP as an IP SAN (/32 constraint); false = no IP SANs. CA_INCLUDE_IP=false # true = if the existing CA's zone/IP constraints differ from CA_ZONE / # CA_INCLUDE_IP, replace it with a new root. Every endpoint (and any GPO) must # then re-trust the new root. A matching CA is always kept. CA_ROTATE=false # true = add " " to this server's /etc/hosts. HOSTS_ENTRY=false # --- acme-dns only --------------------------------------------------------- # Caddy DNS plugin provider name and its Go module path, plus the API token. # Provider list: https://github.com/caddy-dns CADDY_DNS_PROVIDER=cloudflare CADDY_DNS_MODULE=github.com/caddy-dns/cloudflare CADDY_DNS_TOKEN= # --------------------------------------------------------------------------- # Authentication (Clerk) — required # --------------------------------------------------------------------------- # https://dashboard.clerk.com -> your app -> API Keys CLERK_PUBLISHABLE_KEY=pk_live_xxx CLERK_SECRET_KEY=sk_live_xxx # First admin (optional). achilles-installer invites this address through the # Clerk API (Clerk emails a sign-up link) or, if the account already exists, # gives it the admin role. deploy-server.sh ignores it. ADMIN_EMAIL= # --------------------------------------------------------------------------- # Secrets — leave blank to auto-generate (openssl rand -base64 32) # --------------------------------------------------------------------------- SESSION_SECRET= ENCRYPTION_SECRET= CLI_AUTH_SECRET= # --------------------------------------------------------------------------- # Elasticsearch (analytics) # --------------------------------------------------------------------------- # self Run a bundled ES container on this server (needs >= 4 GB RAM). # cloud Use managed Elastic Cloud (fill ELASTICSEARCH_CLOUD_ID + _API_KEY). ES_MODE=self # --- ES_MODE=cloud only ---------------------------------------------------- ELASTICSEARCH_CLOUD_ID= ELASTICSEARCH_API_KEY= ELASTICSEARCH_INDEX_PATTERN=achilles-results-* # Seed ~1000 synthetic records on first provision (self ES only). true/false. SEED_ES=false # --------------------------------------------------------------------------- # Test library + agent source repositories # --------------------------------------------------------------------------- # Git-synced security test library. The default public f0_library needs no token. TESTS_REPO_URL=https://github.com/ubercylon8/f0_library.git TESTS_REPO_BRANCH=main # Agent source (needed for in-app Go cross-compilation of the agent binary). AGENT_REPO_URL=https://github.com/projectachilles/ProjectAchilles.git AGENT_REPO_BRANCH=main # Only needed if either repo above is private. Scope: repo. GITHUB_TOKEN= # --------------------------------------------------------------------------- # DigitalOcean droplet creation (scripts/deploy-do.sh only) # --------------------------------------------------------------------------- DO_API_TOKEN= DO_REGION=nyc3 DO_SIZE=s-2vcpu-4gb # >= 4 GB recommended when ES_MODE=self DO_IMAGE=ubuntu-24-04-x64 DO_DROPLET_NAME=achilles # SSH key fingerprint(s) registered in your DO account (comma-separated). DO_SSH_KEY_FINGERPRINT= # If your domain's nameservers are on DigitalOcean, set true to auto-create the # A record for ACHILLES_DOMAIN. Otherwise create the A record at your DNS host. DO_MANAGE_DNS=false # --------------------------------------------------------------------------- # Remote install over SSH (scripts/deploy-remote.sh, also used by deploy-do.sh) # --------------------------------------------------------------------------- # SSH target. deploy-do.sh fills SSH_HOST automatically from the new droplet IP. SSH_USER=root SSH_HOST= SSH_PORT=22 # Where to place the project on the remote host. REMOTE_DIR=/opt/projectachilles