In this step, you will build and deploy the Spring Boot backend application to EC2 instances. The backend provides RESTful API for DNA analysis, user authentication, and data management.
Get RDS endpoint from CloudFormation outputs:
RDS_ENDPOINT=$(aws cloudformation describe-stacks \
--stack-name workshop-aws-dev \
--region ap-southeast-1 \
--query 'Stacks[0].Outputs[?OutputKey==`RDSEndpoint`].OutputValue' \
--output text)
echo "RDS Endpoint: $RDS_ENDPOINT"
Update file BE/workshop_BE/src/main/resources/application.properties:
# Database Configuration
spring.datasource.url=jdbc:mysql://${RDS_ENDPOINT}:3306/workshop_aws?useSSL=true&requireSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Ho_Chi_Minh
spring.datasource.username=admin
spring.datasource.password=YourStrongPassword123!
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Connection Pool
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=20000
# JPA Configuration
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
# Server Configuration
server.port=8080
server.servlet.context-path=/dna_service
# JWT Configuration
jwt.signerKey=2VJ50pdhYm96e4VECp/vsZGVmkSl9xp1rSYAZKsZL7n9Ti1pZYle3k9mheQEKt6+
jwt.expiration=86400000
# CORS Configuration
cors.allowed.origins=*
# Logging
logging.level.root=INFO
logging.level.aws_project.workshop=DEBUG
logging.file.name=/opt/workshop/application.log
cd BE/workshop_BE
# Clean and build
mvn clean package -DskipTests
# Or use Maven Wrapper
./mvnw clean package -DskipTests
# Verify JAR file
ls -lh target/workshop-0.0.1-SNAPSHOT.jar
Expected result: JAR file approximately 50-80MB in target/ directory
Create S3 bucket for backend artifacts (if not exists):
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
BACKEND_BUCKET="workshop-aws-dev-backend-${ACCOUNT_ID}-ap-southeast-1"
# Create bucket
aws s3 mb s3://${BACKEND_BUCKET} --region ap-southeast-1
# Upload JAR
aws s3 cp target/workshop-0.0.1-SNAPSHOT.jar \
s3://${BACKEND_BUCKET}/jars/ \
--region ap-southeast-1
# Verify upload
aws s3 ls s3://${BACKEND_BUCKET}/jars/
INSTANCE_ID=$(aws ec2 describe-instances \
--filters "Name=tag:aws:cloudformation:stack-name,Values=workshop-aws-dev" \
"Name=instance-state-name,Values=running" \
--region ap-southeast-1 \
--query 'Reservations[0].Instances[0].InstanceId' \
--output text)
echo "Instance ID: $INSTANCE_ID"
aws ssm start-session --target $INSTANCE_ID --region ap-southeast-1
# Switch to ec2-user
sudo su - ec2-user
# Navigate to application directory
cd /opt/workshop
# Download JAR from S3
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
BACKEND_BUCKET="workshop-aws-dev-backend-${ACCOUNT_ID}-ap-southeast-1"
aws s3 cp s3://${BACKEND_BUCKET}/jars/workshop-0.0.1-SNAPSHOT.jar . \
--region ap-southeast-1
# Verify file
ls -lh workshop-0.0.1-SNAPSHOT.jar
cat > application.properties <<'EOF'
spring.application.name=workshop-aws
# Database Configuration
spring.datasource.url=jdbc:mysql://REPLACE_WITH_RDS_ENDPOINT:3306/workshop_aws?useSSL=true&requireSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Ho_Chi_Minh
spring.datasource.username=admin
spring.datasource.password=YourStrongPassword123!
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Connection Pool
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
# JPA Configuration
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false
# Server Configuration
server.port=8080
server.servlet.context-path=/dna_service
# JWT Configuration
jwt.signerKey=2VJ50pdhYm96e4VECp/vsZGVmkSl9xp1rSYAZKsZL7n9Ti1pZYle3k9mheQEKt6+
# Logging
logging.level.root=INFO
logging.level.aws_project.workshop=DEBUG
logging.file.name=/opt/workshop/application.log
EOF
# Replace RDS endpoint
RDS_ENDPOINT=$(aws cloudformation describe-stacks \
--stack-name workshop-aws-dev \
--region ap-southeast-1 \
--query 'Stacks[0].Outputs[?OutputKey==`RDSEndpoint`].OutputValue' \
--output text)
sed -i "s/REPLACE_WITH_RDS_ENDPOINT/${RDS_ENDPOINT}/g" application.properties
# Stop old application (if any)
sudo systemctl stop workshop.service 2>/dev/null || true
pkill -f workshop-0.0.1-SNAPSHOT.jar 2>/dev/null || true
# Start application
nohup java -jar workshop-0.0.1-SNAPSHOT.jar \
--spring.config.location=file:/opt/workshop/application.properties \
> /dev/null 2>&1 &
# Save PID
echo $! > application.pid
# Wait for application to start
sleep 10
# Check process
ps aux | grep java
# On EC2
curl http://localhost:8080/dna_service/actuator/health
# Expected result:
# {"status":"UP"}
# On local machine
ALB_DNS=$(aws cloudformation describe-stacks \
--stack-name workshop-aws-dev \
--region ap-southeast-1 \
--query 'Stacks[0].Outputs[?OutputKey==`ALBDNSName`].OutputValue' \
--output text)
curl http://${ALB_DNS}/dna_service/actuator/health
API_URL=$(aws cloudformation describe-stacks \
--stack-name workshop-aws-dev \
--region ap-southeast-1 \
--query 'Stacks[0].Outputs[?OutputKey==`APIGatewayURL`].OutputValue' \
--output text)
curl ${API_URL}/dna_service/actuator/health
To automatically start application when EC2 restarts:
# On EC2
sudo tee /etc/systemd/system/workshop.service > /dev/null <<'EOF'
[Unit]
Description=Workshop DNA Analysis Backend
After=network.target
[Service]
Type=simple
User=ec2-user
Group=ec2-user
WorkingDirectory=/opt/workshop
ExecStart=/usr/bin/java -jar /opt/workshop/workshop-0.0.1-SNAPSHOT.jar --spring.config.location=file:/opt/workshop/application.properties
Restart=always
RestartSec=10
StandardOutput=append:/opt/workshop/application.log
StandardError=append:/opt/workshop/application.log
[Install]
WantedBy=multi-user.target
EOF
# Reload systemd
sudo systemctl daemon-reload
# Enable service
sudo systemctl enable workshop.service
# Start service
sudo systemctl start workshop.service
# Check status
sudo systemctl status workshop.service
# View application logs
tail -f /opt/workshop/application.log
# View systemd logs
sudo journalctl -u workshop.service -f
# View CloudWatch Logs (on local machine)
aws logs tail /aws/workshop-aws/dev/application \
--follow \
--region ap-southeast-1
Check logs:
tail -100 /opt/workshop/application.log
Common errors:
Database connection failed
Port 8080 already in use
# Kill process using port 8080
sudo lsof -ti:8080 | xargs kill -9
Out of memory
# Increase heap size
java -Xmx512m -jar workshop-0.0.1-SNAPSHOT.jar
# Check application is running
ps aux | grep java
# Check port listening
sudo netstat -tulpn | grep 8080
# Test locally
curl -v http://localhost:8080/dna_service/actuator/health
# Check Target Group health
aws elbv2 describe-target-health \
--target-group-arn <target-group-arn> \
--region ap-southeast-1
# Check Security Group
# EC2 SG must allow traffic from ALB SG on port 8080
Checklist:
{"status":"UP"}After backend is ready: