Technical Documentation: jetty/jetty.project
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (README.md)
:warning: The Eclipse Jetty Project does not use the `master` branch
Please use a version specific branch.
Example:
Eclipse Jetty Canonical Repository
This is the canonical repository for the Jetty project, feel free to fork and contribute now!
Submitting a patch or pull request?
Make sure you have an Eclipse Contributor Agreement (ECA) on file.
Project description
Jetty is a lightweight highly scalable java based web server and servlet engine.
Our goal is to support web protocols like HTTP, HTTP/2 and WebSocket in a high volume low latency way that provides maximum performance while retaining the ease of use and compatibility with years of servlet development.
Jetty is a modern fully async web server that has a long history as a component oriented technology easily embedded into applications while still offering a solid traditional distribution for webapp deployment.
Documentation
Project documentation is available on the Jetty Eclipse website.
Documentation Jetty README (`documentation/jetty/README.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jetty Documentation
This project is the root of the Jetty documentation.
The content files in this project get sourced by the Antora playbook in the playbook repository that builds the website.
In order to build the documentation locally, you first need to prepare a jetty-home directory by running the following command from the top-level folder of the Jetty project:
$ mvn install -Dcollector -Pfast -am -pl documentation/jetty
Then you can use the following command from this directory to prepare and run Antora using a preview profile:
$ mvn antora -N
If you don't run the first command, the Antora build will still succeed, but you will get warnings about missing includes for files taken from jetty-home.
The antora:antora goal, which the antora lifecycle invokes, takes advantage of the playbook provider feature so the playbook for this branch can be centrally managed in the playbook repository.
Note that this preview profile does not run the jetty blocks, so you will only see the configuration for those runs in the preview site.
If you want to build the full site, use the build in the playbook repository.
Documentation Jetty Modules Operations Guide Nav (`documentation/jetty/modules/operations-guide/nav.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
.xref:operations-guide:index.adoc[]
- xref:begin/index.adoc[]
- xref:features/index.adoc[]
- xref:howtos/index.adoc[]
- xref:arch/index.adoc[]
- xref:start/index.adoc[]
** xref:start/start-jpms.adoc[] - xref:modules/index.adoc[]
** xref:modules/custom.adoc[]
** xref:modules/standard.adoc[] - xref:deploy/index.adoc[]
- xref:server/index.adoc[]
- xref:protocols/index.adoc[]
- xref:keystore/index.adoc[]
- xref:session/index.adoc[]
- xref:quickstart/index.adoc[]
- xref:annotations/index.adoc[]
- xref:jsp/index.adoc[]
- xref:jstl/index.adoc[]
- xref:jsf-taglibs/index.adoc[]
- xref:jndi/index.adoc[]
- Jetty Security
** xref:security/configuring-form-size.adoc[]
** xref:security/jaas-support.adoc[]
** xref:security/jaspi-support.adoc[]
** xref:security/openid-support.adoc[] - xref:jmx/index.adoc[]
- xref:tools/index.adoc[]
- xref:troubleshooting/index.adoc[]
- xref:xml/index.adoc[]
- xref:glossary.adoc[]
Documentation Jetty Modules Programming Guide Nav (`documentation/jetty/modules/programming-guide/nav.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
.xref:programming-guide:index.adoc[]
- xref:client/index.adoc[]
** xref:client/http.adoc[]
** xref:client/http2.adoc[]
** xref:client/http3.adoc[]
** xref:client/websocket.adoc[]
** xref:client/io-arch.adoc[]
** xref:client/threads.adoc[] - xref:server/index.adoc[]
** xref:server/http.adoc[]
** xref:server/http2.adoc[]
** xref:server/http3.adoc[]
** xref:server/compliance.adoc[]
** xref:server/session.adoc[]
** xref:server/deploy.adoc[]
** xref:server/websocket.adoc[]
** xref:server/fastcgi.adoc[]
** xref:server/io-arch.adoc[]
** xref:server/threads.adoc[] - Maven and Jetty
** xref:maven-jetty/jetty-maven-helloworld.adoc[]
** xref:maven-jetty/jetty-maven-plugin.adoc[]
** xref:maven-jetty/jetty-jspc-maven-plugin.adoc[] - Jetty Architecture
** xref:arch/bean.adoc[]
** xref:arch/threads.adoc[]
** xref:arch/io.adoc[]
** xref:arch/listener.adoc[]
** xref:arch/jmx.adoc[]
** xref:arch/json.adoc[] - xref:troubleshooting/index.adoc[]
** xref:troubleshooting/logging.adoc[]
** xref:troubleshooting/thread-dump.adoc[]
** xref:troubleshooting/state-tracking.adoc[]
** xref:troubleshooting/component-dump.adoc[]
** xref:troubleshooting/debugging.adoc[] - xref:security/index.adoc[]
** xref:security/siwe-support.adoc[]
** xref:security/configuring-form-size.adoc[]
** xref:security/openid-support.adoc[] - Migration Guides
** xref:migration/94-to-10.adoc[]
** xref:migration/11-to-12.adoc[]
** xref:migration/12.0-to-12.1.adoc[]
Documentation Jetty Modules ROOT Pages Index (`documentation/jetty/modules/ROOT/pages/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Eclipse Jetty {page-version}
This is the main documentation page for the Eclipse Jetty Project.
Jetty provides a highly scalable and memory-efficient web server and Servlet container, supporting web protocols such as HTTP/1.1, HTTP/2, HTTP/3 and WebSocket.
Furthermore, Jetty offers integrations with many other technologies, such as OSGi, JMX, JNDI, JAAS, CDI, etc. and with the relevant Jakarta EE technologies.
Jetty is open source and are freely available for commercial use and distribution under either the link:https://www.eclipse.org/legal/epl-2.0/[Eclipse Public License v2] or the link:https://www.apache.org/licenses/LICENSE-2.0[Apache License v2].
Jetty can either be used as a standalone server to deploy web applications, or as a library that can be used in your code as a dependency.
.Jetty Versions and Compatibilities
[cols="1a,1a,1a,1a", options="header"]
|===
| Jetty Version | Required Java Version | Jakarta EE Version | Status
| Jetty 12.1.x | Java 17 | Jakarta EE11, EE10, EE9, EE8 | Stable
| Jetty 12.0.x | Java 17 | Jakarta EE10, EE9, EE8 | Stable
| Jetty 11.0.x | Java 11 | Jakarta EE9 | EOL (see link:https://github.com/jetty/jetty.project/issues/13918[#13918])
| Jetty 10.0.x | Java 11 | Jakarta EE8 | EOL (see link:https://github.com/jetty/jetty.project/issues/13918[#13918])
| Jetty 9.4.x | Java 8 | Jakarta EE7 | EOL (see link:https://github.com/jetty/jetty.project/issues/13918[#13918])
|===
== xref:operations-guide:index.adoc[]
The Operations Guide targets sysops, devops, and developers who want to install Jetty as a standalone server to deploy web applications.
== xref:programming-guide:index.adoc[]
The Programming Guide targets developers who want to use the Jetty libraries in their applications, and advanced sysops/devops that want to customize the deployment of web applications.
Documentation Jetty Modules Operations Guide Pages Glossary (`documentation/jetty/modules/operations-guide/pages/glossary.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[glossary]
= Glossary
This glossary defines common terms used throughout the Jetty documentation.
[glossary]
[[bean]]
Bean::
A component instance added to a ContainerLifeCycle container.
Beans can be managed (lifecycle tied to container), unmanaged (independent lifecycle), or POJO (plain objects without lifecycle).
See xref:programming-guide:arch/bean.adoc[] for details.
[[connector]]
Connector::
A component that listens on a network port for incoming connections.
Connectors are associated with one or more ConnectionFactory instances that create protocol-specific connections (HTTP/1.1, HTTP/2, HTTP/3).
See xref:server/index.adoc[] for server configuration.
[[container-lifecycle]]
ContainerLifeCycle::
A LifeCycle implementation that can contain other components (beans).
It manages the lifecycle of its managed beans, starting and stopping them together with the container.
See xref:programming-guide:arch/bean.adoc[] for the component architecture.
[[context-handler]]
ContextHandler::
A Handler that scopes HTTP requests to a specific context path.
It provides the foundation for web application deployment, managing attributes, MIME types, and class loaders.
See xref:deploy/index.adoc[] for deployment information.
[[context-xml]]
Context XML file::
An XML configuration file used to deploy web applications in Jetty.
Context XML files use Jetty's XML configuration syntax to instantiate and configure ContextHandler instances.
See xref:xml/index.adoc[] for XML configuration syntax and xref:deploy/index.adoc[] for deployment examples.
[[handler]]
Handler::
The fundamental abstraction for processing HTTP requests in Jetty.
Handlers form a tree structure where requests flow from the server through various handlers.
A handler returns true if it handled the request, false otherwise.
See xref:programming-guide:server/index.adoc[] for the server programming guide.
[[jetty-base]]$JETTY_BASE::
The directory containing your Jetty server customizations and configurations.
You can have multiple $JETTY_BASE directories, each with different configurations, all referencing the same $JETTY_HOME.
See xref:arch/index.adoc#jetty-base[Architecture Overview] for details.
[[jetty-home]]$JETTY_HOME::
The directory containing the Jetty distribution binaries and default configuration.
This directory should not be modified; all customizations should go in $JETTY_BASE.
See xref:arch/index.adoc#jetty-base[Architecture Overview] for details.
[[lifecycle]]
LifeCycle::
An interface implemented by Jetty components that can be started and stopped.
Components implementing LifeCycle participate in the container's lifecycle management.
See xref:programming-guide:arch/bean.adoc#lifecycle[Component Lifecycle] for details.
[[module]]
Module::
A reusable unit that provides one or more Jetty features.
Modules are enabled in $JETTY_BASE and declare dependencies on other modules.
Examples include http, https, http2, deploy, and logging.
See xref:modules/index.adoc[] for the module system documentation.
[[server]]
Server::
The root component of a Jetty server application.
It contains connectors, handlers, and thread pools, forming the top of the component tree.
See xref:server/index.adoc[] for server configuration.
[[server-connector]]
ServerConnector::
The standard TCP/IP connector implementation for accepting network connections.
It supports multiple protocols through ConnectionFactory instances.
See xref:server/index.adoc[] for connector configuration.
[[thread-pool]]
ThreadPool::
A component that manages worker threads for processing requests.
The default implementation is QueuedThreadPool.
See xref:programming-guide:arch/threads.adoc[] for thread architecture details.
[[web-application]]
Web Application::
A collection of code, resources, and configuration deployed to a Jetty server.
Web applications can be Jakarta EE applications (WAR files), Jetty Core applications (using Handler APIs), or static file applications.
Each web application is deployed to a specific context path.
See xref:deploy/index.adoc[] for deployment options.
[[webapp-context]]
WebAppContext::
A ContextHandler subclass specifically for Jakarta EE web applications.
It handles WAR file extraction, web.xml parsing, and servlet lifecycle management.
See xref:deploy/index.adoc[] for deployment information.
Documentation Jetty Modules Operations Guide Pages Index (`documentation/jetty/modules/operations-guide/pages/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[reftext=Operations Guide]
= Jetty {page-version} Operations Guide
The Eclipse Jetty Operations Guide targets sysops, devops, and developers who want to install Eclipse Jetty as a standalone server to deploy web applications.
Documentation Jetty Modules Programming Guide Pages Index (`documentation/jetty/modules/programming-guide/pages/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[reftext=Programming Guide]
= Jetty {page-version} Programming Guide
The Eclipse Jetty Programming Guide targets developers who want to use the Jetty libraries in their applications.
The Jetty libraries provide the client-side and server-side APIs to work with various web protocols such as HTTP/1.1, HTTP/2, HTTP/3, WebSocket and FastCGI.
You may use the xref:client/index.adoc[Jetty client-side library] in your application to make calls to third party REST services, or to other REST microservices in your system.
Likewise, you may use the xref:server/index.adoc[Jetty server-side library] to quickly create an HTTP or REST service without having to create a full Jakarta EE web application archive file (a +*.war+ file) and without having to deploy it to a Jetty standalone server that you would have to download and install.
This guide will walk you through the design of the Jetty libraries and how to use its classes to write your applications.
== Code Deprecation Policy
As the Jetty code evolves, classes and/or methods are deprecated using the @Deprecated annotation and will be removed in a future Jetty release.
The Jetty release numbering follows this scheme: <major>.<minor>.<micro>. For example, 12.0.5 has major=12, minor=0 and micro=5.
The policy to remove deprecated code is the following:
- Code deprecated in a Jetty release
x.y.zis not removed in subsequent micro releasesx.y.(z+n). - Code deprecated in a Jetty release
x.y.zmay be removed in the next minor releasex.(y+1).0, but only if it has been deprecated for more than six micro releases. - Code deprecated in a Jetty release
x.y.zmay be removed in the next major release(x+1).0.0without restrictions.
For example, let's assume that some code codeA is deprecated in Jetty 12.0.5, and some other code codeB is deprecated in Jetty 12.0.8.
Let's also assume that 12.1.0 (a new minor release) is released after the release of Jetty 12.0.11.
Then, by the rules above:
- Neither
codeAnorcodeBare removed from the Jetty 12.0.x releases. - Code
codeAis removed from Jetty 12.1.0 because it has been deprecated for more than six micro releases, since Jetty 12.1.0 is released after Jetty 12.0.11. - Code
codeBis not removed from Jetty 12.1.0 because it has been deprecated for less than six micro releases.
AscodeBis now part of Jetty 12.1.0, it will not be removed from the Jetty 12.1.x releases.
[NOTE]
There could be rare cases where code (possibly not even deprecated) must be removed earlier than specified above to address security vulnerabilities.
Documentation Jetty Modules Operations Guide Pages Annotations Index (`documentation/jetty/modules/operations-guide/pages/annotations/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Annotations
Enable the {ee-all}-annotations module if your Jakarta EE web application -- or any of its third party libraries -- uses any of the following:
- Annotations:
**@Resource
**@Resources
**@PostConstruct
**@PreDestroy
**@DeclaredRoles
**@RunAs
**@MultipartConfig
**@WebServlet
**@WebFilter
**@WebListener
**@WebInitParam
**@ServletSecurity,@HttpConstraint,@HttpMethodConstraint
**@HandlesTypes javax.servlet.ServletContainerInitializerorjakarta.servlet.ServletContainerInitializer- JSP
[[scanning]]
== Annotation Scanning
According to more recent versions of the Jakarta Servlet Specification, the web.xml file can contain the attribute metadata-complete.
If this is set to true, then no annotation scanning takes place, and your descriptor must contain the equivalent xml statements of any annotations.
If it is metadata-complete=false, or your web.xml predates the inclusion of this attribute, annotation scanning is required to take place.
To prevent annotation scanning you can use the WebAppContext.setConfigurationDiscovered(false) method.
Here's an example context XML file that calls this method:
[,xml,subs=attributes+]
However, despite metadata-complete=true, scanning of classes may still occur because of ServletContainerInitializer.
Classes implementing this interface are found by Jetty using the http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html[javax.util.ServiceLoader] mechanism, and if one is present and it includes the @HandlesTypes annotation, then Jetty must scan the class hierarchy of the web application.
This may be very time-consuming if you have many jars.
Jetty can reduce the time taken by limiting the jars that are scanned.
[[og-container-include-jar-pattern]]
=== The container classpath
By default, Jetty will not scan any classes that are on the container's classpath.
Sometimes, you may have third party libraries on the container's classpath that you need to be scanned.
In this case, use the org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern context attribute to define which container jars and class directories to scan.
The value of this attribute is a regular expression.
Here's an example from a context XML file that includes any jar whose name starts with foo- or bar-, or a directory named classes:
[,xml,subs=attributes+]
Note that the order of the patterns defines the ordering of the scanning of the jars or class directories.
[[og-web-inf-include-jar-pattern]]
=== The Jakarta EE Web Application Class-Path
By default, Jetty will scan all classes from WEB-INF/classes and all jars from WEB-INF/lib according to the order, if any, established by absolute or relative ordering clauses in web.xml.
If your web application contains many jar files that you know do not contain any annotations, you can significantly speed up deployment by omitting them from scanning.
However, be careful if your web application uses a ServletContainerInitializer with a @HandlesTypes annotation that you don't exclude jars that contain classes matching the annotation.
Use the org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern context attribute to define a regular expression for jars and class directories to select for scanning.
Here's an example of a Jetty context XML file that sets a pattern that matches any jar on the web application's class-path that starts with "spring-":
[,xml,subs=attributes+]
=== Multi-threading
By default, Jetty performs annotation scanning in a multi-threaded manner in order to complete it in the minimum amount of time.
If you don't want multi-threaded scanning, you can configure Jetty to revert to single-threaded scanning.
There are several options to configure this:
- Set the context attribute
org.eclipse.jetty.annotations.multiThreadedtofalse - Set the
Serverattributeorg.eclipse.jetty.annotations.multiThreadedtofalse - Set the
Systempropertyorg.eclipse.jetty.annotations.multiThreadedtofalse
Method 1 will only affect the current webapp.
Method 2 will affect all web applications deployed to the same Server instance.
Method 3 will affect all web applications deployed in the same JVM.
By default, Jetty will wait a maximum of 60 seconds for all the scanning threads to complete.
You can set this to a higher or lower number of seconds by doing one of the following:
- Set the context attribute
org.eclipse.jetty.annotations.maxWait - Set the
Serverattributeorg.eclipse.jetty.annotations.maxWait - Set the
Systempropertyorg.eclipse.jetty.annotations.maxWait
Method 1 will only affect the current webapp.
Method 2 will affect all web applications deployed to the same Server instance.
Method 3 will affect all web applications deployed in the same JVM.
[[scis]]
== ServletContainerInitializers
The ServletContainerInitializer class can exist in: the container's classpath, the web application's WEB-INF/classes directory, the webapp's WEB-INF/lib jars, or any external extraClasspath that you have configured on the webapp.
The Jakarta Servlet Specification does not define any order in which a ServletContainerInitializer must be called when the web application starts.
By default, Jetty will call them in the following order:
- ServletContainerInitializers from the container's classpath
- ServletContainerInitializers from
WEB-INF/classes - ServletContainerInitializers from
WEB-INF/libjars in the order established in web.xml, or in the order that the SCI is returned by the http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html[javax.util.ServiceLoader] if there is no ordering.
=== Exclusions
By default, as according to the Jakarta Servlet Specification, all ServletContainerInitializer instances that are discovered are invoked.
Sometimes, depending on your requirements, you may need to prevent some being called at all.
In this case, you can define the org.eclipse.jetty.containerInitializerExclusionPattern context attribute.
This is a regular expression that defines http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html[patterns] of classnames that you want to exclude.
Here's an example of setting the context attribute in a context XML file:
[,xml,subs=attributes+]
In this example we exclude all ServletContainerInitializer instances in the com.acme package, and the specific class com.corp.SlowContainerInitializer.
It is possible to use exclusion and ordering together to control ServletContainerInitializer invocation - the exclusions will be applied before the ordering.
=== Ordering
If you need ServletContainerInitializer classes called in a specific order, you can use the context attribute org.eclipse.jetty.containerInitializerOrder.
Set it to a list of comma separated ServletContainerInitializer class names in the order that you want them applied.
You may optionally use the wildcard character +*+ once in the list.
It will match all ServletContainerInitializer classes not explicitly named in the list.
Here is an example context XML file that ensures the com.example.PrioritySCI will be called first, followed by the com.acme.FooSCI, then all other SCIs:
[,xml,subs=attributes+]
Documentation Jetty Modules Operations Guide Pages Arch Index (`documentation/jetty/modules/operations-guide/pages/arch/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Architecture Overview
Jetty is an HTTP server and Servlet Container, and supports deployments of web applications.
The xref:server/index.adoc[Jetty server] listens on one or more network ports using one or more xref:protocols/index.adoc[protocol connectors].
Clients send HTTP requests for specific URIs, such as +https://host/store/cart+.
The HTTP requests arrive to the connectors through the network; the Jetty server processes the requests and, based on their URIs, forwards them to the appropriate xref:deploy/index.adoc[deployed web application].
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
scale 1.25
cloud Internet as internet
rectangle "Jetty Server" as server
rectangle "HTTP/1.1 Connector" as http
rectangle "HTTP/2 Connector" as http2
rectangle "WebApp "Store"" as store
rectangle "WebApp "Catalog"" as catalog
internet -- http internet -- http2 http -- server http2 -- server server -- store server -- catalog
[[concepts]]
== Main Concepts
There are three main concepts on which the Jetty standalone server is based:
- The <<modules,Jetty _module_ system>>, where Jetty modules provides Jetty features.
- The <<jetty-base,
$JETTY_BASEdirectory>>, that provides a place where you configure which Jetty modules you want to enable, configure the properties of each enabled module, and therefore configure the features you need for your web applications. - The <<start,Jetty start mechanism>>, that starts a JVM that runs Jetty with the configuration you specified.
After installing Jetty, you will want to set up a <<jetty-base,$JETTY_BASE directory>> where you configure <<modules,Jetty modules>>.
[[modules]]
== Jetty Modules
The Jetty standalone server is made of Java components that are assembled together, configured and started to provide different features.
A Jetty module provides one or more components that work together to provide typically one feature, although they may provide more than one feature.
A Jetty module is nothing more than Jetty components assembled together like you would do using Java APIs, just done in a declarative way using configuration files.
What you can do in Java code to assemble Jetty components can be done using Jetty modules.
A Jetty module may be dependent on other Jetty modules: for example, the http Jetty module depends on the server Jetty module which in turn depends on the threadpool and logging Jetty modules.
Every feature in a Jetty server is enabled by enabling the corresponding Jetty module(s).
For example, if you enable only the http Jetty module, then your Jetty standalone server will only be able to listen to a network port for clear-text HTTP requests.
It will not be able to process secure HTTP (i.e. https) requests, it will not be able to process WebSocket, or HTTP/2, or HTTP/3 or any other protocol because the correspondent modules have not been enabled.
You can even start a Jetty server without listening on a network port -- for example because you have enabled a custom module you wrote that provides the features you need.
This allows the Jetty standalone server to be as small as necessary: modules that are not enabled are not loaded, don't waste memory, and you don't risk a client using a module that you did not know was even there.
For more detailed information about the Jetty module system, see xref:modules/index.adoc[this section].
[[jetty-base]]
== $JETTY_HOME and $JETTY_BASE
Instead of managing multiple Jetty distributions out of many locations, it is possible to maintain a separation between the binary installation of the standalone Jetty, known as $JETTY_HOME, and the customizations for your specific environment(s), known as $JETTY_BASE.
This separation between the binary installation directory and the specific configuration directory allows managing multiple, different, server configurations, and allows for quick, drop-in upgrades of Jetty.
There should always only be one $JETTY_HOME (per version of Jetty), but there can be many $JETTY_BASE directories that reference it.
This separation between $JETTY_HOME and $JETTY_BASE allows Jetty upgrades without affecting your web applications.$JETTY_HOME contains the Jetty runtime and libraries and the default configuration, while a $JETTY_BASE contains your web applications and any override of the default configuration.
For example, with the $JETTY_HOME installation the default value for the network port for clear-text HTTP is 8080.
However, you may want that port to be 6060, because xref:protocols/index.adoc#proxy[Jetty is behind a load balancer] that is configured to forward to the backend on port 6060.
In this case, you configure the clear-text HTTP port in $JETTY_BASE, not in $JETTY_HOME.
When you upgrade Jetty, you will upgrade only the files in $JETTY_HOME, and all the configuration in $JETTY_BASE will remain unchanged, keeping your clear-text HTTP port at 6060.
Installing the Jetty runtime and libraries in $JETTY_HOME also allows you to leverage file system permissions: $JETTY_HOME may be owned by an administrator user (so that only administrators can upgrade it), while $JETTY_BASE directories may be owned by a less privileged user.
If you had changed the default configuration in $JETTY_HOME, when you upgrade Jetty, say from version 10.0.0 to version 10.0.1, your changes would be lost.
Maintaining all the changes in $JETTY_HOME, and having to reconfigure these with each upgrade results in a massive commitment of time and effort.
To recap:
$JETTY_HOME::
This is the location for the Jetty binaries.$JETTY_BASE::
This is the location for your configurations and customizations to the Jetty binaries.
[[start]]
== Start Mechanism
The Jetty start mechanism provides two features:
- The mean to configure your
$JETTY_BASEby enabling the desired modules, and to display the configuration of your$JETTY_BASE. - The mean to start Jetty itself, by starting a JVM that reads the Jetty configuration in
$JETTY_BASE, which is then executed to assemble and start the Jetty components.
The Jetty start mechanism is invoked by executing $JETTY_HOME/start.jar from within your $JETTY_BASE, and you can think of it as the Jetty command line program, similar to many Unix/Windows command line programs.
For example, you can ask for help:
$ java -jar $JETTY_HOME/start.jar --help
Or you can list all available modules (or only those with a specific tag):
List all the modules.
$ java -jar $JETTY_HOME/start.jar --list-modules=*
List all the modules tagged as "demo".
$ java -jar $JETTY_HOME/start.jar --list-modules=demo
You can enable a module, for example the http module:
$ java -jar $JETTY_HOME/start.jar --add-modules=http
Once you have one or more module enabled, you can display the current configuration, to verify that the configuration is correct:
$ java -jar $JETTY_HOME/start.jar --list-config
You can enable a Jetty demo module, which will deploy a demo web application:
$ java -jar $JETTY_HOME/start.jar --add-modules=demo-simple
Finally, you can start Jetty:
$ java -jar $JETTY_HOME/start.jar
Read more information at the xref:start/index.adoc[Jetty start mechanism section].
Documentation Jetty Modules Operations Guide Pages Begin Index (`documentation/jetty/modules/operations-guide/pages/begin/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Getting Started
If you are new to Eclipse Jetty, read on to download, install, start and deploy web applications to Jetty.
== Quick Setup
Jetty is distributed in an artifact that expands in a directory called $JETTY_HOME, which should not be modified.
Configuration for Jetty is typically done in a directory called $JETTY_BASE.
There may be more than one $JETTY_BASE directories with different configurations.
Jetty supports the deployment of Jakarta {ee-all-caps} web applications, as well as the deployment of Jetty specific web applications, as discussed in xref:deploy/index.adoc[this section].
For example, the following commands can be used to set up a $JETTY_BASE directory that supports deployment of Jakarta {ee-current-caps} +*.war+ files and a clear-text HTTP connector:
$ export JETTY_HOME=/path/to/jetty-home $ mkdir /path/to/jetty-base $ cd /path/to/jetty-base $ java -jar $JETTY_HOME/start.jar --add-modules=http,ee11-deploy
The last command creates a $JETTY_BASE/start.d/ directory and other directories that contain the configuration of the server, including the $JETTY_BASE/webapps/ directory, in which Jakarta {ee-current-caps} +*.war+ files can be deployed.
To deploy Jetty's demo web applications, run this command:
$ java -jar $JETTY_HOME/start.jar --add-module=demos
Now you can start the Jetty server with:
$ java -jar $JETTY_HOME/start.jar
Point your browser at +http://localhost:8080+ to see the demo web applications deployed in Jetty.
The Jetty server can be stopped with kbd:[Ctrl+C] in the terminal window.
The following sections will guide you in details about <<download,downloading>>, <> and <<start,starting>> Jetty, and <<deploy,deploying>> your web applications to Jetty.
Read the xref:arch/index.adoc[Jetty architecture section] for more information about Jetty modules, $JETTY_HOME, $JETTY_BASE and how to customize and start Jetty.
[[download]]
== Downloading Jetty
The Jetty distribution is a file of the form jetty-home-<version>.<ext>, available for download from https://jetty.org/download.html[]
The Jetty distribution is available in both zip and gzip formats; download the one most appropriate for your system, typically zip for Windows and gzip for other operating systems.
[[install]]
== Installing Jetty
After the download, unpacking Jetty will extract the files into a directory called jetty-home-<version>, where <version> is the version of Jetty that you downloaded.
For example, installing Jetty {jetty-version} will create a directory called jetty-home-{jetty-version}.
IMPORTANT: It is important that only stable release versions are used in production environments.
Versions that have been deprecated or are released as Milestones (M), Alpha, Beta or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets.
Unpack Jetty file into a convenient location, such as /opt.
The rest of the instructions in this documentation will refer to this location as $JETTY_HOME, or ${jetty.home}.
CAUTION: For Windows users, you should unpack Jetty to a path that does not contain spaces.
If you are new to Jetty, you should read the xref:arch/index.adoc[Jetty architecture section] to become familiar with the terms used in this documentation.
Otherwise, you can jump to the <<start,section on starting Jetty>>.
[[start]]
== Starting Jetty
Jetty as a standalone server has no graphical user interface; configuring and running the server is done from the command line.
First, create a $JETTY_BASE directory.
$ JETTY_BASE=/path/to/jetty.base $ mkdir $JETTY_BASE $ cd $JETTY_BASE
You will typically start Jetty by executing $JETTY_HOME/start.jar from this directory.
However, if you try to start Jetty from an empty $JETTY_BASE, it will complain that you haven't enabled any modules:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
....
Jetty uses a xref:modules/index.adoc[module system] to configure and assemble the server; these modules are enabled and configured in xref:arch/index.adoc#jetty-base[$JETTY_BASE].
Since the $JETTY_BASE directory you just created is empty, Jetty has no configuration it can use to assemble the server.
NOTE: See the xref:arch/index.adoc[architecture section] of this document for more information on the design of Jetty's module system.
You can explore what modules are available with the --list-modules flag:
$ java -jar $JETTY_HOME/start.jar --list-modules=*
Now try to enable the xref:protocols/index.adoc#http[http] module.
NOTE: If you want to enable support for protocols like secure HTTP/1.1 or HTTP/2 or HTTP/3, or want to configure Jetty behind a load balancer, read xref:protocols/index.adoc[this section].
$ java -jar $JETTY_HOME/start.jar --add-modules=http
[jetty%nowrap]
....
[jetty]
args=--add-modules=http
highlight=([a-z-]+ *transitively enabled)
....
When Jetty enables the http module, it also automatically enables a number of transitive dependencies of the http module, such as the server module, the logging-jetty module, and so on.
You can now start Jetty:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
args=--module=http
highlight=({.*:8080})
....
Jetty is listening on port 8080 for clear-text HTTP/1.1 connections.
But since it has no web applications deployed, it will just reply with 404 Not Found to every request.
Before you <<deploy,deploy your first web application>>, take a moment to see what happened to the $JETTY_BASE directory once you enabled the http module:
[source]
$JETTY_BASE
├── resources
│ └── jetty-logging.properties <1>
└── start.d <2>
├── bytebufferpool.ini
├── http-config.ini
├── http.ini <3>
├── scheduler.ini
├── server.ini
└── threadpool.ini
<1> The resources/jetty-logging.properties file configures the server's logging level; this file was auto-generated when the jetty-logging module was activated as a transitive dependency of the http module.
<2> The start.d/ directory contains the +*.ini+ configuration files for any modules you have enabled, either explicitly or transitively.
<3> The start.d/http.ini file is the http module configuration file, where you can specify values for the xref:modules/standard.adoc#http[http module properties].
[NOTE]
Jetty generates `+*.ini+` configuration files in `start.d/` also for modules enabled as transitive dependencies that have an xref:modules/index.adoc#directive-ini-template[`+[ini-template]+` directive].
In the http.ini file you can find the following (among other contents):
.http.ini [source]
--module=http <1>
jetty.http.port=8080 <2>
...
<1> This line enables the http module and should not be modified.
<2> This commented line specifies the default value for the jetty.http.port property, which is the network port that Jetty uses to listen for clear-text HTTP connections.
Try changing the default port.
Open http.ini, uncomment the line containing jetty.http.port=, and change its value to 9999:
.http.ini
--module=http jetty.http.port=9999 ...
If you restart Jetty, it will use this new value:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
args=--module=http jetty.http.port=9999
highlight=({.*:9999})
....
You can also specify the value of a module property when you start up Jetty.
A property value specified on the command-line in this way will override the value configured in a module's +*.ini+ file.
$ java -jar $JETTY_HOME/start.jar jetty.http.port=8080
[jetty%nowrap]
....
[jetty]
args=--module=http jetty.http.port=8080
highlight=({.*:8080})
....
For more detailed information about the Jetty start mechanism, you can read the xref:arch/index.adoc#start[Jetty start mechanism] section.
[[deploy]]
== Deploying Web Applications
Deployments of web applications in Jetty is detailed in xref:deploy/index.adoc[this section].
Each web application is deployed to a specific environment, such as the old Java EE 8, or Jakarta {ee-current-caps}, or Jetty specific environments.
Jetty supports simultaneous deployment of web applications each to a possibly different environment, for example an old Java EE 8 web application alongside a new Jakarta {ee-current-caps} web application.
In the following sections you can find simple examples of deployments of Jakarta {ee-current-caps} web applications.
[[deploy-war]]
=== Deploying +*.war+ Files
A Jakarta {ee-current-caps} web application is packaged in either a +*.war+ file or in a directory with the structure of a +*.war+ file.
[NOTE]
Recall that the structure of a +*.war+ file is as follows:
[source]
mywebapp.war
├── index.html <1>
└── WEB-INF <2>
├── classes/ <3>
├── lib/ <4>
└── web.xml <5>
<1> Publicly accessible resources such as `+*.html+`, `+*.jsp+`, `+*.css+`, `+*.js+` files, etc. are placed in `+*.war+` or in sub-directories of the `+*.war+`. <2> `WEB-INF` is a special directory used to store anything related to the web application that must not be publicly accessible, but may be accessed by other resources. <3> `WEB-INF/classes` stores the web application's compiled `+*.class+` files <4> `WEB-INF/lib` stores the web application's `+*.jar+` files <5> `WEB-INF/web.xml` is the web application deployment descriptor, which defines the components and the configuration of your web application.
To deploy a Jakarta {ee-current-caps} web application, you need to enable the xref:modules/standard.adoc#eeN-deploy[{ee-current}-deploy module].
[NOTE]
The following examples assume you are deploying a Jakarta {ee-current-caps} web application; for other versions of Jakarta EE, or for Jetty web applications, make sure to activate the corresponding deploy module.
Refer to the section about xref:deploy/index.adoc[deployment] for further information about how to deploy to different environments.
[source,subs=attributes+]
$ java -jar $JETTY_HOME/start.jar --add-modules={ee-current}-deploy
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http
args=--add-modules={ee-current}-deploy
....
The {ee-current}-deploy module creates $JETTY_BASE/webapps, which is the directory where Jetty looks for any +*.war+ files or web application directories to deploy.
Activating one of Jetty's {ee-all}-deploy modules enables web application deployment for that specific environment.
Whether these web applications are served via clear-text HTTP/1.1, or secure HTTP/1.1, or secure HTTP/2, or HTTP/3 (or even all of these protocols) depends on whether the correspondent Jetty protocol modules have been enabled.
Refer to the xref:protocols/index.adoc[section about protocols] for further information.
Now you're ready to copy a web application to the $JETTY_BASE/webapps directory.
You can use one of the demos shipped with Jetty:
[source,subs=attributes+]
$ java -jar $JETTY_HOME/start.jar --add-modules={ee-current}-demo-simple
The $JETTY_BASE directory is now:
[source,subs=attributes+]
$JETTY_BASE
├── resources
│ └── jetty-logging.properties
├── start.d
│ ├── ...
│ ├── {ee-current}-deploy.ini
│ ├── {ee-current}-demo-simple.ini
│ └── http.ini
└── webapps
└── {ee-current}-demo-simple.war
Now start Jetty:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http,deploy,{ee-current}-demo-simple
highlight=WebAppContext
....
Note the highlighted line that logs the deployment of {ee-current}-demo-simple.war.
Now you can access the web application by pointing your browser to pass:a[http://localhost:8080/{ee-current}-demo-simple].
[[deploy-war-advanced]]
=== Advanced Deployment
If you want to customize the deployment of your web application -- for example, by specifying a contextPath different from the file/directory name, or by specifying JNDI entries, or by specifying virtual hosts -- read xref:deploy/index.adoc[this section].
Documentation Jetty Modules Operations Guide Pages Deploy Index (`documentation/jetty/modules/operations-guide/pages/deploy/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Web Application Deployment
The Jetty server supports the deployment of these types of web applications:
- <<web-application-format-jakarta,Jakarta EE 9 to Jakarta {ee-current-caps} web applications>> -- web applications written using the corresponding Servlet (and associated specifications) in the
+jakarta.*+packages. - <<web-application-format-jakarta,Java EE 8 web applications>> -- web applications written using the Servlet 4.0 (and associated specifications) in the
+javax.*+packages. - <<web-application-format-core,Jetty Core web applications>> -- web applications written against the Jetty
HandlerAPIs, without any Servlet dependencies. - <<web-application-format-context,Jetty
ContextHandlerweb applications>> -- web applications made of JettyHandlers shipped with the Jetty libraries. - <<web-application-format-static,Jetty Static web applications>> -- web applications made of static files only.
In the following, the term "web application" is used to refer to either a Jetty Static web application, or Jetty Core web application, or Jetty ContextHandler web application, or Java EE 8 web application or Jakarta EE 9 to Jakarta {ee-current-caps} web application, unless specified otherwise.
Also, in the following, references to "Jakarta EE" refer to both Java EE and Jakarta EE, unless specified otherwise.
The Jetty server deploys each web application to a specific environment.
The available environments are:
- The
staticenvironment, for Jetty Static web applications. - The
coreenvironment, for Jetty Core web applications, and JettyContextHandlerweb applications. - The
{ee-all}environments, for Jakarta EE web applications.
You can simultaneously deploy an old Java EE 8 web application, say old-ee8.war, alongside a new Jakarta {ee-current-caps} web application, say new-{ee-current}.war, alongside a web application that only uses the Jetty Core Handler APIs, say backoffice-core.xml, all in the same Jetty server.
For each specific environment there is a specific deploy module that must be enabled:
- For the
staticenvironment, the xref:modules/standard.adoc#static-deploy[static-deploy] module. - For the
coreenvironment, the xref:modules/standard.adoc#core-deploy[core-deploy] module. - For the
{ee-all}environments, the corresponding xref:modules/standard.adoc#eeN-deploy[{ee-all}-deploy] module.
Each of these modules provides environment specific features, such as library dependencies and default configuration.
The Jakarta EE deploy modules provide the corresponding Jakarta EE APIs and the Jetty implementation of those APIs.
For example, you can enable the {ee-current}-deploy module in the following way:
[source,bash,subs=attributes+]
$ java -jar $JETTY_HOME/start.jar --add-modules={ee-current}-deploy
All deploy modules depend on the xref:modules/standard.adoc#deployment-scanner[deployment-scanner] module, that scans <<monitored-directories,monitored directories>> for <<web-application-files,web applications>> to deploy, and for <<environment-configuration,environment configuration>> files to process.
NOTE: While you can have many deploy modules enabled, one for each environment, there is only one deployment-scanner module that scans the monitored directories.
By default, for security reasons, web applications are only deployed at server startup from the $JETTY_BASE/webapps directory.
However, you can configure the deployment-scanner module to deploy web applications from a <<monitored-directories,different deploy directory>>, and/or to deploy/undeploy web applications as they are moved to/removed from the deploy directory (<<hot-cold,hot deployment>>).
[[monitored-directories]]
== Monitored Directories
The deployment-scanner module scans the web applications deploy directory (or directories) specified by the jetty.deploy.webappsDir property, by default $JETTY_BASE/webapps, for web applications to deploy.
The directory specified by the jetty.deploy.environmentsDir property, by default $JETTY_BASE/environments, is also scanned for configuration files that apply to each environment, and therefore to all web applications deployed to that environment.
[[web-application-files]]
== Web Application Files
A web application basefile can be:
- A <<context-xml, Jetty context XML file>>, for Jetty Static, Jetty Core and Jakarta EE web applications.
- A
+*.war+file, for Jakarta EE web applications. - A directory, for Jetty Static, Jetty Core and Jakarta EE web applications.
A web application has a basename derived either from the basefile described above, that is either from the Jetty context XML file name, from the +*.war+ file name, or from the directory name.
For example, for the Jetty context XML file old-site.xml, the web application basename is old-site.
For the file myapp.war, the basename is myapp.
For the directory shop-app/ the basename is shop-app.
Web applications may have an associated .properties configuration file, for example old-site.properties or shop-app.properties.
This .properties file contains properties that influence the deployment of the web application, for example by declaring its environment, as described <<rules-environment,in this section>>.
A web application .properties configuration file can specify the following properties:
environment=<environment>, to specify the web application environment.jetty.deploy.contextPath=<contextPath>, to specify the web applicationcontextPath(see also <<rules-context-path,this section>>).jetty.deploy.baseResource=, to specify the web application base resource directory.
The web application base resource directory can be outside of$JETTY_BASE/webapps.jetty.deploy.baseResource.dirAllowed=, to specify whether directory listing for the base resource directory is allowed (by defaulttrue).
[[web-application-format]]
== Web Application Format
[[web-application-format-jakarta]]
=== Jakarta EE Web Application Format
For Jakarta EE web applications, the deployment unit is the usual +*.war+ file or a directory with a +*.war+ structure.
Like for the <<web-application-format-core,Jetty Core web application format>>, the +*.war+ file or a directory can contain an optional in-application <<jetty-web-xml,Jetty context XML file>> under the WEB-INF directory, that allows you to configure the web application deployment.
[[web-application-format-core]]
=== Jetty Core Web Application Format
For Jetty Core web applications, the web application format is a directory with the following structure:
[,bash]
core-app ├── static # Static files are served from this directory. │ ├── css │ │ └── styles.css │ └── index.html ├── classes # Where web application Java classes reside. │ └── com │ └── acme │ └── AcmeHandler.class ├── lib # Where web application Java libraries reside. │ └── acme-util.jar └── jetty-web.xml # Web application specific configuration.
The structure is similar to that of a +*.war+ file.
A notable difference with +*.war+ files is that static files are only served from the static/ directory (with the static/ prefix removed).
This means that files in the directory root, or under any other directory that is not static/, are hidden and if requested they will result in a 404 Not Found response.
If the static/ directory is missing, then no static files can be served, and therefore all requests are processed dynamically by the Handlers configured in the web application.
Since static files can only be served from the static/ directory, the classes/ and lib/ directories are implicitly hidden, as well as any other directory such as includes/ or fragments/, and any file in the directory root.
The classes/ directory stores the web application's +*.class+ files, while the lib/ directory stores the web application's libraries, typically +*.jar+ files.
Both these directories are optional.
The <<jetty-web-xml,jetty-web.xml>> file is an optional in-application Jetty context XML file, that allows you to configure the web application deployment.
[[web-application-format-context]]
=== Jetty ContextHandler Web Application Format
For Jetty ContextHandler web applications, the web application format is just a Jetty XML file, that contains references to Jetty Handlers shipped with the Jetty libraries.
Refer to xref:programming-guide:server/http.adoc#handler-use[this section] for the available Jetty Handlers.
For example, you can use xref:programming-guide:server/http.adoc#handler-use-moved[MovedContextHandler] to redirect an old issue-tracking website at bugs.acme.org to the new issue-tracking website at github.com:
$JETTY_BASE/webapps └── bugs.acme.org.xml
.bugs.acme.org.xml [,xml]
In the example above, file $JETTY_BASE/webapps/bugs.acme.org.xml specifies a web application deployed under virtual host bugs.acme.org at context path /.
The web application is a MovedContextHandler that redirects with HTTP status code 301 (a permanent redirect).
Every request to +http://bugs.acme.org/<any-path-or-query>+ will be redirected to +https://github.com/acme/acme/issues+.
Another example is the use of xref:programming-guide:server/http.adoc#handler-use-context[ContextHandler] in conjunction with xref:programming-guide:server/http.adoc#handler-use-rewrite[RewriteHandler] to rewrite old documentation URIs to new documentation URIs:
$JETTY_BASE/webapps └── docs.project.org.xml
.docs.project.org.xml [,xml]
In the example above, file $JETTY_BASE/webapps/docs.project.org.xml specifies a web application deployed under virtual host docs.project.org at context path /.
The web application is a ContextHandler with a child RewriteHandler that rewrites old documentation URIs such as /docs/#_proj-intro to /proj-intro using a regular expression rewrite rule.
[[web-application-format-static]]
=== Jetty Static Web Application Format
For Jetty Static web applications, the web application format is just a directory, and any file in that directory and any subdirectory is served when requested with the proper request URI -- no files are hidden.
For example, with the following directory structure:
$JETTY_BASE/webapps
└── static-app
├── css/
│ └── styles.css
└── index.html
Requests to +http://localhost:8080/static-app/index.html+ and +http://localhost:8080/static-app/css/style.css+ will serve the correspondent files.
A request to +http://localhost:8080/static-app/css/+ will list the content of the directory.
To disable directory listing, create a web application <<web-application-files,properties file>> with the following content:
.static-app.properties [,properties]
Specifies the environment.
environment=static
Disables directory listing.
jetty.deploy.baseResource.dirAllowed=false
[[hot-cold]]
== Hot vs Cold Deployment
You can configure the deployment-scanner module to scan the <<monitored-directories, monitored directories>> every N seconds, where N is configured via the jetty.deploy.scanInterval property.
By default, the scan interval is 0 seconds, which means cold deployment, where the scanning is only performed once, at server startup.
This means that to deploy a new web application, or redeploy/undeploy an existing web application, you will need to stop and restart the Jetty server.
Setting the scan interval to a value greater than zero means that hot deployment is enabled.
The <<monitored-directories, monitored directories>> are scanned periodically for file changes.
When a file is added/changed/removed from the web applications deploy directory (by default $JETTY_BASE/webapps), then the correspondent web application is processed for deploy/redeploy/undeploy with the <<rules,deployment rules>> detailed below.
When a file is added/changed/removed from the environments directory (by default $JETTY_BASE/environments), the file is processed and all web applications deployed to that specific environment are redeployed.
The following command line enables hot deployment by specifying the jetty.deploy.scanInterval property on the command line, and therefore only for this particular run:
$ java -jar $JETTY_HOME/start.jar jetty.deploy.scanInterval=5
To make hot deployment configuration persistent, you need to edit the $JETTY_BASE/start.d/deployment-scanner.ini module configuration file, and uncomment the property jetty.deploy.scanInterval and change the value to 5 seconds:
.deployment-scanner.ini [source,subs=+quotes]
--module=deployment-scanner
#jetty.deploy.scanInterval=5# ...
When hot deployment is enabled, the scanner may detect changes to multiple files, and will process the changes in the following way:
- Undeploy the web applications that have been removed, if any, in basename [.underline]#reverse# alphabetical order.
- Redeploy the web applications that have been modified, if any, in basename alphabetical order.
- Deploy the web applications that have been added, if any, in basename alphabetical order.
[[rules]]
== Deployment Rules
For <<hot-cold,_cold_ deployment>>, the presence of a web application <<web-application-files,_basefile_>> causes its deployment at server startup.
For <<hot-cold,_hot_ deployment>> the following rules apply:
- Adding a new web application basefile that refers to a new basename to the web applications deploy directory (by default
$JETTY_BASE/webapps) causes the deployment of the new web application.
For example, addingmywebapp.warto an empty$JETTY_BASE/webapps. - Adding a new web application basefile (such as
mywebapp.xml), or a web application properties file (such asmywebapp.properties) to the web applications deploy directory that refers to an existing basename causes the redeployment of the web application.
For example, addingmywebapp.xmlormywebapp.propertieswhenmywebapp.waralready exists. - Changing a file that refers to a basename causes the redeployment of the web application.
For example, editing or changingmywebapp.xml,mywebapp.warormywebapp.properties. - Removing some, but not all, of the files that refer to the same basename causes the redeployment of the web application.
For example, removingmywebapp.xmlormywebapp.properties, but leavingmywebapp.war. - Removing all the files that refer to the same basename causes the undeployment of the web application.
For example, removingmywebapp.xml,mywebapp.warandmywebapp.properties.
NOTE: When a web application is deployed as a directory (not as a file), it is not possible to change the directory (for example using the touch command) to cause the redeployment of the web application.
Modification of the files inside the web application directory is not detected as a change.
You must add at least a .properties file (even empty), and touch it to cause redeployment.
In the presence of multiple web application __basefile__s that refers to the same basename, for example when both mywebapp.xml and mywebapp.war exist, or when both mywebapp.war and mywebapp/ exist, then the following rules apply:
- If
.xmlexists, it has precedence over.warand/, so only.xmlwill be considered for deployment.
This allows the XML file to reference the+*.war+file or directory and avoid that the web application is deployed twice. - Otherwise, if
.warexists, it has precedence over/, so only the+*.war+file will be considered for deployment.
This allows the directory with the same basename to be the+*.war+file unpack location and avoid that the web application is deployed twice. - Otherwise,
/exists and will be considered for deployment.
[[rules-context-path]]
=== Context Path Resolution
When a web application is deployed (or redeployed), the web application contextPath is derived from the <<web-application-files,web application files>>, with the following rules:
- If
.xmlexists, it is processed and the directives contained in the XML file can set thecontextPathto any value (including one that is different from the basename). - If
.propertiesexists, then thecontextPathis set to the value of thejetty.deploy.contextPathproperty, if it is present in.properties. - If the basename is
ROOT, case-insensitive, thecontextPathis/, and the web application is reachable at+http://localhost:8080/+. - Otherwise, the
contextPathis the basename, and the web application is reachable at+http://localhost:8080/+.
[[rules-environment]]
=== Environment Resolution
A web application is always deployed to a specific environment, which is either configured explicitly for the web application or set to the default environment.
You must always enable at least one deploy module, otherwise no web application can be deployed.
[[rules-environment-single-deployer]]
==== Single Deployer Environment Resolution
If only a single specific deploy module is enabled, for example {ee-current}-deploy, then its environment is the default environment and applications will be deployed to that environment without any additional configuration.
If a web application <<web-application-files,properties file>> exists, and it specifies the environment property, then its value must specify the same environment as the deploy module, otherwise the deployment will fail.
[CAUTION]
Make sure that you do not inadvertently mix a deploy module for one environment with a web application of a different environment.
For example, if you have a Jetty `core` web application in directory `core-app/`, and you enable the `static-deploy` module, then the `core-app/` directory will be interpreted as a `static` web application, and files from the `core-app/classes/` directory (that are normally hidden and not served) will be served as static files.
TIP: It is good practice to always specify the web application <<web-application-files,properties file>> and specify the environment property, to avoid deployment of your web applications to an unexpected environment.
[[rules-environment-multiple-deployers]]
==== Multiple Deployers Environment Resolution
If multiple deployer modules are enabled, then the default environment is (in order):
- The most recent Jakarta EE environment of the
{ee-all}-deploymodules that are enabled, if any. - Otherwise, the
coreenvironment, if thecore-deploymodule is enabled. - Otherwise, the
staticenvironment, if thestatic-deploymodule is enabled.
For example, if core-deploy, ee9-deploy and the {ee-current}-deploy modules are enabled, then {ee-current} is the default environment, to which applications will be deployed unless otherwise configured (see below).
To configure a specific environment for an application, you add a web application <<web-application-files,properties file>> and specify the environment property.
For example, an application deployed to $JETTY_BASE/webapps/my-ee9-app.war is configured with the file $JETTY_BASE/webapps/my-ee9-app.properties, with the following content:
.my-ee9-app.properties [,properties]
environment=ee9
TIP: In case of multiple deploy environments, it is good practice to always specify the web application <<web-application-files,properties file>> for your web applications, and specify the environment property, to avoid deployment of your web applications to an unexpected environment.
[CAUTION]
If you do not specify the environment property in the web application <<web-application-files,properties file>> for your web applications, then the deployer for the default environment will be used.
For example, if the {ee-current}-deploy and the ee9-deploy module are enabled, and you deploy a Jakarta EE 9 web application without the +*.properties+ file, then it will be deployed to the (default) {ee-current} environment, with unspecified results.
This unspecified deployment may not work as the Jakarta EE 9 web application may use APIs that have been removed in {ee-current-caps}, causing an error at runtime.
Also in case of multiple deployers, if a web application <<web-application-files,properties file>> specifies an environment property, and the corresponding deploy module is not enabled, the deployment will fail.
[[context-xml]]
== Deploying Jetty Context XML Files
A Jetty context XML file is a xref:xml/index.adoc[Jetty XML file] that allows you to customize the deployment of web applications.
NOTE: Recall that the <<rules,deployment rules>> give priority to Jetty context XML files over +*.war+ files or directories.
To deploy a web application using a Jetty context XML file, simply place the Jetty context XML file in the $JETTY_BASE/webapps directory.
For example, to deploy a Jakarta {ee-current-caps} web application, enable the {ee-current}-deploy module, and add the following Jetty context XML file, named wiki.xml:
.wiki.xml [,xml,subs=attributes+]
The Jetty context XML file may be accompanied by a web application <<web-application-files,properties file>> that specifies the xref:deploy/index.adoc[environment] to use for the deployment:
.wiki.properties [,properties,subs=attributes+]
environment={ee-current}
Refer to <<rules-environment,this section>> for more information about specifying the environment.
The $JETTY_BASE directory would look like this:
[,subs=+attributes]
$JETTY_BASE
├── resources
│ └── jetty-logging.properties
├── start.d
│ ├── ...
│ ├── {ee-current}-deploy.ini
│ └── http.ini
└── webapps
├── wiki.properties
└── wiki.xml
TIP: The +*.war+ file may be placed anywhere in the file system and does not need to be placed in the $JETTY_BASE/webapps directory, as long as you have a Jetty context XML file referencing it.
IMPORTANT: If you place both the Jetty context XML file and the +*.war+ file in the $JETTY_BASE/webapps directory, remember that they must produce the same basename, for example wiki.xml and wiki.war, so that the deployment is performed only once using the Jetty context XML file (and not the +*.war+ file).
You can use the features of xref:xml/index.adoc[Jetty XML files] to avoid to hard-code file system paths or other configurations in your Jetty context XML files, for example by using properties declared in wiki.properties or JVM system properties:
.wiki.xml [,xml,subs=attributes+]
Note how the contextPath is obtained from the wiki.contextPath configuration property (as an alternative to the jetty.deploy.contextPath property specified in <<web-application-files,this section>>), while +*.war+ file path is obtained by resolving the system property webapps.dir that you can specify on the command line when you start Jetty:
.wiki.properties [,properties,subs=+attributes]
environment={ee-current} wiki.contextPath=/wiki
[,bash]
$ java -jar $JETTY_HOME/start.jar -Dwebapps.dir=/opt/myapps
Properties specified in environment properties file (described in <<environment-configuration,this section>>) and in the web application properties file (described in <<web-application-files,this section>>) are available when processing the Jetty context XML file.
Remember that Jetty context XML files in the $JETTY_BASE/webapps directory can only refer to classes present in the environment class-path/module-path, in the server class-path/module-path, and in the JVM class-path/module-path.
For more information about the Jetty class loader hierarchy, see xref:start/index.adoc#start-class-path[this section].
If you need to configure the deployment of your web application referring to web application specific classes, use the in-application Jetty context XML file, as described in <<jetty-web-xml,this section>>.
[[environment-configuration]]
== Environment Configuration
Environments can be configured via xref:xml/index.adoc[Jetty XML files] or +*.properties+ files placed in the $JETTY_HOME/environments directory.
Each environment configuration is applied to all web applications deployed/redeployed to that environment.
The environment configuration files must start with the environment name, and are processed in alphabetical order, for example {ee-current}.xml, {ee-current}-extra.xml and {ee-current}-other.xml are processed in this order, and they all affect the {ee-current} environment.
The same holds for +*.properties+ files.
The environment-specific Jetty XML files will be applied to the web application before any Jetty context XML file associated with the web application, present in the $JETTY_HOME/webapps directory.
IMPORTANT: The contents of the environment specific Jetty context XML file may only contain references to classes appropriate for that environment.
For example, you can have a $JETTY_HOME/environments/{ee-current}.xml file with the following content:
.{ee-current}.xml [,xml,subs=+attributes]
The $JETTY_HOME/environments/{ee-current}-extra.xml file may contain:
.{ee-current}-extra.xml [,xml,subs=+attributes]
Custom classes like com.acme.MyListenerFeature must be present in the environment class loader, so that the XML file can reference them.
You can extend the environment class loader by enabling the xref:modules/standard.adoc#eeN-ext[{ee-current}-ext.mod].
Refer to xref:start/index.adoc#start-class-path[this section] for more information about the Jetty class loader hierarchy.
The directory structure would look like this:
[,subs=+attributes]
$JETTY_BASE
├── environments
│ ├── {ee-current}.xml
│ └── {ee-current}-extra.xml
├── start.d
│ ├── ...
│ └── {ee-current}-ext.ini
└── webapps
├── wiki.properties
└── wiki.xml
[[jetty-web-xml]]
== In-Application Jetty Context XML File
As discussed in <<context-xml,this section>>, the deployment of a web application can be specified with a Jetty context XML file placed in the $JETTY_HOME/webapps directory.
However, the deployment of a web application can also be configured using a Jetty context XML file placed inside the web application, both for <<web-application-format-core,Core web application deployments>> and <<web-application-format-jakarta,Jakarta EE web application deployments>>.
This file can be useful:
- To place all configuration inside your web application archive.
- To perform configuration of the web application that can only occur after the web application's class-path has been created, for example because it references classes present in web application itself.
[[jetty-web-xml-core]]
=== In-Application Jetty Context XML File for Core Web Application Deployments
The file must be in the root of the web application and named jetty-web.xml, see <<web-application-format-core,this section>> for an example.
[[jetty-web-xml-jakarta]]
=== In-Application Jetty Context XML Files for Jakarta EE Web Application Deployments
For Jakarta EE deployments, there may be multiple in-application Jetty context XML files, typically one for each {ee-all} environment.
The files must be named either WEB-INF/jetty-{ee-all}-web.xml or WEB-INF/jetty-web.xml; the latter is only processed if the former(s) are missing.
[TIP]
It is good practice to name the file according to the environment into which the web application will be deployed.
If your web application can be deployed to multiple environments, then you should include a WEB-INF/jetty-{ee-all}-web.xml file for each environment.
If you only deploy to a single environment, then you can omit it from the filename and use `WEB-INF/jetty-web.xml`, but be aware that likely you will not be able to deploy the web application to a different environment without updating the contents of the file.
[[jndi]]
== Configuring JNDI Entries
Web applications may reference JNDI entries, such as a JDBC DataSource or a Jakarta Mail Session.
The JNDI entries must be defined in a Jetty context XML file, as detailed in xref:jndi/index.adoc[this section].
[[virtual-hosts]]
== Configuring Virtual Hosts
A virtual host is an internet domain name, registered in the Domain Name Server (DNS), for an IP address such that multiple virtual hosts will resolve to the same IP address of a single server instance.
If you have multiple web applications deployed on the same Jetty server, by using virtual hosts you will be able to target a specific web application.
For example, you may have a web application for your business and a web application for your hobbies , both deployed in the same Jetty server.
By using virtual hosts, you will be able to have the first web application available at +http://domain.biz/+, and the second web application available at +http://hobby.net/+.
Another typical case is when you want to use different subdomains for different web application, for example a project website is at +http://project.org/+ and the project documentation is at +http://docs.project.org+.
Virtual hosts can be used with any context that is a subclass of link:{javadoc-url}/org/eclipse/jetty/server/handler/ContextHandler.html[ContextHandler], and therefore for <<web-application-format-static,Jetty Static web applications>>, <<web-application-format-core,Jetty Core web applications>> and <<web-application-format-jakarta,Jakarta EE web applications>>.
[[virtual-hosts-names]]
=== Virtual Host Names
Jetty supports the following variants to be specified as virtual host names:
www.hostname.com::
A fully qualified domain name. It is important to list all variants as a site may receive traffic for both www.hostname.com and hostname.com.
+*.hostname.com+::
A wildcard domain name which will match only one level of arbitrary subdomains.
The wildcard domain +*.foo.com+ will match www.foo.com and m.foo.com, but not www.other.foo.com.
10.0.0.2::
An IP address may be set as a virtual host to indicate that a web application should handle requests received on the network interface with that IP address.
This is typically only used for protocols that do not indicate a host name such as HTTP/0.9 or HTTP/1.0.
@<ConnectorName>::
A Jetty server Connector name to indicate that a web application should handle requests received on the server Connector with that name, and therefore received on a specific socket address, either an IP port for ServerConnector, or a Unix-Domain path for UnixDomainServerConnector (see also xref:virtual-hosts-port[this section]).
www.√integral.com::
Non-ASCII and https://en.wikipedia.org/wiki/Internationalized_domain_name[IDN] domain names can be set as virtual hosts using https://en.wikipedia.org/wiki/Punycode[Puny Code] equivalents that may be obtained from a https://www.punycoder.com/[Punycode/IDN converters].
For example if the non-ASCII domain name www.√integral.com is given to a browser, then the browser will make a request that uses the domain name www.xn--integral-7g7d.com, which is the name that should be added as the virtual host name.
[[virtual-hosts-config]]
=== Virtual Hosts Configuration
If you have a web application mywebapp.war you can configure its virtual hosts in this way:
[,xml,subs=attributes+]
Your web application will be available at:
+http://mywebapp.com/mywebapp++http://www.mywebapp.com/mywebapp++http://mywebapp.net/mywebapp++http://www.mywebapp.net/mywebapp+
[NOTE]
In the example above, the web application contextPath is configured to /mywebapp.
As such, a request to +http://mywebapp.com/other+ will not match your web application because the contextPath does not match.
Likewise, a request to `+http://other.com/mywebapp+` will not match your web application because the virtual host does not match.
[[virtual-hosts-same-context]]
=== Same Context Path, Different Virtual Hosts
If you want to deploy different web applications to the same context path, typically the root context path /, you must use virtual hosts to differentiate among web applications.
You have domain.war that you want to deploy at +http://domain.biz/+ and hobby.war that you want to deploy at +http://hobby.net+.
To achieve this, you simply use the same context path of / for each of your web applications, while specifying different virtual hosts for each of your web applications:
.domain.xml [,xml,subs=attributes+]
.hobby.xml [,xml,subs=attributes+]
[[virtual-hosts-port]]
=== Different Port, Different Web Application
Sometimes it is required to serve different web applications from different socket addresses (either different IP ports, or different Unix-Domain paths), and therefore from different server Connectors.
For example, you want requests to +http://localhost:8080/+ to be served by one web application, but requests to +http://localhost:9090/+ to be served by another web application.
This configuration may be useful when Jetty sits behind a load balancer.
In this case, you want to xref:protocols/index.adoc[configure multiple connectors], each with a different name specified with link:{javadoc-url}/org/eclipse/jetty/server/AbstractConnector.html#setName(java.lang.String)[], and then reference the connector name in the web application virtual host configuration:
.domain.xml [,xml,subs="attributes+,+quotes"]
.hobby.xml [,xml,subs="attributes+,+quotes"]
[NOTE]
Web application domain.war has a virtual host of @port8080, where port8080 is the name of a Jetty connector.
Likewise, web application hobby.war has a virtual host of @port9090, where port9090 is the name of another Jetty connector.
See xref:protocols/index.adoc[this section] for further information about how to configure connectors.
[[extract-war]]
== Configuring +*.war+ File Extraction
By default, when a Jakarta EE web application in +*.war+ file format is deployed, the +*.war+ file is uncompressed and its content extracted in a temporary directory.
// TODO: reference the work module and how it works, perhaps in a section about the deploy module?
The web application resources are served by Jetty from the files extracted in the temporary directory, not from the files within the +*.war+ file, for performance reasons.
If you do not want Jetty to extract the +*.war+ files, you can disable this feature in this way:
.mywebapp.xml [,xml,subs="attributes+,+quotes"]
[[jetty-override-web-xml]]
== Overriding web.xml
When deploying Jakarta EE web applications, you can configure an additional web.xml that complements the web.xml file that is present in the web application +*.war+ file.
This additional web.xml is processed after the +*.war+ file web.xml.
This allows you to add host specific configuration or server specific configuration without having to extract the web application web.xml, modify it, and repackage it in the +*.war+ file.
.mywebapp.xml [,xml,subs="attributes+,+quotes"]
The format of the additional web.xml is exactly the same as a standard web.xml file, for example:
.mywebapp-web.xml [,xml,linenums,highlight=10-11]
host
192.168.0.13In the example above, you configured the my-servlet Servlet (defined in the web application web.xml), adding a host-specific init-param with the IP address of the host.
Documentation Jetty Modules Operations Guide Pages Features Index (`documentation/jetty/modules/operations-guide/pages/features/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Eclipse Jetty Features
If you know Eclipse Jetty already, jump to a feature:
Protocols::
- xref:protocols/index.adoc#http[HTTP/1.1 Support]
- xref:protocols/index.adoc#http2[HTTP/2 Support]
- xref:protocols/index.adoc#http3[HTTP/3 Support]
- xref:protocols/index.adoc#websocket[WebSocket Support]
Technologies::
- xref:annotations/index.adoc[Servlet Annotations]
- xref:security/jaas-support.adoc[JAAS]
- xref:jndi/index.adoc[JNDI]
- xref:jsp/index.adoc[JSP]
- xref:jmx/index.adoc[JMX Monitoring & Management]
Clustering::
- xref:session/index.adoc[HTTP Session Caching and Clustering]
Performance::
- xref:server/index.adoc#threadpool-virtual[Virtual Threads]
- xref:quickstart/index.adoc[Faster Jakarta EE Web Application Deployment]
Documentation Jetty Modules Operations Guide Pages Howtos Index (`documentation/jetty/modules/operations-guide/pages/howtos/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Eclipse Jetty How-Tos
- xref:protocols/index.adoc#http[Configure Clear-Text HTTP/1.1]
- xref:protocols/index.adoc#https[Configure Secure HTTP/1.1 (https)]
- xref:protocols/index.adoc#http2c[Configure Clear-Text HTTP/2]
- xref:protocols/index.adoc#http2s[Configure Secure HTTP/2]
- xref:protocols/index.adoc#http3[Configure HTTP/3]
- xref:protocols/index.adoc#proxy[Configure Jetty Behind a Load Balancer or Reverse Proxy]
- xref:server/index.adoc#logging[Configure Jetty Logging]
- xref:server/index.adoc#threadpool[Configure Jetty Thread Pool and Virtual Threads]
- xref:troubleshooting/index.adoc[Troubleshooting]
Documentation Jetty Modules Operations Guide Pages Jmx Index (`documentation/jetty/modules/operations-guide/pages/jmx/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= JMX Monitoring & Management
Monitoring and management of a Jetty server is important because it allows you to monitor the status of the server ("Is the server processing requests?") and to manage -- i.e. read and possibly change -- its configuration.
The ability to read and change the Jetty configuration is very important for troubleshooting Jetty -- please refer to the xref:troubleshooting/index.adoc[troubleshooting section] for more information.
Jetty relies on the Java Management Extensions (JMX) APIs included in OpenJDK to provide monitoring and management.
The JMX APIs support a JVM-local MBeanServer, accessible only from within the JVM itself (or by tools that can attach to a running JVM), and a way to expose the MBeanServer to remote clients via Java's RMI (Remote Method Invocation).
[[local]]
== Enabling Local JMX Support
As with many other Jetty features, local JMX support is enabled with the xref:modules/standard.adoc#jmx[jmx Jetty module]:
$ java -jar $JETTY_HOME/start.jar --add-modules=jmx
With the jmx Jetty module enabled, Jetty components will be exported as JMX MBeans to the JVM platform MBeanServer, so that they can be accessed by JMX compliant tools.
Each Jetty component will export to its correspondent MBean relevant configuration parameters, so that a JMX tool can read and possibly change the component configuration through the MBean.
Note that the Jetty MBeans are registered into the platform MBeanServer, but are not available to remote clients: they are local to the JVM.
This configuration is useful when you develop and test your Jetty server locally.
JMX compliant tools such as https://adoptium.net/jmc.html[Java Mission Control (JMC)] can be started locally on your machine and can attach to other JVMs running on your machine, showing you the registered MBeans among which you will find the Jetty MBeans.
NOTE: Enabling only the local JMX support is the most secure option for monitoring and management, but only users that have local access to the JVM will be able to browse the MBeans.
If you need to access the MBeans from a remote machine, read <<remote,this section>>.
[[remote]]
== Enabling Remote JMX Support
There are two ways to configure a Jetty server so that it is possible to access the JVM platform MBeans from remote clients:
- Use the
com.sun.management.jmxremoteand related system properties when starting Jetty.
Unfortunately, this solution does not work well with firewalls, and will not be discussed further. - Use the
jmx-remoteJetty module.
Both ways use Java's Remote Method Invocation (RMI) to communicate between the client and the server.
[IMPORTANT] .Refresher: How RMI Works
A server application that wants to make an object available to remote clients must export the object.
Exporting an object creates an RMI stub that contains the host/port of the RMI server that accepts incoming invocations from clients and forwards them to the object.
During the creation of the RMI stub, the host stored in the RMI stub is retrieved from the local name resolution system (for example, in Linux, from /etc/hosts).
The RMI stub is then sent, along with a name that uniquely identifies the object, to the RMI registry.
The RMI registry is a service that maps names to RMI stubs; it may be external to both clients and server, although often it is part of the server JVM.
When a client application wants to connect to the server object using RMI, it first connects to the RMI registry to download the RMI stub for the RMI server; recall that the RMI stub contains the host/port to connect to the RMI server. Then, the client uses the RMI stub to connect to the RMI server, typically to a host/port that may be different from the RMI registry host/port (in particular, by default the RMI server port will be different from the RMI registry port).
Remote access to the platform MBeans, and therefore the Jetty MBeans, is enabled by the jmx-remote Jetty module:
$ java -jar $JETTY_HOME/start.jar --add-modules=jmx-remote
This command creates the jmx-remote.ini file:
[source,subs=+quotes]
JETTY_BASE
└── start.d
└── #jmx-remote.ini#
Enabling the jmx-remote module transitively enables the <<local,jmx module>> as well.
The configuration for the RMI registry and the RMI server is specified by a JMXServiceURL.
The string format of an RMI JMXServiceURL is the following:
service:jmx:rmi://:/jndi/rmi://:/jmxrmi
Below you can find examples of JMXServiceURLs:
[source,subs=+quotes]
service:jmx:rmi:///jndi/rmi:///jmxrmi
where:
rmi_server_host = local host address
rmi_server_port = randomly chosen
rmi_registry_host = local host address
rmi_registry_port = 1099
service:jmx:rmi://0.0.0.0:1099/jndi/rmi://0.0.0.0:1099/jmxrmi
where:
rmi_server_host = any address
rmi_server_port = 1099
rmi_registry_host = any address
rmi_registry_port = 1099
*service:jmx:rmi://localhost:1100/jndi/rmi://localhost:1099/jmxrmi* where: rmi_server_host = loopback address rmi_server_port = 1100 rmi_registry_host = loopback address rmi_registry_port = 1099
The default JMXServiceURL configured by the jmx-remote module is the following:
service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi
With the default configuration, only clients that are local to the server machine can connect to the RMI registry and RMI server - this is done for security reasons.
However, even with this local-only configuration, it would still be possible to access the MBeans from remote using an SSH tunnel, as explained in <<remote-ssh-tunnel,this section>>.
By specifying an appropriate JMXServiceURL, you can fine tune the network address the RMI registry and the RMI server bind to, and the ports that the RMI registry and the RMI server listen to.
The RMI server and RMI registry hosts and ports can be the same (as in the default configuration) because RMI is able to multiplex traffic arriving to one port to multiple RMI objects.
If you need to allow JMX remote access through a firewall, you must open both the RMI registry and the RMI server ports.
The default configuration simplifies the firewall configuration because you only need to open port 1099.
[NOTE]
When Jetty is started with the jmx-remote module enabled, the RMI stub of the Jetty component that provides access to the MBeans is exported to the RMI registry.
The RMI stub contains the host/port to connect to the RMI server, but the host is typically the machine host name, not the host specified in the JMXServiceURL (the latter is only used to specify the network address the RMI server binds to).
To control the host stored in the RMI stub you need to set the system property `java.rmi.server.hostname` with the desired value in the module configuration file, `jmx-remote.ini`.
IMPORTANT: If your client cannot connect to the server, the most common cause is a mismatch between the RMI server host of the JMXServiceURL and the RMI server host of the RMI stub.
You can customize the RMI server host/port, the RMI registry host/port and the system property java.rmi.server.hostname by editing the jmx-remote.ini configuration file.
Further information about the jmx-remote module configuration can be found xref:modules/standard.adoc#jmx-remote[here].
[[remote-ssh-tunnel]]
=== Remote JMX Access with Port Forwarding via SSH Tunnel
You can access JMX MBeans on a remote machine when the RMI ports are not open, for example because of firewall policies, but you have SSH access to the machine, using local port forwarding via an SSH tunnel.
In this case you want to configure the JMXServiceURL that binds the RMI server and the RMI registry to the loopback interface only and to the same port:
service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi
You must set the system property -Djava.rmi.server.hostname=localhost so that the RMI stub contains localhost as the host name to connect to.
This is, incidentally, the default configuration of the jmx-remote module.
Then you set up the local port forwarding with the SSH tunnel:
$ ssh -L 1099:localhost:1099 @
Thanks to the local port forwarding of the SSH tunnel, when the client connects to localhost:1099 on your local computer, the traffic will be forwarded to machine_host and when there, the SSH daemon will forward the traffic to localhost:1099 on machine_host, which is exactly where the RMI server and the RMI registry listens to.
The client first contacts the RMI registry, so it connects to localhost:1099 on your local computer; the traffic is forwarded to machine_host through the SSH tunnel, connects to the RMI registry and the RMI stub is downloaded to the client.
Then the client uses the RMI stub to connect to the RMI server. The RMI stub contains localhost as the RMI server host because that is what you have configured with the system property java.rmi.server.hostname.
The client will connect again to localhost:1099 on your local computer, this time to contact the RMI server; the traffic is forwarded to machine_host through the SSH tunnel, arrives to machine_host and connects to the RMI server.
[[remote-auth]]
=== Remote JMX Access Authentication & Authorization
The standard javax.management.remote.JMXConnectorServer class, used by the jmx-remote module to provide remote JMX access to Jetty MBeans, provides several options to authenticate and authorize users.
For a complete guide to controlling authentication and authorization in JMX, see https://docs.oracle.com/en/java/javase/11/management/monitoring-and-management-using-jmx-technology.html[the official JMX documentation].
The simplest way to control JMX authentication and authorization is to specify two files: one contains username and password pairs, and the other contains username and permission pairs.
This is achieved by enabling the jmx-remote-auth Jetty module:
$ java -jar $JETTY_HOME/start.jar --add-modules=jmx-remote-auth
Enabling the jmx-remote-auth Jetty module creates the following files:
$JETTY_BASE
├── etc
│ ├── jmxremote.access
│ ├── jmxremote.password
│ └── jmx-remote-auth.xml
└── start.d
├── jmx-remote-auth.ini
└── jmx-remote.ini
Then you edit the $JETTY_BASE/etc/jmxremote.password file, adding the username/password pairs that you need:
.$JETTY_BASE/etc/jmxremote.password
The file format is:
alice wonderland bob marley
You must also edit the $JETTY_BASE/etc/jmxremote.access file to give permissions to your users:
.$JETTY_BASE/etc/jmxremote.access
The file format is:
alice readwrite bob readonly
The above files define user alice with password wonderland to have readwrite access, and user bob with password marley to have readonly access.
[[remote-secure]]
=== Securing Remote JMX Access with TLS
The JMX communication via RMI happens by default in clear-text, but it is possible to secure the JMX communication via RMI with TLS.
If you want to reuse the configuration that you are using for the xref:protocols/index.adoc#https[https module], you can just enable the jmx-remote-ssl.xml Jetty module:
$ java -jar $JETTY_HOME/start.jar --add-modules=jmx-remote-ssl
[NOTE]
The `jmx-remote-ssl` Jetty module depends on the `ssl` Jetty module that in turn requires a KeyStore (read xref:protocols/index.adoc#ssl[this section] for more information).
The KeyStore must contain a valid certificate signed by a Certification Authority.
Having certificates signed by a Certification Authority simplifies by a lot the configuration needed to get the RMI communication over TLS working properly.
The RMI mechanic is the usual one: the RMI client (typically a monitoring console) will connect first to the RMI registry (using TLS), download the RMI stub that contains the address and port of the RMI server to connect to, then connect to the RMI server (using TLS).
This also mean that if the RMI registry and the RMI server are on different hosts, the RMI client must have available the cryptographic material to validate the certificates from both hosts.
This is where having certificates signed by a Certification Authority simplifies the configuration: if they are signed by a well known Certification Authority, the client does not need any extra configuration -- everything will be handled by the Java runtime.
If the certificates are not signed by a Certification Authority (for example the certificate is self-signed), then you need to specify the TLS system properties that allow RMI (especially when acting as an RMI client) to retrieve the cryptographic material necessary to establish the TLS connection.
[IMPORTANT]
When the RMI server exports the `JMXConnectorServer` it acts as an RMI _client_ towards the RMI registry, and as such you must specify the TLS system properties as detailed below.
You must edit the $JETTY_BASE/start.d/jmx-remote-ssl.ini file and add the TrustStore path and password:
.$JETTY_BASE/start.d/jmx-remote-ssl.ini
--module=jmx-remote-ssl
System properties necessary for non-trusted certificates.
-Djavax.net.ssl.trustStore=/path/to/trustStore.p12 -Djavax.net.ssl.trustStorePassword=password
[IMPORTANT]
The TrustStore must contain the certificate you want to trust.
If you are using self-signed certificates, the KeyStore already contains the self-signed certificate and therefore the KeyStore can be used as a TrustStore, and the system properties above can refer to the KeyStore path and password.
JMX compliant tools that offer a graphical user interface also must be started specifying the TrustStore path and password.
For example, to launch https://adoptium.net/jmc.html[Java Mission Control (JMC)]:
$ jmc -vmargs -Djavax.net.ssl.trustStore=/path/to/trustStore.p12 -Djavax.net.ssl.trustStorePassword=password
Documentation Jetty Modules Operations Guide Pages Jndi Index (`documentation/jetty/modules/operations-guide/pages/jndi/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= JNDI
For each specific xref:deploy/index.adoc[environment] there is a specific Jetty module that you must enable in order to use JNDI resources in your web application:
- For Jetty Static and Core web applications, the
plusmodule. - For Jakarta {ee-all-caps} web applications, the correspondent
{ee-all}-plusmodule.
If you have already enabled an xref:annotations/index.adoc[annotations] module suitable for your environment, an appropriate plus module will already have been enabled, and you do not need to explicitly enable a plus module.
If your JNDI resources need extra libraries, for example database driver libraries, that are not located inside your web application, then you must ensure they are on the environment class-path/module-path.
You can enable the xref:modules/standard.adoc#ext[ext] module for Jetty Core web applications, or the specific xref:modules/standard.adoc#eeN-ext[{ee-all}-ext] module for Jakarta EE web applications, and place your extra libraries respectively in $JETTY_BASE/lib/ext or $JETTY_BASE/lib/{ee-all}/ext to make them available in the environment class-path/module-path.
You can now define JNDI resources and reference them within your web applications.
== Defining resources
JNDI resources are referenced by web application via JNDI names.
// TODO: document how it is for Jetty web applications.
For Jakarta EE web applications, the JNDI names must be declared via env-entry, resource-ref and resource-env-refs in web.xml, web-fragment.xml or Jetty's override-web.xml.
The resources are bound to their JNDI names in Jetty XML files that are either external or internal to your web application.
External Jetty XML files are those used to deploy the web application, as defined in xref:deploy/index.adoc[this section].
Internal Jetty XML files are those present inside the web application directory or packaged file, as defined in xref:deploy/index.adoc#jetty-web-xml[this section].
For Jakarta EE web applications, the file WEB-INF/jetty-{ee-all}-env.xml is processed before other internal Jetty XML files such as WEB-INF/jetty-{ee-all}-web.xml, so that JNDI resources can be bound and later possibly processed by WEB-INF/jetty-{ee-all}-web.xml.
See the section on <<xml,Jetty XML files>> for more information on how to choose in which XML file to place the definitions of your JNDI resources.
The definitions of your JNDI resources are instances of the following types:
<<env,org.eclipse.jetty.plus.jndi.EnvEntry>>::
Used for env-entry resources in web.xml.
<<resource,org.eclipse.jetty.plus.jndi.Resource>>::
Used for other type of resources.
<<tx,org.eclipse.jetty.plus.jndi.Transaction>>::
<<tx,org.eclipse.jetty.{ee-all}.plus.jndi.Transaction>>::
Used for a JTA transaction manager.
<<link,org.eclipse.jetty.plus.jndi.Link>>::
Used for linking between a web.xml resource name and a naming entry.
Definitions of each of these types follow this pattern:
[,xml,subs=attributes+]
[[env]]
=== org.eclipse.jetty.plus.jndi.EnvEntry
Sometimes it is useful to pass configuration information to a web application at runtime that you either cannot or cannot conveniently code into a web.xml <env-entry>.
In such cases, you can use the org.eclipse.jetty.plus.jndi.EnvEntry class, and optionally even override an entry of the same name in web.xml.
Here's an example that defines the equivalent of an env-entry called mySpecialValue with value 4000 that overrides an <env-entry> declaration of the same name in web.xml:
[,xml,subs=attributes+]
Note that if you don't want to override the web.xml value, simply omit the last argument, or set it to false.
The Servlet specification allows binding only the following object types to an env-entry:
- java.lang.String
- java.lang.Integer
- java.lang.Float
- java.lang.Double
- java.lang.Long
- java.lang.Short
- java.lang.Character
- java.lang.Byte
- java.lang.Boolean
Jetty is a little more flexible and allows you to also bind:
- Instances of any object.
javax.naming.Referenceinstances.javax.naming.Referenceableinstances.
Be aware that if you take advantage of this flexibility, your web application is not portable across Servlet containers.
[[resource]]
=== org.eclipse.jetty.plus.jndi.Resource
You can configure any type of resource that you want to refer to in web.xml via a resource-ref or resource-env-ref by using the org.eclipse.jetty.plus.jndi.Resource type of naming entry.
You provide the scope, the name of the object (relative to java:comp/env) and either the resource, or a javax.naming.Reference or a javax.naming.Referenceable instance.
==== DataSources
This example configures a http://db.apache.org/derby[Derby] DataSource named jdbc/myds:
[,xml,subs=attributes+]
This would be linked into the web application's JNDI namespace via an entry in a web.xml like so:
[,xml]
[NOTE]
When configuring Resources, ensure that the type of object you configure matches the type of object you expect to look up from java:comp/env.
For database connection factories, this means that the object you register as a Resource must implement the javax.sql.DataSource interface.
Also note that the Jakarta specification recommends storing DataSources relative to jdbc/ and thus looked up by the web application as java:comp/env/jdbc/<datasource-name>.
For example, the `Datasource` bound in Jetty as `jdbc/users` would be looked up by the web application as `java:comp/env/jdbc/users`.
//TODO For more examples of datasource configurations, see xref:jndi-datasource-examples[].
==== JMS Queues, Topics and ConnectionFactories
Jetty can bind any implementation of the JMS destinations and connection factories.
Here is an example of binding an http://activemq.apache.org[ActiveMQ] in-JVM connection factory:
[,xml,subs=attributes+]
The corresponding entry in web.xml to bind the ConnectionFactory into the web application's JNDI namespace would be:
[,xml,subs=attributes+]
[NOTE]
The Jakarta specification recommends storing JMS connection factories under jms/.
For example, the `ConnectionFactory` bound in Jetty as `jms/inqueue` would be looked up by the application as `java:comp/env/jms/inqueue`.
To configure access to jakarta.mail.Session from within a web application, define an org.eclipse.jetty.plus.jndi.Resource with an org.eclipse.jetty.{ee-all}.jndi.factories.MailSessionReference that will hold the mail configuration and create the instance of the Session when it is referenced:
[,xml,subs=attributes+]
The web application performs a lookup for java:comp/env/mail/Session at runtime and obtains a jakarta.mail.Session that has the correct configuration to permit it to send email via SMTP.
[NOTE]
Note also that the Jakarta specification recommends storing Jakarta Mail connection factories under mail/.
For example, the `MailSessionReference` bound to jetty as `mail/smtp` would be looked up by the web application as `java:comp/env/mail/smtp`.
IMPORTANT: Jetty does not provide the jakarta.mail and jakarta.activation libraries.
[[tx]]
=== org.eclipse.jetty.plus.jndi.Transaction
To perform distributed transactions with your resources, a transaction manager that supports the link:https://jakarta.ee/specifications/transactions/[Jakarta Transaction] (JTA) interfaces is required.
The transaction manager is looked up by the application as java:comp/UserTransaction.
Jetty does not ship with a transaction manager, but provides the infrastructure to plug in the transaction manager of your choice.
If the JTA implementation of jakarta.transaction.UserTransaction implements javax.naming.Reference, then you should use the org.eclipse.jetty.plus.jndi.Transaction object in a <<xml,Jetty XML file>> to register it in JNDI:
[,xml,subs=attributes+]
If your JTA implementation of UserTransaction does not implement javax.naming.Reference, then you should use the Jakarta specific Jetty class to register it in JNDI:
[,xml,subs=attributes+]
Jetty will automatically bind this transaction manager to the web application's JNDI namespace at java:comp/UserTransaction.
[[link]]
=== org.eclipse.jetty.plus.jndi.Link
Usually, the name you provide for the org.eclipse.jetty.plus.jndi.Resource is the same name you reference in web.xml.
This ensures that the two are linked together and thus accessible to your web application.
However, if the names cannot be the same, then it is possible to effectively alias one to another using an org.eclipse.jetty.plus.jndi.Link.
Suppose you have a definition for a Datasource named jdbc/workforce in a Jetty context XML file, but your web.xml wants to link to a <resource-ref> named jdbc/employees, and you cannot edit the web.xml.
You can create a WEB-INF/jetty-{ee-all}-env.xml file with an org.eclipse.jetty.plus.jndi.Link that ties together the names jdbc/workforce and jdbc/employees:
The Jetty Context XML file defines jdbc/workforce:
[,xml,subs=attributes+]
The web.xml refers to it as jdbc/employees:
[,xml,subs=attributes+]
Create a WEB-INF/jetty-{ee-all}-env.xml file with a org.eclipse.jetty.plus.jndi.Link to link these names together:
[,xml,subs=attributes+]
[[xml]]
=== Jetty XML files
You can define naming resources in three places:
Server XML file::
Resources defined in a server XML file are <<scope,scoped>> at the JVM, org.eclipse.jetty.server.Server or xref:deploy/index.adoc[environment] level.
Note that the classes for the resource must be accessible at the time that the XML is processed.
+
For example, environment resources that depend on an external library should be defined in an XML file that is processed after the environment class-path has been properly configured.
This can be achieved by using the {ee-all}-ext module, with the external library in the $JETTY_BASE/lib/{ee-all}/ext/ directory, or with a xref:modules/custom.adoc[custom module] that contains an [environment] clause and a [lib] clause.
Context XML file::
Resources defined in a context XML file should be <<scope,scoped>> at the level of the web application to which they apply (it is possible to use a less strict scoping level of Server or JVM, but not recommended).
As the Context XML file executes before the web application classes are available, the classes for your resource must be external to the web application, either on the container or on environment class-path.
WEB-INF/jetty-{ee-all}-env.xml::
Resources defined in a WEB-INF/jetty-{ee-all}-env.xml file are <<scope,scoped>> to the web application in which the file resides.
The resources defined by this file may use classes from inside your web application.
WEB-INF/jetty-{ee-all}-web.xml::
Resources defined in a WEB-INF/jetty-{ee-all}-web.xml file are <<scope,scoped>> to the web application in which the file resides.
The resources defined by this file may use classes from inside your web application.
This file is processed after WEB-INF/jetty-{ee-all}-env.xml.
[[scope]]
=== Resource scoping
Resources within Jetty are defined in different scopes, in increasing order of restrictiveness:
JVM scope:: The resource is unique across the JVM instance, and is visible to all application code. This scope is represented by a `null` first parameter to the resource definition. For example: + [,xml,subs=attributes+]
Environment scope:: The resource is unique within a Jetty _environment_. The scope is represented by referencing the name of the environment as the first parameter to the resource definition. For example: + [,xml,subs=attributes+]
Web application scope:: The resource is unique to the `org.eclipse.jetty.{ee-all}.webapp.WebAppContext` instance, and is only visible to that application. The scope is represented by referencing the context instance as the first parameter to the resource definition. For example: + [,xml,subs=attributes+]
Documentation Jetty Modules Operations Guide Pages Jsf Taglibs Index (`documentation/jetty/modules/operations-guide/pages/jsf-taglibs/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jakarta Faces TagLibs
If you want to use Jakarta Faces with your Jakarta EE web application, you should enable the xref:modules/standard.adoc#eeN-ext[{ee-all}-ext] Jetty module, and copy the relevant Jakarta Faces API jar files, and the Jakarta Faces implementation jar files of your choice into the $JETTY_BASE/lib/{ee-all}/ext directory created by the {ee-all}-ext module you enabled.
Then you will need to tell Jetty which of those jar files contains the +*.tld+ files.
To accomplish that, you need to specify either the name of the file or a pattern that matches the name of the file(s) as the org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern context attribute.
You will need to preserve the existing value of the attribute, and add in your extra pattern.
Below you can find an example of using a Jetty context XML file to add a pattern to match files starting with jsf-, which contain the +*.tld+ files:
[,xml,subs=+attributes]
Documentation Jetty Modules Operations Guide Pages Jsp Index (`documentation/jetty/modules/operations-guide/pages/jsp/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Java Server Pages
Jetty supports JSP via the {ee-all}-jsp modules, which are based on Apache Jasper:
[source,subs=attributes+]
include::{jetty-home}/modules/ee11-jsp.mod[]
Logging has been bridged to Jetty logging, so you can enable logging for the org.apache.jasper package, subpackages and classes as usual.
== Configuration of the JSP Servlet
The org.eclipse.jetty.jsp.JettyJspServlet is the servlet responsible for serving JSPs.
It is configured as the default jsp servlet in the $JETTY_HOME/etc/webdefault.xml file.
Notice that Jetty identifies the jsp servlet by the presence of the id="jsp" attribute in the <servlet> declaration.
That file maps the org.eclipse.jetty.jsp.JettyJspServlet to the following partial urls:
+*.jsp++*.jspf++*.jspx++*.xsp++*.JSP++*.JSPF++*.JSPX++*.XSP+
You can change to a different servlet, change or add ````s or add extra <servlet-mapping>s in your web.xml file.
Here's an example of adding an `` to augment the definitions from the standard webdefault.xml file:
[,xml]
keepgenerated
trueAnother element you might consider adding to the default setup is async-supported:
[,xml]
There are many configuration parameters for the Apache Jasper JSP Servlet, here are some of them:
.JSP Servlet Parameters
[cols=",,,",options="header"]
|===
|init param |Description |Default |webdefault.xml
|checkInterval |If non-zero and development is false, background jsp recompilation is enabled. This value is the interval in seconds between background recompile checks.
|0 |–
|classpath |The classpath is dynamically generated if the context has a URL classloader. The org.apache.catalina.jsp_classpath
context attribute is used to add to the classpath, but if this is not set, this classpath configuration item is added to the classpath instead.` |- |–
|classdebuginfo |Include debugging info in class file. |true |–
|compilerClassName |If not set, defaults to the Eclipse jdt compiler. |- |–
|compiler |Used if the Eclipse jdt compiler cannot be found on the
classpath. It is the classname of a compiler that Ant should invoke. |–
|–
|compilerTargetVM |Target vm to compile for. |1.8 |1.8
|compilerSourceVM |Sets source compliance level for the jdt compiler.
|1.8 |1.8
|development |If true recompilation checks occur at the frequency governed by modificationTestInterval. |true |–
|displaySourceFragment |Should a source fragment be included in
exception messages |true |–
|dumpSmap |Dump SMAP JSR45 info to a file. |false |–
|enablePooling |Determines whether tag handler pooling is enabled. |true |–
|engineOptionsClass |Allows specifying the Options class used to
configure Jasper. If not present, the default EmbeddedServletOptions
will be used. |- |–
|errorOnUseBeanInvalidClassAttribute |Should Jasper issue an error when
the value of the class attribute in an useBean action is not a valid
bean class |true |–
|fork |Only relevant if you use Ant to compile JSPs: by default Jetty will use the Eclipse jdt compiler.|true |-
|genStrAsCharArray |Option for generating Strings as char arrays. |false |–
|ieClassId |The class-id value to be sent to Internet Explorer when
using jsp:plugin tags. |clsid:8AD9C840-044E-11D1-B3E9-00805F499D93 |–
|javaEncoding |Pass through the encoding to use for the compilation.
|UTF8 |–
|jspIdleTimeout |The amount of time in seconds a JSP can be idle before
it is unloaded. A value of zero or less indicates never unload. |-1 |–
|keepgenerated |Do you want to keep the generated Java files around?
|true |–
|mappedFile |Support for mapped Files. Generates a servlet that has a
print statement per line of the JSP file |true |–
|maxLoadedJsps |The maximum number of JSPs that will be loaded for a web
application. If more than this number of JSPs are loaded, the least
recently used JSPs will be unloaded so that the number of JSPs loaded at
any one time does not exceed this limit. A value of zero or less
indicates no limit. |-1 |–
|modificationTestInterval |If development=true, interval between
recompilation checks, triggered by a request. |4 |–
|quoteAttributeEL | When EL is used in an attribute value on a JSP page, should the rules for quoting of attributes described in JSP.1.6 be applied to the expression
|true |-
|recompileOnFail |If a JSP compilation fails should the
modificationTestInterval be ignored and the next access trigger a
re-compilation attempt? Used in development mode only and is disabled by
default as compilation may be expensive and could lead to excessive
resource usage. |false |–
|scratchDir |Directory where servlets are generated. The default is the value of the context attribute javax.servlet.context.tempdir, or the system property java.io.tmpdir if the context attribute is not set. |– |–
|strictQuoteEscaping |Should the quote escaping required by section JSP.1.6 of the JSP specification be applied to scriplet expression.
|true|-
|suppressSmap |Generation of SMAP info for JSR45 debugging. |false |–
|trimSpaces |Should template text that consists entirely of whitespace be removed from the output (true), replaced with a single space (single) or left unchanged (false)? Note that if a JSP page or tag file specifies a trimDirectiveWhitespaces value of true, that will take precedence over this configuration setting for that page/tag.
trimmed? |false |–
|xpoweredBy |Generate an X-Powered-By response header. |false |false
|===
[NOTE]
If the value you set doesn't take effect, try using all lower case instead of camel case, or capitalizing only some of the words in the name, as Jasper is inconsistent in its parameter naming strategy.
Documentation Jetty Modules Operations Guide Pages Jstl Index (`documentation/jetty/modules/operations-guide/pages/jstl/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= JavaServer Pages Standard Tag Libraries
The JavaServer Pages Standard Tag Library (JSTL) is part of the Jetty distribution, and is available via the {ee-all}-jstl modules:
[source,subs=attributes+]
include::{jetty-home}/modules/ee11-jstl.mod[]
When enabled, Jetty will make the JSTL tags available for your web applications.
Documentation Jetty Modules Operations Guide Pages Keystore Index (`documentation/jetty/modules/operations-guide/pages/keystore/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Configuring SSL/TLS KeyStores
A KeyStore is a file on the file system that contains a private key and a public certificate, along with the certificate chain of the certificate authorities that issued the certificate.
The private key, the public certificate and the certificate chain, but more generally the items present in a KeyStore, are typically referred to as "cryptographic material".
Keystores may encode the cryptographic material with different encodings, the most common being https://en.wikipedia.org/wiki/PKCS_12[PKCS12], and are typically protected by a password.
Refer to the xref:protocols/index.adoc#ssl[secure protocols section] for more information about how to configure a secure connector using a KeyStore.
[[create]]
== Creating a KeyStore
KeyStores are created with the JDK tool $JAVA_HOME/bin/keytool.
The following command creates a KeyStore file containing a private key and a self-signed certificate:
[source]
keytool
-genkeypair <1>
-alias mykey <2>
-validity 90 <3>
-keyalg RSA <4>
-keysize 2048 <5>
-keystore /path/to/keystore.p12 <6>
-storetype pkcs12 <7>
-dname "CN=domain.com, OU=Unit, O=Company, L=City, S=State, C=Country" <8>
-ext san=dns:www.domain.com,dns:domain.org <9>
-v <10>
<1> the command to generate a key and certificate pair
<2> the alias name of the key and certificate pair
<3> specifies the number of days after which the certificate expires
<4> the algorithm must be RSA (the DSA algorithm does not work for web sites)
<5> indicates the strength of the key
<6> the KeyStore file
<7> the KeyStore type, stick with the standard PKCS12
<8> the distinguished name (more below) -- customize it with your values for CN, OU, O, L, S and C
<9> the extension with the subject alternative names (more below)
<10> verbose output
The command prompts for the KeyStore password that you must choose to protect the access to the KeyStore.
[IMPORTANT]
The important parts of the command above are the Common Name (CN) part of the distinguished name, and the subject alternative names (SAN).
The CN value must be the main domain you own and that you want to use for your web applications.
For example, if you have bought domains domain.com and domain.org, you want to specify CN=domain.com as your main domain.
Furthermore, to specify additional domains or subdomains within the same certificate, you must specify the SAN extension.
In the example above, san=dns:www.domain.com,dns:domain.org specifies www.domain.com and domain.org as alternative names for your web applications (that you can configure using xref:deploy/index.adoc#virtual-hosts[virtual hosts]).
In rare cases, you may want to specify IP addresses, rather than domains, in the SAN extension. The syntax in such case is `san=ip:127.0.0.1,ip:[::1]`, which specifies as subject alternative names IPv4 `127.0.0.1` and IPv6 `[::1]`.
[[create-many]]
=== KeyStores with Multiple Entries
A single KeyStore may contain multiple key/certificate pairs.
This is useful when you need to support multiple domains on the same Jetty server (typically accomplished using xref:deploy/index.adoc#virtual-hosts[virtual hosts]).
You can create multiple key/certificate pairs as detailed in the <<create,previous section>>, provided that you assign each one to a different alias.
Compliant TLS clients will send the xref:protocols/index.adoc#ssl-sni[TLS SNI extension] when creating new connections, and Jetty will automatically choose the right certificate by matching the SNI name sent by the client with the CN or SAN of certificates present in the KeyStore.
[[csr]]
== Creating a Certificate Signing Request
Self-signed certificates are not trusted by browsers and generic clients: you need to establish a trust chain by having your self-signed certificate signed by a certificate authority (CA).
Browsers and generic clients (e.g. Java clients) have an internal list of trusted certificate authorities root certificates; they use these trusted certificates to verify the certificate they received from the server when they connect to your web applications.
To have your self-signed certificate signed by a certificate authority you first need to produce a certificate signing request (CSR):
[source]
keytool
-certreq <1>
-file domain.com.csr <2>
-keystore keystore.p12 <3>
<1> the command to generate a certificate signing request
<2> the file to save the CSR
<3> the keystore that contains the self-signed certificate
Then, you have to send the CSR file to the certificate authority of your choice, and wait for their reply (they will probably require a proof that you really own the domains indicated in your certificate).
Eventually, the certificate authority will reply to you with one or more files containing the CA certificate chain, and your certificate signed by their certificate chain.
[[csr-import]]
== Importing the Signed Certificate
The file you receive from the CA is typically in PEM format, and you must import it back into the same KeyStore file you used to generate the CSR.
You must import both the certificate chain and your signed certificate.
First, import the certificate chain:
[source]
keytool
-importcert <1>
-alias ca <2>
-file chain_from_ca.pem <3>
-keystore keystore.p12 <4>
-trustcacerts <5>
-v <6>
<1> the command to import certificates
<2> use the ca alias to differentiate from the alias of the server certificate
<3> the file containing the certificate chain received from the CA
<4> your KeyStore file
<5> specify that you trust CA certificates
<6> verbose output
Then, import the signed certificate:
keytool
-importcert
-file signed_certificate.pem
-keystore keystore.p12
-trustcacerts
-v
Now you have a trusted certificate in your KeyStore that you can use for the domains of your web applications.
// TODO: add a section about renewal?
Refer to the section about configuring xref:protocols/index.adoc#ssl[secure protocols] to configure the secure connector with your newly created KeyStore.
[[client-authn]]
== Creating a KeyStore for Client Certificate Authentication
For the majority of secure web sites, it is the client (typically the browser) that validates the certificate sent by the server (by verifying the certificate chain).
This is the server domain certificate.
However, the TLS protocol supports a mutual authentication mode where also the client must send a certificate to the server, that the server validates.
You typically want to sign the client certificate(s) with a server certificate that you control, and you must distribute the client certificate(s) to all the clients that need it, and redistribute the client certificates when they expire.
The server authentication certificate may be different from the server domain certificate, but it's typically stored in the same KeyStore for simplicity (although under a different alias).
First, you want to create the private key and server authentication certificate that you will use to sign client certificates:
[source]
keytool
-genkeypair
-alias server_authn <1>
-validity 90
-keyalg RSA
-keysize 2048
-keystore keystore.p12 <2>
-storetype pkcs12
-dname "CN=server_authn, OU=Unit, O=Company, L=City, S=State, C=Country" <3>
-ext bc=ca:true <4>
-v
<1> use the server_authn alias to differentiate from the alias of the server certificate
<2> the KeyStore file
<3> the CN is not that important, since this certificate will not be validated by clients
<4> the extension with the basic constraints (more below)
IMPORTANT: The important difference with the <<create,creation of a server certificate>> is the basic constraints extension (bc) that indicates that this certificates acts as a certificate authority (ca:true).
Now you want to export both the private key and server authentication certificate.
Unfortunately, the keytool program cannot export private keys, so you need to use a different command line program like openssl, or a graphical program like https://keystore-explorer.org/[KeyStore Explorer].
Let's use openssl to export the server authentication private key:
openssl
pkcs12
-in keystore.p12
-nodes
-nocerts
-out server_authn.key
Now let's export the server authentication certificate:
keytool
-exportcert
-keystore keystore.p12
-rfc
-file server_authn.crt
-v
At this point, you want to create a client KeyStore, so that you can sign the client certificate with the server authentication cryptographic material:
[source]
keytool
-genkeypair
-validity 90
-keyalg RSA
-keysize 2048
-keystore client_keystore.p12 <1>
-storetype pkcs12
-dname "CN=client, OU=Unit, O=Company, L=City, S=State, C=Country" <2>
-v
<1> the client KeyStore file
<2> the CN is not that important, since it will not be validated by the server
Now produce a certificate signing request (CSR):
keytool
-certreq
-file client.csr
-keystore client_keystore.p12
Now you need to sign the CSR, but again the keytool program does not have this functionality, and you must resort again to use openssl:
openssl
x509
-req
-days 90
-in client.csr
-CA server_authn.crt
-CAkey server_authn.key
-CAcreateserial
-sha256
-out signed.crt
Now you need to import the server authentication certificate and the signed client certificate into the client KeyStore.
First, the server authentication certificate:
keytool
-importcert
-alias ca
-file server_authn.crt
-keystore client_keystore.p12
-v
Then, the signed client certificate:
keytool
-importcert
-file signed.crt
-keystore client_keystore.p12
-v
Now you can distribute client_keystore.p12 to your client(s).
// TODO: add a section about renewal?
Refer to the section about configuring xref:protocols/index.adoc#ssl[secure protocols] to configure the secure connector to require client authentication.
Documentation Jetty Modules Operations Guide Pages Modules Custom (`documentation/jetty/modules/operations-guide/pages/modules/custom.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Custom Jetty Modules
In addition to the modules that come packaged with Jetty, you can create your own custom modules.
NOTE: Make sure you have read the xref:modules/index.adoc[Jetty modules section] if you are not familiar with the concepts used in this section.
Custom modules can be used for a number of reasons -- they can extend Jetty features, or add new features, or make additional libraries available to the server, etc.
[[modify]]
== Modifying an Existing Module
The standard Jetty modules typically come with a number of configurable properties that can be easily customized without the need of writing a custom module.
However, there may be cases where the customization is more complex than a simple property, and a custom module is necessary.
For example, let's assume that you want to modify the order of the TLS cipher suites offered by the server when a client connects, using the https://www.openssl.org/docs/man1.1.0/man1/ciphers.html[OpenSSL cipher list format].
The Jetty class that handles the TLS configuration is SslContextFactory, and it already has a method setCipherComparator(Comparator<String>); however, you need to pass your custom implementation, which cannot be represented with a simple module property.
The SslContextFactory component is already allocated by the standard Jetty module ssl, so what you need to do is the following:
- Write the custom cipher
Comparatorand package it into a+*.jar+file (exercise left to reader). - Write a custom Jetty XML file that calls the
SslContextFactory.setCipherComparator(Comparator<String>)method. - Write a custom Jetty module file that depends on the standard
sslmodule.
Start with the custom Jetty XML file, $JETTY_BASE/etc/custom-ssl.xml:
.custom-ssl.xml [,xml]
<Default>ECDH+AESGCM:ECDH+AES256:!aNULL:!MD5:!DSS:!ADH</Default>
</Arg>
</New>
</Set>CAUTION: The cipher list used above may not be secure -- it's just an example.
Then write your custom module in the $JETTY_BASE/modules/custom-ssl.mod file:
.custom-ssl.mod [source]
[description]
Customizes the standard ssl module.
[tags] <1>
acme
[depends] <2>
ssl
[lib] <3>
lib/custom-cipher-comparator.jar
[xml] <4>
etc/custom-ssl.xml
[ini-template] <5>
The cipher list in OpenSSL format.
com.acme.ssl.cipherList=ECDH+AESGCM:ECDH+AES256:!aNULL:!MD5:!DSS:!ADH
<1> A tag that characterizes this custom module (see xref:modules/index.adoc#directive-tags[here]).
<2> This custom module depends on the standard ssl module.
<3> The custom cipher comparator class is compiled and packaged into this +*.jar+ file.
<4> The custom Jetty XML file from above.
<5> The text that will be copied in the custom-ssl.ini file when this custom module will be enabled.
Now you can xref:start/index.adoc#configure-enable[enable] the custom module with the following command issued from the $JETTY_BASE directory:
$ java -jar $JETTY_HOME/start.jar --add-modules=https,custom-ssl
The command above will produce the following $JETTY_BASE directory structure:
[source,subs=+quotes]
$JETTY_BASE
├── etc
│ └── custom-ssl.xml
├── modules
│ └── custom-ssl.mod
├── resources
│ └── jetty-logging.properties
└── start.d
├── https.ini
└── ##custom-ssl.ini##
In the custom XML file you have used a custom module property to parametrize your custom cipher comparator.
This custom module property was then referenced in the [ini-template] section of the custom module file, so that when the custom module is enabled, a correspondent custom-ssl.ini file is created.
In this way, updating the cipher list won't require you to update the XML file, but just the custom-ssl.ini file.
[[create]]
== Creating a New Module
In the cases where you need to enhance Jetty with a custom functionality, you can write a new Jetty module that provides it.
For example, let's assume that you need to add a custom auditing component that integrates with the auditing tools used by your company.
This custom auditing component should measure the HTTP request processing times and record them (how they are recorded is irrelevant here -- could be in a local log file or sent via network to an external service).
The Jetty libraries already provide a way to measure HTTP request processing times via xref:programming-guide:server/http.adoc#handler-use-events[EventsHandler]: you write a custom EventsHandler subclass that overrides the methods corresponding to the events you are interested in.
The steps to create a Jetty module are similar to those necessary to <<modify,modify an existing module>>:
- Write the auditing component and package it into a
+*.jar+file. - Write a custom Jetty XML file that wires the auditing component to the
Handlertree. - Write a custom Jetty module file that puts everything together.
Let's start with the auditing component, sketched below:
[,java]
package com.acme.audit;
public class AuditingEventsHandler extends EventsHandler {
// Auditing is implemented here.
}
Let's assume that this class is compiled and packaged into acme-audit.jar, and that it has a dependency on acme-util.jar.
Both +*.jar+ files will be put in the $JETTY_BASE/lib/ directory.
Next, let's write the Jetty XML file that wires the auditing component to the ServerConnector, $JETTY_BASE/etc/acme-audit.xml:
.acme-audit.xml [,xml,options=nowrap]
</Set>
</New>
</Arg>
</Call>The last step is to create the custom Jetty module file for the auditing component, $JETTY_BASE/modules/acme-audit.mod:
.acme-audit.mod
[description]
Adds ACME auditing to the Jetty Server.
[tags] <1>
acme
audit
[depends] <2>
server
[libs] <3>
lib/acme-audit.jar
lib/acme-util.jar
[xml] <4>
etc/acme-audit.xml
[ini-template] <5>
An auditing property.
com.acme.audit.some.property=42
<1> The tags that characterize this custom module (see xref:modules/index.adoc#directive-tags[here]).
<2> This custom module depends on the standard server module.
<3> The +*.jar+ files that contains the custom auditing component, and its dependencies.
<4> The custom Jetty XML file from above.
<5> The text that will be copied in the acme-audit.ini file when this custom module will be enabled.
Now you can xref:start/index.adoc#configure-enable[enable] the custom auditing module with the following command issued from the $JETTY_BASE directory:
[source]
$ java -jar $JETTY_HOME/start.jar --add-modules=http,acme-audit
The command above will produce the following $JETTY_BASE directory structure:
[source,subs=+quotes]
$JETTY_BASE
├── etc
│ └── acme-audit.xml
├── modules
│ └── acme-audit.mod
├── resources
│ └── jetty-logging.properties
└── start.d
├── http.ini
└── ##acme-audit.ini##
Enabling the custom auditing component will create the $JETTY_BASE/start.d/acme-audit.ini module configuration file that you can edit to configure auditing properties.
Documentation Jetty Modules Operations Guide Pages Modules Index (`documentation/jetty/modules/operations-guide/pages/modules/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jetty Modules
A Jetty module provides one or more Java components that work together to implement one or more features.
Such features could be listening for clear-text HTTP/1.1 requests, exposing Jetty components to JMX, provide hot-deployment of web applications, etc.
Every Jetty feature is provided by a Jetty module.
A Jetty module is defined in a <name>.mod file, where <name> is the module name (see also the <<names,section about module names>>).
Jetty module files are read from the typical xref:start/index.adoc#configure[configuration source directories], under the modules/ subdirectory; from higher priority to lower priority:
- The
$JETTY_BASE/modules/directory. - If a directory is specified with the
--add-config-diroption, itsmodules/subdirectory. - The
$JETTY_HOME/modules/directory.
The standard Jetty modules that Jetty provides out-of-the-box are under $JETTY_HOME/modules/.
xref:modules/custom.adoc[Custom Jetty modules] should be put under $JETTY_BASE/modules/.
[[names]]
== Module Names
A Jetty module has a unique name.
The module name is by default derived from the file name, so module file acme.mod identifies a module named acme.
However, a module file may specify a <<directive-provides,+[provides]+>> directive for a virtual module, so that many modules may provide a different implementation for the same feature.
For example, among the standard modules provided by Jetty, the server module depends on the logging module, but there is no correspondent logging.mod file.
However, the logging-jetty.mod file has, among others, this section:
.logging-jetty.mod
[provides] logging|default
This section means that the logging-jetty.mod file provides the virtual module logging, and it is the default provider.
The logging-log4j2.mod file has a similar section:
.logging-log4j2.mod
[provides] logging
If there are no enabled modules that provide the logging virtual module, either explicitly or transitively, then the default provider is used, in this case logging-jetty.mod.
Otherwise, a module that provides the logging virtual module is explicitly or transitively enabled, and the default provider is not used.
[[components]]
== Module Components
A Jetty module may provide one or more Java components that implement a feature.
These Java components are nothing more than regular Java classes that are instantiated and configured via xref:xml/index.adoc[Jetty XML] files.
The Jetty XML file of a Jetty module may instantiate and assemble together its own components, or reference existing components from other Jetty modules to enhance or reconfigure them.
The Jetty module's XML files are read from the typical xref:start/index.adoc#configure[configuration source directories], under the etc/ subdirectory; from higher priority to lower priority:
- The
$JETTY_BASE/etc/directory. - If a directory is specified with the
--add-config-diroption, itsetc/subdirectory. - The
$JETTY_HOME/etc/directory.
The standard Jetty modules XML files that Jetty provides out-of-the-box are under $JETTY_HOME/etc/.
For example, a Jetty XML file that allocates Jetty's QueuedThreadPool could be as simple as:
[,xml] .jetty-threadpool.xml
</Set>Note how the Jetty XML file above is allocating (with the <New> element) a QueuedThreadPool instance, giving it the unique id of threadPool (so that other modules can reference it, if they need to).
It is then calling the setter method QueuedThreadPool.setMaxThreads(int) with the value defined by the <> jetty.threadPool.maxThreads; if the property value is not defined, it will have the default value of 256.
This is nothing more than Java code in XML format with configurable properties support that can be leveraged by the xref:start/index.adoc[Jetty start mechanism].
The Jetty module's XML files make easy to instantiate and assemble Java components (just write the equivalent Java code in XML format), and make easy to configure them by declaring module properties that can be easily customized elsewhere (for example, in +*.ini+ files as described in xref:start/index.adoc#configure-enable[this section], or on the command line as described in xref:start/index.adoc#start[this section]).
[IMPORTANT]
Remember that the standard Jetty XML files in $JETTY_HOME/etc/ should not be modified.
Even if you need to modify a standard Jetty component, write a new Jetty XML file, save it under `$JETTY_BASE/etc/`, and create a xref:modules/custom.adoc[custom Jetty module] so that it gets processed when Jetty starts.
[[properties]]
== Module Properties
A Jetty module property is declared in the <<components,module XML file(s)>> via the `` element.
Modules properties are used to parametrize Jetty components so that you can customize their values when Jetty starts, rather than hard-coding it in the XML files.
NOTE: You can declare your own properties, but the +jetty.*+ namespace is reserved.
A module property can be given a value in a Jetty module [ini] section (see <<directive-ini,here>>), in a +*.ini+ file as described in xref:start/index.adoc#configure-enable[this section], or on the command line as described in xref:start/index.adoc#start[this section].
The syntax to specify a property value is the following:
=::
Sets the property value unconditionally.
+=::
Appends the value to the existing value.
This is useful to append a value to properties that accept a comma separated list of values, for example:
+
jetty.webapp.addProtectedClasses+=,com.acme.
// TODO: check what happens if the property is empty and +=,value is done: is the comma stripped? If so add a sentence about this.
?=::
Sets the property value only if it is not already set.
This is useful to define default values, for example for "version" properties, where the "version" property can be explicitly configured to a newer version, but if it is not explicitly configured it will have a default version (see also xref:start/index.adoc#configure-custom-module[here]).
For example:
+
conscrypt.version?=2.5.1 jetty.sslContext.provider?=Conscrypt
[[directives]]
== Module Directives
Lines that start with # are comments.
[[directive-description]]
=== [description]
A text that describes the module.
This text will be shown by the xref:start/index.adoc#configure[Jetty start mechanism] when using the --list-modules command.
[[directive-tags]]
=== [tags]
A list of words that characterize the module.
Modules that have the same tags will be shown by the Jetty start mechanism when using the --list-modules=<tag> command.
.example.mod
[tags] demo webapp jsp
[[directive-provides]]
=== [provides]
A module name with an optional default specifier.
As explained in the <<names,module name section>>, there can be many module files each providing a different implementation for the same feature.
The format is:
[provides]
[|default]
where the |default part is optional and specifies that the module is the default provider.
[[directive-depends]]
=== [depends]
A list of module names that this module depends on.
For example, the standard module http depends on module server.
Enabling the http module also enables, transitively, the server module, since the http module cannot work without the server module; when the server module is transitively enabled, the modules it depends on will be transitively enabled, and so on recursively.
The [depends] directive establishes a https://en.wikipedia.org/wiki/Partially_ordered_set[_partial order_] relationship among modules so that enabled modules can be sorted and organized in a graph.
Circular dependencies are not allowed.
The order of the enabled modules is used to determine the processing of the configuration, for example the order of processing of the <<directive-files,+[files]+>> section, the order of processing of XML files defined in the <<directive-xml,+[xml]+>> section, etc.
[[directive-after]]
=== [after]
This directive indicates that this module is ordered after the listed module names, if they are enabled.
For example, module https is [after] module http2.
Enabling the https module does not enable the http2 module.
However, if the http2 module is enabled (explicitly or transitively), then the https module is <<directive-depends,sorted>> after the http2 module.
In this way, you are guaranteed that the https module is processed after the http2 module.
[[directive-before]]
=== [before]
This directive indicates that this module is ordered before the listed module names, if they are enabled.
For example, module test-keystore is [before] module ssl-context.
Enabling the test-keystore module does not enable the ssl-context module.
This directive is used to create a prerequisite module without the need to modify the depends directive of an existing module.
For example, you want to create a custom org.eclipse.jetty.server.Server subclass instance to be used by the standard server module, but without modifying the existing server.mod file nor the jetty.xml file that server.mod uses.
This can be achieved by creating the following custom-server xref:modules/custom.adoc[Jetty custom module]:
.custom-server.mod
[description]
This module creates a custom Server subclass instance.
[before]
server
[xml] etc/custom-server.xml
The custom-server.xml file is the following:
.custom-server.xml [,xml]
The presence of the [before] directive in custom-server.mod causes the processing of the custom-server.xml file to happen before the processing of the standard jetty.xml file referenced by the standard server.mod Jetty module.
Thus, the instance assigned to the Server identifier is your custom com.acme.server.CustomJettyServer instance from the custom-server.xml file; this instance is then used while processing the jetty.xml file.
[[directive-files]]
=== [files]
A list of paths (directories and/or files) that are necessary for the module, created or resolved when the module is enabled.
Each path may be of the following types:
Path Name:: A path name representing a file, or a directory if the path name ends with `/`, such as `webapps/`. The file or directory will be created relative to `$JETTY_BASE`, if not already present. + For example: +
[files] logs/
Maven Artifact:: An URI representing a Maven artifact to be downloaded from Maven Central, if not already present. Property expansion is supported. + The format is: +
[files]
maven:////[/]|
where `` is optional, and `` after the `|` is the path under `$JETTY_BASE` where the downloaded file should be saved.
+
For example:
+
[,options=nowrap]
[files] maven://org.postgresql/postgresql/${postgresql-version}|lib/postgresql-${postgresql-version}.jar
BaseHome:: An URI representing a `$JETTY_HOME` resource to be copied in `$JETTY_BASE`, if not already present. URIs of this type are typically only used by standard Jetty modules; custom modules should not need to use it. + The format is: +
[files]
basehome:|
For example: +
[files] basehome:modules/demo.d/demo-moved-context.xml|webapps/demo-moved-context.xml
HTTP URL::
An `http://` or `https://` URL to be downloaded, if not already present. + The format is: +
[files]
|
For example: +
[files] https://acme.com/favicon.ico|webapps/acme/favicon.ico
[[directive-libs]]
=== [libs]
A list of paths, relative to the xref:start/index.adoc#configure[configuration source directories], of +*.jar+ library files and/or directories that are added to the server class-path (or module-path when xref:start/start-jpms.adoc[running in JPMS mode]).
The [libs] section if often used in conjunction with the [files] section.
For example:
[files]
maven://org.postgresql/postgresql/${postgresql-version}|lib/postgresql-${postgresql-version}.jar
[libs] lib/postgresql-${postgresql-version}.jar
The postgresql-<version>.jar artifact is downloaded from Maven Central, if not already present, into the $JETTY_BASE/lib/ directory when the module is enabled.
When Jetty starts, the $JETTY_BASE/lib/postgresql-<version>.jar will be in the server class-path (or module-path).
[[directive-xml]]
=== [xml]
A list of paths, relative to the xref:start/index.adoc#configure[configuration source directories], of Jetty +*.xml+ files that are passed as program arguments to be processed when Jetty starts (see the xref:start/index.adoc#start-xml[section about assembling Jetty components]).
Jetty XML files are read from the typical xref:start/index.adoc#configure[configuration source directories], under the etc/ subdirectory.
Standard Jetty XML files are under $JETTY_HOME/etc/, while custom Jetty XML files are typically under $JETTY_BASE/etc/.
For example:
[xml] etc/custom/components.xml
[[directive-ini]]
=== [ini]
A list of program arguments to pass to the command line when Jetty is started.
The program arguments may include any command line option (see xref:start/index.adoc#reference[here] for the list of command line options), <> and/or <<components,module XML files>>.
A property defined in the [ini] section is available in the +*.mod+ module file for property expansion, for example:
[ini]
postgresql-version?=42.6.0
[lib] lib/postgresql-${postgresql-version}.jar
In the example above, the [lib] section contains $\{postgresql-version}, a reference to property postgresql-version whose value is defined in the [ini] section.
The expression ${} expands the property replacing the expression with the property value.
See also the xref:start/start-jpms.adoc[JPMS section] for additional examples about the [ini] section.
[[directive-ini-template]]
=== [ini-template]
A list of properties to be copied in the +*.ini+ file generated when xref:start/index.adoc#configure-enable[the module is enabled], either explicitly or transitively.
The list of properties is derived from the <<components,module XML file(s)>> that declare them.
The properties are typically assigned their default value and commented out, so that it is evident which properties have been uncommented and customized with a non-default value.
[[directive-exec]]
=== [exec]
A list of JVM command line options and/or system properties passed to a forked JVM.
When the [exec] section is present, the JVM running the Jetty start mechanism will fork another JVM, passing the JVM command line options and system properties listed in the [exec] sections of the enabled modules.
This is necessary because JVM options such as -Xmx (that specifies the max JVM heap size) cannot be changed in a running JVM.
For an example, see xref:start/index.adoc#configure-custom-module-exec[this section].
You can avoid that the Jetty start mechanism forks the second JVM, as explained in xref:start/index.adoc#configure-dry-run[this section].
[[directive-jpms]]
=== [jpms]
A list of JVM command line options related to the Java Module System.
This section is processed only when Jetty is xref:start/start-jpms.adoc[started in JPMS mode].
The directives are:
add-modules:: Equivalent to the JVM option `--add-modules`. The format is: +
[jpms]
add-modules: (,)*
where module is a JPMS module name.
patch-module:: Equivalent to the JVM option `--patch-module`. The format is: +
[jpms]
patch-module: =(:)*
where module is a JPMS module name.
add-opens:: Equivalent to the JVM option `--add-opens`. The format is: +
[jpms]
add-opens: /=(,)*
where module and target-module are a JPMS module names.
add-exports:: Equivalent to the JVM option `--add-exports`. The format is: +
[jpms]
add-exports: /=(,)*
where module and target-module are a JPMS module names.
add-reads:: Equivalent to the JVM option `--add-exports`. The format is: +
[jpms]
add-reads: =(,)*
where module and target-module are a JPMS module names.
[[directive-license]]
=== [license]
The license under which the module is released.
A Jetty module may be released under a license that is different from Jetty's, or use libraries that require end-users to accept their licenses in order to be used.
You can put the license text in the [license] section, and when the Jetty module is enabled the license text will be printed on the terminal, and the user prompted to accept the license.
If the user does not accept the license, the module will not be enabled.
For example:
[license] Acme Project is an open source project hosted on GitHub and released under the Apache 2.0 license. https://www.apache.org/licenses/LICENSE-2.0.txt
[[directive-version]]
=== [version]
The minimum Jetty version for which this module is valid.
For example, a module may only be valid for Jetty 10 and later, but not for earlier Jetty versions (because it references components that have been introduced in Jetty 10).
For example:
[version] 10.0
A Jetty module with such a section will only work for Jetty 10.0.x or later.
Documentation Jetty Modules Operations Guide Pages Modules Standard (`documentation/jetty/modules/operations-guide/pages/modules/standard.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Standard Modules
[[alpn]]
== Module alpn
The alpn module enables support for the ALPN negotiation mechanism of the TLS protocol.
You can configure the list of application protocols negotiated by the ALPN mechanism, as well as the default protocol to use if the ALPN negotiation fails (for example, the client does not support ALPN).
The module properties are:
include::{jetty-home}/modules/alpn.mod[tags=documentation]
[[accept-rate-limit]]
== Module accept-rate-limit
The accept-rate-limit module limits the rate of new connections accepted by the server, across all connectors.
Once the configured accept rate has been reached, Jetty will not accept more connections.
Existing, established connections will work normally.
Once accepting new connections has been suspended, Jetty will periodically check whether the rate has returned withing the limits, and if so, accepting new connections will be resumed.
This module is often used in conjunction with the xref:network-connection-limit[network-connection-limit] module.
NOTE: The number of connections seen at the JVM level may be different from the number of connections seen at the OS level.
For more information, refer to xref:programming-guide:server/http.adoc#connector-limiting[this section].
The module file is $JETTY_HOME/modules/accept-rate-limit.mod:
include::{jetty-home}/modules/accept-rate-limit.mod[tags=documentation]
[[bytebufferpool]]
== Module bytebufferpool
The bytebufferpool module allows you to configure the server-wide ByteBuffer pool.
Pooling ByteBuffers results in less memory usage and less pressure on the Garbage Collector.
ByteBuffers are pooled in buckets; each bucket as a capacity that is a multiple of a capacity factor that you can configure.
For example, if a request for a ByteBuffer of capacity 2000 is requested, and the capacity factor is 1024, then the pool will allocate a buffer from the second bucket, of capacity 2048 (1024 * 2).
Applications that need to sustain many concurrent requests -- or load spikes -- may require many buffers during peak load. These buffers will remain pooled once the system transitions to a lighter load (or becomes idle), and it may be undesirable to retain a lot of memory for an idle system.
It is possible to configure the max heap memory and the max direct memory that the pool retains.
Excess buffers will not be pooled and will be eventually garbage collected.
The module file is $JETTY_HOME/modules/bytebufferpool.mod:
include::{jetty-home}/modules/bytebufferpool.mod[]
Among the configurable properties, the most relevant are:
jetty.byteBufferPool.maxHeapMemory::
This property allows you to cap the max heap memory retained by the pool.
jetty.byteBufferPool.maxDirectMemory::
This property allows you to cap the max direct memory retained by the pool.
[[compression]]
== Compression Modules
The compression modules allow you to configure server-wide request decompression and response compression by installing the org.eclipse.jetty.compression.server.CompressionHandler at the root of the Handler tree (see also xref:programming-guide:server/http.adoc#handler-use-compression[this section] for further details).
The supported algorithms are the following:
- brotli, via the <<compression-brotli,compression-brotli>> module
- gzip, via the <<compression-gzip,compression-gzip>> module
- zstandard, via the <<compression-zstandard,compression-zstandard>> module
You can explicitly enable one or more of the compression modules, or all of them with the <<compression-all,compression-all>> module.
[[compression-all]]
=== Module compression-all
This module enables request decompression and response compression for all the currently supported algorithms listed in <<compression,this section>>.
[[compression-brotli]]
=== Module compression-brotli
This module enables request decompression and response compression with the link:https://github.com/google/brotli[brotli] algorithm.
The module properties are:
include::{jetty-home}/modules/compression-brotli.mod[tags=documentation]
[[compression-gzip]]
=== Module compression-gzip
This module enables request decompression and response compression with the link:https://en.wikipedia.org/wiki/Gzip[gzip] algorithm.
The module properties are:
include::{jetty-home}/modules/compression-gzip.mod[tags=documentation]
[[compression-zstandard]]
=== Module compression-zstandard
This module enables request decompression and response compression with the link:https://github.com/facebook/zstd[zstdandard] algorithm.
The module properties are:
include::{jetty-home}/modules/compression-zstandard.mod[tags=documentation]
[[network-connection-limit]]
== Module network-connection-limit
The network-connection-limit module limits the number of network connections accepted by the server, across all connectors.
Once the configured maximum number of network connections is reached, Jetty will not accept more network connections.
Existing, established network connections will work normally.
When existing network connections are closed, accepting new network connections will be resumed.
This module is often used in conjunction with the xref:accept-rate-limit[accept-rate-limit] module.
NOTE: The number of network connections seen at the JVM level may be different from the number of network connections seen at the OS level.
For more information, refer to xref:programming-guide:server/http.adoc#connector-limiting[this section].
The module file is $JETTY_HOME/modules/network-connection-limit.mod:
include::{jetty-home}/modules/network-connection-limit.mod[tags=documentation]
[[console-capture]]
== Module console-capture
The console-capture module captures System.out and System.err output and appends it to a rolling file.
The file is rolled every day at the midnight of the configured timezone.
Old, rolled files are kept for the number of days specified by the jetty.console-capture.retainDays property.
The module properties are:
include::{jetty-home}/modules/console-capture.mod[tags=documentation]
[[core-deploy]]
== Module core-deploy
The core-deploy module enables deployment of web applications that only use the Jetty Core APIs, as described in xref:deploy/index.adoc[this section].
See also the <<static-deploy,static-deploy>> module for Jetty static deployment, and the <<eeN-deploy,{ee-all}-deploy>> modules for Jakarta EE deployment environments.
[[cross-origin]]
== Module cross-origin
The cross-origin module provides support for the https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS[CORS protocol] implemented by browsers when performing cross-origin requests.
This module installs the xref:programming-guide:server/http.adoc#handler-use-cross-origin[CrossOriginHandler] in the Handler tree; CrossOriginHandler inspects cross-origin requests and adds the relevant CORS response headers.
CrossOriginHandler should be used when an application performs cross-origin requests to your domain, to protect from https://owasp.org/www-community/attacks/csrf[cross-site request forgery] attacks.
The module properties are:
include::{jetty-home}/modules/cross-origin.mod[tags=documentation]
[[debuglog]]
== Module debuglog
The debuglog module logs extra information about request processing.
This module installs the DebugHandler into the handler tree and logs information into a rollover log file.
By default, the location of the log file is $JETTY_BASE/logs, although this can be configured via the jetty.debuglog.dir.
The name of the log file is of the form: yyyy_mm_dd.debug.log, for example 2024-10-01.debug.log.
All deployed contexts will write to the same log file.
Note that if a request uses asynchronous processing, the log event for the completion of handling may occur out of order with the log event for the continuation of processing.
If more precise logging of request processing is required - including well-ordered async processing events - or you wish to constrain request debug logging to particular contexts only, then configure an ee-specific DebugListener for each context instead of using this module.
The module properties are:
include::{jetty-home}/modules/debuglog.mod[tags=documentation]
[[deployment-scanner]]
== Module deployment-scanner
The deployment-scanner module installs the org.eclipse.jetty.deploy.DeploymentScanner component that watches web application deploy directories for changes, to deploy/redeploy/undeploy web applications that are present in those directories.
This module is a dependency for all the deploy modules such as <<static-deploy,static-deploy>>, <<core-deploy,core-deploy>> and <<eeN-deploy,{ee-all}-deploy.
There is only one DeploymentScanner for all the deploy modules that are enabled.
The module properties are:
include::{jetty-home}/modules/deployment-scanner.mod[tags=documentation]
Among the configurable properties, the most relevant are:
jetty.deploy.webappsDir::
The name of the directory, or a comma-separated list of directories, that is scanned to deploy web applications.jetty.deploy.scanInterval::
The scan period in seconds, that is how frequently the DeploymentScanner wakes up to scan the monitored directories for changes.
By default, jetty.deploy.scanInterval=0 so that hot deployment is disabled and only cold deployment is possible (see also xref:deploy/index.adoc#hot-cold[here] for more information).
[[dos]]
== Module dos
The dos module installs the org.eclipse.jetty.server.handler.DoSHandler at the root of the Handler tree.
The DoSHandler limits the rate of requests per remote client, as explained in xref:programming-guide:server/http.adoc#handler-use-dos[this section].
The module properties are:
include::{jetty-home}/modules/dos.mod[tags=documentation]
[[eager-content]]
== Module eager-content
The eager-content module installs the org.eclipse.jetty.server.handler.EagerContentHandler at the root of the Handler tree.
The EagerContentHandler can eagerly load request content, asynchronously, before calling the next Handler.
For more information see xref:programming-guide:server/http.adoc#handler-use-eager[this section].
EagerContentHandler can eagerly load content for form uploads, multipart uploads and any request content, and you can configure it with different properties for these three cases.
The module properties are:
include::{jetty-home}/modules/eager-content.mod[tags=documentation]
[[eeN-deploy]]
== Module {ee-all}-deploy
The {ee-all}-deploy modules enable deployment of corresponding Java/Jakarta EE web applications, as described in xref:deploy/index.adoc[this section].
Each eeN-deploy module supports the correspondent Java/Jakarta EE specification.
Multiple eeN-deploy modules may be enabled at the same time, allowing deployment of, for example, old Java EE 8 web applications alongside new Jakarta {ee-current-caps} web applications, in the same server.
The module configuration properties are nearly identical across the EE versions.
The module configuration properties for the {ee-current}-deploy Jetty module are:
[,properties,subs=+attributes]
include::{jetty-home}/modules/{ee-current}-deploy.mod[tags=ini-template]
See also the <<static-deploy,static-deploy>> module and the <<core-deploy,core-deploy>> module for Jetty specific deployment environments.
[[eeN-ext]]
== Module {ee-all}-ext
The {ee-all}-ext modules allow to add libraries to the environment class-path or module-path, for example to provide implementations of Jakarta APIs such as a Jakarta Mail implementation or Jakarta Transaction implementation.
The libraries must be in +*.jar+ format, and must be placed in $JETTY_BASE/lib/{ee-all}/ext.
Refer also to the server specific <<ext,ext>> module.
[[eeN-proxy]]
== Module {ee-all}-proxy
The {ee-all}-proxy module adds a simple reverse proxy service that proxies incoming requests to a backend server.
Each module targets the corresponding Jakarta EE platform version.
The module properties are:
include::{jetty-home}/modules/{ee-current}-proxy.mod[tags=documentation]
Among the configurable properties, the only mandatory one is:
jetty.proxy.proxyTo::
The URI of the backend server, in absolute form, for example +http://backend:9090/path+.
+
The path in context of the incoming request is appended to the jetty.proxy.proxyTo property to obtain the URI to proxy to.
For example, for the incoming URI +http://proxy:8080/ctx/foo/bar+, the path in context (assuming the context path is /ctx) is /foo/bar, therefore the request is proxied to +http://backend:9090/path/foo/bar+.
[[eeN-webapp]]
== Module {ee-all}-webapp
The {ee-all}-webapp module adds support for Jakarta {ee-all-caps} web applications.
Multiple versions of this module exist ({ee-all}-webapp) to support each Jakarta EE platform's version of the Java Servlet specification.
The module configuration properties are identical across all versions of this module, and are as follows:
include::{jetty-home}/modules/{ee-current}-webapp.mod[tags=ini-template]
Configuration of protected and hidden classes, if necessary, is explained in xref:programming-guide:server/http.adoc#handler-use-webapp-context-class-loading[this section].
Refer also to the module properties syntax, detailed xref:modules/index.adoc#properties[here].
[[ext]]
== Module ext
The ext module allows to add libraries to the server class-path or module-path, for example for custom classes that extend Jetty classes, for server-wide logging libraries, for JDBC drivers, etc.
The libraries must be in +*.jar+ format, and must be placed in $JETTY_BASE/lib/ext.
Refer also to the environment specific <<eeN-ext,{ee-all}-ext>> modules.
[[graceful]]
== Module graceful
The graceful module allows to shut down gracefully the Jetty server when it is stopped (see xref:start/index.adoc#stop[this section] for more information about stopping Jetty).
The graceful module installs the GracefulHandler at the root of the Handler tree; the GracefulHandler rejects new requests, but allows current requests to terminate within a configurable timeout, as explained in xref:programming-guide:server/http.adoc#handler-use-graceful[this section].
The module properties are:
include::{jetty-home}/modules/graceful.mod[tags=documentation]
[[http]]
== Module http
The http module provides the clear-text connector and support for the clear-text HTTP/1.1 protocol, and depends on the <<server,server module>>.
The module properties to configure the clear-text connector are:
include::{jetty-home}/modules/http.mod[tags=documentation]
Among the configurable properties, the most relevant are:
jetty.http.port::
The network port that Jetty listens to for clear-text HTTP/1.1 connections -- default 8080.jetty.http.idleTimeout::
The amount of time a connection can be idle (i.e. no bytes received and no bytes sent) until the server decides to close it to save resources -- default 30 seconds.jetty.http.acceptors::
The number of threads that compete to accept connections -- default 1. Use -1 to let the accept heuristic decides the value; the current heuristic calculates a value based on the number of cores).
Refer to <<http-acceptors,this section>> for more information about acceptor threads.jetty.http.selectors::
The number of NIO selectors (with an associated thread) that manage connections -- default -1 (i.e. a select heuristic decides the value; the current heuristic calculates a value based on the number of cores).
[[http-acceptors]]
=== Configuration of Acceptors
Accepting connections from remote clients may be configured as a blocking operation, or a non-blocking operation.
When accepting connections is configured as a blocking operation (the number of acceptors is greater than zero), a thread is blocked in the accept() call until a connection is accepted, and other acceptor threads (if any) are blocked on the lock acquired by the accepting thread just before the accept() call.
When the accepting thread accepts a connection, it performs a little processing of the just accepted connection, before forwarding it to other components.
During this little processing other connections may be established; if there is only one accepting thread, the newly established connections are waiting for the accepting thread to finish the processing of the previously accepted connection and call again accept().
Servers that manage a very high number of connections that may (naturally) come and go, or that handle inefficient protocols that open and close connections very frequently (such as HTTP/1.0) may benefit of an increased number of acceptor threads, so that when one acceptor thread processes a just accepted connection, another acceptor thread can immediately take over accepting connections.
When accepting connections is configured as a non-blocking operation (the number of acceptors is zero), then the server socket is set in non-blocking mode and added to a NIO selector.
In this way, no dedicated acceptor threads exist: the work of accepting connections is performed by the selector thread.
[[http-selectors]]
=== Configuration of Selectors
Performing a NIO select() call is a blocking operation, where the selecting thread is blocked in the select() call until at least one connection is ready to be processed for an I/O operation.
There are 4 I/O operations: ready to be accepted, ready to be connected, ready to be read and ready to be written.
A single NIO selector can manage thousands of connections, with the assumption that not many of them will be ready at the same time.
For a single NIO selector, the ratio between the average number of selected connections over the total number of connections for every select() call depends heavily on the protocol but also on the application.
Multiplexed TCP protocols such as HTTP/2 tend to be busier than duplex protocols such as HTTP/1.1, leading to a higher ratio.
REST applications that exchange many little JSON messages tend to be busier than file server applications, leading to a higher ratio.
The higher the ratio, the higher the number of selectors you want to have, compatibly with the number of cores -- there is no point in having 64 selector threads on a single core hardware.
[[http2]]
== Module http2
The http2 module enables support for the secure HTTP/2 protocol.
The module properties are:
include::{jetty-home}/modules/http2.mod[tags=documentation]
// tag::rate-control[]
The jetty.http2.rateControl.maxEventsPerSecond property controls the number of "bad" or "unnecessary" frames that a client may send before the server closes the connection (with code https://tools.ietf.org/html/rfc7540#section-7[`ENHANCE_YOUR_CALM`]) to avoid a denial of service.
For example, an attacker may send empty SETTINGS frames to a server in a tight loop.
While the SETTINGS frames don't change the server configuration and each of them is somehow harmless, the server will be very busy processing them because they are sent by the attacker one after the other, causing a CPU spike and eventually a denial of service (as all CPUs will be busy processing empty SETTINGS frames).
The same attack may be performed with PRIORITY frames, empty DATA frames, PING frames, etc.
[[http2c]]
== Module http2c
The http2c module enables support for the clear-text HTTP/2 protocol.
The module properties are:
include::{jetty-home}/modules/http2c.mod[tags=documentation]
The jetty.http2.rateControl.maxEventsPerSecond property controls the number of "bad" or "unnecessary" frames that a client may send before the server closes the connection (with code https://tools.ietf.org/html/rfc7540#section-7[`ENHANCE_YOUR_CALM`]) to avoid a denial of service.
For example, an attacker may send empty SETTINGS frames to a server in a tight loop.
While the SETTINGS frames don't change the server configuration and each of them is somehow harmless, the server will be very busy processing them because they are sent by the attacker one after the other, causing a CPU spike and eventually a denial of service (as all CPUs will be busy processing empty SETTINGS frames).
The same attack may be performed with PRIORITY frames, empty DATA frames, PING frames, etc.
[[http3]]
== Module http3
The http3 module enables support for the HTTP/3 protocol.
Support for the QUIC protocol underlying HTTP/3 is provided by default via the http3-quiche module that uses the link:https://github.com/cloudflare/quiche[Quiche] native library.
The http3-quiche module properties are:
include::{jetty-home}/modules/http3-quiche.mod[tags=documentation]
[[http-config]]
== Module http-config
The http-config module provides HTTP configuration parameters that describe the HTTP semantic, and therefore do not depend on a specific HTTP protocol version.
This module creates an instance of HttpConfiguration for clear-text HTTP.
For secure HTTP, the <<ssl,ssl>> module creates a copy of the HttpConfiguration created by this module.
The module properties are:
include::{jetty-home}/modules/http-config.mod[tags=documentation]
Among the configurable properties, the most relevant are:
jetty.httpConfig.requestHeaderSize::
The maximum size of the request headers, beyond which the request is rejected with the HTTP status code 431 Request Header Fields Too Large.
jetty.httpConfig.headerCacheSize::
The header cache is used when parsing HTTP/1 to more efficiently handle fields that are repeated in every request on a connection. If the server does not receive persistent connection or infrequent repeated fields, then there may be a performance gain in reducing the cache size. If large fields are frequently repeated, then a large cache may be beneficial.
jetty.httpConfig.outputAggregationSize::
The size of the buffer that aggregates response writes that are not explicitly flushed.
This is used only at the Servlet layer, to buffer writes performed with ServletOutputStream.
`jetty.httpConfig.sendServerVersion`:: Whether you want to send the `Server` header in every HTTP response: + [source,subs=attributes+]
HTTP/1.1 200 OK Content-Length: 0 Server: Jetty({jetty-version})
=== Server Compliance Properties
The Jetty server strives to keep up with the latest https://en.wikipedia.org/wiki/Request_for_Comments[IETF RFC]s for compliance with internet specifications, which are periodically updated.
When possible, Jetty will support backwards compatibility by providing compliance modes that can be configured to allow violations of the current specifications that may have been allowed in obsoleted specifications.
The module properties to configure the Jetty server compliance are:
include::{jetty-home}/modules/http-config.mod[tags=documentation-compliance]
Among the configurable properties, the most relevant are:
jetty.httpConfig.compliance::
Configures the compliance to HTTP specifications, see also xref:programming-guide:server/compliance.adoc#http[this section].
+
The value could be: one of the predefined link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html[HttpCompliance] constants, such as RFC9110, RFC7230 or RFC2616; or a comma-separated list of violations to allow or forbid, as specified by the link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html#from(java.lang.String)[HttpCompliance.from(String)] method.
+
For example, jetty.httpConfig.compliance=RFC9110,MULTIPLE_CONTENT_LENGTHS means that the HTTP compliance is that defined by RFC9110, but also allows the HttpCompliance.Violation.MULTIPLE_CONTENT_LENGTHS, so that requests that have multiple Content-Length headers are accepted (they would be rejected when using just HttpCompliance.RFC9110).
jetty.httpConfig.uriCompliance::
Configures the compliance to URI specifications, see also xref:programming-guide:server/compliance.adoc#uri[this section].
+
The value could be: one of the predefined link:{javadoc-url}/org/eclipse/jetty/http/UriCompliance.html[UriCompliance] constants, such as DEFAULT or RFC3986; or a comma-separated list of violations to allow or forbid, as specified by the link:{javadoc-url}/org/eclipse/jetty/http/UriCompliance.html#from(java.lang.String)[UriCompliance.from(String)] method.
+
For example, jetty.httpConfig.uriCompliance=RFC3986,-AMBIGUOUS_PATH_SEPARATOR means that the URI compliance is that defined by RFC3986, but also does not allow the UriCompliance.Violation.AMBIGUOUS_PATH_SEPARATOR, so that requests that have URIs such as /foo/bar%2Fbaz (where %2F is the URL-encoded / character) are rejected (they would be accepted when using just UriCompliance.RFC3986).
jetty.httpConfig.requestCookieCompliance::jetty.httpConfig.responseCookieCompliance::
Configure the compliance to HTTP cookie specifications, respectively for requests and responses, see also xref:programming-guide:server/compliance.adoc#cookie[this section].
+
The value could be: one of the predefined link:{javadoc-url}/org/eclipse/jetty/http/CookieCompliance.html[CookieCompliance] constants, such as RFC6265; or a comma-separated list of violations to allow or forbid, as specified by the link:{javadoc-url}/org/eclipse/jetty/http/CookieCompliance.html#from(java.lang.String)[CookieCompliance.from(String)] method.
+
For example, jetty.httpConfig.requestCookieCompliance=RFC6265,-RESERVED_NAMES_NOT_DOLLAR_PREFIXED means that the cookie compliance is that defined by RFC6265, but also does not allow the CookieCompliance.Violation.RESERVED_NAMES_NOT_DOLLAR_PREFIXED, so that requests that have cookie headers such as Cookie: $foo=bar are rejected (they would be accepted when using just CookieCompliance.RFC6265).
jetty.httpConfig.multiPartCompliance::
Configures the compliance to MultiPart specifications, see also xref:programming-guide:server/compliance.adoc#multiPart[this section].
+
The value could be: one of the predefined link:{javadoc-url}/org/eclipse/jetty/http/MultiPartCompliance.html[MultiPartCompliance] constants, such as RFC7578_STRICT or RFC7578; or a comma-separated list of violations to allow or forbid, as specified by the link:{javadoc-url}/org/eclipse/jetty/http/MultiPartCompliance.html#from(java.lang.String)[MultiPartCompliance.from(String)] method.
+
For example, jetty.httpConfig.multiPartCompliance=RFC7578,-CONTENT_TRANSFER_ENCODING means that the MultiPart compliance is that defined by RFC7578, but also does not allow the MultiPartCompliance.Violation.CONTENT_TRANSFER_ENCODING, so that parts that specify the Content-Transfer-Encoding header are rejected (they would be accepted when using just MultiPartCompliance.RFC7578).
[[forwarded]]
== Module forwarded
The forwarded module provides support for processing the Forwarded HTTP header (defined in https://tools.ietf.org/html/rfc7239[RFC 7239]) and the now obsoleted X-Forwarded-* HTTP headers.
The module properties are:
include::{jetty-home}/modules/forwarded.mod[tags=documentation]
[[https]]
== Module https
The https module provides the HTTP/1.1 protocol to the <<ssl,ssl module>>.
The module file is $JETTY_HOME/modules/https.mod:
include::{jetty-home}/modules/https.mod[]
[[jmx]]
== Module jmx
include::{jetty-home}/modules/jmx.mod[tags=description]
This configuration is useful for xref:jmx/index.adoc#local[local development and testing].
If you need to xref:jmx/index.adoc#remote[enable remote access], use the xref:jmx/index.adoc#remote[jmx-remote module].
[[jmx-remote]]
== Module jmx-remote
The jmx-remote module provides remote access to JMX clients.
The module properties to configure remote JMX connector are:
include::{jetty-home}/modules/jmx-remote.mod[tags=documentation]
The system property java.rmi.server.hostname is specified with the usual notation, prepending a -D in front of the system property name.
The system property java.rmi.server.hostname is uncommented because it is necessary in the default configuration -- most systems do not have the local name resolution configured properly for remote access.
As an example, in a Linux machine named beryl, the /etc/hosts file may contain these entries:
127.0.0.1 localhost 127.0.1.1 beryl
If the system property java.rmi.server.hostname is not specified, the RMI implementation uses the host name beryl to figure out the IP address to store in the RMI stub, in this case 127.0.1.1.
However, the RMI server is configured to bind to localhost, i.e. 127.0.0.1.
If the system property java.rmi.server.hostname is not specified, the RMI client will try to connect to 127.0.1.1 (because that's what in the RMI stub) and fail because nothing is listening on that address.
[[loginservice-hash]]
== Module loginservice-hash
The loginservice-hash module creates a HashLoginService and adds it as a bean on the Server.
A SecurityHandler uses it by matching its configured realm name.
The HashLoginService reads users, their credentials and their roles from a properties file, where each line has the format : [,<rolename>...].
Enabling the module copies a template etc/realm.properties file into the $JETTY_BASE directory that you can edit to define your users.
The jetty.hashLoginService.name property sets the realm name, which must match the realm name expected by the Authenticator.
It defaults to default, the realm name used by web applications that declare a <login-config> without an explicit <realm-name>.
Set it to match the <realm-name> in a web application's web.xml when a specific realm is used.
The module properties are:
include::{jetty-home}/modules/loginservice-hash.mod[tags=documentation]
See also xref:programming-guide:security/index.adoc[this section] for more information about Jetty's security features.
[[min-data-rate]]
== Module min-data-rate
The min-data-rate installs the MinimumDataRateHandler at the root of the Handler tree.MinimumDataRateHandler enables support to enforce minimum data rates for reading request content and writing response content, as explained in xref:programming-guide:server/http.adoc#handler-use-min-data-rate[this section].
The module properties are:
include::{jetty-home}/modules/min-data-rate.mod[tags=documentation]
[[openid]]
== Module openid
The openid module enables support for OpenID Connect (OIDC) authentication in Jetty, as detailed in xref:security/openid-support.adoc#openid-support[this section].
This module allows Jetty to authenticate users via an OpenID Connect identity provider, making possible to integrate features like "Sign in with Google" or "Sign in with Microsoft", among others.
This simplifies user authentication while leveraging the security and convenience of external identity providers.
The module properties are:
include::{jetty-home}/modules/openid.mod[tags=documentation]
Among the configurable properties, the only required properties are:
jetty.openid.provider::
The issuer identifier of the OpenID Provider, which is the base URL before .well-known/openid-configuration. It must match the issuer field in the provider's configuration and is case-sensitive.jetty.openid.clientId::
The Client Identifier assigned to your application by the OpenID Provider, used to uniquely identify your app during authentication requests.jetty.openid.clientSecret::
The Client Secret issued by the OpenID Provider, used to verify your application's identity during the authentication process. This must be kept confidential.
[[qos]]
== Module qos
The qos module installs the QoSHandler at the root of the Handler tree; the QoSHandler applies limits to the number of concurrent requests, as explained in xref:programming-guide:server/http.adoc#handler-use-qos[this section].
The module properties are:
include::{jetty-home}/modules/qos.mod[tags=documentation]
[[requestlog]]
== Module requestlog
The requestlog module provides HTTP request/response logging in the standard https://en.wikipedia.org/wiki/Common_Log_Format[NCSA format], or in a custom format of your choice.
The module properties are:
include::{jetty-home}/modules/requestlog.mod[tags=documentation]
The property jetty.requestlog.formatString can be customized using format codes.
javadoc::code:partial$org/eclipse/jetty/server/CustomRequestLog.java[]
[[requestlog-slf4j]]
== Module requestlog-slf4j
The requestlog-slf4j module provides HTTP request/response logging to the SLF4J logging framework, as an alternative to the file-based <<requestlog,requestlog>> module.
Request logs are written to a configurable SLF4J logger at INFO level, allowing integration with any SLF4J-compatible logging framework (Logback, Log4j2, etc.).
The module properties are:
include::{jetty-home}/modules/requestlog-slf4j.mod[tags=documentation]
The property jetty.requestlog.formatString uses the same format codes as the <<requestlog,requestlog>> module.
javadoc::code:partial$org/eclipse/jetty/server/CustomRequestLog.java[]
[NOTE]
Unlike the `requestlog` module, `requestlog-slf4j` does not create a `logs/` directory or write to files. All log output is handled by your SLF4J logging configuration.
[[resources]]
== Module resources
include::{jetty-home}/modules/resources.mod[tags=description]
A common use-case for this module is to provide resources for third-party libraries via the xref:start/index.adoc#start-class-path[server classpath].
For instance, many logging libraries (including https://logging.apache.org/log4j/2.x/[Log4j2] and https://logback.qos.ch/[Logback]) look for their configuration files on the classpath.
Jetty provides a logging library implementation -- enabled via the logging-jetty module -- whose configuration file is $JETTY_BASE/resources/jetty-logging.properties.
[[rewrite]]
== Module rewrite
The rewrite module inserts the RewriteHandler at the beginning of the Handler chain, providing URI-rewriting features similar to the https://httpd.apache.org/docs/current/mod/mod_rewrite.html[Apache's mod_rewrite] or the https://nginx.org/en/docs/http/ngx_http_rewrite_module.html[Nginx rewrite module].
The module properties are:
include::{jetty-home}/modules/rewrite.mod[tags=documentation]
A common use of the rewrite module is to redirect/rewrite old URI paths that have been renamed, for example from +/old/*+ to +/new/*+; in this way, the old paths will not result in a 404 response, but rather be redirected/rewritten to the new paths.
RewriteHandler matches incoming requests against a set of rules that you can specify in the $JETTY_BASE/etc/jetty-rewrite-rules.xml file.
Rules can be matched against request data such as the request URI or the request headers; if there is a match, the rule is applied.
The rule file $JETTY_BASE/etc/jetty-rewrite-rules.xml is initially empty, but contains commented examples of rules that you can add.
The list of available rules can be found link:{javadoc-url}/org/eclipse/jetty/rewrite/handler/package-summary.html[here].
An example of jetty-rewrite-rules.xml is the following:
[,xml] .jetty-rewrite-rules.xml
<Arg>
<New class="org.eclipse.jetty.rewrite.handler.RedirectRegexRule">
<Set name="statusCode">301</Set>
<Set name="pattern">/old/(.*)</Set>
<Set name="location">/new/$1</Set>
</New>
</Arg>Rules can be scoped to a specific virtual host.
In the example below, the rule will only be evaluated if the virtual host matches example.com:
[,xml] .jetty-rewrite-rules.xml
<Arg>example.com</Arg>
</Call>
<Call name="addRule">
<Arg>
<New class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
<Set name="pattern">/advice</Set>
<Set name="location">/support</Set>
</New>
</Arg>
</Call>
</New>
</Arg>[[scheduler]]
== Module scheduler
The scheduler module allows you to configure the server-wide scheduler.
The scheduler is used to schedule tasks that must run at a later time, for example the tasks that perform actions when timeouts expire, in particular idle timeouts.
The module properties to configure the scheduler are:
include::{jetty-home}/modules/scheduler.mod[tags=documentation]
[[server]]
== Module server
The server module provides generic server support, and configures generic HTTP properties that apply to all HTTP protocols, the scheduler properties and the server specific properties.
[NOTE]
The server module configures the shared parameters for generic HTTP handling, but does not enable any specific network protocol.
You have to explicitly enable the protocols you want to support by enabling, for example, the <<http,http module>> for clear-text HTTP/1.1 support, or the <<http2,http2 module>> for secure HTTP/2 support, etc.
See also the xref:protocols/index.adoc[protocols section] for more information about the supported protocols.
[[server-config]]
=== Server Configuration Properties
The module properties to configure the Jetty server are:
include::{jetty-home}/modules/server.mod[tags=documentation]
Among the configurable properties, the most relevant are:
jetty.server.dumpAfterStart::
Whether to perform a Server.dump() operation after the Server has started.
The output of the dump operation is sent to System.err.
See also the xref:troubleshooting/index.adoc#dump[Jetty Server Dump] section for more information.
jetty.server.dumpBeforeStop::
Whether to perform a Server.dump() operation before the Server stops.
The output of the dump operation is sent to System.err.
See also the xref:troubleshooting/index.adoc#dump[Jetty Server Dump] section for more information.
jetty.server.stopAtShutdown::
Whether to call Server.stop() through a JVM shutdown hook when the JVM exits.
[[size-limit]]
== Module size-limit
The size-limit module installs the SizeLimitHandler at the root of the Handler tree; the SizeLimitHandler applies limits to the request content and the response content, as explained in xref:programming-guide:server/http.adoc#handler-use-size-limit[this section].
The module properties are:
include::{jetty-home}/modules/size-limit.mod[tags=documentation]
[[ssl]]
== Module ssl
The ssl module provides the secure connector, and allows you to configure the KeyStore properties and the TLS parameters, and depends on the <<server,server module>>.
For more information about securing a connector and supporting secure protocols, refer to xref:protocols/index.adoc#ssl[this section].
The module properties to configure the secure connector are:
include::{jetty-home}/modules/ssl.mod[tags=documentation]
Among the configurable properties, the most relevant are:
jetty.ssl.port::
The network port that Jetty listens to for secure connections -- default 8443.jetty.ssl.idleTimeout::
The amount of time a connection can be idle (i.e. no bytes received and no bytes sent) until the server decides to close it to save resources -- default 30000 milliseconds.jetty.ssl.acceptors::
The number of threads that compete to accept connections -- default 1. Use -1 to let the accept heuristic decides the value; the current heuristic calculates a value based on the number of cores).
Refer to <<http-acceptors,this section>> for more information about acceptor threads.jetty.ssl.selectors::
The number of NIO selectors (with an associated thread) that manage connections -- default -1 (i.e. a select heuristic decides the value; the current heuristic calculates a value based on the number of cores).
Refer to <<http-selectors,this section>> for more information about selector threads.
[[ssl-context]]
== Module ssl-context
The ssl-context module provides the KeyStore, TrustStore and TLS configuration necessary to the ssl module.
The Jetty component that manages the KeyStore, that contains the cryptographic material and the TLS configuration is an instance of SslContextFactory.Server.
The module properties to configure the KeyStore and TLS parameters are:
include::{jetty-home}/modules/ssl-context.mod[tags=documentation]
Among the configurable properties, the most relevant are:
jetty.sslContext.keyStorePath::
The KeyStore path on the file system, either an absolute path or a relative path to $JETTY_BASE -- defaults to $JETTY_BASE/etc/keystore.p12.jetty.sslContext.keyStorePassword::
The KeyStore password, which you want to explicitly configure.
The password may be obfuscated with the xref:tools/index.adoc#password[Jetty Password tool].
If you need to configure client certificate authentication, you want to configure one of these properties (they are mutually exclusive):
jetty.sslContext.needClientAuth::
Whether client certificate authentication should be required.jetty.sslContext.wantClientAuth::
Whether client certificate authentication should be requested.
Configuring SslContextFactory.Server using properties is sufficient for most cases.
For the cases where Jetty module properties are not defined, or when you need more advanced configuration, you can refer to xref:protocols/index.adoc#ssl-customize[this section].
If you configure client certificate authentication, you need to configure and distribute a client KeyStore as explained in xref:keystore/index.adoc#client-authn[this section].
[[ssl-reload]]
== Module ssl-reload
The ssl-reload module provides a periodic scanning of the directory where the KeyStore file resides.
When the scanning detects a change to the KeyStore file, the correspondent SslContextFactory.Server component is reloaded with the new KeyStore configuration.
The module properties are:
include::{jetty-home}/modules/ssl-reload.mod[tags=documentation]
[[state-tracking]]
== Module state-tracking
The state-tracking Jetty module inserts the StateTrackingHandler at the beginning of the Handler chain.
StateTrackingHandler is a xref:troubleshooting/index.adoc[troubleshooting] Handler that tracks usages of Handler/Request/Response asynchronous APIs, and logs at warning level invalid usages of the APIs that may lead to blockages, deadlocks, or missing completion of Callbacks.
This module can be enabled to troubleshoot web applications that do not behave as expected, for example:
- That consume a lot of threads (possibly because they block).
- That do not send responses (or send only partial responses) to clients.
- That timeout when apparently they have received or have sent all data.
The module properties are:
include::{jetty-home}/modules/state-tracking.mod[tags=documentation]
[[static-deploy]]
== Module static-deploy
The static-deploy module enables deployment of web applications that consist only of static files, as described in xref:deploy/index.adoc[this section].
See also the <<core-deploy,core-deploy>> module for Jetty core deployment, and the <<eeN-deploy,{ee-all}-deploy>> modules for Jakarta EE deployment environments.
[[test-keystore]]
== Module test-keystore
The test-keystore module creates on-the-fly a KeyStore containing a self-signed certificate for domain localhost.
The KeyStore file is automatically deleted when the JVM exits, and re-created when you restart Jetty, to enforce the fact that it is a test KeyStore that should not be reused if not for testing.
The module file is $JETTY_HOME/modules/test-keystore.mod:
include::{jetty-home}/modules/test-keystore.mod[]
Note how properties jetty.sslContext.keyStorePath and jetty.sslContext.keyStorePassword are configured, only if not already set (via the ?= operator), directly in the module file, rather than in a +*.ini+ file.
This is done to avoid that these properties accidentally overwrite a real KeyStore configuration.
[[thread-limit]]
== Module thread-limit
The thread-limit module installs the ThreadLimitHandler at the root of the Handler tree; the ThreadLimitHandler applies limits to the number of concurrent threads per remote IP address, as explained in xref:programming-guide:server/http.adoc#handler-use-thread-limit[this section].
The module properties are:
include::{jetty-home}/modules/thread-limit.mod[tags=documentation]
[[threadpool]]
== Module threadpool
The threadpool module allows you to configure the server-wide thread pool.
The thread pool creates threads on demand up to maxThreads, and idles them out if they are not used.
Since Jetty uses the thread pool internally to execute critical tasks, it is not recommended to constrain the thread pool to small values of maxThreads with the purpose of limiting HTTP request concurrency, as this could very likely cause a server lockup when Jetty needs to run a critical task but there are no threads available.
Start with the default value of maxThreads, and tune for larger values if needed.
The module properties to configure the thread pool are:
include::{jetty-home}/modules/threadpool.mod[tags=documentation]
Among the configurable properties, the most relevant are:
jetty.threadPool.namePrefix::
The name prefix to use for the thread names.
jetty.threadPool.detailedDump::
Whether the thread pool should dump the whole stack trace of each thread, or just the topmost stack frame -- defaults to false.
jetty.threadPool.idleTimeout::
The time, in milliseconds, after which an idle thread is released from the pool -- defaults to 60000, i.e. 60 seconds.
jetty.threadPool.maxThreads::
The max number of threads pooled by the thread pool -- defaults to 200.
If you want to use virtual threads, introduced as a preview feature in Java 19 and Java 20, and become an official feature since Java 21, use the following modules:
- The <> Jetty module for Java 21 or later.
- The <> Jetty module for Java 19 and Java 20.
See also the xref:server/index.adoc#threadpool[section about configuring the thread pool].
[[threadpool-all-virtual]]
== Module threadpool-all-virtual
The threadpool-all-virtual module allows you to configure the server-wide thread pool, similarly to what you can do with the <> Jetty module, so that all threads are virtual threads, introduced as an official feature since Java 21.
CAUTION: Only use this module if you are using Java 21 or later.
The module properties to configure the thread pool are:
include::{jetty-home}/modules/threadpool-all-virtual.mod[tags=documentation]
The property jetty.threadpool.maxThreads limits, using a Semaphore, the number of current virtual threads in use.
Please refer to the xref:programming-guide:arch/threads.adoc#thread-pool-virtual-threads[virtual threads section] of the Jetty Threading Architecture for more information about virtual threads and their pitfalls.
[[threadpool-virtual]]
== Module threadpool-virtual
The threadpool-virtual module allows you to configure the server-wide thread pool, similarly to what you can do with the <> Jetty module, but also specify to use virtual threads, introduced as an official feature since Java 21.
CAUTION: Only use this module if you are using Java 21 or later.
If you are using Java 19 or Java 20, use the <> Jetty module instead.
Refer to the <> Jetty module for the general features provided by that Jetty module that also this Jetty module provides.
The module properties to configure the thread pool are:
include::{jetty-home}/modules/threadpool-virtual.mod[tags=documentation]
The specific properties to configure virtual threads are:
jetty.threadPool.virtual.namePrefix::
The name prefix to use for the virtual thread names.
jetty.threadPool.virtual.tracking::
Whether to track virtual threads so that they appear in a xref:troubleshooting/index.adoc#dump[Server Dump] even when they are unmounted.
jetty.threadPool.virtual.maxConcurrentTasks::
The number of concurrent tasks run by virtual threads.
This property limits resource usage, avoiding that virtual threads run an unlimited number of concurrent tasks when the system is under load.
[[threadpool-virtual-preview]]
== Module threadpool-virtual-preview
The threadpool-virtual-preview module allows you to configure the server-wide thread pool, similarly to what you can do with the <> Jetty module, but also specify to use virtual threads, introduced as a preview feature in Java 19 and in Java 20.
CAUTION: Only use this module if you are using Java 19 or Java 20.
If you are using Java 21 or later, use the <> Jetty module instead.
NOTE: To enable preview features, this module needs to specify the +--enable-preview+ command line option using the xref:modules/index.adoc#directive-exec[[exec] directive], and as such it will fork another JVM.
Refer to the <> Jetty module for the general features provided by that Jetty module that also this Jetty module provides.
The module properties to configure the thread pool are:
include::{jetty-home}/modules/threadpool-virtual-preview.mod[tags=documentation]
The specific properties to configure virtual threads are:
jetty.threadPool.virtual.namePrefix::
The name prefix to use for the virtual thread names.
jetty.threadPool.virtual.allowSetThreadLocals::
Whether virtual threads are allowed to set thread locals.
jetty.threadPool.virtual.inheritInheritableThreadLocals::
Whether virtual threads inherit the values of InheritableThreadLocal variables.
[[well-known]]
== Module well-known
The well-known Jetty module creates a ResourceHandler deployed at the /.well-known context path which serves files from a directory.
By default, the directory created at $JETTY_BASE/.well-known is used, but it can be configured from well-known.ini to anywhere in the filesystem.
Note that the .well-known directory may be seen as a hidden directory by the filesystem.
The concept of well-known URIs has been defined in https://datatracker.ietf.org/doc/html/rfc5785[RFC5785].
This module can be used for things like the automatic renewal of https://letsencrypt.org/[Let's Encrypt] certificates.
See https://www.iana.org/assignments/well-known-uris/well-known-uris.xhtml[IANA Well-Known URIs] for more possible examples of how this can be used.
The module properties are:
include::{jetty-home}/modules/well-known.mod[tags=documentation]
Documentation Jetty Modules Operations Guide Pages Protocols Index (`documentation/jetty/modules/operations-guide/pages/protocols/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jetty Connectors and Protocols
Connectors are the network components through which Jetty accepts incoming network connections.
Each connector listens on a network port and can be configured with ConnectionFactory components that understand one or more network protocols.
Understanding a protocol means that the connector is able to interpret incoming network bytes (for example, the bytes that represent an HTTP/1.1 request) and convert them into more abstract objects (for example an HttpServletRequest object) that are then processed by applications.
Conversely, an abstract object (for example an HttpServletResponse) is converted into the correspondent outgoing network bytes (the bytes that represent an HTTP/1.1 response).
Like other Jetty components, connectors are enabled and configured by enabling and configuring the correspondent Jetty module.
IMPORTANT: Recall that you must always issue the commands to enable Jetty modules from within the $JETTY_BASE directory, and that the Jetty module configuration files are in the $JETTY_BASE/start.d/ directory.
You can obtain the list of connector-related modules in this way:
$ java -jar $JETTY_HOME/start.jar --list-modules=connector
[[http]]
== Clear-Text HTTP/1.1
Clear text HTTP/1.1 is enabled with the http Jetty module with the following command (issued from within the $JETTY_BASE directory):
$ java -jar $JETTY_HOME/start.jar --add-modules=http
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http
....
After having enabled the http module, the $JETTY_BASE directory looks like this:
[source,subs=+quotes]
JETTY_BASE
├── resources
│ └── jetty-logging.properties
└── start.d
└── #http.ini#
The http.ini file is the file that you want to edit to configure network and protocol parameters -- for more details see xref:modules/standard.adoc#http[this section].
Note that the http Jetty module depends on the server Jetty module.
Some parameters that you may want to configure are in fact common HTTP parameters that are applied not only for clear-text HTTP/1.1, but also for secure HTTP/1.1 or for clear-text HTTP/2 or for encrypted HTTP/2, or for HTTP/3, and these configuration parameters may be present in the server module configuration file.
You can force the creation of the server.ini file via:
$ java -jar $JETTY_HOME/start.jar --add-modules=server
Now the $JETTY_BASE directory looks like this:
[source]
JETTY_BASE
├── resources
│ └── jetty-logging.properties
└── start.d
├── http.ini
└── server.ini
Now you can edit the server.ini file -- for more details see xref:modules/standard.adoc#server[this section].
[[https]]
== Secure HTTP/1.1
Secure HTTP/1.1 is enabled with both the ssl and https Jetty modules with the following command (issued from within the $JETTY_BASE directory):
$ java -jar $JETTY_HOME/start.jar --add-modules=ssl,https
[jetty%nowrap]
....
[jetty]
args=--add-modules=ssl,https
....
The command above enables the ssl module, that provides the secure network connector, the KeyStore configuration and TLS configuration -- for more details see <<ssl,this section>>.
Then, the xref:modules/standard.adoc#https[https module] adds HTTP/1.1 as the protocol secured by TLS.
The $JETTY_BASE directory looks like this:
[source]
$JETTY_BASE
├── resources
│ └── jetty-logging.properties
└── start.d
├── https.ini
└── ssl-context.ini
Note that the KeyStore file is missing, because you have to provide one with the cryptographic material you want (read xref:keystore/index.adoc[this section] to create your own KeyStore).
You need to configure these two properties by editing ssl-context.ini:
jetty.sslContext.keyStorePathjetty.sslContext.keyStorePassword
As a quick example, you can enable the xref:modules/standard.adoc#test-keystore[test-keystore module], that creates on-the-fly a KeyStore containing a self-signed certificate:
$ java -jar $JETTY_HOME/start.jar --add-modules=test-keystore
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=ssl,https
args=--add-modules=test-keystore
....
The $JETTY_BASE directory is now:
[source,subs=+quotes]
├── etc
│ └── #test-keystore.p12#
├── resources
│ └── jetty-logging.properties
└── start.d
├── https.ini
├── ssl-context.ini
└── test-keystore.ini
Starting Jetty yields:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=ssl,https,test-keystore
highlight=({.*:8443})
....
Note how Jetty is listening on port 8443 for the secure HTTP/1.1 protocol.
[WARNING]
If you point your browser at +https://localhost:8443/+ you will get a warning from the browser about a "potential security risk ahead", or that "your connection is not private", or similar message depending on the browser.
This is normal because the certificate contained in `test-keystore.p12` is self-signed -- and as such not signed by a recognized certificate authority -- and therefore browsers do not trust it.
[[http2]]
== Configuring HTTP/2
https://tools.ietf.org/html/rfc7540[HTTP/2] is the successor of the HTTP/1.1 protocol, but it is quite different from HTTP/1.1: where HTTP/1.1 is a duplex, text-based protocol, HTTP/2 is a multiplex, binary protocol.
Because of these fundamental differences, a client and a server need to negotiate what version of the HTTP protocol they speak, based on what versions each side supports.
To ensure maximum compatibility, and reduce the possibility that an intermediary that only understands HTTP/1.1 will close the connection when receiving unrecognized HTTP/2 bytes, HTTP/2 is typically deployed over secure connections, using the TLS protocol to wrap HTTP/2.
IMPORTANT: Browsers only support secure HTTP/2.
The protocol negotiation is performed by the https://tools.ietf.org/html/rfc7301[ALPN TLS extension]: the client advertises the list of protocols it can speak, and the server communicates to the client the protocol chosen by the server.
For example, you can have a client that only supports HTTP/1.1 and a server that supports both HTTP/1.1 and HTTP/2:
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
participant "client\nsupports\nhttp/1.1" as client
participant "server\nsupports\nhttp/1.1 & http/2" as server
group TLS handshake client -> server : ClientHello (alpn=[http/1.1]) server -> server : picks http/1.1 server -> client : ServerHello (alpn=http/1.1) ...rest of TLS handshake... end group TLS HTTP/1.1 client -> server : HTTP/1.1 GET server -> client : HTTP/1.1 200 end
Nowadays, it's common that both clients and servers support HTTP/2, so servers prefer HTTP/2 as the protocol to speak:
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
participant "client\nsupports\nhttp/1.1 & http/2" as client
participant "server\nsupports\nhttp/1.1 & http/2" as server
group TLS handshake client -> server : ClientHello (alpn=[http/1.1,h2]) server -> server : picks http/2 server -> client : ServerHello (alpn=h2) ...rest of TLS handshake... end group TLS HTTP/2 client -> server : HTTP/2 GET server -> client : HTTP/2 200 end
When you configure a connector with the HTTP/2 protocol, you typically want to also configure the HTTP/1.1 protocol.
The reason to configure both protocols is that you typically do not control the clients: for example an old browser that does not support HTTP/2, or a monitoring console that performs requests using HTTP/1.1, or a heartbeat service that performs a single HTTP/1.0 request to verify that the server is alive.
== Secure vs Clear-Text HTTP/2
Deciding whether you want to configure Jetty with <<http2s,secure HTTP/2>> or <<http2c,clear-text HTTP/2>> depends on your use case.
You want to configure secure HTTP/2 when Jetty is exposed directly to browsers, because browsers only support secure HTTP/2.
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle browser
cloud internet
rectangle jetty
jetty <--> internet : TLS+HTTP/2 internet <--> browser : TLS+HTTP/2
You may configure clear-text HTTP/2 (mostly for performance reasons) if you offload TLS at a load balancer (for example, https://haproxy.org/[HAProxy]) or at a reverse proxy (for example, https://nginx.org/[nginx]).
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle browser
cloud internet
rectangle haproxy
rectangle jetty
note right of haproxy: TLS offload
jetty <--> haproxy : HTTP/2 (clear-text) haproxy <--> internet : TLS+HTTP/2 internet <--> browser : TLS+HTTP/2
You may configure clear-text HTTP/2 (mostly for performance reasons) to call microservices deployed to different Jetty servers (although you may want to use secure HTTP/2 for confidentiality reasons).
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle browser
cloud internet
rectangle haproxy
rectangle jetty
rectangle microservice1
rectangle microservice2
rectangle microservice3
note right of haproxy: TLS offload
internet <--> browser : TLS+HTTP/2 haproxy <--> internet : TLS+HTTP/2 jetty <--> haproxy : HTTP/2 (clear-text) microservice1 <--> jetty : HTTP/2 microservice2 <--> jetty : HTTP/2 microservice3 <--> jetty : HTTP/2 microservice2 <--> microservice3 : HTTP/2 microservice1 <--> microservice3 : HTTP/2
[[http2s]]
== Secure HTTP/2
When you enable secure HTTP/2 you typically want to enable also secure HTTP/1.1, for backwards compatibility reasons: in this way, old browsers or other clients that do not support HTTP/2 will be able to connect to your server.
You need to enable:
- the
sslJetty module, which provides the secure connector and the KeyStore and TLS configuration - the
http2Jetty module, which adds ALPN handling and adds the HTTP/2 protocol to the secured connector - optionally, the
httpsJetty module, which adds the HTTP/1.1 protocol to the secured connector
Use the following command (issued from within the $JETTY_BASE directory):
$ java -jar $JETTY_HOME/start.jar --add-modules=ssl,http2,https
As when enabling the https Jetty module, you need a valid KeyStore (read xref:keystore/index.adoc[this section] to create your own KeyStore).
As a quick example, you can enable the xref:modules/standard.adoc#test-keystore[test-keystore module], that creates on-the-fly a KeyStore containing a self-signed certificate:
$ java -jar $JETTY_HOME/start.jar --add-modules=test-keystore
Starting Jetty yields:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=ssl,http2,https,test-keystore
highlight=({.*:8443})
....
Note how Jetty is listening on port 8443 and the protocols supported are the sequence (ssl, alpn, h2, http/1.1).
The (ordered) list of protocols after alpn are the application protocols, in the example above (h2, http/1.1).
When a new connection is accepted by the connector, Jetty first interprets the TLS bytes, then it handles the ALPN negotiation knowing that the application protocols are (in order) h2 and then http/1.1.
You can customize the list of application protocols and the default protocol to use in case the ALPN negotiation fails by editing the xref:modules/standard.adoc#alpn[alpn module] properties.
The HTTP/2 protocol parameters can be configured by editing the xref:modules/standard.adoc#http2[http2 module] properties.
[[http2c]]
== Clear-Text HTTP/2
When you enable clear-text HTTP/2 you typically want to enable also clear-text HTTP/1.1, for backwards compatibility reasons and to allow clients to https://tools.ietf.org/html/rfc7540#section-3.2[upgrade] from HTTP/1.1 to HTTP/2.
You need to enable:
- the
httpJetty module, which provides the clear-text connector and adds the HTTP/1.1 protocol to the clear-text connector - the
http2cJetty module, which adds the HTTP/2 protocol to the clear-text connector
$ java -jar $JETTY_HOME/start.jar --add-modules=http,http2c
Starting Jetty yields:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http,http2c
highlight=({.+:8080})
....
Note how Jetty is listening on port 8080 and the protocols supported are HTTP/1.1 and h2c (i.e. clear-text HTTP/2).
With this configuration, browsers and client applications will be able to connect to port 8080 using:
- HTTP/1.1 directly (e.g.
curl --http1.1 ++http://localhost:8080++):
GET / HTTP/1.1 Host: localhost:8080
- HTTP/1.1 with upgrade to HTTP/2 (e.g.
curl --http2 ++http://localhost:8080++):
GET / HTTP/1.1 Host: localhost:8080 Connection: Upgrade, HTTP2-Settings Upgrade: h2c HTTP2-Settings:
- HTTP/2 directly (e.g.
curl --http2-prior-knowledge ++http://localhost:8080++):
50 52 49 20 2a 20 48 54 54 50 2f 32 2e 30 0d 0a 0d 0a 53 4d 0d 0a 0d 0a 00 00 12 04 00 00 00 00 00 00 03 00 00 00 64 00 04 40 00 00 00 00 02 00 00 00 00 00 00 1e 01 05 00 00 00 01 82 84 86 41 8a a0 e4 1d 13 9d 09 b8 f0 1e 07 7a 88 25 b6 50 c3 ab b8 f2 e0 53 03 2a 2f 2a
The HTTP/2 protocol parameters can be configured by editing the xref:modules/standard.adoc#http2c[http2c module] properties.
[[http3]]
== HTTP/3
When you enable support for the HTTP/3 protocol, by default the secure HTTP/2 protocol is also enabled, so that browsers or clients that do not support HTTP/3 will be able to connect to your server.
You need to enable:
- the
sslJetty module, which provides the KeyStore and TLS configuration - the
http3Jetty module, which adds the HTTP/3 protocol on the HTTP/3 connector
Use the following command (issued from within the $JETTY_BASE directory):
$ java -jar $JETTY_HOME/start.jar --add-modules=ssl,http3
Enabling any module Jetty module that supports secure network communication requires a valid KeyStore (read xref:keystore/index.adoc[this section] to create your own KeyStore), that, as a quick example, you can enable with the xref:modules/standard.adoc#test-keystore[test-keystore module], that creates on-the-fly a KeyStore containing a self-signed certificate:
$ java -jar $JETTY_HOME/start.jar --add-modules=test-keystore
Starting Jetty yields:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
setupArgs=--approve-all-licenses --add-modules=ssl,http3,test-keystore
highlight=({.*:8444})
....
Note how Jetty is listening on port 8443 for HTTP/2 and on port 8444 for HTTP/3.
The HTTP/3 protocol parameters can be configured by editing the xref:modules/standard.adoc#http3[http3 module] properties.
[[websocket]]
== WebSocket
WebSocket is a network protocol for bidirectional data communication, initiated via HTTP and then upgraded to WebSocket.
WebSocket provides a simple, low-level, framing protocol layered over the underlying transport protocol, typically TCP.
One or more WebSocket data frames compose a WebSocket message that is either a UTF-8 text message or binary message.
Jetty provides an implementation of the following standards and specifications.
http://tools.ietf.org/html/rfc6455[RFC-6455] - The WebSocket Protocol::
Jetty supports version 13 of the released and final specification.
http://www.jcp.org/en/jsr/detail?id=356[JSR-356] - The Java WebSocket API (javax.websocket)::
This is the official Java API for working with WebSockets.
https://tools.ietf.org/html/rfc7692[RFC-7692] - WebSocket Per-Message Deflate Extension::
This is the replacement for perframe-compression, switching the compression to being based on the entire message, not the individual frames.
https://tools.ietf.org/html/rfc8441[RFC-8441] - Bootstrapping WebSockets with HTTP/2::
Allows a single stream of an HTTP/2 connection to be upgraded to WebSocket.
This allows one TCP connection to be shared by both protocols and extends HTTP/2's more efficient use of the network to WebSockets.
[[websocket-configure]]
=== Configuring WebSocket
Jetty provides two WebSocket implementations: one based on the Jakarta EE WebSocket APIs defined by JSR 356, provided by module {ee-current}-websocket-jakarta (for Java EE 8, the module is called ee8-websocket-javax), and one based on Jetty specific WebSocket APIs, provided by module websocket-jetty.
NOTE: Remember that a WebSocket connection is always initiated from the HTTP protocol (either an HTTP/1.1 upgrade or an HTTP/2 connect), therefore to enable WebSocket you need to enable HTTP.
To enable WebSocket support, you also need to decide what version of the HTTP protocol you want WebSocket to be initiated from, and whether you want secure HTTP.
For example, to enable clear-text WebSocket from HTTP/1.1, using the Jakarta {ee-current-caps} implementation, use the following command (issued from within the $JETTY_BASE directory):
[,shell,subs=+attributes]
$ java -jar $JETTY_HOME/start.jar --add-modules=http,{ee-current}-websocket-jakarta
To enable secure WebSocket from HTTP/2, using the Jetty implementation, use the following command (issued from within the $JETTY_BASE directory):
[,shell]
$ java -jar $JETTY_HOME/start.jar --add-modules=http2,websocket-jetty
When enabling secure protocols you need a valid KeyStore (read xref:keystore/index.adoc[this section] to create your own KeyStore).
As a quick example, you can enable the xref:modules/standard.adoc#test-keystore[test-keystore module], that creates on-the-fly a KeyStore containing a self-signed certificate:
$ java -jar $JETTY_HOME/start.jar --add-modules=test-keystore
To enable WebSocket on both HTTP/1.1 and HTTP/2, both clear-text and secure, using the Jakarta {ee-current-caps} implementation, use the following command (issued from within the $JETTY_BASE directory):
$ java -jar $JETTY_HOME/start.jar --add-modules=http,https,http2c,http2,{ee-current}-websocket-jakarta
[[websocket-disable]]
=== Selectively Disabling WebSocket
Enabling the Jakarta EE WebSocket Jetty modules comes with a startup cost because Jetty must perform two steps:
. Scan Jakarta EE web applications +*.war+ files (and all the jars and classes inside it) looking for WebSocket EndPoint classes (either annotated with the Jakarta EE WebSocket API annotations or extending/implementing Jakarta EE WebSocket API classes/interfaces).
This can be a significant cost if your web application contains a lot of classes and/or jar files.
. Configure and wire WebSocket EndPoints so that WebSocket messages are delivered to the correspondent WebSocket EndPoint.
WebSocket support is by default enabled for all Jakarta EE web applications.
For a specific Jakarta EE web application, you can disable step 2 for Jakarta EE WebSocket support (when the {ee-current}-websocket-jakarta module is enabled) by setting the context attribute org.eclipse.jetty.websocket.jakarta to false:
[,xml]
...
----NOTE: For Java EE 8, the parameter name is org.eclipse.jetty.websocket.javax.
Furthermore, for a specific web application, you can disable step 1 (and therefore also step 2) as described in the xref:annotations/index.adoc[annotations processing section].
[[websocket-webapp-client]]
=== Using WebSocket Client in Web Applications
Web applications may need to use a WebSocket client to communicate with third party WebSocket services.
If the web application uses the Jakarta EE WebSocket APIs, the Jakarta EE WebSocket client APIs are provided by Jetty and are available to the web application as long as the {ee-current}-websocket-jakarta Jetty module is enabled.
However, the Jakarta EE WebSocket Client APIs are quite limited (for example, they do not support secure WebSocket).
For this reason, web applications may want to use the Jetty WebSocket Client APIs.
When using the Jetty WebSocket Client APIs, Jakarta EE web applications should include the required jars and their dependencies in the WEB-INF/lib directory of the +*.war+ file.
Alternatively, when deploying your Jakarta EE web applications in Jetty, you can enable the websocket-jetty-client Jetty module to allow Jakarta EE web applications to use the Jetty WebSocket Client APIs provided by Jetty, without the need to include jars and their dependencies in the +*.war+ file.
[[fcgi]]
== FastCGI
FastCGI is a network protocol primarily used by a web server to communicate to a FastCGI server.
FastCGI servers are typically used to serve web content generated by dynamic web languages, primarily http://www.php.net/[PHP], but also Python, Ruby, Perl and others.
Web servers that supports FastCGI are, among others, http://httpd.apache.org/[Apache], http://nginx.org/[Nginx], and Jetty.
Web servers typically act as reverse proxies, converting HTTP requests that they receive from clients (browsers) to FastCGI requests that are forwarded to the FastCGI server.
The FastCGI server spawns the dynamic web language interpreter, passing it the information contained in the FastCGI request and a dynamic web language script is executed, producing web content, typically HTML.
The web content is then formatted into a FastCGI response that is returned to the web server, which converts it to an HTTP response that is then returned to the client.
The most well known FastCGI server is the http://php-fpm.org/[PHP FastCGI Process Manager], or php-fpm.
In the following we will assume that php-fpm is used as FastCGI server.
This is a diagram of what described above:
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
Browser -> Jetty : GET /path (HTTP)
Jetty -> "php-fpm" : GET /path (FastCGI)
"php-fpm" -> PHP : spawn PHP interpreter
PHP -> "index.php" : execute PHP script
"index.php" -> "php-fpm" : HTML
"php-fpm" -> Jetty : 200 OK + HTML (FastCGI)
Jetty -> Browser : 200 OK + HTML (HTTP)
Jetty can be configured to act as a web server that supports FastCGI, replacing the functionality that is normally provided by Apache or Nginx.
This allows users to leverage Jetty features such as the support for HTTP/1.1, HTTP/2 and HTTP/3, Jetty's scalability, and of course Jetty's native support for Jakarta EE Web Standards such as Servlets, JSPs, etc.
With such configuration, users can not only deploy their Jakarta EE web applications in Jetty, but also serve their http://wordpress.com/[WordPress] site or blog or their https://drupal.org/[Drupal] site without having to install and manage multiple web servers.
[[fcgi-configure]]
=== Configuring WordPress
This section explains how to configure Jetty to serve your https://wordpress.com/[WordPress] site.
The prerequisites are:
- Have
php-fpminstalled on your server host, and configured to listen either on a Unix-Domain socket (such as/run/php/php-fpm.sock), or on a TCP socket (such aslocalhost:9000). - Have WordPress installed on your server host, for example under
/var/www/wordpress.
For more information about how to install WordPress and the necessary PHP modules, please refer to the https://wordpress.org/support/article/how-to-install-wordpress/[WordPress Installation Guide].
Then, the <<https,secure HTTP>> and/or the <<http2,secure HTTP/2>> Jetty modules should be enabled to allow browsers to connect to Jetty.
Lastly, enable the fcgi-proxy module to provide FastCGI support (to convert HTTP requests from browsers to FastCGI for php-fpm and vice versa), and the core-deploy module to deploy your WordPress web application as a xref:deploy/index.adoc#jetty[Jetty context XML file].
For example:
$ java -jar $JETTY_HOME/start.jar --add-modules=ssl,https,fcgi-proxy,core-deploy
TIP: The https Jetty module requires a KeyStore. If you do not already have one configured, you can add the test-keystore Jetty module to the command line above to create a KeyStore on-the-fly.
Now you can deploy a Jetty context XML file that represents your WordPress web application.
Use the following file as example, copy it as $JETTY_BASE/webapps/wordpress.xml and customize it as necessary:
[,xml,options=nowrap]
<Set name="handler">
<New class="org.eclipse.jetty.server.handler.PathMappingsHandler">
<Call name="addMapping">
<Arg>
<New class="org.eclipse.jetty.http.pathmap.ServletPathSpec"><Arg>*.php</Arg></New>
</Arg>
<Arg>
<New class="org.eclipse.jetty.fcgi.proxy.FastCGIProxyHandler">
<Arg>(https?)://([^/]+)(.*)</Arg>
<Arg>http://localhost:9000$3</Arg>
<Arg><Ref refid="root" /></Arg>
<Set name="originalPathAttribute">wordpress.originalPath</Set>
<Set name="originalQueryAttribute">wordpress.originalQuery</Set>
<Set name="scriptPattern"><Call class="java.util.regex.Pattern" name="compile"><Arg>(.+?\\.php)</Arg></Call></Set>
<Set name="fastCGISecure">true</Set>
<Set name="unixDomainPath"><Call class="java.nio.file.Path" name="of"><Arg>/run/php/php-fpm.sock</Arg></Call></Set>
</New>
</Arg>
</Call>
<Call name="addMapping">
<Arg>
<New class="org.eclipse.jetty.http.pathmap.ServletPathSpec"><Arg>/</Arg></New>
</Arg>
<Arg>
<New class="org.eclipse.jetty.server.handler.ResourceHandler">
<Set name="welcomeFiles"><Call class="java.util.List" name="of"><Arg>/index.php</Arg></Call></Set>
<Set name="welcomeMode"><Call class="org.eclipse.jetty.server.ResourceService$WelcomeMode" name="valueOf"><Arg>REHANDLE</Arg></Call></Set>
<Set name="dirAllowed">false</Set>
</New>
</Arg>
</Call>
</New>
</Set>
</New>Now you can start Jetty and navigate to +http://localhost:8080+ with your browser to enjoy WordPress:
$ java -jar $JETTY_HOME/start.jar
[[ssl]]
== Configuring Secure Protocols
Secure protocols are normal protocols such as HTTP/1.1, HTTP/2 or WebSocket that are wrapped by the https://en.wikipedia.org/wiki/Transport_Layer_Security[TLS protocol].
Any network protocol based on TCP can be wrapped with TLS.
QUIC, the protocol based on UDP that transports HTTP/3, uses TLS messages but not the TLS protocol framing.
The https scheme used in URIs really means tls+http/1.1 (or tls+http/2, or quic+http/3) and similarly the wss scheme used in URIs really means tls+websocket, etc.
Senders wrap the underlying protocol bytes (e.g. HTTP bytes or WebSocket bytes) with the TLS protocol, while receivers first interpret the TLS protocol to obtain the underlying protocol bytes, and then interpret the wrapped bytes.
The xref:modules/standard.adoc#ssl[ssl Jetty module] allows you to configure a secure network connector; if other modules require encryption, they declare a dependency on the ssl module.
It is the job of other Jetty modules to configure the wrapped protocol.
For example, it is the <<https,https module>> that configures the wrapped protocol to be HTTP/1.1.
Similarly, it is the <<http2,http2 module>> that configures the wrapped protocol to be HTTP/2.
If you enable both the https and the http2 module, you will have a single secure connector that will be able to interpret both HTTP/1.1 and HTTP/2.
[[ssl-customize]]
=== Customizing KeyStore and SSL/TLS Configuration
Secure protocols have a slightly more complicated configuration since they require to configure a KeyStore.
Refer to the xref:keystore/index.adoc[KeyStore section] for more information about how to create and manage a KeyStore.
For simple cases, you only need to configure the KeyStore path and KeyStore password as explained in xref:modules/standard.adoc#ssl-context[this section].
For more advanced configuration, for example where Jetty module properties are not defined, or the values for those properties need to be fetched from external sources, you can follow the steps below.
First, create a custom xref:xml/index.adoc[Jetty XML file] and reference it in $JETTY_BASE/start.d/ssl-context.ini:
.ssl-context.ini [source,subs="verbatim,quotes"]
--module=ssl-context *etc/tls-config.xml* <1> ...
<1> The path to the custom XML file, relative to $JETTY_BASE.
The ssl-context.ini file above only shows the lines that are not commented out (you can leave the lines that are commented unmodified for future reference).
You want to create the $JETTY_BASE/etc/tls-config.xml with the following template content:
.tls-config.xml [,xml]
The tls-config.xml file references the sslContextFactory component (created by the ssl-context Jetty module) that configures the KeyStore and TLS parameters, so that you can now call its APIs via XML (using the syntax described in xref:xml/index.adoc[this section]), and you will have full flexibility for any advanced configuration you want (see below for few examples).
Refer to the link:{javadoc-url}/org/eclipse/jetty/util/ssl/SslContextFactory.Server.html[SslContextFactory.Server javadocs] for the list of methods that you can call through the Jetty XML file.
CAUTION: Use module properties whenever possible, and only resort to use a Jetty XML file for advanced configuration that you cannot do using module properties.
[[ssl-customize-versions]]
==== Customizing SSL/TLS Protocol Versions
By default, the SSL protocols (SSL, SSLv2, SSLv3, etc.) are already excluded because they are vulnerable.
To explicitly add the exclusion of TLSv1.0 and TLSv1.1 (that are also vulnerable -- which leaves only TLSv1.2 and TLSv1.3 available), you want to use this XML:
.tls-config.xml [,xml]
[[ssl-customize-ciphers]]
==== Customizing SSL/TLS Ciphers
By default, certain cipher suites are already excluded because they are either weak or vulnerable.
To explicitly exclude more cipher suites in addition to those excluded by default, you can use this XML:
.tls-config.xml [,xml]
Note how each array item specifies a regular expression that matches multiple ciphers, or specifies a precise cipher to exclude.
You can choose to create multiple XML files, and reference them all from $JETTY_BASE/start.d/ssl-context.ini, or put all your custom configurations in a single XML file.
[[ssl-renew]]
=== Renewing the Certificates
When you create a certificate, you must specify for how many days it is valid.
The typical validity is 90 days, and while this period may seem short, it has two advantages:
- Reduces the risk in case of compromised/stolen keys.
- Encourages automation, i.e. certificate renewal performed by automated tools (rather than manually) at scheduled times.
To renew a certificate, you must go through the xref:keystore/index.adoc#create[same steps] you followed to create the certificate the first time, and then you can <<ssl-reload,reload the KeyStore>> without the need to stop Jetty.
[[ssl-reload]]
=== Watching and Reloading the KeyStore
Jetty can be configured to monitor the directory of the KeyStore file, and reload the SslContextFactory component if the KeyStore file changed.
This feature can be enabled by activating the ssl-reload Jetty module:
$ java -jar $JETTY_HOME/start.jar --add-modules=ssl-reload
For more information about the configuration of the ssl-reload Jetty module, see xref:modules/standard.adoc#ssl-reload[this section].
[[ssl-conscrypt]]
=== Using Conscrypt as SSL/TLS Provider
If not explicitly configured, the TLS implementation is provided by the JDK you are using at runtime.
OpenJDK's vendors may replace the default TLS provider with their own, but you can also explicitly configure an alternative TLS provider.
The standard TLS provider from OpenJDK is implemented in Java (no native code), and its performance is not optimal, both in CPU usage and memory usage.
A faster alternative, implemented natively, is Google's https://github.com/google/conscrypt/[Conscrypt], which is built on https://boringssl.googlesource.com/boringssl/[BoringSSL], which is Google's fork of https://www.openssl.org/[OpenSSL].
CAUTION: As Conscrypt eventually binds to a native library, there is a higher risk that a bug in Conscrypt or in the native library causes a JVM crash, while the Java implementation will not cause a JVM crash.
To use Conscrypt as the TLS provider just enable the conscrypt Jetty module:
$ java -jar $JETTY_HOME/start.jar --add-modules=conscrypt
[[ssl-bouncycastle]]
=== Using Bouncy Castle as SSL/TLS Provider
If not explicitly configured, the TLS implementation is provided by the JDK you are using at runtime.
OpenJDK's vendors may replace the default TLS provider with their own, but you can also explicitly configure an alternative TLS provider.
link:https://www.bouncycastle.org/[Bouncy Castle] is a pure Java alternative provider for the Java security APIs, and includes a TLS provider.
To use Bouncy Castle as the TLS provider just enable the bouncycastle Jetty module:
$ java -jar $JETTY_HOME/start.jar --add-modules=bouncycastle
[[ssl-sni]]
=== Configuring SNI
Server Name Indication (SNI) is a TLS extension that clients send to indicate what domain they want to connect to during the initial TLS handshake.
Modern TLS clients (e.g. browsers) always send the SNI extension; however, older TLS clients may not send the SNI extension.
Being able to handle the SNI is important when you have xref:deploy/index.adoc#virtual-hosts[virtual hosts] and a KeyStore with multiple certificates, one for each domain.
For example, you may have deployed over a secure connector two web applications, both at context path /, one at virtual host one.com and one at virtual host two.net.
The KeyStore contains two certificates, one for one.com and one for two.net.
There are three ssl module properties that control the SNI behavior on the server: one that works at the TLS level, and two that works at the HTTP level.
The property that works at the TLS level is:
jetty.sslContext.sniRequired::
Whether SNI is required at the TLS level, defaults to false.
Its behavior is explained by the following table:
+
.Behavior of the jetty.sslContext.sniRequired property
[cols="3*a"]
|===
|
| sniRequired=false
| sniRequired=true
| SNI = null
| client receives default certificate
| client receives TLS failure
| SNI = wrong.org
| client receives default certificate
| client receives TLS failure
| SNI = `one.com` | client receives `one.com` certificate | client receives `one.com` certificate |=== + [WARNING]
The default certificate is the certificate returned by the TLS implementation in case there is no SNI match, and you should not rely on this certificate to be the same across Java vendors and versions, or Jetty versions, or TLS provider vendors and versions.
In the example above it could be either the `one.com` certificate or the `two.net` certificate.
When jetty.sslContext.sniRequired=true, clients that don't send a valid SNI receive a TLS failure, and their attempt to connect to the server fails.
The details of this failure may not be reported and could be difficult to figure out that the failure is related to an invalid SNI.
For this reason, other two properties are defined at the HTTP level, so that clients can received an HTTP 400 response with more details about what went wrong while trying to connect to the server:
jetty.ssl.sniRequired::
Whether SNI is required at the HTTP level, defaults to false.
Its behavior is similar to the jetty.sslContext.sniRequired property above, and is explained by the following table:
+
.Behavior of the jetty.ssl.sniRequired property
[cols=3*a]
|===
|
| sniRequired=false
| sniRequired=true
| SNI = null
| Accept
| Reject: 400 Bad Request
| SNI = wrong.org
| Accept
| Reject: 400 Bad Request
| SNI = one.com
| Accept
| Accept
|===
When jetty.ssl.sniRequired=true, the SNI is matched against the certificate sent to the client, and only if there is a match the request is accepted.
When the request is accepted, there could be an additional check controlled by the following property:
jetty.ssl.sniHostCheck::
Whether the certificate sent to the client matches the Host header, defaults to true.
Its behavior is explained by the following table:
+
.Behavior of the jetty.ssl.sniHostCheck property
[cols="3*a"]
|===
|
| sniHostCheck=false
| sniHostCheck=true
| certificate = one.com +Host: wrong.org
| Accept
| Reject: 400 Bad Request
| certificate = one.com +Host: one.com
| Accept
| Accept
|===
In the normal case with the default server configuration, for a TLS clients that sends SNI, and then sends an HTTP request with the correct Host header, Jetty will pick the correct certificate from the KeyStore based on the SNI received from the client, and accept the request.
Accepting the request does not mean that the request is responded with an HTTP 200 OK, but just that the request passed successfully the SNI checks and will be processed by the server.
If the request URI is for a resource that does not exist, the response will likely be a 404 Not Found.
You may modify the default values of the SNI properties if you want stricter control over old/broken TLS clients or bad HTTP requests.
[[proxy]]
== Jetty Behind a Load Balancer or Reverse Proxy
You may need to configure one or more Jetty instances behind an intermediary, typically a load balancer such as https://haproxy.org[HAProxy], or a reverse proxy such as https://httpd.apache.org[Apache HTTP Server] or https://nginx.org[Nginx].
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam padding 5
scale 1.5
rectangle client
rectangle proxy
rectangle "Jetty" as jetty1
rectangle "Jetty" as jetty2
client -- proxy proxy -- jetty1 proxy -- jetty2
[WARNING]
HAProxy can communicate either HTTP/1.1 or HTTP/2 to backend servers such as Jetty.
Apache HTTP Server and Nginx can only speak HTTP/1.1 to backend servers such as Jetty, and have no plans to support HTTP/2 towards backend servers.
In these setups, typically the proxy performs TLS offloading, and the communication with backend servers happens in clear-text.
It is possible, however, to configure the proxy so that all the bytes arriving from the client are tunnelled opaquely to the backend Jetty server (that therefore needs to perform the TLS offloading) and vice versa the bytes arriving from the Jetty server are tunnelled opaquely to the client.
Also in these setups, the TCP/IP connection terminating on the Jetty servers does not originate from the client, but from the proxy, so that the remote IP address and port number may be reported incorrectly in backend server logs, or worse applications may not work because they need to be able to differentiate different clients based on the client IP address.
For this reason, intermediaries typically implement at least one of several de facto standards to communicate information about the original client connection to the backend Jetty server.
Jetty supports two methods to process client information sent by intermediaries:
- The
ForwardedHTTP header, defined in https://tools.ietf.org/html/rfc7239[RFC 7239] and replacing the oldX-Forwarded-*headers, defined in <>. - The https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt[Proxy Protocol], defined in <>.
In both methods, web applications asking for the remote client IP address will receive the remote client IP address as specified by the client information sent by the intermediary, not the physical IP address of TCP connection with the intermediary.
Likewise, web applications asking for the remote client IP port will receive the remote client IP port as specified by the client information sent by the intermediary.
Finally, web applications asking whether the remote request was secure will receive whether the remote client made a secure request using the https scheme as specified by the client information sent by the intermediary.
[[proxy-forwarded]]
=== Configuring the Forwarded Header
The Forwarded HTTP header is added by the intermediary with information about the client and the client request, for example:
GET / HTTP/1.1 Host: domain.com Forwarded: for=2.36.72.144:21216;proto=https
In the example above, the intermediary added the Forwarded header specifying that the client remote address is 2.36.72.144:21216 and that the request was made with the https scheme.
Let's assume you have already configured Jetty with the HTTP/1.1 protocol with the following command (issued from within the $JETTY_BASE directory):
$ java -jar $JETTY_HOME/start.jar --add-modules=http
Support for the Forwarded HTTP header (and its predecessor X-Forwarded-* headers) is enabled with the forwarded Jetty module:
$ java -jar $JETTY_HOME/start.jar --add-modules=forwarded
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http
args=--add-modules=forwarded
....
With the forwarded Jetty module enabled, Jetty interprets the Forwarded header and makes its information available to web applications.
For further information about configuring the forwarded Jetty module, see xref:modules/standard.adoc#forwarded[this section].
[[proxy-protocol]]
=== Configuring the Proxy Protocol
The https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt[Proxy Protocol] is the de facto standard, introduced by https://haproxy.org[HAProxy], to communicate client information to backend servers via the TCP connection, rather than via HTTP headers.
The information about the client connection is sent as a small data frame on each newly established connection.
This mechanism is therefore independent of any protocol, so it can be used for TLS, HTTP/1.1, HTTP/2, etc.
[NOTE]
There are 2 versions of the proxy protocol: v1 and v2, both supported by Jetty.
Proxy protocol v1 is human readable, but it only carries information about the client TCP connection (IP address and IP port).
Proxy protocol v2 has a binary format, carries the information about the client TCP connection, and can carry additional arbitrary information encoded in pairs `(type, value)` where `type` is a single byte that indicates the value's meaning, and `value` is a variable length byte array that can encode user-defined data.
Support for the proxy protocol can be enabled for the clear-text connector or for the secure connector (or both).
Let's assume you have already configured Jetty with the HTTP/1.1 clear-text protocol with the following command (issued from within the $JETTY_BASE directory):
$ java -jar $JETTY_HOME/start.jar --add-modules=http
To enable proxy protocol support for the clear-text connector, enable the proxy-protocol Jetty module:
$ java -jar $JETTY_HOME/start.jar --add-modules=proxy-protocol
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http
args=--add-modules=proxy-protocol
....
Starting Jetty yields:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
args=--module=proxy-protocol
highlight=({.*:8080})
....
Note how in the example above the list of protocols for the clear-text connector is first proxy and then http/1.1.
For every new TCP connection, Jetty first interprets the proxy protocol bytes with the client information; after this initial proxy protocol processing, Jetty interprets the incoming bytes as HTTP/1.1 bytes.
Enabling proxy protocol support for the secure connector is similar.
Let's assume you have already configured Jetty with the HTTP/1.1 secure protocol and the test KeyStore with the following command (issued from within the $JETTY_BASE directory):
$ java -jar $JETTY_HOME/start.jar --add-modules=https,test-keystore
Enable the proxy-protocol-ssl Jetty module with the following command (issued from within the $JETTY_BASE directory):
$ java -jar $JETTY_HOME/start.jar --add-modules=proxy-protocol-ssl
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=https
args=--add-modules=proxy-protocol-ssl
....
Starting Jetty yields:
$ java -jar $JETTY_HOME/start.jar
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=https,test-keystore,proxy-protocol-ssl
highlight=({.*:8443})
....
Note how in the example above the list of protocols for the secure connector is first proxy, then ssl and then http/1.1.
[[proxy-haproxy]]
=== HAProxy and Jetty with HTTP/1.1 and HTTP/2
https://haproxy.org[HAProxy] is an open source solution that offers load balancing and proxying for TCP and HTTP based application, and can be used as a replacement for Apache or Nginx when these are used as reverse proxies.
The deployment proposed here has HAProxy playing the role that Apache and Nginx usually do: to perform the TLS offloading (that is, decrypt incoming bytes and encrypt outgoing bytes) and then forwarding the now clear-text traffic to a backend Jetty server, speaking either HTTP/1.1 or HTTP/2.
Since HAProxy's TLS offloading is based on OpenSSL, it is much more efficient than the Java implementation shipped with OpenJDK.
After you have installed HAProxy on your system, you want to configure it so that it can perform TLS offloading.
HAProxy will need a single file containing the X509 certificates and the private key, all in https://en.wikipedia.org/wiki/X.509[PEM format], with the following order:
- The site certificate; this certificate's Common Name refers to the site domain (for example: CN=*.webtide.com) and is signed by Certificate Authority #1.
- The Certificate Authority #1 certificate; this certificate may be signed by Certificate Authority #2.
- The Certificate Authority #2 certificate; this certificate may be signed by Certificate Authority #3; and so on until the Root Certificate Authority.
- The Root Certificate Authority certificate.
- The private key corresponding to the site certificate.
Refer to the xref:keystore/index.adoc[section about KeyStores] for more information about generating the required certificates and private key.
Now you can create the HAProxy configuration file (in Linux it's typically /etc/haproxy/haproxy.cfg).
This is a minimal configuration:
.haproxy.cfg [source]
global
tune.ssl.default-dh-param 1024
defaults
timeout connect 10000ms
timeout client 60000ms
timeout server 60000ms
frontend fe_http <1>
mode http
bind *:80
Redirect to https
redirect scheme https code 301
frontend fe_https <2>
mode tcp
bind *:443 ssl no-sslv3 crt /path/to/domain.pem ciphers TLSv1.2 alpn h2,http/1.1
default_backend be_http
backend be_http <3> mode tcp server domain 127.0.0.1:8282 send-proxy-v2
<1> The fe_http front-end accepts connections on port 80 and redirects them to use the https scheme.
<2> The fe_https front-end accepts connections on port 443, and it is where the TLS decryption/encryption happens.
You must specify the path to the PEM file containing the TLS key material (the crt /path/to/domain.pem part), the ciphers that are suitable for HTTP/2 (ciphers TLSv1.2), and the ALPN protocols supported (alpn h2,http/1.1).
This front-end then forwards the now decrypted bytes to the backend in mode tcp.
The mode tcp says that HAProxy will not try to interpret the bytes but instead opaquely forwards them to the backend.
<3> The be_http backend will forward (again in mode tcp) the clear-text bytes to a Jetty connector that talks clear-text HTTP/2 and HTTP/1.1 on port 8282.
The send-proxy-v2 directive sends the proxy protocol v2 bytes to the backend server.
On the Jetty side, you need to enable the following modules:
$ java -jar $JETTY_HOME/start.jar --add-modules=proxy-protocol,http2c,http,deploy
You need to specify the host (127.0.0.1) and port (8282) you have configured in HAProxy when you start Jetty:
$ java -jar $JETTY_HOME/start.jar jetty.http.host=127.0.0.1 jetty.http.port=8282
[NOTE]
You want the Jetty connector that listens on port 8282 to be available only to HAProxy, and not to remote clients.
For this reason, you want to specify the jetty.http.host property on the command line (or in $JETTY_BASE/start.d/http.ini to make this setting persistent) to bind the Jetty connector only on the loopback interface (127.0.0.1), making it available to HAProxy but not to remote clients.
If your Jetty instance runs on a different machine and/or on a different (sub)network, you may want to adjust both the back-end section of the HAProxy configuration file and the `jetty.http.host` property to match accordingly.
With this configuration for HAProxy and Jetty, browsers supporting HTTP/2 will connect to HAProxy, which will decrypt the traffic and send it to Jetty.
Likewise, HTTP/1.1 clients will connect to HAProxy, which will decrypt the traffic and send it to Jetty.
The Jetty connector, configured with the http2c and the http modules is able to distinguish whether the incoming bytes are HTTP/2 or HTTP/1.1 and will handle the request accordingly.
The response is relayed back to HAProxy, which will encrypt it and send it back to the remote client.
This configuration offers you efficient TLS offloading, HTTP/2 support and transparent fallback to HTTP/1.1 for clients that don't support HTTP/1.1.
Documentation Jetty Modules Operations Guide Pages Quickstart Index (`documentation/jetty/modules/operations-guide/pages/quickstart/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Faster Jakarta EE Web Application Deployment
The auto discovery features of the Servlet specification can make deployments slow and uncertain.
Auto discovery of Jakarta EE web application configuration can be useful during the development as it allows new features and frameworks to be enabled simply by dropping in a jar file.
However, for production deployment, the need to scan the contents of many jars can have a significant impact at startup time.
The {ee-all}-quickstart modules allows a Jakarta EE web application to be pre-scanned, making startup predictable and faster.
During the pre-scanning all declarative configuration (from web.xml, web-fragment.xml and annotations) are encoded into an effective web.xml, called WEB-INF/quickstart-web.xml, which can be inspected to understand what will be deployed.
[NOTE]
Programmatic configuration is _not_ encoded into the generated `quickstart-web.xml` file.
With the {ee-all}-quickstart modules, web applications that took many seconds to scan and deploy can now be deployed in a few hundred milliseconds.
== Enabling
You can enable the {ee-current}-quickstart module in this way:
[,shell,subs=+attributes]
$ cd $JETTY_BASE $ java -jar $JETTY_HOME/start.jar --add-modules={ee-current}-quickstart
The $JETTY-BASE/start.d/quickstart.ini file contains these configurable parameters:
jetty.quickstart.mode::
The values are:
GENERATE:::
In this mode, the quickstart-web.xml file are generated and then the Jetty Server is stopped.
Use this mode first before changing to either AUTO or QUICKSTART.
AUTO:::
Allows to deploy the Jakarta EE web application either with or without a quickstart-web.xml file.
If the quickstart-web.xml file is present, then it will be used, otherwise the web application is deployed normally.
QUICKSTART:::
In this mode, if the quickstart-web.xml file is not present, then the web application deployment will fail.
jetty.quickstart.origin::
Use this parameter to set the name of the attribute in the quickstart-web.xml file that contains the origin of each element.
Knowing the descriptor or annotation from which each element derives can be useful for debugging.
Note that the origin attribute does not conform to the web xml schema, so if you deploy with xml validation, you'll see errors.
It is probably best to do a few trial runs with the attribute set, then turn it off for final generation.
jetty.quickstart.xml::
Use this parameter to change the name of the generated file.
By default this is quickstart-web.xml in the Jakarta EE web application's WEB-INF directory.
The file named by this parameter will always be interpreted relative to the WEB-INF directory.
If your Jakarta EE web application is a +*.war+ file, you will need to either first unpack it yourself, or use a Jetty context XML file (or code equivalent) that calls WebAppContext.setExtractWAR(true).
If you allow Jetty to do the unpacking, it will use the usual mechanisms to find the location where to unpack.
Note that by default Jetty unpacks to a temporary location which is not reused between executions.
You must either specify the directory where to unpack, or make a work directory in your $JETTY_BASE to ensure the unpacked war is preserved and reused across restarts.
Documentation Jetty Modules Operations Guide Pages Security Configuring Form Size (`documentation/jetty/modules/operations-guide/pages/security/configuring-form-size.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[[limit-form-content]]
= Limiting Form Content
Forms can be a vector for denial-of-service attacks, like explained in xref:programming-guide:security/configuring-form-size.adoc[this section] of the Programming Guide.
== Configuring Form Limits for a Web Application
To configure the form limits for a Jakarta EE web application, the WebAppContext instance can be configured from a Jetty context XML file or from a WEB-INF/jetty-{ee-all}-web.xml file:
[,xml,subs=attributes+]
Setting the form limits can also be done, for both Jakarta EE web applications and Jetty Core web applications, by setting the following Context attributes.
org.eclipse.jetty.server.Request.maxFormKeysorg.eclipse.jetty.server.Request.maxFormContentSize
For Jakarta EE web applications, these attributes can be set in web.xml via the <context-param> element.
For Jakarta EE and Jetty web applications, these attributes can be set in the Jetty context XML file.
For Jakarta EE web applications:
[,xml,subs=attributes+]
For Jetty Core web applications:
[,xml]
Documentation Jetty Modules Operations Guide Pages Security Jaas Support (`documentation/jetty/modules/operations-guide/pages/security/jaas-support.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= JAAS
JAAS implements a Java version of the standard Pluggable Authentication Module (PAM) framework.
JAAS can be used for two purposes:
- for authentication of users, to reliably and securely determine who is currently executing Java code, regardless of whether the code is running as an application, an applet, a bean, or a servlet
- for authorization of users to ensure they have the access control rights (permissions) required to do the actions performed
JAAS authentication is performed in a pluggable fashion.
This permits applications to remain independent from underlying authentication technologies.
New or updated authentication technologies can be plugged under an application without requiring modifications to the application itself.
See Java Authentication and Authorization Service (JAAS) http://java.sun.com/javase/7/docs/technotes/guides/security/jaas/JAASRefGuide.html[Reference Guide] for more information about JAAS.
The Jetty JAAS support aims to dictate as little as possible whilst providing a sufficiently flexible infrastructure to allow users to drop either one of the <<loginmodules,JAAS Login Modules that ships with Jetty>>, or their
own custom https://docs.oracle.com/javase/7/docs/api/javax/security/auth/spi/LoginModule.html[LoginModule]s.
[[configuration]]
== Configuration
[[module]]
=== The jaas module
Enable the jaas module.
[source]
include::{jetty-home}/modules/jaas.mod[]
The configurable items in the resulting $JETTY_BASE/start.d/jaas.ini file are:
jetty.jaas.login.conf::
This is the location of the file that will be referenced by the system property java.security.auth.login.config: Jetty sets this system property for you based on the value of this property.
The value of this property is assumed to be relative to $JETTY_BASE.
The default value is etc/login.conf, which resolves to $JETTY_BASE/etc/login.conf.
If you don't want to put your login module configuration file here, you can change this property to point to where it is.
See more about the contents of this file in the <<loginconf,Configuring JAAS>> section.
[[webapp]]
=== Configure the Jakarta EE web application for JAAS
The <realm-name> in web.xml will be used to identify the org.eclipse.jetty.security.jaas.JAASLoginService declaration that integrates JAAS with Jetty.
For example, this web.xml contains a realm called Test JAAS Realm:
[,xml]
We now need to declare an org.eclipse.jetty.security.jaas.JAASLoginService that references the realm name of Test JAAS Realm.
Here's an example of a suitable XML snippet:
[,xml]
The org.eclipse.jetty.security.jaas.JAASLoginService can be declared in a couple of different places, pick whichever suits your purposes best:
- If you have more than one web application that you would like to use the same security infrastructure, then you can declare your
org.eclipse.jetty.security.jaas.JAASLoginServiceas a bean that is added to theorg.eclipse.jetty.server.Server.
The file in which you declare this needs to be on Jetty's execution path.
The recommended procedure is to create a file in your$JETTY_BASE/etcdirectory and then ensure it is on the classpath either by adding it to the Jetty xref:start/index.adoc[start command line], or more conveniently to a xref:modules/custom.adoc[custom module].
Here's an example of this type of XML file: + [,xml]
- Alternatively, if you want to use JAAS with a specific web application only, you declare your
org.eclipse.jetty.security.jaas.JAASLoginServicein a Jetty context XML file specific to that web application:
[,xml,subs=+attributes]
[[loginconf]]
=== Configure JAAS
We now need to set up the contents of the file we specified as the jetty.jaas.login.conf property when we <<module,configured the jaas module>>.
Refer to the https://docs.oracle.com/javase/7/docs/api/javax/security/auth/login/Configuration.html[syntax rules] of this file for a full description.
Remembering the example we set up <<webapp,previously>>, the contents of the $JETTY_BASE/etc/login.conf file could look as follows:
[source]
xyz { <1> com.acme.SomeLoginModule required debug=true; <2> com.other.OtherLoginModule optional; <3> };
<1> The name of the configuration exactly as specified in your org.eclipse.jetty.security.jaas.JAASLoginService declaration.
<2> The first LoginModule declaration, containing the classname of the LoginModule and its configuration properties.
<3> A second LoginModule declaration.
You can provide as many LoginModule alternatives as you like, with a minimum of one.
Refer to the https://docs.oracle.com/javase/7/docs/api/javax/security/auth/login/Configuration.html[JAAS documentation] for more information on the standard configuration properties, and how JAAS interprets this file.
[[loginmodules]]
== Provided LoginModules
- link:{javadoc-url}/org/eclipse/jetty/security/jaas/spi/JDBCLoginModule.html[
org.eclipse.jetty.security.jaas.spi.JDBCLoginModule] - link:{javadoc-url}/org/eclipse/jetty/security/jaas/spi/PropertyFileLoginModule.html[
org.eclipse.jetty.security.jaas.spi.PropertyFileLoginModule] - link:{javadoc-url}/org/eclipse/jetty/security/jaas/spi/DataSourceLoginModule.html[
org.eclipse.jetty.security.jaas.spi.DataSourceLoginModule] - link:{javadoc-url}/org/eclipse/jetty/security/jaas/spi/LdapLoginModule.html[
org.eclipse.jetty.security.jaas.ldap.LdapLoginModule]
[[og-password]] [NOTE]
Passwords can be obfuscated using the xref:tools/index.adoc#password[Jetty Password tool].
=== JDBCLoginModule
The org.eclipse.jetty.security.jaas.spi.JDBCLoginModule stores user passwords and roles in a database accessed via JDBC calls.
You can configure the JDBC connection information, as well as the names of the table and columns storing the username and credential, and the names of the table and columns storing the roles.
Here is an example <<loginconf,login module configuration file>> entry for it using an HSQLDB driver:
[source]
jdbc { <1> org.eclipse.jetty.security.jaas.spi.JDBCLoginModule required <2><3> dbUrl="jdbc:hsqldb:." <4> dbUserName="sa" <5> dbDriver="org.hsqldb.jdbcDriver" <6> userTable="myusers" <7> userField="myuser" <8> credentialField="mypassword" <9> userRoleTable="myuserroles" <10> userRoleUserField="myuser" <11> userRoleRoleField="myrole"; <12> };
<1> The name of the configuration.
<2> The name of the LoginModule class.
<3> A standard JAAS flag making successful authentication via this LoginModule mandatory.
<4> The JDBC url used to connect to the database.
<5> The name of the JDBC user to use for the connection.
<6> The name of the JDBC Driver class.
<7> The name of the table holding the user authenication information.
<8> The name of the column holding the user name.
<9> The name of the column holding the user credential.
<10> The name of the table holding the user authorization information.
<11> The name of the column holding the user name.
<12> The name of the column holding the user role.
The properties 7-12 are used to format the following queries:
[,sql]
select from where =?
select from where =?
Credential and role information is lazily read from the database when a previously unauthenticated user requests authentication.
Note that this information is only cached for the length of the authenticated session.
When the user logs out or the session expires, the information is flushed from memory.
Note that passwords can be stored in the database in plain text or encoded formats -- see the note on "Passwords/Credentials" above.
=== DataSourceLoginModule
Similar to the org.eclipse.jetty.security.jaas.spi.JDBCLoginModule, but using a javax.sql.DataSource to connect to the database instead of a JDBC driver.
The javax.sql.DataSource is obtained at runtime by performing a JNDI lookup on java:comp/env/$\{dnJNDIName}.
A sample login module configuration for this LoginModule:
[source]
ds { <1> org.eclipse.jetty.security.jaas.spi.DataSourceLoginModule required <2><3> dbJNDIName="ds" <4> userTable="myusers" <5> userField="myuser" <6> credentialField="mypassword" <7> userRoleTable="myuserroles" <8> userRoleUserField="myuser" <9> userRoleRoleField="myrole"; <10> };
<1> The name of the configuration.
<2> The name of the LoginModule class.
<3> A standard JAAS flag making successful authentication via this LoginModule mandatory.
<4> The JNDI name, relative to java:comp/env/ to lookup to obtain the javax.sql.DataSource.
<5> The name of the table holding the user authenication information.
<6> The name of the column holding the user name.
<7> The name of the column holding the user credential.
<8> The name of the table holding the user authorization information.
<9> The name of the column holding the user name.
<10> The name of the column holding the user role.
=== PropertyFileLoginModule
With this login module implementation, the authentication and role information is read from a property file.
[source]
props { <1> org.eclipse.jetty.security.jaas.spi.PropertyFileLoginModule required <2><3> file="/somewhere/somefile.props"; <4> };
<1> The name of the configuration.
<2> The name of the LoginModule class.
<3> A standard JAAS flag making successful authentication via this LoginModule mandatory.
<4> The location of a properties file containing the authentication and authorization information.
The property file must be of the format:
[source]
: [, ...]
Here's an example:
fred: OBF:1xmk1w261u9r1w1c1xmq,user,admin harry: changeme,user,developer tom: MD5:164c88b302622e17050af52c89945d44,user dick: CRYPT:adpexzg3FUZAk,admin
The contents of the file are fully read in and cached in memory the first time a user requests authentication.
=== LdapLoginModule
The org.eclipse.jetty.security.jaas.spi.LdapLoginModule uses LDAP to access authentication and authorization information stored in a directory.
The LDAP connection information and structure of the authentication/authorization data can be configured.
Here's an example:
[source]
example { <1> org.eclipse.jetty.security.jaas.spi.LdapLoginModule required <2><3> contextFactory="com.sun.jndi.ldap.LdapCtxFactory" <4> hostname="ldap.example.com" <5> port="389" <6> bindDn="cn=Directory Manager" <7> bindPassword="directory" <8> authenticationMethod="simple" <9> useLdaps="true" <10> userBaseDn="ou=people,dc=alcatel" <11> userRdnAttribute="uid" <12> userIdAttribute="cn" <13> userPasswordAttribute="userPassword" <14> userObjectClass="inetOrgPerson" <15> roleBaseDn="ou=groups,dc=example,dc=com" <16> roleNameAttribute="cn" <17> roleMemberAttribute="uniqueMember" <18> roleObjectClass="groupOfUniqueNames"; <19> forceBindingLogin="false" <20> debug="false" <21> };
<1> The name of the configuration.
<2> The name of the LoginModule class.
<3> A standard JAAS flag making successful authentication via this LoginModule mandatory.
<4> The name of the context factory to use for the LDAP connection.
<5> The hostname for the LDAP connection. Optional.
<6> The port for the LDAP connection. Optional.
<7> The caller security Principal. Optional.
<8> The caller security credential. Optional.
<9> The security level for the LDAP connection environment. Optional.
<10> If true, use ldaps instead of ldap for the connection url.
<11> The distinguished name of the directory to search for user information.
<12> The name of the attribute for the user roles.
<13> The name of the attribute for the user id.
<14> The name of the attribute for the user password.
<15> The ObjectClass for users.
<16> The distinguished name of the directory to search for role information.
<17> The name of the attribute for roles.
<18> The name of the attribute storing the user for the roles ObjectClass.
<19> The name of the ObjectClass for roles.
<20> If true, the authentication proceeds on the basis of a successful LDAP binding using the username and credential provided by the user.
If false, then authentication proceeds based on username and password information retrieved from LDAP.
<21> If true, failed login attempts are logged on the server.
Documentation Jetty Modules Operations Guide Pages Security Jaspi Support (`documentation/jetty/modules/operations-guide/pages/security/jaspi-support.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= JASPI
Enabling this module allows Jetty to utilize authentication modules that implement the Jakarta Authentication (JASPI) specification. JASPI provides an SPI (Service Provider Interface) for pluggable, portable, and standardized authentication modules. Compatible modules are portable between servers that support the JASPI specification. This module provides a bridge from Jakarta Authentication to the Jetty Security framework.
Only modules conforming to the "Servlet Container Profile" with the ServerAuthModule interface within the https://jakarta.ee/specifications/authentication/2.0/jakarta-authentication-spec-2.0.pdf[JakartaAuthentication] are supported. These modules must be configured before start-up. Operations for runtime registering or de-registering authentication modules are not supported.
[[configuration]]
== Configuration
[[module]]
=== The jaspi module
Enable the jaspi module:
include::{jetty-home}/modules/ee11-jaspi.mod[]
[[xml]]
=== Configure JASPI
Activate either the ee9-jaspi or {ee-current}-jaspi module, whichever matches your EE platform version.
[source,subs=attributes+]
$ java -jar $JETTY_HOME/start.jar --add-modules={ee-current}-jaspi
You can then register a AuthConfigProvider onto the static AuthConfigFactory obtained with AuthConfigFactory.getFactory(). This registration can be done in the XML configuration file which will be copied to $JETTY_BASE/etc/jaspi/jaspi-authmoduleconfig.xml when the module is enabled.
==== JASPI Demo
The ee9-jaspi-demo and {ee-current}-jaspi-demo modules illustrate setting up HTTP Basic Authentication using the EE9 and {ee-current-caps} Jakarta Authentication modules that come packaged with Jetty.
The following example uses Jetty's {ee-current-caps} implementation of AuthConfigProvider to register a ServerAuthModule directly.
[,xml]
include::{jetty-home}/etc/jaspi/jetty-ee11-jaspi-demo.xml[]
Other custom or 3rd party modules that are compatible with the ServerAuthModule interface in JASPI can be registered in the same way.
=== Integration with Jetty Authentication Mechanisms
To integrate with Jetty authentication mechanisms you must add a LoginService to your context. The LoginService provides a way for you to obtain a UserIdentity from a username and credentials. JASPI can interact with this Jetty LoginService by using the PasswordValidationCallback.
The CallerPrincipalCallback and GroupPrincipalCallback do not require use of a Jetty LoginService. The principal from the CallerPrincipalCallback will be used directly with the IdentityService to produce a UserIdentity.
=== Replacing the Jetty DefaultAuthConfigFactory
Jetty provides an implementation of the AuthConfigFactory interface which is used to register AuthConfigProviders. This can be replaced by a custom implementation by adding a custom module which provides auth-config-factory.
This custom module must reference an XML file which sets a new instance of the AuthConfigFactory with the static method AuthConfigFactory.setFactory().
For an example of this see the {ee-current}-jaspi-default-auth-config-factory module, which provides the default implementation used by Jetty.
include::{jetty-home}/modules/ee11-jaspi-default-auth-config-factory.mod[]
Documentation Jetty Modules Operations Guide Pages Security Openid Support (`documentation/jetty/modules/operations-guide/pages/security/openid-support.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[[openid-support]]
= OpenID Support
A more general discussion about OpenID and its support in Jetty is available in the xref:programming-guide:security/openid-support.adoc[programming guide section].
== OpenID Provider Configuration
To enable OpenID support, you need to enable the xref:operations-guide:modules/standard.adoc#openid[openid module]:
$ java -jar $JETTY_HOME/start.jar --add-modules=openid
To configure OpenID Authentication with Jetty you will need to specify the OpenID Provider's issuer identifier (a case-sensitive URL) and the OAuth 2.0 Client ID and Client Secret.
If the OpenID Provider does not allow metadata discovery you will also need to specify the token endpoint and authorization endpoint of the OpenID Provider.
These values can be set as properties in $JETTY_BASE/start.d/openid.ini file.
Refer to the xref:modules/standard.adoc#openid[openid] Jetty module for the list of configurable properties.
This is an example of an openid.ini file which uses discovery of the OpenID endpoints:
The OpenID Identity Provider's issuer ID (the entire URL *before* ".well-known/openid-configuration")
jetty.openid.provider=https://id.example.com/
The Client Identifier
jetty.openid.clientId=test1234
The Client Secret
jetty.openid.clientSecret=XT_Mafv_aUCGheuCaKY8P
== Jakarta EE Web Application Specific Configuration in web.xml
The Jakarta EE web application's web.xml file needs some specific configuration to use OpenID.
There must be a <login-config> element with an <auth-method> value of OPENID, and a <realm-name> value of the exact URL string used to set the OpenID Provider.
To set the error page, you must set a <context-param> named org.eclipse.jetty.security.openid.error_page whose value should be a path relative to the web application where authentication errors should be redirected.
For example:
[,xml,subs=attributes+]
...
== Authorization with Security Roles
If security roles are required, they can be configured through a wrapped LoginService which is deferred to for role information by the OpenIdLoginService, and assigns security roles to users.
You can configure the wrapped LoginService by modifying the $JETTY_BASE/etc/openid-baseloginservice.xml file.
You can further configure whether to only authenticate users known to the wrapped LoginService by configuring the property jetty.openid.authenticateNewUsers in the $JETTY_BASE/start.d/openid.ini file.
== Supporting Multiple OpenID Providers
By default, Jetty defines one OpenID Provider that you can configure using the properties defined in the $JETTY_BASE/start.d/openid.ini file.
You can support multiple OpenID Providers by creating a custom Jetty module (as described in xref:operations-guide:modules/custom.adoc[this section]).
The custom Jetty module XML file should add an additional OpenIdConfiguration as a bean on the Server instance, for the additional OpenID Provider.
If there are multiple OpenID configuration instances in the Server, then the OpenIdAuthenticationFactory will select the one with an issuer matching the <realm-name> of the <login-config> element in the web.xml of a given web application.
Documentation Jetty Modules Operations Guide Pages Server Index (`documentation/jetty/modules/operations-guide/pages/server/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jetty Server
The Jetty Server object is the central component that links protocol connectors to web applications.
The Server component is defined by the xref:modules/standard.adoc#server[server Jetty module], that in turn depends on other Jetty modules that provide key functionalities, in particular:
- <<logging,Logging>>
- xref:modules/standard.adoc#bytebufferpool[
ByteBufferpooling] - <>
[[logging]]
== Logging
You can configure two types of logging in Jetty: server logging and request logging.
- <<logging-server,Server logging>> refers to the console output produced by Jetty itself.
- <<logging-request,Request logging>> refers to the information that Jetty can capture about incoming HTTP requests and responses.
[[logging-server]]
=== Server Logging
Jetty uses the http://slf4j.org/[SLF4J] API for its logging.
SLF4J is a generic abstraction layer that is supported by many different logging frameworks (or SLF4J bindings).
Jetty provides a default binding via the jetty-slf4j-impl Maven artifact, but you can plug in the SLF4J binding <<logging-server-custom,of your choice>> provided by other logging frameworks.
Jetty's server logging is enabled by default with the logging Jetty module.
You typically won't have to enable the logging module directly, since it is a transitive dependency of the server module, and thus pulled in by many of the most commonly used modules.
The logging module is a xref:modules/index.adoc#names[virtual module] and its default implementation is provided by the logging-jetty Jetty module, which uses the Jetty SLF4J binding.
[[logging-server-default]]
==== Default Configuration
Jetty's default SLF4J binding uses an appender (org.eclipse.jetty.logging.StdErrAppender) to format a logging message with metadata (like a timestamp) before sending it to System.err.
The default StdErrAppender format is:
::::
where <datetime> is a timestamp with the format yyyy-MM-dd HH:mm:ss.SSS.
You can configure the appender via a file named jetty-logging.properties, which must be found in the server xref:start/index.adoc#start-class-path[class-path].
When you enable the logging-jetty module -- either directly or by transitive dependency, as in the following example -- Jetty automatically generates a jetty-logging.properties file in $JETTY_BASE/resources/:
$ java -jar $JETTY_HOME/start.jar --add-modules=http
[jetty%nowrap]
....
[jetty]
args=--add-modules=http
highlight=(logging-jetty transitively enabled|copy..properties)
....
You can specify the following configuration options in jetty-logging.properties:
org.eclipse.jetty.LEVEL=
Sets the logging level for the logger tree based at org.eclipse.jetty.
You can specify any of the usual SLF4J logging levels -- TRACE, DEBUG, INFO (default), WARN and ERROR -- plus two additional levels: ALL (an alias for TRACE) and OFF (disables logging entirely).
You can also configure a default logging level for specific loggers, or arbitrary logger trees:
com.example.MyComponent.LEVEL=DEBUG(sets logging level of loggercom.example.MyComponenttoDEBUG)com.example.LEVEL=DEBUG(sets logging level of tree+com.example.*+toDEBUG)
com.example.STACKS=::
Specifies whether to hide stack traces for some arbitrary logger tree +com.example.*+.
The exception type and message are logged normally; only stack traces are hidden.
Default value is false
org.eclipse.jetty.logging.appender.NAME_CONDENSE=::
Specifies whether to condense logger names, so that for example org.eclipse.jetty.util.QueuedThreadPool becomes oeju.QueuedThreadPool.
Default value is true.
org.eclipse.jetty.logging.appender.MESSAGE_ALIGN=::
Specifies the column at which the logging <message> should be printed.
The value 0 specifies no alignment.
Default value is 0.
org.eclipse.jetty.logging.appender.MESSAGE_ESCAPE=::
Specifies whether to escape ISO control characters such as \r or \n present in the message.
Character \r is replaced with < and character \n is replaced with |; all other ISO control characters are replaced with ?.
Default value is false.
org.eclipse.jetty.logging.appender.ZONE_ID=
Specifies the timezone ID (such as PST, or America/Los_Angeles or GMT-8:00) for the <datetime> part of the logging line.
The empty string specifies the UTC timezone.
Default value is the local timezone.
When using the Jetty SLF4J binding, the logging levels can be dynamically changed via JMX, see xref:troubleshooting/index.adoc#logging[the troubleshooting section] for more information.
[[logging-server-default-rolling]]
==== Capturing Logs to a Rolling File
Logging to System.err may be fine at development time, but you will typically want to capture logs on disk for later inspection, or if you don't have a terminal access (for example, if you started Jetty as a service).
The console-capture Jetty module allows you to capture what is written to System.out and System.err and write it to a log file.
By default, console-capture logs to a file in the $JETTY_BASE/logs/ directory.
See the xref:modules/standard.adoc#console-capture[console-capture module documentation] for details on configuring how logs are written to the log directory.
[NOTE]
The `console-capture` Jetty module should be used only in conjunction with the `logging-jetty` module, as other SLF4J bindings such as LogBack or Log4j2 have their own, more sophisticated, rolling file appenders.
[[logging-server-custom]]
==== Custom Configuration
You can use a different SLF4J binding if you are more familiar with other logging libraries, or if you need custom logging appenders.
There are a number of out-of-the-box Jetty modules that you can use:
logging-logback, to use the http://logback.qos.ch/[LogBack] bindinglogging-log4j2, to use the https://logging.apache.org/log4j/2.x/[Log4j2] bindinglogging-log4j1, to use the https://logging.apache.org/log4j/1.2/[Log4j1] binding (note that Log4j 1.x is end-of-life)logging-jul, to use thejava.util.loggingbindinglogging-noop, to use the SLF4J no-operation binding (discards all logging)
[[logging-server-custom-logback]]
==== Logging with LogBack
To enable the logging-logback module, run:
$ java -jar $JETTY_HOME/start.jar --add-modules=logging-logback,http
Since LogBack is released under a license that is different from Jetty's, you will be prompted to accept the LogBack license.
Once you accept the LogBack license, your $JETTY_BASE directory will have the following structure.
$JETTY_BASE
├── lib
│ └── logging
│ ├── logback-classic-
│ └── logback-core-
├── resources
│ └── logback.xml
└── start.d
├── http.ini
└── logging-logback.ini
Jetty downloaded the required LogBack +*.jar+ files, and created a $JETTY_BASE/resources/logback.xml file for configuring your LogBack logging.
Please refer to the http://logback.qos.ch/manual/configuration.html[LogBack configuration manual] for more information about how to configure LogBack.
[[logging-server-custom-log4j2]]
==== Logging with Log4j2
To enable the logging-log4j2 module, run:
$ java -jar $JETTY_HOME/start.jar --add-modules=logging-log4j2,http
After accepting the Log4j2 license, you will have the following directory structure:
$JETTY_BASE
├── lib
│ └── logging
│ ├── log4j-api-
│ ├── log4j-core-
│ └── log4j-slf4j2-impl-
├── resources
│ └── log4j2.xml
└── start.d
├── http.ini
└── logging-log4j2.ini
Jetty downloaded the required Log4j2 +*.jar+ files, and created a $JETTY_BASE/resources/log4j2.xml file that you can configure to customize your Log4j2 logging.
Please refer to the https://logging.apache.org/log4j/2.x/manual/configuration.html[Log4j2 configuration manual] for more information about how to configure Log4j2.
[[logging-server-bridges]]
==== Bridging Logging to SLF4J
When you use libraries that provide the features you need (for example, JDBC drivers), it may be possible that those libraries use a different logging framework than SLF4J.
SLF4J provides http://www.slf4j.org/legacy.html[bridges for legacy logging APIs] that allows you to bridge logging from one of these legacy logging frameworks to SLF4J.
Once the logging is bridged to SLF4J, you can use Jetty's <<logging-server-default,default configuration>> or a <<logging-server-custom,custom configuration>> so that your logging is centralized in one place.
Jetty provides the logging-jul-capture module for bridging from java.util.logging to SLF4J.
IMPORTANT: The modules logging-jcl-capture and logging-log4j1-capture similarly provide bridges from Jakarta Commons Logging (JCL) and Apache Log4j, respectively; however, these modules are obsolete and should not be used anymore.
[[logging-server-bridge-jul]]
==== Bridging from java.util.logging
For libraries that use java.util.logging as their logging framework, you can enable Jetty's logging-jul-capture module:
$ java -jar $JETTY_HOME/start.jar --add-modules=logging-jul-capture
The logging-jul-capture module implies --exec and therefore xref:start/index.adoc#start[spawns a second JVM] because it needs to provide the system property java.util.logging.config.file (so that java.util.logging can read the configuration from the specified file), and because it needs to make available on the System ClassLoader the class org.slf4j.bridge.SLF4JBridgeHandler.
For example, a library that uses java.util.logging as its logging library is the Postgresql JDBC driver.
With the logging-jul-capture Jetty module, the logging follows this diagram:
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
participant "Postgresql JDBC" as postgresql
participant java.util.logging
participant SLF4JBridgeHandler
participant Jetty
participant SLF4J
participant "Jetty SLF4J Binding" as binding
postgresql -> java.util.logging java.util.logging -> SLF4JBridgeHandler SLF4JBridgeHandler -> SLF4J SLF4J -> binding Jetty -> SLF4J SLF4J -> binding
Note how Jetty logs directly to SLF4J, while the Postgresql JDBC driver logs to SLF4J through the SLF4JBridgeHandler.
They both arrive to the SLF4J binding, in this case the Jetty SLF4J binding (but could be any other SLF4J binding such as LogBack).
[[logging-request]]
=== Request Logging
HTTP requests and responses can be logged to provide data that can be later analyzed with other tools, that can provide information such as the most frequently accessed request URIs, the response status codes, the request/response content lengths, geographical information about the clients, etc.
Request logging is enabled by enabling the requestlog Jetty module.
In the example below, both the http Jetty module and the requestlog module are enabled, so that you can make HTTP requests to the server and have them logged:
$ cd $JETTY_BASE $ java -jar $JETTY_HOME/start.jar --add-modules=http,requestlog
The $JETTY_BASE directory looks like this:
[source]
$JETTY_BASE
├── logs
├── resources
│ └── jetty-logging.properties
└── start.d
├── http.ini
└── requestlog.ini
The $JETTY_BASE/start.d/requestlog.ini file is the Jetty module configuration file that allows you to configure the requestlog module, see xref:modules/standard.adoc#requestlog[this section] for more details.
By default the requestlog Jetty module produces the $JETTY_BASE/logs/yyyy_MM_dd.request.log, where the pattern yyyy_MM_dd is replaced with the current date, for example 2020_01_31.
The format of the request log lines is the result of a format string that uses formatting symbols to log relevant request/response data.
The default format is the https://en.wikipedia.org/wiki/Common_Log_Format[NCSA Format] extended with referrer data and user-agent data.
A typical log line looks like this:
[,options=nowrap]
192.168.0.100 - - [31/Jan/2020:20:30:40 +0000] "GET / HTTP/1.1" 200 6789 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"
The line above (that uses fake values) shows 192.168.0.100 for the client IP address, a hard-coded - for the identity, - for the authenticated user name, [31/Jan/2020:20:30:40 +0000] for the date and time with timezone, "GET / HTTP/1.1" for the HTTP request line, 200 for the HTTP response status code, 6789 for the HTTP response content length, "-" for the referrer and "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36" for the user-agent.
The format string can be customized as described in xref:modules/standard.adoc#requestlog[this section].
Request log files are rolled every day, and retained for customizable number of days, by default 90 days.
[NOTE]
When Jetty is behind a load balancer, you want to log the remote client IP address, not the load balancer IP address. Refer to xref:protocols/index.adoc#proxy[this section] to configure the load balancer and Jetty to retain the remote client IP address information.
[[logging-request-slf4j]]
==== Request Logging to SLF4J
The requestlog-slf4j Jetty module provides an alternative to the file-based requestlog module.
Instead of writing request logs to a file, it writes them to the SLF4J logging framework at INFO level.
This is useful when:
- You want request logs to appear in your application's main log stream
- You're using a centralized logging system (ELK, Splunk, etc.)
- You prefer console output during development
- You want your logging framework (Logback, Log4j2) to handle log rotation and formatting
To enable SLF4J request logging:
$ java -jar $JETTY_HOME/start.jar --add-modules=http,requestlog-slf4j
By default, request logs are written to the logger named org.eclipse.jetty.server.RequestLog at INFO level.
You can configure the logger name in $JETTY_BASE/start.d/requestlog-slf4j.ini:
jetty.requestlog.slf4j.loggerName=com.example.RequestLog
The format string can be customized the same way as the standard requestlog module:
jetty.requestlog.formatString=%{client}a - %u %t "%r" %s %O
[NOTE]
The requestlog-slf4j module delegates to your SLF4J logging configuration.
To see request logs in your output, ensure that:
- The logger
org.eclipse.jetty.server.RequestLog(or your custom logger name) is configured at INFO level or lower - Your SLF4J binding (Logback, Log4j2, etc.) is properly configured
Example Logback configuration: [source,xml]
[[threadpool]]
== Thread Pooling
Jetty uses thread pooling to efficiently execute tasks that provide Jetty functionalities.
Like any other component, the Jetty thread pool is configured and enabled via the xref:modules/standard.adoc#threadpool[threadpool Jetty module], that is transitively enabled by the xref:modules/standard.adoc#server[server Jetty module] which, in turn, is transitively enabled by a protocol module such as the xref:protocols/index.adoc#http[http Jetty module]:
$ java -jar $JETTY_HOME/start.jar --add-modules=http
The command above gives you the default configuration for the thread pool.
If you want to explicitly configure the thread pool, it is enough to explicitly specify the xref:modules/standard.adoc#threadpool[threadpool] module:
$ java -jar $JETTY_HOME/start.jar --add-modules=threadpool,http
After the command above, the $JETTY_BASE directory looks like this:
[source]
$JETTY_BASE
├── resources
│ └── jetty-logging.properties
└── start.d
├── http.ini
└── threadpool.ini
Now you can customize the threadpool.ini file to explicitly configure the thread pool.
[[threadpool-virtual]]
=== Virtual Threads Support
Virtual threads have been introduced as a preview feature in Java 19 and Java 20, and have become an official feature since Java 21.
The xref:modules/standard.adoc#threadpool-virtual-preview[threadpool-virtual-preview] Jetty module provides support for virtual threads in Java 19 and Java 20, and it is mutually exclusive with the threadpool Jetty module.
When using Java 21, there are two Jetty modules available:
- xref:modules/standard.adoc#threadpool-virtual[
threadpool-virtual] - xref:modules/standard.adoc#threadpool-all-virtual[
threadpool-all-virtual]
Both are mutually exclusive with the threadpool Jetty module.
If you have already enabled the threadpool Jetty module, it is sufficient to remove it by removing the $JETTY_BASE/start.d/threadpool.ini file.
The xref:modules/standard.adoc#threadpool-virtual[threadpool-virtual] Jetty module provides a mixed thread mode, where platform threads are used to run internal Jetty tasks, but application code is invoked using virtual threads.
The xref:modules/standard.adoc#threadpool-all-virtual[threadpool-all-virtual] Jetty module provides a thread mode where all threads are virtual threads, including those used internally by Jetty.
You can enable either module using:
$ java -jar $JETTY_HOME/start.jar --add-modules=threadpool-virtual,http
or
$ java -jar $JETTY_HOME/start.jar --add-modules=threadpool-all-virtual,http
After the command above, the $JETTY_BASE/start.d/ directory will contain the corresponding threadpool-virtual.ini or threadpool-all-virtual.ini file.
You can now explicitly configure the thread pool module properties inside the +*.ini+ file and then start Jetty.
Documentation Jetty Modules Operations Guide Pages Session Index (`documentation/jetty/modules/operations-guide/pages/session/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= HTTP Session Management
HTTP sessions are a concept within the Servlet API which allow requests to store and retrieve information across the time a user spends in an application.
Jetty offers a number of pluggable alternatives for managing and distributing/persisting sessions.
Choosing the best alternative is an important consideration for every application as is the correct configuration to achieve optimum performance.
[[overview]]
== HTTP Session Overview
=== Terminology
Before diving into the specifics of how to plug-in and configure various alternative HTTP session management modules, let's review some useful terminology:
Session::
is a means of retaining information across requests for a particular user.
The Servlet Specification defines the semantics of sessions.
Some of the most important characteristics of sessions is that they have a unique id and that their contents cannot be shared between different contexts (although the id can be): if a session is invalidated in one context, then all other sessions that share the same id in other contexts will also be invalidated.
Sessions can expire or they can be explicitly invalidated.
SessionIdManager::
is responsible for allocating session ids.
A Jetty server can have at most 1 SessionIdManager.
HouseKeeper::
is responsible for periodically orchestrating the removal of expired sessions.
This process is referred to as <>.
SessionHandler::
is responsible for managing the lifecycle of sessions.
A context can have at most 1 SessionHandler.
SessionCache::
is a L1 cache of in-use session objects.
The SessionCache is used by the SessionHandler.
SessionDataStore::
is responsible for all clustering/persistence operations on sessions.
A SessionCache uses a SessionDataStore as a backing store.
CachingSessionDataStore::
is an L2 cache of session data.
A SessionCache can use a CachingSessionDataStore as its backing store.
More details on these concepts can be found in the xref:programming-guide:server/session.adoc[Programming Guide].
[NOTE]
``SessionDataStore``s implementations interact with other, usually third party, systems responsible for storing and/or distributing session information. Sessions can be distributed without being persisted. They can also be persisted without being distributed. Because persisting session information to a shared store is a very common way of distributing (also known as "clustering") sessions, in the documentation we will often refer to just "persisting".
[[modules]]
=== Session Modules
There are a number of modules that offer pluggable alternatives for http session management.
You can design how you want to cache and store http sessions by selecting alternative combinations of session modules.
For example, Jetty ships with two alternative implementations of the SessionCache:
- one that caches sessions in memory: <<cache-hash,
session-cache-hash>> - one that does not actually cache: <<cache-null,
session-cache-null>>
There are at least 6 alternative implementations of the SessionDataStore that you can use to persist/distribute your http sessions:
- file system storage: <<filesystem,
session-store-file>> - relational database storage: <<jdbc,
session-store-jdbc>> - NoSQL database storage: <<mongo,
session-store-mongo>> - Google Cloud datastore storage: <<gcloud,
session-store-gcloud>> - Hazelcast: <<hazelcast-remote,
session-store-hazelcast-remote>> or <<hazelcast-embedded,session-store-hazelcast-embedded>> - Infinispan: <> or <>
TIP: It is worth noting that if you do not configure any session modules, Jetty will still provide HTTP sessions that are cached in memory but are never persisted.
[[base]]
== The Base Session Module
The sessions module is the base module that all other session modules depend upon.
As such it will be transitively enabled if you enable any of the other session modules: you need to explicitly enable it if you wish to change any settings from their defaults.
Enabling the sessions module puts the $JETTY_HOME/etc/sessions/id-manager.xml file onto the execution path and generates a $JETTY_BASE/start.d/sessions.ini file.
The id-manager.xml file instantiates a DefaultSessionIdManager and HouseKeeper.
The former is used to generate and manage session ids whilst the latter is responsible for periodic <> of expired sessions.
=== Configuration
The $JETTY_BASE/start.d/sessions.ini file contains these configuration properties:
jetty.sessionIdManager.workerName::
This uniquely identifies the jetty server instance and is applied to the SessionIdManager.
You can either provide a value for this property, or you can allow Jetty to try and synthesize a workerName - the latter option is only advisable in the case of a single, non-clustered deployment.
There are two ways a default workerName can be synthesized:
- if running on Google AppEngine, the
workerNamewill be formed by concatenating the values of the environment variablesJETTY_WORKER_INSTANCEandGAE_MODULE_INSTANCE - otherwise, the
workerNamewill be formed by concatenating the environment variableJETTY_WORKER_INSTANCEand the literal0.
So, if you're not running on Google AppEngine, and you haven't configured one, the workerName will always be: node0.
IMPORTANT: If you have more than one Jetty instance, it is crucial that you configure the workerName differently for each instance.
jetty.sessionScavengeInterval.seconds::
This is the period in seconds between runs of the HouseKeeper, responsible for orchestrating the removal of expired sessions.
By default it will run approximately every 600 secs (ie 10 mins).
As a rule of thumb, you should ensure that the <> interval is shorter than the <session-timeout> of your sessions to ensure that they are promptly scavenged.
On the other hand, if you have a backend store configured for your sessions, <> too frequently can increase the load on it.
CAUTION: Don't forget that the <session-timeout> is specified in web.xml in minutes and the value of the jetty.sessionScavengeInterval.seconds is in seconds.
[[base-scavenge]]
=== Session Scavenging
The HouseKeeper is responsible for the periodic initiation of session scavenge cycles.
The jetty.sessionScavengeInterval.seconds property in $JETTY_BASE/start.d/sessions.ini controls the periodicity of the cycle.
[NOTE]
The HouseKeeper semi-randomly adds an additional 10% to the configured `sessionScavengeInterval`. This is to prevent multiple nodes in a cluster that are all started at once from syncing up scavenge cycles and placing extra load on the configured persistence mechanism.
A session whose expiry time has been exceeded is considered eligible for scavenging.
The session might be present in a SessionCache and/or present in the session persistence/clustering mechanism.
Scavenging occurs for all contexts on a server at every cycle.
The HouseKeeper sequentially asks the SessionHandler in each context to find and remove expired sessions.
The SessionHandler works with the SessionDataStore to evaluate candidates for expiry held in the SessionCache, and also to sweep the persistence mechanism to find expired sessions.
The sweep takes two forms: once per cycle the SessionDataStore searches for sessions for its own context that have expired; infrequently, the SessionDataStore will widen the search to expired sessions in all contexts.
The former finds sessions that are no longer in this context's SessionCache, and using some heuristics, are unlikely to be in the SessionCache of the same context on another node either.
These sessions will be loaded and fully expired, meaning that HttpSessionListener.destroy() will be called for them.
The latter finds sessions that have not been disposed of by scavenge cycles on any other context/node.
As these will be sessions that expired a long time ago, and may not be appropriate to load by the context doing the scavenging, these are summarily deleted without HttpSessionListener.destroy() being called.
A combination of these sweeps should ensure that the persistence mechanism does not fill over time with expired sessions.
As aforementioned, the sweep period needs to be short enough to find expired sessions in a timely fashion, but not so often that it overloads the persistence mechanism.
[[cache]]
== Modules for HTTP Session Caching
In this section we will look at the alternatives for the SessionCache, i.e. the L1 cache of in-use session objects.
Jetty ships with 2 alternatives: an in-memory cache, and a null cache.
The latter does not actually do any caching of sessions, and can be useful if you either want to minimize your support for sessions, or you are in a clustered deployment without a sticky loadbalancer.
The <> go into more detail on this.
[[cache-hash]]
=== Caching in Memory
If you wish to change any of the default configuration values you should enable the session-cache-hash xref:modules/index.adoc[module].
The name "hash" harks back to historical Jetty session implementations, whereby sessions were kept in memory using a HashMap.
==== Configuration
The $JETTY_BASE/start.d/session-cache-hash.ini contains the following configurable properties:
jetty.session.evictionPolicy::
Integer, default -1.
This controls whether session objects that are held in memory are subject to eviction from the cache.
Eviction means that the session is removed from the cache.
This can reduce the memory footprint of the cache and can be useful if you have a lot of sessions.
Eviction is usually used in conjunction with a SessionDataStore that persists sessions.
The eviction strategies and their corresponding values are:
-1 (NO EVICTION):::
sessions are never evicted from the cache.
The only way they leave are via expiration or invalidation.
0 (EVICT AFTER USE):::
sessions are evicted from the cache as soon as the last active request for it finishes.
The session will be passed to the SessionDataStore to be written out before eviction.
= 1 (EVICT ON INACTIVITY):::
any positive number is the time in seconds after which a session that is in the cache but has not experienced any activity will be evicted.
Use thejetty.session.saveOnInactiveEvictproperty to force a session write before eviction.
NOTE: If you are not using one of the session store modules, ie one of the session-store-xxxxs, then sessions will be lost when the context is stopped, or the session is evicted.
jetty.session.saveOnInactiveEvict::
Boolean, default false.
This controls whether a session will be persisted to the SessionDataStore if it is being evicted due to the EVICT ON INACTIVITY policy.
Usually sessions will be written to the SessionDataStore whenever the last simultaneous request exits the session.
However, as SessionDataStores can be configured to skip some writes (see the documentation for the session-store-xxx module that you are using), this option is provided to ensure that the session will be written out.
NOTE: Be careful with this option, as in clustered scenarios it would be possible to "re-animate" a session that has actually been deleted by another node.
jetty.session.saveOnCreate::
Boolean, default false.
Controls whether a session that is newly created will be immediately saved to the SessionDataStore or lazily saved as the last request for the session exits.
This can be useful if the request dispatches to another context and needs to re-use the same session id.
jetty.session.removeUnloadableSessions::
Boolean, default false.
Controls whether the session cache should ask a SessionDataStore to delete a session that cannot be restored - for example because it is corrupted.
jetty.session.flushOnResponseCommit::
Boolean, default true.
If true, if a session is "dirty" - ie it has never been saved or its attributes have changed - it will be written to the SessionDataStore as the response is about to commit.
This ensures that all subsequent requests - whether to the same or different node - will see the updated session data.
If false, a dirty session will only be written to the backing store when the last simultaneous request for it leaves the session.
Be aware that in this case, the write can happen after the response is returned to the client.
jetty.session.invalidateOnShutdown::
Boolean, default false.
If true, when a context is shutdown, all sessions in the cache are invalidated and deleted both from the cache and from the SessionDataStore.
[[cache-null]]
=== No Caching
You may need to use the session-cache-null module if your clustering setup does not have a sticky load balancer, or if you want absolutely minimal support for sessions.
If you enable this module, but you don't enable a module that provides session persistence (ie one of the session-store-xxx modules), then sessions will neither be retained in memory nor persisted.
==== Configuration
The $JETTY_BASE/start.d/session-cache-null.ini contains the following configurable properties:
jetty.session.saveOnCreate::
Boolean, default false.
Controls whether a session that is newly created will be immediately saved to the SessionDataStore or lazily saved as the last request for the session exits.
This can be useful if the request dispatches to another context and needs to re-use the same session id.
jetty.session.removeUnloadableSessions::
Boolean, default false.
Controls whether the session cache should ask a SessionDataStore to delete a session that cannot be restored - for example because it is corrupted.
jetty.session.flushOnResponseCommit::
Boolean, default false.
If true, if a session is "dirty" - ie its attributes have changed - it will be written to the backing store as the response is about to commit.
This ensures that all subsequent requests whether to the same or different node will see the updated session data.
If false, a dirty session will only be written to the backing store when the last simultaneous request for it leaves the session.
[[filesystem]]
== Modules for Persistent HTTP Sessions: File System
The session-store-file Jetty module supports persistent storage of session data in a filesystem.
IMPORTANT: Persisting sessions to the local file system should never be used in a clustered environment.
Enabling this module creates the $JETTY_BASE/sessions directory.
By default session data will be saved to this directory, one file representing each session.
File names follow this pattern:
+[expiry]_[contextpath]_[virtualhost]_[id]+
expiry::
This is the expiry time in milliseconds since the epoch.
contextpath::
This is the context path with any special characters, including /, replaced by the _ underscore character.
For example, a context path of /catalog would become _catalog.
A context path of simply / becomes just __.
virtualhost::
This is the first virtual host associated with the context and has the form of 4 digits separated by . characters: +[digit].[digit].[digit].[digit]+.
If there are no virtual hosts associated with a context, then 0.0.0.0 is used.
id::
This is the unique id of the session.
Putting all of the above together as an example, a session with an id of node0ek3vx7x2y1e7pmi3z00uqj1k0 for the context with path /test with no virtual hosts and an expiry of 1599558193150 would have a file name of:
1599558193150__test_0.0.0.0_node0ek3vx7x2y1e7pmi3z00uqj1k0
=== Configuration
The $JETTY_BASE/start.d/sessions.ini file contains the following properties which may be modified to customise filesystem session storage:
jetty.session.storeDir::
The default is $JETTY_BASE/sessions.
This is a path that defines the location for storage of session files.
jetty.session.file.deleteUnrestorableFiles::
Boolean, default false.
If set to true, unreadable files will be deleted.
This is useful to prevent repeated logging of the same error when the scavenger periodically (re-)attempts to load the corrupted information for a session in order to expire it.
jetty.session.gracePeriod.seconds::
Integer, default 3600.
Used during session <>.
Multiples of this period are used to define how long ago a stored session must have expired before it should be <>.
jetty.session.savePeriod.seconds::
Integer, in seconds, default is 0.
Whenever a session is accessed by a request, its lastAccessTime and expiry are updated.
Even if your sessions are read-mostly, the lastAccessTime and expiry will always change.
For heavily-used, read-mostly sessions you can save some time by skipping some writes for sessions for which only these fields have changed (ie no session attributes changed).
The value of this property is used to skip writes for these kinds of sessions: the session will only be written out if the time since the last write exceeds the value of this property.
[WARNING]
You should be careful in the use of this property in clustered environments: if you set too large a value for this property, the session may not be written out sufficiently often to update its `expiry` time thus making it appear to other nodes that it has expired. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - it would be undesirable to set a `savePeriod` that is larger than the `maxIdleTime`.
[[jdbc]]
== Modules for Persistent HTTP Sessions: JDBC
Enabling the session-store-jdbc module configures Jetty to persist session data in a relational database.
=== Configuration
After enabling the module, the $JETTY_BASE/start.d/session-store-jdbc.ini file contains the following customizable properties:
jetty.session.gracePeriod.seconds::
Integer, default 3600.
Used during session <>.
Multiples of this period are used to define how long ago a stored session must have expired before it should be <>.
jetty.session.savePeriod.seconds::
Integer, in seconds, default is 0.
Whenever a session is accessed by a request, its lastAccessTime and expiry are updated.
Even if your sessions are read-mostly, the lastAccessTime and expiry will always change.
For heavily-used, read-mostly sessions you can save some time by skipping some writes for sessions for which only these fields have changed (ie no session attributes changed).
The value of this property is used to skip writes for these kinds of sessions: the session will only be written out if the time since the last write exceeds the value of this property.
[WARNING]
You should be careful in the use of this property in clustered environments: if you set too large a value for this property, the session may not be written out sufficiently often to update its `expiry` time thus making it appear to other nodes that it has expired. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - it would be undesirable to set a `savePeriod` that is larger than the `maxIdleTime`.
db-connection-type::
Default datasource.
Set to either datasource or driver depending on the type of connection being used.
Depending which you select, there are additional properties available:
datasource:::
jetty.session.jdbc.datasourceName::::
Name of the remote datasource.
driver:::
jetty.session.jdbc.driverClass::::
Name of the JDBC driver that controls access to the remote database, such as com.mysql.jdbc.Driver
jetty.session.jdbc.driverUrl::::
URL of the database which includes the driver type, host name and port, service name and any specific attributes unique to the database, such as a username.
As an example, here is a mysql connection with the username appended: jdbc:mysql://127.0.0.1:3306/sessions?user=sessionsadmin.
jetty.session.jdbc.blobType::
Optional.
Default blob or bytea for Postgres.
This is the keyword used by the particular database to identify the blob data type.
If netiher default is suitable you can set this value explicitly.
jetty.session.jdbc.longType::
Optional.
Default bigint or number(20) for Oracle.
This is the keyword used by the particular database to identify the long integer data type.
Set this explicitly if neither of the default values is appropriate.
jetty.session.jdbc.stringType::
Optional.
Default varchar.
This is the keyword used by the particular database to identify character type.
If the default is not suitable, you can set this value explicitly.
jetty.session.jdbc.schema.schemaName::
jetty.session.jdbc.schema.catalogName::
Optional.
The exact meaning of these two properties is dependent on your database vendor, but can broadly be described as further scoping for the session table name.
See https://en.wikipedia.org/wiki/Database_schema[] and https://en.wikipedia.org/wiki/Database_catalog[].
These extra scoping names can come into play at startup time when Jetty determines if the session table already exists, or otherwise creates it on-the-fly.
If you have employed either of these concepts when you pre-created the session table, or you want to ensure that Jetty uses them when it auto-creates the session table, then you have two options: either set them explicitly, or let Jetty infer them from a database connection (obtained using either a Datasource or Driver according to the db-connection-type you have configured).
To set them explicitly, uncomment and supply appropriate values for the jetty.session.jdbc.schema.schemaName and/or jetty.session.jdbc.schema.catalogName properties.
Alternatively, to allow Jetty to infer them from a database connection, use the special string INFERRED instead.
If you leave them blank or commented out, then the sessions table will not be scoped by schema or catalog name.
jetty.session.jdbc.schema.table::
Default JettySessions.
This is the name of the table in which session data is stored.
jetty.session.jdbc.schema.accessTimeColumn::
Default accessTime.
This is the name of the column that stores the time - in ms since the epoch - at which a session was last accessed
jetty.session.jdbc.schema.contextPathColumn::
Default contextPath.
This is the name of the column that stores the contextPath of a session.
jetty.session.jdbc.schema.cookieTimeColumn::
Default cookieTime.
This is the name of the column that stores the time - in ms since the epoch - that the cookie was last set for a session.
jetty.session.jdbc.schema.createTimeColumn::
Default createTime.
This is the name of the column that stores the time - in ms since the epoch - at which a session was created.
jetty.session.jdbc.schema.expiryTimeColumn::
Default expiryTime.
This is name of the column that stores - in ms since the epoch - the time at which a session will expire.
jetty.session.jdbc.schema.lastAccessTimeColumn::
Default lastAccessTime.
This is the name of the column that stores the time - in ms since the epoch - that a session was previously accessed.
jetty.session.jdbc.schema.lastSavedTimeColumn::
Default lastSavedTime.
This is the name of the column that stores the time - in ms since the epoch - at which a session was last written.
jetty.session.jdbc.schema.idColumn::
Default sessionId.
This is the name of the column that stores the id of a session.
jetty.session.jdbc.schema.lastNodeColumn::
Default lastNode.
This is the name of the column that stores the workerName of the last node to write a session.
jetty.session.jdbc.schema.virtualHostColumn::
Default virtualHost.
This is the name of the column that stores the first virtual host of the context of a session.
jetty.session.jdbc.schema.maxIntervalColumn::
Default maxInterval.
This is the name of the column that stores the interval - in ms - during which a session can be idle before being considered expired.
jetty.session.jdbc.schema.mapColumn::
Default map.
This is the name of the column that stores the serialized attributes of a session.
[[mongo]]
== Modules for Persistent HTTP Sessions: MongoDB
Enabling the session-store-mongo module configures Jetty to store session data in MongoDB.
Because MongoDB is not a technology provided by the Eclipse Foundation, you will be prompted to assent to the licenses of the external vendor (Apache in this case) during the install.
Jars needed by MongoDB are downloaded and stored into a directory named $JETTY_BASE/lib/nosql/.
IMPORTANT: If you want to use updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated $JETTY_BASE/lib/ directory and use the --skip-create-files=<module name> command line option to prevent errors when starting your server.
=== Configuration
The $JETTY_BASE/start.d/session-store-mongo.ini file contains these configurable properties:
jetty.session.mongo.dbName::
Default is "HttpSessions".
This is the name of the database in MongoDB used to store the session collection.
jetty.session.mongo.collectionName::
Default is "jettySessions".
This is the name of the collection in MongoDB used to store all of the sessions.
The connection type-:: You can connect to MongoDB either using a host/port combination, or a URI. By default, the host/port method is selected, but you can change this by commenting out the unwanted method, and uncommenting the other one. connection-type=address::: Used when utilizing a direct connection to the MongoDB server. jetty.session.mongo.host:::: Host name or address for the remote MongoDB instance. jetty.session.mongo.port:::: Port number for the remote MongoDB instance. connection-type=uri::: Used when utilizing MongoURI for secured connections. jetty.session.mongo.connectionString:::: The string defining the MongoURI value, such as `+mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]+`. More information on how to format the MongoURI string can be found in the https://docs.mongodb.com/manual/reference/connection-string/[official documentation for mongo]. [NOTE]
You will only use *one* `connection-type` at a time, either `address` or `uri`. If both are utilized in your `session-store-mongo.ini`, only the _last_ `connection-type` configured in the file will be used.
jetty.session.gracePeriod.seconds::
Integer, in seconds.
Default 3600.
Used during session <>.
Multiples of this period are used to define how long ago a stored session must have expired before it should be <>.
jetty.session.savePeriod.seconds::
Integer, in seconds, default is 0.
Whenever a session is accessed by a request, its lastAccessTime and expiry are updated.
Even if your sessions are read-mostly, the lastAccessTime and expiry will always change.
For heavily-used, read-mostly sessions you can save some time by skipping some writes for sessions for which only these fields have changed (ie no session attributes changed).
The value of this property is used to skip writes for these kinds of sessions: the session will only be written out if the time since the last write exceeds the value of this property.
[WARNING]
You should be careful in the use of this property in clustered environments: if you set too large a value for this property, the session may not be written out sufficiently often to update its `expiry` time thus making it appear to other nodes that it has expired. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - it would be undesirable to set a `savePeriod` that is larger than the `maxIdleTime`.
[[infinispan]]
== Modules for Persistent HTTP Sessions: Infinispan
In order to persist/cluster sessions using Infinispan, Jetty needs to know how to contact Infinispan.
There are two options: a remote Infinispan instance, or an in-process Infinispan instance.
The former is referred to as "remote" Infinispan and the latter as "embedded" Infinispan.
If you wish Jetty to be able to <> expired sessions, you will also need to enable the appropriate infinispan-[remote|embedded]-query module.
[[infinispan-remote]]
=== Remote Infinispan Session Module
The session-store-infinispan-remote module configures Jetty to talk to an external Infinispan instance to store session data.
Because Infinispan is not a technology provided by the Eclipse Foundation, you will be prompted to assent to the licenses of the external vendor (Apache in this case).
Infinispan-specific jar files are download to the directory named $JETTY_BASE/lib/infinispan/.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the $JETTY_BASE/start.d directory.
NOTE: If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated $JETTY_BASE/lib/ directory and use the --skip-create-files=<module name> command line option to prevent errors when starting your server.
==== Configuration
The $JETTY_BASE/start.d/session-store-infinispan-remote.ini contains the following configurable properties:
jetty.session.infinispan.remoteCacheName::
Default "sessions".
This is the name of the cache in Infinispan where sessions will be stored.
jetty.session.infinispan.idleTimeout.seconds::
Integer, in seconds, default 0.
This is the amount of time, in seconds, that a session entry in Infinispan can be idle (ie neither read nor written) before Infinispan will delete its entry.
Usually, you do not want to set a value for this, as you want Jetty to manage all session expiration (and call any HttpSessionListeners).
You should enable the <> to allow jetty to <> for expired sessions.
If you do not, then there is the possibility that sessions can be left in Infinispan but no longer referenced by any Jetty node (so called "zombie" or "orphan" sessions), in which case you can use this feature to ensure their removal.
IMPORTANT: You should make sure that the number of seconds you specify is larger than the configured maxIdleTime for sessions.
jetty.session.gracePeriod.seconds::
Integer, default 3600.
Used during session <>.
Multiples of this period are used to define how long ago a stored session must have expired before it should be <>.
jetty.session.savePeriod.seconds::
Integer, in seconds, default is 0.
Whenever a session is accessed by a request, its lastAccessTime and expiry are updated.
Even if your sessions are read-mostly, the lastAccessTime and expiry will always change.
For heavily-used, read-mostly sessions you can save some time by skipping some writes for sessions for which only these fields have changed (ie no session attributes changed).
The value of this property is used to skip writes for these kinds of sessions: the session will only be written out if the time since the last write exceeds the value of this property.
[WARNING]
You should be careful in the use of this property in clustered environments: if you set too large a value for this property, the session may not be written out sufficiently often to update its `expiry` time thus making it appear to other nodes that it has expired. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - it would be undesirable to set a `savePeriod` that is larger than the `maxIdleTime`.
[[infinispan-remote-query]]
=== Remote Infinispan Query Module
The infinispan-remote-query module allows Jetty to <> expired sessions.
Note that this is an additional module, to be used in conjunction with the session-store-infinispan-remote module.
There are no configuration properties associated with this module.
[[infinispan-embedded]]
=== Embedded Infinispan Session Module
Enabling the session-store-infinispan-embedded module runs an in-process instance of Infinispan.
Because Infinispan is not a technology provided by the Eclipse Foundation, you will be prompted to assent to the licenses of the external vendor (Apache in this case).
Infinispan-specific jar files will be downloaded and saved to a directory named $JETTY_BASE/lib/infinispan/.
NOTE: If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated $JETTY_BASE/lib/ directory and use the --skip-create-files=<module name> command line option to prevent errors when starting your server.
==== Configuration
The $JETTY_BASE/start.d/session-store-infinispan-embedded.ini contains the following configurable properties:
jetty.session.infinispan.idleTimeout.seconds::
Integer, in seconds, default 0.
This is the amount of time, in seconds, that a session entry in Infinispan can be idle (ie neither read nor written) before Infinispan will delete its entry.
Usually, you do not want to set a value for this, as you want Jetty to manage all session expiration (and call any HttpSessionListeners).
You should enable the <> to allow Jetty to <> for expired sessions.
If you do not, then there is the possibility that expired sessions can be left in Infinispan.
IMPORTANT: You should make sure that the number of seconds you specify is larger than the configured maxIdleTime for sessions.
jetty.session.gracePeriod.seconds::
Integer, default 3600.
Used during session <>.
Multiples of this period are used to define how long ago a stored session must have expired before it should be <>.
jetty.session.savePeriod.seconds::
Integer, in seconds, default is 0.
Whenever a session is accessed by a request, its lastAccessTime and expiry are updated.
Even if your sessions are read-mostly, the lastAccessTime and expiry will always change.
For heavily-used, read-mostly sessions you can save some time by skipping some writes for sessions for which only these fields have changed (ie no session attributes changed).
The value of this property is used to skip writes for these kinds of sessions: the session will only be written out if the time since the last write exceeds the value of this property.
[WARNING]
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - it would be undesirable to set a `savePeriod` that is larger than the `maxIdleTime`.
[[infinispan-embedded-query]]
=== Embedded Infinispan Query Module
The infinispan-embedded-query module allows Jetty to <> expired sessions.
There are no configuration properties associated with this module.
=== Converting Session Format for Jetty-9.4.13
From Jetty-9.4.13 onwards, we have changed the format of the serialized session when using a remote cache (ie using hotrod).
Prior to release 9.4.13 we used the default Infinispan serialization, however this was not able to store sufficient information to allow Jetty to properly deserialize session attributes in all circumstances.
See issue https://github.com/jetty/jetty.project/issues/2919[] for more background.
We have provided a conversion program which will convert any sessions stored in Infinispan to the new format.
IMPORTANT: We recommend that you backup your stored sessions before running the conversion program.
How to use the converter:
[source,subs=attributes]
java -cp jakarta.servlet-api-6.0.0.jar:jetty-util-{jetty-version}.jar:jetty-server-{jetty-version}.jar:infinispan-remote-9.1.0.Final.jar:jetty-infinispan-{jetty-version}.jar:[other classpath] org.eclipse.jetty.session.infinispan.InfinispanSessionLegacyConverter
Usage: InfinispanSessionLegacyConverter [-Dhost=127.0.0.1] [-Dverbose=true|false] [check]
The classpath::
Must contain the servlet-api, jetty-util, jetty-server, jetty-infinispan and infinispan-remote jars. If your sessions contain attributes that use application classes, you will also need to also put those classes onto the classpath. If your session has been authenticated, you may also need to include the jetty-security and jetty-http jars on the classpath.
Parameters::
When used with no arguments the usage message is printed. When used with the cache-name parameter the conversion is performed. When used with both cache-name and check parameters, sessions are checked for whether or not they are converted.
-Dhost::: you can optionally provide a system property with the address of your remote Infinispan server. Defaults to the localhost.
-Dverbose::: defaults to false. If true, prints more comprehensive stacktrace information about failures. Useful to diagnose why a session is not converted.
cache-name::: the name of the remote cache containing your sessions. This is mandatory.
check::: the optional check command will verify sessions have been converted. Use it after doing the conversion.
To perform the conversion, run the InfinispanSessionLegacyConverter with just the cache-name, and optionally the host system property.
The following command will attempt to convert all sessions in the cached named my-remote-cache on the machine myhost, ensuring that application classes in the /my/custom/classes directory are on the classpath:
[source,subs=attributes]
java -cp jakarta.servlet-api-6.0.0.jar:jetty-util-{jetty-version}.jar:jetty-server-{jetty-version}.jar:infinispan-remote-9.1.0.Final.jar:jetty-infinispan-{jetty-version}.jar:/my/custom/classes org.eclipse.jetty.session.infinispan.InfinispanSessionLegacyConverter -Dhost=myhost my-remote-cache
If the converter fails to convert a session, an error message and stacktrace will be printed and the conversion will abort. The failed session should be untouched, however it is prudent to take a backup of your cache before attempting the conversion.
[[hazelcast]]
== Modules for Persistent HTTP Sessions: Hazelcast
Hazelcast can be used to cluster session information in one of two modes: either remote or embedded.
Remote mode means that Hazelcast will create a client to talk to other instances, possibly on other nodes.
Embedded mode means that Hazelcast will start a local instance and communicate with that.
[[hazelcast-remote]]
=== Remote Hazelcast Clustering
Enabling the session-store-hazelcast-remote module allows jetty to communicate with a remote Hazelcast instance to cluster session data.
Because Hazelcast is not a technology provided by the Eclipse Foundation, you will be prompted to assent to the licenses of the external vendor (Apache in this case).
Hazelcast-specific jar files will be downloaded and saved to a directory named $JETTY_BASE/lib/hazelcast/.
NOTE: If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated $JETTY_BASE/lib/ directory and use the --skip-create-files=<module name> command line option to prevent errors when starting your server.
==== Configuration
The start.d/session-store-hazelcast-remote.ini contains a list of all the configurable options for the Hazelcast module:
jetty.session.hazelcast.mapName::
The default is "jetty-distributed-session-map".
This is the name of the Map in Hazelcast where sessions will be stored.
jetty.session.hazelcast.onlyClient::
Boolean, default true.
The Hazelcast instance will be configured in client mode.
jetty.session.hazelcast.configurationLocation::
Optional.
This is the path to an external Hazelcast xml configuration file.
jetty.session.hazelcast.useQueries::
Boolean, default false.
If true, Jetty will use Hazelcast queries to find sessions to <>.
If false sessions that are not currently in a <<cache,session cache>> cannot be <>, and will need to be removed by some external process.
jetty.session.hazelcast.addresses::
Optional.
These are the addresses of remote Hazelcast instances with which to communicate.
jetty.session.gracePeriod.seconds::
Integer, in seconds.
Default 3600.
Used during session <>.
Multiples of this period are used to define how long ago a stored session must have expired before it should be <>.
jetty.session.savePeriod.seconds::
Integer, in seconds, default is 0.
Whenever a session is accessed by a request, its lastAccessTime and expiry are updated.
Even if your sessions are read-mostly, the lastAccessTime and expiry will always change.
For heavily-used, read-mostly sessions you can save some time by skipping some writes for sessions for which only these fields have changed (ie no session attributes changed).
The value of this property is used to skip writes for these kinds of sessions: the session will only be written out if the time since the last write exceeds the value of this property.
[WARNING]
You should be careful in the use of this property in clustered environments: if you set too large a value for this property, the session may not be written out sufficiently often to update its `expiry` time thus making it appear to other nodes that it has expired. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - it would be undesirable to set a `savePeriod` that is larger than the `maxIdleTime`.
IMPORTANT: Be aware that if your session attributes contain classes from inside your web application (or Jetty classes) then you will need to put these classes onto the classpath of all of your Hazelcast instances.
[[hazelcast-embedded]]
=== Embedded Hazelcast Clustering
This will run an in-process instance of Hazelcast.
This can be useful for example during testing.
To enable this you enable the session-store-hazelcast-embedded module.
Because Hazelcast is not a technology provided by the Eclipse Foundation, you will be prompted to assent to the licenses of the external vendor (Apache in this case).
Hazelcast-specific jar files will be downloaded to a directory named $JETTY_BASE/lib/hazelcast/.
==== Configuration
The $JETTY_BASE/start.d/start.d/session-store-hazelcast-embedded.ini contains a list of all the configurable options for the Hazelcast module:
jetty.session.hazelcast.mapName::
The default is "jetty-distributed-session-map".
This is the name of the Map in Hazelcast where sessions will be stored.
jetty.session.hazelcast.hazelcastInstanceName
Default is "JETTY_DISTRIBUTED_SESSION_INSTANCE".
This is the unique name of the Hazelcast instance that will be created.
jetty.session.hazelcast.configurationLocation::
Optional.
This is the path to an external Hazelcast xml configuration file.
jetty.session.hazelcast.useQueries::
Boolean, default false'. If true, Jetty will use Hazelcast queries to find expired sessions to <>. If false` sessions that are not currently in a <<cache,session cache>> cannot be <>, and will need to be removed by some external process.
jetty.session.gracePeriod.seconds::
Integer, in seconds.
Default 3600.
Used during session <>.
Multiples of this period are used to define how long ago a stored session must have expired before it should be <>.
jetty.session.savePeriod.seconds::
Integer, in seconds, default is 0.
Whenever a session is accessed by a request, its lastAccessTime and expiry are updated.
Even if your sessions are read-mostly, the lastAccessTime and expiry will always change.
For heavily-used, read-mostly sessions you can save some time by skipping some writes for sessions for which only these fields have changed (ie no session attributes changed).
The value of this property is used to skip writes for these kinds of sessions: the session will only be written out if the time since the last write exceeds the value of this property.
[WARNING]
You should be careful in the use of this property in clustered environments: if you set too large a value for this property, the session may not be written out sufficiently often to update its `expiry` time thus making it appear to other nodes that it has expired. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - it would be undesirable to set a `savePeriod` that is larger than the `maxIdleTime`.
IMPORTANT: If your session attributes contain classes from inside your web application (or jetty classes) then you will need to put these classes onto the classpath of all of your Hazelcast instances. In the case of embedded Hazelcast, as it is started before your web application, it will NOT have access to your web application's classes - you will need to extract these classes and put them onto the jetty server's classpath.
[[gcloud]]
== Modules for Persistent HTTP Sessions: Google Cloud DataStore
Jetty can store http session information into GCloud by enabling the session-store-gcloud module.
=== Preparation
You will first need to create a project and enable the Google Cloud API: https://cloud.google.com/docs/authentication#preparation[].
Take note of the project id that you create in this step as you need to supply it in later steps.
=== Communicating with GCloudDataStore
==== When Running Jetty Outside of Google Infrastructure
Before running Jetty, you will need to choose one of the following methods to set up the local environment to enable remote GCloud DataStore communications.
- Using the GCloud SDK:
- Ensure you have the GCloud SDK installed: https://cloud.google.com/sdk/?hl=en[]
- Use the GCloud tool to set up the project you created in the preparation step:
gcloud config set project PROJECT_ID - Use the GCloud tool to authenticate a Google account associated with the project created in the preparation step:
gcloud auth login ACCOUNT
- Using environment variables
- Define the environment variable
GCLOUD_PROJECTwith the project id you created in the preparation step. - Generate a JSON https://cloud.google.com/storage/docs/authentication?hl=en#service_accounts[service account key] and then define the environment variable
GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/key.json
==== When Running Jetty Inside of Google Infrastructure
The Google deployment tools will automatically configure the project and authentication information for you.
=== Configuring Indexes for Session Data
Using some special, composite indexes can speed up session search operations, although it may make write operations slower.
By default, indexes will not be used.
In order to use them, you will need to manually upload a file that defines the indexes.
This file is named index.yaml and you can find it in your distribution in $JETTY_BASE/etc/sessions/gcloud/index.yaml.
Follow the instructions https://cloud.google.com/datastore/docs/tools/#the_development_workflow_using_gcloud[here] to upload the pre-generated index.yaml file.
=== Communicating with the GCloudDataStore Emulator
To enable communication using the GCloud Emulator:
- Ensure you have the GCloud SDK installed: https://cloud.google.com/sdk/?hl=en[]
- Follow the instructions https://cloud.google.com/datastore/docs/tools/datastore-emulator[here] on how to start the GCloud datastore emulator, and how to propagate the environment variables that it creates to the terminal in which you run Jetty.
=== Enabling the Google Cloud DataStore Module
The session-store-gcloud module provides GCloud support for storing session data.
Because the Google Cloud DataStore is not a technology provided by the Eclipse Foundation, when enabling the module you will be prompted to assent to the licenses of the external vendor.
As GCloud requires certain Java Commons Logging features to work correctly, Jetty routes these through SLF4J.
By default, Jetty implements the SLF4J api, but you can choose a different logging implementation by following the instructions xref:server/index.adoc#logging[here]
IMPORTANT: If you want to use updated versions of the jar files automatically downloaded during the module enablement, you can place them in the associated $JETTY_BASE/lib/ directory and use the --skip-create-files=<module name> command line option to prevent errors when starting your server.
== Configuration
The $JETTY_BASE/start.d/session-store-gcloud.ini file contains all of the configurable properties for the session-store-gcloud module:
jetty.session.gcloud.maxRetries::
Integer.
Default 5.
Maximum number of retries to connect to GCloud DataStore to write a session.
jetty.session.gcloud.backoffMs::
Integer in milliseconds.
Default 1000.
Number of milliseconds between successive attempts to connect to the GCloud DataStore to write a session.
jetty.session.gracePeriod.seconds::
Integer, in seconds.
Default 3600.
Used during session <>.
Multiples of this period are used to define how long ago a stored session must have expired before it should be <>.
jetty.session.savePeriod.seconds::
Integer, in seconds, default is 0.
Whenever a session is accessed by a request, its lastAccessTime and expiry are updated.
Even if your sessions are read-mostly, the lastAccessTime and expiry will always change.
For heavily-used, read-mostly sessions you can save some time by skipping some writes for sessions for which only these fields have changed (ie no session attributes changed).
The value of this property is used to skip writes for these kinds of sessions: the session will only be written out if the time since the last write exceeds the value of this property.
[WARNING]
You should be careful in the use of this property in clustered environments: if you set too large a value for this property, the session may not be written out sufficiently often to update its `expiry` time thus making it appear to other nodes that it has expired. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - it would be undesirable to set a `savePeriod` that is larger than the `maxIdleTime`.
jetty.session.gcloud.namespace::
Optional.
Sets the namespace for GCloud Datastore to use.
If set, partitions the visibility of session data between web applications, which is helpful for multi-tenant deployments.
More information can be found https://cloud.google.com/datastore/docs/concepts/multitenancy[here.]
Configuration of the stored session object and its fields names-::
You should very rarely, if ever, need to change these defaults.
jetty.session.gcloud.model.kind:::
The default is "GCloudSession".
This is the type of the object that is stored in GCloud.
jetty.session.gcloud.model.id:::
The default is "id".
This is the session id.
jetty.session.gcloud.model.contextPath:::
The default is "contextPath".
This is the canonicalized context path of the context to which the session belongs.
jetty.session.gcloud.model.vhost:::
The default is "vhost".
This is the canonicalized virtual host of the context to which the session belongs.
jetty.session.gcloud.model.accessed:::
The default is "accessed".
This is the current access time of the session.
jetty.session.gcloud.model.lastAccessed:::
The default is "lastAccessed".
This is the last access time of the session.
jetty.session.gcloud.model.createTime:::
The default is "createTime".
This is the time, in ms since the epoch, at which the session was created.
jetty.session.gcloud.model.cookieSetTime:::
The default is "cookieSetTime".
This is the time at which the session cookie was last set.
jetty.session.gcloud.model.lastNode:::
The default is "lastNode".
This is the workerName of the last node to manage the session.
jetty.session.gcloud.model.expiry:::
The default is "expiry".
This is the time, in ms since the epoch, at which the session will expire.
jetty.session.gcloud.model.maxInactive:::
The default is "maxInactive".
This is the session timeout in ms.
jetty.session.gcloud.model.attributes:::
The default is "attributes".
This is a map of all the session attributes.
[[memcached]]
== Modules for Persistent HTTP Sessions: The L2 Session Data Cache
If your chosen persistence technology is slow, it can be helpful to locally cache the session data.
The CachingSessionDataStore is a special type of SessionDataStore that locally caches session data, which makes reads faster. It writes-through to your chosen type of SessionDataStore when session data changes.
=== MemcachedSessionDataMap
The MemcachedSessionDataMap uses memcached to perform caching of SessionData.
To enable it with the Jetty distribution, enable the session-store-cache module, along with your chosen session-store-xxxx module.
==== Configuration
The $JETTY_BASE/start.d/session-store-cache.ini contains the following configurable properties:
jetty.session.memcached.host::
Default value is localhost.
This is the host on which the memcached server resides.
jetty.session.memcached.port::
Default value is 11211.
This is the port on which the memcached server is listening.
jetty.session.memcached.expirySec::
Default value 0.
This is the length of time in seconds that an item can remain in the memcached cache, where 0 indicates indefinitely.
jetty.session.memcached.heartbeats::
Default value true.
Whether the memcached system should generate heartbeats.
[[usecases]]
== Session Scenarios
=== Minimizing Support for Sessions
The standard support for web applications in Jetty will use sessions cached in memory, but not persisted/clustered, with a scavenge for expired sessions that occurs every 10 minutes.
If you wish to pare back support for sessions because you know your app doesn't use them (or use JSPs that use them), then you can do the following:
- enable the <> and <> to 0 to prevent scavenging
- enable the <<cache-null,null session cache module>> to prevent sessions being cached in memory
If you wish to do any further minimization, you should consult the xref:programming-guide:server/session.adoc[Programming Guide].
=== Clustering with a Sticky Load Balancer
Preferably, your cluster will utilize a sticky load balancer.
This will route requests for the same session to the same Jetty instance.
In this case, the <<cache-hash,DefaultSessionCache>> can be used to keep in-use session objects <<cache-hash,in memory>>.
You can fine-tune the cache by controlling how long session objects remain in memory with the <<cache-hash,eviction policy settings>>.
If you have a large number of sessions or very large session objects, then you may want to manage your memory allocation by controlling the amount of time session objects spend in the cache.
The EVICT_ON_SESSION_EXIT eviction policy will remove a session object from the cache as soon as the last simultaneous request referencing it exits.
Alternatively, the EVICT_ON_INACTIVITY policy will remove a session object from the cache after a configurable amount of time has passed without a request referencing it.
If your sessions are very long lived and infrequently referenced, you might use the EVICT_ON_INACTIVITY_POLICY to control the size of the cache.
If your sessions are small, or relatively few or stable in number or they are read-mostly, then you might select the NEVER_EVICT policy.
With this policy, session objects will remain in the cache until they either expire or are explicitly invalidated.
If you have a high likelihood of simultaneous requests for the same session object, then the EVICT_ON_SESSION_EXIT policy will ensure the session object stays in the cache as long as it is needed.
=== Clustering Without a Sticky Load Balancer
Without a sticky load balancer requests for the same session may arrive on any node in the cluster.
This means it is likely that the copy of the session object in any SessionCache is likely to be out-of-date, as the session was probably last accessed on a different node.
In this case, your choices are to use either the <<cache-null,NullSessionCache>> or to de-tune the <<cache-hash,DefaultSessionCache>>.
If you use the NullSessionCache all session object caching is avoided.
This means that every time a request references a session it must be read in from persistent storage.
It also means that there can be no sharing of session objects for multiple requests for the same session: each will have their own independent session object.
Furthermore, the outcome of session writes are indeterminate because the Servlet Specification does not mandate ACID transactions for sessions.
If you use the DefaultSessionCache, there is a risk that the caches on some nodes will contain out-of-date session information as simultaneous requests for the same session are scattered over the cluster.
To mitigate this somewhat you can use the EVICT_ON_SESSION_EXIT eviction policy: this will ensure that the session is removed from the cache as soon as the last simultaneous request for it exits.
Again, due to the lack of session transactionality, the ordering outcome of write operations cannot be guaranteed.
As the session is cached while at least one request is accessing it, it is possible for multiple simultaneous requests to share the same session object.
=== Handling Corrupted or Unreadable Session Data
For various reasons it might not be possible for the SessionDataStore to re-read a stored session.
One scenario is that the session stores a serialized object in its attributes, and after a re-deployment there in an incompatible class change.
Setting the $JETTY_BASE/start.d/session-cache-hash.ini or $JETTY_BASE/start.d/session-cache-null.ini property jetty.session.removeUnloadableSessions to true will allow the unreadable session to be removed from persistent storage.
This can be useful for preventing the <> from continually generating errors on the same expired, but un-readable session.
Documentation Jetty Modules Operations Guide Pages Start Index (`documentation/jetty/modules/operations-guide/pages/start/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jetty Start Mechanism
NOTE: Make sure you have read the xref:arch/index.adoc[Jetty architecture section] if you are not familiar with the terms used in this section.
The Jetty start mechanism is invoked by executing $JETTY_HOME/start.jar, from within a $JETTY_BASE directory, with zero or more command line options:
[source,bash]
$ cd $JETTY_BASE $ java -jar $JETTY_HOME/start.jar ...
The Jetty start mechanism has two main modes of operation:
- The tool mode, detailed in <<configure,this section>>, when it is used as a command line tool to configure the
$JETTY_BASEdirectory by enabling modules, creating sub-directories and files, downloading files, etc.
In this mode, the JVM started withjava -jar $JETTY_HOME/start.jarperforms the specified command and then exits. - The start mode, detailed in <<start,this section>>, when it is used to start the JVM that runs Jetty with the specified configuration.
In this mode, the JVM started withjava -jar $JETTY_HOME/start.jarstarts Jetty and does not exit until stopped, for example by hitting kbd:[Ctrl+C] on the terminal.
Refer to the <<reference,Jetty start mechanism reference section>> for the complete list of the available command line options.
You want to use the Jetty start mechanism to <<configure,configure your $JETTY_BASE>> and then to <<start,start Jetty>>.
[[configure]]
== Configuring $JETTY_BASE
Within the Jetty start mechanism, the source of configurations is layered in this order, from higher priority to lower priority:
- The command line options.
- The
$JETTY_BASEdirectory, and its files. - The directory specified with the
--add-config-diroption, and its files. - The
$JETTY_HOMEdirectory, and its files.
[[configure-enable]]
=== Enabling Modules
You can enable Jetty modules persistently across restarts with the --add-modules command:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --add-modules=https,http2
The Jetty start mechanism will look for the specified modules following the order specified above.
In the common case (without a --add-config-dir directory), it will look in $JETTY_BASE/modules/ first and then in $JETTY_HOME/modules/.
Since the https and http2 modules are standard Jetty modules, they are present in $JETTY_HOME/modules/ and loaded from there.
When you enable a Jetty module, the Jetty start mechanism:
- Creates the correspondent
+$JETTY_BASE/start.d/*.ini+module configuration file.
The content of these+*.ini+files is copied from the[ini-template]section of the correspondent+*.mod+file. - Executes the directives specified in
[files]section (if present) of the+*.mod+file.
This may simply create a file or a directory, or download files from the Internet.
Both steps are performed transitively for all module dependencies.
For example, enabling the http module results in the $JETTY_BASE directory to have the following structure:
$JETTY_BASE
├── resources
│ └── jetty-logging.properties
└── start.d
├── bytebufferpool.ini
├── http-config.ini
├── http.ini
├── scheduler.ini
├── server.ini
└── threadpool.ini
The $JETTY_BASE/resources/jetty-logging.properties is created by the [files] directives of the logging-jetty module, which is a transitive dependency of the server module.
[[configure-disable]]
=== Disabling Modules
A module is enabled because the correspondent +$JETTY_BASE/start.d/*.ini+ file contains a --module=<name> directive.
Commenting out the --module=<name> directive effectively disables the module.
Deleting the correspondent +$JETTY_BASE/start.d/*.ini+ file also disables the module.
[[configure-edit-ini]]
=== Editing +*.ini+ Files
You can now edit the +$JETTY_BASE/start.d/*.ini+ configuration files, typically by uncommenting properties to change their default value.
You want to edit the +$JETTY_BASE/start.d/*.ini+ configuration files so that the configuration is applied every time Jetty is started (or re-started).
For example, $JETTY_BASE/start.d/http.ini contains the following property, commented out:
.http.ini
jetty.http.port=8080
You can change the clear-text HTTP port Jetty listens to by uncommenting that property and changing its value:
.http.ini
jetty.http.port=9876
When Jetty is started (or re-started) this configuration is applied and Jetty will listen for clear-text HTTP/1.1 on port 9876.
[[configure-module-command-line]]
=== Enabling Modules on Command Line
You can also enable a module transiently, only for the current execution of the java -jar $JETTY_HOME/start.jar command.
If you have an empty $JETTY_BASE, the following command enables the http module, but does not create any +$JETTY_BASE/start.d/*.ini+ files.
[source,bash]
$ java -jar $JETTY_HOME/start.jar --module=http
Since there are no +$JETTY_BASE/start.d/*.ini+ files, you can only customize the properties via the command line, for example:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --module=http jetty.http.port=9876
Enabling modules on the command line is useful to verify that the modules work as expected, or to try different configurations.
NOTE: It is possible to enable some module persistently via --add-modules and some other module transiently via --module.
Remember that once the current execution terminates, the modules enabled transiently on the command line via --module and their configuration are not saved and will not be enabled on the next execution (unless you specify them again on the command line).
[[configure-properties-command-line]]
=== Specifying Properties on Command Line
You can also specify module properties transiently, only for the current execution of the java -jar $JETTY_HOME/start.jar command.
Properties specified on the command line override the same properties specified in +*.ini+ files.
For example, you can enable the server module in $JETTY_BASE and the http module on the command line, and specify properties for both on the command line:
[source,bash]
Enable the server module in $JETTY_BASE.
$ java -jar $JETTY_HOME/start.jar --add-modules=server
Start Jetty enabling the http module on the command line,
and specifying properties for both modules.
$ java -jar $JETTY_HOME/start.jar --module=http jetty.server.dumpAfterStart=true jetty.http.port=9876
[[configure-custom-module]]
=== Adding Your Own Modules
NOTE: Refer to the xref:modules/custom.adoc[custom module section] for the details about how to create your own modules.
You can add your own modules by adding a +$JETTY_BASE/modules/*.mod+ file.
For example, you may want to add a Postgres JDBC driver to the server class-path, to avoid that each deployed web application bring its own version. This allows you to control the exact Postgres JDBC driver version for all web applications.
Create the $JETTY_BASE/modules/postgresql.mod file:
.postgresql.mod
include::code:example$jetty-modules/postgresql.mod[]
Then enable it:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --add-modules=postgresql
Enabling the postgresql module will execute the [files] directive (downloading the +*.jar+ file from Maven Central if not already present) and create the $JETTY_BASE/start.d/postgresql.ini with the content of the [ini-template] section.
The [lib] section ensures that the specified file is in the server class-path when Jetty is started.
You can <<configure-display,display the Jetty configuration>> to verify that the server class-path is correct.
[[configure-custom-module-exec]]
=== Custom Module with JVM Options
Using a custom Jetty module, you can customize the JVM startup options.
This is useful if you need to start Jetty and want to specify JVM options such as:
+-Xmx+, to specify the max heap size+-Xlog:gc+, to specify the GC log file and options+-javaagent+, to specify Java agents+-XX:+options, for example to specify the GC implementation+--enable-preview+, to enable Java preview features
Start by creating $JETTY_BASE/modules/jvm.mod:
.jvm.mod
include::code:example$jetty-modules/jvm.mod[]
Enable it:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --add-modules=jvm
Since the module defines an [exec] section, it will fork another JVM when Jetty is started.
This means that when you start Jetty, there will be two JVMs running: one created by you when you run java -jar $JETTY_HOME/start.jar, and another forked by the Jetty start mechanism with the JVM options you specified (that cannot be applied to an already running JVM).
Again, you can <<configure-dry-run,display the JVM command line>> to verify that it is correct.
[TIP]
The second JVM forked by the Jetty start mechanism when one of the modules requires forking, for example a module that contains an `[exec]` section, may not be desirable, and may be avoided as explained in <>.
[[configure-display]]
=== Displaying the Configuration
Once you have enabled and configured the $JETTY_BASE, you can display the configuration to verify that it is correct.
Using the standard server and http Jetty modules, and the postgresql and jvm custom Jetty module defined above, you obtain:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --list-config
[jetty%nowrap]
....
[jetty]
setupModules=code:example$jetty-modules/jvm.mod,code:example$jetty-modules/postgresql.mod
setupArgs=--add-modules=server,http,postgresql,jvm
args=--list-config
....
Note how the configuration displayed above includes:
- In the list of enabled modules, the
postgresqlandjvmmodules - In the list of JVM arguments, those specified by the
jvmmodule - In the server class-path, the
+*.jar+file specified by thepostgresqlmodule
[[configure-dry-run]]
=== Displaying the JVM Command Line
The Jetty start mechanism can display a full JVM command line that will start Jetty with the configuration you specified, with the --dry-run option:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --dry-run
The full JVM command line generated by --dry-run can be split in various parts that can be used individually, for example in scripts.
Furthermore, Jetty modules may specify the --exec option that will fork a second JVM to start Jetty, which may not be desirable.
Some option, such as --jpms, imply --exec, as it won't be possible to modify the module-path in the already started JVM.
To start Jetty without forking a second JVM, the --dry-run option can be used to generate a command line that is then executed so that starting Jetty only spawns one JVM.
IMPORTANT: You can use the --dry-run option as explained below to avoid forking a second JVM when using modules that have the [exec] section, or the --exec option, or when using the --jpms option.
For example, using the --dry-run option with the jvm.mod introduced in <<configure-custom-module-exec,this section>> produces the following command line:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --dry-run
[jetty%nowrap]
....
[jetty]
setupModules=code:example$jetty-modules/jvm.mod
setupArgs=--add-modules=http,jvm
args=--dry-run
replace=( ),$1\\n
....
You can then run the generated command line by copying the output generated using the --dry-run option, and pasting it in a terminal window.
The --dry-run option is quite flexible and below you can find a few examples of how to use it to avoid forking a second JVM, or generating scripts or creating an arguments file that can be passed to (a possibly alternative) java executable.
To display the java executable used to start Jetty:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar --dry-run=##java##
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http
args=--dry-run=java
....
To display the JVM options:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar --dry-run=##opts##
[jetty%nowrap]
....
[jetty]
setupModules=code:example$jetty-modules/jvm.mod
setupArgs=--add-modules=http,jvm
args=--dry-run=opts
replace=( ),$1\\n
....
To display the JVM class-path:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar --dry-run=##path##
[jetty%nowrap]
....
[jetty]
setupModules=code:example$jetty-modules/postgresql.mod
setupArgs=--add-modules=http,jvm
args=--dry-run=path
replace=( |:),$1\\n
....
To display the JVM class-path and module-path, if you want to xref:start/start-jpms.adoc[start Jetty using JPMS] with the --jpms option:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar ##--jpms## --dry-run=##path##
[jetty%nowrap]
....
[jetty]
setupModules=code:example$jetty-modules/postgresql.mod
setupArgs=--add-modules=http,jvm
args=--jpms --dry-run=path
replace=( |:),$1\\n
....
To display the JVM main class:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar --dry-run=##main##
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http
args=--dry-run=main
....
To display the JVM main class when xref:start/start-jpms.adoc[starting Jetty using JPMS]:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar --jpms --dry-run=##main##
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http
args=--jpms --dry-run=main
....
The main class is typically Jetty's XmlConfiguration class that accepts, as program arguments, a list of properties and a list of Jetty XML files to process.
The Jetty XML files compose together the Jetty components that are then configured with the values from the command line properties.
To display the program arguments passed to the main class:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar --dry-run=##args##
[jetty%nowrap]
....
[jetty]
setupModules=code:example$jetty-modules/postgresql.mod
setupArgs=--add-modules=http
args=--dry-run=args
replace=( ),$1\\n
....
Note how the program arguments are a list of properties in the form <name>=<value> and a list of Jetty XML files.
To display the xref:deploy/index.adoc[environments] configuration:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar --dry-run=##envs##
[jetty%nowrap]
....
[jetty]
setupModules=code:example$jetty-modules/postgresql.mod
setupArgs=--add-modules=http,ee10-deploy
args=--dry-run=args
replace=( ),$1\\n
....
Note how the environments configuration specifies additional class-path and Jetty XML files for every environment.
The various parts of the full JVM command line can be combined to leverage the JVM arguments file feature (that is, specify the JVM options in a file rather than on the command line) that is built-in in the java executable:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar --dry-run=##opts,path,main,args,envs## > /tmp/jvm_cmd_line.txt $ /some/other/java @/tmp/jvm_cmd_line.txt
Using --dry-run=opts,path,main,args,envs can be used to avoid that the Jetty start mechanism forks a second JVM when using modules that require forking.
In the Linux bash shell you can run the output of --dry-run in this way:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --dry-run=opts,path,main,args,envs | xargs java
The output of different --dry-run executions can be creatively combined in a script, for example in the Linux bash shell:
[source,bash,subs=+quotes]
$ OPTS=$(java -jar start.jar --dry-run=##opts,path##) $ MAIN=$(java -jar start.jar --dry-run=##main##) $ ARGS=$(java -jar start.jar --dry-run=##args##) $ ENVS=$(java -jar start.jar --dry-run=##envs##) $ echo $OPTS -Dextra=opt $MAIN $ARGS $ENVS extraProp=value extra.xml | xargs java
[[start]]
== Starting Jetty
After you have configured the $JETTY_BASE directory, as explained in <<configure,this section>>, you can start Jetty as a standalone server.
In the start mode, the Jetty start mechanism computes a JVM command line with JVM options, system properties, class-path, module-path, main class and program arguments, and then executes it, forking a new JVM if necessary.
The Jetty start mechanism performs these steps:
. Loads all the Jetty modules files (that have extension +*.mod+) from the modules/ subdirectory of each configuration source directory (see <<configure,this section>> for the list of configuration sources).
In this way, a Jetty module graph can be built in memory, where the module dependencies form the edges of the graph and each node contains the metadata information declared by each module (for example, the libraries that it needs, the XML files to process, and so on), in preparation for the next step.
. Reads the Jetty module configuration files (that have extension +*.ini+) from the start.d/ subdirectory of each configuration source directory and from the command line.
This step produces a list of enabled modules; for each enabled module all its dependencies are transitively resolved by navigating the graph built in the previous steps.
. Processes the list of enabled (explicitly and transitively) modules, gathering the list of libraries to add to the class-path or module-path, the JPMS directives to add to the command line if necessary, the properties and XML files to add as program arguments, etc., so that a full JVM command line can be generated.
. Executes the command line, either in-JVM or by forking a second JVM (if the --exec option is present or implied by other options such as --jpms), and waits for the JVM, or the forked JVM, to exit.
[[start-class-path]]
=== Server Class-Path
When the Jetty server is started in-JVM, the server class-path gathered by processing the enabled modules is organized in a URLClassLoader, the Jetty Start ClassLoader, that is a child of the System ClassLoader:
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle "Jetty Start JVM" {
rectangle "System ClassLoader" as system
rectangle "Jetty Start ClassLoader" as start
note right of system: start.jar
note right of start: jetty-server.jar\njetty-http.jar\njetty-io.jar\njetty-util.jar\njetty-xml.jar\netc.
system <.. start }
The System ClassLoader only has $JETTY_HOME/start.jar in its class-path, since the JVM was started with java -jar $JETTY_HOME/start.jar.
The Jetty Start ClassLoader has in its class-path the +*.jar+ files gathered by processing the enabled modules, typically from +$JETTY_HOME/lib/jetty-*.jar+, but possibly also from +$JETTY_BASE/lib/*.jar+ if custom modules extend the server class-path with their own +*.jar+ files.
When the Jetty server is started in a forked JVM, there will be two JVMs: one started by you with java -jar $JETTY_HOME/start.jar and one forked by the Jetty start mechanism.
In the forked JVM, the System ClassLoader has the server class-path and/or module-path in its class-path, since the forked JVM is started with +java --class-path $JETTY_HOME/lib/jetty-server-<version>.jar:...+:
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle "Jetty Start JVM" as startJVM {
rectangle "System ClassLoader" as system1
note right of system1: start.jar
}
rectangle "Forked JVM" as forkedJVM {
rectangle "System ClassLoader" as system2
note right of system2: jetty-server.jar\njetty-http.jar\njetty-io.jar\njetty-util.jar\njetty-xml.jar\netc.
}
startJVM --> forkedJVM: " waits for"
It is worth mentioning that there are two standard Jetty modules that allow you to easily add entries to the Jetty server class-path:
- The xref:modules/standard.adoc#resources[
resourcesmodule], which adds the$JETTY_BASE/resourcesdirectory to the server class-path.
This is useful if you have third party libraries that lookup resources from the class-path: just put those resources in the$JETTY_BASE/resources/directory. +
Logging libraries often perform class-path lookup of their configuration files (for example,log4j.properties,log4j.xml,logging.properties, andlogback.xml), so$JETTY_BASE/resources/is the ideal place to add those files. + - The
extmodule, that adds all the+*.jar+files under the$JETTY_BASE/lib/ext/directory, and subdirectories recursively, to the server class-path. +
[CAUTION]
On one hand, the ext module provides a handy place to put third party libraries and their dependencies; on the other hand, the $JETTY_BASE/lib/ext/ directory may become a confused mixture of many +*.jar+ files from different third party libraries.
Prefer to group third party libraries and their dependencies into their own directories using xref:modules/custom.adoc[custom modules], or at least group them into `$JETTY_BASE/lib/ext/` subdirectories such as `$JETTY_BASE/lib/ext/util/` or `$JETTY_BASE/lib/ext/acme/`.
[[start-class-path-environments]]
==== Server Jakarta EE Environment Class-Path
When a Jakarta EE Jetty module is enabled, for example the {ee-current}-webapp and/or the {ee-current}-deploy module, the server ClassLoader hierarchy is modified as follows:
[plantuml,subs=+attributes]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle "Jetty Start JVM" {
rectangle "System ClassLoader" as system
rectangle "Jetty Start ClassLoader" as start
rectangle "Jetty {ee-current-caps} ClassLoader" as env
note right of system: start.jar
note right of start: jetty-server.jar\njetty-http.jar\njetty-io.jar\njetty-util.jar\njetty-xml.jar\netc.
note right of env: jakarta.servlet-api.jar\njetty-{ee-current}-servlet.jar\njetty-{ee-current}-deploy.jar\netc.
system <.. start start <.. env }
When different versions of the Jakarta EE ee<N>-deploy or ee<N>-webapp modules are enabled, the server ClassLoader hierarchy is the following:
[plantuml,subs=+attributes]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle "Jetty Start JVM" {
rectangle "System ClassLoader" as system
rectangle "Jetty Start ClassLoader" as start
rectangle "Jetty {ee-prev-caps} ClassLoader" as env1
rectangle "Jetty {ee-current-caps} ClassLoader" as env2
note right of system: start.jar
note right of start: jetty-server.jar\njetty-http.jar\njetty-io.jar\njetty-util.jar\njetty-xml.jar\netc.
note left of env1: jakarta.servlet-api.jar ({ee-prev})\njetty-{ee-prev}-servlet.jar\njetty-{ee-prev}-deploy.jar\netc.
note right of env2: jakarta.servlet-api.jar ({ee-current})\njetty-{ee-current}-servlet.jar\njetty-{ee-current}-deploy.jar\netc.
system <.. start start <.. env1 start <.. env2 }
Note how the Jetty {ee-prev-caps} ClassLoader and the Jetty {ee-current-caps} ClassLoader are siblings.
In this way, they can load independently their own version of the Jakarta EE APIs +*.jar+ files, and the Jetty implementation of the Jakarta EE APIs, without conflicts.
[[start-xml]]
=== Assembling Jetty Components
The Jetty start mechanism eventually invokes, by default, main class org.eclipse.jetty.xml.XmlConfiguration, passing properties and xref:xml/index.adoc[Jetty XML files] as program arguments.
The Jetty XML files are nothing more than Java code in XML format.
The XML files are processed to instantiate Jetty components such as org.eclipse.jetty.server.Server or org.eclipse.jetty.util.ssl.SslContextFactory$Server.
The components are then assembled together to provide the configured Jetty features.
The Jetty XML files are parametrized using properties, and a property is just a name/value pair.
This parametrization of the XML files allows an XML file that resides in $JETTY_HOME/etc/ to declare a property such as jetty.http.port, and allow this property to be set in a $JETTY_BASE/start.d/http.ini file, so that you don't need to change the XML files in $JETTY_HOME, but only change +*.ini+ files in your $JETTY_BASE.
You can write your own xref:modules/custom.adoc[custom modules] with your own Jetty XML files, and your own properties, to further customize Jetty.
[[stop]]
== Stopping Jetty
When Jetty is started, the Jetty components that you have configured by enabling Jetty modules are assembled and started.
If you have started Jetty from a terminal, you can exit the Jetty JVM by hitting kbd:[Ctrl+C] on the same terminal.
Similarly, from a different terminal, you can exit the Jetty JVM using kill -INT or kill -TERM .
In the three cases above, the JVM is exited, but by default Jetty components are not stopped.
If you want to stop the Jetty components, to stop Jetty more gracefully, you can start Jetty with this property:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar ##jetty.server.stopAtShutdown=true##
This property can also be set in $JETTY_BASE/start.d/server.ini so that it is persistently configured across Jetty restarts (see also xref:modules/standard.adoc#server[the server module]).
The jetty.server.stopAtShutdown property configures a JVM shutdown hook that is run, stopping the Server instance, when the JVM exits.
Obviously, the JVM can also be stopped with kill -KILL that exits the process abruptly without running the JVM shutdown hooks.
[[stop-graceful]]
=== Stopping Gracefully
Stopping Jetty abruptly when there are active HTTP requests being handled may result in a variety or errors, because Jetty components that are used to handle requests are being stopped concurrently.
For example, when the Jetty thread pool is stopped, an attempt to submit a task would throw RejectedExecutionException; when a component is stopped, its fields may be nulled-out, resulting in a NullPointerException being thrown if the component is used; etc.
You can stop Jetty gracefully by adding the graceful Jetty module (see xref:modules/standard.adoc#graceful[this section] for more information).
When Jetty is stopped, the graceful module organizes to reject new requests, but allows existing requests to finish within a configurable timeout; then closes all the connections, stops all the Jetty components, and then exits the JVM.
In this way, existing requests are not responded with an error caused by the server stopping, provided they complete within the timeout.
[[stop-remote]]
=== Stopping Jetty from Remote
You can configure a Jetty server so that it can be stopped by remote clients using a command sent through a TCP socket.
You can start Jetty with the following properties:
stop.host, the host name Jetty will bind to listen for stop commands. Defaults to127.0.0.1which means that the stop command can be issued only clients that run on the same host as Jetty.stop.port, the port number Jetty will listen to for stop commands. Defaults to-1, which means that Jetty will not listen to any port.stop.key, the password to verify when a stop command is received. Defaults to a password that is randomly generated and printed when Jetty starts.
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar ##stop.port=8181##
[jetty%nowrap]
....
[jetty]
setupArgs=--add-modules=http
args=stop.port=8181
highlight=(?i)stop.key
....
In the example above, Jetty is started with just the stop.port property, and the stop.key is printed on the terminal when Jetty starts.
CAUTION: You can choose your own stop.key, but make sure it's a strong password.
A remote client can now use the Jetty start mechanism to stop the remote Jetty server:
[source,bash,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar ##--stop## stop.port=8181 stop.key=
Note the --stop command along with the stop.port and stop.key properties.
The stop.key must be the same as the one of remote Jetty server, either the one you chose, or the one printed on the terminal when Jetty starts.
Remote clients can wait for the remote Jetty server to shut down by specifying the stop.wait property with the number of seconds to wait:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --stop stop.port=8181 stop.key= stop.wait=15
If the time specified elapses, without the confirmation that the remote Jetty server stopped, then the --stop command exits with a non-zero return code.
== Start Mechanism Logging
The steps performed by the Jetty start mechanism are logged by the StartLog class, that outputs directly, by default, to System.err.
This is necessary to avoid that the Jetty start mechanism depend on logging libraries that may clash with those defined by Jetty logging modules, when Jetty is started in-VM.
[NOTE]
This section is about the logging performed by the Jetty start mechanism _before_ it configures and starts Jetty. See the xref:server/index.adoc#logging[logging section] for information about logging when Jetty starts.
You can enable DEBUG level logging with the --debug command line option, for both the tool and start modes:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --debug ...
You can send the start log output to a file, by default relative to $JETTY_BASE, with the --start-log-file=<file> option:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --debug --start-log-file=start.log ...
This is useful for capturing startup issues where the Jetty-specific logger has not yet kicked in due to a possible startup configuration error.
[[reference]]
== Usage Reference
[jetty]
....
[jetty]
args=--help
....
Documentation Jetty Modules Operations Guide Pages Start Start Jpms (`documentation/jetty/modules/operations-guide/pages/start/start-jpms.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Starting Jetty using JPMS
Jetty modules are proper https://en.wikipedia.org/wiki/Java_Platform_Module_System[JPMS] modules: each Jetty module has a module-info.class file.
This makes possible to run Jetty from the module-path, rather than the class-path.
To start Jetty on the module-path rather than the class-path, it is enough to add the --jpms option to the command line, for example:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --jpms
[NOTE]
The --jpms option implies the --exec option.
When running on the module-path using the --jpms option, the Jetty start mechanism will fork a second JVM passing it the right JVM options to run on the module-path.
Therefore, you will have two JVMs running: one that runs start.jar and one that runs Jetty on the module-path.
Forking a second JVM may be avoided as explained in xref:start/index.adoc#configure-dry-run[this section].
When Jetty is started in JPMS mode, all JPMS modules in the module-path are added to the set of JPMS root modules through the JVM option --add-modules=ALL-MODULE-PATH.
For a +*.jar+ file that is not a JPMS module, but is on the module-path, the JVM will assume internally it is an automatic JPMS module, with a JPMS module name derived from the +*.jar+ file name.
As an alternative to adding the --jpms option to the command line, you can use a custom Jetty module to centralize your JPMS configuration, where you can specify additional JPMS directives.
Create the $JETTY_BASE/modules/jpms.mod file:
.jpms.mod
include::code:example$jetty-modules/jpms.mod[]
The [ini] section with --jpms is equivalent to passing the --jpms option to the command line (see also xref:modules/index.adoc#directive-ini[this section]).
The [jpms] section allows you to specify additional JPMS configuration, for example additional --add-modules options, or --add-opens options, etc. (see also xref:modules/index.adoc#directive-jpms[this section]).
Then enable it:
[source,bash]
$ java -jar $JETTY_HOME/start.jar --add-modules=jpms
Now you can start Jetty without extra command line options, and it will start in JPMS mode because you have enabled the jpms module.
[[advantages]]
== Advantages of JPMS
The main advantage of running Jetty in JPMS mode is that it provides early error reporting if a dependency is missing, especially in case of custom Jetty modules.
If a Jetty module requires a specific library +*.jar+ file, and the +*.jar+ file is missing, this will be detected early when running in JPMS mode, since the +*.jar+ file would be a JPMS module, and the JPMS module graph resolution would detect this problem as the JVM starts up.
When running in class-path mode, this problem can only be detected when the library classes are loaded, therefore much later at run-time, when an HTTP request arrives and its processing requires to load the library classes.
Similarly, duplicate +*.jar+ files, of possibly different versions, are not allowed by JPMS.
This is again detected early, at JVM startup, when running in JPMS mode, rather than passing completely unnoticed when running in class-path mode, where classes may be loaded from either of those +*.jar+ files, possibly from the wrong version.
Another advantage of running Jetty in JPMS mode is that JPMS provides strong encapsulation.
This means that it is not possible to use reflection to access non-exported classes in JPMS modules within the ModuleLayer hierarchy.
This is enforced at the JVM level, not at the application level through, for example, a custom ClassLoader that performs class loading filtering.
It also means that it is not possible to use reflection to access sibling ModuleLayers.
For example a Jakarta {ee-prev-caps} web application would not be able to use reflection to access a sibling Jakarta {ee-current-caps} web application.
[[hierarchy]]
== Server Module-Path and ModuleLayers
When the Jetty server is started in JPMS mode, there will be two JVMs: one started by you with java -jar $JETTY_HOME/start.jar and one forked by the Jetty start mechanism.
NOTE: Remember that you can avoid to fork a second JVM, as described in xref:start/index.adoc#configure-dry-run[this section].
The forked JVM is started with +java --module-path $JETTY_HOME/lib/jetty-server-<version>.jar:...+, and therefore has the server libraries in its module-path, loaded by the System ClassLoader, in the boot ModuleLayer:
[plantuml]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle "Jetty Start JVM" as startJVM {
rectangle "System ClassLoader" as system1
note right of system1: start.jar
}
rectangle "Forked JVM" as forkedJVM {
rectangle "Boot ModuleLayer" as bootLayer {
rectangle "System ClassLoader" as system2
note right of system2: jetty-server.jar\njetty-http.jar\njetty-io.jar\njetty-util.jar\njetty-xml.jar\netc. }
}
startJVM --> forkedJVM: " waits for"
When a Jakarta EE Jetty module is enabled, for example the {ee-current}-webapp and/or the {ee-current}-deploy module, the forked JVM is configured as follows:
[plantuml,subs=+attributes]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle "Forked JVM" as forkedJVM {
rectangle "Boot ModuleLayer" as bootLayer {
rectangle "System ClassLoader" as systemCL
note right of systemCL: jetty-server.jar\njetty-http.jar\njetty-io.jar\njetty-util.jar\njetty-xml.jar\netc. }
rectangle "Jetty {ee-current-caps} ModuleLayer" as envLayer {
rectangle "Jetty {ee-current-caps} ClassLoader" as envCL
note right of envCL: jakarta.servlet-api.jar\njetty-{ee-current}-servlet.jar\njetty-{ee-current}-deploy.jar\netc. }
}
bootLayer <-- envLayer systemCL <.. envCL
Note how the parent of the Jetty {ee-current-caps} ClassLoader is the System ClassLoader, and how the parent of the Jetty {ee-current-caps} ModuleLayer is the Boot ModuleLayer.
When different versions of the Jakarta EE Jetty modules are enabled, the forked JVM is configured as follows:
[plantuml,subs=+attributes]
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam roundCorner 10
rectangle "Forked JVM" as forkedJVM {
rectangle "Boot ModuleLayer" as bootLayer {
rectangle "System ClassLoader" as systemCL
note right of systemCL: jetty-server.jar\njetty-http.jar\njetty-io.jar\njetty-util.jar\njetty-xml.jar\netc. }
rectangle "Jetty {ee-prev-caps} ModuleLayer" as envLayer1 {
rectangle "Jetty {ee-prev-caps} ClassLoader" as envCL1
note left of envCL1: jakarta.servlet-api.jar ({ee-prev})\njetty-{ee-prev}-servlet.jar\njetty-{ee-prev}-deploy.jar\netc. }
rectangle "Jetty {ee-current-caps} ModuleLayer" as envLayer2 {
rectangle "Jetty {ee-current-caps} ClassLoader" as envCL2
note right of envCL2: jakarta.servlet-api.jar ({ee-current})\njetty-{ee-current}-servlet.jar\njetty-{ee-current}-deploy.jar\netc. }
}
bootLayer <-- envLayer1 bootLayer <-- envLayer2 systemCL <.. envCL1 systemCL <.. envCL2
Note how the Jetty EE ClassLoaderss are siblings, and both have the System ClassLoader as parent.
Note also how the Jetty EE ModuleLayers are siblings, and both have the Boot ModuleLayer as parent.
[[advanced]]
== Advanced JPMS Configuration
Web applications may need additional services from the Servlet Container, such as JDBC DataSource references or JTA UserTransaction references.
For example, for JDBC it is typical to store, in JNDI, a reference to the connection pool's DataSource or directly a reference to the JDBC driver's DataSource (for example, org.postgresql.ds.PGConnectionPoolDataSource).
Jetty needs to be able to instantiate those classes and therefore needs to be able to load those classes and all their super-classes, among which includes javax.sql.DataSource.
When Jetty runs on the class-path, this is easily achieved by using a xref:modules/custom.adoc[custom module] as explained in xref:start/index.adoc#configure-custom-module[this section].
However, when running on the module-path, things are quite different.
When Jetty tries to load, for example, class org.postgresql.ds.PGConnectionPoolDataSource, it must be in a JPMS module that is resolved in the run-time module graph.
Furthermore, any dependency, for example classes from the java.sql JPMS module, must also be in a module present in the resolved module graph.
Thanks to the fact that when Jetty starts in JPMS mode the --add-modules=ALL-MODULE-PATH option is added to the JVM command line, every +*.jar+ file in the module-path is also present in the module graph.
There are now two cases for the postgresql-<version>.jar file: either it is a proper JPMS module, or it is an automatic JPMS module (either an explicit automatic JPMS module with the Automatic-Module-Name attribute in the manifest, or an implicit automatic JPMS module whose name is derived from the +*.jar+ file name).
If the postgresql-<version>.jar file is a proper JPMS module, then there is nothing more that you should do: the postgresql-<version>.jar file is in the module-path, and all the modules in the module-path are in the module graph (thanks to --add-modules=ALL-MODULE-PATH), and any dependency declared in the module-info.class will be added to the module graph.
Otherwise, postgresql-<version>.jar file is an automatic module, and will likely have a dependency on the JDK-bundled java.sql JPMS module.
Fortunately, when Jetty starts in JPMS mode, the --add-modules=ALL-DEFAULT option is also added to the JVM command line, so that all the Java JPMS modules are added to the module graph, and this would include the java.sql JPMS module.
Thanks to the fact that Jetty starts by default adding --add-modules=ALL-DEFAULT,ALL-MODULE-PATH, it is enough that you put custom libraries (and their dependencies) in the module-path, and you should not need any extra JPMS configuration.
However, you can explicitly configure JPMS directives in a custom Jetty module, for example to open or patch a JPMS module.
Using the postgresql.mod introduced in xref:start/index.adoc#configure-custom-module[this section] as an example, modify your custom Jetty module and add the JPMS directives you need, like so:
.postgresql.mod
[jpms]
add-modules: (,)*
patch-module: =()*
add-opens: /=(,)*
add-exports: /=(,)*
add-reads: =(,)*
The Jetty JPMS directives are equivalent to the JDK JPMS directives.
The [jpms] section is only used when Jetty is started on the module-path.
Documentation Jetty Modules Operations Guide Pages Tools Index (`documentation/jetty/modules/operations-guide/pages/tools/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jetty Tools
[[password]]
== Password Tool
The org.eclipse.jetty.util.security.Password class present in the org.eclipse.jetty:jetty-util artifact provides support for <> and <>.
[[password-obfuscation]]
=== Password Obfuscation
There are many cases where you might need to provide credentials such as usernames and passwords to authenticate your access to certain services, for example KeyStore and TrustStore passwords, JDBC credentials, Basic or Digest authentication credentials, etc.
Passwords are typically stored in clear-text in configuration files; a program such as Jetty reading the configuration file must be able to retrieve the original password to pass it to the service (for example, a KeyStore or a JDBC driver).
You can protect clear-text stored passwords from casual view by obfuscating them using class link:{javadoc-url}/org/eclipse/jetty/util/security/Password.html[org.eclipse.jetty.util.security.Password]:
[,bash,subs=attributes+]
$ java -cp jetty-util-{jetty-version}.jar org.eclipse.jetty.util.security.Password --prompt Username: <1> Password: secret <2> OBF:1yta1t331v8w1v9q1t331ytc <3> MD5:5eBe2294EcD0E0F08eAb7690D2A6Ee69 <4> ... MD:SHA-1:E5E9Fa1bA31eCd1aE84f75CaAa474f3a663f05F4 ... MD:SHA3-256:F5A5207a8729B1F709Cb710311751eB2Fc8aCaD5A1Fb8aC991B736E69b6529A3 ...
<1> Hit kbd:[Enter] to specify a blank user.
<2> Enter the password you want to obfuscate.
<3> The obfuscated password.
<4> MD5 and other MessageDigest checksums of the password, using different algorithms.
The Password tool produced an obfuscated string for the password secret, namely OBF:1yta1t331v8w1v9q1t331ytc (the prefix OBF: must be retained).
The obfuscated string can be de-obfuscated to obtain the original password.
Now you can use the obfuscated password in Jetty configuration files, for example to specify the KeyStore password in ssl-context.ini when configuring secure connectors, as explained xref:protocols/index.adoc#ssl-customize[here].
For example:
.ssl-context.ini [,properties]
jetty.sslContext.keyStorePassword=OBF:1yta1t331v8w1v9q1t331ytc
NOTE: Remember that password obfuscation only protects from casual view -- it can be de-obfuscated to obtain the original password.
TIP: You can also use the obfuscated password in your Java source code.
[CAUTION]
Extreme care should be taken when using the Password tool from the command line, especially in cases where the username or password contains characters that may be interpreted by the shell, such as the character $, and the --prompt command line option is not used.
For example, running the following produces the wrong password:
[,bash,subs=attributes+]
$ java -cp jetty-util-{jetty-version}.jar org.eclipse.jetty.util.security.Password bob secret$phrase
where bob is the user, and secret$phrase is the desired password.
The shell may interpret $phrase as a shell variable, likely an empty string, so the Password class only receives secret as the password to obfuscate and hash.
Always use the --prompt command line option, or disable shell interpretation for the parameters, for example by surrounding the parameters with single quotes:
[,bash,subs=attributes+]
$ java -cp jetty-util-{jetty-version}.jar org.eclipse.jetty.util.security.Password 'bob' 'secret$phrase'
====
You can also use obfuscated passwords in Jetty XML files where a clear-text password is usually required.
Here is an example, setting an obfuscated password for a JDBC DataSource:
[,xml,subs=attributes+]
[[password-checksum]]
=== Password Checksums
Password checksums are computed using the JDK MessageDigest class and are useful when Jetty receives a password and needs to verify it without storing the original password (for example, with Basic authentication).
Differently from obfuscated passwords, password checksums are not reversible and cannot be used when Jetty needs to pass the original password to other services; they can only be used to verify that the received password matches the password checksum.
You can store the Basic authentication credentials in checksum form on the server and verify the password received from the client by comparing the stored checksum with the checksum of the received password computed on-the-fly.
If the checksum is identical, then the password was correct.
[NOTE]
MessageDigest algorithms vary in strength, that is the probability that two different inputs produce the same checksum.
The `MD5` and `SHA-1` algorithms are not recommended, as they are weak and insecure. Use at least `SHA-256`, typically available in all modern JVMs.
Documentation Jetty Modules Operations Guide Pages Troubleshooting Index (`documentation/jetty/modules/operations-guide/pages/troubleshooting/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Troubleshooting
To troubleshoot Jetty when used as a standalone server, there are two main tools: the Jetty Server Dump and enabling DEBUG level logging.
It is typically very helpful to enable JMX, as detailed in xref:jmx/index.adoc[this section].
Enabling JMX allows to access the Jetty server (possibly a production server) from a remote location, and obtain the information exported by Jetty via JMX.
Access to the Jetty server via JMX allows to either diagnose the problem, possibly reconfigure and restart the Jetty server.
IMPORTANT: Make sure you read about how to secure the access to Jetty when using xref:jmx/index.adoc#remote[remote JMX].
[[dump]]
== Jetty Server Dump
The most useful too to troubleshoot a Jetty server is the xref:programming-guide:troubleshooting/component-dump.adoc[Jetty Component Dump], that reports the internal state of the Jetty server and all its components (the thread pool, the ByteBuffer pool, the currently established connections, and so on).
The Jetty server dump can easily be obtained via JMX using a JMX console such as Java Mission Control (JMC), as explained in xref:programming-guide:troubleshooting/component-dump.adoc#dump-invoke[this section].
[[dump-start-stop]]
=== Dump at Server Start/Stop
The Jetty server dump may be reported just after the Server starts.
This is useful to verify that all the expected components have been correctly configured and started for the optimal functioning of the server.
Similarly, the Jetty server dump may be reported just before the Server stops.
This is useful to log the state of a server that is not working properly.
The xref:modules/standard.adoc#server[server] Jetty module defines, in xref:modules/standard.adoc#server-config[this section], the properties jetty.server.dumpAfterStart and jetty.server.dumpBeforeStop that you can configure to report the Jetty server dump.
These properties can be specified temporarily as command line arguments, as explained in xref:start/index.adoc#configure-enable-command-line[this section]:
[source,subs=+quotes]
$ java -jar $JETTY_HOME/start.jar *jetty.server.dumpAfterStart=true*
Alternatively, you can specify these properties in the $JETTY_BASE/start.d/server.ini file, as explained in xref:start/index.adoc#configure-edit-ini[this section], to make the values persistent across server restarts.
[[logging]]
== Enabling DEBUG Logging
Enabling DEBUG level logging for the org.eclipse.jetty logger name provides the maximum amount of information to troubleshoot Jetty issues.
Refer to the xref:server/index.adoc#logging[logging section] for more information about how to configure logging in Jetty.
[CAUTION]
Enabling DEBUG level logging for org.eclipse.jetty is very, very expensive.
Your server could be slowed down to almost a halt, especially if it is under heavy load.
Furthermore, the log file could quickly fill up the entire filesystem (unless configured to roll over), so you want to be really careful using DEBUG logging.
For production servers, consider using the xref:dump[Jetty Server Dump] first, and enable DEBUG logging only as a last resort.
However, sometimes issues are such that only DEBUG logging can really tell what's going on in the system, and enabling DEBUG logging is your best chance to figure the issue out.
Below you can find few suggestions that can help you reduce the impact when you have to enable DEBUG logging.
[[logging-backend]]
=== Jetty Behind a Load Balancer
If Jetty instances are behind a load balancer, you may configure the load balancer to send less load to a particular Jetty instance, and enable DEBUG logging in that instance only.
[[logging-jmx]]
=== Enabling DEBUG Logging for a Short Time
In certain cases the issue can be reproduced reliably, but only in the production environment.
You can use JMX to temporarily enable DEBUG logging, reproduce the issue, and then disable DEBUG logging.
Alternatively, if you cannot reliably reproduce the issue, but you know it is happening, you can temporarily enable DEBUG logging for a small period of time, let's say 10-60 seconds, and then disable DEBUG logging.
Changing the log level at runtime is a feature of the logging implementation that you are using.
The Jetty SLF4J implementation, used by default, exposes via JMX method boolean JettyLoggerFactoryMBean.setLoggerLevel(String loggerName, String levelName) that you can invoke via a JMX console to change the level for the specified logger name.
The method returns true if the logger level was successfully changed.
For example, you can pass the string org.eclipse.jetty as the first parameter, and the string DEBUG (upper case) as the second parameter.
You can then use the string INFO or WARN (upper case) to restore the logging level to its previous value.
[[logging-subpackages]]
=== Enabling DEBUG Logging for SubPackages
Enabling DEBUG logging for the org.eclipse.jetty logger name implies that all children logger names, recursively, inherit the DEBUG level.
Processing a single HTTP request involves many Jetty components: the I/O subsystem (under org.eclipse.jetty.io), the thread pool (under org.eclipse.jetty.util), the HTTP/1.1 parsing (under org.eclipse.jetty.http), etc.
If you can cut the amount of DEBUG logging to just what you need to troubleshoot the issue, the impact of enabling DEBUG logging will be much less than enabling it for all Jetty components.
For example, if you need to troubleshoot a client that sends bad HTTP/1.1 requests, it may be enough to enable only the org.eclipse.jetty.http logger name, therefore saving the large amount of DEBUG logging produced by the I/O subsystem and by the thread pool.
In another case, you may need to troubleshoot only HTTP/2 requests, and therefore enabling only the org.eclipse.jetty.http2 logger name could be enough.
[[debugging]]
== Remote Debugging
The Java Virtual Machines allows remote processes on different hosts to connect for debugging purposes, by using specific command line options.
[CAUTION]
While it is possible to enable remote debugging on a Jetty server, it is typically not recommended for security and performance reasons. Only enable remote debugging on a Jetty server as a last resort to troubleshoot issues that could not be troubleshot otherwise.
You can easily create a custom Jetty module (see xref:modules/custom.adoc[this section]) with the following content:
.remote-debug.mod
include::code:example$jetty-modules/remote-debug.mod[]
The [exec] directive (documented xref:modules/index.adoc#directive-exec[here]) is necessary to pass the -agentlib:jdwp JVM option to the forked JVM that runs Jetty, so that you can attach with a debugger.
[NOTE]
The address parameter of the -agentlib:jdwp command line option specifies the network address and port the Jetty JVM listens on for remote debugging.
Please refer to the https://docs.oracle.com/en/java/javase/17/docs/specs/jpda/conninv.html[Java Debug Wire Protocol documentation] for additional information about the `-agentlib:jdwp` command line option and its parameters.
You can now enable the remote-debug Jetty module with the following command issued from the $JETTY_BASE directory:
$ java -jar $JETTY_HOME/start.jar --add-modules=server,remote-debug
The command above minimally adds a Jetty server without connectors (via the server Jetty module) and the remote-debug Jetty module, and produces the following $JETTY_BASE directory structure:
[source,subs=+quotes]
$JETTY_BASE
├── modules
│ └── remote-debug.mod
├── resources
│ └── jetty-logging.properties
└── start.d
├── ##remote-debug.ini##
└── server.ini
You can easily disable the remote-debug Jetty module as explained in xref:start/index.adoc#configure-disable[this section].
Alternatively, you can enable the remote-debug module on the command line, as explained in xref:start/index.adoc#configure-enable-command-line[this section].
Starting the Jetty server with the remote-debug module enabled yields:
[jetty%nowrap]
....
[jetty]
setupModules=code:example$jetty-modules/remote-debug.mod
setupArgs=--add-modules=server,remote-debug
highlight=5005
....
Note how the JVM is listening on port 5005 to allow remote debuggers to connect.
If you want to avoid to fork a second JVM to pass the -agentlib:jdwp JVM option, please read xref:start/index.adoc#configure-dry-run[this section].
[[handlers]]
== Troubleshooting Handlers
[[handlers-state-tracking]]
=== StateTrackingHandler
Jetty's StateTrackingHandler (described in xref:modules/standard.adoc#state-tracking[this module]) can be used to troubleshoot problems in web applications.
StateTrackingHandler tracks the usages of Handler/Request/Response asynchronous APIs by web applications, emitting events (logged at WARN level) when an invalid usage of the APIs is detected.
In conjunction with <<dump,dumping the Jetty component tree>>, it dumps the state of current requests, detailing whether they have reads or writes that are pending, whether callbacks have been completed, along with thread stack traces (including virtual threads) of operations that have been started but not completed, or are stuck in blocking code.
You need to enable the state-tracking Jetty module, and configure it to track what you are interested in tracking (for more details, see the link:{javadoc-url}/org/eclipse/jetty/server/handler/StateTrackingHandler.html[javadocs]).
Documentation Jetty Modules Operations Guide Pages Xml Index (`documentation/jetty/modules/operations-guide/pages/xml/index.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jetty XML
// TODO: merge this small section into the syntax and maybe call it "Jetty XML Reference".
The Jetty XML format is a straightforward mapping of XML elements to Java APIs so that any object can be instantiated and getters, setters, and methods can be called.
The Jetty XML format is very similar to that of frameworks like Spring or Plexus, although it predates all of them and it's typically more powerful as it can invoke any Java API.
The Jetty XML format is used in xref:modules/index.adoc[Jetty modules] to create the Jetty server components, as well as in xref:deploy/index.adoc[Jetty XML context files] to configure web applications, but it can be used to call any Java API.
[[syntax]]
== Jetty XML Syntax
The Jetty XML syntax defines XML element that allow you to call any Java API and that allow you to interact in a simpler way with the xref:modules/index.adoc[Jetty module system] and the xref:deploy/index.adoc[Jetty deploy system].
The Jetty XML elements define attributes such as id, name, class, etc. that may be replaced by correspondent elements, so that these XML documents are equivalent:
[,xml]
[,xml]
The version using attributes is typically shorter and nicer to read, but sometimes the attribute value cannot be a literal string (for example, it could be the value of a system property) and that's where elements gives you the required flexibility.
[[syntax-configure]]
=== <Configure>
Element Configure must be the root element of the XML document.
The following Jetty XML creates an empty String and assigns it the id mystring:
[,xml]
This is equivalent to the following Java code:
[,java]
var mystring = new String();
If an object with the id mystring already exists, then it is not created again but rather just referenced.
Within element <Configure>, the created object (if any) is in <<syntax-scope,scope>> and may be the implicit target of other, nested, elements.
Typically, the <Configure> element is used to configure a Server instance or ContextHandler subclasses such as WebAppContext that represent web applications.
[[syntax-arg]]
=== <Arg>
Element Arg is used to pass arguments to <<syntax-new,constructors>> and <<syntax-call,method calls>>.
The following example creates a minimal Jetty Server:
[,xml]
Arguments may have a type attribute that explicitly performs <<syntax-types,type coercion>>.
Arguments may also have a name attribute, which is matched with the corresponding Java annotation in the source class, that helps to identify arguments:
[,xml]
[[syntax-new]]
=== <New>
Element <New> creates a new object of the type specified by the mandatory class attribute.
A sequence of Arg elements, that must be contiguous and before other elements, may be present to specify the constructor arguments.
Within element <New> the newly created object is in <<syntax-scope,scope>> and may be the implicit target of other, nested, elements.
The following example creates an ArrayList:
[,xml]
This is equivalent to the following Java code:
[,java]
var mylist = new ArrayList(16);
[[syntax-call]]
=== <Call>
Element <Call> invokes a method specified by the mandatory name attribute.
A sequence of Arg elements, that must be contiguous and before other elements, may be present to specify the method arguments.
Within element <Call> the return value, if the return type is not void, is in <<syntax-scope,scope>> and may be the implicit target of other, nested, elements.
[,xml]
This is equivalent to the following Java code:
[,java]
new ArrayList().listIterator(0).next();
It is possible to call static methods by specifying the class attribute:
[,xml]
This is equivalent to the following Java code:
[,java]
var myhost = InetAddress.getByName("jdk.java.net");
The class attribute (or <Class> element) can also be used to specify the Java class or interface to use to lookup the non-static method name.
This is necessary when the object in scope, onto which the <Call> would be applied, is an instance of a class that is not visible to Jetty classes, or not accessible because it is not public.
For example:
[,xml,subs=+quotes]
In the example above, Executors.newSingleThreadScheduledExecutor() returns an object whose class is a private JDK implementation class.
Without an explicit class attribute (or <Class> element), it is not possible to invoke the method shutdown() when it is obtained via reflection from the private JDK implementation class, because while the method is public, the private JDK implementation class is not, therefore this exception is thrown:
[source]
java.lang.IllegalAccessException: class org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration (in module org.eclipse.jetty.xml) cannot access a member of class java.util.concurrent.Executors$DelegatedExecutorService (in module java.base) with modifiers "public"
The solution is to explicitly use the class attribute (or <Class> element) of the <Call> element that is invoking the shutdown() method, specifying a publicly accessible class or interface that the object in scope extends or implements (in the example above java.util.concurrent.ExecutorService).
[[syntax-get]]
=== <Get>
Element <Get> retrieves the value of a JavaBean property specified by the mandatory name attribute.
If the JavaBean property is foo (or Foo), <Get> first attempts to invoke method getFoo() or method isFoo(); failing that, attempts to retrieve the value from field foo (or Foo).
[,xml]
The class attribute (or <Class> element) allows to perform static calls, or to lookup the getter method from the specified class, as described in the <<syntax-call,<Call> section>>.
[[syntax-set]]
=== <Set>
Element <Set> stores the value of a JavaBean property specified by the mandatory name attribute.
If the JavaBean property is foo (or Foo), <Set> first attempts to invoke method setFoo(...) with the value in the <<syntax-scope,scope>> as argument; failing that, attempts to store the value in the scope to field foo (or Foo).
[,xml]
The class attribute (or <Class> element) allows to perform static calls, or to lookup the setter method from the specified class, as described in the <<syntax-call,<Call> section>>.
[[syntax-map]]
=== <Map> and <Entry>
Element <Map> allows the creation of a new java.util.Map implementation, specified by the class attribute -- by default a HashMap.
The map entries are specified with a sequence of <Entry> elements, each with exactly 2 `` elements, for example:
[,xml]
[[syntax-put]]
=== ``
Element `` is a convenience element that puts a key/value pair into objects that implement java.util.Map.
You can only specify the key value via the name attribute, so the key can only be a literal string (for keys that are not literal strings, use the <Call> element).
[,xml]
<Call class="java.net.InetAddress" name="getByName">
<Arg>localhost</Arg>
</Call>[[syntax-array]]
=== <Array> and ``
Element <Array> creates a new array, whose component type may be specified by the type attribute, or by a Type child element.
[,xml]
literalString
1.0D
<New class="java.lang.Exception" />[[syntax-ref]]
=== <Ref>
Element <Ref> allows you to reference an object via the refid attribute, putting it into <<syntax-scope,scope>> so that nested elements can operate on it. You must give a unique id` attribute to the objects you want to reference.
[,xml]
<Ref refid="server">
<Get id="myversion" name="version" />
</Ref>
<Call name="println">
<Arg>Server version is: <Ref refid="myversion" /></Arg>
</Call>[[syntax-property]]
=== ``
Element `` retrieves the value of the Jetty module property specified by the name attribute, and it is mostly used when creating xref:modules/custom.adoc[custom Jetty modules] or when using xref:deploy/index.adoc#jetty[Jetty context XML files].
The deprecated attribute allows you to specify a comma separated list of old, deprecated, property names for backward compatibility.
The default attribute allows you to specify a default value for the property, if it has not been explicitly defined.
For example, you may want to configure the context path of your web application in this way:
[,xml,subs="+attributes,+quotes"]
The contextPath value is resolved by looking for the Jetty module property com.myapps.mywiki.context.path; if this property is not set, then the default value of /wiki is used.
[[syntax-system-property]]
=== <SystemProperty>
Element <SystemProperty> retrieves the value of the JVM system property specified by the name attribute, via System.getProperty(...).
The deprecated attribute allows you to specify a comma separated list of old, deprecated, system property names for backward compatibility.
The default attribute allows you to specify a default value for the system property value, if it has not been explicitly defined.
The following example creates a minimal Jetty Server that listens on a port specified by the com.acme.http.port system property:
[,xml]
[[syntax-env]]
=== <Env>
Element <Env> retrieves the value of the environment variable specified by the name attribute, via System.getenv(...).
The deprecated attribute allows you to specify a comma separated list of old, deprecated, environment variable names for backward compatibility.
The default attribute allows you to specify a default value for the environment variable value, if it has not been explicitly defined.
The following example creates a minimal Jetty Server that listens on a port specified by the COM_ACME_HTTP_PORT environment variable:
[,xml]
[[syntax-types]]
=== Type Coercion
Elements that have the type attribute explicitly perform the type coercion of the string value present in the XML document to the Java type specified by the type attribute.
Supported types are the following:
- all primitive types and their boxed equivalents, for example
type="int"but alsotype="Integer"(short form) andtype="java.lang.Integer"(fully qualified form) java.lang.String, in both short form and fully qualified formjava.net.URL, in both short form and fully qualified formjava.net.InetAddress, in both short form and fully qualified form
[[syntax-scope]]
=== Scopes
Elements that create new objects or that return a value create a scope.
Within these elements there may be nested elements that will operate on that scope, i.e. on the new object or returned value.
The following example illustrates how scopes work:
[,xml]
<Set name="secureScheme">https</Set><Set name="maxThreads" type="int">256</Set><Ref refid="server">
<Get id="myversion" name="version" />
</Ref>
<Call name="println">
<Arg>Server version is: <Ref refid="myversion" /></Arg>
</Call>// TODO: port the documentation from old_docs/jetty-xml/*.adoc
Documentation Jetty Modules Programming Guide Pages Arch Bean (`documentation/jetty/modules/programming-guide/pages/arch/bean.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jetty Component Architecture
Applications that use the Jetty libraries (both client and server) create objects from Jetty classes and compose them together to obtain the desired functionalities.
A client application creates a ClientConnector instance, a HttpClientTransport instance and an HttpClient instance and compose them to have a working HTTP client that uses to call third party services.
A server application creates a ThreadPool instance, a Server instance, a ServerConnector instance, a Handler instance and compose them together to expose an HTTP service.
Internally, the Jetty libraries create even more instances of other components that also are composed together with the main ones created by applications.
The end result is that an application based on the Jetty libraries is a tree of components.
In server application the root of the component tree is a Server instance, while in client applications the root of the component tree is an HttpClient instance.
Having all the Jetty components in a tree is beneficial in a number of use cases.
It makes possible to register the components in the tree as xref:arch/jmx.adoc[JMX MBeans] so that a JMX console can look at the internal state of the components.
It also makes possible to xref:troubleshooting/component-dump.adoc[dump the component tree] (and therefore each component's internal state) to a log file or to the console for xref:troubleshooting/index.adoc[troubleshooting purposes].
// TODO: add a section on Dumpable?
[[lifecycle]]
== Jetty Component Lifecycle
Jetty components typically have a life cycle: they can be started and stopped.
The Jetty components that have a life cycle implement the org.eclipse.jetty.util.component.LifeCycle interface.
Jetty components that contain other components implement the org.eclipse.jetty.util.component.Container interface and typically extend the org.eclipse.jetty.util.component.ContainerLifeCycle class.ContainerLifeCycle can contain these type of components, also called __bean__s:
- managed beans,
LifeCycleinstances whose life cycle is tied to the life cycle of their container - unmanaged beans,
LifeCycleinstances whose life cycle is not tied to the life cycle of their container - POJO (Plain Old Java Object) beans, instances that do not implement
LifeCycle
ContainerLifeCycle uses the following logic to determine if a bean should be managed, unmanaged or POJO:
- the bean implements
LifeCycle
** the bean is not started, add it as managed
** the bean is started, add it as unmanaged - the bean does not implement
LifeCycle, add it as POJO
When a ContainerLifeCycle is started, it also starts recursively all its managed beans (if they implement LifeCycle); unmanaged beans are not started during the ContainerLifeCycle start cycle.
Likewise, stopping a ContainerLifeCycle stops recursively and in reverse order all its managed beans; unmanaged beans are not stopped during the ContainerLifeCycle stop cycle.
Components can also be started and stopped individually, therefore activating or deactivating the functionalities that they offer.
Applications should first compose components in the desired structure, and then start the root component:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ComponentDocs.java[tags=start]
The component tree is the following:
[,screen]
Root
├── Monitor (MANAGED)
└── Service (MANAGED)
└── ScheduledExecutorService (POJO)
When the Root instance is created, also the Monitor instance is created and added as bean, so Monitor is the first bean of Root.Monitor is a managed bean, because it has been explicitly added to Root via ContainerLifeCycle.addManaged(...).
Then, the application creates a Service instance and adds it to Root via ContainerLifeCycle.addBean(...), so Service is the second bean of Root.Service is a managed bean too, because it is a LifeCycle and at the time it was added to Root is was not started.
The ScheduledExecutorService within Service does not implement LifeCycle so it is added as a POJO to Service.
It is possible to stop and re-start any component in a tree, for example:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ComponentDocs.java[tags=restart]
Service can be stopped independently of Root, and re-started.
Starting and stopping a non-root component does not alter the structure of the component tree, just the state of the subtree starting from the component that has been stopped and re-started.
Container provides an API to find beans in the component tree:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ComponentDocs.java[tags=getBeans]
You can add your own beans to the component tree at application startup time, and later find them from your application code to access their services.
[TIP]
The component tree should be used for long-lived or medium-lived components such as thread pools, web application contexts, etc.
It is not recommended adding to, and removing from, the component tree short-lived objects such as HTTP requests or TCP connections, for performance reasons.
If you need component tree features such as automatic xref:arch/jmx.adoc[export to JMX] or xref:troubleshooting/component-dump.adoc[dump capabilities] for short-lived objects, consider having a long-lived container in the component tree instead. You can make the long-lived container efficient at adding/removing the short-lived components using a data structure that is not part of the component tree, and make the long-lived container handle the JMX and dump features for the short-lived components.
[[listener]]
== Jetty Component Listeners
A component that extends AbstractLifeCycle inherits the possibility to add/remove event listeners for various events emitted by components.
A component that implements java.util.EventListener that is added to a ContainerLifeCycle is also registered as an event listener.
The following sections describe in details the various listeners available in the Jetty component architecture.
[[listener-lifecycle]]
=== LifeCycle.Listener
A LifeCycle.Listener emits events for life cycle events such as starting, stopping and failures:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ComponentDocs.java[tags=lifecycleListener]
For example, a life cycle listener attached to a Server instance could be used to create (for the started event) and delete (for the stopped event) a file containing the process ID of the JVM that runs the Server.
[[listener-container]]
=== Container.Listener
A component that implements Container is a container for other components and ContainerLifeCycle is the typical implementation.
A Container emits events when a component (also called bean) is added to or removed from the container:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ComponentDocs.java[tags=containerListener]
A Container.Listener added as a bean will also be registered as a listener:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ComponentDocs.java[tags=containerSiblings]
[[listener-inherited]]
=== Container.InheritedListener
A Container.InheritedListener is a listener that will be added to all descendants that are also Containers.
Listeners of this type may be added to the component tree root only, but will be notified of every descendant component that is added to or removed from the component tree (not only first level children).
The primary use of Container.InheritedListener within the Jetty Libraries is MBeanContainer from the xref:arch/jmx.adoc[Jetty JMX support].
MBeanContainer listens for every component added to the tree, converts it to an MBean and registers it to the MBeanServer; for every component removed from the tree, it unregisters the corresponding MBean from the MBeanServer.
Documentation Jetty Modules Programming Guide Pages Arch Io (`documentation/jetty/modules/programming-guide/pages/arch/io.adoc`)
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
= Jetty I/O Architecture
The Jetty libraries (both client and server) use Java NIO to handle I/O, so that at its core Jetty I/O is completely non-blocking.
[[selector-manager]]
== Jetty I/O: SelectorManager
The main class of The Jetty I/O library is link:{javadoc-url}/org/eclipse/jetty/io/SelectorManager.html[SelectorManager].
SelectorManager manages internally a configurable number of link:{javadoc-url}/org/eclipse/jetty/io/ManagedSelector.html[ManagedSelector]s.
Each ManagedSelector wraps an instance of java.nio.channels.Selector that in turn manages a number of java.nio.channels.SelectionKey instances, that each wrap a java.nio.channels.SelectableChannel instance such as java.nio.channels.SocketChannel.
[plantuml]
object SM as "SelectorManager"
object MS1 as "ManagedSelector" {
java.nio.channels.Selector
}
object MS2 as "ManagedSelector" {
java.nio.channels.Selector
}
object SC1A as "SelectionKey" {
SelectableChannel
}
object SC1B as "SelectionKey" {
SelectableChannel
}
object SC2A as "SelectionKey" {
SelectableChannel
}
object SC2B as "SelectionKey" {
SelectableChannel
}
object SC2C as "SelectionKey" {
SelectableChannel
}
SM o-- MS1 SM o-- MS2 MS1 o-- SC1A MS1 o-- SC1B MS2 o-- SC2A MS2 o-- SC2B MS2 o-- SC2C
SocketChannel instances are typically created by the Jetty implementation, on client-side when connecting to a server and on server-side when accepting connections from clients.
In both cases the SocketChannel instance is passed to SelectorManager (which passes it to ManagedSelector and eventually to java.nio.channels.Selector) to be registered for use within Jetty.
It is possible for an application to create the SocketChannel instances outside Jetty, even perform some initial network traffic also outside Jetty (for example for authentication purposes), and then pass the SocketChannel instance to SelectorManager for use within Jetty.
This example shows how a client can connect to a server:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/SelectorManagerDocs.java[tags=connect]
This example shows how a server accepts a client connection:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/SelectorManagerDocs.java[tags=accept]
[[endpoint-connection]]
== Jetty I/O: EndPoint and Connection
SocketChannels that are passed to SelectorManager are wrapped into two related components: an link:{javadoc-url}/org/eclipse/jetty/io/EndPoint.html[EndPoint] and a link:{javadoc-url}/org/eclipse/jetty/io/Connection.html[Connection].
EndPoint is the Jetty abstraction for a SocketChannel or a DatagramChannel: you can read bytes from an EndPoint, you can write bytes to an EndPoint , you can close an EndPoint, etc.
Connection is the Jetty abstraction that is responsible to read bytes from the EndPoint and to deserialize the read bytes into objects.
For example, an HTTP/1.1 server-side Connection implementation is responsible to deserialize HTTP/1.1 request bytes into an HTTP request object.
Conversely, an HTTP/1.1 client-side Connection implementation is responsible to deserialize HTTP/1.1 response bytes into an HTTP response object.
Connection is the abstraction that implements the reading side of a specific protocol such as HTTP/1.1, or HTTP/2, or HTTP/3, or WebSocket: it is able to read and parse incoming bytes in that protocol.
The writing side for a specific protocol may be implemented in the Connection but may also be implemented in other components, although eventually the bytes to write will be written through the EndPoint.
While there are primarily only two implementations of EndPoint,link:{javadoc-url}/org/eclipse/jetty/io/SocketChannelEndPoint.html[SocketChannelEndPoint] for TCP and link:{javadoc-url}/org/eclipse/jetty/io/DatagramChannelEndPoint.html[DatagramChannelEndPoint] for UDP (used both on the client-side and on the server-side), there are many implementations of Connection, typically two for each protocol (one for the client-side and one for the server-side).
The EndPoint and Connection pairs can be chained, for example in case of encrypted communication using the TLS protocol.
There is an EndPoint and Connection TLS pair where the EndPoint reads the encrypted bytes from the socket and the Connection decrypts them; next in the chain there is an EndPoint and Connection pair where the EndPoint "reads" decrypted bytes (provided by the previous Connection) and the Connection deserializes them into specific protocol objects (for example HTTP/2 frame objects).
Certain protocols, such as WebSocket, start the communication with the server using one protocol (for example, HTTP/1.1), but then change the communication to use another protocol (for example, WebSocket).EndPoint supports changing the Connection object on-the-fly via EndPoint.upgrade(Connection).
This allows to use the HTTP/1.1 Connection during the initial communication and later to replace it with a WebSocket Connection.
// TODO: add a section on UpgradeFrom and UpgradeTo?
SelectorManager is an abstract class because while it knows how to create concrete EndPoint instances, it does not know how to create protocol specific Connection instances.
Creating Connection instances is performed on the server-side by link:{javadoc-url}/org/eclipse/jetty/server/ConnectionFactory.html[ConnectionFactory]s and on the client-side by link:{javadoc-url}/org/eclipse/jetty/io/ClientConnectionFactory.html[ClientConnectionFactory]s.
On the server-side, the component that aggregates a SelectorManager with a set of ConnectionFactorys is link:{javadoc-url}/org/eclipse/jetty/server/ServerConnector.html[ServerConnector] for TCP sockets, link:{javadoc-url}/org/eclipse/jetty/quic/server/QuicServerConnector.html[QuicServerConnector] for QUIC sockets, and link:{javadoc-url}/org/eclipse/jetty/unixdomain/server/UnixDomainServerConnector.html[UnixDomainServerConnector] for Unix-Domain sockets (see the xref:server/io-arch.adoc[server-side architecture section] for more information).
On the client-side, the components that aggregates a SelectorManager with a set of ClientConnectionFactorys are link:{javadoc-url}/org/eclipse/jetty/client/HttpClientTransport.html[HttpClientTransport] subclasses (see the xref:client/io-arch.adoc[client-side architecture section] for more information).
[[endpoint]]
== Jetty I/O: EndPoint
The Jetty I/O library use Java NIO to handle I/O, so that I/O is non-blocking.
At the Java NIO level, in order to be notified when a SocketChannel or DatagramChannel has data to be read, the SelectionKey.OP_READ flag must be set.
In the Jetty I/O library, you can call EndPoint.fillInterested(Callback) to declare interest in the "read" (also called "fill") event, and the Callback parameter is the object that is notified when such an event occurs.
At the Java NIO level, a SocketChannel or DatagramChannel is always writable, unless it becomes congested.
In order to be notified when a channel uncongests and it is therefore writable again, the SelectionKey.OP_WRITE flag must be set.
In the Jetty I/O library, you can call EndPoint.write(Callback, ByteBuffer\...) to write the ByteBuffers and the Callback parameter is the object that is notified when the whole write is finished (i.e. all ByteBuffers have been fully written, even if they are delayed by congestion/uncongestion).
The EndPoint APIs abstract out the Java NIO details by providing non-blocking APIs based on Callback objects for I/O operations.
The EndPoint APIs are typically called by Connection implementations, see <<connection,this section>>.
[[connection]]
== Jetty I/O: Connection
Connection is the abstraction that deserializes incoming bytes into objects, for example an HTTP request object or a WebSocket frame object, that can be used by more abstract layers.
Connection instances have two lifecycle methods:
Connection.onOpen(), invoked when theConnectionis associated with theEndPoint.Connection.onClose(Throwable), invoked when theConnectionis disassociated from theEndPoint, where theThrowableparameter indicates whether the disassociation was normal (when the parameter isnull) or was due to an error (when the parameter is notnull).
When a Connection is first created, it is not registered for any Java NIO event.
It is therefore typical to implement onOpen() to call EndPoint.fillInterested(Callback) so that the Connection declares interest for read events, and it is invoked (via the Callback) when the read event happens.
The abstract class AbstractConnection partially implements Connection and provides simpler APIs.
The example below shows a typical implementation that extends AbstractConnection:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/SelectorManagerDocs.java[tags=connection]
[[connection-listener]]
=== Jetty I/O: Connection.Listener
The Jetty I/O library allows applications to register xref:arch/listener.adoc[event listeners] for the Connection events "opened" and "closed" via the interface Connection.Listener.
This is useful in many cases, for example:
- Gather statistics about connection lifecycle, such as time of creation and duration.
- Gather statistics about the number of concurrent connections, and take action if a threshold is exceeded.
- Gather statistics about the number of bytes read and written, and the number of "messages" read and written, where "messages" may mean HTTP/1.1 requests or responses, or WebSocket frames, or HTTP/2 frames, etc.
- Gather statistics about the different types of connections being opened (TLS, HTTP/1.1, HTTP/2, WebSocket, etc.).
- Etc.
Connection.Listener implementations must be added as beans to a server-side Connector, or to client-side HttpClient, WebSocketClient, HTTP2Client or HTTP3Client.
You can add as beans many Connection.Listener objects, each with its own logic, so that you can separate different logics into different Connection.Listener implementations.
The Jetty I/O library provides useful Connection.Listener implementations that you should evaluate before writing your own, for example link:{javadoc-url}/org/eclipse/jetty/io/ConnectionStatistics.html[ConnectionStatistics].
Here is a simple example of a Connection.Listener used both on the client and on the server:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/SelectorManagerDocs.java[tags=connectionListener]
[[echo]]
== Jetty I/O: TCP Network Echo
With the concepts above it is now possible to write a simple, fully non-blocking, Connection implementation that simply echoes the bytes that it reads back to the other peer.
A naive, but wrong, implementation may be the following:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/SelectorManagerDocs.java[tags=echo-wrong]
WARNING: The implementation above is wrong and leads to StackOverflowError.
The problem with this implementation is that if the writes always complete synchronously (i.e. without being delayed by TCP congestion), you end up with this sequence of calls:
Connection.onFillable()
EndPoint.write()
Connection.succeeded()
Connection.onFillable()
EndPoint.write()
Connection.succeeded()
...
which leads to StackOverflowError.
This is a typical side effect of asynchronous programming using non-blocking APIs, and happens in the Jetty I/O library as well.
NOTE: The callback is invoked synchronously for efficiency reasons.
Submitting the invocation of the callback to an Executor to be invoked in a different thread would cause a context switch and make simple writes extremely inefficient.
This side effect of asynchronous programming leading to StackOverflowError is so common that the Jetty libraries have a generic solution for it: a specialized Callback implementation named org.eclipse.jetty.util.IteratingCallback that turns recursion into iteration, therefore avoiding the StackOverflowError.
IteratingCallback is a Callback implementation that should be passed to non-blocking APIs such as EndPoint.write(Callback, ByteBuffer\...) when they are performed in a loop.
IteratingCallback works by starting the loop with IteratingCallback.iterate().
In turn, this calls IteratingCallback.process(), an abstract method that must be implemented with the code that should be executed for each loop.
Method process() must return:
Action.SCHEDULED, to indicate whether the loop has performed a non-blocking, possibly asynchronous, operationAction.IDLE, to indicate that the loop should temporarily be suspended to be resumed later with another call to iterateAction.SUCCEEDEDto indicate that the loop exited successfully
Any exception thrown within process() exits the loops with a failure.
Now that you know how IteratingCallback works, a correct implementation for the echo Connection is the following:
[,java,indent=0]
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/SelectorManagerDocs.java[tags=echo-correct]
When onFillable() is called, for example the first time that bytes are available from the network, the iteration is started.
Starting the iteration calls process(), where a buffer is allocated and filled with bytes read from the network via EndPoint.fill(ByteBuffer); the buffer is subsequently written back via EndPoint.write(Callback, ByteBuffer\...) -- note that the callback passed to EndPoint.write() is this, i.e. the IteratingCallback itself; finally Action.SCHEDULED is returned, returning from the process() method.
At this point, the call to EndPoint.write(Callback, ByteBuffer\...) may have completed synchronously; IteratingCallback would know that and call process() again; within process(), the buffer has already been allocated so it will be reused, saving further allocations; the buffer will be filled and possibly written again; Action.SCHEDULED is returned again, returning again from the process() method.
At this point, the call to EndPoint.write(Callback, ByteBuffer\...) may have not completed synchronously, so IteratingCallback will not call process() again; the processing thread is free to return to the Jetty I/O system where it may be put back into the thread pool.
If this was the only active network connection, the system would now be idle, with no threads blocked, waiting that the write() completes. This thread-less wait is one of the most important features that make non-blocking asynchronous servers more scalable: they use less resources.
Eventually, the Jetty I/O system will notify that the write() completed; this notifies the IteratingCallback that can now resume the loop and call process() again.
When process() is called, it is possible that zero bytes are read from the network; in this case, you want to deallocate the buffer since the other peer may never send more bytes for the Connection to read, or it may send them after a long pause -- in both cases we do not want to retain the memory allocated by the buffer; next, you want to call fillInterested(this) to declare again interest for read events, and return Action.SCHEDULED since a callback is scheduled to occur once filling is possible.
Another possibility is that during process() the read returns -1 indicating that the other peer has closed the connection; this means that there will not be more bytes to read and the loop can be exited, so you return Action.SUCCEEDED; IteratingCallback will then call onCompleteSuccess() where you can close the EndPoint.
The last case is that during process() an exception is thrown, for example by EndPoint.fill(ByteBuffer) or, in more advanced implementations, by code that parses the bytes that have been read and finds them unacceptable; any exception thrown within process() will be caught by IteratingCallback that will exit the loop with a failure and call onCompleteFailure(Throwable) with the exception that has been thrown, where you can close the EndPoint, passing the exception that is the reason for closing prematurely the EndPoint.
Note that some failures may occur whilst a scheduled operation is in progress.
Such failures are notified immediately via the onFailure(Throwable) method, but care must be taken to not release any resources that may still be in use by the scheduled operation.
The onCompleteFailure(Throwable) method is called when both a failure has occurred and any scheduled operation has completed.
An example of this issue is that a buffer used for a write operation cannot be returned to a pool in onFailure(Throwable) as the write may still be progressing.
Either the buffer must be removed from the pool in onFailure(Throwable) or the release of the buffer deferred until onCompleteFailure(Throwable) is called.
[IMPORTANT]
Asynchronous programming is hard.
Rely on the Jetty classes to implement `Connection` to avoid mistakes that will be difficult to diagnose and reproduce.
[[content-source]]
== Content.Source
The high-level abstraction that Jetty offers to read bytes is org.eclipse.jetty.io.Content.Source.
Content.Source offers a non-blocking demand/read model where a read returns a Content.Chunk (see also <<content-source-chunk,this section>>).
A Content.Chunk groups the following information:
- A
ByteBufferwith the bytes that have been read; it may be empty. - Whether the read reached end-of-file, via its
lastflag. - A failure that might have happened during the read, via its
getFailure()method.
The Content.Chunk returned from Content.Source.read() can either be a normal chunk (a chunk containing a ByteBuffer and a null failure), or a failure chunk (a chunk containing an empty ByteBuffer and a non-null failure).
A failure chunk also indicates (via the last flag) whether the failure is a fatal (when last=true) or transient (when last=false) failure.
A transient failure is a temporary failure that happened during the read, it may be ignored, and it is recoverable: it is possible to call read() again and obtain a normal chunk (or a null chunk).
Typical cases of transient failures are idle timeout failures, where the read timed out, but the application may decide to insist reading until some other event happens.
The application may convert a transient failure into a fatal failure by calling Content.Source.fail(Throwable).
A Content.Source must be fully consumed by reading all its content, or failed by calling Content.Source.fail(Throwable) to signal that the reader is not interested in reading anymore, otherwise it may leak underlying resources.
Fully consuming a Content.Source means reading from it until it returns a Content.Chunk whose last flag is true.
Reading or demanding from an already fully consumed Content.Source is always immediately serviced with the last state of the Content.Source: a Content.Chunk with the last flag set to true, either an end-of-file chunk, or a failure chunk.
Once failed, a Content.Source is considered fully consumed.
Further attempts to read from a failed Content.Source return a failure chunk whose getFailure() method returns the exception passed to Content.Source.fail(Throwable).
When reading a normal chunk, its ByteBuffer is typically a slice of a different ByteBuffer that has been read by a lower layer.
There may be multiple layers between the bottom layer (where the initial read typically happens) and the application layer that calls `C