How to Deploy a Spring Boot and Vue Application on AWS EC2 Using Docker
Intro
To develop a single-page application, Spring Boot and Vue can be a good choice. When you finished the development stage, it is time to deploy the app online.
Traditionally, you may need to write scripts to start your java service, and you need to do a lot of configuration for the Nginx server.
To make the process easier and more efficient, I would recommend using Docker to deploy the app. You may find it a little bit difficult to learn at the beginning, but you will benefit from the learning since Docker could help you a lot.
Install Docker in AWS EC2 instance
Once you have created an AWS EC2 instance, you need to install Docker in the instance. I have written a post about this process, you may check it: https://williamyuaus.com/2021/07/how-to-install-docker-in-aws-ec2-instances/
Deploy the back-end service
Compile and build the JAR file
Firstly, you should compile and build the JAR file for your Spring Boot project. You may need to change the production configuration settings first. After you have done this, you can follow similar steps to get the JAR file.
Upload the JAR file to the server
Next, you need to upload the JAR file to the server. I would use /home/ec2-user/
as my working directory. So, you may need to create a new directory \eladmin
and use scp server to transfer the JAR file from your local computer to the server.
The command for creating the directory is mkdir eladmin
. The command for scp server to transfer the JAR file is:
scp -r -i /Users/willyu/dev/deploy/college-system-keys.cer /Users/willyu/dev/deploy/eladmin-system-2.6.jar ec2-user@IP:/home/ec2-user/eladmin
Fix Permissions 0644 error
You may get Permissions 0644 error when you were trying to use scp command. It is because the private key cannot be accessed by others. The full error message is showing like this:
To fix this issue, you need to give the permission to write and read the file with this command:
sudo chmod 600 /Users/****.cer
Then, the password is required and you will solve the issue.
Build the Docker image for the Java service
To create the Docker image for the Java service, you need to create a Dockerfile for the image. The file should be named as Dockerfile without any extension. The content of the file is:
FROM java:8
ARG JAR_FILE=./*.jar
COPY ${JAR_FILE} app.jar
ENV TZ=Australia/Melbourne
ENTRYPOINT ["java","-jar","/app.jar"]
The file should be uploaded to the same directory with the JAR file in /home/ec2-user/eladmin/
.
Then, you need to create the image using the command:
docker build -t eladmin .
Start the container for back-end service
Before starting the back-end service container, you may need to install and run redis in the Docker.
docker run -itd --name redis --restart=always -p 6379:6379 redis
Now, you can use the following command to run the container back-end server.
docker run -d \
--name eladmin --restart always \
-p 8000:8000 \
-e "TZ=Australia/Melbourne" \
-e REDIS_HOST=172.17.0.1 \
-v /home/ec2-user/data/:/home/eladmin/ \
eladmin
You can test your back-end service in the browser or postman.
Deploy the front-end service
Prepare for the Nginx
To deploy the front-end service, we use Nginx as the web server. Firstly, we need to create some directories for Nginx.
- /home/ec2-user/nginx/conf.d is for configuration files;
- /home/ec2-user/nginx/cert is for storing SSL certificate;
- /home/ec2-user/nginx/html is for storing website files;
- /home/ec2-user/nginx/logs if for storing logs.
- /home/ec2-user/nginx.conf is the default Nginx configuration file.
The default Nginx configuration file is defined as below:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
client_max_body_size 100M;
include /etc/nginx/conf.d/*.conf;
}
Then, we need to define the custom configuration file for the reverse proxy. So, we need to create a file named eladmin.conf
in the /home/ec2-user/nginx/conf.d
directory. The content of the file is:
server
{
listen 80;
server_name domain/IP;
index index.html;
root /usr/share/nginx/html/eladmin/dist; #dist upload directory
client_max_body_size 800M;
# avoid 404 error
location / {
try_files $uri $uri/ @router;
index index.html;
}
location @router {
rewrite ^.*$ /index.html last;
}
# socket
location /api {
proxy_pass http://172.17.0.1:8000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# auth socket
location /auth {
proxy_pass http://172.17.0.1:8000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# WebSocket service
location /webSocket {
proxy_pass http://172.17.0.1:8000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# avatar
location /avatar {
proxy_pass http://172.17.0.1:8000;
}
# files
location /file {
proxy_pass http://172.17.0.1:8000;
}
}
Build the production files for the front-end project
After the preparation for the Nginx server, we need to build the production files for the front-end project. We use this command to build the production files:
npm run build:prod
When the building process is finished, you will get the production files in the dist
folder as below.
Upload the front-end project files
Since the directory in container /usr/share/nginx/html/eladmin/dist
is binding with the directory /home/ec2-user/nginx/html
in the host server. Therefore, we should upload the front-end project files to this directory.
We can use the scp server to upload the production files to the directory.
Install and start the Nginx container in Docker
Now, everything is ready. It is time to install the Nginx container in Docker with the commands:
docker run -d \
--name nginx --restart always \
-p 80:80 -p 443:443 \
-e "TZ=Australia/Melbourne" \
-v /home/ec2-user/nginx/nginx.conf:/etc/nginx/nginx.conf \
-v /home/ec2-user/nginx/conf.d:/etc/nginx/conf.d \
-v /home/ec2-user/nginx/logs:/var/log/nginx \
-v /home/ec2-user/nginx/cert:/etc/nginx/cert \
-v /home/ec2-user/nginx/html:/usr/share/nginx/html \
nginx:alpine
Then, start the Nginx server in Docker with the command:
docker start nginx
Congurationlations, you finished all the steps of deployment for the Spring Boot and Vue app in the AWS EC2 instance with Docker.
Enjoy!