---
title: ELB
url: /docs/iac/guides/clouds/aws/elb/
---
[Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) (ELB) automatically distributes incoming
application traffic across multiple targets, such as Amazon EC2 instances, containers, IP addresses, and Lambda
Functions. It can handle the varying load of your application traffic in a single Availability Zone or across multiple
Availability Zones.

## Overview

The AWSx ELB component provides easy APIs for provisioning Application and Network Load Balancers, and
integrates with functionality for other services, including [API Gateway](/docs/clouds/aws/guides/api-gateway/),
[Elastic Container Service (ECS)](/docs/clouds/aws/guides/ecs), [Lambda](/docs/clouds/aws/guides/lambda/), and [VPC](/docs/clouds/aws/guides/vpc/), to provide
configurable network accessibility to the different kinds of compute you will run inside of AWS.

Elastic Load Balancing offers multiple types of load balancers that all feature the high availability, automatic
scaling, and robust security necessary to make your applications fault tolerant:

* [Network Load Balancer (NLB)](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/introduction.html) is
  best suited for load balancing of Transmission Control Protocol (TCP) and Transport Layer Security (TLS) traffic where
  extreme performance is required. Operating at the connection level (Layer 4), Network Load Balancer routes traffic to
  targets within Amazon Virtual Private Cloud (Amazon VPC) and is capable of handling millions of requests per second
  while maintaining ultra-low latencies. Network Load Balancer is also optimized to handle sudden and volatile traffic
  patterns.

* [Application Load Balancer (ALB)](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html)
  is best suited for load balancing of HTTP and HTTPS traffic and provides advanced request routing targeted at the
  delivery of modern application architectures, including microservices, containers, and HTTP/2 traffic. Operating at
  the individual request level (Layer 7), Application Load Balancer routes traffic to targets within Amazon Virtual
  Private Cloud (Amazon VPC) based on the content of the request.

Each kind of load balancer is represented by a class in the `awsx.lb` module:

* `NetworkLoadBalancer` is used for NLBs
* `ApplicationLoadBalancer` is used for ALBs.

> These types are similar and support many of the same scenarios. Most examples show using ALBs, however changing
> to an NLB is usually as simple as swapping out this class. Any differences will be noted below.

## Creating a Load Balancer

To create a new load balancer, allocate an instance of its class. In addition to creating the load balancer itself, we
must also create a _listener_ to let traffic reach it:

<!-- chooser: language -->

<!-- option: typescript -->

```typescript
import * as awsx from "@pulumi/awsx";

// Create a load balancer in the default VPC listening on port 80.
const alb = new awsx.lb.ApplicationLoadBalancer("lb", {
    listener: {
        port: 80,
    },
});

// Export the resulting URL so that it's easy to access.
export const endpoint = alb.loadBalancer.dnsName;

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-web-listener-typescript)

<!-- /option -->

<!-- option: python -->

```python
import pulumi
import pulumi_awsx as awsx

# Create a load balancer in the default VPC listening on port 80.
alb = awsx.lb.ApplicationLoadBalancer(
    "lb",
    awsx.lb.ApplicationLoadBalancerArgs(
        listener=awsx.lb.ListenerArgs(
            port=80,
        ),
    ),
)

# Export the resulting URL so that it's easy to access.
pulumi.export("endpoint", alb.load_balancer.dns_name)

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-web-listener-python)

<!-- /option -->

<!-- option: go -->

```go
package main

import (
	"github.com/pulumi/pulumi-awsx/sdk/v3/go/awsx/lb"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {

		// Create a load balancer in the default VPC listening on port 80.
		alb, err := lb.NewApplicationLoadBalancer(ctx, "lb", &lb.ApplicationLoadBalancerArgs{
			Listener: &lb.ListenerArgs{
				Port: pulumi.Int(80),
			},
		})
		if err != nil {
			return err
		}

		// Export the resulting URL so that it's easy to access.
		ctx.Export("endpoint", alb.LoadBalancer.DnsName())
		return nil
	})
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-web-listener-go)

<!-- /option -->

<!-- option: csharp -->

```csharp
﻿using Pulumi;
using Awsx = Pulumi.Awsx;
using System.Collections.Generic;

return await Deployment.RunAsync(() =>
{
   // Create a load balancer in the default VPC listening on port 80.
   var alb = new Awsx.Lb.ApplicationLoadBalancer("lb", new()
   {
        Listener = new()
        {
            Port = 80,
        },
   });

    // Export the resulting URL so that it's easy to access.
    return new Dictionary<string, object?>
    {
        ["endpoint"] = alb.LoadBalancer.Apply(lb => lb.DnsName),
    };
});

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-web-listener-csharp)

<!-- /option -->

<!-- option: java -->

```java
package myproject;

import com.pulumi.Pulumi;
import com.pulumi.awsx.lb.ApplicationLoadBalancer;
import com.pulumi.awsx.lb.ApplicationLoadBalancerArgs;
import com.pulumi.awsx.lb.inputs.ListenerArgs;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {

            // Create a load balancer in the default VPC listening on port 80.
            var alb = new ApplicationLoadBalancer("lb", ApplicationLoadBalancerArgs.builder()
                .listener(ListenerArgs.builder()
                    .port(80)
                    .build())
                .build());

            // Export the resulting URL so that it's easy to access.
            ctx.export("endpoint", alb.loadBalancer().apply(loadBalancer -> loadBalancer.dnsName()));
        });
    }
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-web-listener-java)

<!-- /option -->

<!-- option: yaml -->

```yaml
name: awsx-elb-web-listener-yaml
runtime: yaml
description: An example that deploys an ApplicationLoadBalancer listening on port 80.

resources:
  # Create a load balancer in the default VPC listening on port 80.
  alb:
    type: awsx:lb:ApplicationLoadBalancer
    properties:
      listener:
        port: 80

outputs:
  # Export the resulting URL so that it's easy to access.
  endpoint: ${alb.loadBalancer.dnsName}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-web-listener-yaml)

<!-- /option -->

<!-- /chooser -->

