Spring Boot has become the de facto standard for building production-ready Java applications. Its embedded server architecture and convention-over-configuration approach make it ideal for cloud deployments. This guide walks you through deploying a Spring Boot application on a RamNode VPS, covering everything from initial server setup to production-grade configurations with reverse proxy, SSL termination, and process management.
Prerequisites
Before beginning the deployment, ensure you have:
- A RamNode VPS with at least 2GB RAM (4GB recommended for production)
- Ubuntu 22.04 LTS or Ubuntu 24.04 LTS installed
- Root or sudo access to the server
- A domain name pointed to your VPS IP address
- A Spring Boot application packaged as a JAR file
Recommended VPS Specifications
| Workload | RAM | CPU Cores |
|---|---|---|
| Development/Testing | 2GB | 1-2 vCPUs |
| Production (Light) | 4GB | 2-4 vCPUs |
| Production (Heavy) | 8GB+ | 4+ vCPUs |
Initial Server Setup
Update System Packages
Connect to your RamNode VPS via SSH and update the system:
ssh root@your-server-ip
apt update && apt upgrade -yCreate a Dedicated User
Running applications as root is a security risk. Create a dedicated user:
# Create the springboot user
useradd -r -m -U -d /opt/springboot -s /bin/bash springboot
# Create application directories
mkdir -p /opt/springboot/app
mkdir -p /opt/springboot/logs
# Set proper ownership
chown -R springboot:springboot /opt/springbootConfigure Firewall
Configure UFW to allow only necessary traffic:
# Enable UFW
ufw enable
# Allow SSH (important: do this first!)
ufw allow 22/tcp
# Allow HTTP and HTTPS
ufw allow 80/tcp
ufw allow 443/tcp
# Verify rules
ufw status verboseInstalling Java
Spring Boot requires a Java Runtime Environment. We recommend Eclipse Temurin (formerly AdoptOpenJDK) for production deployments.
Install Eclipse Temurin JDK 21
# Install required dependencies
apt install -y wget apt-transport-https gpg
# Add the Adoptium GPG key
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | \
gpg --dearmor | \
tee /etc/apt/keyrings/adoptium.gpg > /dev/null
# Add the repository
echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg] \
https://packages.adoptium.net/artifactory/deb $(lsb_release -cs) main" | \
tee /etc/apt/sources.list.d/adoptium.list
# Update and install
apt update
apt install -y temurin-21-jdkVerify Installation
java -version
# openjdk version "21.0.x" 2024-xx-xx LTS
# OpenJDK Runtime Environment Temurin-21.0.x+x (build 21.0.x+x-LTS)
# OpenJDK 64-Bit Server VM Temurin-21.0.x+x (build 21.0.x+x-LTS, mixed mode)Deploying the Spring Boot Application
Transfer Your Application
Transfer your Spring Boot JAR file to the server:
# From your local machine
scp target/myapp-0.0.1-SNAPSHOT.jar root@your-server-ip:/opt/springboot/app/
# Or using rsync for larger files
rsync -avz --progress target/myapp-0.0.1-SNAPSHOT.jar \
root@your-server-ip:/opt/springboot/app/Create Application Configuration
cat > /opt/springboot/app/application-prod.yml << 'EOF'
server:
port: 8080
forward-headers-strategy: native
spring:
application:
name: myapp
logging:
level:
root: INFO
com.yourcompany: DEBUG
file:
name: /opt/springboot/logs/application.log
logback:
rollingpolicy:
max-file-size: 100MB
max-history: 30
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: when_authorized
EOF
# Set proper ownership
chown springboot:springboot /opt/springboot/app/application-prod.ymlCreate Systemd Service
Create a systemd service file for automatic startup and process management:
cat > /etc/systemd/system/springboot.service << 'EOF'
[Unit]
Description=Spring Boot Application
After=network.target
[Service]
Type=simple
User=springboot
Group=springboot
WorkingDirectory=/opt/springboot/app
ExecStart=/usr/bin/java \
-Xms512m \
-Xmx1024m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-Djava.security.egd=file:/dev/./urandom \
-Dspring.profiles.active=prod \
-jar myapp-0.0.1-SNAPSHOT.jar
SuccessExitStatus=143
Restart=always
RestartSec=10
StandardOutput=append:/opt/springboot/logs/stdout.log
StandardError=append:/opt/springboot/logs/stderr.log
[Install]
WantedBy=multi-user.target
EOFEnable and Start the Service
# Reload systemd configuration
systemctl daemon-reload
# Enable service to start on boot
systemctl enable springboot
# Start the service
systemctl start springboot
# Check status
systemctl status springbootConfiguring Nginx Reverse Proxy
Nginx serves as a reverse proxy, handling SSL termination, load balancing, and serving static content.
Install Nginx
apt install -y nginxCreate Server Block Configuration
cat > /etc/nginx/sites-available/springboot << 'EOF'
upstream springboot {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL configuration (will be updated by Certbot)
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
# SSL security settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Proxy settings
location / {
proxy_pass http://springboot;
proxy_http_version 1.1;
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_set_header Connection "";
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
}
# Health check endpoint (no logging)
location /actuator/health {
proxy_pass http://springboot;
access_log off;
}
# Logging
access_log /var/log/nginx/springboot_access.log;
error_log /var/log/nginx/springboot_error.log;
}
EOFEnable the Configuration
# Enable the site
ln -s /etc/nginx/sites-available/springboot /etc/nginx/sites-enabled/
# Remove default site
rm -f /etc/nginx/sites-enabled/default
# Test configuration
nginx -t
# Reload Nginx
systemctl reload nginxSSL Certificate with Let's Encrypt
Certbot automates the process of obtaining and renewing SSL certificates from Let's Encrypt.
Install Certbot
apt install -y certbot python3-certbot-nginxObtain SSL Certificate
certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Follow the prompts:
# - Enter your email address
# - Agree to terms of service
# - Choose whether to redirect HTTP to HTTPS (recommended)Verify Auto-Renewal
# Check timer status
systemctl status certbot.timer
# Test renewal process (dry run)
certbot renew --dry-runMonitoring and Logging
Log Rotation
Configure logrotate for your Spring Boot logs:
cat > /etc/logrotate.d/springboot << 'EOF'
/opt/springboot/logs/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 springboot springboot
sharedscripts
postrotate
systemctl reload springboot > /dev/null 2>&1 || true
endscript
}
EOFHealth Check Script
cat > /opt/springboot/health-check.sh << 'EOF'
#!/bin/bash
HEALTH_URL="http://localhost:8080/actuator/health"
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL)
if [ "$RESPONSE" = "200" ]; then
echo "$(date): Application is healthy"
exit 0
else
echo "$(date): Application unhealthy (HTTP $RESPONSE)"
exit 1
fi
EOF
chmod +x /opt/springboot/health-check.shUseful Commands
| Action | Command |
|---|---|
| View service status | systemctl status springboot |
| Restart application | systemctl restart springboot |
| View live logs | journalctl -u springboot -f |
| View application logs | tail -f /opt/springboot/logs/application.log |
| Reload Nginx | systemctl reload nginx |
Performance Tuning
JVM Memory Settings
Adjust the JVM heap size based on available RAM. Allocate 50-70% of available RAM to the JVM heap:
| VPS RAM | -Xms | -Xmx |
|---|---|---|
| 2GB | 512m | 1024m |
| 4GB | 1024m | 2560m |
| 8GB | 2048m | 5120m |
Kernel Parameters
Optimize kernel parameters for high-connection workloads:
cat >> /etc/sysctl.conf << 'EOF'
# Network performance tuning
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# TCP keepalive settings
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 3
# File descriptor limits
fs.file-max = 2097152
EOF
# Apply changes
sysctl -pZero-Downtime Deployment Script
Create a deployment script for updating your application with minimal downtime:
cat > /opt/springboot/deploy.sh << 'EOF'
#!/bin/bash
set -e
APP_DIR="/opt/springboot/app"
JAR_NAME="myapp-0.0.1-SNAPSHOT.jar"
BACKUP_DIR="/opt/springboot/backups"
# Create backup directory if it doesn't exist
mkdir -p $BACKUP_DIR
# Backup current JAR
if [ -f "$APP_DIR/$JAR_NAME" ]; then
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
cp "$APP_DIR/$JAR_NAME" "$BACKUP_DIR/${JAR_NAME}.$TIMESTAMP"
echo "Backed up current JAR to $BACKUP_DIR/${JAR_NAME}.$TIMESTAMP"
fi
# Copy new JAR (assumes it's in current directory)
cp "$1" "$APP_DIR/$JAR_NAME"
chown springboot:springboot "$APP_DIR/$JAR_NAME"
# Restart the service
systemctl restart springboot
# Wait for application to start
echo "Waiting for application to start..."
sleep 10
# Health check
/opt/springboot/health-check.sh
# Keep only last 5 backups
ls -t $BACKUP_DIR/*.jar* 2>/dev/null | tail -n +6 | xargs rm -f 2>/dev/null
echo "Deployment complete!"
EOF
chmod +x /opt/springboot/deploy.shUsage
# Deploy a new version
/opt/springboot/deploy.sh /path/to/new-myapp-0.0.1-SNAPSHOT.jarTroubleshooting
Conclusion
You now have a production-ready Spring Boot deployment on your RamNode VPS. This setup provides a solid foundation with proper process management via systemd, secure HTTPS with automatic certificate renewal, and a reverse proxy for enhanced security and performance. For further optimization, consider implementing centralized logging with the ELK stack, container orchestration with Docker or Kubernetes for horizontal scaling, and comprehensive monitoring with Prometheus and Grafana.
