Overview
Fjall provisions an Application Load Balancer (ALB) automatically inside an ECS cluster. You do not create the ALB directly. You declare an ECS cluster, and the cluster builds one shared ALB for all of its services. The ALB operates at Layer 7 and distributes incoming traffic across tasks in multiple Availability Zones.Recommended Entry Point
UseComputeFactory.build() to declare ECS compute. The factory validates props, wires defaults, and returns a construct you add to your application.
cluster.domain set, the ALB serves HTTPS on port 443 and gets a Route 53 A record in the resolved hosted zone.
The domain needs a hosted zone source
Fjall never creates a hosted zone inside an application stack, socluster.domain must name a zone that already exists. Synth throws when it cannot resolve one.
A bare
cdk synth outside the CLI has no injected binding, so it needs one of the two explicit forms. See Domain for how managed domains are declared and bound.
There is no HTTP-to-HTTPS redirect listener. The cluster creates exactly one
listener. Permanent 301 redirects come from
domainConfig.redirectHosts,
which adds host-header rules on the HTTPS listener.Direct EcsCluster Usage
For lower-level control, instantiateEcsCluster directly. The props shape nests cluster-wide settings under cluster and lists services under services.
getLoadBalancer() returns undefined when the ALB is disabled (cluster.loadBalancer: false or cluster.directAccess: true). Guard the result before use. getListener() returns the matching ApplicationListener | undefined.
Cluster Configuration
Thecluster object controls the shared ALB for every service.
Service and Health Checks
Each entry inservices gets its own task definition and target group, all registered behind the cluster ALB. The first container with a port is the primary container that receives ALB traffic.
healthCheck above runs inside the task. The ALB target group runs a separate HTTP health check, configured automatically per service:
Multiple Services and Routing
When a cluster has more than one service with a port, each service needs arouting rule so the ALB knows which traffic to send where. Routing supports path patterns and host headers.
routing also accepts an array of rules. Every rule maps to the same target group, so one service can answer several paths or hosts.
priority are numbered automatically from 100 upwards. A single port-bearing service with at most one rule skips rules entirely and becomes the listener’s default action. Any other shape gives the listener a fixed 404 Not Found default, so unmatched requests fail cleanly instead of hitting an arbitrary service.
Each routing.host must sit inside the cluster’s hosted zone. Synth throws for a host outside it, because its alias record and certificate SAN cannot be created there and TLS would fail after a green deploy.
Default ALB Settings
Fjall configures the cluster ALB with these defaults.Keep-Alive and the Idle Timeout
The ALB holds idle keep-alive connections to your containers open for up to its idle timeout and reuses them freely. Node’s defaultserver.keepAliveTimeout is 5 seconds, far below the ALB’s 60, so the ALB can reuse a connection at the exact moment your server closes it. The symptom is intermittent, ALB-generated 502s that never appear in your application logs.
The fix is server-side, and it is two timeouts:
- Your server’s keep-alive timeout must exceed the ALB idle timeout, so the ALB always closes idle connections first.
- Your server’s headers timeout must exceed its keep-alive timeout, so a request that starts arriving just before the keep-alive deadline is not truncated mid-headers.
port) as the environment variable FJALL_ALB_IDLE_TIMEOUT_SECONDS. Services without an ALB (loadBalancer: false or directAccess: true) do not receive it, because there is no ALB to race.
Node servers
Install@fjall/util and apply the timeouts to the http.Server after listen():
FJALL_ALB_IDLE_TIMEOUT_SECONDS and sets keepAliveTimeout to the idle timeout plus a 5-second margin and headersTimeout one second above that (65 s and 66 s at the default). It returns the applied values in case you want to log them.
- Variable absent (local development, images deployed before Fjall injected it): the helper assumes the AWS default of 60 seconds, which yields the same timeouts.
- Variable malformed: the helper throws at boot. This is deliberate, because a misconfigured contract should fail loudly at startup rather than race the ALB in production.
resolveAlbKeepAliveTimeouts() returns the same values without touching a server, for runtimes that set the timeouts themselves.
Other runtimes
ReadFJALL_ALB_IDLE_TIMEOUT_SECONDS (assume 60 when unset) and set your server’s keep-alive timeout above it:
Outputs
The cluster emits five CloudFormation outputs for the ALB. Output keys use the cluster name in PascalCase.
Export names are not the output keys. CloudFormation export names are unique per account per region, so Fjall qualifies them:
The stack-name prefix is added automatically. Build a cross-stack
Fn.importValue from the export name, never from the output key.
<appName>AlbDnsName, <appName>AlbHostedZoneId) so a Domain can alias it without naming the compute.
Cost
Load Balancer Capacity Units (LCUs) bill on the highest of new connections, active connections, processed bytes, and rule evaluations.
Save cost by:
- Consolidating services behind one cluster ALB with path or host routing.
- Disabling the ALB (
loadBalancer: false) for services that never receive external traffic. - Keeping health-check frequency reasonable for the workload.
Troubleshooting
Inspect the deployed ALB with Fjall-minted credentials:
Next Steps
ECS Cluster
Configure the cluster that owns the load balancer.
Domain
Declare the hosted zone and certificate the ALB serves HTTPS from.
VPC
Choose the network the ALB and tasks run in.
Security Group
Control inbound and outbound traffic to the ALB.
Compute Factory
Declare ECS compute with the recommended factory entry point.