sudoX · deploy

Running it, nothing exposed.

Ten minutes on a laptop to see the whole loop, and the shape of the first real deployment: one instance, one tunnel, no inbound rule anywhere.

On a laptop

One container. Sign in with the gateway secret, connect a database, send an alert, and watch it become an analysis, a plan and — once you approve it — an executed fix with a runbook drafted from the result.

docker run -d --name sudox -p 3000:3000 \
  -e GATEWAY_SECRET=$(openssl rand -hex 32) \
  -e AGENT_ENABLE=true \
  -e AGENT_AI_ENABLE=true \
  -e AGENT_AI_PROVIDER=openai \
  -e AGENT_AI_API_KEY=sk-... \
  ghcr.io/oguzhankarahan/sudox-ai-platform:latest

Ollama works the same way with no API key: AGENT_AI_PROVIDER=ollama AGENT_AI_MODEL=qwen3:8b. From source, build the console first (cd ui && npm install && npm run build) and then go build -o sudox ./cmd. Then open http://localhost:3000.

1

Connect something

The Connections page in the console, or a preset in mcp_servers.yaml. A credential is tested before it is stored.

2

Send an alert

POST /api/incidents with any JSON and an API token that may send alerts (an integration token can do only that). It is persisted before anyone is notified, and shows up on Now.

3

Run the loop

Analyze → plan → approve → execute → verify. The impact report counts only what was measured.

The first real deployment

One EC2 instance running the container, Postgres on RDS beside it, nothing exposed to the internet, and Cloudflare Tunnel + Access in front as the only way in. The instance role is the AWS credential: no access key is created, stored or rotated for the AWS side. Other accounts are reached by assuming a role from it; GCP is reached through workload identity federation with an AWS provider — a credential that never exists as a file.

CLOUDFLARE users Access — sign in Tunnel outbound only no inbound rule VPC · PRIVATE SUBNET EC2 · DOCKER COMPOSE sudox cloudflared binary + uv, node, aws, gcloud, bq instance role: read AWS, assume into other accounts RDS Postgres 5432 · SG-to-SG only
One way in and it is not a port: the instance dials out to Cloudflare, Access asks who you are before the tunnel forwards anything, and the database answers only to the app's security group.

Why a single VM and not ECS or EKS. sudoX is one long-running process that spawns subprocesses — every MCP server is one — and must never sleep. A VM is the natural shape for that, it is the cheapest, and it is the easiest to debug for the first weeks. The Helm chart is there for when a second instance is needed.

Why not Cloudflare Workers or Containers for the product itself. The same reason: a process that forks child processes and holds a warm MCP cache does not fit a platform that scales to zero. Cloudflare's role is the front door. This site and the console share one hostname behind it — the site at /, the console at /console — and Access is scoped to the console path.

The runbook with every command, the IAM policies, the compose file and the corrections found by running it — an instance with no egress, a first boot that never wrote its unit, a region that never reached the container — is in the repository under deploy/ec2/.

One hostname, two doors

/

This site: public, cached

The files in site/, served by the same binary as the console and cached at Cloudflare's edge. No build step, no sign-in.

/console

The console: Access, then sudoX

The product, on the same hostname, behind Cloudflare Access scoped to this path. "Open the console" is a relative link; the sign-in screen links back here.

What the account has to grant

ForAWSGCP
discoverydescribe/list on EC2, RDS, ELB, S3, Lambda — the compiled-in probe list, read-onlyroles/viewer on the project
logslogs:FilterLogEvents, and logs:DescribeLogGroups so sources can be derived rather than guessedroles/logging.viewer
metricscloudwatch:GetMetricDataroles/monitoring.viewer
costce:GetCostAndUsage (Cost Explorer is a single endpoint in us-east-1)a BigQuery billing export, named in the console — GCP publishes its bill nowhere else
actingonly what an approved plan's tools are allowed; the passthrough's verb allowlist is compiled inthe same

Where a permission is missing, sudoX says which one rather than guessing around it, because a source built on a guess fails on every tick, and the console fills with errors about a thing nobody asked for. Take one away and read what it says.

Try it

Take a permission away, read what it says.

what the account granted

in the console Connections (the test before storing) · Watching ("on, but not running") · Cost ("not measured") · Infrastructure (a failed probe is a gap)

Each sentence names the grant, in the provider's own vocabulary, and says what the product will not do in its absence — it will not guess a log group name, it will not render a bill as zero, it will not draw an unreadable cache tier as an empty one. The rule behind all of them is the fourth principle on the front page: a gap is shown as a gap.

← Environments Open the console →