Friday, 6 March 2026

Configure an AWS Application Load Balancer for a Spring Boot App (Step-by-Step)

 Below is a step-by-step, “article-style” guide to configure an AWS Load Balancer for a new Spring Boot application. I’ll show a clean, production-friendly setup using Application Load Balancer (ALB) (best fit for HTTP/HTTPS, path-based routing, host-based routing, WebSockets, etc.). I’ll include both EC2 + Auto Scaling and ECS/Fargate notes where it matters.


Configure an AWS Application Load Balancer for a Spring Boot App (Step-by-Step)

What you’re building

A typical secure AWS setup looks like this:

Internet → ALB (HTTP/HTTPS) → Target Group → Spring Boot instances/containers

The load balancer:

  • Terminates TLS (HTTPS)

  • Health-checks your app

  • Distributes traffic across instances

  • Supports scaling and zero-downtime deployments (with the right strategy)


Prerequisites

Before creating the load balancer, decide these basics:

  1. Where is Spring Boot running?

    • EC2 instances (common)

    • ECS/Fargate (common)

    • EKS (then you’ll likely use AWS Load Balancer Controller; similar concepts)

  2. App port

    • Common: 8080 (Spring Boot default)

    • We’ll assume 8080

  3. Health endpoint

    • Best practice: /actuator/health (Spring Boot Actuator)

    • Use the “liveness” style endpoint for ALB checks where possible


Step 1: Prepare the Spring Boot app for ALB health checks

Enable actuator (recommended)

In build.gradle / pom.xml, include actuator.

Then configure:

  • Expose health endpoint

  • Ensure it returns 200 OK

Example application.yml:

management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
probes:
enabled: true

Recommended health paths:

  • /actuator/health (simple)

  • /actuator/health/liveness (even better for ALB checks)

Tip: ALB health checks must succeed quickly—avoid slow DB checks on the main health check path unless you specifically want that behavior.


Step 2: Network foundation (VPC + subnets)

For an internet-facing ALB, you want:

  • VPC

  • 2+ public subnets in different AZs (ALB requirement for HA)

  • Route table for public subnets with route to an Internet Gateway

Also ensure your backend compute (EC2/ECS tasks) is in:

  • private subnets (recommended), OR

  • public subnets (simpler but less ideal)


Step 3: Create / confirm Security Groups

You’ll typically use two security groups:

A) ALB Security Group (inbound from the internet)

Inbound rules:

  • HTTP 80 from 0.0.0.0/0 (optional; often used only to redirect to HTTPS)

  • HTTPS 443 from 0.0.0.0/0 (recommended for production)

Outbound:

  • Allow all (default is fine), or restrict to backend security group ports.

B) Application Security Group (inbound only from ALB)

Inbound rules:

  • Custom TCP 8080 source = ALB security group

  • SSH 22 only from your VPN/bastion/office IP (if EC2; avoid opening to world)

This is the key security pattern: instances accept app traffic only from the ALB.


Step 4: Create a Target Group

Go to EC2 → Target Groups → Create target group

Choose:

  • Target type

    • Instance (if EC2)

    • IP (if ECS/Fargate, or if you want to register IPs)

    • Lambda (rare for Spring Boot directly)

Configuration:

  • Protocol: HTTP

  • Port: 8080

  • VPC: your VPC

Health checks:

  • Protocol: HTTP

  • Path: /actuator/health (or /actuator/health/liveness)

  • Healthy threshold: 2–3

  • Unhealthy threshold: 2–3

  • Timeout: 5s

  • Interval: 15–30s

  • Success codes: 200 (or 200-399 depending on your endpoint)

Pro tip: Start with /actuator/health and 200-399 if you have redirects or special behavior.

Register targets:

  • If EC2: select instances and add them (or let Auto Scaling do it later)

  • If ECS: ECS service will attach tasks automatically


Step 5: Create the Application Load Balancer (ALB)

Go to EC2 → Load Balancers → Create Load Balancer → Application Load Balancer

  1. Name it (e.g., springboot-alb-prod)

  2. Scheme: Internet-facing (or internal if private)

  3. IP address type: IPv4 (or dualstack if needed)

  4. Network mapping:

    • Select your VPC

    • Select at least two public subnets across AZs

  5. Security group: attach the ALB SG you created


Step 6: Configure ALB Listeners and Rules

Option A (common): HTTP redirects to HTTPS + HTTPS forwards to target group

Listener 80 (HTTP):

  • Action: Redirect to HTTPS 443

Listener 443 (HTTPS):

  • Attach an ACM certificate

  • Forward to your target group

Add TLS Certificate (ACM)

