Listeners & Routing Rules
When a request reaches an Application Load Balancer (ALB — a load balancer that understands HTTP and HTTPS), something has to decide what to do with it. That job belongs to listeners and rules. A listener watches a specific port for incoming connections, and the rules attached to that listener decide where each request goes. Getting this right is the difference between traffic landing on the correct service and users seeing the wrong app — or a 503 error.
What a listener is
A listener is a process that checks for connection requests on a protocol and port you choose. For an ALB, the protocol is HTTP or HTTPS, and common ports are 80 (plain HTTP) and 443 (HTTPS, the encrypted version). You can have several listeners on one load balancer — for example, one on port 80 and one on port 443.
Every listener has one mandatory default action. This is the catch-all: if no rule matches a request, the default action runs. Most people set the default action to either forward to a target group (a group of servers that receive traffic) or return a fixed 404 response.
When to use which port: Add an HTTPS listener on
443for any production traffic so data is encrypted. Keep an HTTP listener on80only to redirect users to HTTPS — do not serve real content over plain HTTP.
What a rule is
A rule belongs to a listener and has three parts:
| Part | Meaning |
|---|---|
| Priority | A number from 1 to 50000. Lower numbers are evaluated first. |
| Conditions | What must be true to match — for example, the host header is api.example.com or the path is /images/*. |
| Actions | What to do on a match — forward to a target group, redirect to a URL, or fixed-response (return canned text). |
The ALB checks rules in priority order. The first rule whose conditions all match wins, and its action runs. If nothing matches, the listener’s default action runs.
When to use each action
| Action | Use it when… | Don’t use it when… |
|---|---|---|
forward | You want the request to reach real servers in a target group. | You only need a redirect or a static message. |
redirect | You’re sending users to HTTPS or to a new path/domain. | The destination needs server processing. |
fixed-response | You want a maintenance page or block message without any backend. | You need dynamic content. |
Adding a rule (Console)
Suppose you want all requests to /api/* to go to a target group named tg-api, while everything else uses the default.
- Open the EC2 console, then choose Load Balancers in the left menu.
- Select your ALB, open the Listeners and rules tab.
- Click the listener (for example
HTTPS:443), then Manage rules. - Choose Add rule, give it a name like
route-api. - Under Conditions, choose Path and enter
/api/*. - Under Actions, choose Forward to target groups and pick
tg-api. - Set the Priority (for example
10), then Save.
Adding a rule (AWS CLI)
The same rule using AWS CLI v2. You need the listener’s Amazon Resource Name (ARN — a unique ID for the resource) and the target group ARN.
aws elbv2 create-rule \
--listener-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:listener/app/my-alb/0a1b2c3d/abc123 \
--priority 10 \
--conditions '[{"Field":"path-pattern","PathPatternConfig":{"Values":["/api/*"]}}]' \
--actions '[{"Type":"forward","TargetGroupArn":"arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/tg-api/0a1b2c3d"}]'
Output:
{
"Rules": [
{
"RuleArn": "arn:aws:elasticloadbalancing:us-east-1:111122223333:listener-rule/app/my-alb/0a1b2c3d/abc123/9f8e7d6c",
"Priority": "10",
"Conditions": [
{
"Field": "path-pattern",
"PathPatternConfig": { "Values": ["/api/*"] }
}
],
"Actions": [
{ "Type": "forward", "TargetGroupArn": "arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/tg-api/0a1b2c3d" }
],
"IsDefault": false
}
]
}
A redirect rule
To push HTTP to HTTPS, attach this as the default action on your port 80 listener:
aws elbv2 modify-listener \
--listener-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:listener/app/my-alb/0a1b2c3d/http80 \
--default-actions '[{"Type":"redirect","RedirectConfig":{"Protocol":"HTTPS","Port":"443","StatusCode":"HTTP_301"}}]'
The priority gotcha
This is the trap that catches people. Because rules run in priority order and stop at the first match, an overly broad rule with a low priority number (high priority) can shadow more specific rules below it.
Imagine these two rules:
| Priority | Condition | Action |
|---|---|---|
5 | path /* | forward to tg-web |
10 | path /api/* | forward to tg-api |
The rule at priority 5 matches every request because /* matches everything, including /api/orders. The ALB never reaches priority 10, so API traffic wrongly lands on tg-web. The fix: put the specific rule first (lower number) and the broad one last, or let the default action handle the catch-all.
Warning: Order your rules from most specific to least specific. Keep the broad
/*or “match anything” behavior in the default action, not in a high-priority rule.
You can confirm what’s actually configured and in what order with:
aws elbv2 describe-rules \
--listener-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:listener/app/my-alb/0a1b2c3d/abc123 \
--query 'Rules[].{Priority:Priority,Field:Conditions[0].Field,Type:Actions[0].Type}' \
--output table
Output:
-------------------------------------
| DescribeRules |
+----------+--------------+---------+
| Priority | Field | Type |
+----------+--------------+---------+
| 10 | path-pattern | forward |
| default | None | forward |
+----------+--------------+---------+
A note on cost
Listeners and rules themselves are free. You pay for the ALB by the hour (around $0.0225 per hour, roughly $16 per month) plus LCU (Load Balancer Capacity Units, which measure connections, bandwidth, and rule evaluations). The first 10 rule evaluations per request are included in the LCU calculation, so a handful of rules adds no meaningful cost. Hundreds of complex rules can nudge LCU usage up.
Best practices
- Always create an HTTPS listener on
443for production and redirect80to443. - Order rules from most specific to least specific; never let a broad pattern sit above narrow ones.
- Use the listener’s default action for the catch-all instead of a wide high-priority rule.
- Group conditions sensibly — you can combine host header and path in one rule to avoid extra rules.
- Use
fixed-responsefor clean maintenance or block pages instead of relying on backend error pages. - Run
describe-rulesafter every change to confirm the live priority order matches your intent.