Course outline

6.4

Stickiness, Cross-Zone, TLS/SNI and Deregistration Delay

Session affinity cookies, cross-zone traffic maths, certificates and SNI, and draining in-flight requests.

28 min Reading + animations

Tip: tap or hover any dotted-underlined term to see what it means.

By the end of this lesson you will be able to

  • Explain sticky sessions (session affinity), set up duration-based and application-based cookies on an ALB, and know how NLB, GWLB and CLB do stickiness.
  • Explain why a user still loses the cart when a sticky server dies (session ID vs session data), and fix it properly with ElastiCache or DynamoDB.
  • Work out the share of traffic every target gets with cross-zone load balancing on and off, and know the default and the billing for each load balancer type.
  • Describe SSL vs TLS, certificates, public CAs and ACM, and choose between TLS termination, re-encryption and NLB passthrough.
  • Configure an HTTPS listener: default certificate, certificate list and security policy, and explain how SNI picks the right certificate for each domain.
  • Set the deregistration delay (connection draining) and slow start for scale-in, deployments and long requests.
  • Recognise every exam pattern for these four features.

#Four features every load balancer setup touches

Lessons 6.2 and 6.3 built the load balancer: listeners, rules, target groups and health checks. This lesson covers four settings that decide how it behaves under real traffic:

FeatureQuestion it answersWhere you set it
Sticky sessionsShould one user always reach the same target?Target group (ALB, NLB, GWLB); listener (CLB)
Cross-zone load balancingMay a load balancer node in one AZ send traffic to targets in another AZ?Load balancer (NLB, GWLB, CLB) and target group (ALB, NLB)
TLS and SNIWhere is HTTPS decrypted, with which certificate, for which domain?Listener (certificates, security policy)
Deregistration delayHow long may a target finish its in-flight requests before it is removed?Target group (ALB, NLB, GWLB); load balancer (CLB: connection draining)

#Sticky sessions (session affinity)

#Why a user can land on a different server every time

By default a load balancer routes every request on its own. An ALB uses round robin (or least outstanding requests) per request, so one user’s clicks are spread over all targets. That is exactly what you want, unless the application keeps the user’s state in the memory of one server: a shopping cart, a login session, a half-filled form.

Then the first click lands on web-1, which puts the shirt in its RAM; the second click lands on web-2, which has never heard of the shirt. The user sees items appearing and disappearing, or is asked to log in again and again.

Sticky sessions (also called session affinity) make the load balancer send all requests from one client to the same target for a while.

#How an ALB makes a client stick: cookies

An ALB remembers the target in a cookie it gives the browser. Stickiness is switched on per target group, and you choose one of two types:

Duration-basedApplication-based
Who decides how long?The load balancer: the stickiness duration you setYour application: stickiness follows the application’s own session cookie
Cookie the target setsNone neededA custom cookie with a name you configure (for example app_session), any attributes the app needs
Cookie the load balancer setsAWSALBAWSALBAPP (shown to the client as AWSALBAPP-0 … AWSALBAPP-3, because a large cookie is split into up to 4 parts)
Duration setting1 second to 7 days, default 1 day1 second to 7 days, default 1 day
Use it whenThe app has no session cookie of its ownThe app already has a session cookie and stickiness should last as long as that session
Several ALB layersOnly one layer can use it (the name AWSALB is fixed)Works on every layer (each target group has its own cookie name)