Go to AWS Certificate Manager (ACM):

  • Request a public certificate for app.yourdomain.com

  • Validate via DNS (recommended)

  • Once “Issued”, select it in the ALB 443 listener


Step 7: Connect ALB to your Spring Boot compute

If using EC2 + Auto Scaling (recommended for reliability)

  1. Put your EC2 instances into an Auto Scaling Group

  2. In the ASG, attach the Target Group

  3. Ensure instances use Application SG and are in correct subnets

  4. Confirm your app runs on 8080 and is reachable from ALB SG

If using ECS/Fargate

  1. Create/update ECS Service

  2. Enable Load balancing

  3. Choose the ALB, listener, and target group

  4. Ensure task security group allows 8080 inbound from ALB SG

  5. Confirm container port mapping exposes 8080


Step 8: Configure DNS (Route 53)

If you own the domain in Route 53:

Route 53 → Hosted zone → Create record:

  • Record name: app (for app.yourdomain.com)

  • Type: A (Alias)

  • Alias to: your ALB DNS name

Now your public URL points to the ALB.


Step 9: Validate end-to-end

  1. Open the ALB DNS name:

    • http://<alb-dns> (should redirect to HTTPS)

    • https://<alb-dns> (should show your app)

  2. Check target group health:

    • Targets should be healthy

  3. Check logs if unhealthy:

    • Security group rules (most common issue)

    • Health check path/port wrong

    • App not listening on 0.0.0.0 / port mismatch


Step 10: Production-grade hardening (highly recommended)

Enable access logs

ALB → Attributes → Access logs → store in S3
Great for debugging and audit.

Enable deletion protection (prod)

Prevents accidental deletion.

Stickiness (only if needed)

If your app uses in-memory sessions (not ideal), enable stickiness. Better: use stateless JWT or external session store.

Timeouts

Tune:

  • Idle timeout (default 60s)
    Useful for long requests or SSE/WebSockets patterns.

Use WAF (for internet-facing apps)

Attach AWS WAF to ALB:

  • Managed rule groups

  • Rate limiting

  • IP reputation filters

Use HTTPS-only

Disable HTTP listener or always redirect HTTP → HTTPS.


Common Spring Boot + ALB gotchas (and fixes)

  1. Health check failing

    • Fix path (/actuator/health)

    • Confirm actuator exposure

    • Confirm security group allows ALB → app port

  2. Wrong port

    • ALB forwards to 8080, but app actually runs on 80 or 5000

    • Align target group port + runtime port

  3. App binds to localhost

    • Ensure server binds to 0.0.0.0 (typical in containers)

    • Spring Boot default is usually fine on EC2

  4. TLS at ALB + app thinks it’s HTTP

    • Add forwarded headers support:

      • For modern Spring Boot, set:

        server.forward-headers-strategy=framework
    • Helps with redirects, scheme detection, secure cookies.


Quick reference: minimal checklist

  • ALB in 2 public subnets

  • ALB SG allows 443 from internet

  • App SG allows 8080 from ALB SG

  • Target group port 8080, correct health path

  • Listener 443 forwards to target group

  • ACM cert attached + Route 53 alias record

  • Targets show healthy


If you tell me EC2 vs ECS/Fargate, your domain setup (Route53 or external), and whether you want blue/green deployments, I can tailor this into an even more “copy/paste runnable” runbook (including exact security group rules, recommended health endpoints, and deployment strategy).

Step-by-step: Configure a Google Cloud Load Balancer for a new Spring Boot app (GCP)

 This walkthrough shows a solid, production-style setup for a Spring Boot application running on Google Cloud Platform, fronted by a Google Cloud HTTP(S) Load Balancer with TLS, health checks, autoscaling, and clean routing.

I’ll cover two common deployment paths:

  • Path A (recommended for many Spring Boot teams): Compute Engine Managed Instance Group (MIG) + External HTTP(S) Load Balancer

  • Path B (container-first): GKE / Cloud Run (quick notes at the end)


What you’ll build

Users → Global external HTTP(S) Load Balancer → Backend service → MIG (Spring Boot VMs)

Key pieces:

  • A Spring Boot service listening on a known port (e.g., 8080)

  • A health endpoint that returns 200 OK (e.g., /actuator/health)

  • A Managed Instance Group (for scale + self-heal)

  • A Backend service with a health check

  • A URL map + target proxy + forwarding rule

  • Optional: Managed SSL certificate + Cloud DNS


Prereqs

  • A GCP project with billing enabled

  • gcloud installed and authenticated

  • A domain name (optional but recommended for HTTPS with managed cert)

  • Spring Boot app ready to run in production profile

Set your defaults:

gcloud config set project YOUR_PROJECT_ID
gcloud config set compute/region asia-south1
gcloud config set compute/zone asia-south1-a

