Deploy Spring Boot applications with Jetty and Docker containers

Intermediate 45 min Apr 11, 2026 230 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Learn to deploy production-ready Spring Boot applications using Jetty embedded server with Docker containerization. This tutorial covers multi-stage Docker builds, production configuration, and deployment with Docker Compose for scalable Java applications.

Prerequisites

  • Root or sudo access
  • At least 4GB RAM
  • Docker and Java 21 installed

What this solves

Spring Boot applications with embedded Jetty server provide a lightweight alternative to traditional Tomcat deployments. Docker containerization enables consistent deployments across environments while multi-stage builds optimize image sizes for production use.

Step-by-step installation

Install Docker and Java development tools

Start by installing Docker Engine and Java JDK for building Spring Boot applications.

sudo apt update && sudo apt upgrade -y
sudo apt install -y docker.io docker-compose openjdk-21-jdk maven
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
sudo dnf update -y
sudo dnf install -y docker docker-compose java-21-openjdk-devel maven
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
Note: Log out and back in after adding your user to the docker group for permissions to take effect.

Verify Java and Docker installation

Confirm all required tools are properly installed and accessible.

java --version
mvn --version
docker --version
docker compose version

Create Spring Boot project structure

Generate a new Spring Boot project with Jetty dependencies using Maven.

mkdir springboot-jetty-app
cd springboot-jetty-app
mvn archetype:generate -DgroupId=com.example -DartifactId=jetty-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Configure Maven dependencies for Spring Boot with Jetty

Replace the default pom.xml with Spring Boot starter dependencies and exclude Tomcat in favor of Jetty.



    4.0.0
    
    
        org.springframework.boot
        spring-boot-starter-parent
        3.2.1
        
    
    
    com.example
    jetty-app
    1.0.0
    jar
    
    
        21
    
    
    
        
            org.springframework.boot
            spring-boot-starter-web
            
                
                    org.springframework.boot
                    spring-boot-starter-tomcat
                
            
        
        
        
            org.springframework.boot
            spring-boot-starter-jetty
        
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
    
    
    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

Create Spring Boot application class

Create the main application class with a sample REST endpoint for testing.

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class Application {
    
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
    @GetMapping("/")
    public String home() {
        return "Spring Boot with Jetty Server - Running in Docker Container";
    }
    
    @GetMapping("/health")
    public String health() {
        return "OK - Jetty Server is running";
    }
}

Configure application properties

Set Jetty server configuration and production settings in application properties.

# Server configuration
server.port=8080
server.jetty.threads.max=200
server.jetty.threads.min=10
server.jetty.threads.idle-timeout=60000
server.jetty.connection-idle-timeout=30000

Actuator endpoints

management.endpoints.web.exposure.include=health,info,metrics management.endpoint.health.show-details=always management.server.port=8081

Logging configuration

logging.level.org.eclipse.jetty=INFO logging.level.com.example=DEBUG logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n

Create multi-stage Dockerfile

Build an optimized Docker image using multi-stage builds to minimize the final image size.

# Build stage
FROM openjdk:21-jdk-slim AS build

WORKDIR /app

Copy pom.xml and download dependencies

COPY pom.xml . RUN apt-get update && apt-get install -y maven RUN mvn dependency:go-offline -B

Copy source code and build application

COPY src ./src RUN mvn clean package -DskipTests

Runtime stage

FROM openjdk:21-jre-slim AS runtime

Create non-root user for security

RUN groupadd -r appgroup && useradd -r -g appgroup appuser

Install curl for health checks

RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* WORKDIR /app

Copy JAR from build stage

COPY --from=build /app/target/jetty-app-1.0.0.jar app.jar

Change ownership to non-root user

RUN chown -R appuser:appgroup /app USER appuser

Expose ports

EXPOSE 8080 8081

Health check

HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -f http://localhost:8081/actuator/health || exit 1

Run application

ENTRYPOINT ["java", "-jar", "-Djava.security.egd=file:/dev/./urandom", "app.jar"]

Create Docker Compose configuration

Set up Docker Compose for easy deployment with environment-specific configurations.

version: '3.8'

services:
  springboot-jetty:
    build:
      context: .
      dockerfile: Dockerfile
    image: springboot-jetty:latest
    container_name: springboot-jetty-app
    ports:
      - "8080:8080"
      - "8081:8081"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - JAVA_OPTS=-Xmx512m -Xms256m
    restart: unless-stopped
    networks:
      - app-network
    volumes:
      - ./logs:/app/logs
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8081/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  nginx:
    image: nginx:alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - springboot-jetty
    restart: unless-stopped
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  logs:
    driver: local

Configure Nginx reverse proxy

Create Nginx configuration to proxy requests to the Spring Boot application with load balancing capabilities.

events {
    worker_connections 1024;
}

http {
    upstream springboot {
        server springboot-jetty:8080;
    }
    
    server {
        listen 80;
        server_name localhost;
        
        # Security headers
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        
        location / {
            proxy_pass http://springboot;
            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;
            
            # Timeouts
            proxy_connect_timeout 30s;
            proxy_send_timeout 30s;
            proxy_read_timeout 30s;
        }
        
        location /actuator/health {
            proxy_pass http://springboot-jetty:8081/actuator/health;
            access_log off;
        }
    }
}

Create production environment configuration

Add production-specific application properties for Docker deployment.

# Production configuration for Docker
server.jetty.threads.max=300
server.jetty.threads.min=20

Logging configuration for production

logging.level.com.example=INFO logging.file.name=/app/logs/application.log logging.logback.rollingpolicy.max-file-size=100MB logging.logback.rollingpolicy.max-history=30

Actuator security

management.endpoints.web.base-path=/actuator management.endpoint.health.show-components=always

Build and deploy the application

Build the Docker images and start the complete application stack.

cd jetty-app

Build the application

docker compose build

Start the services

docker compose up -d

View logs

docker compose logs -f springboot-jetty

Verify your setup

Test the Spring Boot application and verify all components are working correctly.

# Check container status
docker compose ps

Test application endpoint

curl http://localhost/

Check health endpoint

curl http://localhost/actuator/health

View application metrics

curl http://localhost:8081/actuator/metrics

Check Jetty server info in logs

docker compose logs springboot-jetty | grep -i jetty

You should see responses indicating the Spring Boot application is running with Jetty server. The health check should return status "UP" and metrics should show Jetty-specific measurements.

Production optimization

Configure JVM memory settings

Optimize JVM memory allocation for containerized environments.

version: '3.8'

services:
  springboot-jetty:
    environment:
      - JAVA_OPTS=-Xmx1g -Xms512m -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0
      - JVM_ARGS=-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap

Add container resource limits

Set resource constraints to prevent container resource exhaustion.

services:
  springboot-jetty:
    deploy:
      resources:
        limits:
          cpus: '1.5'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

Common issues

SymptomCauseFix
Port binding failedPort already in usesudo netstat -tlnp | grep :8080 to find conflicting process
Application won't startInsufficient memoryIncrease Docker memory limits or reduce -Xmx value
Container exits immediatelyJava application errordocker compose logs springboot-jetty to check startup errors
Health check failingManagement port not accessibleVerify port 8081 is exposed and actuator endpoints enabled
Nginx 502 Bad GatewayBackend connection failedCheck if springboot-jetty container is healthy and network connectivity
Build fails with Maven errorsDependencies not downloadedRun docker compose build --no-cache to rebuild images

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.