Details worth knowing:

  • The load balancer’s cookies are encrypted with a rotating key. They contain a pointer to a target, never user data, and you cannot read or edit them.
  • The ALB resets the expiry on every request, so an active user stays stuck; a user idle for longer than the duration gets a new target.
  • For cross-origin (CORS) requests the ALB also sets AWSALBCORS with SameSite=None; Secure, so browsers send it on cross-site calls.
  • Reserved names: an application cookie name may not start with AWSALB, AWSALBAPP or AWSALBTG. (AWSALBTG is used for stickiness to a target group when a listener rule forwards to several weighted target groups; that is set on the rule, and lesson 6.3 shows weighted forwarding.)
  • The client must accept cookies. A client that drops cookies is routed fresh on every request.
  • If the sticky target is unhealthy, deregistering or gone, the ALB ignores the cookie, chooses a healthy target and updates the cookie. The user is re-stuck there.
  • WebSocket connections are naturally sticky: after the upgrade, the whole connection stays on one target.
  • Restrictions: stickiness does not work when the target group has cross-zone turned off, with the weighted random routing algorithm, or with application-based cookies on weighted target groups.

#Stickiness on NLB, GWLB and CLB

Load balancerHow it sticksNotes
ALBCookies: AWSALB (duration) or custom + AWSALBAPP (application)Configured per target group
NLBSource IP address (source_ip)No cookies: an NLB works at layer 4 and never reads HTTP. Not supported on TLS or QUIC listeners. Everyone behind one NAT gateway or corporate proxy shares an IP and lands on one target.
GWLBFlow hashing: 5-tuple by default, or 3-tuple / 2-tuple (source_ip_dest_ip_proto, source_ip_dest_ip)Keeps both directions of a flow on the same appliance (lesson 6.3)
CLBDuration-based cookie AWSELB, or application-controlled (follows the app’s cookie)Configured per listener; CLB is the legacy generation

The slides say stickiness “works for CLB, ALB and NLB”, and it does, but only CLB and ALB use cookies with an expiry you control. The NLB has no cookie and no duration: it hashes the client’s IP.

#Session ID vs session data: why the cart is still lost when a server dies

This is the question that confuses almost everyone: “The cookie is in the user’s browser, so why is the cart lost when the server dies?”

The answer: the session ID and the session data are two different things, kept in two different places.

  1. What the cookie holds: only the session ID

    The cookie the load balancer gives the browser holds a token, roughly “this user belongs to web-1”. It does not hold the shirt and the trousers. It is the restaurant token, nothing more.

  2. What the server holds: the session data

    The real cart (2 shirts, 1 pair of trousers) is written in web-1’s RAM (or its local disk). Stickiness works by sending the user back to the one place where that data exists.

  3. Normal flow

    The user adds a shirt; web-1 stores it in RAM; the load balancer sets the cookie. The user adds trousers; the browser shows the cookie; the load balancer sends the request to web-1; web-1 combines the shirt from memory with the new trousers.

  4. web-1 crashes or is terminated

    The RAM is wiped, and the cart with it. The next request still carries the cookie saying “web-1”. The load balancer sees that web-1 is dead and is forced to pick web-2.

  5. web-2 has never seen this user

    web-2 looks in its own memory, finds nothing, and answers: “Your cart is empty.” With sticky sessions the session data is trapped inside one server. When the server dies, the data dies.

Sticky sessions and the shopping cart

Two web servers keep each user’s cart in their own memory (RAM). Watch what happens without stickiness, with a stickiness cookie, when the sticky server dies, and when the cart lives in ElastiCache instead.

Scenario

Browser
ALB
web-110.0.1.10RAM: shirt
web-210.0.2.10
add shirt
Step 1 of 3
1

The user adds a shirt. The ALB picks web-1 with round robin, and web-1 writes the cart into its own RAM.

#The real fix: keep session data outside the servers

If the cart is written to a shared, external store instead of web-1’s RAM, it does not matter which server dies or which server the next request reaches. Every server reads the same data.

StoreWhy it fits sessions
Amazon ElastiCache (Valkey, Redis or Memcached)In-memory, sub-millisecond reads, keys with a time to live (TTL), replication across AZs with Valkey or Redis
Amazon DynamoDBFully managed, durable, scales automatically, TTL deletes expired sessions for free
A token in the client (for example a signed JWT)No server-side store at all, for small amounts of data such as identity

This makes the web tier stateless: servers can crash, be terminated by Auto Scaling or be replaced in a deployment, and traffic still spreads evenly. Once state is external, stickiness is not needed.

