AWS Application Load Balancer (ALB): How It Works, Use Cases, and Terraform

When you build a web application or API on AWS and need to distribute traffic across multiple servers, an Application Load Balancer (ALB) is the standard tool. It accepts HTTP and HTTPS requests, applies routing rules based on the content of each request, and forwards traffic to the correct backend. Most production web workloads on AWS have an ALB at the front.

ALBs work at Layer 7, which means they can read HTTP headers, inspect URL paths, and make routing decisions based on request content. This is what separates them from a basic network load balancer that only looks at IP and port. You can run an API, a frontend, and an admin panel behind a single ALB and it routes each request to the right place using listener rules.

This page explains how an ALB works, walks through the key concepts (listeners, rules, target groups, health checks), covers security setup and TLS termination, and includes a ready-to-use Terraform example. For a hands-on step-by-step walkthrough, see the HTTP Load Balancer Setup guide.

Simple explanation

Think of an ALB as a traffic router sitting at the entrance to your application. Every HTTP request that arrives at your domain passes through the ALB first. The ALB looks at the request: what URL, what domain, what headers. Then it applies your routing rules to decide which backend should handle it.

If your app is a single service running on three EC2 instances, the ALB simply distributes requests across all three and skips any that are unhealthy. If your app is a collection of microservices, the ALB routes each request to the right service based on the URL path or subdomain, all through a single entry point and a single DNS name.

Analogy: the hotel front desk. Imagine a hotel where guests all walk in through the same front door. Some want the restaurant, some want the gym, some want to check in. The front desk (your ALB listener) greets every guest, figures out what they need, and directs them to the right place. The restaurant is one target group, the gym is another, and the check-in counter is the default. The front desk also calls ahead to make sure each department is open before sending anyone there. That call-ahead check is the health check.