This load balancer listens on port 80, in our account's per-region default VPC, using its public subnets, thereby
exposing it to the Internet. See below for instructions on how to
[make your load balancer private](#listening-on-private-subnets) or to
[run in a custom VPC](#creating-a-load-balancer-in-a-custom-vpc).

There are a number of additional properties you may set:

* `enableHttp2`: Set to `true` to enable HTTP/2 traffic on your ALB. HTTP/2 is not supported for NLBs.

* `enableDeletionProtection`: Set to `true` to disable deletion of the resource. This can be helpful to avoid
  accidentally deleting a long-lived, but auto-generated, load balancer URL.

* `idleTimeout`: The time in seconds a connection is permitted to be idle before being severed. The default is `60`.

* `tags`: Can be used to tag your load balancer with metadata about its purpose, for reporting or compliance.

For the load balancer to do anything useful, we must also specify a _target_ that traffic will be routed to.
The target could be an EC2 instance, ECS service, or anything with an IP address, for instance. We
will also have to configure SecurityGroups to let traffic flow inside of our VPC on the correct ports.

## Load Balancing EC2 Instance Targets

To target an EC2 instance with your load balancer, you must do the following:

1. Open ingress traffic to your load balancer. Explicitly needed for NLB, but not ALB.
2. Open egress traffic from your EC2 instance to your load balancer (for health checks).
3. Ensure the security group for your load balancer at least contains the ingress rule from (1).
4. Create the EC2 instance(s) in the same VPC and ensure the security group contains the egress rule (2).
5. Attach your load balancer's target group to the desired EC2 instance(s).

Aside from those three steps, the code and capabilities of the load balancer are the same as shown above.

> **Note:** Note that ALBs automatically open ingress traffic to the ports listened on, whereas NLBs do not.

Here is an example that creates an EC2 instance per availability zone, running a simple Ubuntu web server:

<!-- chooser: language -->

<!-- option: typescript -->

```typescript
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

// Get the default VPC for the current region.
const vpc = new awsx.ec2.DefaultVpc("default-vpc");

// Create a security group to allow traffic to and from the virtual machine.
const securityGroup = new aws.ec2.SecurityGroup("web-sg", {
    vpcId: vpc.vpcId,
    ingress: [{
            protocol: "tcp",
            fromPort: 80,
            toPort: 80,
            cidrBlocks: ["0.0.0.0/0"],
        },
    ],
    egress: [{
            protocol: "-1",
            fromPort: 0,
            toPort: 0,
            cidrBlocks: ["0.0.0.0/0"],
        },
    ],
});

// Create an ALB in the default VPC listening on port 80.
const alb = new awsx.lb.ApplicationLoadBalancer("web-traffic", {
    listener: {
        port: 80,
    },
    securityGroups: [securityGroup.id],
});

vpc.publicSubnetIds.apply(subnetIds => {
    // Get the latest Amazon Linux 2 AMI.
    const ami = aws.ec2.getAmiOutput({
        filters: [{ name: "name", values: ["amzn2-ami-hvm-*"] }],
        owners: ["amazon"],
        mostRecent: true,
    });

    // In each VPC subnet, create an EC2 instance and attach it to the ALB.
    subnetIds.forEach((subnetId, i) => {
        const vm = new aws.ec2.Instance(`web-${i}`, {
            ami: ami.id,
            instanceType: "t2.micro",
            subnetId,
            vpcSecurityGroupIds: alb.loadBalancer.securityGroups,
            userData: [`#!/bin/bash`, `echo "Hello World, from Server ${i + 1}!" > index.html`, `nohup python -m SimpleHTTPServer 80 &`].join("\n"),
        });

        const attachment = new awsx.lb.TargetGroupAttachment(`attachment-${i}`, {
            targetGroup: alb.defaultTargetGroup,
            instance: vm,
        });
    });
});

// Export the resulting URL so that it's easy to access.
export const endpoint = alb.loadBalancer.dnsName;

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-ec2-instances-typescript)

<!-- /option -->

<!-- option: python -->

```python
import pulumi
import pulumi_aws as aws
import pulumi_awsx as awsx

# Get the default VPC for the current region.
vpc = awsx.ec2.DefaultVpc("default-vpc")

# Create a security group to allow traffic to and from the virtual machine.
security_group = aws.ec2.SecurityGroup(
    "web-sg",
    vpc_id=vpc.vpc_id,
    ingress=[aws.ec2.SecurityGroupIngressArgs(
            protocol="tcp",
            from_port=80,
            to_port=80,
            cidr_blocks=["0.0.0.0/0"],
        ),
    ],
    egress=[aws.ec2.SecurityGroupEgressArgs(
            protocol="-1",
            from_port=0,
            to_port=0,
            cidr_blocks=["0.0.0.0/0"],
        ),
    ],
)

# Create an ALB in the default VPC listening on port 80.
alb = awsx.lb.ApplicationLoadBalancer(
    "web-traffic",
    listener=awsx.lb.ListenerArgs(
        port=80,
    ),
    security_groups=[security_group.id],
)

# Get the latest Amazon Linux 2 AMI.
ami = aws.ec2.get_ami_output(
    most_recent=True,
    owners=["amazon"],
    filters=[aws.ec2.GetAmiFilterArgs(name="name", values=["amzn2-ami-hvm-*"])],
)

def create_instance(subnet_id, i):
    vm = aws.ec2.Instance(
        f"web-{str(i)}",
        aws.ec2.InstanceArgs(
            ami=ami.id,
            instance_type="t2.micro",
            subnet_id=subnet_id,
            vpc_security_group_ids=alb.load_balancer.security_groups,
            user_data=f"""#!/bin/bash
            echo 'Hello World, from Server {str(i + 1)}!' > index.html
            nohup python -m SimpleHTTPServer 80 &
            """,
        ),
    )
    attachment = awsx.lb.TargetGroupAttachment(
        f"attachment-{str(i)}",
        awsx.lb.TargetGroupAttachmentArgs(
            target_group=alb.default_target_group,
            instance=vm,
        ),
    )

def create_and_attach_instances(subnet_ids):
    for index, subnet_id in enumerate(subnet_ids):
        create_instance(subnet_id, index)

# In each VPC subnet, create an EC2 instance and attach it to the ALB.
vpc.public_subnet_ids.apply(create_and_attach_instances)

# Export the resulting URL so that it's easy to access.
pulumi.export("endpoint", alb.load_balancer.dns_name)

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-ec2-instances-python)

<!-- /option -->

<!-- option: go -->

```go
package main

import (
	"fmt"

	awsec2 "github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
	"github.com/pulumi/pulumi-awsx/sdk/v3/go/awsx/ec2"
	"github.com/pulumi/pulumi-awsx/sdk/v3/go/awsx/lb"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {

		// Get the default VPC for the current region.
		vpc, err := ec2.NewDefaultVpc(ctx, "default-vpc", nil)
		if err != nil {
			return err
		}

		// Create a security group to allow traffic to and from the virtual machine.
		securityGroup, err := awsec2.NewSecurityGroup(ctx, "web-sg", &awsec2.SecurityGroupArgs{
			VpcId: vpc.VpcId,
			Ingress: awsec2.SecurityGroupIngressArray{
				&awsec2.SecurityGroupIngressArgs{
					Protocol:   pulumi.String("tcp"),
					FromPort:   pulumi.Int(80),
					ToPort:     pulumi.Int(80),
					CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
				},
			},
			Egress: awsec2.SecurityGroupEgressArray{
				&awsec2.SecurityGroupEgressArgs{
					Protocol:   pulumi.String("-1"),
					FromPort:   pulumi.Int(0),
					ToPort:     pulumi.Int(0),
					CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
				},
			},
		})
		if err != nil {
			return err
		}

		// Create an ALB in the default VPC listening on port 80.
		alb, err := lb.NewApplicationLoadBalancer(ctx, "lb", &lb.ApplicationLoadBalancerArgs{
			Listener: &lb.ListenerArgs{
				Port: pulumi.Int(80),
			},
			SecurityGroups: pulumi.StringArray{securityGroup.ID()},
		})
		if err != nil {
			return err
		}

		// In each VPC subnet, create an EC2 instance and attach it to the ALB.
		vpc.PublicSubnetIds.ApplyT(func(subnetIds []string) error {
			for i, subnetId := range subnetIds {
				suffix := fmt.Sprintf("web-%d", i)

				ami, err := awsec2.LookupAmi(ctx, &awsec2.LookupAmiArgs{
					Filters: []awsec2.GetAmiFilter{
						{
							Name:   "name",
							Values: []string{"amzn2-ami-hvm-*"},
						},
					},
					Owners:     []string{"amazon"},
					MostRecent: pulumi.BoolRef(true),
				})
				if err != nil {
					return err
				}

				vm, err := awsec2.NewInstance(ctx, suffix, &awsec2.InstanceArgs{
					Ami:                 pulumi.String(ami.Id),
					InstanceType:        pulumi.String("t2.micro"),
					SubnetId:            pulumi.String(subnetId),
					VpcSecurityGroupIds: alb.LoadBalancer.SecurityGroups(),
					UserData: pulumi.Sprintf(`#!/bin/bash
						echo "Hello World, from Server %d!" > index.html
						nohup python -m SimpleHTTPServer 80 &`, i+1),
				})
				if err != nil {
					return err
				}

				_, err = lb.NewTargetGroupAttachment(ctx, suffix, &lb.TargetGroupAttachmentArgs{
					TargetGroup: alb.DefaultTargetGroup,
					Instance:    vm,
				})
				if err != nil {
					return err
				}
			}

			return nil
		})

		// Export the resulting URL so that it's easy to access.
		ctx.Export("endpoint", alb.LoadBalancer.DnsName())
		return nil
	})
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-ec2-instances-go)

