LoadBalancer Services so AWS provisions Network Load Balancers for Den web and Den API. Move to an ALB or an existing ingress platform when you need shared layer-7 routing, WAF policy, or more advanced certificate handling.
What AWS manages
- EKS control plane, compute, pod networking, and load-balancer integration
- VPCs, subnets, routing, security groups, and IAM
- RDS for MySQL, encryption, backups, and failover
- Route 53 DNS and ACM certificates when you use those services
AWS checklist
- Create an EKS Auto Mode cluster with
eksctl0.195.0or newer. - Create an RDS MySQL 8-compatible database in private subnets.
- Allow database port
3306only from the EKS workload or node security boundary. - Store
DATABASE_URL,BETTER_AUTH_SECRET, andDEN_DB_ENCRYPTION_KEYin a Kubernetes Secret. - Start from the chart’s
values.aws-load-balancer.yamlexample. - Install the chart, verify migrations and readiness, then point DNS at the generated load balancers.
- Enable trusted HTTPS before creating the first administrator.
ECS Fargate with Terraform
These instructions and historical contract-v1 live results apply to direct Terraform users. The managed AWS installer now consumes the same module with explicit legacy state-backed secrets, a maintenance-first runner fence and separate customer IAM re-approval. It does not silently convert existing keys to write-only mode. Its real version-increasing Update/fresh-install/destroy proof is a separate gate, not certified by the direct-user results below. See the managed installer upgrade notes.What it deploys
If you run containers on ECS Fargate rather than Kubernetes, the Terraform module creates an ECS cluster (or uses yours), Den API and Den web as Fargate services behind an HTTPS Application Load Balancer, private RDS for MySQL, optional ElastiCache for Redis, and AWS Secrets Manager references. One standalone migration task must finish with exit 0 before API or web rollout. Application replicas do not run migrations. A small native Lambda invocation starts the task and observes completion; no local-exec provisioner is required. API defaults to 1 vCPU / 2 GiB and web to 0.5 vCPU / 1 GiB. Managed RDS deletion protection defaults on. The 0.18.57/0.18.58 API/web defaults are digest-pinned; other versions and enabled optional services require digest-pinned image overrides. Database TLS verifies the certificate chain using the public regional RDS CA bundle, loaded before Node starts. The application’s current MySQL parser does not enable mysql2’s separate hostname identity check; full hostname verification remains an application follow-up, not a claim of this module.Tested scenarios
Support level
The table records the tested core only, not production load, backup restoration, legacy handover, or every optional component. Complete your review before pinning a source commit. The module and its deployment-contract improvements are available ondev in beta;
the managed installer has separate approval and live-verification gates.
See the shared module contract
for baseline checks and known limits.
Upgrade notes
Database sizing default:db.t4g.micro → db.t4g.small (2 GiB memory).
Existing direct Terraform users who omitted database.instance_class will see an
in-place instance-class change in their next plan. Apply schedules it for
the next RDS maintenance window by default (apply_immediately = false); the
class change restarts the database and interrupts connections when performed.
With apply_immediately = true, it restarts during apply instead. Review pending
modifications and arrange maintenance before applying.
AWS documents modification timing here.
Estimated Single-AZ MySQL instance cost in us-east-1 rises from **23.36/month (+0.016 → $0.032/hour, public list prices
checked 2026-10-19). This excludes storage, CPU credits, backups, networking,
taxes and discounts; see RDS pricing.
To keep the old size, add this to the module call before upgrading, merging
it into your existing database object without dropping other settings:
database.deletion_protection alias. Floating image tags are now rejected: pin the current digests before upgrading. Use one state/release coordinator per physical database. Migration failure or an unknown outcome blocks rollout and requires inspection, not automatic SQL retry. See the module upgrade notes for the full fence and secret-conversion procedure.
State guidance
Use Terraform or OpenTofu >= 1.11, < 2.0 with encrypted, access-controlled remote state. An S3 root backend should setencrypt = true and use_lockfile = true; do not create a new DynamoDB locking table. The reusable module configures neither a provider nor a backend and ships no cross-registry lock file. Generate and retain the root lock with your chosen tool. This direct-user module uses the live-tested AWS ~> 6.69 provider line and random ~> 3.9; the previous cross-major compatibility exception is no longer needed. The managed AWS root now locks AWS 6.69.1 and random 3.9.1 and explicitly retains legacy state-backed secrets/current strict SecretVersion. Its updated bootstrap grants only deployment-scoped migration Lambda, role and log permissions and requires customer re-approval plus a maintenance window. The runner drains old tasks before migration and verifies completed strict deployments; retained legacy revisions must never be started manually. Synthetic state tests do not replace a real provider-upgrade proof or managed-deployments owner review.
For new installs, use write_only_secrets = true with persistent core values supplied through the ephemeral secret_values_wo input: RDS and Secrets Manager write-only fields keep those values out of new state snapshots. Write-only mode is the new default. Existing installations must explicitly set write_only_secrets = false before upgrading to retain their current keys/state, or securely preserve and supply the exact existing keys and DB password before converting. Missing ephemeral values fail validation before changes, rather than silently regenerating auth/encryption keys. Never regenerate an encryption key during an infrastructure upgrade. Optional integration secrets retain their state-backed compatibility path; restrict state history accordingly. Secret settings belong in extra_secrets, not plain extra_environment.
Cost notes
Costs depend on region, replica count and egress: Fargate API/web, RDS, ALB, optional NAT/Redis, image pulls for the standalone migrator, and brief Lambda duration. A two-API-task lab with one NAT costs more than the one-task defaults. Stop disposable stacks promptly and disable deletion protection explicitly only for those tests. You provide a VPC, two hostnames (the web host andapi. plus the web host), and an ACM certificate or a Route 53 zone the module can use to create one. HTTPS is required: Den API does not start with a plain-HTTP public URL. Email is optional for setup and sign-in, but member invites and password reset need SMTP or Resend.
The module can also run OpenWork Web, so members chat in the browser with each workspace in a Daytona sandbox: set openwork_web_enabled = true and provide a Daytona API key and sandbox snapshot.
It can also run the headless runner, so the Slack assistant, headless Automations and Workbot (a chat app at chat. plus your web host) work on your deployment with your own model provider: set headless_runner, workbot and slack_assistant_enabled.
See the module README for inputs, a complete example, and cost notes.
Next: Create the first administrator.