> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fjall.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Application Load Balancer

> Distribute HTTP and HTTPS traffic across AWS targets with the Application Load Balancer Fjall provisions inside an ECS cluster.

## 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.

| Behaviour | Detail                                                            |
| --------- | ----------------------------------------------------------------- |
| Creation  | Automatic when a cluster has a service with a port                |
| Sharing   | One ALB per cluster, shared across services                       |
| Disable   | Set `cluster.loadBalancer: false` for internal-only workers       |
| HTTPS     | Implied when `cluster.domain` is set (ACM cert + Route 53 record) |

## Recommended Entry Point

Use `ComputeFactory.build()` to declare ECS compute. The factory validates props, wires defaults, and returns a construct you add to your application.

```typescript theme={null}
import { ComputeFactory } from "@fjall/components-infrastructure";

app.addCompute(
  ComputeFactory.build("WebApp", {
    type: "ecs",
    cluster: { domain: "app.example.com" },
    services: [
      {
        name: "web",
        capacityProvider: "FARGATE",
        containers: [{ port: 3000 }],
      },
    ],
  }),
);
```

With `cluster.domain` set, the ALB serves HTTPS on port 443, requests an ACM certificate validated by DNS, creates a Route 53 A record, and redirects HTTP to HTTPS.

## Direct EcsCluster Usage

For lower-level control, instantiate `EcsCluster` directly. The props shape nests cluster-wide settings under `cluster` and lists services under `services`.

```typescript theme={null}
import { EcsCluster } from "@fjall/components-infrastructure/lib/resources/aws/compute/ecs";

const cluster = new EcsCluster(this, "MyCluster", {
  clusterName: "my-cluster",
  vpc,
  ecrRepository: "my-app",
  cluster: {
    domain: "api.example.com",
  },
  services: [
    {
      name: "api",
      capacityProvider: "FARGATE",
      containers: [{ port: 3000 }],
    },
  ],
});

// getLoadBalancer() returns ApplicationLoadBalancer | undefined
const alb = cluster.getLoadBalancer();
```

`getLoadBalancer()` returns `undefined` when the ALB is disabled (`cluster.loadBalancer: false` or `cluster.directAccess: true`). Guard the result before use.

```typescript theme={null}
const alb = cluster.getLoadBalancer();
if (alb !== undefined) {
  // safe to read alb.loadBalancerDnsName, etc.
}
```

## Cluster Configuration

The `cluster` object controls the shared ALB for every service.

| Field          | Type                              | Description                                                                  |
| -------------- | --------------------------------- | ---------------------------------------------------------------------------- |
| `domain`       | `string`                          | Domain for HTTPS access. Omit for default `*.elb.amazonaws.com` DNS.         |
| `loadBalancer` | `false \| "public" \| "internal"` | `"public"` (default) internet-facing, `"internal"` VPC-only, `false` no ALB. |
| `directAccess` | `boolean`                         | EC2-only. Opens container ports directly, no ALB.                            |
| `domainConfig` | `DomainConfig`                    | Advanced routing policies (latency, weighted, geo). Used with `domain`.      |

```typescript theme={null}
// Public ALB with HTTPS (default loadBalancer is "public")
cluster: { domain: "app.example.com" }

// Internal ALB, reachable only inside the VPC
cluster: { loadBalancer: "internal", domain: "internal.example.com" }

// No ALB, for background workers
cluster: { loadBalancer: false }
```

## Service and Health Checks

Each entry in `services` 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.

```typescript theme={null}
services: [
  {
    name: "api",
    capacityProvider: "FARGATE",
    containers: [
      {
        name: "app",
        port: 8080,
        healthCheck: {
          command: [
            "CMD-SHELL",
            "curl -f http://localhost:8080/health || exit 1",
          ],
          interval: 30,
          timeout: 10,
          retries: 3,
        },
      },
    ],
  },
];
```

The container `healthCheck` runs inside the task. ALB target-group health checks default to path `/` on the traffic port and are configured automatically per service.

## Multiple Services and Routing

