Skip to main content

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
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