Skip to main content
Load Balancer Modules 0.29.22Last updated in version 0.29.21

Application Load Balancer (ALB) Module

View SourceRelease Notes

This Terraform Module creates an Application Load Balancer that you can use as a load balancer for any ALB Target Group. In practice, a Target Group is usually an ECS Service or an Auto Scaling Group.

See the Background section below for more information on the ALB.

ALB Terminology

Amazon has its own vocabulary for the ALB that can be confusing. Here's a helpful guide:

  • Listener: Represents a port open on the ALB that receives incoming traffic (e.g., port 80 for HTTP, 443 for HTTPs).

  • Target Group: Represents one or more servers that are listening for requests. You can configure what port(s) those servers listen on and how to perform health checks on the servers.

  • Listener Rules: Represents a mapping between Listeners and Target Groups. For each of your Listeners, you can specify which paths and/or domain names should be routed to which Target Groups. For example, you could configure path /foo to go to the Target Group foo and /bar to go to bar; or, you could configure foo.my-domain.com to go to foo and bar.my-domain.com to go to bar; or any combination/permutation of these rules.

Background

What's the difference between an ALB and ELB?

The ELB, now known as the Classic Load Balancer, is a Layer 4 load balancer, which means that the ELB will accept both HTTP traffic and TCP traffic. By asking the ELB to simply forward TCP traffic, Amazon users gained the benefit of a high-availability load balancer with the flexibility of handling any kind of TCP traffic they wanted on their backend instances.

But over time, it became clear that many customers were running HTTP microservices that needed more "opinionated" functionality like built-in support for WebSockets, built-in support for HTTP/2, and routing to different backend services depending on the particular URL requested in the HTTP request. Because these requests are all HTTP-specific, the "flexible" Layer 4 ELB could not be updated to handle these use cases.

In addition, when Amazon released the EC2 Container Service for easily running a Docker cluster, they needed some way to allow a load balancer to route requests to containers that just launched somewhere in the cluster. The ELB was originally designed in a pre-container world and was able to route only to a single port across many different EC2 Instances.

This imposed an awkward restriction on the ECS Cluster where you had to run each ECS Task (Docker container) so that it listened on the same host port. This, in turn, meant you couldn't run two instances of the same Docker container on the same host, which was one of the main benefits of Docker in the first place.

The ALB was meant to solve both of these problems:

  1. Offer HTTP-specific functionality (known as "Layer 7" functionality)
  2. Allow Docker containers to launch on a dynamic port

ALB Functionality

The ALB gives us the following HTTP-specific functionality compared to the ELB:

  • Route requests via HTTP or HTTPS
  • Native support for WebSockets
  • Native support for HTTP/2
  • Path-based routing
  • Hostname-based routing
  • Ability to route to a Target, which incorporates both an endpoint and a port and therefore allows different instances of an ECS Service to receive traffic on different ports.
  • Better metrics
  • Support for sticky sessions using load-balancer-generated cookies

For a visual explanation of the ALB's features, check out A Talk on the New AWS Application Load Balancer, Updates to ECS, and Kinesis Analytics.

ELB Functionality

The Classic Load Balancer, or ELB, gives us the following unique functionality compared to the ALB:

  • Route requests via HTTP, HTTPS or TCP
  • Support for sticky sessions using application-generated cookies

When should I use an ALB vs. ELB?

Based on the above analysis, you should generally prefer the ALB when selecting a load balancer for an HTTP-based service. There are, of course, still times when the ELB makes sense:

  • If your service listens on a non-HTTP protocol, such as ZeroMQ.
  • If you wish to terminate a TLS connection at your service, instead of at the load balancer, only the ELB will support this. That is, an ALB will accept TLS connections, but it will then open a second HTTP or HTTPS connection to your backend service. If you want end-to-end encryption, only the ELB can forward the TCP request directly to your backend service so that the backend service terminates the TLS connection.
  • If you need the power of Nginx, or HAProxy, but don't want to bother setting these up as a High Availability cluster.

Finally, the ALB uses a different pricing model than the ELB. Here's an excerpt from the Blog Post that introduced the ALB:

When you use an Application Load Balancer, you will be billed by the hour and for the use of Load Balancer Capacity Units, also known as LCU’s. An LCU measures the number of new connections per second, the number of active connections, and data transfer. We measure on all three dimensions, but bill based on the highest one. One LCU is enough to support either:

  • 25 connections/second with a 2 KB certificate, 3,000 active connections, and 2.22 Mbps of data transfer or
  • 5 connections/second with a 4 KB certificate, 3,000 active connections, and 2.22 Mbps of data transfer.

Billing for LCU usage is fractional, and is charged at $0.008 per LCU per hour. Based on our calculations, we believe that virtually all of our customers can obtain a net reduction in their load balancer costs by switching from a Classic Load Balancer to an Application Load Balancer.

You may note that if you have 1,000,000 idle WebSocket connections (an "active connection"), this would cost ALB users $1,920/month! Whereas with the original ELB, your costs will not scale with the number of idle WebSocket connections (credit to this Hacker News thread for the observation).

Given all the benefits of the ALB, even if you plan to get to massive scale eventually, you may as well start with the ALB. You can always re-assess at any time.

Using the ALB with ECS

When should I use this module with Amazon ECS?

With the ELB, now known as a Classic Load Balancer, each ECS Service was fronted by a unique ELB. As a result, each ECS Service module eventually created its own ELB. This gave us good isolation and made it easy to give each ECS Service a unique DNS name on the same port (e.g. api.acme.com and stats.acme.com, both on port 443). But it also led to low utilization among all the ELBs, little resource sharing, and consequently higher costs.

With the ALB, a single ALB is shared among multiple ECS Services. For that reason, after you've created an ALB using this module, you may wish to create an ECS Cluster using the ecs-cluster module, where you'll pass in the Security Group ID of the newly created ALB to permit the ALB to forward traffic to the ECS Cluster.