#Downsides of stickiness

  • Uneven load. Users stuck to a busy target stay there. After a scale-out, the new instances get only new users while the old ones stay overloaded. The longer the duration, the worse; a 7-day cookie can keep a fleet unbalanced for a week.
  • Lost sessions. As shown above, stickiness does not protect state; it only hides the problem until a target fails, is scaled in or is replaced.
  • NAT hot spots on an NLB: one office or one mobile carrier NAT sends thousands of users from one IP to one target.
  • Fewer features: no stickiness with cross-zone off (ALB), with weighted random routing, or on NLB TLS listeners.

Self-checkQuestion

An online shop runs on six EC2 instances behind an ALB with duration-based stickiness. Whenever Auto Scaling terminates an instance, the customers who were on it find their carts empty. What should a solutions architect do to stop this?

#Cross-zone load balancing

#How traffic reaches a target: DNS, nodes, targets

When you enable an AZ for a load balancer, ELB places a load balancer node in that AZ. Traffic then flows in two hops:

  1. Client → node. The load balancer’s DNS name resolves to the IP addresses of its nodes, one per enabled AZ, with a 60-second TTL. Clients pick among them, so over many clients each node receives an equal share: 50/50 with two AZs, a third each with three. DNS does not know how many targets sit behind each node.
  2. Node → target. Each node chooses a target. Cross-zone load balancing decides which targets it may choose from:
    • On: every registered target in all enabled AZs.
    • Off: only targets in its own AZ.

#Worked example: 2 targets in one AZ, 8 in the other

The notes’ example: AZ a has 2 instances, AZ b has 8. DNS sends 50% of the traffic to each node.

Each instance in AZ aEach instance in AZ bBusiest ÷ idlest
Cross-zone off50% ÷ 2 = 25%50% ÷ 8 = 6.25%4×
Cross-zone on100% ÷ 10 = 10%100% ÷ 10 = 10%1×

With cross-zone off, the two instances in AZ a are hammered while the eight in AZ b sit mostly idle. With it on, the load balancer ignores the AZ boundary and spreads the traffic evenly over all ten.

The general rule, with k AZs that have healthy targets, n targets in an AZ and N targets in total:

  • Off: each target gets (1 ÷ k) ÷ n.
  • On: each target gets 1 ÷ N.
  • Traffic that crosses an AZ boundary when on: each node keeps only its own AZ’s share of targets, and on average (k − 1) ÷ k of requests go to another AZ: half with 2 AZs, two thirds with 3. That is the traffic an NLB or GWLB pays inter-AZ data transfer for.

Cross-zone load balancing: off vs on

The load balancer has one node in each AZ. DNS spreads clients evenly across the nodes, so each node receives half of the traffic. AZ a has 2 targets and AZ b has 4.

Scenario

AZ a
AZ b
Clients
Route 53DNS
LB node a
LB node b
a-1
a-2
b-1
b-2
b-3
b-4
LB name?2 node IPs
Step 1 of 4
1

A client resolves the load balancer’s DNS name. Route 53 answers with the IP addresses of the nodes, one per AZ, with a 60-second TTL. Over many clients, each node gets about half of the traffic.

#Defaults and billing for each load balancer type

Load balancerDefaultWhere you change itInter-AZ data when on
ALBAlways on at load balancer levelCan be turned off per target group (load_balancing.cross_zone.enabled=false)Free
NLBOffOn or off for the load balancer; override per target groupCharged (normal inter-AZ data transfer)
GWLBOffLoad balancer attributeCharged
CLBOn if created in the console, off if created with the API or CLILoad balancer attributeFree

Two corrections to the notes: the NLB’s “extra charge” is not a fee for the feature but the regular inter-AZ data transfer charge for the bytes that cross AZs; and the ALB’s cross-zone, while always on at load balancer level, can be turned off per target group (since late 2022). The slides’ table is up to date on both.

#When would you turn it off?

