AWS Internal Load Balancers Explained: ALB vs NLB, DNS & Setup

An internal load balancer in AWS distributes traffic between services inside your private network, with no internet-facing endpoint. It gets only private IP addresses and a DNS name that resolves to those private IPs. Only clients with a network path into the VPC can reach it. Internal load balancers are the backbone of service-to-service communication in multi-tier and microservice architectures.

Internal load balancers in simple terms

When your app tier needs to call a backend service (say a payments API running on five EC2 instances), it does not pick an instance directly. It sends the request to a single stable DNS name. The internal load balancer receives the request, checks which instances are healthy, and routes the request to one of them.

If instances come and go as the backend scales, the calling service sees no change. The DNS name stays the same. The load balancer handles the rest.

Internal load balancers are not reachable from the internet. They only accept traffic from within the VPC or from connected private networks.

When to use an internal load balancer

Internal load balancers fit well when:

  • Service-to-service traffic inside a VPC. Your app tier, worker tier, and data tier each talk through internal load balancers rather than direct IP addresses.
  • Private APIs used by other app tiers. A payments service, auth service, or inventory service that should never be called directly from the internet.
  • ECS, EKS, or EC2 backends that must stay private. The service runs behind an internal ALB so it is never accidentally exposed publicly.
  • Access from connected private networks. Teams with on-premises systems connected via Site-to-Site VPN or Direct Connect can reach internal services through internal load balancers as if they were on the same network.
  • Cross-VPC traffic via peering or Transit Gateway. A service in VPC-A can call an internal load balancer in VPC-B once VPC Peering or Transit Gateway provides the network path.

When not to use an internal load balancer

  • Public web traffic. Use an internet-facing load balancer for anything that needs to accept requests from the open internet.
  • Exposing a service to other VPCs without full network connectivity. If you want to share a specific service without opening full network connectivity, AWS PrivateLink is the better abstraction. It avoids routing overlap problems and gives the consumer a private endpoint in their own VPC.
  • Simple single-instance backends or container service discovery. If you are running one instance or using ECS service discovery with AWS Cloud Map, a full load balancer may add complexity without adding value.

How internal load balancers work in AWS

Here is what happens when a service sends a request to an internal load balancer:

  1. The client has a network path to the VPC. It could be in the same VPC, a peered VPC, or an on-premises network connected via VPN or Direct Connect. Without a network path, nothing else works.
  2. The client calls the load balancer DNS name. For example: internal-payments-alb-123.us-east-1.elb.amazonaws.com, or a friendly alias from a Route 53 private hosted zone.
  3. DNS resolves to private IP addresses. The load balancer nodes sit in private subnets across two or more Availability Zones. The DNS name resolves to the private IPs of those nodes.
  4. The listener receives the request. The listener is configured with a protocol and port (HTTP/80 or HTTPS/443). It evaluates any routing rules you have defined.
  5. The target group selects a healthy target. The target group holds a list of registered targets (EC2 instances, IP addresses, or Lambda functions). The load balancer sends the request to one of the healthy targets.
  6. Health checks determine eligibility. Each target is checked on a configured interval. Only targets that pass the health check receive live traffic. Unhealthy targets are automatically excluded until they recover.

Internal ALB vs internal NLB

Both the Application Load Balancer and the Network Load Balancer can run as internal. The right choice depends on your traffic type and requirements.

FeatureInternal ALBInternal NLB
OSI layerLayer 7 (application)Layer 4 (transport)
ProtocolsHTTP, HTTPS, gRPCTCP, UDP, TLS
Routing capabilityPath, host header, query string, HTTP headersIP and port only
Static IP behaviourDNS-based only, no static IPStatic private IP per subnet (assigned from your subnet CIDR)
Security groupsYes, supported on the ALB itselfNot on the NLB itself (control via target security groups)
WAF supportYesNo
Client IP handlingOriginal IP in X-Forwarded-For headerSource IP preserved natively
Typical use casesREST APIs, HTTP microservices, gRPC, multi-path routingDatabase proxies, message queues, TCP services, firewall allowlisting

Decision rule: choose internal ALB for HTTP/HTTPS and content-based routing. Choose internal NLB for TCP/UDP/TLS, very high throughput, or when a stable static private IP per subnet is required. For example, when a security group or firewall policy must allowlist a fixed IP rather than a DNS name.

Note on static IPs: Internet-facing NLBs can use Elastic IPs (public). Internal NLBs use static private IPs that AWS assigns from the subnets you specify. These IPs are stable across restarts but are not Elastic IPs and cannot be remapped between subnets.

Internal vs internet-facing load balancers

PropertyInternalInternet-facing
ExposurePrivate network onlyReachable from the open internet
IP type assignedPrivate IPs onlyPublic and private IPs
DNS resolutionResolves to private IPs; only usable with a network path to the VPCResolves to public IPs; reachable from anywhere
Subnet placementPrivate subnets (no internet gateway needed)Public subnets (requires internet gateway)
Typical use caseService-to-service, backend APIs, private data tiersWeb applications, public APIs, user-facing services
Security postureNot directly reachable from internet; lower attack surfaceAccepts internet traffic by design; requires careful security group and WAF rules