The key difference from a basic load balancer: A Network Load Balancer routes by IP and port only. An ALB reads the HTTP request before deciding where to send it. This makes it possible to route /api/* to one service and /web/* to another through a single entry point, without running separate load balancers for each service.

When to use an ALB

Use an ALB when your workload communicates over HTTP or HTTPS. Specific cases where ALB is the right choice:

  • Web applications: any app users access through a browser over HTTPS
  • REST APIs: HTTP APIs distributed across multiple backend instances
  • Microservices: multiple services sharing a single domain entry point, routed by path or subdomain
  • Path-based routing: send /api/* to one target group and /app/* to another
  • Host-based routing: serve api.example.com and admin.example.com from one ALB
  • TLS termination: terminate HTTPS at the ALB using a free ACM certificate; backends receive plain HTTP inside the VPC
  • Container workloads: ECS services with dynamic port mapping, or Kubernetes services via an ingress controller
  • Lambda backends: route specific paths to a Lambda function with no servers required
  • Auto Scaling: pair with an Auto Scaling group so new instances automatically register and receive traffic

Quick decision rule: If your app speaks HTTP or HTTPS, use ALB. If it speaks raw TCP, UDP, or a custom binary protocol, use NLB instead. When in doubt, ALB is the right starting point for anything web-facing.

When not to use an ALB

ALBs only understand HTTP and HTTPS. If your workload does not use HTTP, use a Network Load Balancer (NLB) instead. Specific cases where NLB is a better fit:

  • Non-HTTP protocols: TCP, UDP, TLS passthrough, database connections, MQTT, or any custom binary protocol
  • Static IP requirement: ALBs use DNS and do not have fixed IP addresses. If a downstream firewall requires a fixed IP for allowlisting, use NLB (which supports Elastic IPs) or place a Global Accelerator in front of the ALB
  • Ultra-low latency TCP/UDP: NLB operates at Layer 4 with near-zero added overhead; ALB adds a small processing cost for HTTP inspection
  • Preserving client source IP natively: NLB preserves the original source IP transparently; ALB passes it via the X-Forwarded-For header, which requires your application to read it deliberately

See the Internal Load Balancers guide for a full comparison of internal ALB vs internal NLB for service-to-service traffic.

How an AWS ALB works

Here is the full request flow from a client making an HTTPS request to a backend instance sending a response:

  1. Client makes a request. A browser sends an HTTPS request to app.example.com. DNS resolves this domain to the ALB’s DNS name via a Route 53 alias record (see DNS with Route 53).
  2. ALB receives the connection. The request hits the ALB on port 443. The ALB terminates the TLS connection using the ACM certificate attached to the listener. Your backend instances never see the raw TLS handshake.
  3. Listener identifies the request. The HTTPS listener on port 443 receives the decrypted HTTP request and passes it through the rule evaluation engine.
  4. Rules are evaluated in priority order. The listener checks each rule from lowest to highest priority number. Rules can match on path pattern, host header, HTTP headers, query string, HTTP method, or source IP. The first matching rule wins.
  5. A target group is selected. The matching rule’s action forwards the request to a specific target group. If no rule matches, the listener’s default rule applies as the catch-all.
  6. A healthy target is chosen. From within the selected target group, the ALB picks an available, healthy target using round-robin. If a target is failing health checks, it is skipped entirely.
  7. Request is forwarded. The ALB opens a new connection to the chosen target on the target group’s configured port and sends the HTTP request. The original client IP is passed in the X-Forwarded-For header.
  8. Response is returned. The backend responds, and the ALB proxies the response back to the client over the original TLS connection.

Concrete routing example: A single ALB serves both app.example.com and api.example.com. Rule 1 (priority 10): Host header is api.example.com AND path starts with /v2/, forward to api-v2-tg. Rule 2 (priority 20): Host header is api.example.com, forward to api-v1-tg. Default rule: forward all remaining requests to web-app-tg. Two domains, three services, one ALB.

Core concepts

Listeners

A listener is bound to a specific port and protocol on the ALB. You typically create two: an HTTP listener on port 80 (configured to redirect all traffic to HTTPS) and an HTTPS listener on port 443 (which handles real traffic). An ALB supports up to 50 listeners, though two is the standard setup for almost all workloads.

An HTTPS listener requires an ACM certificate attached to it. The ALB uses that certificate to terminate TLS connections, then forwards plain HTTP to your backends inside the private network. You can attach multiple certificates to one listener; the ALB uses SNI to pick the correct certificate based on the domain the client connects to.

Rules

Rules are the routing logic inside a listener. Each rule has conditions (what to match) and an action (what to do). Available actions:

  • Forward: send the request to a specific target group
  • Redirect: return an HTTP 301 or 302 response (the standard way to implement HTTP to HTTPS redirect)
  • Fixed response: return a static status code and body, useful for maintenance pages or load-balancer-level health endpoints
  • Authenticate: integrate with Amazon Cognito or an OIDC provider to authenticate users before forwarding

Rules are evaluated in priority order. The rule with the lowest priority number is evaluated first. Every listener must have a default rule that acts as the catch-all for requests that do not match any other rule.

Target groups

A target group is a named pool of backends. Each target group has a protocol, a port, and a target type:

  • instance: EC2 instances identified by instance ID
  • ip: IP addresses, used for containers with dynamic port mapping, on-premises servers connected via VPN or Direct Connect, or any other IP-addressable resource in the subnet
  • lambda: a Lambda function; the ALB invokes it synchronously with the HTTP request as the event payload
  • alb: another ALB, used in advanced multi-tier routing scenarios

Health checks

The ALB continuously polls each registered target to verify it can accept traffic. Health check configuration lives at the target group level. Each target group has its own settings:

  • Path: the URL to check (e.g., /health). Avoid using / in production. A dedicated health endpoint that tests your database or cache connection gives more reliable signal.
  • Interval: how often to check. Default: 30 seconds.
  • Timeout: how long to wait for a response. Default: 5 seconds.
  • Healthy threshold: consecutive successes before marking healthy. Default: 5.
  • Unhealthy threshold: consecutive failures before removing from rotation. Default: 2.
  • Success codes: HTTP codes that count as healthy. Default: 200. Accepts a range (200-299) or a list (200,301).

What happens when all targets fail health checks? The ALB has nowhere to send matching requests and returns a 502 or 503 to the client. This is one of the most common sources of unexpected outages. See Load Balancer Backend Unhealthy for a full troubleshooting checklist.

Internet-facing vs internal ALB

When you create an ALB, you choose its scheme: internet-facing or internal. This setting cannot be changed after creation.

PropertyInternet-facingInternal
IP addressesPublic and privatePrivate only
DNS resolutionResolves to public IPs from anywhereResolves to private IPs within VPC only
Appropriate subnetsPublic subnets (with internet gateway route)Private subnets
Typical useEnd-user HTTP/HTTPS traffic from the internetService-to-service traffic inside the VPC

A critical point that confuses beginners: the ALB must be in public subnets for internet-facing use, but your EC2 instances should be in private subnets. The ALB’s subnets are where it receives incoming connections. Your instances only need to accept traffic from the ALB security group. They never need a public IP or a direct internet route.

For traffic between internal services (for example, your API tier calling your user service), use an internal ALB placed in private subnets. It gets only private IP addresses and a DNS name that resolves only within the VPC. See Internal Load Balancers for a full guide including internal ALB vs internal NLB.

Path-based and host-based routing

Path-based routing

Path-based routing matches the URL path of the incoming request. Rules with lower priority numbers are evaluated first, and the first match wins.

Example: a single ALB fronts three services.

  • Priority 10: path is /api/*, forward to api-service-tg
  • Priority 20: path is /auth/*, forward to auth-service-tg
  • Default: all other requests, forward to web-frontend-tg

A request to https://app.example.com/api/users matches priority 10 and goes to the API service. A request to https://app.example.com/ matches no specific rule and falls through to the web frontend. Three services, one domain, one ALB.

Host-based routing

Host-based routing matches the Host HTTP header, which is the domain name the client addressed the request to. This lets a single ALB serve multiple subdomains and route each to a different backend.

Example: all three subdomains point at the same ALB DNS name via Route 53 alias records.

  • Priority 10: host is api.example.com, forward to api-service-tg
  • Priority 20: host is admin.example.com, forward to admin-service-tg
  • Default: all other hosts, forward to web-frontend-tg

Rules can combine both conditions: host is api.example.com AND path starts with /v2/. This gives precise control over routing with a small set of rules. Multiple conditions within a single rule use AND logic. All conditions must match for the rule to fire.

Security and TLS

Security group setup

An ALB is controlled by security groups, and the correct setup requires two groups working together:

  • ALB security group: allows inbound TCP 80 and 443 from 0.0.0.0/0 (and ::/0 for IPv6) for an internet-facing ALB. This group faces the internet.
  • Target security group: allows inbound on the application port sourced from the ALB security group ID, not from a CIDR range. This means only the ALB can reach your instances.

Do not open your target security group to 0.0.0.0/0. If you allow the open internet inbound on your instance security group, anyone can bypass the ALB and hit your instances directly, skipping your WAF rules, routing logic, and rate limiting. Always use the ALB security group ID as the inbound source rule on your targets, never a CIDR range.

HTTPS with ACM

The standard pattern is to terminate TLS at the ALB using a free certificate from AWS Certificate Manager (ACM). You request the certificate, validate domain ownership via DNS, and attach it to the HTTPS listener. ACM renews the certificate automatically before it expires. No calendar reminders needed.

The recommended TLS policy for new ALBs is ELBSecurityPolicy-TLS13-1-2-2021-06. This enforces TLS 1.2 as the minimum and supports TLS 1.3, satisfying most compliance frameworks.

Traffic from the ALB to your backend instances typically travels as plain HTTP inside the private VPC. This is acceptable because the traffic never leaves the VPC. If compliance requires end-to-end encryption, configure the target group protocol as HTTPS and install a certificate on each backend.

WAF integration

Attach an AWS WAF web ACL to an ALB to filter requests before they reach your application. WAF on an ALB provides rate limiting, SQL injection and XSS protection, bot control, and geographic blocking. See Network Security Best Practices for guidance on where WAF fits in a layered security architecture.

Common use cases

EC2 web application. The classic pattern: two or more EC2 instances behind an internet-facing ALB. The ALB distributes requests across healthy instances. Pair with an Auto Scaling group to add and remove instances based on demand. The scaling group registers new instances with the target group automatically when they launch.

ECS / containerized services. ECS can register container tasks directly into an ALB target group using the ip target type. Each task gets its own IP and registers when it starts, deregisters when it stops. Dynamic port mapping means multiple tasks on the same EC2 host can bind different ports without conflict.

Microservices behind one entry point. Multiple independent services, each in its own target group, all fronted by a single ALB. Listener rules route by path or host. Each team deploys their service independently; the ALB routing configuration is the only coordination point between teams.

Lambda HTTP endpoint. An ALB can route specific paths to a Lambda function without needing API Gateway. This is useful when you want a lightweight HTTP interface for a Lambda function, especially for workloads that fit the ALB pricing model better than API Gateway.

Terraform example

This example creates a complete ALB setup: the load balancer, two target groups, an HTTPS listener with an ACM certificate, an HTTP-to-HTTPS redirect listener, and a path-based routing rule.

# The ALB itself — internet-facing, placed in two public subnets across different AZs
resource "aws_lb" "main" {
  name               = "main-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = [aws_subnet.public_1a.id, aws_subnet.public_1b.id]

  # Prevents accidental deletion via Terraform or the console
  enable_deletion_protection = true

  tags = {
    Name        = "main-alb"
    Environment = "production"
  }
}

# Default target group — receives all requests that don't match a specific rule
resource "aws_lb_target_group" "app" {
  name        = "app-target-group"
  port        = 8080
  protocol    = "HTTP"
  vpc_id      = aws_vpc.main.id
  target_type = "instance"

  health_check {
    enabled             = true
    path                = "/health"
    interval            = 30
    timeout             = 5
    healthy_threshold   = 2  # 2 consecutive successes before marking healthy
    unhealthy_threshold = 3
    matcher             = "200"
  }
}

# API target group — receives requests matched by the path-based rule below
resource "aws_lb_target_group" "api" {
  name        = "api-target-group"
  port        = 8081
  protocol    = "HTTP"
  vpc_id      = aws_vpc.main.id
  target_type = "instance"

  health_check {
    enabled  = true
    path     = "/api/health"
    matcher  = "200"
  }
}

# HTTPS listener — primary listener; handles real traffic on port 443
resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_lb.main.arn
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS13-1-2-2021-06"  # enforces TLS 1.2+
  certificate_arn   = aws_acm_certificate_validation.main.certificate_arn

  # Default: send everything to the app target group unless a rule matches
  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.app.arn
  }
}

# HTTP listener — immediately redirects all port 80 requests to HTTPS
resource "aws_lb_listener" "http_redirect" {
  load_balancer_arn = aws_lb.main.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "redirect"
    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

# Path-based routing rule — requests to /api/* go to the API target group
# Lower priority number = evaluated first; this rule is checked before the default
resource "aws_lb_listener_rule" "api_routing" {
  listener_arn = aws_lb_listener.https.arn
  priority     = 100

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.api.arn
  }

  condition {
    path_pattern {
      values = ["/api/*"]
    }
  }
}

ALB vs NLB vs CLB

FeatureALBNLBCLB (legacy)
OSI layerLayer 7 (application)Layer 4 (transport)Layer 4 and 7 (limited)
ProtocolsHTTP, HTTPS, gRPCTCP, UDP, TLSHTTP, HTTPS, TCP, SSL
Content-based routingYes: path, host, headers, query stringNoLimited
Static IPNo (DNS-based)Yes (Elastic IPs)No
WAF integrationYesNoNo
WebSocket supportYesYesNo
Lambda targetsYesNoNo
Preserves source IPVia X-Forwarded-For headerYes (natively)Via X-Forwarded-For
Best forWeb apps, REST APIs, microservicesHigh-throughput TCP/UDP, static IP neededLegacy only. Do not use for new workloads.

Decision guide: Choose ALB when your workload uses HTTP or HTTPS and you need content-based routing, WAF integration, or Lambda targets. Choose NLB when you need a static IP, a non-HTTP protocol, or ultra-low-latency TCP/UDP load balancing. Avoid CLB for any new workload. It exists for legacy compatibility only and lacks most features of both ALB and NLB.

Common beginner mistakes

  1. Creating the ALB in only one Availability Zone. An ALB must span subnets in at least two AZs. If you specify only one subnet, ALB creation fails. A single-AZ load balancer is a single point of failure. One AZ issue takes down your entire application.
  2. Putting an internet-facing ALB in private subnets. An internet-facing ALB must be in public subnets with a route to an internet gateway. Without that, the ALB cannot receive external traffic even though its scheme is internet-facing. Your EC2 instances can remain in private subnets. See Subnets in AWS for how public and private subnets differ.
  3. Not allowing traffic from the ALB security group to the target security group. After creating the ALB security group and attaching it to the ALB, you must add an inbound rule to the EC2 instances’ security group that allows the application port from the ALB security group ID. Without this rule, health checks fail and all targets show as unhealthy, even if the application is running fine.
  4. Opening the target security group to 0.0.0.0/0 instead of scoping it to the ALB. If you allow the open internet inbound on your instance security group, anyone can bypass the ALB and hit your instances directly, skipping WAF rules, rate limits, and routing logic. Always reference the ALB security group ID as the source rule, not a CIDR range.
  5. Assuming ALB works for non-HTTP protocols. ALB handles HTTP and HTTPS only. If you try to use it for a TCP database proxy, an MQTT broker, or a custom binary protocol, it will not work. Use NLB for anything that is not HTTP-based.

Frequently asked questions

What is the difference between a listener and a target group?

A listener is the front door. It defines the port and protocol the ALB accepts connections on (e.g., port 443, HTTPS). A target group is the back door. It defines where traffic is forwarded to: a set of EC2 instances, IP addresses, or Lambda functions. Listener rules sit in between, evaluating each incoming request and deciding which target group receives it.

Can an ALB route to Lambda functions?

Yes. ALB supports Lambda as a target type. When a request matches a rule pointing to a Lambda target group, the ALB invokes the Lambda function with the HTTP request details in the event payload and returns the function response to the client. This works well for serverless HTTP backends that handle occasional bursts of requests.

Does an ALB support WebSockets?

Yes. ALB natively supports WebSocket connections. When a client upgrades an HTTP connection to WebSocket, the ALB maintains the persistent connection and routes subsequent frames to the same backend target. No special configuration is required beyond allowing the WebSocket upgrade in your application.

Why are my ALB health checks failing even though my application is running?

The three most common causes: (1) the target instance security group does not allow inbound traffic from the ALB security group on the health check port, (2) the health check path returns a non-2xx status code, (3) the health check timeout is shorter than your application response time. Check all three before digging further.

Can I use an ALB with Auto Scaling?

Yes, and this is the standard pattern. You create an Auto Scaling group and configure it to register new instances with a specific target group automatically. When the group scales out, new instances register and start receiving traffic once health checks pass. When the group scales in, instances drain in-flight connections before deregistering.

Last verified: 21 April 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.