Keeping traffic in its AZ has real benefits, and AWS documents them:

  • No inter-AZ data charges on an NLB or GWLB.
  • Zonal isolation: a problem in one AZ (a bad deployment, a gray failure) cannot spill into targets in another AZ.
  • Slightly lower latency.

The price is capacity planning. With cross-zone off:

  • each AZ must have enough targets for its share, and the AZs should have similar numbers of targets (an Auto Scaling group spread evenly across AZs does this for you, lesson 6.5);
  • if every target in an AZ is unhealthy, the load balancer removes that node’s IP from DNS (DNS failover) and the other AZs take all the traffic;
  • every target group behind the load balancer should use the same AZs: an AZ with no targets for a target group is treated as unhealthy, and an ALB returns 503 for requests that enter an empty AZ;
  • on an ALB target group, sticky sessions and Lambda targets are not supported.

If you cannot guarantee even capacity per AZ, AWS’s advice is to keep cross-zone on.

Cross-zone traffic calculator

Set how many healthy targets each AZ has, pick the load balancer type and switch cross-zone on or off. Every bar is one target and its share of all requests.

Load balancer type

Cross-zone load balancing

AZ a2
AZ b8
AZ c0

NLB: off by default. Turn it on for the load balancer, or override it per target group. When it is on, the bytes that cross AZs pay normal inter-AZ data transfer charges.

AZ a · 2 targets

LB node gets 50% · 25% each

a-125%
a-225%

AZ b · 8 targets

LB node gets 50% · 6.25% each

b-16.25%
b-26.25%
b-36.25%
b-46.25%
b-56.25%
b-66.25%
b-76.25%
b-86.25%

AZ c · 0 targets

no healthy target: removed from DNS

Busiest ÷ idlest target: 4.00×Requests that cross an AZ: 0%

#TLS on a load balancer

#SSL or TLS?

SSL (Secure Sockets Layer) is the original protocol for encrypting web traffic. All versions of SSL are broken and disabled today. TLS (Transport Layer Security) is its modern successor; current versions are TLS 1.2 and TLS 1.3. Every “HTTPS” padlock today is TLS, but people still say “SSL certificate” out of habit, and AWS’s own settings still use names like ELBSecurityPolicy and “SSL certificate”. In exam questions, read “SSL” as “TLS”.

Encryption between the client and the load balancer is called in-flight (or in-transit) encryption. It stops anyone on the path from reading or changing the traffic.

#Certificates, public CAs and ACM

A load balancer proves its identity with an X.509 certificate (a TLS server certificate). It contains the domain names it is valid for, a public key, a validity period, and the signature of a certificate authority (CA). The matching private key stays secret on the server. The browser trusts the certificate only if the name matches what the user typed, it has not expired, and a CA in the browser’s trust store signed it.

  • Public CAs (Let’s Encrypt, GoDaddy, Comodo/Sectigo and others) issue certificates browsers trust. Certificates expire and must be renewed. The industry is shortening lifetimes: from 15 March 2026 public certificates may be valid for at most 200 days.
  • AWS Certificate Manager (ACM) is the AWS way:
    • Public certificates are free when used with integrated services (ELB, CloudFront, API Gateway).
    • You prove you own the domain with DNS validation (a CNAME record, created for you in Route 53) or email validation.
    • ACM renews its certificates automatically, as long as the DNS validation record stays in place, and redeploys them to the load balancer.
    • The private key never leaves AWS: you cannot download a normal ACM certificate or install it on an EC2 instance.
    • Imported certificates (bought from an outside CA and imported into ACM) are supported, but ACM cannot renew them: you must renew and re-import before they expire. ACM emits expiry events to EventBridge, and an AWS Config rule can flag expiring certificates.
    • ACM certificates are Regional: a certificate for an ALB must be in the ALB’s Region; a certificate for CloudFront must be in us-east-1.
    • Certificates can also be uploaded to IAM (the old way, still needed in Regions without ACM).

