Spring Boot Application Deployment on Linux
Spring Boot simplifies Java application development and deployment by providing embedded servers and minimal configuration. Deploying Spring Boot applications requires Java runtime, Maven/Gradle build tools, Nginx reverse proxy, systemd service management, and proper memory configuration. This guide covers production-ready Spring Boot deployment including Java installation, application building, systemd service setup, Nginx reverse proxy, logging configuration, monitoring, and optimization for Linux servers.
Table of Contents
- Spring Boot Architecture
- Java Environment Setup
- Spring Boot Application Build
- Application Properties Configuration
- Systemd Service Setup
- Nginx Reverse Proxy
- Database Configuration
- Logging and Monitoring
- Security Hardening
- Performance Optimization
- Conclusion
Spring Boot Architecture
Spring Boot packages Java applications as executable JAR files with embedded application servers, simplifying deployment compared to traditional Java application servers.
Architecture benefits:
- Self-contained JAR file with Tomcat/Netty embedded
- No separate application server installation needed
- Configuration via application.properties or YAML
- Automatic dependency management via Maven/Gradle
- Built-in actuator for monitoring and management
Request flow:
- Nginx receives HTTP request
- Nginx forwards to Spring Boot application on port 8080
- Spring Boot processes request
- Controller handles business logic
- Service layer executes operations
- Repository interacts with database
- Response returned to Nginx
- Nginx caches or returns to client
Java Environment Setup
Install Java and prepare environment for Spring Boot.
Update system:
sudo apt update
sudo apt upgrade -y
sudo apt install curl wget git zip unzip vim htop build-essential -y
Install Java 17 LTS:
# Add repository
sudo apt install software-properties-common -y
sudo add-apt-repository ppa:openjdk-r/ppa -y
# Install OpenJDK
sudo apt install openjdk-17-jdk openjdk-17-jdk-headless -y
# Verify
java -version
javac -version
Or install Oracle JDK:
# Download from Oracle website or use:
wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz
tar xzf jdk-17_linux-x64_bin.tar.gz
sudo mv jdk-17.0.X /usr/lib/jvm/
# Set environment
echo 'export JAVA_HOME=/usr/lib/jvm/jdk-17.0.X' >> ~/.bashrc
source ~/.bashrc
Create application user:
sudo useradd -m -s /bin/bash springboot
sudo usermod -aG www-data springboot
# Create application directory
sudo mkdir -p /home/springboot/app
sudo chown -R springboot:www-data /home/springboot/app
Install Maven (optional, if not using Gradle):
wget https://archive.apache.org/dist/maven/maven-3/3.9.0/binaries/apache-maven-3.9.0-bin.tar.gz
tar xzf apache-maven-3.9.0-bin.tar.gz
sudo mv apache-maven-3.9.0 /usr/lib/maven
# Set environment
echo 'export PATH="/usr/lib/maven/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Verify
mvn --version
Install Gradle (optional):
sdk install gradle 8.0
# Verify
gradle --version
Install Nginx:
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
Install PostgreSQL:
sudo apt install postgresql postgresql-contrib -y
sudo systemctl start postgresql
sudo systemctl enable postgresql
Spring Boot Application Build
Build Spring Boot application from source.
Clone or create application:
cd /home/springboot/app
# Clone from repository
sudo -u springboot git clone https://github.com/yourname/spring-boot-app.git .
# Or use Spring Initializr to generate project
Configure pom.xml (Maven):
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-boot-app</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Or build.gradle (Gradle):
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.0'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'com.example'
version = '1.0.0'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'org.postgresql:postgresql'
}
springBoot {
buildInfo()
}
Build application:
cd /home/springboot/app
# Build with Maven
mvn clean package -DskipTests
# Or with Gradle
gradle build -x test
# Verify JAR created
ls -lah target/*.jar
Application Properties Configuration
Configure Spring Boot for production environment.
Create application.properties:
sudo -u springboot cat > /home/springboot/app/src/main/resources/application-production.properties << 'EOF'
# Server configuration
server.port=8080
server.servlet.context-path=/
server.shutdown=graceful
server.compression.enabled=true
# Logging
logging.level.root=INFO
logging.level.com.example=INFO
logging.file.name=/home/springboot/app/logs/application.log
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
# Database
spring.datasource.url=jdbc:postgresql://localhost:5432/springboot_db
spring.datasource.username=springboot_user
spring.datasource.password=SecurePassword123!
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
# JPA/Hibernate
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL10Dialect
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.jdbc.batch_size=20
# Actuator (monitoring)
management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=when-authorized
management.metrics.export.prometheus.enabled=true
# Application specific
app.name=Spring Boot App
app.version=1.0.0
EOF
Or application.yml:
sudo -u springboot cat > /home/springboot/app/src/main/resources/application-production.yml << 'EOF'
server:
port: 8080
shutdown: graceful
compression:
enabled: true
logging:
level:
root: INFO
file:
name: /home/springboot/app/logs/application.log
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
spring:
datasource:
url: jdbc:postgresql://localhost:5432/springboot_db
username: springboot_user
password: SecurePassword123!
hikari:
maximum-pool-size: 20
minimum-idle: 5
jpa:
database-platform: org.hibernate.dialect.PostgreSQL10Dialect
hibernate:
ddl-auto: validate
show-sql: false
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: when-authorized
metrics:
export:
prometheus:
enabled: true
app:
name: Spring Boot App
version: 1.0.0
EOF
Systemd Service Setup
Configure Spring Boot to run as systemd service.
Create systemd service file:
sudo cat > /etc/systemd/system/springboot.service << 'EOF'
[Unit]
Description=Spring Boot Application
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=simple
User=springboot
WorkingDirectory=/home/springboot/app
# JVM memory settings
Environment="JAVA_OPTS=-Xms512m -Xmx1g -XX:+UseG1GC"
Environment="SPRING_PROFILES_ACTIVE=production"
ExecStart=/usr/bin/java -jar /home/springboot/app/target/spring-boot-app-1.0.0.jar
# Restart configuration
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
# Security
NoNewPrivileges=yes
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable springboot
sudo systemctl start springboot
sudo systemctl status springboot
Verify service:
# Check status
sudo systemctl status springboot
# View logs
sudo journalctl -u springboot -f
# Check if listening on port 8080
netstat -tulpn | grep 8080
Nginx Reverse Proxy
Configure Nginx to proxy requests to Spring Boot.
Create Nginx configuration:
sudo cat > /etc/nginx/sites-available/springboot.conf << 'EOF'
upstream springboot {
server 127.0.0.1:8080 fail_timeout=0;
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
access_log /var/log/nginx/springboot_access.log;
error_log /var/log/nginx/springboot_error.log;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
# Gzip compression
gzip on;
gzip_types application/json text/css text/javascript;
location / {
proxy_pass http://springboot;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
location /health {
access_log off;
proxy_pass http://springboot;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/springboot.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Database Configuration
Set up PostgreSQL database for Spring Boot application.
Create database and user:
sudo -u postgres psql << EOF
CREATE DATABASE springboot_db;
CREATE USER springboot_user WITH PASSWORD 'SecurePassword123!';
ALTER ROLE springboot_user SET client_encoding TO 'utf8';
ALTER ROLE springboot_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE springboot_user SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE springboot_db TO springboot_user;
\q
EOF
Run migrations:
# Spring Boot JPA will create/update schema based on entities
# If using Flyway or Liquibase, migrations run automatically
# Verify database
sudo -u postgres psql -d springboot_db -c "SELECT * FROM information_schema.tables;"
Logging and Monitoring
Configure logging for production monitoring.
Create logs directory:
sudo -u springboot mkdir -p /home/springboot/app/logs
sudo chmod 755 /home/springboot/app/logs
Configure logback (Spring Boot default):
sudo -u springboot cat > /home/springboot/app/src/main/resources/logback-spring.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_FILE" value="/home/springboot/app/logs/application.log"/>
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}</file>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</configuration>
EOF
Monitor application:
# View logs
tail -f /home/springboot/app/logs/application.log
# Check via actuator endpoint
curl http://localhost:8080/actuator/health
# Monitor metrics
curl http://localhost:8080/actuator/metrics
Security Hardening
Implement security best practices.
Set JVM security properties:
# Edit systemd service
sudo systemctl edit springboot
# Add JVM options
Environment="JAVA_OPTS=-Xms512m -Xmx1g -XX:+UseG1GC -XX:+AlwaysPreTouch -server"
Configure Spring Security:
// In Spring Boot SecurityConfig
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.requiresChannel()
.anyRequest()
.requiresSecure()
.and()
.sessionManagement()
.sessionFixationProtection(SessionFixationProtection.MIGRATE_SESSION)
.and()
.headers()
.xssProtection()
.frameOptions()
.disable()
.contentSecurityPolicy("default-src 'self'");
return http.build();
}
}
Performance Optimization
Optimize Spring Boot for production load.
Configure JVM memory settings:
# Edit systemd service environment variable
JAVA_OPTS="-Xms512m -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+AlwaysPreTouch"
Enable database connection pooling:
# In application.properties
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.max-lifetime=1200000
Monitor performance:
# Check JVM memory usage
jps -l
jstat -gc -h10 <pid> 1000
# Monitor application metrics
curl http://localhost:8080/actuator/metrics/jvm.memory.usage
# Check system resources
top -u springboot
Conclusion
Deploying Spring Boot applications on Linux requires Java installation, application building with Maven/Gradle, systemd service configuration, Nginx reverse proxy setup, and database configuration. This guide covers production-ready deployment with proper JVM memory tuning, logging configuration, security hardening, and monitoring. Key focus areas are Java runtime setup, Spring Boot JAR packaging, systemd service reliability, Nginx reverse proxy efficiency, and proper database connection pooling. Regular monitoring of logs and metrics ensures continued operation. Following these practices creates a robust Spring Boot deployment ready for production traffic and scalability.