When a cluster has more than one service with a port, each service needs a `routing` rule so the ALB knows which traffic to send where. Routing supports path patterns and host headers.

```typescript theme={null}
app.addCompute(
  ComputeFactory.build("ApiCluster", {
    type: "ecs",
    cluster: { domain: "api.example.com" },
    services: [
      {
        name: "users",
        capacityProvider: "FARGATE",
        containers: [{ port: 3000 }],
        routing: { path: "/users/*", priority: 100 },
      },
      {
        name: "orders",
        capacityProvider: "FARGATE",
        containers: [{ port: 3001 }],
        routing: { path: "/orders/*", priority: 200 },
      },
    ],
  }),
);
```

| Routing field     | Type     | Description                                  |
| ----------------- | -------- | -------------------------------------------- |
| `path`            | `string` | Path pattern, e.g. `/api/*`.                 |
| `host`            | `string` | Host header, e.g. `api.example.com`.         |
| `priority`        | `number` | 1 to 50000. Lower wins.                      |
| `healthCheckPath` | `string` | Target-group health-check path. Default `/`. |

## Default ALB Settings

Fjall configures the cluster ALB with these defaults.

| Setting                   | Value                                                            |
| ------------------------- | ---------------------------------------------------------------- |
| Scheme                    | Internet-facing (`loadBalancer: "public"`)                       |
| IP address type           | IPv4                                                             |
| Deletion protection       | Disabled                                                         |
| Subnets                   | Public subnets                                                   |
| Cross-zone load balancing | Enabled                                                          |
| Security group            | Auto-created (Fargate) or paired with the EC2 ASG (EC2 capacity) |

## Outputs

The cluster exports the ALB DNS name as a CloudFormation output, keyed by the sanitised cluster name.

```typescript theme={null}
// Produced automatically, e.g. MyClusterLoadBalancerDnsName
{
  key: `${clusterName}LoadBalancerDnsName`,
  exportName: `${clusterName}LoadBalancerDnsName`,
  value: alb.loadBalancerDnsName
}
```

## Cost

| Component | Approximate cost |
| --------- | ---------------- |
| ALB hour  | \~\$0.0225/hour  |
| LCU hour  | \~\$0.008/LCU    |

Load Balancer Capacity Units (LCUs) bill on the highest of new connections, active connections, processed bytes, and rule evaluations.

**Save cost by:**

1. Consolidating services behind one cluster ALB with path or host routing.
2. Disabling the ALB (`loadBalancer: false`) for services that never receive external traffic.
3. Keeping health-check frequency reasonable for the workload.

## Troubleshooting

| Symptom            | Check                                                  |
| ------------------ | ------------------------------------------------------ |
| Unhealthy targets  | Security group rules and container health-check path   |
| 502 errors         | Target-group protocol matches the container port       |
| Slow responses     | ALB target-response-time metrics                       |
| Certificate errors | `cluster.domain` matches the requested ACM certificate |

Inspect the deployed ALB with the AWS CLI:

```bash theme={null}
# Describe the load balancer
aws elbv2 describe-load-balancers --names my-cluster-LoadBalancer

# Check target health
aws elbv2 describe-target-health --target-group-arn arn:aws:elasticloadbalancing:...

# View listeners
aws elbv2 describe-listeners --load-balancer-arn arn:aws:elasticloadbalancing:...
```

## Next Steps

<CardGroup cols={2}>
  <Card title="ECS Cluster" icon="server" href="/resources/compute/ecs-cluster">
    Configure the cluster that owns the load balancer.
  </Card>

  <Card title="VPC" icon="network-wired" href="/resources/networking/vpc">
    Choose the network the ALB and tasks run in.
  </Card>

  <Card title="Security Group" icon="shield-halved" href="/resources/networking/security-group">
    Control inbound and outbound traffic to the ALB.
  </Card>

  <Card title="Compute Factory" icon="microchip" href="/patterns/compute-factory">
    Declare ECS compute with the recommended factory entry point.
  </Card>
</CardGroup>
