Backend Framework Guide

    Deploying Spring Boot

    Deploy production-ready Spring Boot applications with Nginx reverse proxy, SSL/TLS encryption, and systemd process management on RamNode's reliable VPS hosting.

    Java 21
    systemd
    Nginx
    SSL/TLS

    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.

    1

    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

    WorkloadRAMCPU Cores
    Development/Testing2GB1-2 vCPUs
    Production (Light)4GB2-4 vCPUs
    Production (Heavy)8GB+4+ vCPUs
    2

    Initial Server Setup

    Update System Packages

    Connect to your RamNode VPS via SSH and update the system:

    SSH & System Update
    ssh root@your-server-ip
    apt update && apt upgrade -y

    Create a Dedicated User

    Running applications as root is a security risk. Create a dedicated user:

    Create springboot 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/springboot

    Configure Firewall

    Configure UFW to allow only necessary traffic:

    UFW Configuration
    # 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 verbose
    3

    Installing Java

    Spring Boot requires a Java Runtime Environment. We recommend Eclipse Temurin (formerly AdoptOpenJDK) for production deployments.

    Install Eclipse Temurin JDK 21

    Install Java 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-jdk

    Verify Installation

    Verify Java
    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)
    4

    Deploying the Spring Boot Application

    Transfer Your Application

    Transfer your Spring Boot JAR file to the server:

    Transfer JAR File
    # 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

    application-prod.yml
    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.yml

    Create Systemd Service

    Create a systemd service file for automatic startup and process management:

    springboot.service
    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
    EOF

    Enable and Start the Service

    Start 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 springboot
    5

    Configuring Nginx Reverse Proxy

    Nginx serves as a reverse proxy, handling SSL termination, load balancing, and serving static content.

    Install Nginx

    Install Nginx
    apt install -y nginx

    Create Server Block Configuration

    Nginx 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;
    }
    EOF

    Enable the Configuration

    Enable Nginx Site
    # 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 nginx
    6

    SSL Certificate with Let's Encrypt

    Certbot automates the process of obtaining and renewing SSL certificates from Let's Encrypt.

    Install Certbot

    Install Certbot
    apt install -y certbot python3-certbot-nginx

    Obtain SSL Certificate

    Obtain 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

    Verify Renewal
    # Check timer status
    systemctl status certbot.timer
    
    # Test renewal process (dry run)
    certbot renew --dry-run
    7

    Monitoring and Logging

    Log Rotation

    Configure logrotate for your Spring Boot logs:

    Logrotate Configuration
    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
    }
    EOF

    Health Check Script

    health-check.sh
    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.sh

    Useful Commands

    ActionCommand
    View service statussystemctl status springboot
    Restart applicationsystemctl restart springboot
    View live logsjournalctl -u springboot -f
    View application logstail -f /opt/springboot/logs/application.log
    Reload Nginxsystemctl reload nginx
    8

    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
    2GB512m1024m
    4GB1024m2560m
    8GB2048m5120m

    Kernel Parameters

    Optimize kernel parameters for high-connection workloads:

    Kernel Tuning
    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 -p
    9

    Zero-Downtime Deployment Script

    Create a deployment script for updating your application with minimal downtime:

    deploy.sh
    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.sh

    Usage

    Deploy New Version
    # Deploy a new version
    /opt/springboot/deploy.sh /path/to/new-myapp-0.0.1-SNAPSHOT.jar
    10

    Troubleshooting

    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.