<!-- /option -->

<!-- option: csharp -->

```csharp
﻿using Pulumi;
using Aws = Pulumi.Aws;
using Awsx = Pulumi.Awsx;
using System.Collections.Generic;

return await Deployment.RunAsync(() =>
{
    // Get the default VPC for the current region.
    var vpc = new Awsx.Ec2.DefaultVpc("default-vpc");

    // Create a security group to allow traffic to and from the virtual machine.
    var securityGroup = new Aws.Ec2.SecurityGroup("web-sg", new()
    {
        VpcId = vpc.VpcId,
        Ingress = new[]
        {
            new Aws.Ec2.Inputs.SecurityGroupIngressArgs
            {
                Protocol = "tcp",
                FromPort = 80,
                ToPort = 80,
                CidrBlocks = new[]
                {
                    "0.0.0.0/0",
                },
            },
        },
        Egress = new[]
        {
            new Aws.Ec2.Inputs.SecurityGroupEgressArgs
            {
                Protocol = "-1",
                FromPort = 0,
                ToPort = 0,
                CidrBlocks = new[]
                {
                    "0.0.0.0/0"
                },
            },
        },
    });

    // Create an ALB in the default VPC listening on port 80.
    var alb = new Awsx.Lb.ApplicationLoadBalancer("lb", new()
    {
        Listener = new()
        {
            Port = 80,
        },

        SecurityGroups = new[] { securityGroup.Id },
    });

    vpc.PublicSubnetIds.Apply(subnetIds => {

        // Get the latest Amazon Linux 2 AMI.
        var ami = Aws.Ec2.GetAmi.Invoke(new()
        {
            Filters = new[]
            {
                new Aws.Ec2.Inputs.GetAmiFilterInputArgs
                {
                    Name = "name",
                    Values = new[] { "amzn2-ami-hvm-*" },
                },
            },
            Owners = new[] { "amazon" },
            MostRecent = true,
        });

        // In each VPC subnet, create an EC2 instance and attach it to the ALB.
        for (var i = 0; i < subnetIds.Length; i++)
        {
            var vm = new Aws.Ec2.Instance($"web-{i}", new()
            {
                Ami = ami.Apply(result => result.Id),
                InstanceType = "t2.micro",
                SubnetId = subnetIds[i],
                VpcSecurityGroupIds = alb.LoadBalancer.Apply(lb => lb.SecurityGroups),
                UserData = $@"
                    #!/bin/bash
                    echo ""Hello World, from Server {i + 1}!"" > index.html
                    nohup python -m SimpleHTTPServer 80 &
                ",
            });

            var attachment = new Awsx.Lb.TargetGroupAttachment($"attachment-{i}", new()
            {
                TargetGroup = alb.DefaultTargetGroup,
                Instance = vm,
            });
        }

        return subnetIds;
    });

    // Export the resulting URL so that it's easy to access.
    return new Dictionary<string, object?>
    {
        ["endpoint"] = alb.LoadBalancer.Apply(lb => lb.DnsName),
    };
});

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-ec2-instances-csharp)

<!-- /option -->

<!-- option: java -->

```java
package myproject;

import com.pulumi.Pulumi;
import com.pulumi.aws.ec2.Ec2Functions;
import com.pulumi.aws.ec2.SecurityGroup;
import com.pulumi.aws.ec2.SecurityGroupArgs;
import com.pulumi.aws.ec2.inputs.SecurityGroupIngressArgs;
import com.pulumi.aws.ec2.inputs.SecurityGroupEgressArgs;
import com.pulumi.aws.ec2.Instance;
import com.pulumi.aws.ec2.InstanceArgs;
import com.pulumi.aws.ec2.inputs.GetAmiArgs;
import com.pulumi.aws.ec2.inputs.GetAmiFilterArgs;
import com.pulumi.aws.ec2.outputs.GetAmiResult;
import com.pulumi.awsx.ec2.DefaultVpc;
import com.pulumi.awsx.lb.ApplicationLoadBalancer;
import com.pulumi.awsx.lb.ApplicationLoadBalancerArgs;
import com.pulumi.awsx.lb.TargetGroupAttachment;
import com.pulumi.awsx.lb.TargetGroupAttachmentArgs;
import com.pulumi.awsx.lb.inputs.ListenerArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {

            // Get the default VPC for the current region.
            var vpc = new DefaultVpc("default-vpc");

            // Create a security group to allow traffic to and from the virtual machine.
            var securityGroup = new SecurityGroup("web-sg", SecurityGroupArgs.builder()
                .vpcId(vpc.vpcId())
                .ingress(SecurityGroupIngressArgs.builder()
                    .protocol("tcp")
                    .fromPort(80)
                    .toPort(80)
                    .cidrBlocks(List.of("0.0.0.0/0"))
                    .build())
                .egress(SecurityGroupEgressArgs.builder()
                    .protocol("-1")
                    .fromPort(0)
                    .toPort(0)
                    .cidrBlocks(List.of("0.0.0.0/0"))
                    .build())
                .build());

            // Create an ALB in the default VPC listening on port 80.
            var alb = new ApplicationLoadBalancer("web-traffic", ApplicationLoadBalancerArgs.builder()
                .listener(ListenerArgs.builder()
                    .port(80)
                    .build())
                .securityGroups(securityGroup.id().applyValue(id -> List.of(id)))
                .build());

            // Get the latest Amazon Linux 2 AMI.
            var ami = Ec2Functions.getAmi(GetAmiArgs.builder()
                .filters(List.of(GetAmiFilterArgs.builder()
                    .name("name")
                    .values(List.of("amzn2-ami-hvm-*"))
                    .build()))
                .owners(List.of("amazon"))
                .mostRecent(true)
                .build());

            // In each VPC subnet, create an EC2 instance and attach it to the ALB.
            vpc.publicSubnetIds().applyValue(subnetIds -> {
                for(int i = 0; i < subnetIds.size(); i++){
                    var subnetId = subnetIds.get(i);

                    var vm = new Instance(String.format("web-%s", i), InstanceArgs.builder()
                        .ami(ami.applyValue(GetAmiResult::id))
                        .instanceType("t2.micro")
                        .subnetId(subnetId)
                        .vpcSecurityGroupIds(alb.loadBalancer().apply(lb -> lb.securityGroups()))
                        .userData("#!/bin/bash\n"
                            + String.format("echo \"Hello World, from Server %s!\" > index.html\n", i + 1)
                            + "nohup python -m SimpleHTTPServer 80 &")
                        .build(),
                        CustomResourceOptions.builder()
                            .dependsOn(List.of(securityGroup))
                            .build());

                    new TargetGroupAttachment(String.format("attachment-%s", i), TargetGroupAttachmentArgs.builder()
                        .targetGroup(alb.defaultTargetGroup())
                        .instance(vm)
                        .build());
                }

                return subnetIds;
            });

            // Export the resulting URL so that it's easy to access.
            ctx.export("endpoint", alb.loadBalancer().apply(loadBalancer -> loadBalancer.dnsName()));
        });
    }
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-ec2-instances-java)