Side notes (2025–26): ACM public certificates are now issued with a 198-day validity (down from 395 days) and are renewed automatically 45 days before expiry, so nothing changes for you if you use ACM-issued certificates. ACM can also issue exportable public certificates (paid, about $7 per domain name) whose private key you can download and install on EC2 or on-premises servers. The exam still expects “ACM certificates cannot be exported; import or self-manage if the instance itself needs the certificate”.

#Where to decrypt: termination, re-encryption or passthrough

TLS termination (offload)End-to-end re-encryptionTLS passthrough
Load balancer and listenerALB HTTPS listener (or NLB TLS listener)ALB HTTPS listener + HTTPS target group (or NLB TLS listener + TLS target group)NLB TCP listener on 443
Who holds the client-facing certificateThe load balancer (from ACM)The load balancer (from ACM)The targets
Load balancer → targetPlain HTTP (or TCP) inside the VPCEncrypted again with a new TLS sessionThe client’s original encrypted bytes, untouched
Can the load balancer route on path, host, cookies?YesYesNo, it never sees HTTP
CPU cost on targetsNone for TLSSome (TLS to the load balancer)Full TLS work
Typical reasonThe default: offload CPU, one place to manage certificatesCompliance: “encrypted on every hop”The load balancer must never see plain text; the app does its own mutual TLS
  • With re-encryption, the target needs its own certificate, but the ALB does not validate target certificates, so a self-signed certificate is fine.
  • After termination the ALB adds X-Forwarded-Proto: https (and X-Forwarded-For with the client’s IP) so the application knows how the user connected.
  • An ALB can also do mutual TLS (mTLS) with clients, verifying client certificates against a trust store, without passthrough.

Where is TLS decrypted?

The browser always speaks HTTPS. What changes is who holds the certificate and private key, and whether the traffic behind the load balancer is encrypted.

Scenario

VPC10.0.0.0/16
Browser
ACMcertificate
ALBHTTPS :443
web-110.0.1.10
web-210.0.2.10
certificate
Step 1 of 4
1

ACM gives the ALB a certificate for www.shop.example. ACM keeps the private key; you never download it, and ACM renews the certificate by itself.

#The HTTPS listener: default certificate, certificate list, security policy

An HTTPS listener on an ALB (or a TLS listener on an NLB) has three TLS settings:

SettingWhat it is
Default certificateExactly one, required. Used when the client sends no SNI, or when no certificate in the list matches the requested name.
Certificate listOptional extra certificates, so one listener can serve many domains with their own certificates. Up to 25 per ALB by default (not counting the default), adjustable. The load balancer chooses among them with SNI.
Security policyWhich TLS versions and ciphers the listener accepts. Choose a strict policy for modern clients, or an older one to support legacy clients.

Security policy defaults today:

  • A listener created in the console gets ELBSecurityPolicy-TLS13-1-2-Res-PQ-2025-09: TLS 1.3 and 1.2 only, a restricted set of strong ciphers, and post-quantum key exchange.
  • A listener created with the CLI, CloudFormation or CDK without a policy gets the older ELBSecurityPolicy-2016-08, which still accepts TLS 1.0 and 1.1. Name a modern policy explicitly in your templates.
  • If old devices that only speak TLS 1.0 must still connect, attach a policy that includes TLS 1.0. That is what the slides mean by “a security policy to support older versions of SSL/TLS”.

#Classic Load Balancer: one certificate

The CLB (v1) supports one certificate per listener and no SNI. To serve several domains with different certificates on a CLB you need one CLB per domain (or one certificate that lists every name as a Subject Alternative Name). The ALB and NLB (v2) support multiple certificates on a listener, using SNI.

#SNI (Server Name Indication)

#The problem SNI solves

Picture one load balancer serving www.cats.com and www.dogs.com. The TLS handshake happens before any HTTP is sent, so when a connection arrives the server cannot read the Host header yet. It does not know which site the user wants, so it does not know which certificate to show. Before SNI it always showed the same one: a visitor to dogs.com received the cats.com certificate and the browser displayed a red “Not secure” warning.