DNS, private hosted zones, and access from other networks

When AWS creates an internal load balancer, it generates a DNS name automatically: for example internal-payments-alb-0123456789.us-east-1.elb.amazonaws.com. That name always resolves to the load balancer’s private IP addresses.

Common misconception

The AWS-generated internal LB DNS name is not restricted to inside the VPC. It is a public DNS record that resolves to private IPs. Any DNS resolver can look it up. But a client outside the VPC that gets those private IPs back cannot do anything useful with them. Private IPs are not routable from the internet. Only clients with an actual network path into the VPC can connect.

Adding a friendly name with Route 53 private hosted zones

Most teams do not want service code referencing the long AWS-generated name. You can create a Route 53 private hosted zone (for example internal.example.com) associated with your VPC, then add an alias record:

  • payments-api.internal.example.com pointing as an alias to the internal ALB DNS name

Services in the VPC call the friendly name. Route 53 resolves it to the ALB’s private IPs. The long AWS name becomes an implementation detail.

Private hosted zones are only visible inside the VPCs you associate them with. If you associate a private hosted zone with multiple VPCs, all of them can resolve those names. This is useful when you have peered VPCs or a Transit Gateway hub. Read more in DNS with Route 53.

Access from connected networks

The internal load balancer is reachable from any network that has IP-level connectivity to the VPC:

  • Peered VPCs: Once VPC Peering is set up and route tables are updated, services in the peer VPC can reach the internal load balancer by IP. Associate the private hosted zone with the peer VPC for DNS resolution to work there too.
  • Transit Gateway: All VPCs attached to a Transit Gateway share routes. An internal load balancer in one VPC becomes reachable from all other attached VPCs once routes and security groups allow it.
  • Site-to-Site VPN: On-premises systems connected via VPN can reach internal load balancers across the tunnel, provided routes are propagated and security groups permit the traffic.
  • Direct Connect: Same principle as VPN. Direct Connect creates a private network path between your data center and the VPC, making internal load balancers reachable over the dedicated connection.

When PrivateLink is the better option

If you want to expose a service to another AWS account or VPC without giving that consumer full network connectivity, consider AWS PrivateLink. PrivateLink lets you create an endpoint service backed by an NLB and give consumers a private endpoint in their own VPC. No routing overlap issues, no full VPC peering required.

Security groups, target groups, health checks, and subnet requirements

ALB security group rules

An internal ALB has a security group. You must add an inbound rule allowing traffic from the callers: typically the security group attached to the app tier instances or containers that will call this load balancer. Scoping the source to the caller’s security group (rather than a CIDR) is cleaner and easier to maintain.

Target security group rules

Each target (EC2 instance, container, etc.) also has a security group. That security group must allow inbound traffic on the target port from the ALB’s security group.

Watch out

Forgetting the second security group rule is the single most common reason internal load balancer traffic fails silently. You need two rules to complete the chain: the caller must be allowed into the ALB, and the ALB must be allowed into the targets. Either one missing and every request is dropped.

Target groups

A target group defines the protocol, port, and set of backend resources. Targets can be EC2 instances, IP addresses (useful for ECS Fargate or on-premises targets via Direct Connect), or Lambda functions. Each target group has its own health check configuration independent of the load balancer.

Health checks

The load balancer sends health check requests to each target on a configured interval. Only targets that return a healthy response receive live traffic. For HTTP/HTTPS targets, the health check hits a path you specify (for example /health). Pick a path that tests whether the service is working, not just whether the server process is running.

Why two Availability Zones matter

A load balancer requires subnets in at least two AZs. If one AZ has a disruption, the load balancer continues serving traffic through the other AZ’s nodes.

Single-AZ is a single point of failure. A load balancer with one subnet is a single point of failure. If that AZ has an issue, every service call routed through it stops. Always specify subnets in at least two Availability Zones.

Private subnet placement and IP capacity

Internal load balancers belong in private subnets: subnets with no route to an internet gateway. As the load balancer scales under higher traffic, its nodes consume more IP addresses from the subnets you assigned. A /27 is the stated minimum per subnet, but a /24 gives comfortable room for scaling without running out of IPs.

Example architecture

Here is a realistic two-tier architecture showing how an internet-facing and an internal load balancer work together:

  1. A public-facing Application Load Balancer sits in public subnets and accepts HTTPS traffic from the internet. Its security group allows port 443 from anywhere.
  2. The internet-facing ALB forwards requests to an app tier: a set of EC2 instances or ECS tasks in private subnets. These instances process requests and need to call a backend payments service.
  3. The app tier does not call the payments instances directly. It sends requests to an internal ALB (for example payments-api.internal.example.com) on port 8080.
  4. The internal ALB sits in separate private subnets across two AZs. Its security group allows port 8080 inbound from the app tier’s security group.
  5. The internal ALB routes requests across healthy payments service instances. Their security group allows port 8080 from the internal ALB’s security group.
  6. If the payments service scales from 2 instances to 10, the app tier sees no change. It keeps calling the same DNS name. The internal ALB handles the rest.

