How to deploy Java on Amazon EC2 (Spring Boot edition)

java ec2 deployment

Using Azure to deploy your Java projects is expensive and time consuming. Let’s learn how to deploy a Java Spring Boot web server to Amazon EC2.

This will cost you just $3 / month. With Azure, you don’t even know how much it is going to cost you.

Example Spring Boot project

In this tutorial, we are focusing on deploying our Java Spring Boot server to Amazon EC2 - so we are not going to learn how to build a Spring Boot web service from scratch.

If you don’t have an existing project, you can clone our example repository from GitHub.

Launch an Amazon Linux EC2 instance

First, go to AWS Console for EC2 and select Amazon Linux 2023 AMI and 64-bit (Arm) Architecture.

In the instance type you can select whatever you want. Here I am going with the cheapest instance, which is t4g.nano which will give us 2vCPU and 512 MiB of RAM.

This t4g.nano instance will cost you just $3/month in us-east-1 . Breakdown of On-Demand Linux base pricing:

= $0.0042 / hour = $0.0042 * 24 / day = $0.0042 * 24 * 30 / month = $3.024 / month 

EC2 console showing t4g nano instance selected

EC2 key pair login

In Key pair select or create a new SSH key pair for your instance. We will need this to login.

In the Network section allow HTTP and HTTPS traffic, you can also select existing security group as well.

AWS security group config with http and ssh port enabled

default EC2 instance storage config

Now Launch instance with the default storage config by clicking on Launch instance on the bottom right.

EC2 launched successful notification in AWS console

Our EC2 instance was created with this success message: Successfully initiated launch of instance (i-xxxx)

Connect to EC2 instance via SSH

AWS EC2 instance public IP address to login via SSH

Go to your instance, find and copy the public IP by selecting the instance:

Use the SSH command with IP

We will be using rsync , so it’s best to connect using the terminal.

Alternatively, you can use the connect button to directly get the command or connect to EC2 from the browser itself.

Amazon EC2 connect helper to connect to EC2

The default username for Amazon Linux EC2 instance is ec2-user .

ssh -i your-key.pem ec2-user@your-ip-address 

ssh connection asking for fingerprint for the first time

Type yes and save the fingerprint:

On successful login you’ll see the Amazon Linux logo:

 , #_  ~\_ ####_ Amazon Linux 2023  ~~ \_#####\  ~~ \###|  ~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023  ~~ V~' '->  ~~~ /  ~~._. _/  _/ _/  _/m/' Last login: Mon Jun 3 13:15:51 2024 from 46.36.xxx.53 [ec2-user@ip-172-31-xx-82 ~]$ 

Install Java 17 on Amazon Linux

All you need to do is use yum to install the headless java-17 :

sudo yum install java-17-amazon-corretto-headless 

Type y and hit enter to install Java on your EC2 instance:

[ec2-user@ip-172-31-19-82 ~]$ sudo yum install java-17-amazon-corretto-headless Last metadata expiration check: 1 day, 17:42:09 ago on Tue Jun 18 04:50:04 2024. Dependencies resolved. ==============================================================================================================================================================================  Package Architecture Version Repository Size ============================================================================================================================================================================== Installing:  java-17-amazon-corretto-headless aarch64 1:17.0.11+9-1.amzn2023.1 amazonlinux 91 M Installing dependencies:  alsa-lib aarch64 1.2.7.2-1.amzn2023.0.2 amazonlinux 492 k  cairo aarch64 1.17.6-2.amzn2023.0.1 amazonlinux 669 k  dejavu-sans-fonts noarch 2.37-16.amzn2023.0.2 amazonlinux 1.3 M  dejavu-sans-mono-fonts noarch 2.37-16.amzn2023.0.2 amazonlinux 467 k  dejavu-serif-fonts noarch 2.37-16.amzn2023.0.2 amazonlinux 1.0 M  fontconfig aarch64 2.13.94-2.amzn2023.0.2 amazonlinux 278 k  fonts-filesystem noarch 1:2.0.5-12.amzn2023.0.2 amazonlinux 9.5 k  freetype aarch64 2.13.0-2.amzn2023.0.1 amazonlinux 412 k  google-noto-fonts-common noarch 20201206-2.amzn2023.0.2 amazonlinux 15 k  google-noto-sans-vf-fonts noarch 20201206-2.amzn2023.0.2 amazonlinux 492 k  graphite2 aarch64 1.3.14-7.amzn2023.0.2 amazonlinux 93 k  harfbuzz aarch64 7.0.0-2.amzn2023.0.1 amazonlinux 843 k  javapackages-filesystem noarch 6.0.0-7.amzn2023.0.6 amazonlinux 12 k  langpacks-core-font-en noarch 3.0-21.amzn2023.0.4 amazonlinux 10 k  libX11 aarch64 1.7.2-3.amzn2023.0.4 amazonlinux 648 k  libX11-common noarch 1.7.2-3.amzn2023.0.4 amazonlinux 152 k  libXau aarch64 1.0.9-6.amzn2023.0.2 amazonlinux 32 k  libXext aarch64 1.3.4-6.amzn2023.0.2 amazonlinux 40 k  libXrender aarch64 0.9.10-14.amzn2023.0.2 amazonlinux 27 k  libjpeg-turbo aarch64 2.1.4-2.amzn2023.0.5 amazonlinux 191 k  libpng aarch64 2:1.6.37-10.amzn2023.0.6 amazonlinux 121 k  libxcb aarch64 1.13.1-7.amzn2023.0.2 amazonlinux 231 k  pixman aarch64 0.40.0-3.amzn2023.0.3 amazonlinux 194 k  xml-common noarch 0.6.3-56.amzn2023.0.2 amazonlinux 32 k Transaction Summary ============================================================================================================================================================================== Install 25 Packages Total download size: 98 M Installed size: 271 M Is this ok [y/N]: 