The old fix was one IP address per HTTPS site, which meant one load balancer per site. Expensive, and IPv4 addresses are scarce.

#How SNI works

SNI is an extension to TLS. In the very first handshake message, the ClientHello, the browser includes the hostname it wants, in plain text: “I am here for www.dogs.com”. The server reads it and answers with the matching certificate.

On an ALB the selection works like this:

  1. The client sends a hostname with SNI.
  2. If exactly one certificate in the list matches it (by its common name or a Subject Alternative Name, wildcards included), the ALB uses that one.
  3. If several match, the ALB picks the best one the client supports (elliptic-curve keys before RSA, then not expired, stronger hash, longer key).
  4. If the client sent no SNI or nothing matches, the ALB uses the default certificate, which usually means a name mismatch error for the client.

SNI only chooses the certificate. Which target group gets the request is still decided by the listener rules (usually a host-header rule) after decryption.

SNI: one ALB, many certificates

One HTTPS listener serves www.cats.example (the default certificate) and www.dogs.example (in the certificate list). Each site has its own target group.

Scenario

Browser
ALBHTTPS :443
cats targets
dogs targets
ClientHello · SNI: www.dogs.example
Step 1 of 6
1

The user types www.dogs.example. In the very first handshake message, before anything is encrypted, the browser names the site it wants. That field is Server Name Indication.

#Who supports SNI

  • ALB: yes, multiple certificates per HTTPS listener.
  • NLB: yes, multiple certificates per TLS listener.
  • CloudFront: yes (SNI is its default and free; a dedicated IP per distribution costs extra).
  • CLB: no, one certificate per listener.

Practically every client made in the last 15 years sends SNI. The ones that do not are very old browsers and operating systems, old Java and Python libraries, and some embedded devices.

One more fact: because the SNI hostname travels in plain text, anyone watching the network can see which site you visit, though not what you do there. The newer Encrypted Client Hello extension hides it, but it is not yet common and is not on the exam.

Self-checkQuestion

A company serves three websites, each with its own domain and its own TLS certificate. Today it runs three Classic Load Balancers. It wants one load balancer, HTTPS for all three domains, and less CPU load on its instances. What should it do?

#Deregistration delay (connection draining)

#What happens when a target is removed

A target leaves a target group when Auto Scaling scales in, when a deployment replaces it, or when you deregister it by hand. The load balancer does not cut it off instantly:

  1. Draining starts

    The target enters the draining state. The load balancer stops sending it new requests; every new request goes to the other targets.

  2. In-flight requests finish

    Requests that were already in progress on the target are allowed to complete, for up to the deregistration delay.

  3. Done

    When the target has no in-flight requests and no active connections, the ALB completes the deregistration early, without waiting for the full delay. Otherwise, when the delay runs out, the target becomes unused and any connections still open are closed (clients see a 5xx error). If the target belongs to an Auto Scaling group, Auto Scaling waits for this before terminating the instance.

ALB / NLB / GWLBCLB
NameDeregistration delayConnection draining
WhereTarget group attribute deregistration_delay.timeout_secondsLoad balancer attribute
Range0–3600 seconds (0 turns it off)1–3600 seconds when enabled
Default300 seconds300 seconds (on by default in the console, off through the API/CLI)

NLB extras: QUIC traffic always uses 300 seconds; the attribute deregistration_delay.connection_termination.enabled closes the remaining connections at the end of the delay (otherwise an idle-but-open TCP connection can keep receiving traffic); AWS recommends at least 120 seconds on an NLB.

#Choosing the value

  • Short requests (APIs answering in milliseconds): a low value such as 30 seconds is plenty. A long delay only slows scale-in and deployments.
  • Long requests (uploads, reports, video processing): set the delay longer than the longest request, or the end of it is cut off.
  • Long-lived connections (WebSockets, long polling, HTTP keep-alive that never idles): they never “finish”, so the drain always runs to the full delay. Make the application close connections when it is told to stop (on SIGTERM), so clients reconnect elsewhere.
  • 0 means no draining: in-flight requests are dropped. Use it only for tests or stateless, instantly retried traffic.

