How to Remove an AWS ALB Setup for a Laravel App on EC2 (Step by Step)

You spun up an Application Load Balancer for your Laravel app. Now you want it gone. Maybe the bill surprised you, maybe you’re trying to stay inside the free tier, maybe you just want to start over without a bunch of half-configured resources hanging around.

Whatever the reason, tearing down an ALB isn’t a single delete button. There’s a handful of resources involved, and AWS is picky about the order you remove them in. Get it wrong and you’ll spend twenty minutes reading dependency errors.

Below is exactly what I ran to strip the ALB off a Laravel blog running on one EC2 box. Real commands, real output, so you know what you’re looking at when it scrolls past.

What We’re Taking Down

Quick inventory before we start deleting things. A basic ALB-in-front-of-one-instance setup usually leaves you with:

  • ALB Security Group — lets port 80 traffic in from the internet to the load balancer
  • ALB (Application Load Balancer) — the load balancer itself
  • Target Group — where your EC2 instance is registered as a backend
  • HTTP Listener — the bit that actually forwards port 80 from the ALB into the target group
  • EC2 Security Group change — when you built the ALB, you probably locked EC2’s port 80 down so only the ALB security group could reach it

All of that has to come off, and order matters. AWS won’t let you delete a security group that’s still bolted to a load balancer, and it won’t let you delete a load balancer that still has a live listener on it.

Prerequisites

  • AWS CLI installed and configured, with credentials that can touch EC2 and ELB
  • The ALB name or ARN (if you’ve forgotten it, the commands below will find it)
  • Your EC2 instance’s security group ID

Set the region once and save yourself typing --region forty times:

export AWS_DEFAULT_REGION=us-east-1

Step 1: Restore EC2 Direct Access (Port 80)

Do this one first. Seriously.

When you set up the ALB, you almost certainly tightened the EC2 security group so port 80 only accepted traffic from the ALB’s security group. Kill the ALB before fixing that and your site goes dark the instant the load balancer disappears. Not a fun way to find out.

Start by looking at what’s currently on the group:

aws ec2 describe-security-groups   --group-ids sg-0ea87bf2cc1cabb58   --query 'SecurityGroups[0].IpPermissions'

Output:

[
    {
        "FromPort": 80,
        "IpProtocol": "tcp",
        "IpRanges": [],
        "Ipv6Ranges": [],
        "PrefixListIds": [],
        "ToPort": 80,
        "UserIdGroupPairs": [
            {
                "GroupId": "sg-0d4462e05fdc97746",
                "UserId": "363479758429"
            }
        ]
    },
    {
        "FromPort": 22,
        "IpProtocol": "tcp",
        "IpRanges": [
            {
                "CidrIp": "0.0.0.0/0"
            }
        ],
        "Ipv6Ranges": [],
        "PrefixListIds": [],
        "ToPort": 22,
        "UserIdGroupPairs": []
    }
]

There it is. Port 80 has an empty IpRanges and an entry pointing at sg-0d4462e05fdc97746 the ALB security group. Nothing else on the internet can reach that port right now.

Drop the ALB-only rule:

aws ec2 revoke-security-group-ingress   --group-id sg-0ea87bf2cc1cabb58   --protocol tcp   --port 80   --source-group sg-0d4462e05fdc97746

Output:

{
    "Return": true
}

And put the open rule back:

aws ec2 authorize-security-group-ingress   --group-id sg-0ea87bf2cc1cabb58   --protocol tcp   --port 80   --cidr 0.0.0.0/0

Output:

{
    "Return": true,
    "SecurityGroupRules": [
        {
            "SecurityGroupRuleId": "sgr-0b2f3c4d5e6f7a8b9",
            "GroupId": "sg-0ea87bf2cc1cabb58",
            "GroupOwnerId": "363479758429",
            "IsEgress": false,
            "IpProtocol": "tcp",
            "FromPort": 80,
            "ToPort": 80,
            "CidrIpv4": "0.0.0.0/0"
        }
    ]
}

EC2 is reachable on port 80 again. Prove it before you touch anything else—pull up the instance’s public DNS in a browser:

http://ec2-32-192-208-72.compute-1.amazonaws.com

If that loads, you’ve got a working fallback, and the rest of this is low risk.

Step 2: Delete the ALB Listener

Listeners go before the load balancer. AWS will block you otherwise.

Grab the listener ARN:

aws elbv2 describe-listeners   --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:363479758429:loadbalancer/app/laravel-blog-alb/3efc9c6906f063d5   --query 'Listeners[*].ListenerArn'   --output text

Output:

arn:aws:elasticloadbalancing:us-east-1:363479758429:listener/app/laravel-blog-alb/3efc9c6906f063d5/a1b2c3d4e5f6a7b8

