Deploy Your Spring Boot API to AWS

Deploy a Spring Boot REST API to EC2 and connect it to a managed RDS database.

Introduction

30 Second Summary

Building an app on your own computer is one thing. Making it available to the world is a completely different challenge.

In this project, you will deploy a Spring Boot REST API to AWS so anyone on the internet can access it. You will set up a cloud server, a managed database, and the networking rules that connect them.

What You'll Build

A production-style deployment of your AI-Powered Invoice Processing Service running on an AWS EC2 instance connected to a managed PostgreSQL database on RDS.

By the end of this project, you'll have:

  • A running EC2 instance with Java installed and your application JAR deployed.
  • An RDS PostgreSQL database securely connected to your server through the default VPC.
  • Two Security Groups that control exactly which traffic can reach each resource.
  • A tested, live REST API endpoint accessible from the public internet.
  • Secret Mission: Add HTTPS to your API using Let's Encrypt and Nginx as a reverse proxy.

Are there any prerequisites?

This project builds on an existing Spring Boot + PostgreSQL REST API (the Invoice Processing Service). You should also have basic familiarity with the terminal.

Install Maven and AWS CLI

Your Spring Boot API runs perfectly on your local machine. To get it running in the cloud, you need to package it into a portable format and have a way to talk to AWS from your terminal.

Maven handles the packaging. It compiles your Java code and dependencies into a single JAR file that any server with Java can run. The AWS CLI handles the cloud connection, letting you manage AWS resources directly from Terminal.

In this step, get ready to:
  • Install Maven using Homebrew.
  • Install the AWS CLI v2 on your Mac.
  • Connect your terminal to your AWS account.
Install Maven using Homebrew

Homebrew is a package manager for macOS that makes installing developer tools simple. You will use it to install Maven in one command.

  • Press Cmd+Space to open your search bar.
  • Type Terminal and press Enter to open it.
  • Install Maven by running this command:
brew install maven

This may take a minute while Homebrew downloads Maven and its dependencies.

  • Verify Maven installed correctly by running:
mvn --version

✔️ I see a version number

You should see output starting with Apache Maven 3.9 or similar. Maven is ready to go.

ⓧ brew: command not found

This means Homebrew is not installed on your Mac. Install it by running this command:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  • Follow the on-screen instructions. Your Mac may ask for your login password.
  • Once Homebrew finishes installing, close and reopen Terminal.
  • Run brew install maven again.

ⓧ mvn: command not found

If brew install maven completed without errors but mvn is not found, close and reopen Terminal to reload your shell configuration. Then run mvn --version again.

Install the AWS CLI v2

The AWS CLI is a command-line tool that lets you create and manage AWS resources from Terminal. You will install it using the official macOS package installer.

  • Download and install the AWS CLI by running these commands. The second command uses sudo, which will prompt for your macOS login password:
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /

What do these commands do?

The first command downloads the official AWS CLI installer package to your current directory. The second command runs that installer, which places the aws command in /usr/local/bin so you can use it from anywhere in Terminal.

  • Verify the AWS CLI installed correctly by running:
aws --version

✔️ I see a version number

You should see output like aws-cli/2.x.x followed by Python version info. The AWS CLI is ready.

ⓧ command not found

If you see aws: command not found, your shell does not know where the aws binary is located.

  • Close and reopen Terminal, then try aws --version again.
  • If it still fails, check that /usr/local/bin is in your PATH by running echo $PATH. If you do not see it listed, add it to your shell profile.
  • Clean up the downloaded installer file by running:
rm AWSCLIV2.pkg
Connect the AWS CLI to your account

The AWS CLI is installed, but it does not know which AWS account to talk to yet. You need to provide it with credentials so it can make requests on your behalf.

Where to find your AWS credentials