Step 1: Prepare your Spring Boot app for load balancing

1.1 Add a health endpoint

If you use Spring Actuator:

Gradle

implementation 'org.springframework.boot:spring-boot-starter-actuator'

application.yml

management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
probes:
enabled: true

Health endpoint:

  • /actuator/health (or /actuator/health/liveness depending on config)

1.2 Make sure your app binds correctly

Ensure Spring Boot binds to all interfaces:

server:
address: 0.0.0.0
port: 8080

1.3 Keep it stateless

A load balancer will route requests across instances. Prefer:

  • external session store (Redis / Cloud Memorystore), or

  • JWT/stateless auth


Step 2: Build a VM image that runs your Spring Boot app

You have two practical approaches:

Option A: Startup script on a base OS (simple)

  • Create an instance template that installs Java and runs the jar via a startup script.

Option B: Bake a custom image (cleaner, faster scale-up)

  • Use Packer or custom image pipeline.

Below is Option A (fast to implement).


Step 3: Create an instance template (with startup script)

3.1 Upload your app artifact

Example: put the jar in a GCS bucket:

gsutil mb -l asia-south1 gs://YOUR_BUCKET_NAME
gsutil cp build/libs/your-app.jar gs://YOUR_BUCKET_NAME/

3.2 Create a service account for instances (recommended)

gcloud iam service-accounts create springboot-vm-sa \
--display-name="Spring Boot VM Service Account"

Grant only what you need (example: read jar from GCS):

gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:springboot-vm-sa@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/storage.objectViewer"

3.3 Create a startup script

Create startup.sh locally:

cat > startup.sh <<'EOF'
#!/bin/bash
set -e

APP_BUCKET="YOUR_BUCKET_NAME"
APP_JAR="your-app.jar"
APP_DIR="/opt/app"
PORT="8080"

apt-get update
apt-get install -y default-jre-headless google-cloud-cli

mkdir -p ${APP_DIR}
gsutil cp gs://${APP_BUCKET}/${APP_JAR} ${APP_DIR}/${APP_JAR}

cat > /etc/systemd/system/springboot.service <<SYSTEMD
[Unit]
Description=Spring Boot App
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=${APP_DIR}
ExecStart=/usr/bin/java -jar ${APP_DIR}/${APP_JAR} --server.port=${PORT}
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
SYSTEMD

systemctl daemon-reload
systemctl enable springboot.service
systemctl start springboot.service
EOF

3.4 Create the instance template

gcloud compute instance-templates create springboot-template \
--machine-type=e2-medium \
--service-account=springboot-vm-sa@YOUR_PROJECT_ID.iam.gserviceaccount.com \
--scopes=https://www.googleapis.com/auth/cloud-platform \
--tags=springboot-backend \
--metadata-from-file=startup-script=startup.sh \
--image-family=debian-12 \
--image-project=debian-cloud

Step 4: Create a Managed Instance Group (MIG)

gcloud compute instance-groups managed create springboot-mig \
--base-instance-name=springboot \
--size=2 \
--template=springboot-template

Enable autoscaling (example):

gcloud compute instance-groups managed set-autoscaling springboot-mig \
--max-num-replicas=10 \
--min-num-replicas=2 \
--target-cpu-utilization=0.6 \
--cool-down-period=60

Step 5: Allow traffic from the load balancer to your instances (Firewall)

For an external HTTP(S) Load Balancer, backend VMs must allow traffic from Google LB health check + proxy ranges.

Create a firewall rule allowing traffic to port 8080 from Google LB ranges:

gcloud compute firewall-rules create allow-lb-to-springboot \
--network=default \
--action=ALLOW \
--direction=INGRESS \
--rules=tcp:8080 \
--source-ranges=130.211.0.0/22,35.191.0.0/16 \
--target-tags=springboot-backend

If you use a separate health check path, same port is fine.


Step 6: Create a health check for the backend

Use HTTP health check to /actuator/health:

gcloud compute health-checks create http springboot-hc \
--port 8080 \
--request-path /actuator/health \
--check-interval 10s \
--timeout 5s \
--unhealthy-threshold 3 \
--healthy-threshold 2

Step 7: Create a backend service and attach the MIG

7.1 Create backend service

gcloud compute backend-services create springboot-backend \
--protocol=HTTP \
--port-name=http \
--health-checks=springboot-hc \
--global

7.2 Attach the MIG

First, make the MIG a backend (needs an instance group reference; MIG is zonal by default):

gcloud compute backend-services add-backend springboot-backend \
--instance-group=springboot-mig \
--instance-group-zone=asia-south1-a \
--global

