Deploying / Hosting Spring Boot applications on AWS using Elastic beanstalk for Free

AWS (Amazon Web Services) is the most widely used cloud computing platform all over the world. It provides a whole range of managed cloud services from S3 (Simple Storage Service) to Machine Learning to IOT.

In this article, you’ll learn how to deploy a Spring Boot application on AWS using Elastic beanstalk for free.

AWS comes with a free tier that lets new users experiment with its services for free for 1 year.

Every AWS resource that we’ll create in this article is eligible for AWS free tier. So you can confidently work with me step by step without worrying about pricing.

AWS free tier Before proceeding to the next section, go ahead and sign up for AWS free tier. AWS will ask for your credit card information during the sign up process.

But don’t worry, they won’t charge anything unless you exceed the free tier limit. Also, you can delete your AWS account any time if you no longer need it.

Downloading the application to deploy on AWS

In this article, we’ll deploy a Spring boot and MySQL based Note-Taking application.

You can download the app from Github -

$ git clone https://github.com/callicoder/spring-boot-mysql-rest-api-tutorial.git

There is also a tutorial on this blog that teaches you how to build this app from scratch.

I’ve chosen this app for deployment on AWS because It contains a Rest service as well as a database. So you can understand how to deploy a real-world app on AWS instead of some simple Hello World app.

Installing Elastic Beanstalk Command Line Interface (EB CLI)

Elastic Beanstalk CLI is a command line interface that lets you create, update and monitor Elastic Beanstalk environments, and deploy applications right from the terminal.

You can install Elastic Beanstalk CLI using Python’s Package management system, PIP. It comes bundled with Python version 3.x.x.

If Python 3.x.x is not installed in your system, then you can download and install it from Python’s download page.

You can check the current version of python and pip using the following commands -

$ python --version
Python 3.6.4
$ pip --version
pip 9.0.1 from /Users/rajeevkumarsingh/anaconda3/lib/python3.6/site-packages (python 3.6)

Now, To install EB CLI using pip, Type the following command in your terminal -

$ pip install awsebcli --upgrade

Initializing Elastic Beanstalk CLI and Creating an application

Let’s initialize our project with EB CLI and create an application. Fire up your terminal and go to the root directory of the project that you downloaded from Github in the previous section.

After that, type the following command to initialize the Elastic beanstalk CLI -

$ eb init

Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-south-1 : Asia Pacific (Mumbai)
7) ap-southeast-1 : Asia Pacific (Singapore)
8) ap-southeast-2 : Asia Pacific (Sydney)
9) ap-northeast-1 : Asia Pacific (Tokyo)
10) ap-northeast-2 : Asia Pacific (Seoul)
11) sa-east-1 : South America (Sao Paulo)
12) cn-north-1 : China (Beijing)
13) us-east-2 : US East (Ohio)
14) ca-central-1 : Canada (Central)
15) eu-west-2 : EU (London)
(default is 3):

The default AWS region is 3. Let’s work with the default for now. Press enter to proceed to the next step -

You have not yet set up your credentials or your credentials are incorrect
You must provide your credentials.
(aws-access-id): <YOUR_AWS_ACCESS_ID>
(aws-secret-key): <YOUR_AWS_SECRET_KEY>

You need to enter your AWS AccessId and SecretKey. You can find them on your AWS Account.

The EB CLI creates a config file inside a hidden folder named .aws in your home directory, and stores the ACCESS_ID and SECRET_KEY in this file -

$ ls ~/.aws/config

When you initialize an application next time, the CLI will directly use the credentials stored in the above config file instead of asking for them.

All right! So after entering the ACCESS_ID and SECRET_KEY, the EB CLI will display the following prompt:

Select an application to use
1) [ Create new Application ]
(default is 1):

Press enter to select the default option - Create new Application. You’ll then be asked to enter the application name -

Enter Application Name
(default is "spring-boot-mysql-rest-api-tutorial"): spring-boot-app

The default application name is the name of the current directory. Let’s change the application name to spring-boot-app and press enter.

You’ll now see the following