<!-- /option -->

<!-- option: yaml -->

```yaml
name: awsx-load-balanced-ec2-instances-yaml
runtime: yaml
description: An example that deploys multiple load-balanced VMs in Amazon EC2.

variables:
  amiId:
    fn::invoke:
      function: aws:ec2:getAmi
      arguments:
        filters:
          - name: "name"
            values: ["amzn2-ami-hvm-*"]
        owners: ["amazon"]
        mostRecent: true
      return: id

resources:
  # Get the default VPC for the current region.
  defaultVpc:
    type: awsx:ec2:DefaultVpc

  # Create a security group to allow traffic to and from the virtual machine.
  webSg:
    type: aws:ec2:SecurityGroup
    properties:
      vpcId: ${defaultVpc.vpcId}
      ingress:
        - protocol: tcp
          fromPort: 80
          toPort: 80
          cidrBlocks: ["0.0.0.0/0"]
      egress:
        - protocol: "-1"
          fromPort: 0
          toPort: 0
          cidrBlocks: ["0.0.0.0/0"]
  # Create an ALB in the default VPC listening on port 80.
  webTrafficAlb:
    type: awsx:lb:ApplicationLoadBalancer
    properties:
      listener:
        port: 80
      securityGroups:
        - ${webSg.id}

  # In each VPC subnet, create an EC2 instance and attach it to the ALB.

  web1:
    type: aws:ec2:Instance
    properties:
      ami: ${amiId}
      instanceType: t2.micro
      subnetId: ${defaultVpc.publicSubnetIds[0]}
      vpcSecurityGroupIds:
        - ${webTrafficAlb.loadBalancer.securityGroups[0]}
      userData: |
        #!/bin/bash
        echo "Hello World, from Server 1!" > index.html
        nohup python -m SimpleHTTPServer 80 &

  attachment1:
    type: awsx:lb:TargetGroupAttachment
    properties:
      targetGroup: ${webTrafficAlb.defaultTargetGroup}
      instance: ${web1}

  web2:
    type: aws:ec2:Instance
    properties:
      ami: ${amiId}
      instanceType: t2.micro
      subnetId: ${defaultVpc.publicSubnetIds[1]}
      vpcSecurityGroupIds:
        - ${webTrafficAlb.loadBalancer.securityGroups[0]}
      userData: |
        #!/bin/bash
        echo "Hello World, from Server 2!" > index.html
        nohup python -m SimpleHTTPServer 80 &

  attachment2:
    type: awsx:lb:TargetGroupAttachment
    properties:
      targetGroup: ${webTrafficAlb.defaultTargetGroup}
      instance: ${web2}

  web3:
    type: aws:ec2:Instance
    properties:
      ami: ${amiId}
      instanceType: t2.micro
      subnetId: ${defaultVpc.publicSubnetIds[2]}
      vpcSecurityGroupIds:
        - ${webTrafficAlb.loadBalancer.securityGroups[0]}
      userData: |
        #!/bin/bash
        echo "Hello World, from Server 3!" > index.html
        nohup python -m SimpleHTTPServer 80 &

  attachment3:
    type: awsx:lb:TargetGroupAttachment
    properties:
      targetGroup: ${webTrafficAlb.defaultTargetGroup}
      instance: ${web3}

# Export the resulting URL so that it's easy to access.
outputs:
  endpoint: ${webTrafficAlb.loadBalancer.dnsName}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-ec2-instances-yaml)

<!-- /option -->

<!-- /chooser -->

After deploying this using `pulumi up`, we will have a fully functional endpoint:

```bash
$ for i in {1..5} ; do curl "http://$(pulumi stack output endpoint)" ; done
Hello World, from Server 1!
Hello World, from Server 1!
Hello World, from Server 3!
Hello World, from Server 2!
Hello World, from Server 1!
```

The load balancer creates a default target group that forwards traffic on the same port. If you need
to configure the way that traffic is forwarded, health checks, and so on, see
[Advanced NLB Target Group and Listener Configuration](#advanced-nlb-target-group-and-listener-configuration) below.

For more advanced cases, you will most likely want to use [EC2 Auto Scaling](
https://docs.aws.amazon.com/autoscaling/ec2/userguide/what-is-amazon-ec2-auto-scaling.html), rather than hard-coding
the number of and placement of VMs. Refer to the API docs for
[LaunchConfiguration](/registry/packages/aws/api-docs/ec2/launchconfiguration/) and
[AutoScalingGroup](/registry/packages/aws/api-docs/autoscaling/group/) for details on how to do so.

## Load Balancing ECS Service Targets

Your ECS service can use ELB to distribute traffic evenly across each of your service's tasks. To target an ECS service
with your load balancer, pass the listener in your task definition's `portMappings`:

<!-- chooser: language -->

<!-- option: typescript -->

```typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const lb = new awsx.lb.ApplicationLoadBalancer("lb");
const cluster = new aws.ecs.Cluster("cluster");

const service = new awsx.ecs.FargateService("service", {
    cluster: cluster.arn,
    assignPublicIp: true,
    desiredCount: 2,
    taskDefinitionArgs: {
        container: {
            name: "my-service",
            image: "nginx:latest",
            cpu: 128,
            memory: 512,
            essential: true,
            portMappings: [{
                    containerPort: 80,
                    targetGroup: lb.defaultTargetGroup,
                },
            ],
        },
    },
});

export const url = pulumi.interpolate`http://${lb.loadBalancer.dnsName}`;

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-fargate-nginx-typescript)

<!-- /option -->

<!-- option: python -->

