Spring Boot REST API
-in Docker
serve HTTPS instead of plain HTTP
Local testing and VPS deployment.
1️⃣ Generate an SSL certificate
You have a few options:
A. Self-signed (for testing)
keytool -genkeypair
-alias gnostex
-keyalg RSA
-keysize 2048
-storetype PKCS12
-keystore gnostex.p12
-validity 3650
-dname "CN=yourdomain.com, OU=Dev, O=YourCompany, L=City, S=State, C=US"
-storepass changeit
-keypass changeit
Generates a PKCS12 keystore (gnostex.p12) containing private key + certificate.
Remember the password — you’ll need it in Spring Boot.
B. Production (recommended)
Use Let’s Encrypt with Certbot to generate a real SSL certificate.
Mount the certificate in your container (or use a reverse proxy like Nginx/Traefik).
2️⃣ Configure Spring Boot for HTTPS
Add these properties to application-dev.properties (or application-prod.properties for production):
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:gnostex.p12
server.ssl.key-store-password=changeit
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=gnostex
server.port=8443 → HTTPS default port
server.ssl.key-store → path to your .p12 keystore
server.ssl.key-store-password → the password you used
server.ssl.key-alias → alias of the key in the keystore
If your keystore is outside the JAR (like in Docker), you can use file:/app/certs/gnostex.p12 instead of classpath:.
3️⃣ Add keystore to Docker image
Option 1: Copy into image
//copy SSL certificate into container
COPY certs/gnostex.p12 /app/certs/gnostex.p12
Option 2: Mount as volume (recommended for production)
docker run -d \
-p 8443:8443 \
-v /home/deploy/certs:/app/certs \
-e SPRING_PROFILES_ACTIVE=prod \
-e DB_URL=jdbc:postgresql://host.docker.internal:5432/gnostexdb \
-e DB_USERNAME=gnostex \
-e DB_PASSWORD=gnostex \
ghcr.io/michael-maldo/gnostex-backend-api:latest
4️⃣ Test HTTPS locally
curl -k https://localhost:8443/actuator/health
-k skips verification if self-signed.
If using Let’s Encrypt, -k is not needed.
✅ TL;DR Workflow
- Generate SSL certificate (self-signed or Let’s Encrypt)
- Configure Spring Boot server.ssl.* properties
- Copy or mount keystore into container
5️⃣ Optional: use a reverse proxy (production best practice)
- Instead of letting Spring Boot handle SSL:
- Run Spring Boot with HTTP only (server.port=8080).
- Put Nginx/Traefik/HAProxy in front.
- Let the proxy handle SSL termination with real certificates.
Advantages:
- No need to rebuild Docker image for SSL changes
- Easier certificate renewal (e.g., Certbot)
- Supports multiple apps/domains on same VPS
Expose HTTPS port (8443) in Dockerfile and docker run
https:// endpoint
Reverse Proxy + SSL
-
Spring Boot app stays HTTP only on port 8080 inside Docker.
-
A reverse proxy (Nginx/Traefik/HAProxy)
- sits in front
- listens on HTTPS port 443
- Terminates SSL (handles HTTPS handshake)
- Forwards requests to your Spring Boot app over HTTP (8080)
- Can handle multiple apps/domains on the same VPS
This way:
- You don’t need Spring Boot to know anything about certificates.
- Certificates are easy to renew (Let’s Encrypt).
- CI/CD workflow stays simpler.
Example: Nginx Setup on VPS
- Install Nginx:
sudo dnf install nginx -y # Fedora / CentOS
sudo systemctl enable nginx
sudo systemctl start nginx
- Obtain a certificate (Let’s Encrypt):
sudo dnf install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
-
Certbot will automatically configure Nginx for HTTPS.
-
Nginx reverse proxy config (simplified example):
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# Redirect HTTP to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost: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;
}
}
- Requests come to HTTPS 443 → Nginx → forwards to Spring Boot 8080
Docker Setup
- Spring Boot Docker container stays HTTP:
docker run -d \
--name gnostex-backend-api \
--restart unless-stopped \
-p 8080:8080 \
-e SPRING_PROFILES_ACTIVE=prod \
-e DB_URL=jdbc:postgresql://host.docker.internal:5432/gnostexdb \
-e DB_USERNAME=gnostex \
-e DB_PASSWORD=gnostex \
ghcr.io/michael-maldo/gnostex-backend-api:latest
- Nginx listens on 80/443 and proxies to the container.
Optional: Dockerized Nginx
- Instead of installing Nginx on VPS host, you can run Nginx in a Docker container:
version: "3"
services:
gnostex-backend-api:
image: ghcr.io/michael-maldo/gnostex-backend-api:latest
container_name: gnostex-backend-api
restart: unless-stopped
environment:
SPRING_PROFILES_ACTIVE: prod
DB_URL: jdbc:postgresql://host.docker.internal:5432/gnostexdb
DB_USERNAME: gnostex
DB_PASSWORD: gnostex
ports:
- "8080:8080"
nginx:
image: nginx:latest
container_name: nginx-proxy
restart: unless-stopped
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro
ports:
- "80:80"
- "443:443"
This way your whole stack is containerized.
Advantages of Reverse Proxy Approach
- Benefit Explanation
- Easier SSL Let’s Encrypt handles it automatically
- Multiple apps One Nginx can route many containers/domains
- Simpler Spring Boot App doesn’t need SSL certificates
- Cert renewal Automated via cron or Certbot
✅ TL;DR
- Spring Boot → HTTP only (port 8080)
- Nginx/Traefik → listens HTTPS (443)
- Nginx proxies traffic to Spring Boot (HTTP 8080)
- Use Let’s Encrypt for free SSL
- Your Dockerfile stays mostly unchanged