Then delete it:

aws elbv2 delete-listener   --listener-arn arn:aws:elasticloadbalancing:us-east-1:363479758429:listener/app/laravel-blog-alb/3efc9c6906f063d5/a1b2c3d4e5f6a7b8

Output:

(no output — success returns empty)

Silence is good here. The ELB APIs don’t print anything on a successful delete, so an empty response means it went through.

Step 3: Delete the ALB

Listener’s gone, so the load balancer can go too:

aws elbv2 delete-load-balancer   --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:363479758429:loadbalancer/app/laravel-blog-alb/3efc9c6906f063d5

Output:

(no output — deletion initiated)

This one isn’t instant. The ALB drops into a deleting state and takes a minute or two to actually go away. Don’t rush ahead — the next steps will fail if it’s still hanging around. Poll it:

aws elbv2 describe-load-balancers   --load-balancer-arns arn:aws:elasticloadbalancing:us-east-1:363479758429:loadbalancer/app/laravel-blog-alb/3efc9c6906f063d5   --query 'LoadBalancers[0].State.Code'   --output text

Output:

deleting

Give it 60 seconds and run it again. Eventually you’ll see this:

An error occurred (LoadBalancerNotFound) when calling the DescribeLoadBalancers operation: 'arn:aws:elasticloadbalancing:...' not found

Looks like a failure, isn’t one. LoadBalancerNotFound is the signal you’re waiting for — nothing left to describe means nothing left to bill.

Step 4: Delete the Target Group

Target groups live on their own and survive the ALB. They also refuse to delete while they’re still attached to a load balancer, which is why this comes after Step 3 rather than before it.

aws elbv2 delete-target-group   --target-group-arn arn:aws:elasticloadbalancing:us-east-1:363479758429:targetgroup/laravel-blog-tg/d921805e7e5a464a

Output:

(no output — success)

Step 5: Delete the ALB Security Group

Last AWS resource on the list — the security group you made specifically for the load balancer. Same dependency story: try this while the ALB still exists and AWS will tell you the group is in use.

aws ec2 delete-security-group   --group-id sg-0d4462e05fdc97746

Output:

(no output — success)

Step 6: Verify Everything Is Cleaned Up

Worth two minutes to confirm you didn’t leave anything behind.

No ALBs matching our name:

aws elbv2 describe-load-balancers   --query 'LoadBalancers[?contains(LoadBalancerName, `laravel-blog`)].LoadBalancerName'   --output text

Output:

(empty — no matching load balancers)

No leftover target groups:

aws elbv2 describe-target-groups   --query 'TargetGroups[?contains(TargetGroupName, `laravel-blog`)].TargetGroupName'   --output text

Output:

(empty — no matching target groups)

And the actual point of all this — is the app still up?

curl -I http://ec2-32-192-208-72.compute-1.amazonaws.com

Output:

HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block

200 OK, straight from nginx on the instance. No load balancer in the path.

What About Billing?

For most people on the free tier, this is the whole reason they’re here. A few things to know:

  • Charges stop when the ALB finishes deleting. No grace period, no trailing window.
  • AWS bills per Load Balancer Capacity Unit hour, so an ALB that’s sitting there doing nothing still costs you.
  • On a t2.micro with barely any traffic, the ALB routinely costs more than the instance it’s balancing. That’s usually the moment people go looking for a teardown guide.
  • Your current month’s bill won’t drop to zero right away — it still reflects everything used up to the deletion.

If this is a personal project or you’re just poking around AWS to learn it, running straight off EC2 is completely fine. Add the ALB back when you actually need what it does — SSL termination, spreading traffic across instances, that kind of thing.

Quick Reference: Deletion Order

Stick to this order. Deviate and AWS starts throwing dependency errors at you:

  1. Restore the EC2 security group (open port 80 to 0.0.0.0/0)
  2. Delete the HTTP listener
  3. Delete the ALB, then wait for it to finish
  4. Delete the target group
  5. Delete the ALB security group

Five steps, and the ALB is out of your account for good. No stray resources, no line item next month for something you forgot about.

Want it back later? I’ve got a post on setting up an ALB for Laravel on EC2 — same environment, same resource IDs, just running this in reverse.

Avatar photo

Asif Khan

I have spent over 10 years working across IT systems, open source software, DevOps, Linux administration and cloud operations. Three things drive most of what I do: automation, security and resilience. Much of that work involves planning and building the platforms that sit behind services people rely on daily, which means designing for failure just as carefully as for load. Cloud computing held my attention early on, largely for its flexibility. Being able to scale up and then back down again means far less guessing about how much capacity you will need. Across projects I work with the full DevOps toolchain, from provisioning, orchestration and configuration management through to release management and microservices architecture.