```python
import pulumi
import pulumi_aws as aws
import pulumi_awsx as awsx

lb = awsx.lb.ApplicationLoadBalancer("lb")
cluster = aws.ecs.Cluster("cluster")

service = awsx.ecs.FargateService("service",
    cluster=cluster.arn,
    assign_public_ip=True,
    desired_count=2,
    task_definition_args=awsx.ecs.FargateServiceTaskDefinitionArgs(
        container=awsx.ecs.TaskDefinitionContainerDefinitionArgs(
            name="my-service",
            image="nginx:latest",
            cpu=256,
            memory=512,
            essential=True,
            port_mappings=[awsx.ecs.TaskDefinitionPortMappingArgs(
                container_port=80,
                target_group=lb.default_target_group,
            )],
        ),
    ))

pulumi.export("url", pulumi.Output.concat("http://", lb.load_balancer.dns_name))

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-fargate-nginx-python)

<!-- /option -->

<!-- option: go -->

```go
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ecs"
	ecsx "github.com/pulumi/pulumi-awsx/sdk/v3/go/awsx/ecs"
	"github.com/pulumi/pulumi-awsx/sdk/v3/go/awsx/lb"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		lb, err := lb.NewApplicationLoadBalancer(ctx, "lb", nil)
		if err != nil {
			return err
		}

		cluster, err := ecs.NewCluster(ctx, "cluster", nil)
		if err != nil {
			return err
		}

		_, err = ecsx.NewFargateService(ctx, "service", &ecsx.FargateServiceArgs{
			Cluster:        cluster.Arn,
			AssignPublicIp: pulumi.Bool(true),
			DesiredCount:   pulumi.Int(2),
			TaskDefinitionArgs: &ecsx.FargateServiceTaskDefinitionArgs{
				Container: &ecsx.TaskDefinitionContainerDefinitionArgs{
					Name:      pulumi.String("my-service"),
					Image:     pulumi.String("nginx:latest"),
					Cpu:       pulumi.Int(128),
					Memory:    pulumi.Int(512),
					Essential: pulumi.Bool(true),
					PortMappings: ecsx.TaskDefinitionPortMappingArray{
						&ecsx.TaskDefinitionPortMappingArgs{
							ContainerPort: pulumi.Int(80),
							TargetGroup:   lb.DefaultTargetGroup,
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}

		ctx.Export("url", pulumi.Sprintf("http://%s", lb.LoadBalancer.DnsName()))
		return nil
	})
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-fargate-nginx-go)

<!-- /option -->

<!-- option: csharp -->

```csharp
using System.Collections.Generic;
using Pulumi;
using Aws = Pulumi.Aws;
using Awsx = Pulumi.Awsx;

return await Deployment.RunAsync(() =>
{
    var lb = new Awsx.Lb.ApplicationLoadBalancer("lb");
    var cluster = new Aws.Ecs.Cluster("cluster");

    var service = new Awsx.Ecs.FargateService("service", new()
    {
        Cluster = cluster.Arn,
        AssignPublicIp = true,
        TaskDefinitionArgs = new Awsx.Ecs.Inputs.FargateServiceTaskDefinitionArgs
        {
            Container = new Awsx.Ecs.Inputs.TaskDefinitionContainerDefinitionArgs
            {
                Name = "my-service",
                Image = "nginx:latest",
                Cpu = 128,
                Memory = 512,
                Essential = true,
                PortMappings = new()
                {
                    new Awsx.Ecs.Inputs.TaskDefinitionPortMappingArgs
                    {
                        ContainerPort = 80,
                        TargetGroup = lb.DefaultTargetGroup,
                    },
                },
            },
        },
    });

    return new Dictionary<string, object?>
    {
        ["url"] = lb.LoadBalancer.Apply(loadBalancer => Output.Format($"http://{loadBalancer.DnsName}")),
    };
});

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-fargate-nginx-csharp)

<!-- /option -->

<!-- option: java -->

```java
package myproject;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ecs.Cluster;
import com.pulumi.awsx.lb.ApplicationLoadBalancer;
import com.pulumi.awsx.ecs.FargateService;
import com.pulumi.awsx.ecs.FargateServiceArgs;
import com.pulumi.awsx.ecs.inputs.FargateServiceTaskDefinitionArgs;
import com.pulumi.awsx.ecs.inputs.TaskDefinitionContainerDefinitionArgs;
import com.pulumi.awsx.ecs.inputs.TaskDefinitionPortMappingArgs;
import java.util.Map;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var cluster = new Cluster("cluster");
        var lb = new ApplicationLoadBalancer("lb");

        var service = new FargateService("service", FargateServiceArgs.builder()
            .cluster(cluster.arn())
            .assignPublicIp(true)
            .taskDefinitionArgs(FargateServiceTaskDefinitionArgs.builder()
                .containers(Map.of("my-service", TaskDefinitionContainerDefinitionArgs.builder()
                    .name("my-service")
                    .image("nginx:latest")
                    .cpu(128)
                    .memory(512)
                    .essential(true)
                    .portMappings(TaskDefinitionPortMappingArgs.builder()
                        .containerPort(80)
                        .targetGroup(lb.defaultTargetGroup())
                        .build())
                    .build()))
                .build())
            .build());

        ctx.export("url", Output.format("http://%s", lb.loadBalancer().applyValue(loadBalancer -> loadBalancer.dnsName())));
    }
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-fargate-nginx-java)

<!-- /option -->

<!-- option: yaml -->

```yaml
name: awsx-load-balanced-fargate-nginx-yaml
runtime: yaml
resources:
  lb:
    type: awsx:lb:ApplicationLoadBalancer
  cluster:
    type: aws:ecs:Cluster
  service:
    type: awsx:ecs:FargateService
    properties:
      cluster: ${cluster.arn}
      assignPublicIp: true
      taskDefinitionArgs:
        container:
          name: my-service
          image: "nginx:latest"
          cpu: 128
          memory: 512
          essential: true
          portMappings:
            - containerPort: 80
              targetGroup: ${lb.defaultTargetGroup}
outputs:
  url: http://${lb.loadBalancer.dnsName}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-load-balanced-fargate-nginx-yaml)

<!-- /option -->

<!-- /chooser -->

> [The AWSx ECS component](/docs/clouds/aws/guides/ecs/) -- those classes in the `awsx.ecs` package -- will automatically create the
> right ingress and egress rules. If you are using raw `aws.ecs`, you will need to manually manage the security group
> ingress and egress rules, much like the [EC2 Instance](#load-balancing-ec2-instances) example earlier.

After deploying this using `pulumi up`, we will have a fully functional endpoint:

```bash
$ curl http://$(pulumi stack output endpoint)
<!DOCTYPE html>
<html>
<body>

# Welcome to nginx!

</body>
</html>
```

This load balancer uses reasonable targeting defaults and health checks. If you'd like to customize these,
see [Advanced NLB Target Group and Listener Configuration](#advanced-nlb-target-group-and-listener-configuration) below.

Although ECS supports both NLB and ALB, ALB offer several features that make them more attractive for ECS:

* Dynamic host port mapping enables multiple tasks from the same service to use the same container instance.
* Path-based routing and priority rules allow multiple services to use the same listener port on a single ALB.

We recommend using ALBs for your ECS services unless it requires a feature that is only available with NLBs.

For more extensive information about load balancing and ECS Services, refer to AWS's
[Service Load Balancing](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-load-balancing.html)
documentation.

## Listening on Private Subnets

By default, your load balancer will created as _internet-facing_, meaning it'll use the VPC's public subnets and listen for traffic coming from the Internet.
If you want to instead keep your load balancer private, servicing traffic inside of your VPC over its private subnets,
set the `internal` property to `true`:

<!-- chooser: language -->

<!-- option: typescript -->

```typescript
import * as awsx from "@pulumi/awsx";

// Create a load balancer in the default VPC listening on port 80.
const alb = new awsx.lb.ApplicationLoadBalancer("lb", {
    listener: {
        port: 80,
    },

    // Configure the load balancer as internal rather than internet-facing.
    internal: true,
});

// Export the resulting URL so that it's easy to access.
export const endpoint = alb.loadBalancer.dnsName;

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-private-subnet-typescript)

<!-- /option -->

<!-- option: python -->