Deregistration delay during scale-in

An Auto Scaling group is attached to the target group. When it removes web-1, the load balancer first drains it. The delay is a target group setting: 300 seconds by default, 0 to 3600 allowed.

Scenario

Users
ALB
web-1healthy
web-2healthy
Auto Scaling
checkout (in flight)
Step 1 of 6
1

A user’s checkout request is being processed on web-1. It takes a few seconds.

#Slow start mode (ALB)

Draining protects targets that are leaving. Slow start protects targets that are arriving. A fresh instance with cold caches or a runtime that is still warming up can be overwhelmed if it gets its full share of requests the moment it passes its health check.

  • With slow start on, a new healthy target’s share rises linearly over the slow start duration: 30 to 900 seconds (default 0, off).
  • It is an ALB target group setting and works with the round robin algorithm only, not with least outstanding requests or weighted random.
  • A target that already existed when you turned slow start on does not enter slow start, and a newly registered target enters it only when at least one other healthy target is not in slow start.

#How these features fit together in system design

  • Stateless web tier first. Put sessions in ElastiCache or DynamoDB, files in S3 or EFS. Then stickiness is unnecessary, scale-in is safe, and any target can serve any request. Keep stickiness for legacy applications you cannot change, with a short duration.
  • Leave cross-zone on for ALBs. For NLBs, turn it on when targets are uneven across AZs or when even load matters more than the inter-AZ data bill; leave it off when you want zonal isolation and you spread targets evenly with Auto Scaling.
  • Terminate TLS at the load balancer with ACM certificates by default; add an HTTPS target group when compliance requires encryption on every hop; use NLB passthrough only when the load balancer must never decrypt. Use a modern security policy and put all your domains on one listener with SNI.
  • Tune draining to your request length: 30 seconds for APIs, longer than the longest upload for upload services, and add slow start for instances that need to warm up.
  • Watch the metrics: per-target RequestCount (imbalance from stickiness or cross-zone), HTTPCode_ELB_5XX_Count (draining too short, empty AZ), and ACM certificate expiry for imported certificates.

#Try it yourself

# Variables: your target group, listener and load balancer
TG=arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/web/0123456789abcdef
LISTENER=arn:aws:elasticloadbalancing:us-east-1:111122223333:listener/app/web-alb/50dc6c495c0c9188/f2f7dc8efc522ab2
NLB=arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/net/tcp-nlb/1234567890abcdef

# 1. Duration-based stickiness for one hour
aws elbv2 modify-target-group-attributes --target-group-arn $TG --attributes \
  Key=stickiness.enabled,Value=true Key=stickiness.type,Value=lb_cookie \
  Key=stickiness.lb_cookie.duration_seconds,Value=3600

#    ...or application-based stickiness that follows the app's app_session cookie
aws elbv2 modify-target-group-attributes --target-group-arn $TG --attributes \
  Key=stickiness.enabled,Value=true Key=stickiness.type,Value=app_cookie \
  Key=stickiness.app_cookie.cookie_name,Value=app_session \
  Key=stickiness.app_cookie.duration_seconds,Value=86400

# 2. See the cookie: the response carries AWSALB and AWSALBCORS
curl -sI https://www.shop.example/ | grep -i set-cookie

# 3. Cross-zone: turn it on for an NLB (inter-AZ data charges apply)...
aws elbv2 modify-load-balancer-attributes --load-balancer-arn $NLB \
  --attributes Key=load_balancing.cross_zone.enabled,Value=true
#    ...or turn it off for one ALB target group
aws elbv2 modify-target-group-attributes --target-group-arn $TG \
  --attributes Key=load_balancing.cross_zone.enabled,Value=false