You need an Access Key ID and Secret Access Key from your AWS account. To create these:

  • Log in to the AWS Management Console.
  • Go to IAM (search for it in the top search bar).
  • Click Users in the left sidebar, then select your user.
  • Click the Security credentials tab.
  • Click Create access key. Choose Command Line Interface (CLI) as the use case.
  • Copy both the Access Key ID and Secret Access Key. Save them somewhere safe. You will not be able to see the Secret Access Key again after closing this page.
  • Configure the AWS CLI by running this command. It will prompt you for four values one at a time:
aws configure
  • When prompted for AWS Access Key ID, paste the Access Key ID you copied from IAM.
  • When prompted for AWS Secret Access Key, paste the Secret Access Key you copied from IAM.
  • When prompted for Default region name, type us-east-1.
  • When prompted for Default output format, type json.

What did this just do?

The aws configure command saved your credentials and preferences to two files on your Mac: ~/.aws/credentials and ~/.aws/config. Every AWS CLI command you run from now on will use these credentials automatically.

  • Verify your terminal is connected to AWS by running:
aws sts get-caller-identity

You should see a JSON response containing your AWS account ID, user ARN, and user ID. This confirms your terminal can communicate with AWS.

Seeing an error about invalid credentials?

  • Double-check that you pasted the full Access Key ID and Secret Access Key without extra spaces.
  • Make sure you copied the credentials from the correct IAM user.
  • If you closed the IAM page before copying the Secret Access Key, delete the access key and create a new one.

Help me troubleshoot my AWS CLI credentials error.

Your Mac is now equipped with both tools you need. Next up, you will package your Spring Boot project into a deployable JAR file.

Build Your Spring Boot JAR

Your tools are installed and your terminal is connected to AWS. Now you need to prepare your application for cloud deployment.

Right now, your Spring Boot project has database credentials hardcoded for your local machine. That will not work on an EC2 instance that connects to a different database. You need to make the connection details configurable, then package everything into a single JAR file that you can upload to the server.

In this step, get ready to:
  • Update your database configuration to use environment variables.
  • Build your project into a deployable JAR file with Maven.
  • Verify the JAR file exists and note its filename.
Update application.properties for environment variables

Your application.properties file currently has your local database connection details hardcoded. On AWS, your app will connect to an RDS database with a completely different host, name, and credentials.

Environment variables let you inject these values at runtime. Your app reads them when it starts up, so the same JAR file works in any environment without code changes.

  • Open your Spring Boot project in your code editor.
  • Navigate to src/main/resources/application.properties.
  • Find your existing datasource lines. They likely look something like this:
spring.datasource.url=jdbc:postgresql://localhost:5432/invoicedb
spring.datasource.username=postgres
spring.datasource.password=yourLocalPassword
  • Replace those three datasource lines with the following environment variable placeholders:
# Database connection - reads from environment variables at runtime
spring.datasource.url=jdbc:postgresql://${DB_HOST}:5432/${DB_NAME}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASSWORD}

What does this code do?

The ${...} syntax tells Spring Boot to look for an environment variable with that name when the application starts.

When you deploy to EC2 later, you will set DB_HOST to your RDS endpoint, DB_NAME to the database name, and DB_USER and DB_PASSWORD to your RDS credentials. The same JAR file works locally or in the cloud depending on what values you provide.

  • Save application.properties.
  • Keep any other properties in the file (like spring.jpa.hibernate.ddl-auto or other settings your project uses). Only replace the three datasource lines.

Not sure which lines to replace?

Look for any lines that start with spring.datasource. You should see a URL, username, and password line. Replace all three with the environment variable versions above.

If your project uses application.yml instead of application.properties, the equivalent YAML values are the same placeholders under the spring.datasource key.

Help me update my application.properties for environment variables.

Build the JAR with Maven

Maven compiles your Java source code, bundles all dependencies, and packages everything into a single JAR file. This JAR is the artifact you will upload to your EC2 instance.

  • In your Terminal, navigate to your project root directory (the folder containing pom.xml) by running:
cd ~/Desktop/invoice-processing-service

Your folder name may differ