```python
import pulumi
import pulumi_awsx as awsx

# Create a load balancer in the default VPC listening on port 80.
alb = awsx.lb.ApplicationLoadBalancer(
    "lb",
    awsx.lb.ApplicationLoadBalancerArgs(
        listener=awsx.lb.ListenerArgs(
            port=80,
        ),

        # Configure the load balancer as internal rather than internet-facing.
        internal=True,
    ),
)

# Export the resulting URL so that it's easy to access.
pulumi.export("endpoint", alb.load_balancer.dns_name)

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-private-subnet-python)

<!-- /option -->

<!-- option: go -->

```go
package main

import (
	"github.com/pulumi/pulumi-awsx/sdk/v3/go/awsx/lb"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {

		// Create a load balancer in the default VPC listening on port 80.
		alb, err := lb.NewApplicationLoadBalancer(ctx, "lb", &lb.ApplicationLoadBalancerArgs{
			Listener: &lb.ListenerArgs{
				Port: pulumi.Int(80),
			},

			// Configure the load balancer as internal rather than internet-facing.
			Internal: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}

		// Export the resulting URL so that it's easy to access.
		ctx.Export("endpoint", alb.LoadBalancer.DnsName())
		return nil
	})
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-private-subnet-go)

<!-- /option -->

<!-- option: csharp -->

```csharp
﻿using Pulumi;
using Awsx = Pulumi.Awsx;
using System.Collections.Generic;

return await Deployment.RunAsync(() =>
{
   // Create a load balancer in the default VPC listening on port 80.
   var alb = new Awsx.Lb.ApplicationLoadBalancer("lb", new()
   {
        Listener = new()
        {
            Port = 80,
        },

        // Configure the load balancer as internal rather than internet-facing.
        Internal =   true,
   });

    // Export the resulting URL so that it's easy to access.
    return new Dictionary<string, object?>
    {
        ["endpoint"] = alb.LoadBalancer.Apply(lb => lb.DnsName),
    };
});

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-private-subnet-csharp)

<!-- /option -->

<!-- option: java -->

```java
package myproject;

import com.pulumi.Pulumi;
import com.pulumi.awsx.lb.ApplicationLoadBalancer;
import com.pulumi.awsx.lb.ApplicationLoadBalancerArgs;
import com.pulumi.awsx.lb.inputs.ListenerArgs;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {

            // Create a load balancer in the default VPC listening on port 80.
            var alb = new ApplicationLoadBalancer("lb", ApplicationLoadBalancerArgs.builder()
                .listener(ListenerArgs.builder()
                    .port(80)
                    .build())

                // Configure the load balancer as internal rather than internet-facing.
                .internal(true)
                .build());

            // Export the resulting URL so that it's easy to access.
            ctx.export("endpoint", alb.loadBalancer().apply(loadBalancer -> loadBalancer.dnsName()));
        });
    }
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-private-subnet-java)

<!-- /option -->

<!-- option: yaml -->

```yaml
name: awsx-elb-private-subnet-yaml
runtime: yaml
description: An example that deploys an ApplicationLoadBalancer listening on a private subnet.

resources:
  # Create a load balancer in the default VPC listening on port 80.
  alb:
    type: awsx:lb:ApplicationLoadBalancer
    properties:
      listener:
        port: 80

      # Configure the load balancer as internal rather than internet-facing.
      internal: true

outputs:
  # Export the resulting URL so that it's easy to access.
  endpoint: ${alb.loadBalancer.dnsName}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-private-subnet-yaml)

<!-- /option -->

<!-- /chooser -->

For complete control, you can elect instead to pass in an explicit list of subnets using the `subnets` property.

## Creating a Load Balancer in a Custom VPC

Each region contains [a default VPC](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html) for your
account. The load balancers created above will use it automatically, in addition to its default public or private
subnets, depending on whether you've overridden the default of public using `internal`.

If you'd like to create a load balancer for a custom VPC, provision (or look up) the VPC, then use the `subnetIds`
property of the load balancer to associate it with the VPC's public or private subnet:

<!-- chooser: language -->

<!-- option: typescript -->

```typescript
import * as awsx from "@pulumi/awsx";

// Allocate (or get) a custom VPC.
const vpc = new awsx.ec2.Vpc("vpc");

// Create a load balancer in the default VPC listening on port 80.
const alb = new awsx.lb.ApplicationLoadBalancer("lb", {
    listener: {
        port: 80,
    },

    // Associate the load balancer with the VPC's `public` or `private` subnet.
    subnetIds: vpc.publicSubnetIds,
});

// Export the resulting URL so that it's easy to access.
export const endpoint = alb.loadBalancer.dnsName;

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-vpc-typescript)

<!-- /option -->

<!-- option: python -->

```python
import pulumi
import pulumi_awsx as awsx

# Allocate (or get) a custom VPC.
vpc = awsx.ec2.Vpc("vpc");

# Create a load balancer in the default VPC listening on port 80.
alb = awsx.lb.ApplicationLoadBalancer(
    "lb",
    awsx.lb.ApplicationLoadBalancerArgs(
        listener=awsx.lb.ListenerArgs(
            port=80,
        ),

        # Associate the load balancer with the VPC's `public` or `private` subnet.
        subnet_ids=vpc.public_subnet_ids,
    ),
)

# Export the resulting URL so that it's easy to access.
pulumi.export("endpoint", alb.load_balancer.dns_name)

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-vpc-python)

<!-- /option -->

<!-- option: go -->

```go
package main

import (
	"github.com/pulumi/pulumi-awsx/sdk/v3/go/awsx/ec2"
	"github.com/pulumi/pulumi-awsx/sdk/v3/go/awsx/lb"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {

		// Allocate (or get) a custom VPC.
		vpc, err := ec2.NewVpc(ctx, "vpc", nil)
		if err != nil {
			return err
		}

		// Create a load balancer in the default VPC listening on port 80.
		alb, err := lb.NewApplicationLoadBalancer(ctx, "lb", &lb.ApplicationLoadBalancerArgs{
			Listener: &lb.ListenerArgs{
				Port: pulumi.Int(80),
			},

			// Associate the load balancer with the VPC's `public` or `private` subnet.
			SubnetIds: vpc.PrivateSubnetIds,
		})
		if err != nil {
			return err
		}

		// Export the resulting URL so that it's easy to access.
		ctx.Export("endpoint", alb.LoadBalancer.DnsName())
		return nil
	})
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-vpc-go)

<!-- /option -->

<!-- option: csharp -->

```csharp
﻿using Pulumi;
using Awsx = Pulumi.Awsx;
using System.Collections.Generic;

return await Deployment.RunAsync(() =>
{
   // Allocate (or get) a custom VPC.
   var vpc = new Awsx.Ec2.Vpc("vpc");

   // Create a load balancer in the default VPC listening on port 80.
   var alb = new Awsx.Lb.ApplicationLoadBalancer("lb", new()
   {
        Listener = new()
        {
            Port = 80,
        },

         // Associate the load balancer with the VPC's `public` or `private` subnet.
        SubnetIds = vpc.PublicSubnetIds,
   });

    // Export the resulting URL so that it's easy to access.
    return new Dictionary<string, object?>
    {
        ["endpoint"] = alb.LoadBalancer.Apply(lb => lb.DnsName),
    };
});

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-vpc-csharp)

<!-- /option -->

<!-- option: java -->

```java
package myproject;