Step 8: Create URL map (routing rules)

Basic single-service routing:

gcloud compute url-maps create springboot-urlmap \
--default-service springboot-backend

If later you want /api/* to one backend and /static/* to another, you’d add path matchers.


Step 9: Create the target HTTP proxy + forwarding rule (HTTP)

9.1 Target HTTP proxy

gcloud compute target-http-proxies create springboot-http-proxy \
--url-map=springboot-urlmap

9.2 Global forwarding rule (port 80)

gcloud compute forwarding-rules create springboot-http-fr \
--global \
--target-http-proxy=springboot-http-proxy \
--ports=80

Get the LB IP:

gcloud compute forwarding-rules describe springboot-http-fr --global --format="value(IPAddress)"

Test:

curl -i http://LB_IP/
curl -i http://LB_IP/actuator/health

At this point you have a working HTTP load balancer.


Step 10: Enable HTTPS with a managed certificate (recommended)

10.1 Reserve a static global IP (best practice)

gcloud compute addresses create springboot-lb-ip --global
gcloud compute addresses describe springboot-lb-ip --global --format="value(address)"

Re-create the forwarding rule to use this IP (or create a new one):

gcloud compute forwarding-rules delete springboot-http-fr --global -q

gcloud compute forwarding-rules create springboot-http-fr \
--global \
--address=springboot-lb-ip \
--target-http-proxy=springboot-http-proxy \
--ports=80

10.2 Create a managed SSL certificate

gcloud compute ssl-certificates create springboot-managed-cert \
--domains=yourdomain.com \
--global

Managed cert becomes ACTIVE only after DNS points to the LB IP.

10.3 Create an HTTPS target proxy

gcloud compute target-https-proxies create springboot-https-proxy \
--url-map=springboot-urlmap \
--ssl-certificates=springboot-managed-cert

10.4 Create HTTPS forwarding rule (port 443)

gcloud compute forwarding-rules create springboot-https-fr \
--global \
--address=springboot-lb-ip \
--target-https-proxy=springboot-https-proxy \
--ports=443

Step 11: Point DNS to the load balancer

In your DNS provider (or Cloud DNS), create:

  • A record: yourdomain.comLB_STATIC_IP

Once propagated, check cert status:

gcloud compute ssl-certificates describe springboot-managed-cert --global

When it’s ACTIVE:

curl -i https://yourdomain.com/actuator/health

Step 12: (Strongly recommended) Force HTTP → HTTPS redirect

Create a second URL map just for redirects:

gcloud compute url-maps create springboot-redirect-map \
--default-url-redirect=httpsRedirect=true,responseCode=301

Create a redirect proxy and update the HTTP forwarding rule:

gcloud compute target-http-proxies create springboot-redirect-proxy \
--url-map=springboot-redirect-map

gcloud compute forwarding-rules delete springboot-http-fr --global -q

gcloud compute forwarding-rules create springboot-http-fr \
--global \
--address=springboot-lb-ip \
--target-http-proxy=springboot-redirect-proxy \
--ports=80

Now all http:// gets redirected to https://.


Step 13: Observability & operations checklist

Logging and metrics

  • Enable Cloud Logging and Cloud Monitoring (default on GCE)

  • Add Spring Boot structured logs (JSON) if you can

  • Consider exporting app metrics using Micrometer to Cloud Monitoring or Prometheus (if on GKE)

Security hardening

  • Put instances in private subnets (if using Shared VPC) and only allow LB ingress

  • Use least privilege for instance service account

  • Use Secret Manager for secrets (don’t bake into VM)

Reliability

  • Use regional MIG for higher availability across zones (recommended for prod)

  • Enable autohealing on MIG using the same health check:

gcloud compute instance-groups managed set-autohealing springboot-mig \
--health-check=springboot-hc \
--initial-delay=120

Common Spring Boot gotchas behind a load balancer

  • If you generate absolute URLs or redirects, configure forwarded headers:

    • In Spring Boot, ensure it respects X-Forwarded-* headers (depends on version and config).

  • If you have large uploads, tune max request size and timeouts.

  • Health endpoint must be fast and consistently return 200.


Alternative: If your Spring Boot app is containerized

Cloud Run

  • Easiest: deploy to Cloud Run and optionally put it behind an external HTTPS LB for custom domains / advanced routing / WAF.

  • Cloud Run already scales and handles many LB-ish concerns.

GKE Ingress

  • You’d create a Kubernetes Service + Ingress (or Gateway API), and GKE provisions the LB.

If you tell me which runtime you’re actually using (GCE VM, GKE, or Cloud Run) and whether you need internal or external LB, I’ll tailor the article to that exact architecture and include the right commands and diagrams.