Replace invoice-processing-service with the actual name of your Spring Boot project folder. The key is to be inside the directory that contains your pom.xml file.

  • Build your project into a JAR file by running:
mvn clean package -DskipTests

What does this command do?

  • clean deletes any previous build output in the target/ directory.
  • package compiles your code, resolves dependencies, and bundles everything into a JAR file.
  • -DskipTests skips running tests. Your tests expect a local PostgreSQL database, but you are building for a cloud database that does not exist yet.

The build takes 30-60 seconds. You should see BUILD SUCCESS at the end of the output.

Seeing BUILD FAILURE?

If you see a compilation error, check that your application.properties changes did not accidentally remove a required property or introduce a typo.

If you see a dependency resolution error, make sure you are connected to the internet and run mvn clean package -DskipTests again. Maven needs to download dependencies on the first build.

Help me fix my Maven build failure.

Verify the JAR was created
  • Confirm your JAR file exists by running:
ls target/*.jar

You should see a filename like target/invoice-processing-service-0.0.1-SNAPSHOT.jar. Your exact filename depends on your project's artifactId and version in pom.xml.

  • Note the exact JAR filename. You will need it when uploading to EC2 in a later step.

Write down your JAR filename

Copy the filename from the ls output and save it somewhere accessible. You will reference it multiple times during deployment.

Your application is now packaged and ready for the cloud. Next up, you will create the security groups that control which traffic can reach your EC2 instance and RDS database.

Create Security Groups

Your JAR is built and ready to deploy. Before you launch any servers or databases, you need to define the network rules that control who can talk to what.

In AWS, Security Groups act as virtual firewalls for your resources. You will create two: one for your EC2 server (allowing internet traffic in on port 8080) and one for your RDS database (allowing only your EC2 instance to connect).

In this step, get ready to:
  • Create an EC2 security group that allows SSH and API traffic.
  • Create an RDS security group that only accepts connections from the EC2 instance.
Navigate to EC2 Security Groups

Security Groups live under the EC2 service in the AWS Console. You will create both groups in the default VPC, which is automatically set up in every AWS account.

  • In the AWS Management Console, click the search bar at the top.
  • Type EC2 and select EC2 from the results.
  • In the left sidebar, scroll down to the Network & Security section.
  • Click Security Groups.

You should see a list of existing security groups. There is at least one default group already present.

Create the EC2 security group

This security group controls what traffic can reach your EC2 server. You need two inbound rules: one for SSH (so you can connect to the server) and one for port 8080 (so anyone can reach your API).

  • Click Create security group in the top right.
  • In the Security group name field, enter invoice-api-ec2-sg.
  • In the Description field, enter Security group for Invoice API EC2 instance.
  • For VPC, keep the default VPC selected.

Now add the inbound rules. Scroll down to the Inbound rules section.

  • Click Add rule.
  • Set Type to SSH.
  • Set Source to My IP. This restricts SSH access to your current IP address only.
  • Click Add rule again to add a second rule.
  • Set Type to Custom TCP.
  • Set Port range to 8080.
  • Set Source to Anywhere-IPv4 (0.0.0.0/0). This allows anyone on the internet to reach your API.
  • Leave the Outbound rules section as-is. The default allows all outbound traffic.
  • Click Create security group.

You should see a green success banner confirming the security group was created. Note the security group ID (it starts with sg-). You will need it in the next step.

Why restrict SSH to My IP?

SSH gives full command-line access to your server. Leaving it open to the entire internet (0.0.0.0/0) is a security risk because anyone could attempt to connect.

Restricting it to "My IP" means only your current network can initiate an SSH connection. If your IP changes (e.g., you switch Wi-Fi networks), you can update the rule later.

Don't see the Create security group button?

Make sure you are in the us-east-1 region. Check the region selector in the top right corner of the console. If you are in a different region, your security groups will not be in the same network as the resources you create later.

help me find the Security Groups page in the EC2 console

Create the RDS security group

This second security group protects your database. Instead of allowing traffic from the whole internet, you will only allow connections from your EC2 security group. This means only your server can reach the database.

  • Navigate back to the Security Groups list by clicking Security Groups in the left sidebar.
  • Click Create security group.
  • In the Security group name field, enter invoice-api-rds-sg.
  • In the Description field, enter Security group for Invoice API RDS database.
  • For VPC, keep the default VPC selected.

Now add the inbound rule. Scroll down to the Inbound rules section.

  • Click Add rule.
  • Set Type to PostgreSQL. This automatically fills in port 5432.
  • In the Source field, click the search box and start typing invoice-api-ec2-sg.
  • Select the invoice-api-ec2-sg security group from the dropdown. This means only resources attached to that security group can connect to the database.
  • Leave the Outbound rules section as-is.
  • Click Create security group.

You should see another green success banner. Note this security group ID as well. You will use it when creating the RDS database in the next step.

Why point the RDS source at a security group instead of an IP?

EC2 instances can change IP addresses when they restart. By referencing the EC2 security group as the source, AWS automatically allows any instance attached to that group to connect. No manual IP updates needed.

Can't find your EC2 security group in the source dropdown?

Make sure both security groups are in the same VPC. If you accidentally selected a different VPC for one of them, the other will not appear in the source dropdown.

Also confirm you are typing the name correctly: invoice-api-ec2-sg (with hyphens, not underscores).

help me set the source of my RDS security group to my EC2 security group

Your network rules are locked down. Next up, you will launch the RDS PostgreSQL database that your Spring Boot app will connect to.

Launch Your RDS Database

Your security groups are ready to go. Now it's time to create the actual database your Spring Boot app will connect to in the cloud.

RDS (Relational Database Service) is AWS's managed database offering. It handles backups, patching, and maintenance for you so you can focus on your application code instead of database administration.

In this step, get ready to:
  • Create a PostgreSQL database instance on RDS.
  • Configure the instance for minimal cost and private access.
  • Note the database endpoint address for connecting your app later.
Start creating your RDS instance

You need a PostgreSQL database running in the cloud that your EC2 instance can talk to. RDS gives you a fully managed PostgreSQL database without needing to install or maintain the database software yourself.

  • In the AWS Management Console, type RDS in the top search bar and select RDS from the results.
  • Click Create database.
  • Under Choose a database creation method, select Standard create.
  • Under Engine options, select PostgreSQL.
  • For Engine version, select the latest PostgreSQL 16.x version available in the dropdown.
  • Under Templates, select Free tier.

What if I don't see a Free tier template?

If your account uses the new AWS credit-based plan (post-July 2025), the Free tier template may not appear. Select Dev/Test instead. Your $200 in credits covers the cost of this project.

  • Under Settings, set the DB instance identifier to invoice-db.
  • Set the Master username to postgres.
  • Choose Self managed for Credentials management.
  • Enter a strong password in the Master password field and confirm it.

Save your password somewhere safe

You will need this password later to connect your Spring Boot app to the database. Write it down or save it in a password manager now. You cannot retrieve it from AWS after creation.

Configure connectivity and storage

The next section of the form controls how powerful your database is, how much storage it has, and which network resources can reach it.

  • Under Instance configuration, select db.t3.micro as the instance class.
  • Under Storage, set Allocated storage to 20 GB.
  • Set the storage type to gp2 (General Purpose SSD).
  • Under Connectivity, keep the default VPC selected (the same default VPC where your security groups live).
  • Set Public access to No.
  • Under VPC security group, choose Choose existing.
  • Remove the default security group and select invoice-api-rds-sg from the dropdown.

Why set Public access to No?

Setting Public access to No means the database has no public IP address. The only way to reach it is from within the same VPC. Combined with the invoice-api-rds-sg security group (which only allows traffic from your EC2 security group), this ensures only your EC2 instance can connect to the database.

  • Leave all other settings at their defaults.
  • Scroll to the bottom and click Create database.
Get your database endpoint

RDS provisioning takes 5-10 minutes. The console shows your database status as Creating while it sets everything up.

  • On the RDS Databases page, wait for the status of invoice-db to change from Creating to Available.
  • Click on invoice-db to open its detail page.
  • Select the Connectivity & security tab.
  • Find the Endpoint field and copy the full address.

Your endpoint looks something like invoice-db.xxxxxxxxxx.us-east-1.rds.amazonaws.com. Save this somewhere accessible. You will need it when you deploy your application to EC2.

What is this endpoint?

The endpoint is the hostname your Spring Boot app uses to find the database on the network. It replaces localhost in your database connection string. Your app will connect to jdbc:postgresql://<endpoint>:5432/postgres instead of the local PostgreSQL URL you use in development.

Database still showing Creating after 10 minutes?

RDS provisioning can occasionally take up to 15 minutes. Try clicking the refresh icon in the top-right of the Databases list. If the status shows Failed, delete the instance and re-create it. Double-check that you selected the default VPC and the invoice-api-rds-sg security group.

Help me troubleshoot my RDS instance creation

Your managed database is live and locked down. Next up, you'll launch an EC2 instance, install Java on it, and prepare the server that will run your Spring Boot application.

Launch Your EC2 Instance and Install Java

Your database is live and waiting for connections. Now you need a server to actually run your Spring Boot application.

In this step, you will launch an EC2 instance (a virtual server in AWS), connect to it remotely using SSH, and install Java so the server can run your JAR file.

In this step, get ready to:
  • Launch an EC2 instance with Amazon Linux 2023.
  • Connect to the instance via SSH from your terminal.
  • Install Java 17 (Amazon Corretto) on the instance.
Launch the EC2 instance

An EC2 instance is a virtual machine that runs in AWS. You will configure it with a lightweight operating system and attach the security group you created earlier so your API traffic can reach it.

  • In the AWS Management Console, type EC2 in the top search bar and select EC2.
  • Click Launch instance (the orange button near the top of the page).

The Launch an instance wizard opens with several configuration sections.

  • Under Name and tags, enter invoice-api-server.
  • Under Application and OS Images, confirm that Amazon Linux 2023 AMI is selected (it is the default).
  • Under Instance type, select t3.micro from the dropdown.

Why t3.micro?

The t3.micro instance gives you 2 vCPUs and 1 GB of RAM. That is enough to run a Spring Boot application with low traffic, and the cost is covered by your AWS credits.

Next, you will create a key pair. This generates a private key file that acts like a password for SSH access to your instance.

  • Under Key pair (login), click Create new key pair.
  • Enter invoice-api-key as the key pair name.
  • Select RSA for the key pair type.
  • Select .pem for the private key file format.
  • Click Create key pair.

Your browser automatically downloads a file called invoice-api-key.pem. Keep this file safe. You cannot download it again.

  • Under Network settings, click Edit.
  • Select Select existing security group.
  • From the Common security groups dropdown, choose invoice-api-ec2-sg.
  • Leave all other settings at their defaults.
  • Click Launch instance at the bottom of the page.

You should see a success banner confirming that your instance is launching.

  • Click View all instances to go to the Instances page.
  • Wait for the Instance state column to show Running (this takes about 30 seconds).
  • Click on your invoice-api-server instance to open its details.
  • Find the Public IPv4 address field and copy the IP address. You will use this to connect via SSH.

Now move the downloaded key file to a safe location on your Mac. Open your terminal to do this.

  • Create the ~/.ssh directory (if it does not already exist) and move the key file there by running these commands:
mkdir -p ~/.ssh
mv ~/Downloads/invoice-api-key.pem ~/.ssh/

What do these commands do?

  • mkdir -p ~/.ssh creates the hidden .ssh folder in your home directory. The -p flag means it will not error if the folder already exists.
  • mv ~/Downloads/invoice-api-key.pem ~/.ssh/ moves the key file from your Downloads folder into ~/.ssh/ where SSH tools expect to find key files.
  • Confirm the file was moved by running:
ls ~/.ssh/invoice-api-key.pem

You should see the file path printed back. If you see "No such file or directory", check that the filename in your Downloads folder matches exactly.

File not found in Downloads?

Your browser may have saved the file with a different name (e.g. invoice-api-key.pem (1) if you downloaded it more than once). Check your Downloads folder for the exact filename and adjust the mv command accordingly.

help me find my downloaded .pem key file

Connect to your instance via SSH

SSH lets you open a remote terminal session on your EC2 instance. Before connecting, you need to restrict the key file permissions so only you can read it.

  • Lock down the key file permissions by running this command:
chmod 400 ~/.ssh/invoice-api-key.pem

Why chmod 400?

SSH refuses to use a key file that other users on your machine could read. The 400 permission makes the file read-only for you and invisible to everyone else.

  • Connect to your EC2 instance by running this command:
ssh -i ~/.ssh/invoice-api-key.pem ec2-user@[[EC2_PUBLIC_IP="your EC2 public IPv4 address"]]

What does this command do?

  • -i ~/.ssh/invoice-api-key.pem tells SSH which private key to use for authentication.
  • ec2-user is the default username on Amazon Linux instances.
  • The IP address after @ is your instance's public address that you copied from the console.

SSH will ask you to confirm the server's fingerprint the first time you connect. This is expected.

  • Type yes and press Enter when prompted.

You should see a welcome message and a prompt that looks like [ec2-user@ip-xxx-xxx-xxx-xxx ~]$. You are now running commands directly on your cloud server.

Connection timed out or refused?

Double-check that your EC2 instance state is Running in the console. Also verify that the invoice-api-ec2-sg security group has an inbound rule for SSH (port 22) from your IP address. If your IP has changed since you created the rule, update it.

help me troubleshoot my SSH connection to EC2

Install Java on the EC2 instance

Your Spring Boot JAR needs a Java runtime to execute. Amazon Linux 2023 does not come with Java pre-installed, so you will install Amazon Corretto 17, which is Amazon's production-ready distribution of OpenJDK.

  • In your SSH session (not your local terminal), install Java 17 by running this command:
sudo dnf install java-17-amazon-corretto -y

What does this command do?

  • sudo runs the command with administrator privileges.
  • dnf is the package manager on Amazon Linux 2023 (similar to apt on Ubuntu or brew on macOS).
  • The -y flag automatically confirms the installation without prompting.
  • Verify that Java is installed by running:
java -version

You should see output that includes openjdk version "17 followed by the full version number. This confirms your server can run Spring Boot applications.

Seeing "command not found" after install?

Make sure you are running java -version in the SSH session on your EC2 instance, not in your local terminal. Your local machine and the EC2 instance are separate computers with separate software.

help me verify my Java installation on EC2

Your cloud server is up, connected, and ready to run Java applications. Next up, you will upload your JAR file and launch your API for the world to see.

Deploy and Test Your Application

Your EC2 instance has Java installed and your RDS database is ready for connections. Now it's time to bring everything together and get your API live on the internet.

You'll upload your packaged Spring Boot application to EC2 and connect it to your RDS database. Once running, anyone on the internet will be able to hit your API endpoints.

In this step, get ready to:
  • Upload your Spring Boot JAR file to the EC2 instance.
  • Configure database environment variables and start the application.
  • Test your live API endpoints from your local machine.
Upload the JAR to EC2

Your JAR file lives on your Mac, but it needs to run on your EC2 instance in the cloud. SCP (Secure Copy Protocol) lets you transfer files securely over your existing SSH connection.

  • Open a NEW Terminal window on your local Mac (not the SSH session).
  • Make sure you're in your Spring Boot project directory where the target/ folder exists.
  • Upload your JAR file to EC2 by running this command:
scp -i ~/.ssh/invoice-api-key.pem target/[[JAR_FILENAME="your-app-0.0.1-SNAPSHOT.jar"]] ec2-user@[[EC2_PUBLIC_IP="your EC2 public IPv4 address"]]:/home/ec2-user/

What does this command do?

  • scp copies files securely over SSH.
  • -i ~/.ssh/invoice-api-key.pem authenticates using your EC2 key pair.
  • target/<filename> is the source JAR file on your Mac.
  • ec2-user@<IP>:/home/ec2-user/ is the destination path on your EC2 instance.
  • Switch to your SSH session on EC2.
  • Confirm the file arrived by running:
ls /home/ec2-user/*.jar

You should see your JAR filename listed in the output.

Upload failed or permission denied?

  • Make sure you're running scp from your LOCAL Terminal, not from inside the SSH session.
  • Confirm you're in your Spring Boot project directory where the target/ folder exists. Run ls target/*.jar locally to verify.
  • Double-check that your EC2 instance's public IP matches what's shown in the AWS Console under Instances.

Why is my SCP upload failing?

Set environment variables and start the application

Your Spring Boot app reads database connection details from environment variables (configured in Step 2). You need to set these on EC2 so the application knows where to find your RDS database.

  • In your SSH session on EC2, set the database connection variables by running these commands:
export DB_HOST=[[RDS_ENDPOINT="invoice-db.xxxxxxxxxx.us-east-1.rds.amazonaws.com"]]
export DB_NAME=postgres
export DB_USER=postgres
export DB_PASSWORD=your-rds-password

What do these variables do?

  • DB_HOST points to your RDS endpoint from Step 4 (find it on the Connectivity & security tab in the RDS console).
  • DB_NAME is the default postgres database that RDS creates automatically.
  • DB_USER is the master username you set during RDS creation.
  • DB_PASSWORD is the password you chose when creating the RDS instance.
  • Replace your-rds-password with the password you set when creating your RDS instance in Step 4.
  • Start your Spring Boot application in the background by running this command:
nohup java -Xmx512m -jar [[JAR_FILENAME="your-app-0.0.1-SNAPSHOT.jar"]] > app.log 2>&1 &

What does this command do?

  • nohup keeps the process running even after you close your SSH session.
  • -Xmx512m limits Java's memory usage to 512 MB. This leaves room for the operating system on the 1 GB t3.micro instance.
  • > app.log 2>&1 redirects all output (including errors) to a log file you can check later.
  • & runs the process in the background so you get your terminal back.
  • Wait about 15-20 seconds for Spring Boot to start up.
  • Check that the application started successfully by running:
cat app.log

You should see Spring Boot's startup banner and a line like Started Application in X.XXX seconds. This confirms your app is running and connected to the database.

Seeing connection refused or database errors in the log?

  • Verify your DB_HOST matches the exact RDS endpoint from the AWS Console (Connectivity & security tab on your RDS instance page).
  • Confirm the RDS instance status is Available in the RDS dashboard.
  • Check that invoice-api-rds-sg has an inbound rule for port 5432 with the source set to the invoice-api-ec2-sg security group ID.
  • Re-run your export commands if you disconnected and reconnected to SSH. Environment variables are lost when you close a session.

Why can't my Spring Boot app connect to RDS?

Test your live API from your local machine

Your application is running on EC2 and port 8080 is open to the internet via your Security Group. Time to confirm everything works end-to-end from your local machine.

  • Open a Terminal window on your local Mac (not the SSH session).
  • Test that your API is reachable by running:
curl http://[[EC2_PUBLIC_IP="your EC2 public IPv4 address"]]:8080

What should I see?

If your API has a root endpoint, you'll see its JSON response. If your API only responds on specific paths (like /api/invoices), you'll see a Spring Boot Whitelabel error page or a 404 response. That's normal.

The important thing is that you got a response from the server at all. Any response (even a 404) means your EC2 instance is reachable on port 8080.

  • Now test one of your actual API endpoints by running:
curl http://[[EC2_PUBLIC_IP="your EC2 public IPv4 address"]]:8080/api/invoices
  • Replace /api/invoices with one of the endpoints from your Invoice Processing Service that you know works locally.

You should see the same JSON response you get when running the application on your local machine. Your API is now live on the internet.

Not getting a response?

  • Verify the EC2 instance's public IP in the AWS Console matches what you're using in the curl command.
  • Check that invoice-api-ec2-sg has an inbound rule allowing port 8080 from 0.0.0.0/0.
  • SSH back into EC2 and run cat app.log to check for application errors.
  • If the app crashed, re-export your environment variables and restart with the nohup java command from the previous substep.

Why can't I reach my EC2 instance on port 8080?

Secret mission

Add HTTPS with Nginx and Let's Encrypt

Your API is live, but it runs over plain HTTP. Any frontend app trying to connect from an HTTPS domain will be blocked by browser security policies. In this secret mission, you will add a secure HTTPS layer using Nginx as a reverse proxy and a free SSL certificate from Let's Encrypt.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to save credits, or delete them entirely.

This project uses AWS resources that deduct from your $200 credit balance while running.

Cost warning

Your EC2 and RDS instances together cost approximately $22/month if left running 24/7. This is deducted from your $200 AWS credits.

If you are not actively using the API, stop or delete your instances to conserve credits.

Resources you used:

  • 1 EC2 instance (t3.micro) running your Spring Boot application.
  • 1 RDS PostgreSQL instance (db.t3.micro, 20 GB storage) hosting your database.
  • 2 Security Groups (invoice-api-ec2-sg and invoice-api-rds-sg) controlling network access.
  • 1 Key Pair (invoice-api-key) for SSH access to EC2.

Keep everything running

No action needed. Choose this if you are still actively building or testing your API.

  • Your API stays live at your EC2 public IP on port 8080.
  • Both instances together cost roughly $22/month, deducted from your $200 credits.
  • At this rate, you have enough credits to run for several months before they run out.

Pause - I'll come back to this later

Stop your instances to conserve credits while keeping all your data and configuration intact.

  • In the AWS Console, go to EC2 > Instances.
  • Select your invoice-api-server instance, click Instance state, then Stop instance.
  • Go to RDS > Databases.
  • Select invoice-db, click Actions, then Stop temporarily.
  • Stopped instances only incur minimal storage costs (approximately $2/month for EBS and RDS storage combined).
  • When you are ready to resume, start both instances from the same menus. Note that your EC2 public IP will change after a stop/start cycle.

Delete - I don't want to use this again

Remove all project resources and stop all charges immediately.

  • Go to EC2 > Instances. Select invoice-api-server, click Instance state, then Terminate instance.
  • Go to RDS > Databases. Select invoice-db, click Actions, then Delete. Uncheck Create final snapshot and confirm deletion.
  • Go to EC2 > Security Groups. Delete invoice-api-rds-sg first (since it has no dependencies), then delete invoice-api-ec2-sg.
  • Go to EC2 > Key Pairs. Select invoice-api-key and click Actions > Delete.
  • Delete the invoice-api-key.pem file from your local ~/.ssh/ directory.

That's a Wrap!

That's a Wrap!

You just deployed a Spring Boot REST API to AWS. Your application is live on the internet, backed by a managed PostgreSQL database, and secured with proper network controls.

Here's what you accomplished:

  • Deployed a Spring Boot REST API to an EC2 instance accessible from the public internet.
  • Launched a managed PostgreSQL database on RDS with Security Groups restricting database access to only your EC2 instance.
  • Built, uploaded, and ran your application JAR in the cloud, connecting it to RDS using environment variables.
  • Secret Mission: Added HTTPS to your API using Nginx as a reverse proxy and a free SSL certificate from Let's Encrypt.

Ready to quiz yourself?