import com.pulumi.Pulumi;
import com.pulumi.awsx.ec2.Vpc;
import com.pulumi.awsx.lb.ApplicationLoadBalancer;
import com.pulumi.awsx.lb.ApplicationLoadBalancerArgs;
import com.pulumi.awsx.lb.inputs.ListenerArgs;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {

            // Allocate (or get) a custom VPC.
            var vpc = new Vpc("vpc");

            // Create a load balancer in the default VPC listening on port 80.
            var alb = new ApplicationLoadBalancer("lb", ApplicationLoadBalancerArgs.builder()
                .listener(ListenerArgs.builder()
                    .port(80)
                    .build())

                // Associate the load balancer with the VPC's `public` or `private` subnet.
                .subnetIds(vpc.publicSubnetIds())
                .build());

            // Export the resulting URL so that it's easy to access.
            ctx.export("endpoint", alb.loadBalancer().apply(loadBalancer -> loadBalancer.dnsName()));
        });
    }
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-vpc-java)

<!-- /option -->

<!-- option: yaml -->

```yaml
name: awsx-elb-vpc-yaml
runtime: yaml
description: An example that deploys an ApplicationLoadBalancer in a VPC.

resources:
  # Allocate (or get) a custom VPC.
  vpc:
    type: awsx:ec2:Vpc

  # Create a load balancer in the default VPC listening on port 80.
  alb:
    type: awsx:lb:ApplicationLoadBalancer
    properties:
      listener:
        port: 80

      # Associate the load balancer with the VPC's `public` or `private` subnet.
      subnetIds: ${vpc.publicSubnetIds}

outputs:
  # Export the resulting URL so that it's easy to access.
  endpoint: ${alb.loadBalancer.dnsName}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-vpc-yaml)

<!-- /option -->

<!-- /chooser -->

For more information on creating and configuring VPCs, refer to [the AWSx VPC component guide](/docs/clouds/aws/guides/vpc/).

## Advanced Load Balancer Listener and Target Group Configuration

The above examples were simplistic in their usage of target groups and listeners. In many scenarios, that's all we
need. However, target groups and listeners are more powerful than this and have advanced functionality built-in.

Let's review the core concepts involved in both NLB and ALB style load balancers:

* A _load balancer_ serves as the single point of contact for clients. The load balancer distributes incoming
  application traffic across multiple targets, such as EC2 instances, in multiple availability zones. This increases
  the availability of your application. You add one or more listeners to your load balancer.

* A [_listener_](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-listeners.html) checks
  for connection requests from clients, using the protocol and port that you configure, and forwards
  requests to one or more target groups, based on the rules that you define. Each rule specifies a target group,
  condition, and priority. When the condition is met, the traffic is forwarded to the target group. You must define a
  default rule for each listener, and you can add rules that specify different target groups based on the content of the
  request (also known as content-based routing).

* Each [_target group_](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html) routes
  requests to one or more registered targets, such as EC2 instances, using the protocol and
  port number that you specify. You can register a target with multiple target groups. You can configure health checks
  on a per target group basis. Health checks are performed on all targets registered to a target group that is
  specified in a listener rule for your load balancer.

Many of the examples above leverage smart defaults in the `NetworkLoadBalancer` and `ApplicationLoadBalancer` classes.
This includes creating target groups automatically that leverage the same inbound port information as the listeners.

### Manually Configuring Listeners

During the creation of a listener, the `listener` property will attempt to choose smart defaults based on the scenario
of creating the listener against a load balancer or target group, but there are several configuration options available. These include:

* `protocol`: NLBs support `TCP`, `TLS`, `HTTP`, and `HTTPS`, while ALBs support `HTTP` and `HTTPS`. If not specified,
  NLBs default to `TCP` and ALBs will select `HTTP` or `HTTPS` based on the port supplied.

* `certificateArn` and `sslPolicy`: Enables SSL using the given certificate and policy. This policy controls how
  SSL connections are terminated, among other things. Refer to
  [Create an HTTPS Listener for Your Application Load Balancer](
  https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html) for more information.

* `defaultActions`: Configure the rules and actions to take in response to traffic reaching your
  load balancer. By default, that entails forwarding traffic to a target group. However, additional options are
  available via the `ListenerDefaultAction` type. You may provide multiple rules:

* `authenticateCognito`: Enable Cognito authentication for access through your load balancer. For more
information, see [Authenticate Users Using and Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-authenticate-users.html).

* `authenticateOidc`: Authenticate access through your load balancer using an OpenID Connect (OIDC) compliant
identity provider.

* `fixedResponse`: Return a custom HTTP response, rather than forwarding traffic. For details, see
[Fixed-Response Actions](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#fixed-response-actions).

* `redirect`: Redirect from one URL to another. For details, see
[Redirect Actions](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#redirect-actions).

As an example of a custom action, the following load balancer redirects HTTP traffic on port 80 to port 8080 by defining two listeners, one configured to redirect to the other:

<!-- chooser: language -->

<!-- option: typescript -->

```typescript
import * as awsx from "@pulumi/awsx";

// Create a load balancer in the default VPC.
const alb = new awsx.lb.ApplicationLoadBalancer("lb", {
    listeners: [{
            // Redirect HTTP traffic on port 8080 to port 8081.
            port: 8080,
            protocol: "HTTP",
            defaultActions: [{
                    type: "redirect",
                    redirect: {
                        port: "8081",
                        protocol: "HTTP",
                        statusCode: "HTTP_301",
                    },
                },
            ],
        },
        {
            // Accept HTTP traffic on port 8080.
            port: 8081,
            protocol: "HTTP",
        },
    ],
});

// Export the resulting URL so that it's easy to access.
export const endpoint = alb.loadBalancer.dnsName;

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-multi-listener-redirect-typescript)

<!-- /option -->

<!-- option: python -->

```python
import pulumi
import pulumi_aws as aws
import pulumi_awsx as awsx

# Create a load balancer in the default VPC.
alb = awsx.lb.ApplicationLoadBalancer(
    "lb",
    awsx.lb.ApplicationLoadBalancerArgs(
        listeners=[# Redirect HTTP traffic on port 8080 to port 8081.
            awsx.lb.ListenerArgs(
                port=8080,
                protocol="HTTP",
                default_actions=[aws.lb.ListenerDefaultActionArgs(
                        type="redirect",
                        redirect=aws.lb.ListenerDefaultActionRedirectArgs(
                            port="8081",
                            protocol="HTTP",
                            status_code="HTTP_301",
                        ),
                    ),
                ],
            ),

            # Accept HTTP traffic on port 8081.
            awsx.lb.ListenerArgs(
                port=8081,
                protocol="HTTP",
            ),
        ],
    ),
)

# Export the resulting URL so that it's easy to access.
pulumi.export("endpoint", alb.load_balancer.dns_name)

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-multi-listener-redirect-python)

<!-- /option -->

<!-- option: go -->

```go
package main

import (
	awslb "github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lb"
	"github.com/pulumi/pulumi-awsx/sdk/v3/go/awsx/lb"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {

		// Create a load balancer in the default VPC.
		alb, err := lb.NewApplicationLoadBalancer(ctx, "lb", &lb.ApplicationLoadBalancerArgs{
			Listeners: []lb.ListenerArgs{

				// Redirect HTTP traffic on port 8080 to port 8081.
				{
					Port:     pulumi.Int(8080),
					Protocol: pulumi.String("HTTP"),
					DefaultActions: awslb.ListenerDefaultActionArray{
						awslb.ListenerDefaultActionArgs{
							Type: pulumi.String("redirect"),
							Redirect: awslb.ListenerDefaultActionRedirectArgs{
								Port:       pulumi.String("8081"),
								Protocol:   pulumi.String("HTTP"),
								StatusCode: pulumi.String("HTTP_301"),
							},
						},
					},
				},

				// Accept HTTP traffic on port 8081.
				{
					Port:     pulumi.Int(8081),
					Protocol: pulumi.String("HTTP"),
				},
			},
		})
		if err != nil {
			return err
		}

		// Export the resulting URL so that it's easy to access.
		ctx.Export("endpoint", alb.LoadBalancer.DnsName())
		return nil
	})
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-multi-listener-redirect-go)

