TL;DR
Complete guide to deploying a Spring Boot JAR on Ubuntu with systemd, nginx, and JVM tuning for production.
Key facts
- Topology
- Spring Boot on Ubuntu
TL;DR
This guide covers deploying a Spring Boot application as a standalone JAR on Ubuntu with systemd, nginx, and basic JVM tuning for production.
Prerequisites
- Ubuntu 24.04 LTS with root or sudo access
- Java 21 (LTS) or Java 17 (LTS)
- Your Spring Boot application packaged as an executable JAR
Step 1 — Install Java
sudo apt update && sudo apt upgrade -y
sudo apt install -y openjdk-21-jre-headless
java -version
Step 2 — Deploy the JAR
Create a dedicated service user and directory:
sudo useradd -r -s /bin/false springapp
sudo mkdir -p /opt/springapp
sudo chown springapp:springapp /opt/springapp
Copy your JAR and configuration:
sudo cp myapp-1.0.0.jar /opt/springapp/app.jar
sudo cp application-production.yml /opt/springapp/
sudo chown springapp:springapp /opt/springapp/*
Step 3 — Systemd service
Create /etc/systemd/system/springapp.service:
[Unit]
Description=Spring Boot Application
After=network.target
[Service]
User=springapp
Group=springapp
WorkingDirectory=/opt/springapp
ExecStart=/usr/bin/java \
-Xms512m -Xmx1024m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-Dspring.profiles.active=production \
-jar app.jar
Restart=always
RestartSec=10
SuccessExitStatus=143
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl start springapp
sudo systemctl enable springapp
Verify the application started:
sudo journalctl -u springapp -f
curl http://localhost:8080/actuator/health
Step 4 — nginx reverse proxy
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8080;
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_read_timeout 60s;
}
}
sudo ln -s /etc/nginx/sites-available/springapp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Step 5 — SSL and firewall
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable
JVM tuning notes
-Xms/-Xmx: Set initial and max heap to the same value in production to avoid resize pauses-XX:+UseG1GC: G1 is the default in Java 21 and handles most workloads well- Spring Boot Actuator: Enable
/actuator/healthand/actuator/metricsfor production monitoring
With Reflex
Reflex monitors your Spring Boot process via Actuator endpoints and systemd status. It tracks JVM heap usage, garbage collection pauses, HTTP error rates, and system resources. When issues arise, Reflex can restart the service, verify health through the Actuator endpoint, and alert your team with correlated diagnostics. See How it works.