# 4. A free ACM certificate with DNS validation
aws acm request-certificate --domain-name www.dogs.example \
  --subject-alternative-names dogs.example --validation-method DNS
aws acm describe-certificate --certificate-arn $CERT \
  --query "Certificate.[Status,RenewalEligibility,NotAfter]"

# 5. HTTPS listener: default certificate + modern security policy, then SNI certificates
aws elbv2 modify-listener --listener-arn $LISTENER \
  --certificates CertificateArn=$CATS_CERT \
  --ssl-policy ELBSecurityPolicy-TLS13-1-2-Res-PQ-2025-09
aws elbv2 add-listener-certificates --listener-arn $LISTENER \
  --certificates CertificateArn=$DOGS_CERT
aws elbv2 describe-listener-certificates --listener-arn $LISTENER

# 6. Watch SNI choose the certificate (and the default one when SNI is missing)
openssl s_client -connect web-alb-123456.us-east-1.elb.amazonaws.com:443 \
  -servername www.dogs.example </dev/null 2>/dev/null | openssl x509 -noout -subject
openssl s_client -connect web-alb-123456.us-east-1.elb.amazonaws.com:443 \
  -noservername </dev/null 2>/dev/null | openssl x509 -noout -subject

# 7. Draining: 30 s for a short-request API, and slow start of 2 minutes
aws elbv2 modify-target-group-attributes --target-group-arn $TG --attributes \
  Key=deregistration_delay.timeout_seconds,Value=30 \
  Key=slow_start.duration_seconds,Value=120

# 8. Deregister a target and watch it drain
aws elbv2 deregister-targets --target-group-arn $TG --targets Id=i-0abc1234def567890
aws elbv2 describe-target-health --target-group-arn $TG \
  --query "TargetHealthDescriptions[].[Target.Id,TargetHealth.State]"   # draining → unused

#Summary

Key takeaways

  • Sticky sessions send one client to the same target. ALB: duration-based cookie AWSALB or application-based (your cookie + AWSALBAPP), set per target group, duration 1 s to 7 days, default 1 day; names starting with AWSALB, AWSALBAPP, AWSALBTG are reserved. CLB: AWSELB. NLB: source IP, no cookies. GWLB: flow hashing.
  • The cookie holds only the session ID; the session data lives in the server’s RAM. When that server dies, the cart dies. The real fix is an external session store, ElastiCache or DynamoDB, which makes the tier stateless and stickiness unnecessary.
  • Stickiness causes imbalance (worse with long durations and NAT) and does not work with ALB cross-zone off or weighted random routing.
  • Cross-zone: DNS splits traffic evenly over the nodes; with cross-zone off each node uses only its AZ’s targets (2 + 8 targets → 25% vs 6.25%), with it on every target gets an equal share (10% each).
  • ALB: always on at load balancer level, free, can be turned off per target group. NLB / GWLB: off by default, inter-AZ data charges when on. CLB: on in the console, off via API/CLI, free.
  • TLS replaced SSL; certificates come from public CAs or ACM (free public certificates, automatic renewal, private key stays in AWS; imported certificates are not renewed; CloudFront needs us-east-1).
  • Termination at the load balancer offloads CPU; re-encryption (HTTPS target group) keeps every hop encrypted; NLB TCP passthrough leaves decryption to the targets.
  • An HTTPS listener has one default certificate, an optional certificate list (25 per ALB by default) and a security policy (TLS versions and ciphers; legacy policies for old clients).
  • SNI: the client puts the hostname in the ClientHello, and the load balancer picks the matching certificate. ALB, NLB and CloudFront support it; CLB does not (one certificate). No SNI or no match → default certificate.
  • Deregistration delay (CLB: connection draining): default 300 s, 0–3600 s, per target group. Draining targets get no new requests while in-flight ones finish. Raise it if scale-in drops requests; lower it for short requests and faster deployments. Slow start (30–900 s) ramps up new ALB targets.