Pourquoi self-héberger Spring Boot sur un VPS
Une application Spring Boot embarque son propre serveur (Tomcat ou Undertow) et se livre sous forme de JAR exécutable autonome. C'est idéal pour un VPS : un seul fichier app.jar, une JVM, et vous tournez. Les PaaS comme Heroku ou les conteneurs managés facturent chaque tranche de 512 Mo de RAM, or la JVM est gourmande au démarrage. Sur un VPS, vous fixez vous-même -Xmx, vous mutualisez la base PostgreSQL et l'API sur la même machine, et vous maîtrisez le warm-up à froid sans timeout imposé. Vous gardez aussi la main sur la version exacte du JDK (Temurin 21 LTS, GraalVM) et sur les paramètres GC, ce qui est rarement possible en environnement managé.
Bénéfices concrets
- Contrôle total de l'heap JVM (
-Xmx,-Xms) et du garbage collector selon votre charge réelle - Base PostgreSQL et API co-localisées : latence réseau quasi nulle entre l'app et la donnée
- Coût mensuel fixe et prévisible, sans facturation à la tranche de RAM ni au temps de calcul
- Liberté du JDK : Temurin 21 LTS, GraalVM native-image ou Azul Zulu selon vos besoins
- Pas de cold start imposé : votre service reste chaud 24/7 pour des temps de réponse stables
- Actuator, Micrometer et Prometheus exposés librement pour un monitoring fin sans surcoût
Prérequis matériels et logiciels
Une API Spring Boot avec base de données tourne confortablement sur un VPS de 2 vCPU et 4 Go de RAM (comptez 1 à 1,5 Go pour la JVM, le reste pour PostgreSQL et le système). Pour un microservice léger sans ORM lourd, 2 Go suffisent mais restent justes au démarrage. Installez Docker et Docker Compose, un JDK 21 si vous compilez sur le serveur (sinon construisez le JAR en CI et n'envoyez que l'artefact), et pointez un nom de domaine de type api.mondomaine.ma sur l'IP du VPS via un enregistrement A. Prévoyez 10 Go de disque minimum pour les images Docker et les logs.
Déploiement pas à pas
Construire le JAR exécutable
Lancez ./mvnw clean package -DskipTests (ou ./gradlew bootJar). Vous obtenez un fichier dans target/app.jar qui embarque Tomcat et toutes les dépendances. Vérifiez localement avec java -jar target/app.jar avant tout envoi.
Conteneuriser avec un Dockerfile multi-stage
Utilisez eclipse-temurin:21-jre-alpine comme image finale et copiez uniquement le JAR. Un build multi-stage (maven:3.9-eclipse-temurin-21 pour compiler, JRE pour exécuter) réduit l'image de 700 Mo à environ 250 Mo. Exposez le port 8080.
Orchestrer app + PostgreSQL avec Docker Compose
Déclarez deux services dans docker-compose.yml : app et db (image postgres:16). Passez les credentials via variables d'environnement (SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME) et liez-les par un réseau interne. Lancez docker compose up -d.
Configurer Nginx en reverse proxy
Installez Nginx et créez un vhost qui fait un proxy_pass http://127.0.0.1:8080;. Ajoutez les en-têtes X-Forwarded-For et X-Forwarded-Proto pour que Spring détecte correctement le HTTPS derrière le proxy (server.forward-headers-strategy=framework).
Activer HTTPS avec Certbot
Exécutez certbot --nginx -d api.mondomaine.ma pour obtenir et installer un certificat Let's Encrypt. Le renouvellement automatique est géré par le timer systemd de Certbot. Forcez la redirection HTTP vers HTTPS dans le vhost.
Fiabiliser le redémarrage
Ajoutez restart: unless-stopped à vos services Compose et configurez le healthcheck Actuator (/actuator/health) comme sonde Docker. Ainsi l'app redémarre seule après un reboot du VPS ou un crash JVM.
Compilez votre application en image native avec GraalVM (./mvnw -Pnative native:compile via Spring Boot 3) : le binaire démarre en moins de 100 ms et consomme 3 à 5 fois moins de RAM qu'une JVM classique. C'est décisif sur un petit VPS où chaque centaine de Mo compte. Limitez aussi l'heap explicitement avec JAVA_OPTS=-Xmx512m dans le Compose pour éviter que la JVM ne réclame toute la mémoire disponible.