# AWS ACM certificate on an Application Load Balancer (HTTPS)

> Request a free ACM certificate with DNS validation, attach it to an ALB HTTPS listener with a TLS 1.3 policy, redirect HTTP, keep managed renewal working.

Source: https://ssl.sh/guides/aws-acm-alb/
Last updated: 2026-11-10

An Application Load Balancer (ALB) serves HTTPS with a free ACM certificate: request the certificate with DNS validation, attach it to a port-443 listener and redirect port 80 to HTTPS. ACM then renews the certificate without your involvement.

Commands use the AWS CLI v2 and reflect ACM and Elastic Load Balancing as of November 2026. The console offers the same steps.

## Prerequisites

The ALB and its target group should already serve your application over HTTP.

- AWS CLI v2 configured with permissions for ACM and Elastic Load Balancing (`aws sts get-caller-identity` works).
- An internet-facing ALB, its target group, and their ARNs; a security group allowing inbound 80 and 443.
- Access to the domain's DNS (Route 53 or another provider) to add a CNAME and point `example.com` at the ALB.
- CAA records, if you use them, that allow Amazon (`amazon.com`, `amazontrust.com`, `awstrust.com` or `amazonaws.com`); check with the [CAA checker](https://ssl.sh/tools/caa-checker/).

## Step 1: Request the certificate

Request the certificate in the ALB's region, because a listener can only use an ACM certificate from its own region:

```bash
export AWS_REGION=eu-west-1
CERT_ARN=$(aws acm request-certificate \
  --domain-name example.com \
  --subject-alternative-names www.example.com \
  --validation-method DNS \
  --key-algorithm EC_prime256v1 \
  --query CertificateArn --output text)
echo "$CERT_ARN"
```

`EC_prime256v1` requests an ECDSA key; use `RSA_2048` if old clients must connect.

## Step 2: Create the DNS validation records

ACM validates each name through a CNAME record. Print the records it expects:

```bash
aws acm describe-certificate --certificate-arn "$CERT_ARN" \
  --query 'Certificate.DomainValidationOptions[].ResourceRecord' --output table
```

Create each CNAME at your DNS provider (in the Route 53 console, the certificate page offers **Create records in Route 53**). Then wait:

```bash
aws acm wait certificate-validated --certificate-arn "$CERT_ARN"
```

## Step 3: Add the HTTPS listener

The port-443 listener presents the certificate and forwards to the target group. The `ELBSecurityPolicy-TLS13-1-2-2021-06` policy allows TLS 1.3 and 1.2:

```bash
ALB_ARN=arn:aws:elasticloadbalancing:eu-west-1:111122223333:loadbalancer/app/web/0123456789abcdef
TG_ARN=arn:aws:elasticloadbalancing:eu-west-1:111122223333:targetgroup/web/0123456789abcdef
aws elbv2 create-listener --load-balancer-arn "$ALB_ARN" \
  --protocol HTTPS --port 443 \
  --certificates CertificateArn="$CERT_ARN" \
  --ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06 \
  --default-actions Type=forward,TargetGroupArn="$TG_ARN"
```

Replace the ARNs with yours (`aws elbv2 describe-load-balancers` and `describe-target-groups` list them).

## Step 4: Redirect HTTP to HTTPS and point DNS at the ALB

Change the port-80 listener's default action to a redirect (create it if it does not exist):

```bash
HTTP_LISTENER_ARN=$(aws elbv2 describe-listeners --load-balancer-arn "$ALB_ARN" \
  --query 'Listeners[?Port==`80`].ListenerArn' --output text)
aws elbv2 modify-listener --listener-arn "$HTTP_LISTENER_ARN" \
  --default-actions 'Type=redirect,RedirectConfig={Protocol=HTTPS,Port=443,StatusCode=HTTP_301}'
```

Then point `example.com` (Route 53 alias record) and `www.example.com` (alias or CNAME) at the ALB's DNS name.

## Verify

The endpoint should present the Amazon-issued certificate, and HTTP should return a 301 to HTTPS. Check it with the [SSL checker](https://ssl.sh/tools/ssl-checker/), or from any terminal:

```bash
curl ssl.sh/example.com
curl -sI http://example.com | grep -iE '^(HTTP|location)'
```

In AWS:

```bash
aws acm describe-certificate --certificate-arn "$CERT_ARN" --query 'Certificate.[Status,InUseBy,NotAfter]'
```

## Automatic renewal

ACM renews DNS-validated public certificates automatically while two conditions hold: the certificate is associated with an AWS service such as this ALB, and the validation CNAME records stay in DNS. The ARN does not change, so the listener picks up the renewed certificate without any change. Check the status at any time:

```bash
aws acm describe-certificate --certificate-arn "$CERT_ARN" --query 'Certificate.RenewalSummary'
```

Imported certificates are never renewed by ACM. Public certificate lifetimes are capped by the CA/Browser Forum (200 days since March 15, 2026, 47 days from March 15, 2029), so ACM will renew more often; that is automatic as long as the CNAMEs remain. Add the domain to [ssl.sh monitoring](https://ssl.sh/monitor/) (in development) as an external check.

## Troubleshooting

- **Status stays PENDING_VALIDATION**: the CNAME is missing or has a doubled zone name; compare with `describe-certificate` output.
- **CAA_ERROR or failed validation**: a CAA record excludes Amazon; see [CAA record prevents issuance](https://ssl.sh/errors/caa-record-prevents-issuance/).
- **Certificate not listed when creating the listener**: it was requested in another region.
- **Browsers show a name mismatch**: the requested name is not on the certificate or DNS points at another load balancer; see [NET::ERR_CERT_COMMON_NAME_INVALID](https://ssl.sh/errors/net-err-cert-common-name-invalid/).
- **Old clients fail the handshake**: the TLS 1.3/1.2 policy or ECDSA key excludes them; see [ERR_SSL_VERSION_OR_CIPHER_MISMATCH](https://ssl.sh/errors/err-ssl-version-or-cipher-mismatch/).