Application spring-boot-app has been created.

Select a platform.
1) Node.js
2) PHP
3) Python
4) Ruby
5) Tomcat
6) IIS
7) Docker
8) Multi-container Docker
9) GlassFish
10) Go
11) Java
12) Packer
(default is 1): 11

Type 11 to select Java and press enter -

Select a platform version.
1) Java 8
2) Java 7
(default is 1): 1

Enter 1 to select Java 8. You’ll get the following prompt after that -

Note: Elastic Beanstalk now supports AWS CodeCommit; a fully-managed source control service. To learn more, see Docs: https://aws.amazon.com/codecommit/
Do you wish to continue with CodeCommit? (y/N) (default is n):

We don’t want to use CodeCommit, so just press enter to continue. You’ll now get the following prompt -

Do you want to set up SSH for your instances?
(Y/n): Y

We might need to login to our EC2 instances. Let’s type Y to proceed with SSH setup.

Select a keypair.
1) [ Create new KeyPair ]
(default is 1): 1

Enter 1 to create a new SSH KeyPair -

Type a keypair name.
(Default is aws-eb): spring-boot-app-key

After entering the keypair name, You’ll get the following prompt.

Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

Type a passphrase or press enter for no passphrase.

Configuring the deployment of our Spring Boot application

After completing the above steps, Elastic beanstalk will create a configuration file in your project directory at the path .elasticbeanstalk/config.yml.

We need to configure elastic beanstalk to deploy our application as a packaged jar. Open .elasticbeanstalk/config.yml file and add a deploy config like so -

branch-defaults:
  master:
    environment: null
## Add the following deploy configuration    
deploy:
  artifact: target/easy-notes-1.0.0.jar
global:
  application_name: spring-boot-app
  branch: null
  default_ec2_keyname: spring-boot-app-key
  default_platform: Java 8
  default_region: us-west-2
  include_git_submodules: true
  instance_profile: null
  platform_name: null
  platform_version: null
  profile: eb-cli
  repository: null
  sc: git
  workspace_type: Application

The easy-notes-1.0.0.jar is the artifact name of our application. It is created in the target folder when you package your application.

Let’s package the application by typing the following command -

$ mvn clean package

It will create the artifact in the target folder -

$ ls target/easy-notes-1.0.0.jar
target/easy-notes-1.0.0.jar

Creating an Elastic Beanstalk Environment with an RDS database

An elastic beanstalk application can have multiple environments (e.g. staging, QA, prod).

Type the following command to create an Elastic beanstalk environment with a single EC2 instance and an RDS database -

$ eb create --single --database
Enter Environment Name
(default is spring-boot-app-dev):

The --single option is important. It tells EB CLI to create a single instance for running our application. Otherwise, Elastic beanstalk will create multiple instances with a load balancer. And that will cost you money :-)

The next prompt will display the following -

Enter DNS CNAME prefix
(default is spring-boot-app-dev):

Just press enter and proceed -

Enter an RDS DB username (default is "ebroot"): boot
Enter an RDS DB master password:
Retype password to confirm:

Enter a username and password for your RDS database in the above prompt.

EB CLI will now create your environment and display several logs like so -

Creating application version archive "app-41fb-180716_173651".
Uploading spring-boot-app/app-41fb-180716_173651.zip to S3. This may take a while.
Upload Complete.
Environment details for: spring-boot-app-dev
  Application name: spring-boot-app
  Region: us-west-2
  Deployed Version: app-41fb-180716_173651
  Environment ID: e-grmpd336k2
  Platform: arn:aws:elasticbeanstalk:us-west-2::platform/Java 8 running on 64bit Amazon Linux/2.7.2
  Tier: WebServer-Standard-1.0
  CNAME: spring-boot-app-dev.us-west-2.elasticbeanstalk.com
  Updated: 2018-07-16 12:07:06.528000+00:00
