Application Java Spring Boot + Angular dans un environnement Linux (serveur sous Ubuntu/Debian)
- Curl :
sudo apt install -y curl - Git :
# Installation
sudo apt install -y git
# Version et configuration
git config --list- Java JDK 21(LTS)
#Installation :
sudo apt update
sudo apt install openjdk-21-jdk
#Vérification :
java -version
javac -version-
Maven : pas d'installation nécessaire grâce au Maven Wrapper inclus
-
Spring Boot CLI 3.5(LTS) : pas d'installation nécessaire sur serveur de prod
Vérification finale : ./mvnw -v
- PostgreSQL 17.6 : port par défaut
5432
Installation :
# Installation PostgreSQL + contrib (extensions utiles)
sudo apt install -y postgresql-17 postgresql-contrib-17
# Démarrer et activer PostgreSQL
sudo systemctl start postgresql
sudo systemctl enable postgresql
# Vérifier le statut
sudo systemctl status postgresql
#Création de la BDD et d'un user :
```bash
# Créer un utilisateur
sudo -u postgres createuser --interactive
# Répondre aux questions:
# - Nom du rôle: votre_user
# - Superutilisateur: n
# - Créer des BDD: y
# - Créer des rôles: n
# Définir un mot de passe pour cet utilisateur
sudo -u postgres psql
ALTER USER votre_user PASSWORD 'votre_mot_de_passe';
\q
# Créer une base de données
sudo -u postgres createdb votre_db -O votre_user
# Test de connexion
psql -h localhost -U votre_user -d votre_db
# Saisir le mot de passe quand demandé- Node.js 22.20.0
- npm 10.9.3
# Télécharger et installer nvm :
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# au lieu de redémarrer le shell
\. "$HOME/.nvm/nvm.sh"
# Télécharger et installer Node.js :
nvm install 22.20.0
# Vérifiez la version de Node.js :
node -v # Doit afficher "v22.20.0".
# Vérifier la version de npm :
npm -v # Doit afficher "10.9.3".- Angular CLI 20.2.2
Installation : npm install -g @angular/[email protected]
Vérification finale : ng version
Dépendances listées dans pom.xml
- Spring Security - Authentification JWT
- JPA/Hibernate - ORM
- PostGIS 3.5.3 - Localisation via lattitude/longitude
Dépendances listées dans package-lock.json
npx ng version
- Angular 20 - Framework frontend
- RxJS 7.8.0 - Programmation réactive
Toujours utiliser le wrapper pour garantir la même version de Maven
## DEV (macOS/Linux) ##
# Build basique pour développer
./mvn clean compile
# → Compile juste le code, pas de JAR, pas de tests
# Build complet avec tests automatiques
./mvn clean install
# → Installe dépendances + Compile + Tests + Crée le JAR + L'installe en local
# Build SANS les tests (plus rapide)
./mvn clean install -DskipTests
# → Compile et crée le JAR, mais ignore les tests
# Lancer l'application
./mvn spring-boot:run
## TESTS
# Exécution des tests sans build
./mvn test
# → Lance tous les tests unitaires
## PROD (Linux): création du JAR final ##
# Build optimisé pour déploiement
./mvn clean verify
# → Compile + Tests unitaires + Tests integration + JAR
# Build avec profil production (si tu as un profil)
./mvn clean package -Pprod
# → Utilise les configs production
# Build sans tests pour déploiement rapide
./mvn clean package -DskipTests
# → Compile et crée le JAR, mais ignore les tests
## SERVEUR DE PROD
# Copier SEULEMENT le JAR
scp target/powerme-1.0.0.jar user@serveur:/opt/app/
# Sur le serveur (avec SEULEMENT Java installé)
ssh user@serveur
cd /opt/app
# Lancer l'application sur le serveur de prod
java -jar demo-app-1.0.0.jar#TESTS
# Exécution des tests sans build
npm run test
# BUILD
cd frontend
# Installer les dépendances
npm install
# → Télécharge node_modules/ (peut prendre 2-3min)
# Build développement
npm run build
# Build production (optimisé)
npm run build --configuration=production
# → Génère dist/ folder- JAR exécutable Spring Boot : target/mon-app-1.0.0.jar
- Lancer l'app en prod :
java -jar target/mon-app-1.0.0.jar
- Application Angular buildée : app/dist/powerme/
- Point d'entrée : app/dist/powerme/index.html
# 1. Démarrer PostgreSQL
docker compose -f docker-compose.dev.yml up -d
# 2. (Optionnel) Personnaliser la config
cp .env.dev.example .env.dev
# Modifier .env.dev selon vos besoins
# 3. Lancer le backend dans IntelliJ
# Active profiles: dev
---
## ✅ **Checklist : Ton setup est prêt si...**
```bash
# ✅ Docker Compose démarre la BDD
docker compose -f docker-compose.dev.yml up -d
docker compose -f docker-compose.dev.yml ps
# → db: Up, pgadmin: Up
# ✅ Spring Boot se connecte à la BDD
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
# → Logs "HikariPool-1 - Start completed"
# ✅ pgAdmin accessible
open http://localhost:5050
# → Page de login affichée
# ✅ Backend accessible
curl http://localhost:8080/actuator/health
# → {"status":"UP"}
## Déploiement
### Backend
Via un service systemd
- Préparation :
```bash
# 1. Créer utilisateur dédié (sécurité)
sudo useradd -r -s /bin/false appuser
sudo mkdir -p /opt/app
sudo mkdir -p /var/log/app
# 2. Copier le JAR
scp target/mon-app-1.0.0.jar user@serveur:/opt/app/app.jar
# 3. Permissions
sudo chown -R appuser:appuser /opt/app
sudo chown -R appuser:appuser /var/log/app
sudo chmod +x /opt/app/app.jar- Service systemd : `/etc/systemd/system/mon-app.service``
[Unit]
Description=Mon App Spring Boot
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
User=appuser
Group=appuser
ExecStart=/usr/bin/java -jar /opt/app/app.jar
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
# Variables d'environnement
Environment=SPRING_PROFILES_ACTIVE=prod
Environment=SERVER_PORT=8080
Environment=DB_HOST=localhost
Environment=DB_PORT=5432
Environment=DB_NAME=myapp
EnvironmentFile=-/opt/app/.env
# Sécurité
WorkingDirectory=/opt/app
PrivateTmp=true
NoNewPrivileges=true
# Logs
SyslogIdentifier=mon-app
[Install]
WantedBy=multi-user.target
- Fichier d'environnement :
/opt/app/.env
# Base de données
DB_USER=app_user
DB_PASSWORD=SuperSecurePassword123!
JWT_SECRET=MonSuperSecretJWT2024!
# CORS pour le frontend
CORS_ALLOWED_ORIGINS=https://mon-app.com,https://www.mon-app.com
# Configuration serveur
LOGGING_LEVEL_ROOT=INFO
LOGGING_FILE_PATH=/var/log/app/app.log
- Gestion du service :
# Recharger systemd
sudo systemctl daemon-reload
# Activer au démarrage
sudo systemctl enable mon-app
# Démarrer le service
sudo systemctl start mon-app
# Vérifier le statut
sudo systemctl status mon-app
# Voir les logs en temps réel
sudo journalctl -f -u mon-app
# Redémarrer
sudo systemctl restart mon-app
# Arrêter
sudo systemctl stop mon-app# Copie vers serveur :
sudo mkdir -p /var/www/mon-app
sudo cp -r dist/mon-app/* /var/www/mon-app/
# Permissions correctes
sudo chown -R www-data:www-data /var/www/mon-app
sudo chmod -R 755 /var/www/mon-app- Via server block HTTPS avec proxy vers JAR :
sudo nano /etc/nginx/sites-available/fullstack-app
server {
# Redirection HTTP → HTTPS
listen 80;
server_name mon-app.com www.mon-app.com;
return 301 https://$server_name$request_uri;
}
server {
# 🔐 HTTPS sécurisé
listen 443 ssl http2;
server_name mon-app.com www.mon-app.com;
# Certificats SSL
ssl_certificate /etc/letsencrypt/live/mon-app.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mon-app.com/privkey.pem;
# Configuration SSL moderne
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Headers de sécurité
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
# 📁 Frontend Angular (fichiers statiques)
root /var/www/mon-app;
index index.html;
# Gestion des routes Angular (SPA)
location / {
try_files $uri $uri/ /index.html;
# Cache pour les fichiers statiques
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
}
}
# 🔗 Proxy vers le JAR Spring Boot
location /api/ {
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_set_header X-Forwarded-Host $server_name;
# Timeouts
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# Pas de cache pour l'API
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# Healthcheck accessible
location /actuator/health {
proxy_pass http://127.0.0.1:8080/actuator/health;
proxy_set_header Host $host;
access_log off;
}
# Logs
access_log /var/log/nginx/mon-app.access.log;
error_log /var/log/nginx/mon-app.error.log;
# Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
}- Finalisation de l'installation :
# Activer le site
sudo ln -s /etc/nginx/sites-available/mon-app /etc/nginx/sites-enabled/
# Tester la configuration
sudo nginx -t
# Recharger Nginx (sans interruption)
sudo systemctl reload nginx
# Redémarrer Nginx
sudo systemctl restart nginx- Via VirtualHost HTTPS :
sudo nano /etc/apache2/sites-available/mon-app-ssl.conf
# Redirection HTTP → HTTPS
<VirtualHost *:80>
ServerName mon-app.com
ServerAlias www.mon-app.com
DocumentRoot /var/www/mon-app
# Redirection forcée vers HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Logs
ErrorLog ${APACHE_LOG_DIR}/mon-app-error.log
CustomLog ${APACHE_LOG_DIR}/mon-app-access.log combined
</VirtualHost>
# Configuration HTTPS principale
<VirtualHost *:443>
ServerName mon-app.com
ServerAlias www.mon-app.com
DocumentRoot /var/www/mon-app
# 🔐 SSL Configuration
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
# Certificats SSL (Let's Encrypt)
SSLCertificateFile /etc/letsencrypt/live/mon-app.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mon-app.com/privkey.pem
# 🔒 Headers de sécurité
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options SAMEORIGIN
Header always set Referrer-Policy strict-origin-when-cross-origin
Header always set X-XSS-Protection "1; mode=block"
# 📁 Frontend Angular
DirectoryIndex index.html
<Directory "/var/www/mon-app">
AllowOverride All
Require all granted
# Configuration pour SPA Angular
RewriteEngine On
# Handle Angular Router
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
# Cache pour les assets statiques
<FilesMatch "\.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$">
ExpiresActive On
ExpiresDefault "access plus 1 year"
Header set Cache-Control "public, immutable"
</FilesMatch>
# Pas de cache pour index.html
<FilesMatch "index\.html$">
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires 0
</FilesMatch>
</Directory>
# 🔗 Proxy vers Spring Boot JAR
ProxyPreserveHost On
ProxyRequests Off
# API Backend
<Location "/api/">
ProxyPass "http://127.0.0.1:8080/api/"
ProxyPassReverse "http://127.0.0.1:8080/api/"
# Headers pour le reverse proxy
ProxyPassReverseAdjustHeaders On
ProxySetHeader Host %{HTTP_HOST}
ProxySetHeader X-Real-IP %{REMOTE_ADDR}
ProxySetHeader X-Forwarded-For %{REMOTE_ADDR}
ProxySetHeader X-Forwarded-Proto %{REQUEST_SCHEME}
ProxySetHeader X-Forwarded-Host %{HTTP_HOST}
# Pas de cache pour l'API
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires 0
</Location>
# Healthcheck
<Location "/api/actuator/health">
ProxyPass "http://127.0.0.1:8080/api/actuator/health"
ProxyPassReverse "http://127.0.0.1:8080/api/actuator/health"
</Location>
# 📊 Compression
<Location "/">
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \
\.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
</Location>
# 📝 Logs
ErrorLog ${APACHE_LOG_DIR}/mon-app-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/mon-app-ssl-access.log combined
# Log niveau SSL (debugging)
LogLevel ssl:warn
</VirtualHost>- Finalisation de l'installation :
# Activer le site
sudo a2ensite mon-app-ssl.conf
# Désactiver le site par défaut si besoin
sudo a2dissite 000-default.conf
# Tester la configuration
sudo apache2ctl configtest
# Recharger Apache
sudo systemctl reload apache2