This pattern keeps the payments service completely private, decouples the app tier from backend instance details, and gives you health checking and load distribution without any extra code.

How to create an internal ALB with AWS CLI

Four steps: create the load balancer, create a target group, register targets, and add a listener.

# 1. Create the internal ALB (scheme internal = private IPs only)
aws elbv2 create-load-balancer \
  --name payments-api-alb \
  --scheme internal \
  --type application \
  --subnets subnet-private-1a subnet-private-1b \
  --security-groups sg-internal-alb

# 2. Create a target group (targets receive traffic on port 8080)
aws elbv2 create-target-group \
  --name payments-api-tg \
  --protocol HTTP \
  --port 8080 \
  --vpc-id vpc-0123456789abcdef0 \
  --health-check-path /health \
  --health-check-interval-seconds 30

# 3. Register EC2 instances as targets
aws elbv2 register-targets \
  --target-group-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/payments-api-tg/abc123 \
  --targets Id=i-0123456789abcdef0 Id=i-0987654321fedcba0

# 4. Create a listener (ALB accepts HTTP on port 80, forwards to target group)
aws elbv2 create-listener \
  --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/payments-api-alb/abc123 \
  --protocol HTTP \
  --port 80 \
  --default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/payments-api-tg/abc123
Production tip

In production, use HTTPS on port 443 with an ACM certificate on the listener. HTTP/80 is acceptable for internal traffic in trusted private networks, but HTTPS adds defence-in-depth and is a good habit on any service that handles sensitive data.

Common mistakes

  1. Placing the internal ALB in public subnets. An internal load balancer has no internet-facing role. Putting it in public subnets wastes IP space and creates confusion. It belongs in private subnets with no internet gateway route.
  2. Missing security group rules between caller and ALB. The internal ALB’s security group must allow inbound traffic from the calling service. Forgetting this means every request is dropped before it reaches a target.
  3. Missing security group rules between ALB and targets. The targets’ security group must allow inbound traffic from the ALB’s security group. Both sides of the chain must be open. One missing rule silently drops all traffic.
  4. Misunderstanding DNS reachability. The AWS-generated internal LB DNS name resolves to private IPs from anywhere, but those IPs are only usable by clients with a network path into the VPC. A client without that path will get the IPs from DNS and then fail to connect.
  5. Choosing internal ALB when static private IPs are required. If a downstream firewall or security group needs to allowlist a fixed IP, an ALB cannot provide that. Its IPs change as it scales. Use an internal NLB, which provides static private IPs per subnet.
  6. Assuming internal means cross-VPC access is automatic. Internal only means no internet exposure. Another VPC still needs a network path (peering, Transit Gateway, VPN, or Direct Connect) plus route table entries and security group rules that permit the traffic.
  7. Confusing internal load balancers with PrivateLink. An internal load balancer is a private endpoint within your own network. PrivateLink is a different service for sharing a specific endpoint across VPCs or accounts without full network connectivity. They solve different problems.

Frequently asked questions

Can an internal load balancer be reached from another VPC?

Not automatically. An internal load balancer resolves to private IP addresses. A client in a different VPC needs network connectivity first: VPC Peering, Transit Gateway, Site-to-Site VPN, or Direct Connect. Once the network path exists, the DNS name resolves and the load balancer is reachable. If you want to expose a service to other VPCs without full network connectivity, AWS PrivateLink is the cleaner option.

Do I need a public subnet for an internal load balancer?

No. An internal load balancer should be placed in private subnets. It has no internet-facing role and does not need a route to an internet gateway. Placing it in a public subnet wastes IP space and adds unnecessary confusion.

When should I choose internal ALB vs internal NLB?

Choose internal ALB for HTTP and HTTPS traffic where you want content-based routing, path-based rules, header inspection, or WAF integration. Choose internal NLB for TCP/UDP/TLS traffic, very high throughput workloads, or when you need a stable static private IP address per subnet. For example, when a firewall allowlist requires a fixed IP rather than a DNS name.

Does the AWS-generated internal LB DNS name resolve publicly?

The DNS name resolves to private IP addresses. Those IPs are not routable from the internet, so even if the name itself technically resolves, a public client cannot connect to those IPs. Only clients with a network path into the VPC can actually use the load balancer.

Do I need Route 53 private hosted zones for an internal load balancer?

No, they are optional. AWS gives every internal load balancer a DNS name automatically. Private hosted zones let you add a human-readable alias like payments-api.internal.example.com on top of that. Most teams use them for readability and to avoid embedding AWS-generated names in code.

Last verified: 21 April 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.