Skip to main content

Deploy Spring Boot on AWS EC2

TL;DR

Complete guide to deploying a Spring Boot application on AWS EC2 with Amazon Corretto, systemd, nginx, and CloudWatch.

Key facts

Topology
Spring Boot on AWS EC2

TL;DR

This guide covers deploying a Spring Boot application on an AWS EC2 instance with Amazon Corretto JDK, systemd process management, nginx reverse proxy, SSL via Certbot, and CloudWatch monitoring for JVM metrics.

Step 1 — Launch and configure the EC2 instance

Launch an EC2 instance with Ubuntu 24.04 LTS (t3.medium or larger for production). Configure the security group to allow only the ports you need:

  • Port 22 — SSH (restrict to your IP or VPN CIDR)
  • Port 80 — HTTP (for Certbot verification and redirect)
  • Port 443 — HTTPS (public traffic)
  • Port 8080 — do NOT open publicly (Spring Boot listens here, nginx proxies internally)

SSH into the instance:

ssh -i your-key.pem ubuntu@ec2-xx-xx-xx-xx.compute-1.amazonaws.com

Step 2 — Install Amazon Corretto JDK

Amazon Corretto is a no-cost, production-ready OpenJDK distribution maintained by AWS:

sudo apt update && sudo apt upgrade -y
wget -O - https://apt.corretto.aws/corretto.key | sudo gpg --dearmor -o /usr/share/keyrings/corretto-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/corretto-keyring.gpg] https://apt.corretto.aws stable main" | \
    sudo tee /etc/apt/sources.list.d/corretto.list
sudo apt update
sudo apt install -y java-21-amazon-corretto-jdk
java -version

Step 3 — Deploy the JAR

Create a service user and deploy directory:

sudo useradd -r -s /bin/false springapp
sudo mkdir -p /opt/springapp
sudo chown springapp:springapp /opt/springapp

Upload your JAR via SCP or pull from S3:

# From S3
aws s3 cp s3://your-bucket/releases/myapp-1.0.0.jar /opt/springapp/app.jar
sudo chown springapp:springapp /opt/springapp/app.jar

Step 4 — Systemd service

Create /etc/systemd/system/springapp.service:

[Unit]
Description=Spring Boot Application
After=network.target

[Service]
User=springapp
Group=springapp
WorkingDirectory=/opt/springapp
ExecStart=/usr/bin/java \
    -Xms1g -Xmx1g \
    -XX:+UseG1GC \
    -XX:+HeapDumpOnOutOfMemoryError \
    -XX:HeapDumpPath=/opt/springapp/dumps/ \
    -Dspring.profiles.active=production \
    -jar app.jar
Restart=always
RestartSec=10
SuccessExitStatus=143
StandardOutput=journal
StandardError=journal
PrivateTmp=true
NoNewPrivileges=true
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
sudo mkdir -p /opt/springapp/dumps
sudo chown springapp:springapp /opt/springapp/dumps
sudo systemctl daemon-reload
sudo systemctl start springapp
sudo systemctl enable springapp

Step 5 — nginx reverse proxy

sudo apt install -y nginx

Create /etc/nginx/sites-available/springapp:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 60s;
    }
}
sudo ln -s /etc/nginx/sites-available/springapp /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Step 6 — SSL with Certbot

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com

Step 7 — CloudWatch agent for JVM metrics

Install the CloudWatch agent to ship system and JVM metrics:

wget https://amazoncloudwatch-agent.s3.amazonaws.com/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i amazon-cloudwatch-agent.deb

Configure the agent to collect memory, disk, and CPU metrics. Combine this with Spring Boot Actuator's /actuator/metrics endpoint pushed via Micrometer's CloudWatch registry for JVM-level metrics (heap usage, GC pauses, thread count).

Add the Micrometer CloudWatch dependency to your Spring Boot project:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-cloudwatch2</artifactId>
</dependency>

With Reflex

Reflex provides an alternative to complex CloudWatch configuration by monitoring your EC2 instance and Spring Boot application from a single agent. It tracks JVM heap, GC pauses, HTTP error rates, and system resources — and can execute automated recovery playbooks when issues arise, without requiring IAM role configuration or CloudWatch dashboards. See How it works.