<!-- /option -->

<!-- option: csharp -->

```csharp
﻿using Pulumi;
using Aws = Pulumi.Aws;
using Awsx = Pulumi.Awsx;
using System.Collections.Generic;
using System;

return await Deployment.RunAsync(() =>
{
   // Create a load balancer in the default VPC.
   var alb = new Awsx.Lb.ApplicationLoadBalancer("lb", new()
   {
        Listeners = {

            // Redirect HTTP traffic on port 8080 to port 8081.
            new Awsx.Lb.Inputs.ListenerArgs
            {
                Port = 8080,
                Protocol = "HTTP",
                DefaultActions = {
                    new Aws.LB.Inputs.ListenerDefaultActionArgs
                    {
                        Type = "redirect",
                        Redirect = new Aws.LB.Inputs.ListenerDefaultActionRedirectArgs
                        {
                            Port = "8081",
                            Protocol = "HTTP",
                            StatusCode = "HTTP_301",
                        },
                    }
                }
            },

            // Accept HTTP traffic on port 8081.
            new Awsx.Lb.Inputs.ListenerArgs
            {
                Port = 8081,
                Protocol = "HTTP",
            },
        },
   });

    // Export the resulting URL so that it's easy to access.
    return new Dictionary<string, object?>
    {
        ["endpoint"] = alb.LoadBalancer.Apply(lb => lb.DnsName),
    };
});

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-multi-listener-redirect-csharp)

<!-- /option -->

<!-- option: java -->

```java
package myproject;

import com.pulumi.Pulumi;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionArgs;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionRedirectArgs;
import com.pulumi.awsx.lb.ApplicationLoadBalancer;
import com.pulumi.awsx.lb.ApplicationLoadBalancerArgs;
import com.pulumi.awsx.lb.inputs.ListenerArgs;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {

            // Create a load balancer in the default VPC.
            var alb = new ApplicationLoadBalancer("lb", ApplicationLoadBalancerArgs.builder()
                .listeners(new ListenerArgs[] {

                    // Redirect HTTP traffic on port 8080 to port 8081.
                    ListenerArgs.builder()
                        .port(8080)
                        .protocol("HTTP")
                        .defaultActions(new ListenerDefaultActionArgs[] {
                            ListenerDefaultActionArgs.builder()
                                .type("redirect")
                                .redirect(ListenerDefaultActionRedirectArgs.builder()
                                    .port("8081")
                                    .protocol("HTTP")
                                    .statusCode("HTTP_301")
                                    .build())
                                .build(),
                        })
                        .build(),

                    // Accept HTTP traffic on port 8081.
                    ListenerArgs.builder()
                        .port(8081)
                        .protocol("HTTP")
                        .build(),
                })
                .build());

            // Export the resulting URL so that it's easy to access.
            ctx.export("endpoint", alb.loadBalancer().apply(loadBalancer -> loadBalancer.dnsName()));
        });
    }
}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-multi-listener-redirect-java)

<!-- /option -->

<!-- option: yaml -->

```yaml
name: awsx-elb-multi-listener-redirect-yaml
runtime: yaml
description: An example of an ApplicationLoadBalancer with multiple listeners and a custom redirect action.
resources:
  # Create a load balancer in the default VPC.
  alb:
    type: awsx:lb:ApplicationLoadBalancer
    properties:
      listeners:
        # Redirect HTTP traffic on port 8080 to port 8081.
        - port: 8080
          protocol: HTTP
          defaultActions:
            - type: redirect
              redirect:
                port: "8081"
                protocol: HTTP
                statusCode: HTTP_301

        # Accept HTTP traffic on port 8081.
        - port: 8081
          protocol: HTTP

outputs:
  # Export the resulting URL so that it's easy to access.
  endpoint: ${alb.loadBalancer.dnsName}

```

[View full example on GitHub](https://github.com/pulumi/docs/tree/master/static/programs/awsx-elb-multi-listener-redirect-yaml)

<!-- /option -->

<!-- /chooser -->

```bash
$ curl -I "http://$(pulumi stack output endpoint):8080"

HTTP/1.1 301 Moved Permanently
Location: http://lb-692829a-1197942792.us-west-2.elb.amazonaws.com:8081/
```

For more information on listener rules, refer to the [AWS documentation about listeners](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#rule-action-types).

### Manually Configuring Target Groups

A target group is automatically created for each listener that doesn't override the default action. This group
can then be used to load balance any number of targets, including EC2 instances, ECS services, or arbitrary IPs.

You can also create a target group manually, either by defining a `defaultTargetGroup` on the load balancer directly or by allocating a
`TargetGroupAttachment` resource. When doing so, the following additional options are available:

* `deregistrationDelay`: The amount of time for ELB to wait before changing the state of a load balancer from
  draining to unused. The range is 0-3600 seconds, and the default is 300. This is the period of time in which
  an application should gracefully shut down before traffic to it is severed.

* `slowStart`: The amount of time for ELB to wait before sending a target its full share of requests. This can give
  the application time to boot and warm up before it takes traffic. The range is 30-900 seconds or 0 to disable. The
  default is for slow start to be disabled.

* `stickiness`: If enabled (for ALBs only), a cookie will be used to ensure traffic consistently flows to the same
  targets, provided they remain active.

* `targetType`: The type of target you will be using with this target group. The possible values are `instance`,
  if targeting an EC2 instance ID directly, or `ip`, if targeting an IP address. The default is `ip`. Note also that
  IP addresses must be routable within your VPC and cannot be public IP addresses (within your VPC's private subnet
  range, the RFC 1918 range (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), and the RFC 6598 range (100.64.0.0/10).

* `healthCheck`: Overrides the default health check behavior. The parameters available vary by target protocol
  and differ considerably between NLB and ALB. This includes:

* `interval`: The approximate amount of time, in seconds, between health checks of an individual
target. The range is between 5-300 seconds, and defaults to 30 seconds.

* `healthyThreshold`: The number of consecutive health checks successes required before considering an
unhealthy target healthy. The default is 3.

* `unhealthyThreshold`: The number of consecutive health check failures required before considering the target
unhealthy. For NLBs, this value must be the same as `healthyThreshold`. The default is 3.

* `path`: For ALB only, the required destination for health check requests. This allows for application level
health checking, versus NLBs which only support health checking the availability of the target.

* `timeout`: For ALB only, the timeout in seconds for health check requests. The range is 2-60 seconds, and the
default value is 5 seconds.

* `matcher`: For ALB only, the HTTP codes to use when checking for a successful response from a target. You can
specify multiple values (for example, "200,202") or a range of values (for example, "200-299").

* `tags`: Can be used to tag your target group with metadata about its purpose, for reporting or compliance.

For more extensive information on ELB target groups, [refer to the AWS documentation](
https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html).