Printing Status:
INFO: createEnvironment is starting.
INFO: Using elasticbeanstalk-us-west-2-120931462184 as Amazon S3 storage bucket for environment data.
INFO: Created security group named: awseb-e-grmpd336k2-stack-AWSEBSecurityGroup-OR643345R86B
INFO: Creating RDS database named: aaf16jegytegm5. This may take a few minutes.
INFO: Created EIP: 34.217.199.203 
 -- Events -- (safe to Ctrl+C)

The above process will take several minutes to complete. You can press Ctrl+C to quit, and check the current status of the environment by typing the following command -

$ eb status
Environment details for: spring-boot-app-dev
  Application name: spring-boot-app
  Region: us-west-2
  Deployed Version: None
  Environment ID: e-gm9sm7bvhr
  Platform: arn:aws:elasticbeanstalk:us-west-2::platform/Java 8 running on 64bit Amazon Linux/2.7.2
  Tier: WebServer-Standard-1.0
  CNAME: spring-boot-app-dev.us-west-2.elasticbeanstalk.com
  Updated: 2018-07-17 09:56:00.930000+00:00
  Status: Launching
  Health: Grey

The Status is Launching and Health is Grey. You can also type eb console command to open the elastic beanstalk console in your default web browser and check the progress from there.

Once the Status is Ready and Health turns Green, you can type eb logs to retrieve the application logs -

$ eb logs

The application logs will display the following error -

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.

That’s because we didn’t configure Spring Boot to connect to the RDS database. It’s still trying to connect to a localhost mysql database. Let’s configure that now.

Configuring Environment properties for RDS database

Let’s first find out the RDS database endpoint. Open the Elastic beanstalk console by typing the following command -

$ eb console

Spring Boot AWS Deployment RDS database configuration The database endpoint is displayed in the Database section in your elastic beanstalk console configurations page.

You can now set the database URL, username and password in the elastic beanstalk environment like this -

$ eb setenv SPRING_DATASOURCE_URL=jdbc:mysql://aacbxdecop2bv.cmhzbwstuj3x.us-west-2.rds.amazonaws.com:3306/ebdb SPRING_DATASOURCE_USERNAME=boot SPRING_DATASOURCE_PASSWORD=<YOUR_PASSWORD>

That’s it! The environment will update and the application will start on port 8080. You should see the following in web logs section of the eb logs response -

2018-07-17 11:01:55.124  INFO 9690 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-07-17 11:01:55.128  INFO 9690 --- [           main] c.e.easynotes.EasyNotesApplication       : Started EasyNotesApplication in 11.386 seconds (JVM running for 12.612)

Let’s open the application in the web browser by typing the following command -

$ eb open

The application will open in your default browser and display a 502 Bad Gateway error. Why you ask?

Well, Let’s check the logs again. Specially the logs titled /var/log/nginx/error.log -

type: post
-------------------------------------
/var/log/nginx/error.log
type: post
-------------------------------------
2018/07/17 10:24:16 [error] 3254#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 131.221.192.25, server: , request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:5000/", host: "34.218.27.206:80"
2018/07/17 11:11:35 [error] 9673#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 79.132.201.115, server: , request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:5000/", host: "34.218.27.206:80"

Your application runs behind an Nginx proxy server, and the Nginx server expects your application to run on port 5000 by default.

Configuring Spring Boot application PORT

There are two ways to configure your spring boot application to run on the default port 5000 expected by elastic beanstalk.

1. Set server.port property

Note that, Elastic beanstalk passes the port through a PORT environment variable. To listen on this port, add the following property to your src/main/resources/application.properties file -

# Listen on the port passed through `PORT` environment variable (Fallback to 8080)
server.port=${PORT:8080}

After setting the above property, you’ll need to package the application again with mvn clean package command. Once the application is packaged, type the following command to deploy it -

$ eb deploy

2. Set SERVER_PORT environment variable

You can also set an environment variable called SERVER_PORT to run the spring boot application on that port -

$ eb setenv SERVER_PORT=5000

Congratulations! The Application is Deployed

Our application is now deployed on AWS. You can type the following command to open it in your default browser -

$ eb open

You can explore various REST APIs exposed by the application. Check out the Github Readme to know more about those APIs.