With an ECS Cluster and ALB in place, you can now use the [ecs-service-with-alb] (https://github.com/gruntwork-io/terraform-aws-ecs/tree/main/modules/ecs-service-with-alb) module to create a new ECS Service that contains an ALB Target Group you can configure to receive traffic from an ALB. To do that, you need to add one or more aws_alb_listener_rule resources to map which of the ALB listeners should send their traffic to the ECS service's Target Group.

How should I use the ALB with multiple microservices?

To use the ALB with multiple services, you each service should create aws_alb_listener_rule resources to specify which paths or domain names should be routed to that service. For working sample code, check out the docker-service-with-alb example.

Gotcha's

Make sure your Listeners handle all possible request paths

An ALB Listener represents an open port on your ALB, waiting to receive requests and route them to a Target Group.

Suppose you want to have this ALB Listener route requests for /foo to ServiceFoo and requests for /bar to ServiceBar. You'd accomplish this creating two ALB Listener Rules as follows:

  • Route /foo traffic to Target Group ServiceFoo
  • Route /bar traffic to Target Group ServiceBar

So far so good. But what if the Listener receives a request for /hello? Since no Listener Rule handles that path, the ALB will handle it with its default_action. The default_action in this module is to return a fixed response, which by default is a blank 404 page.

There are two ways for you to override this behavior:

  • You can override the default fixed response via the default_action_content_type, default_action_body, and default_action_status_code parameters.
  • You can add an ALB Listener Rule that catches ALL requests (i.e., *) and have that rule forward to a custom Target Group so your own apps can respond in any way you wish.

Sample Usage

main.tf

# ------------------------------------------------------------------------------------------------------
# DEPLOY GRUNTWORK'S ALB MODULE
# ------------------------------------------------------------------------------------------------------

module "alb" {

source = "git::git@github.com:gruntwork-io/terraform-aws-load-balancer.git//modules/alb?ref=v0.29.22"

# ----------------------------------------------------------------------------------------------------
# REQUIRED VARIABLES
# ----------------------------------------------------------------------------------------------------

# The name of the ALB. Do not include the environment name since this module
# will automatically append it to the value of this variable.
alb_name = <string>

# If the ALB should only accept traffic from within the VPC, set this to true.
# If it should accept traffic from the public Internet, set it to false.
is_internal_alb = <bool>

# The AWS predefined TLS/SSL policy for the ALB. A List of policies can be
# found here:
# https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies.
# AWS recommends ELBSecurityPolicy-2016-08 policy for general use but this
# policy includes TLSv1.0 which is rapidly being phased out.
# ELBSecurityPolicy-TLS-1-1-2017-01 is the next policy up that doesn't include
# TLSv1.0.
ssl_policy = <string>

# A list of the subnets into which the ALB will place its underlying nodes.
# Include one subnet per Availabability Zone. If the ALB is public-facing,
# these should be public subnets. Otherwise, they should be private subnets.
vpc_subnet_ids = <list(string)>

# ----------------------------------------------------------------------------------------------------
# OPTIONAL VARIABLES
# ----------------------------------------------------------------------------------------------------

# When looking up the ACM certs passed in via
# https_listener_ports_and_acm_ssl_certs, only match certs with the given
# statuses. Valid values are PENDING_VALIDATION, ISSUED, INACTIVE, EXPIRED,
# VALIDATION_TIMED_OUT, REVOKED and FAILED.
acm_cert_statuses = ["ISSUED"]

# When looking up the ACM certs passed in via
# https_listener_ports_and_acm_ssl_certs, only match certs of the given types.
# Valid values are AMAZON_ISSUED and IMPORTED.
acm_cert_types = ["AMAZON_ISSUED","IMPORTED"]

# Add additional security groups to the ALB
additional_security_group_ids = []

# List of additional SSL certs (non-ACM and ACM) to bind to the given listener
# port. Note that this must not overlap with the certificates defined in
# var.https_listener_ports_and_ssl_certs and
# var.https_listener_ports_and_acm_ssl_certs. The keys are the listener ports.
additional_ssl_certs_for_ports = {}

# The S3 Bucket name where ALB logs should be stored. If left empty, no ALB
# logs will be captured. Tip: It's easiest to create the S3 Bucket using the
# Gruntwork Module
# https://github.com/gruntwork-io/terraform-aws-monitoring/tree/main/modules/logs/load-balancer-access-logs.
alb_access_logs_s3_bucket_name = null

# Set to true to enable all outbound traffic on this ALB. If set to false, the
# ALB will allow no outbound traffic by default. This will make the ALB
# unusuable, so some other code must then update the ALB Security Group to
# enable outbound access!
allow_all_outbound = true

# The CIDR-formatted IP Address ranges from which this ALB will allow incoming
# requests. If var.is_internal_alb is false, use the default value. If
# var.is_internal_alb is true, consider setting this to the VPC's CIDR Block,
# or something even more restrictive.
allow_inbound_from_cidr_blocks = ["0.0.0.0/0"]

# The IDs of security groups from which this ALB will allow incoming requests.
# . If you update this variable, make sure to update
# var.allow_inbound_from_security_group_ids_num too!
allow_inbound_from_security_group_ids = []

# The number of elements in var.allow_inbound_from_security_group_ids. We
# should be able to compute this automatically, but due to a Terraform
# limitation, if there are any dynamic resources in
# var.allow_inbound_from_security_group_ids, then we won't be able to:
# https://github.com/hashicorp/terraform/pull/11482
allow_inbound_from_security_group_ids_num = 0

# Prefix to use for access logs to create a sub-folder in S3 Bucket name where
# ALB logs should be stored. Only used if
# var.enable_custom_alb_access_logs_s3_prefix is true.
custom_alb_access_logs_s3_prefix = null

# A map of custom tags to apply to the ALB and its Security Group. The key is
# the tag name and the value is the tag value.
custom_tags = {}

# Define the default action if a request to the load balancer does not match
# any of your listener rules. Currently only 'fixed-response' and 'redirect'
# are supported.
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener#default_action
default_action = {"fixed-response":{"content_type":"text/plain","message_body":null,"status_code":404}}

# Create a dependency between the resources in this module to the interpolated
# values in this list (and thus the source resources). In other words, the
# resources in this module will now depend on the resources backing the values
# in this list such that those resources need to be created before the
# resources in this module, and the resources in this module need to be
# destroyed before the resources in the list.
dependencies = []

# Determines how the load balancer handles requests that might pose a security
# risk to an application due to HTTP desync. Valid values are monitor,
# defensive (default), strictest.
desync_mitigation_mode = "defensive"

# If true, the ALB will drop invalid headers. Elastic Load Balancing requires
# that message header names contain only alphanumeric characters and hyphens.
drop_invalid_header_fields = false

# Set to true to enable the ALB to log all requests. Ideally, this variable
# wouldn't be necessary, but because Terraform can't interpolate dynamic
# variables in counts, we must explicitly include this. Enter true or false.
enable_alb_access_logs = false

# Set to true to use the value of alb_access_logs_s3_prefix for access logs
# prefix. If false, the alb_name will be used. This is useful if you wish to
# disable the S3 prefix. Only used if var.enable_alb_access_logs is true.
enable_custom_alb_access_logs_s3_prefix = false

# If true, deletion of the ALB will be disabled via the AWS API. This will
# prevent Terraform from deleting the load balancer.
enable_deletion_protection = false

# Indicates whether HTTP/2 is enabled in application load balancers. Defaults
# to true.
enable_http2 = true

# Indicates whether to allow a WAF-enabled load balancer to route requests to
# targets if it is unable to forward the request to AWS WAF.
enable_waf_fail_open = false

# Indicates whether the X-Forwarded-For header should preserve the source port
# that the client used to connect to the load balancer in application load
# balancers. Defaults to true.
enable_xff_client_port = true

# A list of ports for which an HTTP Listener should be created on the ALB.
# Tip: When you define Listener Rules for these Listeners, be sure that, for
# each Listener, at least one Listener Rule uses the '*' path to ensure that
# every possible request path for that Listener is handled by a Listener Rule.
# Otherwise some requests won't route to any Target Group.
http_listener_ports = []

# A list of the ports for which an HTTPS Listener should be created on the
# ALB. Each item in the list should be a map with the keys 'port', the port
# number to listen on, and 'tls_domain_name', the domain name of an SSL/TLS
# certificate issued by the Amazon Certificate Manager (ACM) to associate with
# the Listener to be created. If your certificate isn't issued by ACM, specify
# var.https_listener_ports_and_ssl_certs instead. Tip: When you define
# Listener Rules for these Listeners, be sure that, for each Listener, at
# least one Listener Rule uses the '*' path to ensure that every possible
# request path for that Listener is handled by a Listener Rule. Otherwise some
# requests won't route to any Target Group.
https_listener_ports_and_acm_ssl_certs = []

# The number of elements in var.https_listener_ports_and_acm_ssl_certs. We
# should be able to compute this automatically, but due to a Terraform
# limitation, if there are any dynamic resources in
# var.https_listener_ports_and_acm_ssl_certs, then we won't be able to:
# https://github.com/hashicorp/terraform/pull/11482
https_listener_ports_and_acm_ssl_certs_num = 0

# A list of the ports for which an HTTPS Listener should be created on the
# ALB. Each item in the list should be a map with the keys 'port', the port
# number to listen on, and 'tls_arn', the Amazon Resource Name (ARN) of the
# SSL/TLS certificate to associate with the Listener to be created. If your
# certificate is issued by the Amazon Certificate Manager (ACM), specify
# var.https_listener_ports_and_acm_ssl_certs instead. Tip: When you define
# Listener Rules for these Listeners, be sure that, for each Listener, at
# least one Listener Rule uses the '*' path to ensure that every possible
# request path for that Listener is handled by a Listener Rule. Otherwise some
# requests won't route to any Target Group.
https_listener_ports_and_ssl_certs = []

# The number of elements in var.https_listener_ports_and_ssl_certs. We should
# be able to compute this automatically, but due to a Terraform limitation, if
# there are any dynamic resources in var.https_listener_ports_and_ssl_certs,
# then we won't be able to: https://github.com/hashicorp/terraform/pull/11482
https_listener_ports_and_ssl_certs_num = 0

# The time in seconds that the client TCP connection to the ALB is allowed to
# be idle before the ALB closes the TCP connection.
idle_timeout = 60

# The type of IP addresses used by the subnets for your load balancer. The
# possible values are ipv4 and dualstack.
ip_address_type = null

# DEPRECATED. The VPC ID in which this ALB will be placed.
vpc_id = ""

# (Optional) Determines how the load balancer modifies the X-Forwarded-For
# header in the HTTP request before sending the request to the target. The
# possible values are append, preserve, and remove. Only valid for Load
# Balancers of type application. The default is append.
xff_header_processing_mode = "append"

}


Reference

Required

alb_namestringrequired

The name of the ALB. Do not include the environment name since this module will automatically append it to the value of this variable.

is_internal_albboolrequired

If the ALB should only accept traffic from within the VPC, set this to true. If it should accept traffic from the public Internet, set it to false.

ssl_policystringrequired

The AWS predefined TLS/SSL policy for the ALB. A List of policies can be found here: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies. AWS recommends ELBSecurityPolicy-2016-08 policy for general use but this policy includes TLSv1.0 which is rapidly being phased out. ELBSecurityPolicy-TLS-1-1-2017-01 is the next policy up that doesn't include TLSv1.0.

vpc_subnet_idslist(string)required

A list of the subnets into which the ALB will place its underlying nodes. Include one subnet per Availabability Zone. If the ALB is public-facing, these should be public subnets. Otherwise, they should be private subnets.

Optional

acm_cert_statuseslist(string)optional

When looking up the ACM certs passed in via https_listener_ports_and_acm_ssl_certs, only match certs with the given statuses. Valid values are PENDING_VALIDATION, ISSUED, INACTIVE, EXPIRED, VALIDATION_TIMED_OUT, REVOKED and FAILED.

[ "ISSUED" ]
acm_cert_typeslist(string)optional

When looking up the ACM certs passed in via https_listener_ports_and_acm_ssl_certs, only match certs of the given types. Valid values are AMAZON_ISSUED and IMPORTED.

[
"AMAZON_ISSUED",
"IMPORTED"
]
additional_security_group_idslist(string)optional

Add additional security groups to the ALB

[]
additional_ssl_certs_for_portsmap(list(…))optional

List of additional SSL certs (non-ACM and ACM) to bind to the given listener port. Note that this must not overlap with the certificates defined in https_listener_ports_and_ssl_certs and https_listener_ports_and_acm_ssl_certs. The keys are the listener ports.

map(list(object({
# Exactly one of the following must be set, with the other set to null.
# The domain name to use when looking up the ACM cert to associate.
tls_domain_name = string
# The ARN of the TLS cert to associate with the listener.
tls_arn = string
})))
{}

The S3 Bucket name where ALB logs should be stored. If left empty, no ALB logs will be captured. Tip: It's easiest to create the S3 Bucket using the Gruntwork Module https://github.com/gruntwork-io/terraform-aws-monitoring/tree/main/modules/logs/load-balancer-access-logs.

null
allow_all_outboundbooloptional

Set to true to enable all outbound traffic on this ALB. If set to false, the ALB will allow no outbound traffic by default. This will make the ALB unusuable, so some other code must then update the ALB Security Group to enable outbound access!

true
allow_inbound_from_cidr_blockslist(string)optional

The CIDR-formatted IP Address ranges from which this ALB will allow incoming requests. If is_internal_alb is false, use the default value. If is_internal_alb is true, consider setting this to the VPC's CIDR Block, or something even more restrictive.

[ "0.0.0.0/0" ]

The IDs of security groups from which this ALB will allow incoming requests. . If you update this variable, make sure to update allow_inbound_from_security_group_ids_num too!

[]

The number of elements in allow_inbound_from_security_group_ids. We should be able to compute this automatically, but due to a Terraform limitation, if there are any dynamic resources in allow_inbound_from_security_group_ids, then we won't be able to: https://github.com/hashicorp/terraform/pull/11482

0

Prefix to use for access logs to create a sub-folder in S3 Bucket name where ALB logs should be stored. Only used if enable_custom_alb_access_logs_s3_prefix is true.

null
custom_tagsmap(string)optional

A map of custom tags to apply to the ALB and its Security Group. The key is the tag name and the value is the tag value.

{}
default_actionmap(any)optional

Define the default action if a request to the load balancer does not match any of your listener rules. Currently only 'fixed-response' and 'redirect' are supported. https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener#default_action

Any types represent complex values of variable type. For details, please consult `variables.tf` in the source repo.
{
fixed-response = {
content_type = "text/plain",
message_body = null,
status_code = 404
}
}
dependencieslist(string)optional

Create a dependency between the resources in this module to the interpolated values in this list (and thus the source resources). In other words, the resources in this module will now depend on the resources backing the values in this list such that those resources need to be created before the resources in this module, and the resources in this module need to be destroyed before the resources in the list.

[]

Determines how the load balancer handles requests that might pose a security risk to an application due to HTTP desync. Valid values are monitor, defensive (default), strictest.

"defensive"

If true, the ALB will drop invalid headers. Elastic Load Balancing requires that message header names contain only alphanumeric characters and hyphens.

false

Set to true to enable the ALB to log all requests. Ideally, this variable wouldn't be necessary, but because Terraform can't interpolate dynamic variables in counts, we must explicitly include this. Enter true or false.

false

Set to true to use the value of alb_access_logs_s3_prefix for access logs prefix. If false, the alb_name will be used. This is useful if you wish to disable the S3 prefix. Only used if enable_alb_access_logs is true.

false

If true, deletion of the ALB will be disabled via the AWS API. This will prevent Terraform from deleting the load balancer.

false
enable_http2booloptional

Indicates whether HTTP/2 is enabled in application load balancers. Defaults to true.

true

Indicates whether to allow a WAF-enabled load balancer to route requests to targets if it is unable to forward the request to AWS WAF.

false

Indicates whether the X-Forwarded-For header should preserve the source port that the client used to connect to the load balancer in application load balancers. Defaults to true.

true
http_listener_portslist(string)optional

A list of ports for which an HTTP Listener should be created on the ALB. Tip: When you define Listener Rules for these Listeners, be sure that, for each Listener, at least one Listener Rule uses the '*' path to ensure that every possible request path for that Listener is handled by a Listener Rule. Otherwise some requests won't route to any Target Group.

[]

A list of the ports for which an HTTPS Listener should be created on the ALB. Each item in the list should be a map with the keys 'port', the port number to listen on, and 'tls_domain_name', the domain name of an SSL/TLS certificate issued by the Amazon Certificate Manager (ACM) to associate with the Listener to be created. If your certificate isn't issued by ACM, specify https_listener_ports_and_ssl_certs instead. Tip: When you define Listener Rules for these Listeners, be sure that, for each Listener, at least one Listener Rule uses the '*' path to ensure that every possible request path for that Listener is handled by a Listener Rule. Otherwise some requests won't route to any Target Group.

list(object({
port = number
tls_domain_name = string
}))
[]
Example
   default = [
{
port = 443
tls_domain_name = "foo.your-company.com"
}
]

The number of elements in https_listener_ports_and_acm_ssl_certs. We should be able to compute this automatically, but due to a Terraform limitation, if there are any dynamic resources in https_listener_ports_and_acm_ssl_certs, then we won't be able to: https://github.com/hashicorp/terraform/pull/11482

0
https_listener_ports_and_ssl_certslist(object(…))optional

A list of the ports for which an HTTPS Listener should be created on the ALB. Each item in the list should be a map with the keys 'port', the port number to listen on, and 'tls_arn', the Amazon Resource Name (ARN) of the SSL/TLS certificate to associate with the Listener to be created. If your certificate is issued by the Amazon Certificate Manager (ACM), specify https_listener_ports_and_acm_ssl_certs instead. Tip: When you define Listener Rules for these Listeners, be sure that, for each Listener, at least one Listener Rule uses the '*' path to ensure that every possible request path for that Listener is handled by a Listener Rule. Otherwise some requests won't route to any Target Group.

list(object({
port = number
tls_arn = string
}))
[]
Example
   default = [
{
port = 443
tls_arn = "arn:aws:iam::123456789012:server-certificate/ProdServerCert"
}
]

The number of elements in https_listener_ports_and_ssl_certs. We should be able to compute this automatically, but due to a Terraform limitation, if there are any dynamic resources in https_listener_ports_and_ssl_certs, then we won't be able to: https://github.com/hashicorp/terraform/pull/11482

0
idle_timeoutnumberoptional

The time in seconds that the client TCP connection to the ALB is allowed to be idle before the ALB closes the TCP connection.

60
ip_address_typestringoptional

The type of IP addresses used by the subnets for your load balancer. The possible values are ipv4 and dualstack.

null
vpc_idstringoptional

DEPRECATED. The VPC ID in which this ALB will be placed.

""

(Optional) Determines how the load balancer modifies the X-Forwarded-For header in the HTTP request before sending the request to the target. The possible values are append, preserve, and remove. Only valid for Load Balancers of type application. The default is append.

"append"