Deploy Eclipse Jetty application server with SSL/TLS encryption, systemd service management, and production-ready performance optimizations. Configure reverse proxy integration and security hardening for Java web applications.
Prerequisites
- Root or sudo access
- At least 2GB RAM
- Java 17 or later
- Basic understanding of Java web applications
What this solves
Eclipse Jetty is a lightweight, high-performance Java application server and servlet container ideal for deploying Java web applications, REST APIs, and microservices. This tutorial shows you how to install Jetty with SSL certificates, configure it as a systemd service with automatic startup, optimize JVM performance for production workloads, and set up a reverse proxy with Nginx for enhanced security and load distribution.
Step-by-step installation
Update system packages and install Java
Start by updating your system and installing OpenJDK 17, which provides the best performance and long-term support for Jetty.
sudo apt update && sudo apt upgrade -y
sudo apt install -y openjdk-17-jdk wget curl unzip
Create Jetty user and directories
Create a dedicated system user for Jetty to run securely without root privileges. This follows security best practices by isolating the application server.
sudo useradd --system --home /opt/jetty --shell /bin/false jetty
sudo mkdir -p /opt/jetty /var/log/jetty /etc/jetty
sudo chown jetty:jetty /opt/jetty /var/log/jetty
Download and install Jetty
Download the latest stable Jetty release and extract it to the installation directory. We'll use Jetty 12 which supports Jakarta EE and modern Java features.
cd /tmp
wget https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-home/12.0.5/jetty-home-12.0.5.tar.gz
tar -xzf jetty-home-12.0.5.tar.gz
sudo cp -r jetty-home-12.0.5/* /opt/jetty/
sudo chown -R jetty:jetty /opt/jetty
Create Jetty base directory
Set up a Jetty base directory where you'll store your configuration, webapps, and customizations. This separates your configuration from the Jetty installation.
sudo mkdir -p /var/lib/jetty
sudo chown jetty:jetty /var/lib/jetty
sudo -u jetty java -jar /opt/jetty/start.jar --create-startd --add-modules=http,https,deploy,ext,resources,server,webapp,jstl
Configure Jetty base settings
Create the basic configuration for HTTP and HTTPS connectors. This sets up Jetty to listen on standard ports with proper buffer sizes for production use.
# HTTP Connector Configuration
--module=http
jetty.http.port=8080
jetty.http.host=127.0.0.1
jetty.httpConfig.outputBufferSize=32768
jetty.httpConfig.requestHeaderSize=8192
jetty.httpConfig.responseHeaderSize=8192
Generate SSL keystore and configure HTTPS
Create a self-signed certificate for development or prepare the keystore for your production certificate. The keystore stores your SSL certificate and private key.
sudo mkdir -p /etc/jetty/ssl
sudo keytool -genkeypair -alias jetty -keyalg RSA -keysize 2048 -validity 365 \
-dname "CN=example.com,OU=IT,O=Example Corp,L=City,S=State,C=US" \
-keystore /etc/jetty/ssl/keystore.jks -storepass changeit -keypass changeit
sudo chown jetty:jetty /etc/jetty/ssl/keystore.jks
sudo chmod 600 /etc/jetty/ssl/keystore.jks
Configure HTTPS connector
Set up the HTTPS connector with modern security settings including TLS 1.2+ only and secure cipher suites.
# HTTPS Connector Configuration
--module=https
jetty.https.port=8443
jetty.https.host=127.0.0.1
jetty.sslContext.keyStorePath=/etc/jetty/ssl/keystore.jks
jetty.sslContext.keyStorePassword=changeit
jetty.sslContext.keyManagerPassword=changeit
jetty.sslContext.trustStorePath=/etc/jetty/ssl/keystore.jks
jetty.sslContext.trustStorePassword=changeit
jetty.sslContext.excludeProtocols=SSLv2Hello,SSLv3,TLSv1,TLSv1.1
jetty.sslContext.includeCipherSuites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
Configure JVM performance tuning
Create optimized JVM settings for production use including garbage collection tuning, memory allocation, and performance monitoring options.
# Jetty Environment Configuration
JETTY_HOME=/opt/jetty
JETTY_BASE=/var/lib/jetty
JETTY_USER=jetty
JETTY_PID=/var/run/jetty.pid
JETTY_ARGS=jetty.http.host=127.0.0.1 jetty.https.host=127.0.0.1
JVM Options for Production
JAVA_OPTIONS="
-server
-Xms1g
-Xmx2g
-XX:NewRatio=2
-XX:+UseG1GC
-XX:+UseStringDeduplication
-XX:+OptimizeStringConcat
-XX:+UseCompressedOops
-XX:MaxGCPauseMillis=200
-Djava.awt.headless=true
-Dfile.encoding=UTF-8
-Djava.security.egd=file:/dev/./urandom
-Djetty.logs=/var/log/jetty
"
Create systemd service file
Set up Jetty as a systemd service for automatic startup, proper logging, and service management. This ensures Jetty starts on boot and restarts if it crashes.
[Unit]
Description=Jetty Application Server
After=network.target
Wants=network.target
[Service]
Type=forking
User=jetty
Group=jetty
EnvironmentFile=/etc/jetty/jetty.conf
ExecStart=/opt/jetty/bin/jetty.sh start
ExecStop=/opt/jetty/bin/jetty.sh stop
ExecReload=/opt/jetty/bin/jetty.sh restart
PIDFile=/var/run/jetty.pid
SuccessExitStatus=143
TimeoutStopSec=10
Restart=on-failure
RestartSec=5
Security settings
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/jetty /var/log/jetty /var/run
Resource limits
LimitNOFILE=65536
LimitNPROC=4096
[Install]
WantedBy=multi-user.target
Create Jetty startup script
Create a proper startup script that sources the configuration and starts Jetty with the correct user and environment.
#!/bin/bash
Jetty startup script
set -e
Source configuration
[ -f /etc/jetty/jetty.conf ] && . /etc/jetty/jetty.conf
Set defaults
JETTY_HOME=${JETTY_HOME:-/opt/jetty}
JETTY_BASE=${JETTY_BASE:-/var/lib/jetty}
JETTY_USER=${JETTY_USER:-jetty}
JETTY_PID=${JETTY_PID:-/var/run/jetty.pid}
case "$1" in
start)
echo "Starting Jetty..."
cd "$JETTY_BASE"
exec java $JAVA_OPTIONS -jar "$JETTY_HOME/start.jar" \
$JETTY_ARGS --daemon &
echo $! > "$JETTY_PID"
;;
stop)
echo "Stopping Jetty..."
if [ -f "$JETTY_PID" ]; then
kill $(cat "$JETTY_PID")
rm -f "$JETTY_PID"
fi
;;
restart)
$0 stop
sleep 2
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac
Set proper permissions and enable service
Make the startup script executable and enable the systemd service for automatic startup on boot.
sudo chmod +x /opt/jetty/bin/jetty.sh
sudo chown -R jetty:jetty /var/lib/jetty
sudo systemctl daemon-reload
sudo systemctl enable jetty
Configure logging
Set up proper logging configuration for production monitoring and troubleshooting. This creates structured logs with rotation.
# Jetty Logging Configuration
org.eclipse.jetty.LEVEL=INFO
org.eclipse.jetty.server.LEVEL=INFO
org.eclipse.jetty.server.RequestLog.LEVEL=INFO
Console Handler
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
File Handler
java.util.logging.FileHandler.level=INFO
java.util.logging.FileHandler.pattern=/var/log/jetty/jetty.%g.log
java.util.logging.FileHandler.limit=10485760
java.util.logging.FileHandler.count=10
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
Start and test Jetty
Start the Jetty service and verify it's running correctly on both HTTP and HTTPS ports.
sudo systemctl start jetty
sudo systemctl status jetty
Configure reverse proxy with Nginx
Install and configure Nginx
Set up Nginx as a reverse proxy to handle SSL termination, static content serving, and load balancing. This improves security and performance.
sudo apt install -y nginx
Configure Nginx reverse proxy
Create an Nginx virtual host that proxies requests to Jetty while handling SSL termination and adding security headers.
upstream jetty_backend {
server 127.0.0.1:8080;
keepalive 16;
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL Configuration
ssl_certificate /etc/ssl/certs/jetty.crt;
ssl_certificate_key /etc/ssl/private/jetty.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# Security Headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Logging
access_log /var/log/nginx/jetty-access.log;
error_log /var/log/nginx/jetty-error.log;
# Static content handling
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri @jetty;
}
# Proxy to Jetty
location / {
proxy_pass http://jetty_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_cache_bypass $http_upgrade;
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
location @jetty {
proxy_pass http://jetty_backend;
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;
}
}
Enable Nginx configuration and restart
Enable the Jetty site configuration and restart Nginx to apply the changes. For more advanced Nginx configuration, see our Nginx reverse proxy with SSL tutorial.
sudo ln -s /etc/nginx/sites-available/jetty /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
sudo systemctl enable nginx
Security hardening and firewall configuration
Configure firewall rules
Set up firewall rules to allow only necessary traffic and block direct access to Jetty ports from external sources.
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
Configure system resource limits
Set appropriate system resource limits for the Jetty process to prevent resource exhaustion attacks and ensure stable operation.
jetty soft nofile 65536
jetty hard nofile 65536
jetty soft nproc 4096
jetty hard nproc 4096
jetty soft memlock unlimited
jetty hard memlock unlimited
Performance tuning and optimization
Configure thread pool optimization
Optimize Jetty's thread pool settings for your expected load. This configuration handles concurrent requests efficiently without resource waste.
# Thread Pool Configuration
--module=threadpool
jetty.threadPool.minThreads=10
jetty.threadPool.maxThreads=200
jetty.threadPool.idleTimeout=60000
jetty.threadPool.reservedThreads=20
Configure JVM garbage collection monitoring
Add GC logging and monitoring options to track memory usage and optimize garbage collection performance.
# Add to existing JAVA_OPTIONS
JAVA_OPTIONS="$JAVA_OPTIONS
-Xloggc:/var/log/jetty/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=10M
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationStoppedTime
"
Configure system kernel optimization
Optimize kernel parameters for high-performance web serving with proper TCP settings and memory management. For more comprehensive system optimization, see our Linux system performance tuning guide.
# Network Performance Tuning
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_congestion_control = bbr
File and Process Limits
fs.file-max = 2097152
kernel.pid_max = 4194304
Memory Management
vm.swappiness = 1
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
Apply kernel optimizations and restart services
Apply the kernel parameter changes and restart Jetty with the optimized configuration.
sudo sysctl -p /etc/sysctl.d/99-jetty.conf
sudo systemctl restart jetty
sudo systemctl restart nginx
Verify your setup
Test your Jetty installation to ensure all components are working correctly with proper SSL configuration and performance settings.
# Check service status
sudo systemctl status jetty
sudo systemctl status nginx
Verify Jetty is listening on correct ports
sudo netstat -tlnp | grep java
Test HTTP to HTTPS redirect
curl -I http://example.com
Test HTTPS response
curl -k -I https://example.com
Check SSL certificate
openssl s_client -connect example.com:443 -servername example.com
Monitor JVM performance
jstat -gc $(pgrep -f jetty) 5s
Check log files
sudo tail -f /var/log/jetty/jetty.0.log
sudo tail -f /var/log/nginx/jetty-access.log
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Jetty fails to start | Incorrect Java version or missing dependencies | Verify Java 17+ with java --version, check logs in /var/log/jetty/ |
| Port binding errors | Port already in use or permission issues | Check with sudo netstat -tlnp | grep :8080, ensure Jetty runs as jetty user |
| SSL handshake failures | Invalid keystore or weak ciphers | Regenerate keystore, verify cipher suites with openssl s_client |
| 502 Bad Gateway from Nginx | Jetty not responding or connection issues | Check Jetty status, verify upstream configuration, check Nginx error logs |
| High memory usage | Incorrect JVM heap settings | Adjust -Xmx value, monitor with jstat -gc, tune garbage collector |
| Slow response times | Thread pool exhaustion or database connections | Increase thread pool size, optimize database queries, enable connection pooling |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Jetty Installation Script with SSL and Performance Tuning
# Supports Ubuntu, Debian, AlmaLinux, Rocky Linux, CentOS, RHEL, Fedora
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Variables
JETTY_VERSION="12.0.5"
JETTY_USER="jetty"
JETTY_HOME="/opt/jetty"
JETTY_BASE="/var/lib/jetty"
JETTY_LOGS="/var/log/jetty"
SSL_DIR="/etc/jetty/ssl"
DOMAIN="${1:-localhost}"
KEYSTORE_PASS="${2:-changeit}"
# Usage function
usage() {
echo "Usage: $0 [domain] [keystore_password]"
echo "Example: $0 example.com mySecurePassword"
exit 1
}
# Error handling
cleanup() {
echo -e "${RED}[ERROR] Installation failed. Cleaning up...${NC}"
systemctl stop jetty 2>/dev/null || true
systemctl disable jetty 2>/dev/null || true
userdel -r jetty 2>/dev/null || true
rm -rf /opt/jetty /var/lib/jetty /var/log/jetty /etc/jetty /etc/systemd/system/jetty.service
exit 1
}
trap cleanup ERR
# Check if running as root
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}This script must be run as root${NC}"
exit 1
fi
# Detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
JAVA_PKG="openjdk-17-jdk"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
JAVA_PKG="java-17-openjdk java-17-openjdk-devel"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
JAVA_PKG="java-17-amazon-corretto java-17-amazon-corretto-devel"
;;
*)
echo -e "${RED}Unsupported distribution: $ID${NC}"
exit 1
;;
esac
else
echo -e "${RED}Cannot detect distribution${NC}"
exit 1
fi
echo -e "${GREEN}Installing Jetty on $PRETTY_NAME${NC}"
# Step 1: Update system and install Java
echo -e "${YELLOW}[1/9] Updating system and installing Java...${NC}"
$PKG_UPDATE
$PKG_INSTALL $JAVA_PKG wget curl unzip
# Step 2: Create Jetty user and directories
echo -e "${YELLOW}[2/9] Creating Jetty user and directories...${NC}"
useradd --system --home $JETTY_HOME --shell /bin/false $JETTY_USER 2>/dev/null || true
mkdir -p $JETTY_HOME $JETTY_BASE $JETTY_LOGS /etc/jetty $SSL_DIR
chown $JETTY_USER:$JETTY_USER $JETTY_HOME $JETTY_BASE $JETTY_LOGS
# Step 3: Download and install Jetty
echo -e "${YELLOW}[3/9] Downloading and installing Jetty $JETTY_VERSION...${NC}"
cd /tmp
wget -q "https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-home/$JETTY_VERSION/jetty-home-$JETTY_VERSION.tar.gz"
tar -xzf "jetty-home-$JETTY_VERSION.tar.gz"
cp -r "jetty-home-$JETTY_VERSION"/* $JETTY_HOME/
chown -R $JETTY_USER:$JETTY_USER $JETTY_HOME
rm -rf /tmp/jetty-home-*
# Step 4: Create Jetty base directory with modules
echo -e "${YELLOW}[4/9] Setting up Jetty base configuration...${NC}"
cd $JETTY_BASE
sudo -u $JETTY_USER java -jar $JETTY_HOME/start.jar --create-startd --add-modules=http,https,deploy,ext,resources,server,webapp,jstl
# Step 5: Configure HTTP connector
echo -e "${YELLOW}[5/9] Configuring HTTP connector...${NC}"
cat > $JETTY_BASE/start.d/http.ini << 'EOF'
--module=http
jetty.http.port=8080
jetty.http.host=127.0.0.1
jetty.httpConfig.outputBufferSize=32768
jetty.httpConfig.requestHeaderSize=8192
jetty.httpConfig.responseHeaderSize=8192
EOF
# Step 6: Generate SSL certificate and configure HTTPS
echo -e "${YELLOW}[6/9] Generating SSL certificate and configuring HTTPS...${NC}"
keytool -genkeypair -alias jetty -keyalg RSA -keysize 2048 -validity 365 \
-dname "CN=$DOMAIN,OU=IT,O=Example Corp,L=City,S=State,C=US" \
-keystore $SSL_DIR/keystore.jks -storepass $KEYSTORE_PASS -keypass $KEYSTORE_PASS
chown $JETTY_USER:$JETTY_USER $SSL_DIR/keystore.jks
chmod 600 $SSL_DIR/keystore.jks
cat > $JETTY_BASE/start.d/https.ini << EOF
--module=https
jetty.https.port=8443
jetty.https.host=127.0.0.1
jetty.sslContext.keyStorePath=$SSL_DIR/keystore.jks
jetty.sslContext.keyStorePassword=$KEYSTORE_PASS
jetty.sslContext.keyManagerPassword=$KEYSTORE_PASS
jetty.sslContext.trustStorePath=$SSL_DIR/keystore.jks
jetty.sslContext.trustStorePassword=$KEYSTORE_PASS
jetty.sslContext.excludeProtocols=SSLv2Hello,SSLv3,TLSv1,TLSv1.1
jetty.sslContext.includeCipherSuites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
EOF
# Step 7: Configure JVM performance settings
echo -e "${YELLOW}[7/9] Configuring JVM performance settings...${NC}"
cat > /etc/jetty/jetty.conf << EOF
JETTY_HOME=$JETTY_HOME
JETTY_BASE=$JETTY_BASE
JETTY_USER=$JETTY_USER
JETTY_PID=/var/run/jetty.pid
JETTY_LOGS=$JETTY_LOGS
JAVA_OPTIONS="-server -Xms512m -Xmx2g -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+OptimizeStringConcat -Djava.awt.headless=true -Dfile.encoding=UTF-8"
EOF
# Step 8: Create systemd service
echo -e "${YELLOW}[8/9] Creating systemd service...${NC}"
cat > /etc/systemd/system/jetty.service << EOF
[Unit]
Description=Jetty Application Server
After=network.target
After=syslog.target
[Service]
Type=forking
User=$JETTY_USER
Group=$JETTY_USER
EnvironmentFile=/etc/jetty/jetty.conf
ExecStart=/usr/bin/java \$JAVA_OPTIONS -jar $JETTY_HOME/start.jar --base=$JETTY_BASE --logs=$JETTY_LOGS jetty.http.host=127.0.0.1 jetty.https.host=127.0.0.1
PIDFile=/var/run/jetty.pid
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=jetty
[Install]
WantedBy=multi-user.target
EOF
chown -R $JETTY_USER:$JETTY_USER $JETTY_BASE
# Configure firewall
if command -v firewall-cmd >/dev/null 2>&1; then
firewall-cmd --permanent --add-port=8080/tcp --add-port=8443/tcp
firewall-cmd --reload
elif command -v ufw >/dev/null 2>&1; then
ufw allow 8080/tcp
ufw allow 8443/tcp
fi
# Enable and start Jetty service
systemctl daemon-reload
systemctl enable jetty
systemctl start jetty
# Step 9: Verification
echo -e "${YELLOW}[9/9] Verifying installation...${NC}"
sleep 5
if systemctl is-active --quiet jetty; then
echo -e "${GREEN}✓ Jetty service is running${NC}"
else
echo -e "${RED}✗ Jetty service failed to start${NC}"
exit 1
fi
if curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080 | grep -q "404\|200"; then
echo -e "${GREEN}✓ HTTP connector is working${NC}"
else
echo -e "${RED}✗ HTTP connector test failed${NC}"
fi
if curl -s -k -o /dev/null -w "%{http_code}" https://127.0.0.1:8443 | grep -q "404\|200"; then
echo -e "${GREEN}✓ HTTPS connector is working${NC}"
else
echo -e "${RED}✗ HTTPS connector test failed${NC}"
fi
echo -e "${GREEN}Jetty installation completed successfully!${NC}"
echo "HTTP: http://127.0.0.1:8080"
echo "HTTPS: https://127.0.0.1:8443"
echo "Deploy webapps to: $JETTY_BASE/webapps"
echo "Logs: $JETTY_LOGS"
echo "Service: systemctl {start|stop|restart|status} jetty"
Review the script before running. Execute with: bash install.sh