Test the installation of Java

Run java --version to find if you have installed Java and JDK correctly.

You should see something like this:

[ec2-user@ip-172-31-19-82 ~]$ java --version openjdk 17.0.11 2024-04-16 LTS OpenJDK Runtime Environment Corretto-17.0.11.9.1 (build 17.0.11+9-LTS) OpenJDK 64-Bit Server VM Corretto-17.0.11.9.1 (build 17.0.11+9-LTS, mixed mode, sharing) 

Create jar file with mvn

Just run mvn package to create the .jar file of your Java application. You’ll see two .jar files inside target directory:

├── hello-0.0.1-SNAPSHOT.jar ├── hello-0.0.1-SNAPSHOT.jar.original 

Copy .jar file to EC2 with rsync

Copy the file ending with SNAPSHOT.jar to your remote maching:

rsync target/hello-0.0.1-SNAPSHOT.jar ec2-user@your-ec2-ip-addr:~/ 

You can confirm on the EC2 machine if the jar file got transferred or not using ls :

[ec2-user@ip-172-31-xx-82 ~]$ ls hello-0.0.1-SNAPSHOT.jar 

Execute .jar file with Java

We installed Java earlier so that we can use it’s CLI to run the jar file using -jar and passing the path for the .jar file:

java -jar hello-0.0.1-SNAPSHOT.jar 

Output from the Java server

[ec2-user@ip-172-31-19-82 ~]$ java -jar hello-0.0.1-SNAPSHOT.jar  . ____ _ __ _ _  /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \  \\/ ___)| |_)| | | | | || (_| | ) ) ) )  ' |____| .__|_| |_|_| |_\__, | / / / /  =========|_|==============|___/=/_/_/_/  :: Spring Boot :: (v3.3.0) 2024-06-19T22:43:29.909Z INFO 684333 --- [hello] [ main] com.learnaws.hello.HelloApplication : Starting HelloApplication v0.0.1-SNAPSHOT using Java 17.0.11 with PID 684333 (/home/ec2-user/hello-0.0.1-SNAPSHOT.jar started by ec2-user in /home/ec2-user) 2024-06-19T22:43:29.929Z INFO 684333 --- [hello] [ main] com.learnaws.hello.HelloApplication : No active profile set, falling back to 1 default profile: "default" 2024-06-19T22:43:32.204Z INFO 684333 --- [hello] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) 2024-06-19T22:43:32.223Z INFO 684333 --- [hello] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-06-19T22:43:32.224Z INFO 684333 --- [hello] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24] 2024-06-19T22:43:32.287Z INFO 684333 --- [hello] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-06-19T22:43:32.288Z INFO 684333 --- [hello] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2209 ms 2024-06-19T22:43:33.135Z INFO 684333 --- [hello] [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint beneath base path '/actuator' 2024-06-19T22:43:33.259Z INFO 684333 --- [hello] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' 2024-06-19T22:43:33.303Z INFO 684333 --- [hello] [ main] com.learnaws.hello.HelloApplication : Started HelloApplication in 4.11 seconds (process running for 4.915) 

Enable port 8080 in EC2 security group for Spring Boot

Go to the security group attached to your EC2 instance and add port range of 8080:

AWS security group allow port 8080

Test Spring Boot server running on EC2 with IP

Java Spring Boot server preview in browser with the EC2 IP

Now we just visit the IP followed by the port ( 8080 )

Use curl to test the other path of our server

 curl 3.xx.xxx.161:8080/hello\?name=LearnAWS.io Hello LearnAWS.io! It's 2024-06-19T22:51:56.371516135Z% 

Health status with actuator

 curl 3.xx.xxx.161:8080/actuator/health "status":"UP">% 

How to setup Spring Boot for production

Set up custom domain and SSL with Caddy

  1. Point your domain to EC2 IP
  2. Install and set up Caddy as a reverse proxy
  3. Setup CDN like CloudFront or Cloudflare for caching

That’s it! You’re ready to go.

Keep the Java server running in background

On system restart and application crash we want our application to start automatically, to achieve this we can use systemd.

Create systemd service file

Create a service file in /etc/systemd/system/java-server.service using vim :

sudo vim /etc/systemd/system/java-server.service 

Press i and paste the content and save it with Esc followed by :wq .

[Unit] Description=Spring Boot Server [Service] ExecStart=java -jar /home/ec2-user/hello-0.0.1-SNAPSHOT.jar Restart=on-failure RestartSec=1s [Install] WantedBy=multi-user.target 

Enable java-server service using systemctl

Now you’ll need to reload systemd and enable the java server:

sudo systemctl daemon-reload sudo systemctl enable java-server 

Start the java-server service

sudo systemctl start java-server 

Check status with systemctl

sudo systemctl status java-server 

You’ll see something like this:

 java-server.service - Spring Boot Server  Loaded: loaded (/etc/systemd/system/java-server.service; enabled; preset: disabled)  Active: active (running) since Thu 2024-06-20 15:58:30 UTC; 53s ago  Main PID: 712513 (java)  Tasks: 30 (limit: 406)  Memory: 140.0M  CPU: 8.844s  CGroup: /system.slice/java-server.service  └─712513 java -jar /home/ec2-user/hello-0.0.1-SNAPSHOT.jar 

Now this ensures your Java web server will keep running even when you restart your system or logout from the SSH session.