Getting Started With Jetty
Introducing Jetty
What is Jetty?
Jetty is an open-source project providing an HTTP server, HTTP client, and javax.servlet container.
This guide is broken up in to five parts:
-
The first section emphasizes beginning to use Jetty. It provides information about what Jetty is and where you can download it, and where to find Jetty in repositories like Central Maven. It also provides a Quick Start guide on how to get Jetty up and running as well as an overview of how and what to configure in Jetty.
-
The second section of the guide deals with configuring Jetty at a more granular level. It explains how to use Jetty to deploy web applications, configure contexts and connects, and how to implement SSL and other security measures.
-
Administration of Jetty is the focus of the third section of the guide. From server startup to session management, logging, HTTP/2 support and Jetty optimization, these chapters will help administrators get the most out of their Jetty server instances. This section also covers configuring many of the most common servlet container features such as JNDI and JMX.
-
Aimed at advanced users of Jetty, the fourth section of the guide focuses on Jetty development. A large portion of this section is focused on using Jetty as an embedded server in existing applications. It contains several examples and how-to guides for making the most out of the Jetty framework. This section also includes a guide on using the Jetty Maven plugin as well as information on debugging Jetty.
-
The final section of the guide is a reference section. Included there are guides on Jetty architecture and Jetty XML syntax, alternate distributions of Jetty and even troubleshooting of common issues. There is also a chapter on getting involved in the Jetty community including information on how to contribute code and how to find help.
Feedback is always welcome! Additionally, if you are interested in how to contribute to the open source project there is a section on that as well!
What Version Do I Use?
Jetty 9 is the most recent version of Jetty and has a great many improvements over previous versions. This documentation which focuses on Jetty 9. While many people continue to use older versions of Jetty, we generally recommend using Jetty 9 as it represents the version of Jetty that we will actively maintain and improve over the next few years.
It is important that only stable releases are used in production environments. Versions that have been deprecated or are released as Milestones (M) or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets. |
Version | Year | Home | Min JVM | Protocols | Servlet | JSP | Status |
---|---|---|---|---|---|---|---|
11 |
2020- |
Eclipse |
11 (2) |
HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI, JakartaEE Namespace(1) |
5.0.0 |
3.0.0 |
Stable |
10 |
2019- |
Eclipse |
11 (2) |
HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |
4.0.1 |
2.2 |
Stable |
9.4 |
2016- |
Eclipse |
1.8 |
HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |
3.1 |
2.3 |
Stable |
9.3 |
2015- |
Eclipse |
1.8 (3) |
HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |
3.1 |
2.3 |
Deprecated / End of Life December 2020 |
9.2 |
2014-2018 |
Eclipse |
1.7 (3) |
HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |
3.1 |
2.3 |
Deprecated / End of Life January 2018 |
9.1 |
2013-2014 |
Eclipse |
1.7 (3) |
HTTP/1.1 RFC2616 |
3.1 |
2.3 |
Deprecated / End of Life May 2014 |
9.0 |
2013-2013 |
Eclipse |
1.7 (3) |
HTTP/1.1 RFC2616 |
3.1-beta |
2.3 |
Deprecated / End of Life November 2013 |
8 |
2009-2014 |
Eclipse/Codehaus |
1.6 (3) |
HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |
3.0 |
2.2 |
Deprecated / End of Life November 2014 |
7 |
2008-2014 |
Eclipse/Codehaus |
1.5 |
HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |
2.5 |
2.1 |
Deprecated / End of Life November 2014 |
6 |
2006-2010 |
Codehaus |
1.4-1.5 |
HTTP/1.1 RFC2616 |
2.5 |
2.0 |
Deprecated / End of Life November 2010 |
5 |
2003-2009 |
Sourceforge |
1.2-1.5 |
HTTP/1.1 RFC2616 |
2.4 |
2.0 |
Antique |
4 |
2001-2006 |
Sourceforge |
1.2, J2ME |
HTTP/1.1 RFC2616 |
2.3 |
1.2 |
Ancient |
3 |
1999-2002 |
Sourceforge |
1.2 |
HTTP/1.1 RFC2068 |
2.2 |
1.1 |
Fossilized |
2 |
1998-2000 |
Mortbay |
1.1 |
HTTP/1.0 RFC1945 |
2.1 |
1.0 |
Legendary |
1 |
1995-1998 |
Mortbay |
1.0 |
HTTP/1.0 RFC1945 |
- |
- |
Mythical |
-
Due to Oracle’s ownership of the "Java" trademark, usage of the javax.* namespace has been restricted and the jakarta.* namespace was adopted by the Eclipse Foundation.
-
JPMS module support is optional
-
JDK9 and newer is not supported if using MultiRelease JAR Files, or Bytecode / Annotation scanning.
Jetty and Java EE Web Profile
Jetty implements aspects of the Java EE specification, primarily the Servlet Specification. Recent releases of the Java EE platform have introduced a Web Profile, recognizing that many developers need only a subset of the many technologies under the Java EE umbrella.
While Jetty itself does not ship all of the Web Profile technologies, Jetty architecture is such that you can plug in third party implementations to produce a container customized to your exact needs.
Java EE 7 Web Profile
In the forthcoming Java EE-7 specification, the Web Profile reflects updates in its component specifications and adds some new ones:
JSR | Name | Included with jetty-9.1.x | Pluggable |
---|---|---|---|
Servlet Specification API 3.1 |
Yes |
||
Java Server Faces 2.2 (JSF) |
No |
||
Java Server Pages 2.3/Java Expression Language 3.0 (JSP/EL) |
Yes |
Yes |
|
Java Standard Tag Library 1.2 (JSTL) |
Yes |
Yes |
|
Debugging Support for Other Languages 1.0 |
Yes (via JSP) |
Yes (via JSP) |
|
Contexts and Dependency Injection for the JavaEE Platform 1.1 (Web Beans) |
No |
Yes, Weld |
|
Dependency Injection for Java 1.0 |
No |
Yes as part of a CDI implementation, Weld |
|
Managed Beans 1.0 |
No |
Yes, as part of another technology |
|
Enterprise JavaBeans 3.2 Lite |
No |
||
Java Persistence 2.1 (JPA) |
No |
Yes, eg Hibernate |
|
Common Annotations for the Java Platform 1.2 |
Yes |
Partially (for non-core Servlet Spec annotations) |
|
Java Transaction API 1.2 (JTA) |
Yes |
Yes |
|
Bean Validation 1.1 |
No |
Yes as part of another technology eg JSF, or a stand-alone implementation such as Hiberate Validator |
|
Java API for RESTful Web Services 2.0 (JAX-RS) |
No |
||
Java API for Websocket 1.0 |
Yes |
No |
|
Java API for JSON Processing 1.0 (JSON-P) |
No |
Yes, eg JSON-P reference implementation |
|
Interceptors 1.2 |
No |
Yes as part of a CDI implementation |
Jetty EE 6 Web Profile
Here is the matrix of JSRs for Java EE 6 Web Profile, and how they relate to Jetty:
JSR | Name | Included with jetty-9.0.x | Pluggable |
---|---|---|---|
Servlet Specification API 3.0 |
Yes |
||
JavaServer Faces 2.0 (JSF) |
No |
||
JavaServer Pages 2.2/Java Expression Language 2.2 (JSP/EL) |
Yes |
Yes |
|
Java Standard Tag Library 1.2 (JSTL) |
Yes |
Yes |
|
Debugging Support for Other Languages 1.0 |
Yes (via JSP) |
Yes (via JSP) |
|
Contexts and Dependency Injection for the Java EE Platform 1.0 (Web Beans) |
No |
Yes, Weld or OpenWebBeans |
|
Dependency Injection for Java 1.0 |
No |
Yes as part of a CDI implementation, Weld |
|
Managed Beans 1.0 |
No |
Yes, as part of another technology. |
|
Enterprise JavaBeans 3.1 |
No |
Yes, OpenEJB |
|
Java Persistence 2.0 (JPA) |
No |
Yes, Hibernate |
|
Common Annotations for the Java Platform |
Yes |
Partially (for non-core Servlet Spec annotations) |
|
Java Transaction API (JTA) |
Yes |
Implementations are pluggable, such as Atomikos, JOTM, Jencks (Geronimo Transaction Manager) |
|
Bean Validation 1.0 |
No |
Yes as part of another technology (JSF), or a stand-alone implementation such as Hiberate Validator |
Finding Jetty in Maven
It is important that only stable releases are used in production environments. Versions that have been deprecated or are released as Milestones (M) or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets. |
Maven Coordinates
Jetty has existed in Maven Central almost since its inception, though the coordinates have changed over the years.
When Jetty was based at SourceForge and then The Codehaus it was located under the groupId
of org.mortbay.jetty
.
With Jetty 7 the project moved to the Eclipse foundation and to a new groupId
at that time to reflect its new home.
The top level Project Object Model (POM) for the Jetty project is located under the following coordinates.
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>${project.version}</version>
</dependency>
Changelogs in Maven Central
The changes between versions of Jetty are tracked in a file called VERSIONS.txt, which is under source control and is generated on release. Those generated files are also uploaded into Maven Central during the release of the top level POM. You can find them as a classifier marked artifact.
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>${project.version}</version>
<classifier>version</classifier>
<type>txt</type>
</dependency>
Using Jetty
You can use Jetty in many different ways ranging from embedding Jetty in applications, launching it from different build systems, from different JVM-based languages, or as a standalone distribution. This guide covers the latter, a standalone distribution suitable for deploying web applications.
Downloading Jetty
Downloading the Jetty Distribution
The standalone Jetty distribution is available for download from the Eclipse Foundation:
It is available in both zip and gzip formats; download the one most appropriate for your system.
When you download and unpack the binary, it is extracted into a directory called jetty-distribution-VERSION.
Put this directory in a convenient location.
The rest of the instructions in this documentation refer to this location as either $JETTY_HOME
or as $(jetty.home).
It is important that only stable releases are used in production environments. Versions that have been deprecated or are released as Milestones (M) or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets. |
Distribution Content
A summary of the distribution’s contents follows. The top-level directory contains:
Location | Description |
---|---|
license-eplv10-aslv20.html |
License file for Jetty |
README.txt |
Useful getting started information |
VERSION.txt |
Release information |
bin/ |
Utility shell scripts to help run Jetty on Unix systems |
demo-base/ |
A Jetty base directory to run a Jetty server with demonstration webapps |
etc/ |
Directory for Jetty XML configuration files |
lib/ |
All the JAR files necessary to run Jetty |
logs/ |
Directory for request logs |
modules/ |
Directory of module definitions |
notice.html |
License information and exceptions |
resources/ |
Directory containing additional resources for classpath, activated via configuration |
start.ini |
File containing the arguments that are added to the effective command line (modules, properties and XML configuration files) |
start.jar |
Jar that invokes Jetty (see also Running Jetty) |
webapps/ |
Directory containing webapps that run under the default configuration of Jetty |
Downloading the Jetty-Home Distribution
Jetty-Home is an alternate version of the distribution that contains only the necessary items to host a Jetty distribution. It is intended for advanced users who are already familiar with Jetty and want to download a smaller distribution package. Jetty-Home can be downloaded from the Maven Central repository:
Like the main Jetty distribution, Jetty-Home is available in both zip and gzip formats; download the one most appropriate for your system.
Notice that there are a number of other files with extensions of .sha or .md5 which are checksum files.
When you download and unpack the binary, it is extracted into a directory called jetty-home-VERSION.
Put this directory in a convenient location.
Distribution Content
A summary of the Jetty-Home’s distribution contents follows. The top-level directory contains:
Location | Description |
---|---|
license-eplv10-aslv20.html |
License file for Jetty |
VERSION.txt |
Release information |
etc/ |
Directory for Jetty XML configuration files |
lib/ |
All the JAR files necessary to run Jetty |
modules/ |
Directory of module definitions |
notice.html |
License information and exceptions |
start.jar |
Jar that invokes Jetty (see also Running Jetty) |
Running Jetty
Once you have a copy of the Jetty distribution downloaded, extract the zip
or tar.gz
file to a location where you have read and write access.
Jetty has no GUI (Graphical User Interface), so running the server and performing many configuration options is done from the command line.
Once you have access to your system’s command line, navigate to the directory where you unpacked your copy of the Jetty distribution. To start Jetty on the default port of 8080, run the following command:
$ java -jar start.jar
2017-09-20 15:45:11.986:INFO::main: Logging initialized @683ms to org.eclipse.jetty.util.log.StdErrLog
2017-09-20 15:45:12.197:WARN:oejs.HomeBaseWarning:main: This instance of Jetty is not running from a separate {jetty.base} directory, this is not recommended. See documentation at https://www.eclipse.org/jetty/documentation/current/startup.html
2017-09-20 15:45:12.243:INFO:oejs.Server:main: {VERSION}
2017-09-20 15:45:12.266:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///installs/repository/jetty/webapps/] at interval 1
2017-09-20 15:45:12.298:INFO:oejs.AbstractConnector:main: Started ServerConnector@39c0f4a{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2017-09-20 15:45:12.298:INFO:oejs.Server:main: Started @995ms
You can point a browser at this server at http://localhost:8080.
However, as there are no webapps deployed in the $JETTY_HOME
directory, you will see a 404 error page served by Jetty.
To stop the server, press CTRL
+ c
or CTRL
+ z
in your terminal.
Note the HomeBaseWarning
- it is not recommended to run Jetty from the $JETTY_HOME
directory.
Instead, see how to create a Jetty Base below.
You will see examples throughout the documentation referencing |
Demo Base
Within the standard Jetty distribution there is the demo-base
directory.
This is a fully-functioning Jetty Base (more on that later) complete with numerous web applications demonstrating different Jetty functionality.
Additionally, the demo-base
demonstrates the recommended way to run a Jetty base in a directory separate from $JETTY_HOME
:
$ cd demo-base/
$ java -jar ../start.jar
2017-09-20 16:23:03.563:INFO::main: Logging initialized @429ms to org.eclipse.jetty.util.log.StdErrLog
2017-09-20 16:23:03.802:WARN::main: demo test-realm is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:03.804:INFO:oejs.Server:main: {VERSION}
2017-09-20 16:23:03.819:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///installs/repository/jetty/demo-base/webapps/] at interval 1
2017-09-20 16:23:04.098:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=102ms
2017-09-20 16:23:04.103:WARN::main: async-rest webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:04.267:INFO:oejs.session:main: DefaultSessionIdManager workerName=node0
2017-09-20 16:23:04.267:INFO:oejs.session:main: No SessionScavenger set, using defaults
2017-09-20 16:23:04.268:INFO:oejs.session:main: Scavenging every 660000ms
2017-09-20 16:23:04.306:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@371a67ec{/async-rest,[file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-async-rest.war-_async-rest-any-5319296087878801290.dir/webapp/, jar:file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-async-rest.war-_async-rest-any-5319296087878801290.dir/webapp/WEB-INF/lib/example-async-rest-jar-{VERSION}.jar!/META-INF/resources],AVAILABLE}{/async-rest.war}
2017-09-20 16:23:04.429:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=53ms
2017-09-20 16:23:04.432:WARN::main: test webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:04.511:INFO:oejsh.ManagedAttributeListener:main: update PushFilter null->org.eclipse.jetty.servlets.PushCacheFilter@2362f559 on o.e.j.w.WebAppContext@35e2d654{/test,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test.war-_test-any-6279588879522983394.dir/webapp/,STARTING}{/test.war}
2017-09-20 16:23:04.516:INFO:oejsh.ManagedAttributeListener:main: update QoSFilter null->org.eclipse.jetty.servlets.QoSFilter@7770f470 on o.e.j.w.WebAppContext@35e2d654{/test,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test.war-_test-any-6279588879522983394.dir/webapp/,STARTING}{/test.war}
2017-09-20 16:23:04.519:WARN:oeju.DeprecationWarning:main: Using @Deprecated Class org.eclipse.jetty.servlets.MultiPartFilter
2017-09-20 16:23:04.549:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@35e2d654{/test,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test.war-_test-any-6279588879522983394.dir/webapp/,AVAILABLE}{/test.war}
2017-09-20 16:23:04.646:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=12ms
2017-09-20 16:23:04.649:WARN::main: test-jndi webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:04.697:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@561b6512{/test-jndi,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-jndi.war-_test-jndi-any-6023636263414992288.dir/webapp/,AVAILABLE}{/test-jndi.war}
2017-09-20 16:23:04.770:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=40ms
2017-09-20 16:23:05.036:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@2beee7ff{/proxy,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-javadoc-proxy.war-_javadoc-proxy-any-2758874759195597975.dir/webapp/,AVAILABLE}{/javadoc-proxy.war}
2017-09-20 16:23:05.072:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=16ms
2017-09-20 16:23:05.074:WARN::main: test-jaas webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:05.098:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@506ae4d4{/test-jaas,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-jaas.war-_test-jaas-any-8067423971450448377.dir/webapp/,AVAILABLE}{/test-jaas.war}
2017-09-20 16:23:05.182:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=37ms
2017-09-20 16:23:05.184:WARN::main: test-spec webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:05.243:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@45099dd3{/test-spec,[file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-spec.war-_test-spec-any-1205866915335004234.dir/webapp/, jar:file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-spec.war-_test-spec-any-1205866915335004234.dir/webapp/WEB-INF/lib/test-web-fragment-{VERSION}.jar!/META-INF/resources],AVAILABLE}{/test-spec.war}
2017-09-20 16:23:05.247:INFO:oejsh.ContextHandler:main: Started o.e.j.s.h.MovedContextHandler@3e08ff24{/oldContextPath,null,AVAILABLE}
2017-09-20 16:23:05.274:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=18ms
2017-09-20 16:23:05.296:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@5ddeb7cb{/,file:///installs/repository/jetty/demo-base/webapps/ROOT/,AVAILABLE}{/ROOT}
2017-09-20 16:23:05.326:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=21ms
2017-09-20 16:23:05.352:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@6b695b06{/doc,file:///installs/repository/jetty/demo-base/webapps/doc/,AVAILABLE}{/doc}
2017-09-20 16:23:05.370:INFO:oejs.AbstractConnector:main: Started ServerConnector@28cda624{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2017-09-20 16:23:05.380:INFO:oejus.SslContextFactory:main: x509=X509@126253fd(jetty,h=[jetty.eclipse.org],w=[]) for SslContextFactory@57db2b13(file:///installs/repository/jetty/demo-base/etc/keystore,file:///installs/repository/jetty/demo-base/etc/keystore)
2017-09-20 16:23:05.381:INFO:oejus.SslContextFactory:main: x509=X509@475c9c31(mykey,h=[],w=[]) for SslContextFactory@57db2b13(file:///installs/repository/jetty/demo-base/etc/keystore,ffile:///installs/repository/jetty/demo-base/etc/keystore)
2017-09-20 16:23:05.523:INFO:oejs.AbstractConnector:main: Started ServerConnector@53f3bdbd{SSL,[ssl, http/1.1]}{0.0.0.0:8443}
2017-09-20 16:23:05.524:INFO:oejs.Server:main: Started @2390ms
You can visit this demo server by pointing a browser at http://localhost:8080, which will now show a welcome page and several demo/test web applications.
The demonstration web applications are not necessarily secure and should not be deployed in production web servers. |
You can see the configuration of the demo-base
by using the following commands:
> cd $JETTY_HOME/demo-base/
> java -jar $JETTY_HOME/start.jar --list-modules
...
> java -jar $JETTY_HOME/start.jar --list-config
...
The --list-modules
command will return a complete list of available and enabled modules for the server.
It will also display the location of the modules, how and in what order they are implemented, dependent modules, and associated jar files.
The --list-config
command displays a trove of information about the server including the Java and Jetty environments, the configuration order, any JVM arguments or System Properties set, general server properties, a full listing of the Jetty server class path, and active Jetty XML files.
Common Jetty Configuration
Creating a new Jetty Base
The demo-base
directory described earlier is an example of the jetty.base
mechanism.
A Jetty base directory allows the configuration and web applications of a server instance to be stored separately from the Jetty distribution, so that upgrades can be done with minimal disruption.
Jetty’s default configuration is based on two properties:
- jetty.home
-
The property that defines the location of the Jetty distribution, its libs, default modules and default XML files (typically start.jar, lib, etc).
- jetty.base
-
The property that defines the location of a specific implementation of a Jetty server, its configuration, logs and web applications (typically start.d/*.ini files, logs and webapps).
Your Jetty Home directory should be treated as a standard of truth and remain unmodified or changed. Changes or additions to your configuration should take place in the Jetty Base directory. |
The jetty.home
and jetty.base
properties may be explicitly set on the command line, or they can be inferred from the environment if used with commands like:
> cd $JETTY_BASE
> java -jar $JETTY_HOME/start.jar
The following commands create a new base directory, enables both the HTTP connector and the web application deployer modules, and copies a demo webapp to be deployed:
> JETTY_BASE=/tmp/mybase
> mkdir $JETTY_BASE
> cd $JETTY_BASE
> java -jar $JETTY_HOME/start.jar
WARNING: Nothing to start, exiting ...
Usage: java -jar start.jar [options] [properties] [configs]
java -jar start.jar --help # for more information
> java -jar $JETTY_HOME/start.jar --create-startd
INFO : Base directory was modified
> java -jar $JETTY_HOME/start.jar --add-to-start=http,deploy
INFO: server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO: http initialised in ${jetty.base}/start.d/http.ini
INFO: security initialised (transitively) in ${jetty.base}/start.d/security.ini
INFO: servlet initialised (transitively) in ${jetty.base}/start.d/servlet.ini
INFO: webapp initialised (transitively) in ${jetty.base}/start.d/webapp.ini
INFO: deploy initialised in ${jetty.base}/start.d/deploy.ini
MKDIR: ${jetty.base}/webapps
INFO: Base directory was modified
> cp $JETTY_HOME/demo-base/webapps/async-rest.war webapps/ROOT.war
> java -jar $JETTY_HOME/start.jar
2015-06-04 11:10:16.286:INFO::main: Logging initialized @274ms
2015-06-04 11:10:16.440:INFO:oejs.Server:main: jetty-9.3.0.v20150601
2015-06-04 11:10:16.460:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///tmp/mybase/webapps/] at interval 1
2015-06-04 11:10:16.581:WARN::main: async-rest webapp is deployed. DO NOT USE IN PRODUCTION!
2015-06-04 11:10:16.589:INFO:oejw.StandardDescriptorProcessor:main: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
2015-06-04 11:10:16.628:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@1a407d53{/,[file:///tmp/jetty-0.0.0.0-8080-ROOT.war-_-any-4510228025526425427.dir/webapp/, jar:file:///tmp/jetty-0.0.0.0-8080-ROOT.war-_-any-4510228025526425427.dir/webapp/WEB-INF/lib/example-async-rest-jar-{VERSION}.jar!/META-INF/resources],AVAILABLE}{/ROOT.war}
2015-06-04 11:10:16.645:INFO:oejs.ServerConnector:main: Started ServerConnector@3abbfa04{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2015-06-04 11:10:16.646:INFO:oejs.Server:main: Started @634ms
Changing the Jetty Port
You can configure Jetty to run on a different port by setting the jetty.http.port
property on the command line:
> cd $JETTY_BASE
> java -jar $JETTY_HOME/start.jar jetty.http.port=8081
...
When the server starts, it will now run on port 8081
.
It is important to note that setting properties on the command line will only take affect for that instance of the server.
To change the configuration so that the server will always start on the desired port, you will need to edit the start.d/http.ini
The configuration by properties works via the following chain:
For more information see the Quickstart Configuration Guide and Configuring Connectors. |
Adding SSL for HTTPS & HTTP2
Building on the example above, we can activate additional modules to add support HTTPS and HTTP2 for the server. To add HTTPS and HTTP2 connectors to a Jetty configuration, the modules can be activated by the following command:
> java -jar $JETTY_HOME/start.jar --add-to-start=https,http2
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: alpn-impl/alpn-8
+ ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
+ ALPN replaces/modifies OpenJDK classes in the sun.security.ssl package.
+ http://github.com/jetty-project/jetty-alpn
+ http://openjdk.java.net/legal/gplv2+ce.html
Proceed (y/N)? y
INFO : alpn-impl/alpn-1.8.0_92 dynamic dependency of alpn-impl/alpn-8
INFO : alpn transitively enabled, ini template available with --add-to-start=alpn
INFO : alpn-impl/alpn-8 dynamic dependency of alpn
INFO : http2 initialized in ${jetty.base}/start.d/http2.ini
INFO : https initialized in ${jetty.base}/start.d/https.ini
INFO : ssl transitively enabled, ini template available with --add-to-start=ssl
MKDIR : ${jetty.base}/lib/alpn
DOWNLD: https://repo1.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.8.v20160420/alpn-boot-8.1.8.v20160420.jar to ${jetty.base}/lib/alpn/alpn-boot-8.1.8.v20160420.jar
MKDIR : ${jetty.base}/etc
COPY : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
INFO : Base directory was modified
> java -jar $JETTY_HOME/start.jar
[...]
2017-05-22 12:48:23.271:INFO:oejs.AbstractConnector:main: Started ServerConnector@134d0064{SSL,[ssl, alpn, h2, http/1.1]}{0.0.0.0:8443}
[...]
The --add-to-start
command sets up the effective command line in the ini files to run an ssl connection that supports the HTTPS and HTTP2 protocols as follows:
-
transitively enabled the
ssl
module that configures an SSL connector (eg port, keystore etc.) by addingetc/jetty-ssl.xml
andetc/jetty-ssl-context.xml
to the effective command line. -
transitively enabled the
alpn
module that configures protocol negotiation on the SSL connector by addingetc/jetty-alpn.xml
to the effective command line. -
creates
start.d/https.ini
that configures the HTTPS protocol on the SSL connector by addingetc/jetty-https.xml
to the effective command line. -
creates
start.d/http2.ini
that configures the HTTP/2 protocol on the SSL connector by addingetc/jetty-http2.xml
to the effective command line. -
checks for the existence of a
etc/keystore
file and if not present, downloads a demonstration keystore file.
Changing the Jetty HTTPS Port
You can configure the SSL connector to run on a different port by setting the jetty.ssl.port
property on the command line:
> cd $JETTY_BASE
> java -jar $JETTY_HOME/start.jar jetty.ssl.port=8444
Alternatively, property values can be added to the effective command line built from the start.ini
file or start.d/*.ini
files, depending on your set up.
Please see the section on Start.ini vs. Start.d for more information.
More start.jar Options
The job of the start.jar
is to interpret the command line, start.ini
and start.d
directory (and associated .ini files) to build a Java classpath and list of properties and configuration files to pass to the main class of the Jetty XML configuration mechanism.
The start.jar
mechanism has many options which are documented in the Starting Jetty administration section and you can see them in summary by using the command:
> java -jar $JETTY_HOME/start.jar --help
Deploying Web Applications
Jetty server instances that configure the deploy module will have a web application deployer that hot deploys files found in the webapps
directory.
Standard WAR files and Jetty configuration files that are placed in the webapps
directory are hot deployed to the server with the following conventions:
-
A directory called
example/
is deployed as a standard web application if it contains aWEB-INF/
subdirectory, otherwise it is deployed as context of static content. The context path is/example
(that is,http://localhost:8080/example/
) unless the base name is ROOT (case insensitive), in which case the context path is /. If the directory name ends with ".d" it is ignored (but may be used by explicit configuration). -
A file called
example.war
is deployed as a standard web application with the context path/example
(that is,http://localhost:8080/example/
). If the base name isROOT
(case insensitive), the context path is/
. Ifexample.war
andexample/
exist, only the WAR is deployed (which may use the directory as an unpack location). -
An XML file like
example.xml
is deployed as a context whose configuration is defined by the XML. The configuration itself must set the context path. Ifexample.xml
andexample.war
exists, only the XML is deployed (which may use the WAR in its configuration).
If you have a standard web application, you can hot deploy it into Jetty by copying it into the webapps
directory.
Jetty Demonstration Web Applications
The demo-base/webapps directory contains the following deployable and auxiliary files:
ROOT/
-
A directory of static content that is deployed to the root context / due to it’s name. Contains the Jetty demo welcome page.
test.d
-
A directory containing additional configuration files used by
test.xml
to inject extra configuration intotest.war
. test.xml
-
A context configuration file that configures and deploys
test.war.
The additional configuration includes the context path as well as setting additional descriptors found in thetest.d
directory. test.war
-
The demonstration web application that is configured and deployed by
test.xml
. async-rest.war
-
A web application demonstration of asynchronous REST to eBay, automatically deployed to /async-rest based on the file name.
test-jaas.war
-
A demonstration web application utilizing JAAS for authentication.
test-jaas.xml
-
A context configuration file that configures
test-jaas.war
. Additional configuration includes setting up the LoginService for authentication and authorization. test-jndi.war
-
A demonstration web application showing the use of JNDI.
test-jndi.xml
-
A context configuration file that configures
test-jndi.war
. Additional configuration includes defining objects in the naming space that can be referenced from the webapp. test-spec.war
-
A demonstration web application that shows the use of annotations, fragments,
ServletContainerInitializers
and other Servlet Specification 3.0/3.1 features. test-spec.xml
-
A context configuration file that configures
test-spec.war
. Additional configuration includes setting up some objects in the naming space that can be referenced by annotations. javadoc-proxy.war
-
A demonstration web application that uses a transparent proxy to serve the Jetty source Javadoc from the Eclipse Jetty website.
example-moved.xml
-
A demonstration context configuration file that shows how to use the
MovedContextHandler
to redirect from one path to another.
An Introduction to Jetty Configuration
How to Configure Jetty
To understand Jetty configuration, you need to understand the "How" and the "What". This section covers how to configure Jetty in terms of what mechanisms exist to perform configuration. The next section gives an overview of the action components and fields that you can configure with these mechanisms.
Jetty POJO Configuration
The core components of Jetty are Plain Old Java Objects (POJOs) The process of configuring Jetty is mostly the process of instantiating, assembling and setting fields on the Jetty POJOs. This can be achieved by:
-
Writing Java code to directly instantiate and assemble Jetty objects. This is referred to as Embedding Jetty.
-
Using Jetty XML configuration, which is an Inversion of Control (IoC) framework, to instantiate and assemble Jetty objects as XML objects. The
etc/jetty.xml
file is the main Jetty XML configuration file, but there are many otheretc/jetty-feature.xml
files included in the Jetty distribution. -
Using a third party IoC framework like Spring, to instantiate and assemble Jetty objects as Spring beans.
Because the main Jetty configuration is done by IoC, the Jetty API documentation is the ultimate configuration reference.
Jetty Start Configuration Files
The Jetty distribution uses the following configuration files to instantiate, inject and start server via the start.jar
mechanism.
ini
files-
The Jetty Start mechanism uses the command line, the
$JETTY_BASE/start.ini
and/or$JETTY_BASE/start.d/*.ini
files to create an effective command line of arguments. Arguments may be:-
Module activations in the form
--module=name
-
Properties in the form of
name=value
, used to parameterize Jetty IoC XML -
XML files in Jetty IoC (or Spring) XML format
-
A standard Java property file containing additional start properties
-
Other start.jar options (see
java -jar start.jar --help
) -
Some JVM options in combination with
--exec
, such as-Xbootclasspath
.
-
It is the |
mod
files-
The
$JETTY_HOME/modules/*.mod
files contain the definition of modules that can be activated by--module=name
. Eachmod
file defines:-
Module dependencies for ordering and activation
-
The libraries needed by the module to be added to the classpath
-
The XML files needed by the module to be added to the effective command line
-
Files needed by the activated module
-
A template
ini
file to be used when activating the--add-to-start=name
optionTypically module files are rarely edited and only then for significant structural changes. The
.mod
files are normally located in$JETTY_HOME/modules/
, but extra or edited modules may be added to$JETTY_BASE/module
. If module changes are required, it is best practice to copy the particular.mod
file from$JETTY_HOME/modules/
to$JETTY_BASE/modules/
before being modified.
-
- XML files
-
XML files in Jetty IoC XML format or Spring IoC format are listed either on the command line, in
ini
files, or are added to the effective command line by a module definition. The XML files instantiate and inject the actual Java objects that comprise the server, connectors and contexts. Because Jetty IoC XML files use properties, most common configuration tasks can be accomplished without editing these XML files and can instead be achieved by editing the property in the correspondingini
files. XML files are normally located in$JETTY_HOME/etc/
, but extra or edited XML files may be added to$JETTY_BASE/etc/
. Note If XML configuration changes are required, it is best practice to copy the XML file from$JETTY_HOME/etc/
to$JETTY_BASE/etc/
before being modified.
Below is an illustration of how the various Jetty configuration files (ini
, mod
and XML) are related:
A Closer Look
To put it simply: XML files are responsible for instantiating the Jetty POJOs that make up the server. They define properties which users can modify to meet the needs of their server. These XML files are broken up by type in the distribution so they can be consumed as a user/server needs them. For example, a server may need HTTP and HTTPS functionality, but opt out of using HTTP/2 and Websocket.
Module files allow users to enable and remove functionality quickly and easily from their server implementation.
They include a template of the different properties included in the associated XML file, as well as a pointer to the XML or JAR file(s) they are referencing.
When a module is activated these properties are added to a related ini
file where users can configure them to meet their needs.
We will discuss modules in further detail in an upcoming chapter.
Ini files are where most users will spend the bulk of their time editing the configuration for their server. As mentioned, they contain properties which were defined in their associated XML files which in turn reference Jetty Java objcts.
This can be a bit overwhelming at first, so let’s look at an example - in this case the http
module.
We will work backwards from an ini file to the associated module and then the XML file in question.
First up, the http.ini
file.
If we take a look at it’s contents, we will see the following:
$ cat start.d/http.ini
# ---------------------------------------
# Module: http
# Enables a HTTP connector on the server.
# By default HTTP/1 is support, but HTTP2C can
# be added to the connector with the http2c module.
# ---------------------------------------
--module=http
### HTTP Connector Configuration
## Connector host/address to bind to
# jetty.http.host=0.0.0.0
## Connector port to listen on
# jetty.http.port=8080
## Connector idle timeout in milliseconds
# jetty.http.idleTimeout=30000
## Number of acceptors (-1 picks default based on number of cores)
# jetty.http.acceptors=-1
## Number of selectors (-1 picks default based on number of cores)
# jetty.http.selectors=-1
## ServerSocketChannel backlog (0 picks platform default)
# jetty.http.acceptQueueSize=0
## Thread priority delta to give to acceptor threads
# jetty.http.acceptorPriorityDelta=0
## Reserve threads for high priority tasks (-1 use a heuristic, 0 no reserved threads)
# jetty.http.reservedThreads=-1
## Connect Timeout in milliseconds
# jetty.http.connectTimeout=15000
## HTTP Compliance: RFC7230, RFC2616, LEGACY
# jetty.http.compliance=RFC7230
So what do we see?
We have a module name, the module activation (--module=http
), as well as a description and what look like properties to configure.
Those will some scripting/coding experience might notice that most of the lines are commented out with #
and you’d be correct.
When a module is enabled and an ini
file is created, all of the properties you see here were set to these defaults - the server is already using the values shown
If you wanted to change one of the properties though, say jetty.http.port
, you’d simply uncomment the line and change the value.
For example:
$ cat start.d/http.ini
# ---------------------------------------
# Module: http
# Enables a HTTP connector on the server.
# By default HTTP/1 is support, but HTTP2C can
# be added to the connector with the http2c module.
# ---------------------------------------
--module=http
### HTTP Connector Configuration
## Connector host/address to bind to
# jetty.http.host=0.0.0.0
## Connector port to listen on
jetty.http.port=1234
...
As seen before, these properties were populated in this ini file based on a related module.
Standard Jetty modules live in the Home of the Jetty Distribution in the aptly named modules
directory.
So let’s take a quick look at the associated $JETTY_HOME/modules/http.mod
file:
$ cat $JETTY_HOME/modules/http.mod
[description]
Enables a HTTP connector on the server.
By default HTTP/1 is support, but HTTP2C can
be added to the connector with the http2c module.
[tags]
connector
http
[depend]
server
[xml]
etc/jetty-http.xml
[ini-template]
### HTTP Connector Configuration
## Connector host/address to bind to
# jetty.http.host=0.0.0.0
## Connector port to listen on
# jetty.http.port=8080
## Connector idle timeout in milliseconds
# jetty.http.idleTimeout=30000
...
At first blush, it looks remarkable similar to the ini
file we just looked at.
We still have a description and the properties we could edit, but now we also have several other sections.
These other sections will be looked at further in our chapter on modules, but for now it is worth noting the [xml]
and [ini-template]
sections.
As you could probably have puzzled out, the [ini-template]
contains a template (go figure) for properties to be placed in the associated ini
file when a module is activated.
The [xml]
section refers to the file and location of the XML file these properties are based on.
It is important to note that not every module file will have the same sections, but most should look structurally the same.
Now that we know what XML file these properties relate to, we can navigate to it and have a look.
$ cat $JETTY_HOME/etc/jetty-http.xml
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<!-- ============================================================= -->
<!-- Configure the Jetty Server instance with an ID "Server" -->
<!-- by adding a HTTP connector. -->
<!-- This configuration must be used in conjunction with jetty.xml -->
<!-- ============================================================= -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Add a HTTP Connector. -->
<!-- Configure an o.e.j.server.ServerConnector with a single -->
<!-- HttpConnectionFactory instance using the common httpConfig -->
<!-- instance defined in jetty.xml -->
<!-- -->
<!-- Consult the javadoc of o.e.j.server.ServerConnector and -->
<!-- o.e.j.server.HttpConnectionFactory for all configuration -->
<!-- that may be set here. -->
<!-- =========================================================== -->
<Call name="addConnector">
<Arg>
<New id="httpConnector" class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="acceptors" type="int"><Property name="jetty.http.acceptors" deprecated="http.acceptors" default="-1"/></Arg>
<Arg name="selectors" type="int"><Property name="jetty.http.selectors" deprecated="http.selectors" default="-1"/></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config"><Ref refid="httpConfig" /></Arg>
<Arg name="compliance"><Call class="org.eclipse.jetty.http.HttpCompliance" name="valueOf"><Arg><Property name="jetty.http.compliance" default="RFC7230"/></Arg></Call></Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="host"><Property name="jetty.http.host" deprecated="jetty.host" /></Set>
<Set name="port"><Property name="jetty.http.port" deprecated="jetty.port" default="8080" /></Set>
<Set name="idleTimeout"><Property name="jetty.http.idleTimeout" deprecated="http.timeout" default="30000"/></Set>
<Set name="acceptorPriorityDelta"><Property name="jetty.http.acceptorPriorityDelta" deprecated="http.acceptorPriorityDelta" default="0"/></Set>
<Set name="acceptQueueSize"><Property name="jetty.http.acceptQueueSize" deprecated="http.acceptQueueSize" default="0"/></Set>
<Get name="SelectorManager">
<Set name="connectTimeout"><Property name="jetty.http.connectTimeout" default="15000"/></Set>
<Set name="reservedThreads"><Property name="jetty.http.reservedThreads" default="-2"/></Set>
</Get>
</New>
</Arg>
</Call>
</Configure>
Now we can see where those properties in our ini
and module files came from.
In Jetty XML files, Jetty objects come to life; defined properties are set which link back to the jar libraries and run the server to a user’s specification.
It is important to remember that you should not modify the XML files in your |
Other Configuration Files
In addition to the configuration files described above, the configuration of the server can use the following file types:
- Context XML files
-
Any XML files in Jetty IoC XML format or Spring IoC format that is discovered in the
/webapps
directory are used by the deploy module to instantiate and injectHttpContext
instances to create a specific context. These may be standard web applications or bespoke contexts created from special purpose handlers. - web.xml
-
The Servlet Specification defines the
web.xml
deployment descriptor that defines and configures the filters, servlets and resources a web application uses. The JettyWebAppContext
component uses this XML format to:-
Set up the default configuration of a web application context.
-
Interpret the application-specific configuration supplied with a web application in the
WEB-INF/web.xml
file. -
Interpret descriptor fragments included in the
META-INF
directory of Jar files withinWEB-INF/lib.
Normally the
web.xml
file for a web application is found in theWEB-INF/web.xml
location within the war file/directory or asweb.xml
fragments with.jar
files found inWEB-INF/lib
. Jetty also supports multipleweb.xml
files so that a default descriptor may be applied beforeWEB-INF/web.xml
(typically set toetc/webdefault.xml
by the deploy module) and an override descriptor may be applied afterWEB-INF/web.xml
(typically set by a context XML file seetest.xml
)
-
- Property Files
-
Standard Java property files are also used for Jetty configuration in several ways:
-
To parameterize Jetty IoC XML via the use of the
Property
element. -
To configure the default logging mechanism (
StdErrLog
). Other logging frameworks can be utilized and also use property files (for example,log4j
). -
As a simple database for login usernames and credentials.
-
Jetty IoC XML format
To understand the Jetty IoC XML format, consider the following example of an embedded Jetty server instantiated and configured in Java:
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.embedded;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
public class ExampleServer
{
public static Server createServer(int port)
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(port);
server.setConnectors(new Connector[]{connector});
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
context.addServlet(HelloServlet.class, "/hello");
context.addServlet(AsyncEchoServlet.class, "/echo/*");
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[]{context, new DefaultHandler()});
server.setHandler(handlers);
return server;
}
public static void main(String[] args) throws Exception
{
int port = ExampleUtil.getPort(args, "jetty.http.port", 8080);
Server server = createServer(port);
server.start();
server.join();
}
}
Jetty IoC XML format allows you to instantiate and configure the exact same server in XML without writing any java code:
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="ExampleServer" class="org.eclipse.jetty.server.Server">
<Set name="connectors">
<Array type="org.eclipse.jetty.server.Connector">
<Item>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg><Ref refid="ExampleServer"/></Arg>
<Set name="port">
<Property name="http.port" default="8080" />
</Set>
</New>
</Item>
</Array>
</Set>
<New id="context" class="org.eclipse.jetty.servlet.ServletContextHandler">
<Set name="contextPath">/hello</Set>
<Call name="addServlet">
<Arg>org.eclipse.jetty.embedded.HelloServlet</Arg>
<Arg>/</Arg>
</Call>
</New>
<Set name="handler">
<New class="org.eclipse.jetty.server.handler.HandlerCollection">
<Set name="handlers">
<Array type="org.eclipse.jetty.server.Handler">
<Item>
<Ref refid="context" />
</Item>
<Item>
<New class="org.eclipse.jetty.server.handler.DefaultHandler" />
</Item>
</Array>
</Set>
</New>
</Set>
</Configure>
What to Configure in Jetty
This section gives an overview of the components of Jetty you typically configure using the mechanisms outlined in the previous section. Jetty Architecture describes the structure of a Jetty server, which is good background reading to understand configuration, and is vital if you want to change the structure of the server as set up by the default configurations in the Jetty distribution. However, for most purposes, configuration is a matter of identifying the correct configuration file and modifying existing configuration values.
Configuring the Server
The Server instance is the central coordination object of a Jetty server; it provides services and life cycle management for all other Jetty server components.
In the standard Jetty distribution, the core server configuration is in etc/jetty.xml
file, but you can mix in other server configurations which can include:
- ThreadPool
-
The Server instance provides a ThreadPool instance that is the default Executor service other Jetty server components use. The prime configuration of the thread pool is the maximum and minimum size and is set in
start.ini
orstart.d/threadpool.ini
. - Handlers
-
A Jetty server can have only a single Handler instance to handle incoming HTTP requests. However a handler may be a container or wrapper of other handlers forming a tree of handlers that typically handle a request as a collaboration between the handlers from a branch of the tree from root to leaf. The default handler tree set up in the
etc/jetty.xml
file is a Handler Collection containing a Context Handler Collection and the Default Handler. The Context Handler Collection selects the next handler by context path and is where deployed Context Handler and Web Application Contexts are added to the handler tree. The Default Handler handles any requests not already handled and generates the standard 404 page. Other configuration files may add handlers to this tree (for example,jetty-rewrite.xml
,jetty-requestlog.xml
) or configure components to hot deploy handlers (for example,jetty-deploy.xml
). - Server Attributes
-
The server holds a generic attribute map of strings to objects so that other Jetty components can associate named objects with the server, and if the value objects implement the LifeCycle interface, they are started and stopped with the server. Typically server attributes hold server-wide default values.
- Server fields
-
The server also has some specific configuration fields that you set in
start.ini
orstart.d/server.ini
for controlling, among other things, the sending of dates and versions in HTTP responses. - Connectors
-
The server holds a collection of connectors that receive connections for HTTP and the other protocols that Jetty supports. The next section, Configuring Connectors describes configuration of the connectors themselves. For the server you can either set the collection of all connectors or add/remove individual connectors.
- Services
-
The server can hold additional service objects, sometimes as attributes, but often as aggregated LifeCycle beans. Examples of services are Login Services and DataSources, which you configure at the server level and then inject into the web applications that use them.
Configuring Connectors
A Jetty Server Connector is a network end point that accepts connections for one or more protocols which produce requests and/or messages for the Jetty server.
In the standard Jetty server distribution, several provided configuration files add connectors to the server for various protocols and combinations of protocols: http.ini
, https.ini
and jetty-http2.xml
.
The configuration needed for connectors is typically:
- Port
-
The TCP/IP port on which the connector listens for connections is set using the the XML Property element which looks up the
jetty.http.port
(orjetty.ssl.port
) property, and if not found defaults to 8080 (or 8443 for TLS). - Host
-
You can configure a host either as a host name or IP address to identify a specific network interface on which to listen. If not set, or set to the value of 0.0.0.0, the connector listens on all local interfaces. The XML Property element is used to look up the host value from the
jetty.host
property. - Idle Timeout
-
The time in milliseconds that a connection can be idle before the connector takes action to close the connection.
- HTTP Configuration
-
Connector types that accept HTTP semantics (including HTTP, HTTPS and HTTP2) are configured with a
HttpConfiguration
instance that contains common HTTP configuration that is independent of the specific wire protocol used. Because these values are often common to multiple connector types, the standard Jetty Server distribution creates a singleHttpConfiguration
in thejetty.xml
file which is used via the XML Ref element in the specific connector files. - SSL Context Factory
-
The TLS connector types (HTTPS and HTTP2) configure an SSL Context Factory with the location of the server keystore and truststore for obtaining server certificates.
Virtual hosts are not configured on connectors. You must configure individual contexts with the virtual hosts to which they respond. |
Prior to Jetty 9, the type of the connector reflected both the protocol supported (HTTP, HTTPS, AJP, SPDY), and the nature of the implementation (NIO or BIO).
From Jetty 9 onwards there is only one prime Connector type ( |
Configuring Contexts
A Jetty context is a handler that groups other handlers under a context path together with associated resources and is roughly equivalent to the standard ServletContext API. A context may contain either standard Jetty handlers or a custom application handler.
The servlet specification defines a web application.
In Jetty a standard web application is a specialized context that uses a standard layout and |
Configuration values that are common to all contexts are:
- contextPath
-
The contextPath is a URL prefix that identifies which context a HTTP request is destined for. For example, if a context has a context path
/foo
, it handles requests to/foo
,/foo/index.html
,/foo/bar/
, and/foo/bar/image.png
but it does not handle requests like/
,/other/
, or/favicon.ico
. A context with a context path of / is called the root context.The context path can be set by default from the deployer (which uses the filename as the basis for the context path); or in code; or it can be set by a Jetty IoC XML that is either applied by the deployer or found in the
WEB-INF/jetty-web.xml
file of a standard web app context. - virtualHost
-
A context may optionally have one or more virtual hosts set. Unlike the host set on a connector (which selects the network interface on which to listen), a virtual host does not set any network parameters. Instead a virtual host represents an alias assigned by a name service to an IP address, which may have many aliases. To determine which virtual host a request is intended for, the HTTP client (browser) includes in the request the name used to look up the network address. A context with a virtual host set only handles requests that have a matching virtual host in their request headers.
- classPath
-
A context may optionally have a classpath, so that any thread that executes a handler within the context has a thread context classloader set with the classpath. A standard web application has the classpath initialized by the
WEB-INF/lib
andWEB-INF/classes
directory and has additional rules about delegating classloading to the parent classloader. All contexts may have additional classpath entries added. - attributes
-
Attributes are arbitrary named objects that are associated with a context and are frequently used to pass entities between a web application and its container. For example the attribute
javax.servlet.context.tempdir
is used to pass the File instance that represents the assigned temporary directory for a web application. - resourceBase
-
The resource base is a directory (or collection of directories or URL) that contains the static resources for the context. These can be images and HTML files ready to serve or JSP source files ready to be compiled. In traditional web servers this value is often called the docroot.
Context Configuration by API
In an embedded server, you configure contexts by directly calling the ContextHandler API as in the following example:
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.embedded;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
public class OneContext
{
public static Server createServer(int port)
{
Server server = new Server(port);
// Add a single handler on context "/hello"
ContextHandler context = new ContextHandler();
context.setContextPath("/hello");
context.setHandler(new HelloHandler());
// Can be accessed using http://localhost:8080/hello
server.setHandler(context);
return server;
}
public static void main(String[] args) throws Exception
{
int port = ExampleUtil.getPort(args, "jetty.http.port", 8080);
Server server = createServer(port);
// Start the server
server.start();
server.join();
}
}
Context Configuration by IoC XML
You can create and configure a context entirely by IoC XML (either Jetty’s or Spring). The deployer discovers and hot deploys context IoC descriptors like the following which creates a context to serve the Javadoc from the Jetty distribution:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC
"-//Jetty//Configure//EN"
"https://eclipse.org/jetty/configure_9_3.dtd">
<!--
Configure a custom context for serving javadoc as static resources
-->
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
<Set name="contextPath">/javadoc</Set>
<Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/javadoc/</Set>
<Set name="handler">
<New class="org.eclipse.jetty.server.handler.ResourceHandler">
<Set name="welcomeFiles">
<Array type="String">
<Item>index.html</Item>
</Array>
</Set>
<Set name="cacheControl">max-age=3600,public</Set>
</New>
</Set>
</Configure>
Configuring Web Applications
The servlet specification defines a web application, which when packaged as a zip is called WAR file (Web application ARchive). Jetty implements both WAR files and unpacked web applications as a specialized context that is configured by means of:
-
A standard layout which sets the location of the resourceBase (the root of the WAR) and initializes the classpath from jars found in
WEB-INF/lib
and classes found inWEB-INF/classes
. -
The standard
WEB-INF/web.xml
deployment descriptor which is parsed to define and configure init parameters, filters, servlets, listeners, security constraints, welcome files and resources to be injected. -
A default
web.xml
format deployment descriptor provided either by Jetty or in configuration configures the JSP servlet and the default servlet for handling static content. The standardweb.xml
may override the defaultweb.xml
. -
Annotations discovered on classes in Jars contained in
WEB-INF/lib
can declare additional filters, servlets and listeners. -
Standard deployment descriptor fragments discovered in Jars contained in
WEB-INF/lib
can declare additional init parameters, filters, servlets, listeners, security constraints, welcome files and resources to be injected. -
An optional
WEB-INF/jetty-web.xml
file may contain Jetty IoC configuration to configure the Jetty specific APIs of the context and handlers.
Because these configuration mechanisms are contained within the WAR file (or unpacked web application), typically a web application contains much of its own configuration and deploying a WAR is often just a matter of dropping the WAR file in to the webapps directory that is scanned by the Jetty deployer.
If you need to configure something within a web application, often you do so by unpacking the WAR file and editing the web.xml
and other configuration files.
However, both the servlet standard and some Jetty features allow for other configuration to be applied to a web application externally from the WAR:
-
Configured data sources and security realms in the server can be injected into a web application either explicitly or by name matching.
-
Jetty allows one or more override deployment descriptors, in
web.xml
format, to be set on a context (via code or IoC XML) to amend the configuration set by the default and standardweb.xml
. -
The normal Jetty Java API may be called by code or IoC XML to amend the configuration of a web application.
Setting the Context Path
The web application standard provides no configuration mechanism for a web application or WAR file to set its own contextPath
.
By default the deployer uses conventions to set the context path:
If you deploy a WAR file called foobar.WAR
, the context path is /foobar
; if you deploy a WAR file called ROOT.WAR
the context path is /
.
However, it is often desirable to explicitly set the context path so that information (for example, version numbers) may be included in the filename of the WAR. Jetty allows the context Path of a WAR file to be set internally (by the WAR itself) or externally (by the deployer of the WAR).
To set the contextPath from within the WAR file, you can include a WEB-INF/jetty-web.xml
file which contains IoC XML to set the context path:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC
"-//Jetty//Configure//EN"
"https://eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/contextpath</Set>
</Configure>
Alternately, you can configure the classpath externally without the need to modify the WAR file itself. Instead of allowing the WAR file to be discovered by the deployer, an IoC XML file may be deployed that both sets the context path and declares the WAR file that it applies to:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC
"-//Jetty//Configure//EN"
"https://eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test.war</Set>
<Set name="contextPath">/test</Set>
</Configure>
An example of setting the context path is included with the Jetty distribution in $JETTY_HOME/webapps/test.xml
.
Web Application Deployment
Jetty is capable of deploying a variety of Web Application formats.
This is accomplished via scans of the ${jetty.base}/webapps
directory for contexts to deploy.
A Context can be any of the following:
-
A standard WAR file. (must in “.war”).
-
A directory containing an expanded WAR file. (must contain
{dir}/WEB-INF/web.xml
file). -
A directory containing static content.
-
A XML descriptor in Jetty XML Syntax that configures a ContextHandler instance (Such as a WebAppContext).
The new WebAppProvider will attempt to avoid double deployments during the directory scan with the following heuristics:
-
Hidden files (starting with
"."
) are ignored -
Directories with names ending in
".d"
are ignored -
If a directory and matching WAR file exist with the same base name (eg:
foo/
andfoo.war
), then the directory is assumed to be the unpacked WAR and only the WAR is deployed (which may reuse the unpacked directory) -
If a directory and matching XML file exists (eg:
foo/
andfoo.xml
), then the directory is assumed to be an unpacked WAR and only the XML is deployed (which may use the directory in its own configuration) -
If a WAR file and matching XML file exist (eg:
foo.war
andfoo.xml
), then the WAR is assumed to be configured by the XML and only the XML is deployed.
In prior versions of Jetty there was a separate ContextDeployer that provided XML-based deployment. As of Jetty 9 the ContextDeployer no longer exists and its functionality has been merged with the new WebAppProvider to avoid double deployment scenarios. |
Setting an Authentication Realm
The authentication method and realm name for a standard web application may be set in the web.xml
deployment descriptor with elements like:
...
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Test Realm</realm-name>
</login-config>
...
This example declares that the BASIC authentication mechanism will be used with credentials validated against a realm called "Test Realm." However the standard does not describe how the realm itself is implemented or configured. In Jetty, there are several realm implementations (called LoginServices) and the simplest of these is the HashLoginService, which can read usernames and credentials from a Java properties file.
To configure an instance of HashLoginService that matches the "Test Realm" configured above, the following $JETTY_BASE/etc/test-realm.xml
IoC XML file should be passed on the command line or set in start.ini
or start.d/server.ini
.
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Configure Authentication Login Service -->
<!-- Realms may be configured for the entire server here, or -->
<!-- they can be configured for a specific web app in a context -->
<!-- configuration (see $(jetty.home)/webapps/test.xml for an -->
<!-- example). -->
<!-- =========================================================== -->
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set>
<Set name="config"><Property name="jetty.demo.realm" default="etc/realm.properties"/></Set>
<Set name="hotReload">false</Set>
</New>
</Arg>
</Call>
<Get class="org.eclipse.jetty.util.log.Log" name="rootLogger">
<Call name="warn"><Arg>demo test-realm is deployed. DO NOT USE IN PRODUCTION!</Arg></Call>
</Get>
</Configure>
This creates and configures the LoginService as an aggregate bean on the server. When a web application is deployed that declares a realm called "Test Realm," the server beans are searched for a matching Login Service.
Jetty Configuration Guide
Deploying to Jetty
This chapter discusses various ways to deploy applications with Jetty. Topics range from deployment bindings to deploying third party products. It also includes information about the Deployment Manager and WebApp Provider.
Anatomy of a Web Application
The standard Jetty distribution is capable of deploying standard Servlet Spec Web Applications and Jetty internal ContextHandler deployment descriptors, or even a mix of the two.
Web Applications are deployable collections of dynamic (servlets, filters, jsps, etc..) and static content, support libraries, and descriptive metadata that are bound to a specific context path on Jetty.
Ultimately the format and layout are defined by the Servlet Spec, and the official Servlet Spec documentation should be consulted for a more detailed understanding of Web Application layout and structure; however, this will outline basics about how Jetty views these requirements.
Web Applications can be bundled into a single Web Archive (WAR file) or as a directory tree.
/WEB-INF/
-
Special Servlet API defined directory used to store anything related to the Web Application that are not part of the public access of the Web Application. If there is content that is accessed by a Web Application internally, but that should also never be accessed directly by a web browser, this is the directory it would placed in.
/WEB-INF/web.xml
-
Required deployment descriptor defining various behavior of the Web Application.
/WEB-INF/classes/
-
Location for Web Application specific compiled java classes
/WEB-INF/lib/
-
Directory for JAR files (libraries)
The Jetty internal WebAppClassloader
will load classes from /WEB-INF/classes/
first, then from jar files found in /WEB-INF/lib/
.
Automatic Web Application Deployment
The most basic technique for deploying Web Applications is to put a WAR file or Exploded WAR directory into the ${jetty.base}/webapps/
directory and let Jetty’s deployment scanner find it and deploy it under a Context path of the same name.
Only Web Applications that follow the Web Application Layout will be detected by Jetty and deployed this way.
The Context Path assigned to this automatic deployment is based the filename (or directory name) of the WAR.
File or Directory Name | Assigned Context Path |
---|---|
|
|
|
|
|
|
|
|
|
|
|
Configuring a Specific Web Application Deployment
Using the Automatic Web Application Deployment model is quick and easy, but sometimes you might need to tune certain deployment properties (for example, you want to deploy with a context path that is not based on the file name, or you want to define a special database connection pool just for this web application). You can use a Jetty Deployable Descriptor XML File to accomplish such tuning.
Jetty Deployable Descriptor XML File
Jetty supports deploying Web Applications via XML files which will build an instance of a ContextHandler that Jetty can then deploy.
Using Basic Descriptor Files
In a default Jetty installation, Jetty scans its $JETTY_HOME/webapps
directory for context deployment descriptor files.
To deploy a web application using such a file, simply place the file in that directory.
The deployment descriptor file itself is an xml file that configures a WebAppContext
class.
For a basic installation only two properties need configured:
- war
-
The filesystem path to the web application file (or directory)
- contextPath
-
The context path to use for the web application
For example, here is a descriptor file that deploys the file /opt/myapp/myapp.war
to the context path /wiki
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/wiki</Set>
<Set name="war">/opt/myapp/myapp.war</Set>
</Configure>
Both SystemProperty
and Property
elements can be used in the descriptor file.
For example, if the system property is set to myapp.home=/opt/myapp
, the previous example can be rewritten as:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/wiki</Set>
<Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
</Configure>
If the home path for an application needs altered, only the system property needs changed. This is useful if the version of an app is frequently changed.
To ensure your |
Configuring Advanced Descriptor Files
Official documentation for the for the WebAppContext
class lists all the properties that can be set.
Here are some examples that configure advanced options in the descriptor file.
This first example tells Jetty not to expand the WAR file when deploying it. This can help make it clear that users should not make changes to the temporary unpacked WAR because such changes do not persist, and therefore do not apply the next time the web application deploys.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/wiki</Set>
<Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
<Set name="extractWAR">false</Set>
</Configure>
The next example retrieves the JavaEE Servlet context and sets an initialization parameter on it.
The setAttribute
method can also be used to set a Servlet context attribute.
However, since the web.xml
for the web application is processed after the deployment descriptor, the web.xml
values overwrite identically named attributes from the deployment descriptor.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/wiki</Set>
<Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
<Get name="ServletContext">
<Call name="setInitParameter">
<Arg>myapp.config</Arg>
<Arg><SystemProperty name="myapp.home">/config/app-config.xml</Arg>
</Call>
</Get>
</Configure>
The following example sets a special web.xml
override descriptor.
This descriptor is processed after the web application’s web.xml
, so it may override identically named attributes.
This feature is useful when adding parameters or additional Servlet mappings without breaking open a packed WAR file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/wiki</Set>
<Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
<Set name="overrideDescriptor">/opt/myapp/overlay-web.xml</Set>
</Configure>
The next example configures not only the web application context, but also a database connection pool (see Datasource Examples) that the application can then use.
If the web.xml
does not include a reference to this data source, an override descriptor mechanism (as shown in the previous example) can be used to include it.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/wiki</Set>
<Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="org.apache.commons.dbcp.BasicDataSource">
<Set name="driverClassName">org.some.Driver</Set>
<Set name="url">jdbc.url</Set>
<Set name="username">jdbc.user</Set>
<Set name="password">jdbc.pass</Set>
</New>
</Arg>
</New>
</Configure>
There are many other settings that can be changed in a WebAppContext
.
The javadoc for WebAppContext
is a good source of information.
Also see the documentation on avoiding zip file exceptions for a description of WebAppContext
settings that determine such things as whether or not the war is automatically unpacked during deployment, or whether certain sections of a webapp are copied to a temporary location.
Deployment Processing of WebAppContexts
Web applications require a certain amount of processing before they can go into service: they may need to be unpacked, a special classloader created for their jar files, web.xml
and web-fragment.xml
descriptors processed, and classes scanned for annotations amongst other things.
As web applications have become more complex, Jetty has added ways to assist with customization by either broadening or lessening the amount of processing that is done at deployment time.
This section will examine this processing and it can be tailored to fit individual needs.
If instead you’re looking for information on how to configure a specific WebAppContext
- such as its context path, whether it should be unpacked or not - then you can find that in the section entitled Configuring a Specific WebApp Deployment.
Configuration Classes
As a webapp is being deployed, a series of org.eclipse.jetty.webapp.Configuration classes are applied to it, each one performing a specific function. The ordering of these Configurations is significant as subsequent Configurations tend to build on information extracted or setup in foregoing Configurations. These are the default list, in order, of Configurations that are applied to each org.eclipse.jetty.webapp.WebAppContext:
Extracts war, orders jars and defines classpath |
|
Processes a WEB-INF/web.xml file |
|
Looks in container and webapp jars for META-INF/resources and META-INF/web-fragment.xml |
|
Processes all discovered META-INF/web-fragment.xml files |
|
Processes a WEB-INF/jetty-web.xml file |
Anatomy of a Configuration Class
A Configuration class is called 5 times in different phases of the WebAppContext’s
lifecycle:
- preConfigure
-
As the
WebAppContext
is starting up this phase is executed. TheConfiguration
should discover any of the resources it will need during the subsequent phases. - configure
-
This phase is where the work of the class is done, usually using the resources discovered during the
preConfigure
phase. - postConfigure
-
This phase allows the
Configuration
to clear down any resources that may have been created during the previous 2 phases that are not needed for the lifetime of theWebAppContext
. - deconfigure
-
This phase occurs whenever a
WebAppContext
is being stopped and allows the Configuration to undo any resources/metadata that it created. AWebAppContext
should be able to be cleanly start/stopped multiple times without resources being held. - destroy
-
This phase is called when a
WebAppContext
is actually removed from service. For example, the war file associated with it is deleted from the $JETTY_HOME/webapps directory.
Each phase is called on each Configuration
class in the order in which the Configuration
class is listed.
Using the default Configuration
classes as an example, preConfigure()
will be called on WebInfConfiguration
, WebXmlConfiguration
, MetaInfConfiguration
, FragmentConfiguration
and then JettyWebXmlConfiguration
.
The cycle begins again for the configure()
phase and again for the postConfigure()
phases.
The cycle is repeated in reverse order for the deconfigure()
and eventually the destroy()
phases.
Extending Container Support by Creating Extra Configurations
As shown, there is a default set of Configurations that support basic deployment of a webapp.
JavaEE features such as JNDI and advanced servlet spec features such as annotations have not been mentioned.
Jetty’s philosophy is to allow the user to tailor the container exactly to their needs.
If these features are not needed, then Jetty does not pay the price for them - an important consideration because features such as annotations require extensive and time-consuming scanning of WEB-INF/lib
jars.
As modern webapps may have scores of these jars, it can be a source of significant deployment delay.
We will see in the section Other Configuration another helpful webapp facility that Jetty provides for cutting down the time spent analyzing jars.
Jetty makes use of the flexibility of Configurations to make JNDI and annotation support pluggable.
Firstly, lets look at how Configurations help enable JNDI.
Example: JNDI Configurations
JNDI lookups within web applications require the container to hookup resources defined in the container’s environment to that of the web application. To achieve that, we use 2 extra Configurations:
Creates |
|
Processes JNDI related aspects of |
These configurations must be added in exactly the order shown above and should be inserted immediately before the org.eclipse.jetty.webapp.JettyWebXmlConfiguration class in the list of configurations. To fully support JNDI additional configuration is required, full details of which can be found here.
Example: Annotation Configurations
We need just one extra Configuration class to help provide servlet annotation scanning:
Scan container and web app jars looking for @WebServlet, @WebFilter, @WebListener etc |
The above configuration class must be inserted immediately before the org.eclipse.jetty.webapp.JettyWebXmlConfiguration class in the list of configurations. To fully support annotations additional configuration is require, details of which can be found below.
How to Set the List of Configurations
You have a number of options for how to make Jetty use a different list of Configurations.
Setting the list directly on the WebAppContext
If you have only one webapp that you wish to affect, this may be the easiest option. You will, however, either need to have a context xml file that represents your web app, or you need to call the equivalent in code. Let’s see an example of how we would add in the Configurations for both JNDI and annotations:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="war"><SystemProperty name="jetty.base" default="."/>/webapps/my-cool-webapp</Set>
<Set name="configurationClasses">
<Array type="java.lang.String">
<Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
<Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
<Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
<Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
</Array>
</Set>
</Configure>
Of course, you can also use this method to reduce the Configurations applied to a specific WebAppContext
.
Setting the list for all webapps via the Deployer
If you use the deployer, you can set up the list of Configuration classes on the WebAppProvider.
They will then be applied to each WebAppContext
deployed by the deployer:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addBean">
<Arg>
<New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
<Set name="contexts">
<Ref refid="Contexts" />
</Set>
<Call id="webappprovider" name="addAppProvider">
<Arg>
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
<Set name="monitoredDirName"><Property name="jetty.base" default="." />/webapps</Set>
<Set name="configurationClasses">
<Array type="java.lang.String">
<Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
<Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
<Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
<Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
</Array>
</Set>
</New>
</Arg>
</Call>
</New>
</Arg>
</Call>
</Configure>
Adding or inserting to an existing list
Instead of having to enumerate the list in its entirety, you can simply nominate classes that you want to add, and indicate whereabouts in the list you want them inserted.
Let’s look at an example of using this method to add in Configuration support for JNDI - as usual you can either do this in an xml file, or via equivalent code.
This example uses an xml file, in fact it is the $JETTY_HOME/etc/jetty-plus.xml
file from the Jetty distribution:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Add plus Configuring classes to all webapps for this Server -->
<!-- =========================================================== -->
<Call class="org.eclipse.jetty.webapp.Configuration$ClassList" name="setServerDefault">
<Arg><Ref refid="Server" /></Arg>
<Call name="addAfter">
<Arg name="afterClass">org.eclipse.jetty.webapp.FragmentConfiguration</Arg>
<Arg>
<Array type="String">
<Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
</Array>
</Arg>
</Call>
</Call>
</Configure>
The org.eclipse.jetty.webapp.Configuration.ClassList class provides these methods for insertion:
- addAfter
-
Inserts the supplied list of
Configuration
class names after the given Configuration class name. - addBefore
-
Inserts the supplied list of
Configuration
class names before the given Configuration class name.
Other Configuration
org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern
This is a context attribute that can be set on an org.eclipse.jetty.webapp.WebAppContext to control which parts of the container’s classpath should be processed for things like annotations, META-INF/resources
, META-INF/web-fragment.xml
and tlds
inside META-INF
.
Normally, nothing from the container classpath will be included for processing.
However, sometimes you will need to include some.
For example, you may have some libraries that are shared amongst your webapps and thus you have put them into a $JETTY_HOME/lib
directory.
The libraries contain annotations and therefore must be scanned.
The value of this attribute is a regexp that defines which jars and class directories from the container’s classpath should be examined.
Here’s an example from a context xml file (although as always, you could have accomplished the same in code), which would match any jar whose name starts with "foo-" or "bar-", or a directory named "classes":
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>.*/foo-[^/]*\.jar$|.*/bar-[^/]*\.jar$|.*/classes/.*</Arg>
</Call>
</Configure>
Note that the order of the patterns defines the ordering of the scanning of the jars or class directories.
org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern
Similarly to the previous context attribute, this attribute controls which jars are processed for things like annotations, META-INF/resources
, META-INF/web-fragment.xml
and tlds
in META-INF
.
However, this attribute controls which jars from the webapp’s classpath (usually WEB-INF/lib
) are processed.
This can be particularly useful when you have dozens of jars in WEB-INF/lib
, but you know that only a few need to be scanned.
Here’s an example in a xml file of a pattern that matches any jar that starts with spring-
:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</Arg>
<Arg>.*/spring-[^/]*\.jar$</Arg>
</Call>
</Configure>
Note that the order of the patterns defines the ordering of the scanning of jar files.
Configuring Static Content Deployment
To serve purely static content, the Jetty Deployment Descriptor XML concepts and the internal ResourceHandler
can be used.
Create a file called scratch.xml
in the ${jetty.base}/webapps
directory and paste the following file contents in it.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
<Set name="contextPath">/scratch</Set>
<Set name="handler">
<New class="org.eclipse.jetty.server.handler.ResourceHandler">
<Set name="resourceBase">/home/scratch</Set>
<Set name="directoriesListed">true</Set>
</New>
</Set>
</Configure>
This is a very basic setup for serving static files. For advanced static file serving, use the DefaultServlet.
Hot Deployment
Jetty allows for deploying an arbitrary context or web application by monitoring a directory for changes.
If a web application or a context descriptor is added to the directory, Jetty’s DeploymentManager
(DM) deploys a new context.
If a context descriptor is touched or updated, the DM stops, reconfigures, and redeploys its context.
If a context is removed, the DM stops it and removes it from the server.
This behavior can be controlled by configuring WebAppProvider
properties.
- monitoredDirName
-
The directory to scan for possible deployable Web Applications (or Deployment Descriptor XML files).
- scanInterval
-
Number of seconds between scans of the provided
monitoredDirName
. A value of0
disables the continuous hot deployment scan, Web Applications will be deployed on startup only.
The default location for this configuration is in the ${jetty.home}/etc/jetty-deploy.xml
file.
To modify it as part of the Jetty distribution, first enable the deploy
module.
Once it is enabled, you can edit these properties in either the $JETTY_BASE/start.d/deploy.ini
or $JETTY_BASE/start.ini
file, depending on how your implementation is configured.
<?xml version="1.0"?>
# ---------------------------------------
# Module: deploy
# Enables webapplication deployment from the webapps directory.
# ---------------------------------------
--module=deploy
# Monitored directory name (relative to $jetty.base)
# jetty.deploy.monitoredDir=webapps
# - OR -
# Monitored directory path (fully qualified)
# jetty.deploy.monitoredPath=/var/www/webapps
# Defaults Descriptor for all deployed webapps
# jetty.deploy.defaultsDescriptorPath=${jetty.base}/etc/webdefault.xml
# Monitored directory scan period (seconds)
# jetty.deploy.scanInterval=1
# Whether to extract *.war files
# jetty.deploy.extractWars=true
See Understanding the Default WebAppProvider for more configuration details.
See also Deployment Architecture for detailed conceptual information.
Deployment Architecture
Jetty is built around an extensible Deployment Manager architecture complete with formal LifeCycle for Web Applications going through it.
For Jetty to serve content (static or dynamic), a ContextHandler needs to be configured and added to Jetty in the appropriate location.
A pluggable DeploymentManager
exists to make this process easier.
The Jetty distribution contains example DeploymentManager
configurations to deploy WAR files found in a directory to Jetty, and to deploy Jetty context xml files into Jetty as well.
The DeploymentManager
is the heart of the typical webapp deployment mechanism; it operates as a combination of an Application LifeCycle Graph, Application Providers that find and provide Applications into the Application LifeCycle Graph, and a set of bindings in the graph that control the deployment process.
Application Providers
Before Jetty deploys an application, an AppProvider
identifies the App and then provides it to the DeploymentManager
.
The main AppProvider
with the Jetty distribution is the WebAppProvider
.
Application LifeCycle Graph
The core feature of the DeploymentManager
is the Application LifeCycle Graph.
The nodes and edges of this graph are pre-defined in Jetty along the most common actions and states found. These nodes and edges are not hardcoded; they can be adjusted and added to depending on need (for example, any complex requirements for added workflow, approvals, staging, distribution, coordinated deploys for a cluster or cloud, etc.).
New applications enter this graph at the Undeployed node, and the java.lang.String DeploymentManager.requestAppGoal(App,String)
method pushes them through the graph.
LifeCycle Bindings
A set of default AppLifeCycle.Bindings
defines standard behavior, and handles deploying, starting, stopping, and undeploying applications.
If desired, custom AppLifeCycle.Bindings
can be written and assigned anywhere on the Application LifeCycle graph.
Examples of new AppLifeCycle.Binding
implementations that can be developed include:
-
Validating the incoming application.
-
Preventing the deployment of known forbidden applications.
-
Submitting the installation to an application auditing service in a corporate environment.
-
Distributing the application to other nodes in the cluster or cloud.
-
Emailing owner/admin of change of state of the application.
There are four default bindings:
-
StandardDeployer
— Deploys the ContextHandler into Jetty in the appropriate place. -
StandardStarter
— Sets the ContextHandler to started and start accepting incoming requests. -
StandardStopper
— Stops the ContextHandler and stops accepting incoming requests. -
StandardUndeployer
— Removes the ContextHandler from Jetty.
A fifth, non-standard binding, called DebugBinding, is also available for debugging reasons; it logs the various transitions through the Application LifeCycle.
Using GlobalWebappConfigBinding
In addition to the LifeCycle bindings discussed above, there is also the GlobalWebappConfigBinding
which, when added to the DeploymentManager
will apply an additional configuration XML file to each webapp that it deploys.
This can useful when setting server or system classes, or when defining override descriptors.
This configuration XML file will be in addition to any context XML file that exists for the webapp; it will be applied after any context XML files but before the webapp is started.
The format for the XML file is the same as any context XML file and can be used to same parameters for a webapp.
To use this binding, you can either modify the existing jetty-deploy.xml
which comes with the Jetty distribution (be sure to copy it to your $JETTY_BASE/etc directory first), or by creating a new module file which calls to an additional XML file.
<Call name="addLifeCycleBinding">
<Arg>
<New class="org.eclipse.jetty.deploy.bindings.GlobalWebappConfigBinding" >
<Set name="jettyXml"><Property name="jetty.home" default="." />/etc/global-webapp-config.xml</Set>
</New>
</Arg>
</Call>
Understanding the Default WebAppProvider
The WebAppProvider is used for the deployment of Web Applications packaged as WAR files, expanded as a directory, or declared in a Jetty Deployable Descriptor XML File. It supports hot (re)deployment.
The basic operation of the WebAppProvider
is to periodically scan a directory for deployables.
In the standard Jetty Distribution, this is configured in the ${jetty.home}/etc/jetty-deploy.xml
file.
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addBean">
<Arg>
<New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
<Set name="contexts">
<Ref refid="Contexts" />
</Set>
<Call id="webappprovider" name="addAppProvider">
<Arg>
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
<Set name="monitoredDirName"><Property name="jetty.home" default="." />/webapps</Set>
<Set name="defaultsDescriptor"><Property name="jetty.home" default="." />/etc/webdefault.xml</Set>
<Set name="scanInterval">1</Set>
<Set name="extractWars">true</Set>
</New>
</Arg>
</Call>
</New>
</Arg>
</Call>
</Configure>
The above configuration will create a DeploymentManager
tracked as a Server LifeCycle Bean, with the following configuration.
- contexts
-
A passed in reference to the HandlerContainer into which the discovered webapps are deployed. This is normally a reference that points to the
id="Contexts"
found in the${jetty.home}/etc/jetty.xml
file, which itself is an instance ofContextHandlerCollection
. - monitoredDirName
-
The file path or URL to the directory to scan for web applications.
Scanning follows these rules:
-
A base directory must exist.
-
Hidden Files (starting with
"."
) are ignored. -
Directories with names ending in
".d"
are ignored. -
Common CVS directories
"CVS"
and"CVSROOT"
are ignored. -
Any
*.war
files are considered automatic deployables. -
Any
*.xml
files are considered context descriptor deployables. -
In the special case where both a WAR file and XML file exists for same base name, the XML file is assumed to configure and reference the WAR file (see Configuring a Specific Web Application Deployment). Since jetty-9.2.7, if either the WAR file or its corresponding XML file changes, the webapp will be redeployed.
-
A directory is considered to be deployable.
-
In the special case where both a Directory and WAR file of the same name exists, the WAR file is assumed to be an automatic deployable.
-
In the special case where both a Directory and XML file of the same name exists, the XML file is assumed to configure and reference the Directory.
-
All other directories are subject to automatic deployment.
-
If automatic deployment is used, and the special filename
root.war/ROOT.war
or directory nameroot/ROOT
will result in a deployment to the"/"
context path.
-
- defaultsDescriptor
-
Specifies the default Servlet web descriptor to use for all Web Applications. The intent of this descriptor is to include common configuration for the Web Application before the Web Application’s own
/WEB-INF/web.xml
is applied. The${jetty.home}/etc/webdefault.xml
that comes with the Jetty distribution controls the configuration of the JSP and Default servlets, along with MIME-types and other basic metadata. - scanInterval
-
The period in seconds between sweeps of the
monitoredDirName
for changes: new contexts to deploy, changed contexts to redeploy, or removed contexts to undeploy. - extractWars
-
If parameter is true, any packed WAR or zip files are first extracted to a temporary directory before being deployed. This is advisable if there are uncompiled JSPs in the web apps.
- parentLoaderPriority
-
Parameter is a boolean that selects whether the standard Java parent first delegation is used or the servlet specification webapp classloading priority. The latter is the default.
Quickstart Webapps
The auto discovery features of the Servlet specification can make deployments slow and uncertain. Auto discovery of Web Application configuration can be useful during the development of a webapp as it allows new features and frameworks to be enabled simply by dropping in a jar file. However, for deployment, the need to scan the contents of many jars can have a significant impact of the start time of a webapp.
With the release of Jetty 9.2, a quickstart module was included which allows a webapp to be pre-scanned and preconfigured.
This means that all the scanning is done prior to deployment and all configuration is encoded into an effective web.xml
, called WEB-INF/quickstart-web.xml
, which can be inspected to understand what will be deployed before deploying.
Not only does the quickstart-web.xml
contain all the discovered Servlets, Filters and Constraints, but it also encodes as context parameters all discovered:
-
ServletContainerInitializers
-
HandlesTypes classes
-
Taglib Descriptors
With the quickstart mechanism, Jetty is able to entirely bypass all scanning and discovery modes and start a webapp in a predictable and fast way. Tests have shown that webapps that took many seconds to scan and deploy can now be deployed in a few hundred milliseconds.
Setting up Quickstart
Prerequisites
Jetty Distribution
In a standard Jetty distribution the quickstart module can be configured with the following command:
$ java -jar $JETTY_HOME/start.jar --add-to-start=quickstart
Embedded
In a Maven project you add a dependency on the artifact jetty-quickstart
.
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-quickstart</artifactId>
<version>{VERSION}</version>
</dependency>
Configuration
Webapps need to be instances of org.eclipse.jetty.quickstart.QuickStartWebApp
rather than the normal org.eclipse.jetty.webapp.WebAppContext
.
org.eclipse.jetty.quickstart.QuickStartWebApp
instances offer the same setters as the familiar org.eclipse.jetty.webapp.WebAppContext
, with the addition of:
- autoPreconfigure
-
(true/false). If true, the first time the webapp is run, the WEB-INF/quickstart-web.xml is generated BEFORE the webapp is deployed. Subsequent runs use the previously generated quickstart file.
- originAttribute
-
The name of an attribute to insert into the generated elements in quickstart-web.xml that gives the origin of the element. By default it is
origin
. - generateOrigin
-
(true/false). By default it is
false
. If true, the origin attribute will be inserted into each element in quickstart-web.xml. Note that origin attributes will also be generated if debug log level is enabled.
If you are using Spring-Boot you must set |
The origin is either a descriptor eg web.xml,web-fragment.xml,override-web.xml file, or an annotation eg @WebServlet. For xml validation each attribute must be unique, and therefore an integer counter is appended to each value. Some examples of elements with origin attribute information are:
<listener origin="DefaultsDescriptor(file:///path/to/distro/etc/webdefault.xml):21">
<listener origin="WebDescriptor(file:///path/to/base/webapps/test-spec/WEB-INF/web.xml):22">
<servlet-class origin="FragmentDescriptor(jar:file:///path/to/base/webapps/test-spec/WEB-INF/lib/test-web-fragment.jar!/META-INF/web-fragment.xml):23">
<servlet-class origin="@WebServlet(com.acme.test.TestServlet):24">
In XML
If a web application already has a context xml file, eg webapps/myapp.xml
file, simply change the class in the Configure
element.
Otherwise, create a context xml file with the following information (in addition to the usual setting of contextPath, war etc):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.quickstart.QuickStartWebApp">
<Set name="autoPreconfigure">true</Set>
</Configure>
In Code
Create an instance of org.eclipse.jetty.quickstart.QuickStartWebApp
rather than the normal org.eclipse.jetty.webapp.WebAppContext
. You then use the QuickStartWebApp instance in exactly the same way that you would a WebAppContext.
Here’s a snippet:
QuickStartWebApp webapp = new QuickStartWebApp();
webapp.setAutoPreconfigure(true);
Pre-generating the quickstart-web.xml file
Rather than use the autoPreconfigure
feature of the QuickStartWebApp - which lazily generates the quickstart-web.xml
file - you can eagerly pre-generate it for an existing war by invoking as a main class org.eclipse.jetty.quickstart.PreconfigureQuickStartWar
.
Note that you will need to provide all necessary jetty jars on the command line classpath.
This will unpack the war if necessary, and create the quickstart-web.xml
before the first deployment:
$ java -cp [jetty classpath] org.eclipse.jetty.quickstart.PreconfigureQuickStartWar myapp.war
Run the class with no arguments to see other runtime options.
Alternatively, you could use the Jetty Maven Plugin goal jetty:effective-web-xml
: this will generate quickstart information, but print it to stderr.
The goal provides a configuration option to save the output to a file, which you can then copy into your webapp’s WEB-INF dir.
Note that as the Jetty Maven Plugin is a general tool for running webapps, it may have more jars on its classpath than are needed by your application, and thus may generate extra quickstart information: we recommend that you use this goal only as a quick guide to the type of information that quickstart generates.
Avoiding TLD Scans with precompiled JSPs
Of course precompiling JSPs is an excellent way to improve the start time of a web application.
As of Jetty 9.2 the Apache Jasper JSP implementation has been used and has been augmented to allow the TLD scan to be skipped.
This can be done by adding a context-param
to the web.xml
file (this is done automatically by the Jetty Maven JSPC plugin):
<context-param>
<param-name>org.eclipse.jetty.jsp.precompiled</param-name>
<param-value>true</param-value>
</context-param>
Bypassing start.jar
The Jetty start.jar
mechanism is a very powerful and flexible mechanism for constructing a classpath
and executing a configuration encoded in Jetty XML format.
However, this mechanism does take some time to build the classpath
.
The start.jar mechanism can be bypassed by using the –dry-run
option to generate and reuse a complete command line to start Jetty at a later time:
$ RUN=$(java -jar $JETTY_HOME/start.jar --dry-run)
$ eval $RUN
Note that --dry-run
may create a properties file in the temp directory and include it on the generated command line.
If so, then a copy of the temporary properties file should be taken and the command line updated with it’s new persistent location.
Configuring Contexts
This chapter discusses various options for configuring Jetty contexts.
Setting a Context Path
The context path is the prefix of a URL path that is used to select the context(s) to which an incoming request is passed. Typically a URL in a Java servlet server is of the format http://hostname.com/contextPath/servletPath/pathInfo
, where each of the path elements can be zero or more / separated elements.
If there is no context path, the context is referred to as the root context.
The root context must be configured as /
but is reported as the empty string by the servlet API getContextPath()
method.
How you set the context path depends on how you deploy the web application (or ContextHandler
).
Using Embedded Deployment
If you run Jetty from code as an embedded server (see Embedding), setting the context path is a matter of calling the setContextPath
method on the ContextHandler
instance (or WebAppContext
instance).
By naming convention
If a web application is deployed using the WebAppProvider of the DeploymentManager without an XML IoC file, then the name of the WAR file is used to set the context path:
-
If the WAR file is named myapp.war, then the context will be deployed with a context path of
/myapp
-
If the WAR file is named ROOT.WAR (or any case insensitive variation), then the context will be deployed with a context path of
/
-
If the WAR file is named ROOT-foobar.war ( or any case insensitive variation), then the context will be deployed with a context path of
/
and a virtual host of "foobar"
By Deployer configuration
If a web application is deployed using the WebAppProvider
of the DeploymentManager
with an XML IoC file to configure the context, then the setContextPath
method can be called within that file.
For example:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
...
</Configure>
Embedding a WEB-INF/jetty-web.xml File
You can also set the context path for webapps by embedding a WEB-INF/jetty-web.xml
file in the WAR, which uses the same XML IoC format as the deployer example above.
However this is not the preferred method as it requires the web application to be modified.
Configuring Virtual Hosts
A virtual host is an alternative name, registered in DNS, for an IP address such that multiple domain names will resolve to the same IP of a shared server instance. If the content to be served to the aliases names is different, then a virtual host needs to be configured for each deployed context to indicate which names a context will respond to.
Virtual hosts are set on a context by calling the setVirtualHosts
or addVirtualHost
method which can be done in several ways:
-
Using a context XML file in the webapps directory (see the example in test.xml in the Jetty distribution).
-
Creating a custom deployer with a binding to configure virtual hosts for all contexts found in the same
webapps
directory. -
Using a
WEB-INF/jetty-web.xml
file (now deprecated).
Virtual Host Names
Jetty supports the following styles of virtual host name:
- www.hostname.com
-
A fully qualified host name. It is important to list all variants as a site may receive traffic from both www.hostname.com and just hostname.com
- *.hostname.com
-
A wildcard qualified host which will match only one level of arbitrary names. *.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 given as a virtual host name to indicate that a context should handle requests received on that server port that do not have a host name specified (HTTP/0.9 or HTTP/1.0).
- @ConnectorName
-
A connector name, which is not strictly a virtual host, but instead will only match requests that are received on connectors that have a matching name set with Connector.setName(String).
- www.√integral.com
-
Non-ASCII and IDN domain names can be set as virtual hosts using Puny Code equivalents that may be obtained from a Punycode/IDN converters. For example if the non-ASCII domain name
www.√integral.com
is given to a browser, then it will make a request that uses the domain namewww.xn—integral-7g7d.com
, which is the name that should be added as the virtual host name.
Example Virtual Host Configuration
Virtual hosts can be used with any context that is a subclass of ContextHandler. Lets look at an example where we configure a web application - represented by the WebAppContext class - with virtual hosts. You supply a list of IP addresses and names at which the web application is reachable, such as the following:
-
333.444.555.666
-
127.0.0.1
-
www.blah.com
-
www.blah.net
-
www.blah.org
Suppose you have a webapp called blah.war
, that you want all of the above names and addresses to be served at path “/blah”.
Here’s how you would configure the virtual hosts with a context XML file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/blah</Set>
<Set name="war"><Property name="jetty.webapps"/>blah.war</Set>
<Set name="virtualHosts">
<Array type="java.lang.String">
<Item>333.444.555.666</Item>
<Item>127.0.0.1</Item>
<Item>www.blah.com</Item>
<Item>www.blah.net</Item>
<Item>www.blah.org</Item>
</Array>
</Set>
</Configure>
Using Different Sets of Virtual Hosts to Select Different Contexts
You can configure different contexts to respond on different virtual hosts by supplying a specific list of virtual hosts for each one.
For example, suppose your imaginary machine has these DNS names:
-
www.blah.com
-
www.blah.net
-
www.blah.org
-
www.other.com
-
www.other.net
-
www.other.org
Suppose also you have 2 webapps, one called blah.war
that you would like served from the .blah.
names, and one called other.war
that you want served only from the .other.
names.
Using the method of preparing contextXML files, one for each webapp yields the following:
For blah
webapp:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/blah</Set>
<Set name="war"><Property name="jetty.webapps"/>/blah.war</Set>
<Set name="virtualHosts">
<Array type="java.lang.String">
<Item>www.blah.com</Item>
<Item>www.blah.net</Item>
<Item>www.blah.org</Item>
</Array>
</Set>
</Configure>
These URLs now resolve to the blah context (ie blah.war
):
For other
webapp:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/other</Set>
<Set name="war"><Property name="jetty.webapps"/>/other.war</Set>
<Set name="virtualHosts">
<Array type="java.lang.String">
<Item>www.other.com</Item>
<Item>www.other.net</Item>
<Item>www.other.org</Item>
</Array>
</Set>
</Configure>
These URLs now resolve to the other context (i.e. other.war
):
Using Different Sets of Virtual Hosts to Select Different Contexts at the Same Context Path
In the previous section we setup 2 different contexts to be served from different virtual hosts at different context paths. However, there is no requirement that the context paths must be distinct: you may use the same context path for multiple contexts, and use virtual hosts to determine which one is served for a given request.
Consider an example where we have the same set of DNS names as before, and the same webapps blah.war
and other.war
. We still want blah.war
to be served in response to hostnames of .blah.
, and we still want other.war
to be served in response to .other.
names.
However, we would likeall of our clients to use the "/"
context path, no matter which context is being targeted.
In other words, we want all of the following URLs to map to blah.war
:
Similarly, we want the following URLs to map to other.war
:
To achieve this, we simply use the same context path of /
for each of our webapps, while still applying our different set of virtual host names.
For foo webapp:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/</Set>
<Set name="war"><Property name="jetty.webapps"/>/foo.war</Set>
<Set name="virtualHosts">
<Array type="java.lang.String">
<Item>www.blah.com</Item>
<Item>www.blah.net</Item>
<Item>www.blah.org</Item>
</Array>
</Set>
</Configure>
For bar webapp:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/</Set>
<Set name="war"><Property name="jetty.webapps"/>/bar.war</Set>
<Set name="virtualHosts">
<Array type="java.lang.String">
<Item>www.other.com</Item>
<Item>www.other.net</Item>
<Item>www.other.org</Item>
</Array>
</Set>
</Configure>
Temporary Directories
Jetty itself has no temporary directories, but you can assign a directory for each web application, into which the WAR is unpacked, JSPs compiled on-the-fly, etc. If you do not assign a specific temporary directory, Jetty will create one as needed when your web application starts. Whether you set the location of the temporary directory - or you let Jetty create one for you - you also have a choice to either keep or delete the temporary directory when the web application stops.
The Default Temp Directory
By default, Jetty will create a temporary directory for each web application. The name of the directory will be of the form:
"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"+randomdigits+".dir"
For example:
jetty-0.0.0.0-8080-test.war-_test-any-8900275691885214790.dir
Where 0.0.0.0
is the host address, 8080
is the port, test.war
is the resourceBase, test
is the context path (with / converted to _), any
is the virtual host, and randomdigits
are a string of digits guaranteed to be unique.
Once the temp directory is created, it is retrievable as the value (as a File) of the context attribute javax.servlet.context.tempdir.
The location of the temp directory
By default, Jetty will create this directory inside the directory named by the java.io.tmpdir
System property.
You can instruct Jetty to use a different parent directory by setting the context attribute org.eclipse.jetty.webapp.basetempdir
to the name of the desired parent directory.
The directory named by this attribute must exist and be writeable.
As usual with Jetty, you can either set this attribute in a context xml file, or you can do it in code.
Here’s an example of setting it in an xml file:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
<Set name="war">foo.war</Set>
<Call name="setAttribute">
<Arg>org.eclipse.jetty.webapp.basetempdir</Arg>
<Arg>/home/my/foo</Arg>
</Call>
</Configure>
The equivalent in code is:
WebAppContext context = new WebAppContext();
context.setContextPath("/test");
context.setWar("foo.war");
context.setAttribute("org.eclipse.jetty.webapp.basetempdir", "/tmp/foo");
Setting a Specific Temp Directory
There are several ways to use a particular directory as the temporary directory:
Call WebAppContext.setTempDirectory(String dir)
As before this can be accomplished with an XML file or directly in code. Here is an example of setting the temp directory in XML:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
<Set name="war">foo.war</Set>
<Set name="tempDirectory">/some/dir/foo</Set>
</Configure>
And here is an example of doing it with java code:
WebAppContext context = new WebAppContext();
context.setContextPath("/test");
context.setWar("foo.war");
context.setTempDirectory(new File("/some/dir/foo"));
Setting the javax.servlet.context.tempdir Context Attribute
You should set this context attribute with the name of directory you want to use as the temp directory. Again, you can do this in XML:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
<Set name="war">foo.war</Set>
<Call name="setAttribute">
<Arg>javax.servlet.context.tempdir</Arg>
<Arg>/some/dir/foo</Arg>
</Call>
</Configure>
Or in java:
WebAppContext context = new WebAppContext();
context.setContextPath("/test");
context.setWar("foo.war");
context.setAttribute("javax.servlet.context.tempdir", "/some/dir/foo");
Once a temporary directory has been created by either of these methods, a file instance for it is set as the value of the javax.servlet.context.tempdir
attribute of the web application.
Be wary of setting an explicit temp directory if you are likely to change the jars in WEB-INF/lib between redeployments. There is a JVM bug concerning caching of jar contents. |
Setting the Temp Directory on the Command Line
You can set the location of the temp directory on the command line when Jetty starts up in two ways. First is the most straightforward, simply add it to your command line when starting Jetty.
java -jar ../start.jar -Djava.io.tmpdir=/path/to/desired/directory
Alternately, this can be defined in a module.
The jvm
module packaged with Jetty is set up to add additional JVM options.
After enabling the module (using the --add-to-start=jvm
command), edit the jvm.ini
file and add the location to the temporary directory.
You will also need verify the line including the --exec
command is not commented out, as this is required for Jetty to start a new, forked JVM.
Below is an example of the standard jvm.ini
file altered to include a reference to a temp directory.
# ---------------------------------------
# Module: jvm
# A noop module that creates an ini template useful for
# setting JVM arguments (eg -Xmx )
# ---------------------------------------
--module=jvm
## JVM Configuration
## If JVM args are include in an ini file then --exec is needed
## to start a new JVM from start.jar with the extra args.
##
## If you wish to avoid an extra JVM running, place JVM args
## on the normal command line and do not use --exec
--exec
# -Xmx2000m
# -Xmn512m
# -XX:+UseConcMarkSweepGC
# -XX:ParallelCMSThreads=2
# -XX:+CMSClassUnloadingEnabled
# -XX:+UseCMSCompactAtFullCollection
# -XX:CMSInitiatingOccupancyFraction=80
# -internal:gc
# -XX:+PrintGCDateStamps
# -XX:+PrintGCTimeStamps
# -XX:+PrintGCDetails
# -XX:+PrintTenuringDistribution
# -XX:+PrintCommandLineFlags
# -XX:+DisableExplicitGC
-Djava.io.tmpdir=/path/to/desired/directory
The "work" Directory
It is possible to create a directory named work
in the $\{jetty.base}
directory.
If such a directory is found, it is assumed you want to use it as the parent directory for all of the temporary directories of the webapps in $\{jetty.base}
.
Moreover, as has historically been the case, these temp directories inside the work directory are not cleaned up when Jetty exits (or more correctly speaking, the temp
directory corresponding to a context is not cleaned up when that context stops).
When a work
directory is used, the algorithm for generating the name of the context-specific temp directories omits the random digit string.
This ensures the name of the directory remains consistent across context restarts.
Persisting the temp directory
Sometimes it is useful to keep the contents of the temporary directory between restarts of the web application. By default, Jetty will not persist the temp directory. To configure Jetty to keep it, use WebAppContext.setPersistTempDirectory(true).
Be aware that if you call |
Serving a WebApp from a Particular Port/Connector
Sometimes it is required to serve different web applications from different ports/connectors.
The simplest way to do this is to create multiple Server
instances.
However, if contexts need to share resources (eg data sources, authentication), or if the mapping of ports to web applications is not cleanly divided, then the named connector mechanism can be used.
Creating Multiple Server Instances
Creating multiple server instances is a straight forward process that includes embedding Jetty code by creating multiples instances of the Server class and configuring them as needed.
This is also easy to achieve if you are configuring Jetty servers via XML.
The id
field in the Configure element of jetty.xml
files is used to identify the instance that the configuration applies to, so to run two instances of the Server, you can copy the jetty.xml
, jetty-http.xml and other jetty configuration files used and change the "Server" id to a new name.
This can be done in the same style and layout as the existing jetty.xml
files or the multiple XML files may be combined to a single file.
When creating new configurations for alternative server:
-
Change all
id="Server"
to the new server name:
<Configure id="OtherServer" class="org.eclipse.jetty.server.Server">
-
For all connectors for the new server change the
refid
in the server argument:
<Arg name="server"><Ref refid="OtherServer" /></Arg>
-
Make sure that any references to properties like
jetty.http.port
are either renamed or replaced with absolute values. -
Make sure that any deployers
AppProviders
refer to a different "webapps" directory so that a different set of applications are deployed.
Example Other Server XML
The following example creates another server instance and configures it with a connector and deployer:
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="OtherServer" class="org.eclipse.jetty.server.Server">
<Set name="handler">
<New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
<Set name="handlers">
<Array type="org.eclipse.jetty.server.Handler">
<Item>
<New id="OtherContexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
</Item>
<Item>
<New class="org.eclipse.jetty.server.handler.DefaultHandler"/>
</Item>
</Array>
</Set>
</New>
</Set>
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="OtherServer" /></Arg>
<Set name="port">8888</Set>
</New>
</Arg>
</Call>
<Call name="addBean">
<Arg>
<New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
<Set name="contexts">
<Ref refid="OtherContexts" />
</Set>
<Call id="webappprovider" name="addAppProvider">
<Arg>
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
<Set name="monitoredDirName"><Property name="jetty.base" default="." />/other-webapps</Set>
<Set name="defaultsDescriptor"><Property name="jetty.home" default="." />/etc/webdefault.xml</Set>
<Set name="extractWars">true</Set>
<Set name="configurationManager">
<New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager"/>
</Set>
</New>
</Arg>
</Call>
</New>
</Arg>
</Call>
</Configure>
To run the other server, add the extra configuration file(s) to the command line:
java -jar start.jar jetty-otherserver.xml
Named Connectors
It is also possible to use an extension to the virtual host mechanism with named to connectors to make some web applications only accessible by specific connectors.
If a connector has a name "MyConnector" set using the setName
method, then this can be referenced with the special virtual host name "@MyConnector".
Creating Custom Error Pages
The following sections describe several ways to create custom error pages in Jetty.
Defining error pages in web.xml
You can use the standard webapp configuration file located in webapp/WEB-INF/web.xml
to map errors to specific URLs with the error-page
element.
This element creates a mapping between the error-code or exception-type to the location of a resource in the web application.
-
error-code
- an integer value -
exception-type
- a fully qualified class name of a Java Exception type -
location
- location of the resource in the webapp relative to the root of the web application. Value should start with/
.
Error code example:
<error-page>
<error-code>404</error-code>
<location>/jspsnoop/ERROR/404</location>
</error-page>
Exception example:
<error-page>
<exception-type>java.io.IOException</exception-type>
<location>/jspsnoop/IOException</location>
</error-page>
The error page mappings created with the error-page element will redirect to a normal URL within the web application and will be handled as a normal request to that location and thus may be static content, a JSP or a filter and/or servlet. When handling a request generated by an error redirection, the following request attributes are set and are available to generate dynamic content:
- javax.servlet.error.exception
-
The exception instance that caused the error (or null).
- javax.servlet.error.exception_type
-
The class name of the exception instance that caused the error (or null).
- javax.servlet.error.message
-
The error message.
- javax.servlet.error.request_uri
-
The URI of the request with an error.
- javax.servlet.error.servlet_name
-
The Servlet name of the servlet that the request was dispatched to.
- javax.servlet.error.status_code
-
The status code of the error (e.g. 404, 500 etc.).
Configuring error pages context files
You can use context IoC XML files to configure the default error page mappings with more flexibility than is available with web.xml
, specifically with the support of error code ranges.
Context files are normally located in ${jetty.base}/webapps/
(see DeployerManager
for more details) and an example of more flexible error page mapping is below:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
<Set name="war">
<SystemProperty name="jetty.base" default="."/>/webapps/test
</Set>
<!-- by Code -->
<Get name="errorHandler">
<Call name="addErrorPage">
<Arg type="int">404</Arg>
<Arg type="String">/jspsnoop/ERROR/404</Arg>
</Call>
</Get>
<!-- by Exception -->
<Get name="errorHandler">
<Call name="addErrorPage">
<Arg>
<Call class="java.lang.Class" name="forName">
<Arg type="String">java.io.IOException</Arg>
</Call>
</Arg>
<Arg type="String">/jspsnoop/IOException</Arg>
</Call>
</Get>
<!-- by Code Range -->
<Get name="errorHandler">
<Call name="addErrorPage">
<Arg type="int">500</Arg>
<Arg type="int">599</Arg>
<Arg type="String">/dump/errorCodeRangeMapping</Arg>
</Call>
</Get>
</Configure>
Custom ErrorHandler class
If no error page mapping is defined, or if the error page resource itself has an error, then the error page will be generated by an instance of ErrorHandler
configured either the Context or the Server.
An ErrorHandler
may extend the ErrorHandler
class and may totally replace the handle method to generate an error page, or it can implement some or all of the following methods to partially modify the error pages:
void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message) throws IOException
void writeErrorPage(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks) throws IOException
void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message) throws IOException
void writeErrorPageBody(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks) throws IOException
void writeErrorPageMessage(HttpServletRequest request, Writer writer, int code, String message, String uri) throws IOException
void writeErrorPageStacks(HttpServletRequest request, Writer writer) throws IOException
An ErrorHandler
instance may be set on a Context by calling the ContextHandler.setErrorHandler
method. This can be done by embedded code or via context IoC XML.
For example:
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
...
<Set name="errorHandler">
<New class="com.acme.handler.MyErrorHandler"/>
</Set>
...
</Configure>
An ErrorHandler
instance may be set on the entire server by setting it as a dependent bean on the Server instance.
This can be done by calling Server.addBean(Object)
via embedded code or in jetty.xml
IoC XML:
<Configure id="Server" class="org.eclipse.jetty.server.Server">
...
<Call name="addBean">
<Arg>
<New class="com.acme.handler.MyErrorHandler"/>
</Arg>
</Call>
...
</Configure>
Server level 404 error
It is possible to get a 'page not found' when a request is made to the server for a resource that is outside of any registered contexts. As an example, you have a domain name pointing to your public server IP, yet no context is registered with Jetty to serve pages for that domain. As a consequence, the server, by default, gives a listing of all contexts running on the server.
One of the quickest ways to avoid this behavior is to create a catch all context.
Create a "root" web app mapped to the "/" URI, and use the index.html
redirect to whatever place with a header directive.
Setting Max Form Size
Jetty limits the amount of data that can post back from a browser or other client to the server. This helps protect the server against denial of service attacks by malicious clients sending huge amounts of data. The default maximum size Jetty permits is 200000 bytes. You can change this default for a particular webapp, for all webapps on a particular Server instance, or all webapps within the same JVM.
For a Single Webapp
The method to invoke is: ContextHandler.setMaxFormContentSize(int maxSize);
This can be done either in a context XML deployment descriptor external to the webapp, or in a jetty-web.xml
file in the webapp’s WEB-INF
directory.
In either case the syntax of the XML file is the same:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- Max Form Size -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<Set name="maxFormContentSize">200000</Set>
</Configure>
For All Apps on a Server
Set an attribute in jetty.xml
on the Server instance for which you want to modify the maximum form content size:
<Configure class="org.eclipse.jetty.server.Server">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.Request.maxFormContentSize</Arg>
<Arg>200000</Arg>
</Call>
</Configure>
It is important to remember that you should not modify the XML files in your |
For All Apps in the JVM
Use the system property org.eclipse.jetty.server.Request.maxFormContentSize
.
This can be set on the command line or in the $JETTY_BASE\start.ini
or any $JETTY_BASE\start.d\*.ini
module ini file.
Using $JETTY_BASE\start.d\server.ini
as an example:
# ---------------------------------------
# Module: server
# Enables the core Jetty server on the classpath.
# ---------------------------------------
--module=server
### Common HTTP configuration
## Scheme to use to build URIs for secure redirects
# jetty.httpConfig.secureScheme=https
...
-Dorg.eclipse.jetty.server.Request.maxFormContentSize=200000
Configuring Jetty Connectors
This chapter discusses various options for configuring Jetty connectors.
Connector Configuration Overview
Connectors are the mechanism through which Jetty accepts network connections for various protocols. Configuring a connector is a combination of configuring the following:
-
Network parameters on the connector itself (for example: the listening port).
-
Services the connector uses (for example: executors, schedulers).
-
Connection factories that instantiate and configure the protocol for an accepted connection.
Typically connectors require very little configuration aside from setting the listening port, and enabling X-Forwarded-For
customization when applicable.
Additional settings, including construction your own constructor Jetty XML files, are for expert configuration only.
Enabling Connectors
Out of the box, Jetty provides several modules for enabling different types of connectors, from HTTP to HTTPS, HTTP/2, and others.
If you startup Jetty with the --list-modules=connector
command, you can see a list of all available connector modules:
[mybase]$ java -jar $JETTY_HOME/start.jar --list-modules=connector
Available Modules:
==================
tags: [connector]
Modules for tag 'connector':
----------------------------
Module: acceptratelimit
: Enable a server wide accept rate limit
Tags: connector
Depend: server
XML: etc/jetty-acceptratelimit.xml
Module: connectionlimit
: Enable a server wide connection limit
Tags: connector
Depend: server
XML: etc/jetty-connectionlimit.xml
Module: http
: Enables a HTTP connector on the server.
: By default HTTP/1 is support, but HTTP2C can
: be added to the connector with the http2c module.
Tags: connector, http
Depend: server
XML: etc/jetty-http.xml
Module: http-forwarded
: Adds a forwarded request customizer to the HTTP Connector
: to process forwarded-for style headers from a proxy.
Tags: connector
Depend: http
XML: etc/jetty-http-forwarded.xml
Module: http2
: Enables HTTP2 protocol support on the TLS(SSL) Connector,
: using the ALPN extension to select which protocol to use.
Tags: connector, http2, http, ssl
Depend: ssl, alpn
LIB: lib/http2/*.jar
XML: etc/jetty-http2.xml
Module: http2c
: Enables the HTTP2C protocol on the HTTP Connector
: The connector will accept both HTTP/1 and HTTP/2 connections.
Tags: connector, http2, http
Depend: http
LIB: lib/http2/*.jar
XML: etc/jetty-http2c.xml
Module: https
: Adds HTTPS protocol support to the TLS(SSL) Connector
Tags: connector, https, http, ssl
Depend: ssl
Optional: http-forwarded, http2
XML: etc/jetty-https.xml
Module: proxy-protocol-ssl
: Enables the Proxy Protocol on the TLS(SSL) Connector.
: http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
: This allows a Proxy operating in TCP mode to transport
: details of the proxied connection to the server.
: Both V1 and V2 versions of the protocol are supported.
Tags: connector, ssl
Depend: ssl
XML: etc/jetty-proxy-protocol-ssl.xml
Module: ssl
: Enables a TLS(SSL) Connector on the server.
: This may be used for HTTPS and/or HTTP2 by enabling
: the associated support modules.
Tags: connector, ssl
Depend: server
XML: etc/jetty-ssl.xml
XML: etc/jetty-ssl-context.xml
Module: unixsocket
: Enables a Unix Domain Socket Connector that can receive
: requests from a local proxy and/or SSL offloader (eg haproxy) in either
: HTTP or TCP mode. Unix Domain Sockets are more efficient than
: localhost TCP/IP connections as they reduce data copies, avoid
: needless fragmentation and have better dispatch behaviours.
: When enabled with corresponding support modules, the connector can
: accept HTTP, HTTPS or HTTP2C traffic.
Tags: connector
Depend: server
LIB: lib/jetty-unixsocket-${jetty.version}.jar
LIB: lib/jnr/*.jar
XML: etc/jetty-unixsocket.xml
Module: unixsocket-forwarded
: Adds a forwarded request customizer to the HTTP configuration used
: by the Unix Domain Socket connector, for use when behind a proxy operating
: in HTTP mode that adds forwarded-for style HTTP headers. Typically this
: is an alternate to the Proxy Protocol used mostly for TCP mode.
Tags: connector
Depend: unixsocket-http
XML: etc/jetty-unixsocket-forwarded.xml
Module: unixsocket-http
: Adds a HTTP protocol support to the Unix Domain Socket connector.
: It should be used when a proxy is forwarding either HTTP or decrypted
: HTTPS traffic to the connector and may be used with the
: unix-socket-http2c modules to upgrade to HTTP/2.
Tags: connector, http
Depend: unixsocket
XML: etc/jetty-unixsocket-http.xml
Module: unixsocket-http2c
: Adds a HTTP2C connetion factory to the Unix Domain Socket Connector
: It can be used when either the proxy forwards direct
: HTTP/2C (unecrypted) or decrypted HTTP/2 traffic.
Tags: connector, http2
Depend: unixsocket-http
LIB: lib/http2/*.jar
XML: etc/jetty-unixsocket-http2c.xml
Module: unixsocket-proxy-protocol
: Enables the proxy protocol on the Unix Domain Socket Connector
: http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
: This allows information about the proxied connection to be
: efficiently forwarded as the connection is accepted.
: Both V1 and V2 versions of the protocol are supported and any
: SSL properties may be interpreted by the unixsocket-secure
: module to indicate secure HTTPS traffic. Typically this
: is an alternate to the forwarded module.
Tags: connector
Depend: unixsocket
XML: etc/jetty-unixsocket-proxy-protocol.xml
Module: unixsocket-secure
: Enable a secure request customizer on the HTTP Configuration
: used by the Unix Domain Socket Connector.
: This looks for a secure scheme transported either by the
: unixsocket-forwarded, unixsocket-proxy-protocol or in a
: HTTP2 request.
Tags: connector
Depend: unixsocket-http
XML: etc/jetty-unixsocket-secure.xml
...
To enable a connector, simply activate the associated module.
Below is an example of activating both the http
and https
modules in a fresh Jetty base using the start.d directory:
[mybase] java -jar $JETTY_HOME/start.jar --create-startd
MKDIR : ${jetty.base}/start.d
INFO : Base directory was modified
[mybase] java -jar $JETTY_HOME/start.jar --add-to-start=http,https
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : http initialized in ${jetty.base}/start.d/http.ini
INFO : https initialized in ${jetty.base}/start.d/https.ini
INFO : ssl transitively enabled, ini template available with --add-to-start=ssl
MKDIR : ${jetty.base}/etc
COPY : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
INFO : Base directory was modified
[mybase] tree
.
├── etc
│ └── keystore
└── start.d
├── http.ini
└── https.ini
When the http
and https
modules were activated, so too were any modules they were dependent on, in this case server
and ssl
, as well as any dependencies for those modules, such as the etc
and ketystore
directories for ssl
.
At this point the server has been configured with connectors for both HTTP and HTTPS and can be started:
[mybase] java -jar $JETTY_HOME/start.jar
2017-08-31 10:19:58.855:INFO::main: Logging initialized @372ms to org.eclipse.jetty.util.log.StdErrLog
2017-08-31 10:19:59.076:INFO:oejs.Server:main: jetty-9.4.6.v20170531
2017-08-31 10:19:59.125:INFO:oejs.AbstractConnector:main: Started ServerConnector@421e98e0{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2017-08-31 10:19:59.150:INFO:oejus.SslContextFactory:main: x509=X509@5315b42e(jetty,h=[jetty.eclipse.org],w=[]) for SslContextFactory@2ef9b8bc(file:///Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase/etc/keystore,file:///Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase/etc/keystore)
2017-08-31 10:19:59.151:INFO:oejus.SslContextFactory:main: x509=X509@5d624da6(mykey,h=[],w=[]) for SslContextFactory@2ef9b8bc(file:///Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase/etc/keystore,file:///Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase/etc/keystore)
2017-08-31 10:19:59.273:INFO:oejs.AbstractConnector:main: Started ServerConnector@2b98378d{SSL,[ssl, http/1.1]}{0.0.0.0:8443}
2017-08-31 10:19:59.274:INFO:oejs.Server:main: Started @791ms
When modules are enabled, they are loaded with several default options.
These can be changed by editing the associated module ini file in the start.d
directory (or the associated lines in server.ini
if your implementation does not use start.d
).
For example, if we examine the http.ini
file in our start.d
directory created above, we will see the following settings:
# ---------------------------------------
# Module: http
# Enables a HTTP connector on the server.
# By default HTTP/1 is support, but HTTP2C can
# be added to the connector with the http2c module.
# ---------------------------------------
--module=http
### HTTP Connector Configuration
## Connector host/address to bind to
# jetty.http.host=0.0.0.0
## Connector port to listen on
# jetty.http.port=8080
## Connector idle timeout in milliseconds
# jetty.http.idleTimeout=30000
## Number of acceptors (-1 picks default based on number of cores)
# jetty.http.acceptors=-1
## Number of selectors (-1 picks default based on number of cores)
# jetty.http.selectors=-1
## ServerSocketChannel backlog (0 picks platform default)
# jetty.http.acceptQueueSize=0
## Thread priority delta to give to acceptor threads
# jetty.http.acceptorPriorityDelta=0
## HTTP Compliance: RFC7230, RFC2616, LEGACY
# jetty.http.compliance=RFC7230
To make a change to these settings, uncomment the line (by removing the #) and change the property to the desired value. For example, if you wanted to change the HTTP port to 5231, you would edit the line as follows:
...
## Connector port to listen on
jetty.http.port=5231
...
Now when the server is started, HTTP connections will enter on port 5231:
[mybase] java -jar ../start.jar
2017-08-31 10:31:32.955:INFO::main: Logging initialized @366ms to org.eclipse.jetty.util.log.StdErrLog
2017-08-31 10:31:33.109:INFO:oejs.Server:main: jetty-9.4.6.v20170531
2017-08-31 10:31:33.146:INFO:oejs.AbstractConnector:main: Started ServerConnector@2ef9b8bc{HTTP/1.1,[http/1.1]}{0.0.0.0:5231}
...
2017-08-31 10:31:33.263:INFO:oejs.Server:main: Started @675ms
Every module has their own set of configuration options, and reviewing them all is recommended. For additional information on the module system, please refer to our documentation on Startup Modules.
Editing these module files is the recommended way to edit the configuration of your server. Making changes to the associated Jetty XML file for connectors is not recommended, and is for advanced users only. If you do wish to edit Jetty XML, please see our section on managing Jetty Home and Jetty Base to ensure your Jetty Home remains a standard of truth for your implementation. |
Limiting Connections
Jetty also provides the means by which to limit connections to the server and/or contexts. This is provided by two different modules in the distribution.
connectionlimit
-
Applies a limit to the number of connections. If this limit is exceeded, new connections are suspended for the time specified (in milliseconds).
acceptratelimit
-
Limits the rate at which new connections are accepted. If this limit is exceeded, new connections are suspended for the time specified (in milliseconds).
As with the modules listed above, these can be enabled by adding --add-to-start=<module-name>
to the command line.
Advanced Configuration
Jetty primarily uses a single connector type called ServerConnector.
Prior to Jetty 9, the type of the connector specified both the protocol and the implementation used; for example, selector-based non blocking I/O vs blocking I/O, or SSL connector vs non-SSL connector.
Jetty 9 has a single selector-based non-blocking I/O connector, and a collection of ConnectionFactories
now configure the protocol on the connector.
The standard Jetty distribution comes with the following Jetty XML files that create and configure connectors; you should examine them as you read this section:
jetty-http.xml
-
Instantiates a
ServerConnector
that accepts HTTP connections (that may be upgraded to WebSocket connections). jetty-ssl.xml
-
Instantiates a
ServerConnector
that accepts SSL/TLS connections. On it’s own, this connector is not functional and requires one or more of the following files to also be configured to addConnectionFactories
to make the connector functional. jetty-https.xml
-
Adds a
HttpConnectionFactory
to theServerConnector
configured byjetty-ssl.xml
which combine to provide support for HTTPS. jetty-http-forwarded.xml
-
Adds a
ForwardedRequestCustomizer
to the HTTP Connector to process forwarded-for style headers from a proxy. jetty-http2.xml
-
Adds a
Http2ServerConnectionFactory
to theServerConnector
configured byjetty-ssl.xml
to support the http2 protocol. jetty-alpn.xml
-
Adds an
ALPNServerConnectionFactory
to theServerConnector
configured byjetty-ssl.xml
which allows the one SSL connector to support multiple protocols with the ALPN extension used to select the protocol to be used for each connection.
Constructing a ServerConnector
The services a ServerConnector
instance uses are set by constructor injection and once instantiated cannot be changed.
Many of the services may be defaulted with null or 0 values so that a reasonable default is used, thus for most purposes only the Server and the connection factories need to be passed to the connector constructor. In Jetty XML (that is, in jetty-http.xml
) you can do this by:
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<!-- insert one or more factories here -->
</Array>
</Arg>
<!-- set connector fields here -->
</New>
You can see the other arguments that can be passed when constructing a ServerConnector
in the Javadoc.
Typically the defaults are sufficient for almost all deployments.
Network Settings
You can configure connector network settings by calling setters on the connector before it is started. For example, you can set the port with the Jetty XML:
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="factories"><!-- insert one or more factories here --></Arg>
<Set name="port">8080</Set>
</New>
Values in Jetty XML can also be parameterized so that they may be passed from property files or set on the command line.
Thus typically the port is set within Jetty XML, but uses the Property
element to be customizable:
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="factories"><!-- insert one or more factories here --></Arg>
<Set name="port"><Property name="jetty.http.port" default="8080"/></Set>
</New>
The network settings available for configuration on the ServerConnector
include:
Field | Description |
---|---|
host |
The network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, bind to all interfaces. |
port |
The configured port for the connector or 0 a random available port may be used (selected port available via |
idleTimeout |
The time in milliseconds that the connection can be idle before it is closed. |
defaultProtocol |
The name of the default protocol used to select a |
stopTimeout |
The time in milliseconds to wait before gently stopping a connector. |
acceptQueueSize |
The size of the pending connection backlog. The exact interpretation is JVM and operating system specific and you can ignore it. Higher values allow more connections to wait pending an acceptor thread. Because the exact interpretation is deployment dependent, it is best to keep this value as the default unless there is a specific connection issue for a specific OS that you need to address. |
reuseAddress |
Allow the server socket to be rebound even if in TIME_WAIT. For servers it is typically OK to leave this as the default true. |
HTTP Configuration
The HttpConfiguration
class holds the configuration for HttpChannel
s, which you can create 1:1 with each HTTP connection or 1:n on a multiplexed HTTP/2 connection.
Thus a HttpConfiguration
object is injected into both the HTTP and HTTP/2 connection factories.
To avoid duplicate configuration, the standard Jetty distribution creates the common HttpConfiguration
instance in jetty.xml
, which is a Ref
element then used in jetty-http.xml
, jetty-https.xml
and in jetty-http2.xml
.
A typical configuration of HttpConfiguration is:
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Set name="secureScheme">https</Set>
<Set name="securePort"><Property name="jetty.ssl.port" default="8443" /></Set>
<Set name="outputBufferSize">32768</Set>
<Set name="requestHeaderSize">8192</Set>
<Set name="responseHeaderSize">8192</Set>
</New>
This example HttpConfiguration may be used by reference to the ID “httpConfig”:
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config"><Ref refid="httpConfig" /></Arg>
</New>
</Item>
</Array>
</Arg>
<!-- ... -->
</New>
</Arg>
</Call>
This same httpConfig
is referenced by the SecuredRedirectHandler
when redirecting secure requests.
Please note that if your httpConfig
does not include a secureScheme
or securePort
or there is no HttpConfiguration
present these types of secured requests will be returned a 403
error.
For SSL-based connectors (in jetty-https.xml
and jetty-http2.xml
), the common “httpConfig” instance is used as the basis to create an SSL specific configuration with ID “sslHttpConfig”:
<New id="sslHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Arg><Ref refid="httpConfig"/></Arg>
<Call name="addCustomizer">
<Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
</Call>
</New>
This adds a SecureRequestCustomizer
which adds SSL Session IDs and certificate information as request attributes.
SSL Context Configuration
The SSL/TLS connectors for HTTPS and HTTP/2 require a certificate to establish a secure connection.
Jetty holds certificates in standard JVM keystores and are configured as keystore and truststores on a SslContextFactory.Server
instance that is injected into an SslConnectionFactory
instance.
An example using the keystore distributed with Jetty (containing a self signed test certificate) is in jetty-https.xml
.
Read more about SSL keystores in Configuring SSL.
Proxy / Load Balancer Connection Configuration
Often a Connector needs to be configured to accept connections from an intermediary such as a Reverse Proxy and/or Load Balancer deployed in front of the server. In such environments, the TCP/IP connection terminating on the server does not originate from the client, but from the intermediary, so that the Remote IP and port number can be reported incorrectly in logs and in some circumstances the incorrect server address and port may be used.
Thus Intermediaries typically implement one of several de facto standards to communicate to the server information about the original client connection terminating on the intermediary.
Jetty supports the X-Forwarded-For
header and the Proxy Protocol mechanisms as described below.
The XML files in the Jetty distribution contain commented out examples of both the |
X-Forward-for Configuration
The X-Forwarded-for
header and associated headers are a de facto standard where intermediaries add HTTP headers to each request they forward to describe the originating connection.
These headers can be interpreted by an instance of ForwardedRequestCustomizer
which can be added to a HttpConfiguration
as follows:
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Set name="outputBufferSize">32768</Set>
<Set name="requestHeaderSize">8192</Set>
<Set name="responseHeaderSize">8192</Set>
<Call name="addCustomizer">
<Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
</Call>
</New>
Proxy Protocol
The Proxy Protocol is the de facto standard created by HAProxy and used by environments such as Amazon Elastic Cloud.
This mechanism is independent of any protocol, so it can be used for HTTP2, TLS etc.
The information about the client connection is sent as a small data frame on each newly established connection.
In Jetty, this protocol can be handled by the ProxyConnectionFactory
which parses the data frame and then instantiates the next ConnectionFactory
on the connection with an end point that has been customized with the data obtained about the original client connection.
The connection factory can be added to any ServerConnector
and should be the first ConnectionFactory
.
An example of adding the factory to a HTTP connector is shown below:
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.ProxyConnectionFactory"/>
</Item>
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config"><Ref refid="httpConfig" /></Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="jetty.http.port" default="80" /></Set>
</New>
</Arg>
</Call>
Configuring SSL/TLS
This document provides an overview of how to configure SSL and TLS for Jetty.
Configuring Jetty for SSL
To configure Jetty for SSL, complete the tasks in the following sections:
TLS and SSL versions
Which browser/OS supports which protocols can be found on Wikipedia.
-
TLS v1.2: The protocol which should be used wherever possible. All CBC based ciphers are supported since Java 7, the new GCM modes are supported since Java 8.
Older Protocols
TLS v1.0, v1.1 and SSL v3 are no longer supported by default. If your Jetty implementation requires these protocols for legacy support, they can be enabled manually.
Once TLS v1.3 is released, there will be no workaround available for TLS v1.0 or v1.1. Plans for TLS v1.3 include banning ciphers with known vulnerabilities from being present at any level. It is recommended to upgrade any clients using these ciphers as soon as possible or face being locked into a outdated version of Jetty, Java or even OS. |
By default, Jetty excludes these ciphers in the SslContextFactory
.
You can re-enable these by re-declaring the ciphers you want excluded in code:
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setExcludeCipherSuites("^.*_(MD5|SHA|SHA1)$");
If, after making these changes, you still have issues using these ciphers they are likely being blocked at the JVM level.
Locate the $JAVA_HOME/jre/lib/security/
directory for the java.security
file and examine it for any configuration that is excluding ciphers or algorithms (depending on the version of the JVM you are using the nomenclature may be different).
Understanding Certificates and Keys
Configuring SSL can be a confusing experience of keys, certificates, protocols and formats, thus it helps to have a reasonable understanding of the basics. The following links provide some good starting points:
-
Certificates:
-
Keytool:
-
Other tools:
-
OpenSSL:
OpenSSL vs. Keytool
For testing, the keytool
utility bundled with the JDK provides the simplest way to generate the key and certificate you need.
You can also use the OpenSSL tools to generate keys and certificates, or to convert those that you have used with Apache or other servers. Since Apache and other servers commonly use the OpenSSL tool suite to generate and manipulate keys and certificates, you might already have some keys and certificates created by OpenSSL, or you might also prefer the formats OpenSSL produces.
If you want the option of using the same certificate with Jetty or a web server such as Apache not written in Java, you might prefer to generate your private key and certificate with OpenSSL.
Generating Key Pairs and Certificates
The simplest way to generate keys and certificates is to use the keytool
application that comes with the JDK, as it generates keys and certificates directly into the keystore.
See Generating Keys and Certificates with JDK’s keytool.
If you already have keys and certificates, see Loading Keys and Certificates to load them into a JSSE keystore. This section also applies if you have a renewal certificate to replace one that is expiring.
The examples below generate only basic keys and certificates. You should read the full manuals of the tools you are using if you want to specify:
-
The key size
-
The certificate expiration date
-
Alternate security providers
Generating Keys and Certificates with JDK’s keytool
The following command generates a key pair and certificate directly into file keystore
:
$ keytool -keystore keystore -alias jetty -genkey -keyalg RSA
The DSA key algorithm certificate produces an error after loading several pages. In a browser, it displays a message "Could not establish an encrypted connection because certificate presented by localhost as an invalid signature." The solution is to use RSA for the key algorithm. |
This command prompts for information about the certificate and for passwords to protect both the keystore and the keys within it. The only mandatory response is to provide the fully qualified host name of the server at the "first and last name" prompt. For example:
$ keytool -keystore keystore -alias jetty -genkey -keyalg RSA -sigalg SHA256withRSA
Enter keystore password: password
What is your first and last name?
[Unknown]: jetty.eclipse.org
What is the name of your organizational unit?
[Unknown]: Jetty
What is the name of your organization?
[Unknown]: Mort Bay Consulting Pty. Ltd.
What is the name of your City or Locality?
[Unknown]:
What is the name of your State or Province?
[Unknown]:
What is the two-letter country code for this unit?
[Unknown]:
Is CN=jetty.eclipse.org, OU=Jetty, O=Mort Bay Consulting Pty. Ltd.,
L=Unknown, ST=Unknown, C=Unknown correct?
[no]: yes
Enter key password for <jetty>
(RETURN if same as keystore password):
$
You now have the minimal requirements to run an SSL connection and could proceed directly to configure an SSL connector. However, the browser will not trust the certificate you have generated, and prompts the user to this effect. While what you have at this point is often sufficient for testing, most public sites need a trusted certificate, which is demonstrated in the section generating a CSR with keytool.
If you want to use only a self signed certificate for some kind of internal admin panel add -validity <days> to the keytool call above, otherwise your certificate is only valid for one month.
If you are using Java 8 or later, then you may also use the SAN extension to set one or more names that the certificate applies to:
$ keytool -keystore keystore -alias jetty -genkey -keyalg RSA -sigalg SHA256withRSA -ext 'SAN=dns:jetty.eclipse.org,dns:*.jetty.org'
...
Generating Keys and Certificates with OpenSSL
The following command generates a key pair in the file jetty.key
:
$ openssl genrsa -aes128 -out jetty.key
You might also want to use the -rand
file argument to provide an arbitrary file that helps seed the random number generator.
The following command generates a certificate for the key into the file jetty.crt
:
$ openssl req -new -x509 -newkey rsa:2048 -sha256 -key jetty.key -out jetty.crt
Adding -sha256 ensures to get a certificate with the now recommended SHA-256 signature algorithm. For the those with heightened security in mind, add -b4096 to get a 4069 bit key.
The next command prompts for information about the certificate and for passwords to protect both the keystore and the keys within it. The only mandatory response is to provide the fully qualified host name of the server at the "Common Name" prompt. For example:
$ openssl genrsa -aes128 -out jetty.key
Generating RSA private key, 2048 bit long modulus
..............+++
......................................................................+++
e is 65537 (0x10001)
Enter pass phrase for jetty.key:
Verifying - Enter pass phrase for jetty.key:
$ openssl req -new -x509 -newkey rsa:2048 -sha256 -key jetty.key -out jetty.crt
Enter pass phrase for jetty.key:
You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank.
For some fields there will be a default value.
If you enter '.', the field will be left blank.
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Mort Bay Consulting Pty. Ltd.
Organizational Unit Name (eg, section) []:Jetty
Common Name (e.g. server FQDN or YOUR name) []:jetty.eclipse.org
Email Address []:
$
You now have the minimal requirements to run an SSL connection and could proceed directly to Loading Keys and Certificates to load these keys and certificates into a JSSE keystore. However the browser will not trust the certificate you have generated, and prompts the user to this effect. While what you have at this point is often sufficient for testing, most public sites need a trusted certificate, which is demonstrated in the section, Generating a CSR from OpenSSL to obtain a certificate.
Using Keys and Certificates from Other Sources
If you have keys and certificates from other sources, you can proceed directly to Loading Keys and Certificates.
Requesting a Trusted Certificate
The keys and certificates generated with JDK’s keytool
and OpenSSL are sufficient to run an SSL connector.
However the browser will not trust the certificate you have generated, and it will prompt the user to this effect.
To obtain a certificate that most common browsers will trust, you need to request a well-known certificate authority (CA) to sign your key/certificate. Such trusted CAs include: AddTrust, Entrust, GeoTrust, RSA Data Security, Thawte, VISA, ValiCert, Verisign, and beTRUSTed, among others. Each CA has its own instructions (look for JSSE or OpenSSL sections), but all involve a step that generates a certificate signing request (CSR).
Generating a CSR with keytool
The following command generates the file jetty.csr
using keytool
for a key/cert already in the keystore:
$ keytool -certreq -alias jetty -keystore keystore -file jetty.csr
Generating a CSR from OpenSSL
The following command generates the file jetty.csr
using OpenSSL for a key in the file jetty.key
:
$ openssl req -new -key jetty.key -out jetty.csr
Notice that this command uses only the existing key from jetty.key
file, and not a certificate in jetty.crt
as generated with OpenSSL.
You need to enter the details for the certificate again.
Loading Keys and Certificates
Once a CA has sent you a certificate, or if you generated your own certificate without keytool
, you need to load it into a JSSE keystore.
You need both the private key and the certificate in the JSSE keystore.
You should load the certificate into the keystore used to generate the CSR with |
Loading Certificates with keytool
You can use keytool
to load a certificate in PEM form directly into a keystore.
The PEM format is a text encoding of certificates; it is produced by OpenSSL, and is returned by some CAs.
An example PEM file is:
jetty.crt
-----BEGIN CERTIFICATE-----
MIICSDCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQQFADBUMSYwJAYDVQQKEx1Nb3J0
IEJheSBDb25zdWx0aW5nIFB0eS4gTHRkLjEOMAwGA1UECxMFSmV0dHkxGjAYBgNV
BAMTEWpldHR5Lm1vcnRiYXkub3JnMB4XDTAzMDQwNjEzMTk1MFoXDTAzMDUwNjEz
MTk1MFowVDEmMCQGA1UEChMdTW9ydCBCYXkgQ29uc3VsdGluZyBQdHkuIEx0ZC4x
DjAMBgNVBAsTBUpldHR5MRowGAYDVQQDExFqZXR0eS5tb3J0YmF5Lm9yZzBcMA0G
CSqGSIb3DQEBAQUAA0sAMEgCQQC5V4oZeVdhdhHqa9L2/ZnKySPWUqqy81riNfAJ
7uALW0kEv/LtlG34dOOcVVt/PK8/bU4dlolnJx1SpiMZbKsFAgMBAAGjga4wgasw
HQYDVR0OBBYEFFV1gbB1XRvUx1UofmifQJS/MCYwMHwGA1UdIwR1MHOAFFV1gbB1
XRvUx1UofmifQJS/MCYwoVikVjBUMSYwJAYDVQQKEx1Nb3J0IEJheSBDb25zdWx0
aW5nIFB0eS4gTHRkLjEOMAwGA1UECxMFSmV0dHkxGjAYBgNVBAMTEWpldHR5Lm1v
cnRiYXkub3JnggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADQQA6NkaV
OtXzP4ayzBcgK/qSCmF44jdcARmrXhiXUcXzjxsLjSJeYPJojhUdC2LQKy+p4ki8
Rcz6oCRvCGCe5kDB
-----END CERTIFICATE-----
The following command loads a PEM encoded certificate in the jetty.crt
file into a JSSE keystore:
$ keytool -keystore keystore -import -alias jetty -file jetty.crt -trustcacerts
If the certificate you receive from the CA is not in a format that keytool
understands, you can use the openssl
command to convert formats:
$ openssl x509 -in jetty.der -inform DER -outform PEM -out jetty.crt
Loading Keys and Certificates via PKCS12
If you have a key and certificate in separate files, you need to combine them into a PKCS12 format file to load into a new keystore. The certificate can be one you generated yourself or one returned from a CA in response to your CSR.
The following OpenSSL command combines the keys in jetty.key
and the certificate in the jetty.crt
file into the jetty.pkcs12
file:
$ openssl pkcs12 -inkey jetty.key -in jetty.crt -export -out jetty.pkcs12
If you have a chain of certificates, because your CA is an intermediary, build the PKCS12 file as follows:
$ cat example.crt intermediate.crt [intermediate2.crt] ... rootCA.crt > cert-chain.txt
$ openssl pkcs12 -export -inkey example.key -in cert-chain.txt -out example.pkcs12
The order of certificates must be from server to rootCA, as per RFC2246 section 7.4.2. |
OpenSSL asks for an export password.
A non-empty password is required to make the next step work.
Load the resulting PKCS12 file into a JSSE keystore with keytool
:
$ keytool -importkeystore -srckeystore jetty.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
Renewing Certificates
If you are updating your configuration to use a newer certificate, as when the old one is expiring, just load the newer certificate as described in the section, Loading Keys and Certificates. If you imported the key and certificate originally using the PKCS12 method, use an alias of "1" rather than "jetty", because that is the alias the PKCS12 process enters into the keystore.
Layout of keystore and truststore
The keystore
only contains the server’s private key and certificate.

├── PrivateKeyEntry │ ├── PrivateKey │ ├── Certificate chain │ │ ├── Server certificate (end entity) │ │ ├── Intermediary CA certificate │ │ └── Root CA certificate ├── TrustedCertEntry │ └── Intermediary CA certificate └── TrustedCertEntry └── Root CA certificate
Both the |
$ cd $JETTY_BASE
$ keytool -list -keystore etc/keystore -storetype jks -storepass '' -v
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 3 entries
Alias name: *.example.com
Creation date: Sep 20, 2016
Entry type: PrivateKeyEntry
Certificate chain length: 3
Certificate[1]:
Owner: CN=*.example.com, OU=Web Servers, O="Example.com Co.,Ltd.", C=CN
Issuer: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Serial number: b63af619ff0b4c368735113ba5db8997
Valid from: Mon Sep 12 15:09:49 CST 2016 until: Wed Sep 12 15:09:49 CST 2018
Certificate fingerprints:
MD5: D9:26:CC:27:77:9D:26:FE:67:4C:BE:FF:E3:95:1E:97
SHA1: AF:DC:D2:65:6A:33:42:E3:81:9E:4D:19:0D:22:20:C7:6F:2F:11:D0
SHA256: 43:E8:21:5D:C6:FB:A0:7D:5D:7B:9C:8B:8D:E9:4B:52:BF:50:0D:90:4F:61:C2:18:9E:89:AA:4C:C2:93:BD:32
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 44 9B AD 31 E7 FE CA D5 5A 8E 17 55 F9 F0 1D 6B D..1....Z..U...k
0010: F5 A5 8F C1 ....
]
]
#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]
#3: ObjectId: 2.5.29.37 Criticality=true
ExtendedKeyUsages [
serverAuth
clientAuth
]
#4: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
Key_Encipherment
Data_Encipherment
]
#5: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 7D 26 36 73 61 5E 08 94 AD 25 13 46 DB DB 95 25 .&6sa^...%.F...%
0010: BF 82 5A CA ..Z.
]
]
Certificate[2]:
Owner: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Serial number: f6e7b86f6fdb467f9498fb599310198f
Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2035
Certificate fingerprints:
MD5: ED:A3:91:57:D8:B8:6E:B1:01:58:55:5C:33:14:F5:99
SHA1: D9:A4:93:9D:A6:F8:A3:F9:FD:85:51:E2:C5:2E:0B:EE:80:E7:D0:22
SHA256: BF:54:7A:F6:CA:0C:FA:EF:93:B6:6B:6E:2E:D7:44:A8:40:00:EC:69:3A:2C:CC:9A:F7:FE:8E:6F:C0:FA:22:38
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
0010: E6 E6 04 46 ...F
]
]
#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
Key_CertSign
Crl_Sign
]
#4: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 44 9B AD 31 E7 FE CA D5 5A 8E 17 55 F9 F0 1D 6B D..1....Z..U...k
0010: F5 A5 8F C1 ....
]
]
Certificate[3]:
Owner: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Serial number: f0a45bc9972c458cbeae3f723055f1ac
Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2114
Certificate fingerprints:
MD5: 50:61:62:22:71:60:F7:69:2E:27:42:6B:62:31:82:79
SHA1: 7A:6D:A6:48:B1:43:03:3B:EA:A0:29:2F:19:65:9C:9B:0E:B1:03:1A
SHA256: 05:3B:9C:5B:8E:18:61:61:D1:9C:AA:0E:8C:B1:EA:44:C2:6E:67:5D:96:30:EC:8C:F6:6F:E1:EC:AD:00:60:F1
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
0010: E6 E6 04 46 ...F
]
]
#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
Key_CertSign
Crl_Sign
]
#4: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
0010: E6 E6 04 46 ...F
]
]
*******************************************
*******************************************
Alias name: example.com co.,ltd. etp ca
Creation date: Sep 20, 2016
Entry type: trustedCertEntry
Owner: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Serial number: f6e7b86f6fdb467f9498fb599310198f
Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2035
Certificate fingerprints:
MD5: ED:A3:91:57:D8:B8:6E:B1:01:58:55:5C:33:14:F5:99
SHA1: D9:A4:93:9D:A6:F8:A3:F9:FD:85:51:E2:C5:2E:0B:EE:80:E7:D0:22
SHA256: BF:54:7A:F6:CA:0C:FA:EF:93:B6:6B:6E:2E:D7:44:A8:40:00:EC:69:3A:2C:CC:9A:F7:FE:8E:6F:C0:FA:22:38
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
0010: E6 E6 04 46 ...F
]
]
#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
Key_CertSign
Crl_Sign
]
#4: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 44 9B AD 31 E7 FE CA D5 5A 8E 17 55 F9 F0 1D 6B D..1....Z..U...k
0010: F5 A5 8F C1 ....
]
]
*******************************************
*******************************************
Alias name: example.com co.,ltd. root ca
Creation date: Sep 20, 2016
Entry type: trustedCertEntry
Owner: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Serial number: f0a45bc9972c458cbeae3f723055f1ac
Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2114
Certificate fingerprints:
MD5: 50:61:62:22:71:60:F7:69:2E:27:42:6B:62:31:82:79
SHA1: 7A:6D:A6:48:B1:43:03:3B:EA:A0:29:2F:19:65:9C:9B:0E:B1:03:1A
SHA256: 05:3B:9C:5B:8E:18:61:61:D1:9C:AA:0E:8C:B1:EA:44:C2:6E:67:5D:96:30:EC:8C:F6:6F:E1:EC:AD:00:60:F1
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
0010: E6 E6 04 46 ...F
]
]
#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
Key_CertSign
Crl_Sign
]
#4: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
0010: E6 E6 04 46 ...F
]
]
*******************************************
*******************************************
In addition, you can split $JETTY/etc/keystore
as two files.
One is $JETTY/etc/keystore
which only contains the server’s private key and certificate,
the other is $JETTY/etc/truststore
which contains intermediary CA and root CA.
$JETTY/etc/keystore
└── PrivateKeyEntry ├── PrivateKey └── Certificate chain └── Server certificate (end entity)
$JETTY/etc/truststore
├── TrustedCertEntry │ └── Intermediary CA certificate └── TrustedCertEntry └── Root CA certificate
Configuring the Jetty SslContextFactory
The generated SSL certificates from above are held in the key store are configured in an instance of SslContextFactory.Server object.
The SslContextFactory
is responsible for:
-
Creating the Java
SslEngine
used by Jetty’s Connectors and Jetty’s Clients (HTTP/1, HTTP/2, and WebSocket). -
Managing Keystore Access
-
Managing Truststore Access
-
Managing Protocol selection via Excludes / Includes list
-
Managing Cipher Suite selection via Excludes / Includes list
-
Managing order of Ciphers offered (important for TLS/1.2 and HTTP/2 support)
-
SSL Session Caching options
-
Certificate Revocation Lists and Distribution Points (CRLDP)
-
OCSP Support
-
Client Authentication Support
For Jetty Connectors, the configured SslContextFactory.Server
is injected into a specific ServerConnector SslConnectionFactory
.
For Jetty Clients, the various constructors support using a configured SslContextFactory.Client
.
While the SslContextFactory
can operate without a keystore (this mode is most suitable for the various Jetty Clients) it is best practice to at least configure the keystore being used.
- setKeyStorePath
-
The configured keystore to use for all SSL/TLS in configured Jetty Connector (or Client).
As a keystore is vital security information, it can be desirable to locate the file in a directory with very restricted access. |
- setKeyStorePassword
-
The keystore password may be set here in plain text, or as some measure of protection from casual observation, it may be obfuscated using the Password class.
- setTrustStorePath
-
This is used if validating client certificates and is typically set to the same path as the keystore.
- setKeyManagerPassword
-
The password that is passed to the
KeyManagerFactory.init(…)
. If there is nokeymanagerpassword
, then thekeystorepassword
is used instead. If there is notrustmanager
set, then the keystore is used as the trust store and thekeystorepassword
is used as the truststore password. - setExcludeCipherSuites / setIncludeCipherSuites
-
This allows for the customization of the selected Cipher Suites that will be used by SSL/TLS.
- setExcludeProtocols / setIncludeProtocols
-
This allows for the customization of the selected Protocols that will be used by SSL/TLS.
When working with Includes / Excludes, it is important to know that Excludes will always win. The selection process is to process the JVM list of available Cipher Suites or Protocols against the include list, then remove the excluded ones. Be aware that each Include / Exclude list has a Set method (replace the list) or Add method (append the list). |
The keystore and truststore passwords may also be set using the system properties: |
Conscrypt SSL
Jetty includes support for Google’s Conscrypt SSL, which is built on their fork of OpenSSL, BoringSSL.
Implementing Conscrypt for the server or client is very straightforward process - simply instantiate an instance of Conscrypt’s OpenSSLProvider
and set Conscrypt
as a provider for Jetty’s SslContextFactory
:
...
Security.addProvider(new OpenSSLProvider());
...
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath("path/to/keystore");
sslContextFactory.setKeyStorePassword("CleverKeyStorePassword");
sslContextFactory.setKeyManagerPassword("OBF:VerySecretManagerPassword");
sslContextFactory.setProvider("Conscrypt");
...
If you are using the Jetty Distribution, please see the section on enabling the Conscrypt SSL module.
If you are using Conscrypt with Java 8, you must exclude TLSv1.3
protocol as it is now enabled per default with Conscrypt 2.0.0 but not supported by Java 8.
Configuring SNI
From Java 8, the JVM contains support for the Server Name Indicator (SNI) extension, which allows an SSL connection handshake to indicate one or more DNS names that it applies to.
To support this, the SslContextFactory
is used.
The SslContextFactory
will look for multiple X509 certificates within the keystore, each of which may have multiple DNS names (including wildcards) associated with the Subject Alternate Name extension.
When using the SslContextFactory
, the correct certificate is automatically selected if the SNI extension is present in the handshake.
Disabling/Enabling Specific Cipher Suites
New cipher suites are always being developed to stay ahead of attacks. It’s only a matter of time before the best of suites is exploited though, and making sure your server is up-to-date in this regard is paramount for any implementation. As an example, to avoid the BEAST attack it is necessary to configure a specific set of cipher suites. This can either be done via SslContext.setIncludeCipherSuites(java.lang.String…) or viaSslContext.setExcludeCipherSuites(java.lang.String…).
It’s crucial that you use the exact names of the cipher suites as used/known by the JDK.
You can get them by obtaining an instance of SSLEngine and call getSupportedCipherSuites()
.
Tools like ssllabs.com might report slightly different names which will be ignored.
It is important to stay up-to-date with the latest supported cipher suites. Be sure to consult Oracle’s JRE and JDK Cryptographic Roadmap frequently for recent and upcoming changes to supported ciphers. |
It’s recommended to install the Java Cryptography Extension (JCE) Unlimited Strength policy files in your JRE to get full strength ciphers such as AES-256.
The files can be found on the Java download page.
Just overwrite the two present JAR files in |
Both setIncludeCipherSuites
and setExcludeCipherSuites
can be fed by the exact cipher suite name used in the JDK or by using regular expressions.
If you have a need to adjust the Includes or Excludes, then this is best done with a custom XML that configures the SslContextFactory
to suit your needs.
Jetty does allow users to enable weak/deprecated cipher suites (or even no cipher suites at all). By default, if you have these suites enabled warning messages will appear in the server logs. |
To do this, first create a new ${jetty.base}/etc/tweak-ssl.xml
file (this can be any name, just avoid prefixing it with "jetty-").
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
"http://www.eclipse.org/jetty/configure_9_3.dtd">
<!-- Tweak SsslContextFactory Includes / Excludes -->
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server">
<!-- Mitigate SLOTH Attack -->
<Call name="addExcludeCipherSuites">
<Arg>
<Array type="String">
<Item>.*_RSA_.*SHA1$</Item>
<Item>.*_RSA_.*SHA$</Item>
<Item>.*_RSA_.*MD5$</Item>
</Array>
</Arg>
</Call>
</Configure>
This new XML will configure the id sslContextFactory
further (this id is first created by the ssl
module and its associated ${jetty.home}/etc/jetty-ssl-context.xml
).
You can do anything you want with the SslContextFactory
in use by the Jetty Distribution from this tweaked XML.
To make sure that your ${jetty.base}
uses this new XML, add it to the end of your ${jetty.base}/start.ini
or ${jetty.base}/start.d/server.ini
.
$ cd /path/to/mybase
$ ls -l
drwxrwxr-x. 2 user group 4096 Feb 2 11:47 etc/
-rw-rw-r--. 1 user group 4259 Feb 2 11:47 start.ini
$ tail start.ini
# Module: https
--module=https
etc/tweak-ssl.xml
$
The default |
You can enable the |
Additional Include / Exclude examples:
Example: Include all ciphers which support Forward Secrecy using regex:
<!-- Enable Forward Secrecy Ciphers.
Note: this replaces the default Include Cipher list -->
<Set name="IncludeCipherSuites">
<Array type="String">
<Item>TLS_DHE_RSA.*</Item>
<Item>TLS_ECDHE.*</Item>
</Array>
</Set>
Example: Exclude all old, insecure or anonymous cipher suites:
<!-- Eliminate Old / Insecure / Anonymous Ciphers -->
<Call name="addExcludeCipherSuites">
<Arg>
<Array type="String">
<Item>.*NULL.*</Item>
<Item>.*RC4.*</Item>
<Item>.*MD5.*</Item>
<Item>.*DES.*</Item>
<Item>.*DSS.*</Item>
</Array>
</Arg>
</Call>
Example: Since 2014 SSLv3 is considered insecure and should be disabled.
<!-- Eliminate Insecure Protocols -->
<Call name="addExcludeProtocols">
<Arg>
<Array type="java.lang.String">
<Item>SSL</Item>
<Item>SSLv2</Item>
<Item>SSLv2Hello</Item>
<Item>SSLv3</Item>
</Array>
</Arg>
</Call>
Note that disabling SSLv3 prevents very old browsers like Internet Explorer 6 on Windows XP from connecting. |
Example: TLS renegotiation could be disabled too to prevent an attack based on this feature.
<Set name="renegotiationAllowed">FALSE</Set>
You can view what cipher suites are enabled and disabled by performing a server dump.
To perform a server dump upon server startup, add jetty.server.dumpAfterStart=true
to the command line when starting the server.
You can also dump the server when shutting down the server instance by adding jetty.server.dumpBeforeStop
.
Specifically, you will want to look for the SslConnectionFactory
portion of the dump.
[my-base]$ java -jar ${JETTY_HOME}/start.jar jetty.server.dumpAfterStart=true
...
| += SslConnectionFactory@18be83e4{SSL->http/1.1} - STARTED
| | += SslContextFactory@42530531(null,null) trustAll=false
| | +- Protocol Selections
| | | +- Enabled (size=3)
| | | | +- TLSv1
| | | | +- TLSv1.1
| | | | +- TLSv1.2
| | | +- Disabled (size=2)
| | | +- SSLv2Hello - ConfigExcluded:'SSLv2Hello'
| | | +- SSLv3 - JreDisabled:java.security, ConfigExcluded:'SSLv3'
| | +- Cipher Suite Selections
| | +- Enabled (size=15)
| | | +- TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
| | | +- TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
| | | +- TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
| | | +- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
| | | +- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
| | | +- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
| | | +- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
| | | +- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
| | | +- TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
| | | +- TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
| | | +- TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
| | | +- TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
| | | +- TLS_EMPTY_RENEGOTIATION_INFO_SCSV
| | | +- TLS_RSA_WITH_AES_128_CBC_SHA256
| | | +- TLS_RSA_WITH_AES_128_GCM_SHA256
| | +- Disabled (size=42)
| | +- SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_DHE_DSS_WITH_DES_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_DHE_RSA_WITH_DES_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_DH_anon_WITH_3DES_EDE_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_DH_anon_WITH_DES_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_RSA_EXPORT_WITH_DES40_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_RSA_WITH_3DES_EDE_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_RSA_WITH_DES_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_RSA_WITH_NULL_MD5 - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- SSL_RSA_WITH_NULL_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_DHE_DSS_WITH_AES_128_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_DHE_RSA_WITH_AES_128_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_DH_anon_WITH_AES_128_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_DH_anon_WITH_AES_128_CBC_SHA256 - JreDisabled:java.security
| | +- TLS_DH_anon_WITH_AES_128_GCM_SHA256 - JreDisabled:java.security
| | +- TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDHE_ECDSA_WITH_NULL_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDHE_RSA_WITH_NULL_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDH_ECDSA_WITH_NULL_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDH_RSA_WITH_AES_128_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDH_RSA_WITH_NULL_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDH_anon_WITH_AES_128_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_ECDH_anon_WITH_NULL_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_KRB5_WITH_3DES_EDE_CBC_MD5 - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_KRB5_WITH_3DES_EDE_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_KRB5_WITH_DES_CBC_MD5 - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_KRB5_WITH_DES_CBC_SHA - JreDisabled:java.security, ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_RSA_WITH_AES_128_CBC_SHA - ConfigExcluded:'^.*_(MD5|SHA|SHA1)$'
| | +- TLS_RSA_WITH_NULL_SHA256 - JreDisabled:java.security
...
In the example above you can see both the enabled/disabled protocols and included/excluded cipher suites. For disabled or excluded protocols and ciphers, the reason they are disabled is given - either due to JVM restrictions, configuration or both. As a reminder, when configuring your includes/excludes, excludes always win.
Dumps can be configured as part of the jetty.xml
configuration for your server.
Please see the documentation on the Jetty Dump Tool for more information.
SslContextFactory KeyStore Reload
Jetty can be configured to monitor the directory of the KeyStore file specified in the SslContextFactory, and reload the SslContextFactory if any changes are detected to the KeyStore file.
If changes need to be done to other file such as the TrustStore file, this must be done before the change to the Keystore
file which will then trigger the SslContextFactory
reload.
With the Jetty distribution this feature can be used by simply activating the ssl-reload
startup module.
For embedded usage the KeyStoreScanner
should be created given the SslContextFactory
and added as a bean on the Server.
SSL in the Jetty Distribution
When making use of the Jetty Distribution, enabling SSL support is as easy as activating the appropriate module. Jetty supports both the default JSSE provider and the Conscrypt provider as SSL implementations.
Default JSSE SSL Configuration
For the default SSL support, simply activate the ssl
module:
$ cd /path/to/mybase
$ java -jar ${JETTY_HOME}/start.jar --add-to-startd=ssl
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO : ssl initialised in ${jetty.base}/start.d/ssl.ini
INFO : Base directory was modified
$ tree
.
├── etc
│ └── keystore
└── start.d
├── server.ini
└── ssl.ini
When you open start.d/ssl.ini
, you will see several commented properties ready for use when configuring SslContextFactory
basics.
To highlight some of the more commonly used properties:
- jetty.ssl.host
-
Configures which interfaces the SSL/TLS Connector should listen on.
- jetty.ssl.port
-
Configures which port the SSL/TLS Connector should listen on.
- jetty.httpConfig.securePort
-
If a webapp needs to redirect to a secure version of the same resource, then this is the port reported back on the response
location
line (having this be separate is useful if you have something sitting in front of Jetty, such as a Load Balancer or proxy). - jetty.sslContext.keyStorePath
-
Sets the location of the
keystore
that you configured with your certificates. - jetty.sslContext.keyStorePassword
-
Sets the Password for the
keystore
.
Conscrypt SSL Configuration
Enabling Conscrypt SSL is just as easy as default SSL - enable both the conscrypt
and ssl
modules:
$ cd ${JETTY_HOME}
$ java -jar ../start.jar --add-to-start=ssl,conscrypt
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: conscrypt
+ Conscrypt is distributed under the Apache Licence 2.0
+ https://github.com/google/conscrypt/blob/master/LICENSE
Proceed (y/N)? y
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : conscrypt initialized in ${jetty.base}/start.d/conscrypt.ini
INFO : ssl initialized in ${jetty.base}/start.d/ssl.ini
MKDIR : ${jetty.base}/lib/conscrypt
DOWNLD: https://repo1.maven.org/maven2/org/conscrypt/conscrypt-openjdk-uber/1.0.0.RC11/conscrypt-openjdk-uber-1.0.0.RC11.jar to ${jetty.base}/lib/conscrypt/conscrypt-uber-1.0.0.RC11.jar
MKDIR : ${jetty.base}/etc
COPY : ${jetty.home}/modules/conscrypt/conscrypt.xml to ${jetty.base}/etc/conscrypt.xml
COPY : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
INFO : Base directory was modified
No additional Conscrypt configuration is needed.
SSL-specific parameters, like keyStorePath
and keyStorePassword
can still configured as in the example above, making use of the ${JETTY_BASE}/start.d/ssl.ini
file.
Client Certificate Authentication
To enable client certificate authentication in the Jetty Distribution, you need to enable the both the ssl
and https
modules.
$ cd /path/to/mybase
$ java -jar /path/to/jetty-dist/start.jar --add-to-startd=ssl,https
# Module: ssl
--module=ssl
jetty.ssl.host=0.0.0.0
jetty.ssl.port=8583
jetty.sslContext.keyStorePath=etc/keystore
jetty.sslContext.trustStorePath=etc/truststore
jetty.sslContext.keyStorePassword=OBF:
jetty.sslContext.keyManagerPassword=OBF:
jetty.sslContext.trustStorePassword=OBF:
# Enable client certificate authentication.
jetty.sslContext.needClientAuth=true
# Module: https
--module=https
Configuring Security
Authentication and Authorization
There are two aspects to securing a web application(or context) within the Jetty server:
- Authentication
-
The web application can be configured with a mechanism to determine the identity of the user. This is configured by a mix of standard declarations and jetty specific mechanisms and is covered in this section.
- Authorization
-
Once the identify of the user is known (or not known), the web application can be configured via standard descriptors with security constraints that declare what resources that user may access.
Configuring an Authentication mechanism
Jetty server supports several standard authentication mechanisms: BASIC; DIGEST; FORM; CLIENT-CERT; and other mechanisms can be plugged in using the extensible JASPI or SPNEGO mechanisms.
Internally, configuring an authentication mechanism is done by setting an instance of a the Authenticator interface onto the SecurityHandler of the context, but in most cases it is done by declaring a <login-config>
element in the standard web.xml descriptor or via annotations.
Below is an example taken from the jetty-test-webapp web.xml that configures BASIC authentication:
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Test Realm</realm-name>
</login-config>
The jetty-test-webapp web.xml also includes commented out examples of other DIGEST and FORM configuration:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Test Realm</realm-name>
<form-login-config>
<form-login-page>/logon.html?param=test</form-login-page>
<form-error-page>/logonError.html?param=test</form-error-page>
</form-login-config>
</login-config>
With FORM Authentication, you must also configure URLs of pages to generate a login form and handle errors. Below is a simple HTML form from the test webapp logon.html:
<HTML>
<H1>FORM Authentication demo</H1>
<form method="POST" action="j_security_check">
<table border="0" cellspacing="2" cellpadding="1">
<tr>
<td>Username:</td>
<td><input size="12" value="" name="j_username" maxlength="25" type="text"></td>
</tr>
<tr>
<td>Password:</td>
<td><input size="12" value="" name="j_password" maxlength="25" type="password"></td>
</tr>
<tr>
<td colspan="2" align="center">
<input name="submit" type="submit" value="Login">
</td>
</tr>
</table>
</form>
</HTML>
The Authentication mechanism declared for a context / web application defines how the server obtain authentication credentials from the client, but it does not define how the server checks if those credentials are valid. To check credentials, the server and/or context also need to be configured with a LoginService instance, which may be matched by the declared realm-name.
Security Realms
Security realms allow you to secure your web applications against unauthorized access. Protection is based on authentication that identifies who is requesting access to the webapp and access control that restricts what can be accessed and how it is accessed within the webapp.
A webapp statically declares its security requirements in its web.xml file.
Authentication is controlled by the <login-config>
element.
Access controls are specified by <security-constraint>
and <security-role-ref>
elements.
When a request is received for a protected resource, the web container checks if the user performing the request is authenticated, and if the user has a role assignment that permits access to the requested resource.
The Servlet Specification does not address how the static security information in the WEB-INF/web.xml
file is mapped to the runtime environment of the container.
For Jetty, the LoginService performs this function.
A LoginService
has a unique name, and gives access to information about a set of users.
Each user has authentication information (e.g. a password) and a set of roles associated with him/herself.
You may configure one or many different LoginServices depending on your needs. A single realm would indicate that you wish to share common security information across all of your web applications. Distinct realms allow you to partition your security information webapp by webapp.
When a request to a web application requires authentication or authorization, Jetty will use the <realm-name>
sub-element inside <login-config>
element in the web.xml file to perform an exact match to a LoginService.
Scoping Security Realms
A LoginService
has a unique name, and is composed of a set of users.
Each user has authentication information (for example, a password) and a set of roles associated with him/herself.
You can configure one or many different realms depending on your needs.
-
Configure a single LoginService to share common security information across all of your web applications.
-
Configure distinct LoginServices to partition your security information webapp by webapp.
Globally Scoped
A LoginService is available to all web applications on a Server instance if you add it as a bean to the Server.
Such a definition would go into an xml file in your ${jetty.base}/etc
directory, e.g. ${jetty.base}/etc/my-realm.xml
and you would add this xml file to the execution path via start.ini
or start.d
(you may want to review the material in the Starting Jetty chapter).
Here’s an example of an xml file that defines an in-memory type of LoginService called the HashLoginService:
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set>
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
<Set name="hotReload">true</Set>
</New>
</Arg>
</Call>
</Configure>
If you define more than one LoginService
on a Server, you will need to specify which one you want used for each context.
You can do that by telling the context the name of the LoginService
, or passing it the LoginService
instance.
Here’s an example of doing both of these, using a context xml file:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Get name="securityHandler">
<!-- Either: -->
<Set name="loginService">
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set>
</New>
</Set>
<!-- or if you defined a LoginService called "Test Realm" in jetty.xml : -->
<Set name="realmName">Test Realm</Set>
</Get>
Per-Webapp Scoped
Alternatively, you can define a LoginService
for just a single web application.
Here’s how to define the same HashLoginService, but inside a context xml file:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
<Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test</Set>
<Get name="securityHandler">
<Set name="loginService">
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set>
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
</New>
</Set>
</Get>
</Configure>
Jetty provides a number of different LoginService
types which can be seen in the next section.
Configuring a LoginService
A LoginService
instance is required by each context/webapp that has a authentication mechanism, which is used to check the validity of the username and credentials collected by the authentication mechanism. Jetty provides the following implementations of LoginService
:
- HashLoginService
-
A user realm that is backed by a hash map that is filled either programatically or from a Java properties file.
- JDBCLoginService
-
Uses a JDBC connection to an SQL database for authentication
- DataSourceLoginService
-
Uses a JNDI defined DataSource for authentication
- JAASLoginService
-
Uses a JAAS provider for authentication; see the section on JAAS support for more information
- SpnegoLoginService
-
SPNEGO Authentication; see the section on SPNEGO support for more information.
An instance of a LoginService
can be matched to a context/webapp by:
-
A
LoginService
instance may be set directly on theSecurityHandler
instance via embedded code or IoC XML -
Matching the realm-name defined in web.xml with the name of a
LoginService
instance that has been added to the Server instance as a dependent bean -
If only a single
LoginService
instance has been set on the Server then it is used as the login service for the context
HashLoginService
The HashLoginService
is a simple and efficient login service that loads usernames, credentials and roles from a Java properties file in the format:
username: password[,rolename ...]
Where:
- username
-
is the user’s unique identity
- password
-
is the user’s (possibly obfuscated or MD5 encrypted) password;
- rolename
-
is a role of the user
For example:
admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin
other: OBF:1xmk1w261u9r1w1c1xmq
guest: guest,read-only
You configure the HashLoginService
with a name and a reference to the location of the properties file:
<Item>
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set>
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
</New>
</Item>
You can also configure it to reload the configuration file when changes to it are detected.
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set>
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
<Set name="hotReload">true</Set>
<Call name="start"></Call>
</New>
JDBCLoginService
In this implementation, authentication and role information is stored in a database accessed via JDBC. A properties file defines the JDBC connection and database table information. Here is an example of a properties file for this realm implementation:
jdbcdriver = org.gjt.mm.mysql.Driver
url = jdbc:mysql://localhost/jetty
username = jetty
password = jetty
usertable = users
usertablekey = id
usertableuserfield = username
usertablepasswordfield = pwd
roletable = roles
roletablekey = id
roletablerolefield = role
userroletable = user_roles
userroletableuserkey = user_id
userroletablerolekey = role_id
cachetime = 300
The format of the database tables is (pseudo-sql):
users
(
id integer PRIMARY KEY,
username varchar(100) NOT NULL UNIQUE KEY,
pwd varchar(50) NOT NULL
);
user_roles
(
user_id integer NOT NULL,
role_id integer NOT NULL,
UNIQUE KEY (user_id, role_id),
INDEX(user_id)
);
roles
(
id integer PRIMARY KEY,
role varchar(100) NOT NULL UNIQUE KEY
);
Where:
-
users is a table containing one entry for every user consisting of:
- id
-
the unique identity of a user
- user
-
the name of the user
- pwd
-
the user’s password (possibly obfuscated or MD5 encrypted)
-
user-roles is a table containing one row for every role granted to a user:
- user_id
-
the unique identity of the user
- role_id
-
the role for a user
-
roles is a a table containing one role for every role in the system:
- id
-
the unique identifier of a role
- role
-
a human-readable name for a role
If you want to use obfuscated, MD5 hashed or encrypted passwords the pwd
column of the users
table must be large enough to hold the obfuscated, hashed or encrypted password text plus the appropriate prefix.
You define a JDBCLoginService
with the name of the realm and the location of the properties file describing the database:
<New class="org.eclipse.jetty.security.JDBCLoginService">
<Set name="name">Test JDBC Realm</Set>
<Set name="config">etc/jdbcRealm.properties</Set>
</New>
Authorization
As far as the Servlet Specification is concerned, authorization is based on roles.
As we have seen, a LoginService
associates a user with a set of roles.
When a user requests a resource that is access protected, the LoginService
will be asked to authenticate the user if they are not already, and then asked to confirm if that user possesses one of the roles permitted access to the resource.
Until Servlet 3.1, role-based authorization could define:
-
Access granted to a set of named roles:
<security-constraint>
<web-resource-collection>
<web-resource-name>Foo Admin Data</web-resource-name>
<url-pattern>/foo/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
-
Access totally forbidden, regardless of role:
<security-constraint>
<web-resource-collection>
<web-resource-name>Foo Protected Data</web-resource-name>
<url-pattern>/foo/protected/*</url-pattern>
</web-resource-collection>
<auth-constraint>
</auth-constraint>
</security-constraint>
-
Access granted to a user in any of the roles defined in the effective
web.xml
. This is indicated by the special value of*
for the<role-name>
of a<auth-constraint>
in the<security-constraint>
:
<security-constraint>
<web-resource-collection>
<web-resource-name>Foo Role Data</web-resource-name>
<url-pattern>/foo/role/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
Servlet 3.1 introduced an additional authorization:
-
Access granted to any user who is authenticated, regardless of roles. This is indicated by the special value of
**
for the<role-name>
of a<auth-constraint>
in the<security-constraint>
:
<security-constraint>
<web-resource-collection>
<web-resource-name>Foo Authenticated Data</web-resource-name>
<url-pattern>/foo/authenticated/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>**</role-name>
</auth-constraint>
</security-constraint>
Additionally, when configuring your security constraints you can protect various HTTP methods as well, such as PUT
, GET
, POST
, HEAD
or DELETE
.
This is done by adding the method you want to protect as a <http-method>
in the <web-resource-collection>
.
You can then define roles that should be able to perform these protected methods in an <auth-constraint>
:
<security-constraint>
<web-resource-collection>
<web-resource-name>Foo Authenticated Data</web-resource-name>
<url-pattern>/foo/authenticated/*</url-pattern>
<http-method>DELETE</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
In the above example, only users with an admin
role will be able to perform DELETE
or POST
methods.
Configuring Authorization with Context XML Files
While the examples above show configuration of Authorization in a web.xml
file, they can also be configured as part of the link#context xml file for a web application.
This is especially helpful if authorization needs change over time and need updated without re-packaging the whole web app.
To do this, we add a section for security constraints into the context xml file for our web app as part of the securityHandler
.
In the example below, a HashLoginService
is defined with authorization being granted too foo/*
paths to users with the admin
and manager
roles.
<Configure id="testWebapp" class="org.eclipse.jetty.webapp.WebAppContext">
<Get name="securityHandler">
<Set name="realmName">Test Realm</Set>
<Set name="authMethod">BASIC</Set>
<Call name="addConstraintMapping">
<Arg>
<New class="org.eclipse.jetty.security.ConstraintMapping">
<Set name="pathSpec">/foo/*</Set>
<Set name="constraint">
<New class="org.eclipse.jetty.util.security.Constraint">
<Set name="name">Foo Auth</Set>
<Set name="authenticate">true</Set>
<Set name="roles">
<Array type="java.lang.String">
<Item>admin</Item>
<Item>manager</Item>
</Array>
</Set>
</New>
</Set>
</New>
</Arg>
</Call>
<Set name="loginService">
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set>
<Set name="config">/src/tmp/small-security-test/realm.properties</Set>
</New>
</Set>
</Get>
</Configure>
If roles changed in the future, administrators could easily change this context xml file without having to edit the contents of the web app at all.
Authentication and Authorization with Embedded Jetty
In addition to the distribution, security can be defined as part of an embedded implementation as well.
Below is an example which, like the one above, sets up a server with a HashLoginService
and adds security constraints to restrict access based on roles.
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.embedded;
import java.io.FileNotFoundException;
import java.net.URL;
import java.util.Collections;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.security.Constraint;
public class SecuredHelloHandler
{
public static Server createServer(int port) throws FileNotFoundException
{
// Create a basic jetty server object that will listen on port 8080.
// Note that if you set this to port 0 then a randomly available port
// will be assigned that you can either look in the logs for the port,
// or programmatically obtain it for use in test cases.
Server server = new Server(port);
// Since this example is for our test webapp, we need to setup a
// LoginService so this shows how to create a very simple hashmap based
// one. The name of the LoginService needs to correspond to what is
// configured a webapp's web.xml and since it has a lifecycle of its own
// we register it as a bean with the Jetty server object so it can be
// started and stopped according to the lifecycle of the server itself.
// In this example the name can be whatever you like since we are not
// dealing with webapp realms.
String realmResourceName = "etc/realm.properties";
ClassLoader classLoader = SecuredHelloHandler.class.getClassLoader();
URL realmProps = classLoader.getResource(realmResourceName);
if (realmProps == null)
throw new FileNotFoundException("Unable to find " + realmResourceName);
LoginService loginService = new HashLoginService("MyRealm",
realmProps.toExternalForm());
server.addBean(loginService);
// A security handler is a jetty handler that secures content behind a
// particular portion of a url space. The ConstraintSecurityHandler is a
// more specialized handler that allows matching of urls to different
// constraints. The server sets this as the first handler in the chain,
// effectively applying these constraints to all subsequent handlers in
// the chain.
ConstraintSecurityHandler security = new ConstraintSecurityHandler();
server.setHandler(security);
// This constraint requires authentication and in addition that an
// authenticated user be a member of a given set of roles for
// authorization purposes.
Constraint constraint = new Constraint();
constraint.setName("auth");
constraint.setAuthenticate(true);
constraint.setRoles(new String[]{"user", "admin"});
// Binds a url pattern with the previously created constraint. The roles
// for this constraint mapping are mined from the Constraint itself
// although methods exist to declare and bind roles separately as well.
ConstraintMapping mapping = new ConstraintMapping();
mapping.setPathSpec("/*");
mapping.setConstraint(constraint);
// First you see the constraint mapping being applied to the handler as
// a singleton list, however you can passing in as many security
// constraint mappings as you like so long as they follow the mapping
// requirements of the servlet api. Next we set a BasicAuthenticator
// instance which is the object that actually checks the credentials
// followed by the LoginService which is the store of known users, etc.
security.setConstraintMappings(Collections.singletonList(mapping));
security.setAuthenticator(new BasicAuthenticator());
security.setLoginService(loginService);
// The Hello Handler is the handler we are securing so we create one,
// and then set it as the handler on the
// security handler to complain the simple handler chain.
HelloHandler hh = new HelloHandler();
// chain the hello handler into the security handler
security.setHandler(hh);
return server;
}
public static void main(String[] args) throws Exception
{
int port = ExampleUtil.getPort(args, "jetty.http.port", 8080);
Server server = createServer(port);
// Start things up!
server.start();
// The use of server.join() the will make the current thread join and
// wait until the server is done executing.
server.join();
}
}
Limiting Form Content
Form content sent to the server is processed by Jetty into a map of parameters to be used by the web application. This can be vulnerable to denial of service (DOS) attacks since significant memory and CPU can be consumed if a malicious clients sends very large form content or large number of form keys. Thus Jetty limits the amount of data and keys that can be in a form posted to Jetty.
The default maximum size Jetty permits is 200000 bytes and 1000 keys. You can change this default for a particular webapp or for all webapps on a particular Server instance.
Configuring Default Form Limits via System Properties
There exists 2 system properties that will adjust the default maximum form sizes.
-
org.eclipse.jetty.server.Request.maxFormKeys
- the maximum number of Form Keys allowed -
org.eclipse.jetty.server.Request.maxFormContentSize
- the maximum size of Form Content allowed
Used from command line as such:
$ java -Dorg.eclipse.jetty.server.Request.maxFormKeys=200 -jar ...
$ java -Dorg.eclipse.jetty.server.Request.maxFormContentSize=400000 -jar ...
Or via Java code (make sure you do this before you instantiate any ContextHandler
, ServletContextHandler
, or WebAppContext
)
System.setProperty(ContextHandler.MAX_FORM_KEYS_KEY, "200");
System.setProperty(ContextHandler.MAX_FORM_CONTENT_SIZE_KEY, "400000");
Configuring Form Limits for a Webapp
To configure the form limits for a single web application, the context handler (or webappContext) instance must be configured using the following methods:
ContextHandler.setMaxFormContentSize(int maxSizeInBytes);
ContextHandler.setMaxFormKeys(int formKeys);
These methods may be called directly when embedding Jetty, but more commonly are configured from a context XML file or WEB-INF/jetty-web.xml file:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
...
<Set name="maxFormContentSize">200000</Set>
<Set name="maxFormKeys">200</Set>
</Configure>
Aliased Files and Symbolic links
Web applications will often serve static content from the file system provided by the operating system running underneath the JVM. However, because file systems often implement multiple aliased names for the same file, then security constraints and other servlet URI space mappings may inadvertently be bypassed by aliases.
A key example of this is case insensitivity and 8.3 filenames implemented by the Windows file system.
If a file within a web application called /mysecretfile.txt
is protected by a security constraint on the URI /mysecretfile.txt
, then a request to /MySecretFile.TXT
will not match the URI constraint because URIs are case sensitive, but the Windows file system will report that a file does exist at that name and it will be served despite the security constraint.
Less well known than case insensitivity is that Windows files systems also support 8.3 filenames for compatibility with legacy programs.
Thus a request to a URI like /MYSECR~1.TXT
will again not match the security constraint, but will be reported as an existing file by the file system and served.
There are many examples of aliases, not just on Windows:
-
NTFS Alternate stream names like
c:\test\file.txt::$DATA:name
-
OpenVMS support file versionig so that
/mysecret.txt;N
refers to version N of/mysecret.txt
and is essentially an alias. -
The clearcase software configuration management system provides a file system where
@@
in a file name is an alias to a specific version. -
The Unix files system supports
/./foo.txt
as and alias for/foo.txt
-
Many JVM implementations incorrectly assume the null character is a string terminator, so that a file name resulting from
/foobar.txt%00
is an alias for/foobar.txt
-
Unix symbolic links and hard links are a form of aliases that allow the same file or directory to have multiple names.
In addition, it is not just URI security constraints that can be bypassed. For example the mapping of the URI pattern *.jsp
to the JSP
Servlet may be bypassed by an a request to an alias like /foobar.jsp%00
, thus rather than execute the JSP, the source code of the JSP is returned by the file system.
Good Security Practise
Part of the problem with aliases is that the standard web application security model is to allow all requests except the ones that are specifically denied by security constraints. A best practice for security is to deny all requests and to permit only those that are specifically identified as allowable. While it is possible to design web application security constraints in this style, it can be difficult in all circumstances and it is not the default. T hus it is important for Jetty to be able to detect and deny requests to aliased static content.
Alias detection
It is impossible for Jetty to know of all the aliases that may be implemented by the file system running beneath it, thus it does not attempt to make any specific checks for any know aliases.
Instead Jetty detects aliases by using the canonical path of a file.
If a file resource handled by jetty has a canonical name that differs from the name used to request the resource, then Jetty determines that the resource is an aliased request and it will not be returned by the ServletContext.getResource(String)
method (or similar) and thus will not be served as static content nor used as the basis of a JSP.
This if Jetty is running on a Windows operating system, then a file called /MySecret.TXT
will have a canonical name that exactly matches that case.
So while a request to /mysecret.txt
or /MYSECR~1.TXT
will result in a File Resource that matches the file, the different canonical name will indicate that those requests are aliases and they will not be served as static content and instead a 404 response returned.
Unfortunately this approach denies all aliases, including symbolic links, which can be useful in assembling complex web applications.
Serving Aliases and Symbolic Links
Not all aliases are bad nor should be seen as attempts to subvert security constraints.
Specifically, symbolic links can be very useful when assembling complex web applications.
As such, Jetty contexts support an extensible AliasCheck
mechanism to allow aliases resources to be inspected and conditionally served.
In this way, "good" aliases can be detected and served.
Jetty provides several utility implementations of the AliasCheck
interface as nested classes with ContextHandler
:
- ApproveAliases
-
Approve all aliases (Use with caution!).
- AllowSymLinkAliasChecker
-
Approve Aliases using the java-7
Files.readSymbolicLink(path)
andPath.toRealPath(…)
APIs to check that aliases are valid symbolic links.
By default, Jetty serves aliased files for implementations running on UNIX as Contexts are created with both the |
An application is free to implement its own Alias checking.
Alias Checkers can be installed in a context via the following XML used in a context deployer file or WEB-INF/jetty-web.xml
:
<!-- Allow symbolic links -->
<Call name="addAliasCheck">
<Arg><New class="org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker"/></Arg>
</Call>
Secure Password Obfuscation
There are many places where you might want to use and store a password, for example for the SSL connectors and user passwords in realms.
Passwords can be stored in clear text, obfuscated, checksummed or encrypted in order of increasing security.
The choice of method to secure a password depends on where you are using the password.
In some cases, such as keystore passwords and DIGEST
authentication, the system must retrieve the original password, which requires the obfuscation method.
The drawback of the obfuscation algorithm is that it protects passwords from casual viewing only.
When the stored password is compared to one a user enters, the handling code can apply the same algorithm that secures the stored password to the user input and compare results, making password authentication more secure.
The class org.eclipse.jetty.util.security.Password
can be used to generate all varieties of passwords.
Run it without arguments to see usage instructions:
$ java -cp lib/jetty-util-{VERSION}.jar org.eclipse.jetty.util.security.Password
Usage - java org.eclipse.jetty.util.security.Password [<user>] <password>
If the password is ?, the user will be prompted for the password
For example, to generate a secured version of the password password
for the user username
:
$ java -cp ../lib/jetty-util-{VERSION}.jar org.eclipse.jetty.util.security.Password username password
2017-12-13 11:19:27.928:INFO::main: Logging initialized @95ms to org.eclipse.jetty.util.log.StdErrLog
password
OBF:1v2j1uum1xtv1zej1zer1xtn1uvk1v1v
MD5:5f4dcc3b5aa765d61d8327deb882cf99
CRYPT:usjRS48E8ZADM
If using a external tool to create/verify the MD5 hash (such as md5sum
or md5
), be sure to verify a carriage return (CR) or new line is not added.
For example:
//With a CR included
$ echo password | md5sum
286755fad04869ca523320acce0dc6a4 *-
//Using the `-n` option to exclude a new line from being added.
$ echo -n password | md5sum
5f4dcc3b5aa765d61d8327deb882cf99 *-
When using the |
$ java -cp ../lib/jetty-util-9.4.7.v20170914.jar org.eclipse.jetty.util.security.Password username username:realm:password
2017-12-13 11:34:33.263:INFO::main: Logging initialized @97ms to org.eclipse.jetty.util.log.StdErrLog
username:realm:password
OBF:1w281yf41v1x1z7e1xmi1v1p1tvv1v901c3j1x8k1ugo1ri71uh21x8a1c3j1v9m1tv71v2p1xms1z7o1v2h1yf21w1a
MD5:66999343281b2624585fd58cc9d36dfc
CRYPT:usulxZfApLefk
$ echo -n username:realm:password | md5sum
66999343281b2624585fd58cc9d36dfc *-
You can now cut and paste whichever secure version you choose into your configuration file or Java code.
For example, the last line below shows how you would implement the encrypted password generated above into the properties file for a LoginService
:
admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin
other: OBF:1xmk1w261u9r1w1c1xmq
guest: guest,read-only
me:CRYPT:me/ks90E221EY
Don’t forget to also copy the OBF:, MD5: or CRYPT: prefix on the generated password. It will not be usable by Jetty without it. |
You can also use obfuscated passwords in Jetty xml files where a plain text password is required. Here’s an example setting the password for a JDBC Datasource with obfuscation:
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.jolbox.bonecp.BoneCPDataSource">
<Set name="driverClass">com.mysql.jdbc.Driver</Set>
<Set name="jdbcUrl">jdbc:mysql://localhost:3306/foo</Set>
<Set name="username">dbuser</Set>
<Set name="password">
<Call class="org.eclipse.jetty.util.security.Password" name="deobfuscate">
<Arg>OBF:1ri71v1r1v2n1ri71shq1ri71shs1ri71v1r1v2n1ri7</Arg>
</Call>
</Set>
<Set name="minConnectionsPerPartition">5</Set>
<Set name="maxConnectionsPerPartition">50</Set>
<Set name="acquireIncrement">5</Set>
<Set name="idleConnectionTestPeriod">30</Set>
</New>
</Arg>
</New>
Setting Port 80 Access for a Non-Root User
On Unix-based systems, port 80 is protected; typically only the superuser root
can open it. For security reasons, it is not desirable to run the server as root
.
This page presents several options to access port 80 as a non-root user, including using ipchains
, iptables
, Jetty’s SetUID feature, xinetd
, and the Solaris 10 User Rights Management Framework.
Using ipchains
On some Linux systems you can use the ipchains REDIRECT mechanism to redirect from one port to another inside the kernel (if ipchains
is not available, then iptables
usually is):
# /sbin/ipchains -I input --proto TCP --dport 80 -j REDIRECT 8080
This command instructs the system as follows: "Insert into the kernel’s packet filtering the following as the first rule to check on incoming packets: if the protocol is TCP and the destination port is 80, redirect the packet to port 8080".
Be aware that your kernel must be compiled with support for ipchains
(virtually all stock kernels are).
You must also have the ipchains
command-line utility installed.
You can run this command at any time, preferably just once, since it inserts another copy of the rule every time you run it.
Using iptables
On many Linux systems you can use the iptables
REDIRECT mechanism to redirect from one port to another inside the kernel (if iptables
is not available, then usually ipchains
is).
You need to add something like the following to the startup scripts or your firewall rules:
# /sbin/iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
The underlying model of iptables
is different from ipchains
, so the forwarding normally happens only to packets originating outside of the server itself.
You also need to allow incoming packets to port 8080 if you use iptables
as a local firewall.
Be careful to place rules like this one early in your input chain. Such rules must precede any rule that accepts the packet, otherwise the redirection won’t occur. You can insert as many rules as required if your server needs to listen on multiple ports, as for HTTPS.
Configuring Jetty’s SetUID Feature
SetUID is a technique that uses Unix-like file system access rights to allow users to run an executable that would otherwise require higher privileges.
Jetty’s SetUID
module allows you to run Jetty as a normal user even when you need to run Jetty on port 80 or 443.
To use it with the Jetty distribution:
-
Ensure that you have the
http.mod
(and https.mod if you are using SSL) modules enabled for the base you are using. Thehttp.mod
is enabled by default in the distribution, while the https.mod is only enabled in the demo-base directory. -
Ensure that you have changed the http port to 80 (and changed the https port to 443 if you are using SSL).
-
Enable the
setuid.mod
module:# java -jar start.jar --add-to-start=setuid
The --add-to-start command will enable the setuid module for this and all subsequent executions of jetty. There are other ways to enable the module, such as for a single execution. For more information on the alternatives see the section on Managing Startup Modules.
-
Edit the configuration for the
setuid
module to substitute theuserid
andgroupid
of the user to switch to after starting. If your server instance has a${jetty.base/start.d}
directory, this configuration is in thestart.d/setuid.ini
file instead. Otherwise. this configuration is in the${jetty.base}start.ini
file.
Below are the lines to configure:
jetty.startServerAsPrivileged=false
jetty.username=foo
jetty.groupname=bar
jetty.umask=002
As well as opening the connectors as |
-
A native code library is required to perform user switching. This code is hosted as part of the Jetty ToolChain project and is released independently from Jetty itself. You can find the source code in the eclipse/jetty.toolchain/jetty-setuid project. Build it locally, which will produce a native library appropriate for the operating system:
# mvn clean install
If you built on a linux machine you will find the native library in
jetty-setuid/libsetuid-linux/target/libsetuid-linux.so
. If you built on a different operating system you will find the library in a different subdirectory, with the name containing the name of the operating system. You may want copy this file into your Jetty distribution’s lib directory. -
Start Jetty as the
root
user in your base directory, providing the location of the native library to Java. Below is an example of how to do it from the command line, assuming you are in the demo-base directory:# sudo java -Djava.library.path=libsetuid-linux -jar $JETTY_HOME/start.jar
Using the Solaris 10 User Rights Management Framework
Solaris 10 provides a User Rights Management framework that can permit users and processes superuser-like abilities:
usermod -K defaultpriv=basic,net_privaddr myself
Now the myself
user can bind to port 80.
Refer to the Solaris 10 and Solaris 11 Security Services documentation for more information.
JAAS Support
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.
Applications enable the authentication process by instantiating a LoginContext
object, which in turn references a configuration to determine the authentication technology(ies), or LoginModule
(s), to be used in performing the authentication.
Typical LoginModules
may prompt for and verify a username and password.
Others may read and verify a voice or fingerprint sample.
See Java Authentication and Authorization Service (JAAS) Reference Guide for more information about JAAS.
Jetty and JAAS
Many application servers support JAAS as a means of bringing greater flexibility to the declarative security models of the J2EE (now known as the JavaEE) specification. Jetty support for JAAS provides greater alternatives for servlet security, and increases the portability of web applications.
The JAAS support aims to dictate as little as possible whilst providing a sufficiently flexible infrastructure to allow users to drop in their own custom LoginModules.
Configuration
Using JAAS with Jetty is very simply a matter of declaring a org.eclipse.jetty.jaas.JAASLoginService
, creating a JAAS login module configuration file and specifying it on the Jetty run line.
Let’s look at an example.
Step 1
Configure a Jetty org.eclipse.jetty.jaas.JAASLoginService
to match the <realm-name>
in your web.xml
file. For example, if the web.xml
contains a realm called "Test JAAS Realm" like so:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Test JAAS Realm</realm-name>
<form-login-config>
<form-login-page>/login/login</form-login-page>
<form-error-page>/login/error</form-error-page>
</form-login-config>
</login-config>
then you need to create a JAASLoginService
with the matching realm name of "Test JAAS Realm":
<New class="org.eclipse.jetty.jaas.JAASLoginService">
<Set name="Name">Test JAAS Realm</Set>
<Set name="LoginModuleName">xyz</Set>
</New>
The LoginModuleName
must match the name of your LoginModule as declared in your login module configuration file (see Step 2).
The name of the realm-name that you declare in |
You can declare your JAASLoginService
in a couple of different ways:
-
If you have more than one webapp that you would like to use the same security infrastructure, then you can declare your
JAASLoginService
in a top-level Jetty xml file as a bean that is added to theorg.eclipse.jetty.server.Server
. An example:<Configure id="Server" class="org.eclipse.jetty.server.Server"> <Call name="addBean"> <Arg> <New class="org.eclipse.jetty.jaas.JAASLoginService"> <Set name="name">Test JAAS Realm</Set> <Set name="LoginModuleName">xyz</Set> </New> </Arg> </Call> </Configure>
-
Alternatively, you can use a
JAASLoginService
with just a specific webapp by creating a context xml file for the webapp, and specifying theJAASLoginService
in it:<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="securityHandler"> <New class="org.eclipse.jetty.security.ConstraintSecurityHandler"> <Set name="loginService"> <New class="org.eclipse.jetty.jaas.JAASLoginService"> <Set name="name">Test JAAS Realm</Set> <Set name="loginModuleName">xyz</Set> </New> </Set> </New> </Set> </Configure>
Step 2
Set up your LoginModule
in a configuration file, following the syntax rules :
xyz {
com.acme.SomeLoginModule required debug=true;
};
It is imperative that the application name on the first line is exactly the same as the |
You may find it convenient to name this configuration file as etc/login.conf
because, as we will see below, some of the wiring up for JAAS has been done for you.
Step 3
You now need to invoke Jetty with support for JAAS. There are 2 aspects to this:
-
adding JAAS-related jars to the Jetty container classpath
-
setting the System property
java.security.auth.login.config
To accomplish the above, use the Jetty startup modules mechanism to add the JAAS module:
java -jar start.jar --add-to-start=jaas
The top level of the distribution does not have the JAAS module enabled by default.
However, there are several demo webapps - including a JAAS webapp - available in the |
Now you will have a file named start.d/jaas.ini
, which contains:
--module=jaas
jaas.login.conf=etc/login.conf
The jaas.login.conf
property refers to the location of your LoginModule
configuration file that you established in Step 2.
If you called it etc/login.conf
, then your work is done. Otherwise, change the value of the jaas.login.conf
property to be the location of your LoginModule configuration file.
Jetty will automatically use this property to set the value of the System property java.security.auth.login.config.
A Closer Look at JAASLoginService
To allow the greatest degree of flexibility in using JAAS with web applications, the JAASLoginService
supports a couple of configuration options.
Note that you don’t ordinarily need to set these explicitly, as Jetty has defaults which will work in 99% of cases.
However, should you need to, you can configure:
-
a CallbackHandler (Default:
org.eclipse.jetty.jaas.callback.DefaultCallbackHandler
) -
a list of classnames for the Principal implementation that equate to a user role (Default:
org.eclipse.jetty.jaas.JAASRole
)
Here’s an example of setting each of these (to their default values):
<New class="org.eclipse.jetty.jaas.JAASLoginService">
<Set name="Name">Test JAAS Realm</Set>
<Set name="LoginModuleName">xyz</Set>
<Set name="CallbackHandlerClass">
org.eclipse.jetty.jaas.callback.DefaultCallbackHandler
</Set>
<Set name="roleClassNames">
<Array type="java.lang.String">
<Item>org.eclipse.jetty.jaas.JAASRole</Item>
</Array>
</Set>
</New>
CallbackHandler
A CallbackHandler is responsible for interfacing with the user to obtain usernames and credentials to be authenticated.
Jetty ships with the org.eclipse.jetty.jaas.DefaultCallbackHandler
which interfaces the information contained in the request to the Callbacks that are requested by LoginModules
.
You can replace this default with your own implementation if you have specific requirements not covered by the default.
Role Principal Implementation Class
When LoginModules
authenticate a user, they usually also gather all of the roles that a user has and place them inside the JAAS Subject.
As LoginModules
are free to use their own implementation of the JAAS Principal to put into the Subject, Jetty needs to know which Principals represent the user and which represent his/her roles when performing authorization checks on <security-constraint>
. The example LoginModules
that ship with Jetty all use the org.eclipse.jetty.jaas.JAASRole
class. However, if you have plugged in other LoginModules
, you must configure the classnames of their role Principal implementations.
Sample LoginModules
Passwords can be stored in clear text, obfuscated or checksummed.
The class |
JDBCLoginModule
The JDBCLoginModule
stores user passwords and roles in a database that are 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 login module configuration file entry for it using an HSQLDB driver:
jdbc {
org.eclipse.jetty.jaas.spi.JDBCLoginModule required
debug="true"
dbUrl="jdbc:hsqldb:."
dbUserName="sa"
dbDriver="org.hsqldb.jdbcDriver"
userTable="myusers"
userField="myuser"
credentialField="mypassword"
userRoleTable="myuserroles"
userRoleUserField="myuser"
userRoleRoleField="myrole";
};
There is no particular schema required for the database tables storing the authentication and role information.
The properties userTable
, userField
, credentialField
, userRoleTable
, userRoleUserField
, userRoleRoleField
configure the names of the tables and the columns within them that are used to format the following queries:
select <credentialField> from <userTable>
where <userField> =?
select <userRoleRoleField> from <userRoleTable>
where <userRoleUserField> =?
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 JDBCLoginModule
, but this LoginModule
uses a DataSource
to connect to the database instead of a JDBC driver. The DataSource
is obtained by performing a JNDI lookup on java:comp/env/${dnJNDIName}
.
A sample login module configuration using this method:
ds {
org.eclipse.jetty.jaas.spi.DataSourceLoginModule required
debug="true"
dbJNDIName="ds"
userTable="myusers"
userField="myuser"
credentialField="mypassword"
userRoleTable="myuserroles"
userRoleUserField="myuser"
userRoleRoleField="myrole";
};
PropertyFileLoginModule
With this login module implementation, the authentication and role information is read from a property file.
props {
org.eclipse.jetty.jaas.spi.PropertyFileLoginModule required
debug="true"
file="/somewhere/somefile.props";
};
The file parameter is the location of a properties file of the same format as the etc/realm.properties
example file.
The format is:
<username>: <password>[,<rolename> ...]
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
Here’s an example:
ldaploginmodule {
org.eclipse.jetty.jaas.spi.LdapLoginModule required
debug="true"
contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
hostname="ldap.example.com"
port="389"
bindDn="cn=Directory Manager"
bindPassword="directory"
authenticationMethod="simple"
forceBindingLogin="false"
userBaseDn="ou=people,dc=alcatel"
userRdnAttribute="uid"
userIdAttribute="uid"
userPasswordAttribute="userPassword"
userObjectClass="inetOrgPerson"
roleBaseDn="ou=groups,dc=example,dc=com"
roleNameAttribute="cn"
roleMemberAttribute="uniqueMember"
roleObjectClass="groupOfUniqueNames";
};
Writing your Own LoginModule
If you want to implement your own custom LoginModule
, there are two classes to be familiar with: org.eclipse.jetty.jaas.spi.AbstractLoginModule
and org.eclipse.jetty.jaas.spi.UserInfo
.
The org.eclipse.jetty.jaas.spi.AbstractLoginModule
implements all of the javax.security.auth.spi.LoginModule
methods.
All you need to do is to implement the getUserInfo
method to return a org.eclipse.jetty.jaas.UserInfo
instance which encapsulates the username, password and role names (note: as java.lang.Strings
) for a user.
The AbstractLoginModule
does not support any caching, so if you want to cache UserInfo (eg as does the org.eclipse.jetty.jaas.spi.PropertyFileLoginModule
) then you must provide this yourself.
Other Goodies
ServletRequestCallback
This callback gives you access to the ServletRequest that is involved in the authentication, and thus to other features like the current Session. This callback can be configured in your custom LoginModule implementation. Note that none of the LoginModule implementations provided with Jetty currently use this callback.
RequestParameterCallback
As all servlet containers intercept and process a form submission with action j_security_check
, it is usually not possible to insert any extra input fields onto a login form with which to perform authentication: you may only pass j_username
and j_password
.
For those rare occasions when this is not good enough, and you require more information from the user in order to authenticate them, you can use the JAAS callback handler org.eclipse.jetty.jaas.callback.RequestParameterCallback
.
This callback gives you access to all parameters that were passed in the form submission.
To use it, in the login()
method of your custom login module, add the RequestParameterCallback
to the list of callback handlers the login module uses, tell it which params you are interested in, and then get the value of the parameter back.
Here is an example:
public class FooLoginModule extends AbstractLoginModule
{
public boolean login()
throws LoginException
{
Callback[] callbacks = new Callback[3];
callbacks[0] = new NameCallback();
callbacks[1] = new ObjectCallback();
//as an example, look for a param named "extrainfo" in the request
//use one RequestParameterCallback() instance for each param you want to access
callbacks[2] = new RequestParameterCallback ();
((RequestParameterCallback)callbacks[2]).setParameterName ("extrainfo");
callbackHandler.handle(callbacks);
String userName = ((NameCallback)callbacks[0]).getName();
Object pwd = ((ObjectCallback)callbacks[1]).getObject();
List paramValues = ((RequestParameterCallback)callbacks[2]).getParameterValues();
//use the userName, pwd and the value(s) of the parameter named "extrainfo" to
//authenticate the user
}
}
Example JAAS WebApp
An example webapp using JAAS can be found in the Jetty GitHub repository:
SPNEGO Support
Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) is a way for users to be seamlessly authenticated when running on a Windows or Active Directory based network. Jetty supports this type of authentication and authorization through the JDK (which has been enabled since the later versions of Java 6 and 7). Also important to note is that this is an incredibly fragile setup where everything needs to be configured just right for things to work, otherwise it can fail in fun and exciting, not to mention obscure, ways.
There is a substantial amount of configuration and testing required to enable this feature as well as knowledge and access to central systems on a Windows network such as the Active Domain Controller and the ability to create and maintain service users.
Configuring Jetty and SPNEGO
To run with SPNEGO enabled the following command line options are required:
-Djava.security.krb5.conf=/path/to/jetty/etc/krb5.ini \
-Djava.security.auth.login.config=/path/to/jetty/etc/spnego.conf \
-Djavax.security.auth.useSubjectCredsOnly=false
For debugging the SPNEGO authentication the following options are very helpful:
-Dorg.eclipse.jetty.LEVEL=debug \
-Dsun.security.spnego.debug=all
SPNEGO Authentication must be enabled in the webapp in the following way. The name of the role will be different for your network.
<security-constraint>
<web-resource-collection>
<web-resource-name>Secure Area</web-resource-name>
<url-pattern>/secure/me/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<!-- this is the domain that the user is a member of -->
<role-name>MORTBAY.ORG</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>SPNEGO</auth-method>
<realm-name>Test Realm</realm-name>
<!-- optionally to add custom error page -->
<spnego-login-config>
<spnego-error-page>/loginError.html?param=foo</spnego-error-page>
</spnego-login-config>
</login-config>
A corresponding UserRealm
needs to be created either programmatically if embedded, via the jetty.xml
or in a context file for the webapp.
This is what the configuration within a Jetty xml file would look like.
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.security.SpnegoLoginService">
<Set name="name">Test Realm</Set>
<Set name="config"><Property name="jetty.home" default="."/>/etc/spnego.properties</Set>
</New>
</Arg>
</Call>
This is what the configuration within a context xml file would look like.
<Get name="securityHandler">
<Set name="loginService">
<New class="org.eclipse.jetty.security.SpnegoLoginService">
<Set name="name">Test Realm</Set>
<Set name="config">
<SystemProperty name="jetty.home" default="."/>/etc/spnego.properties
</Set>
</New>
</Set>
<Set name="checkWelcomeFiles">true</Set>
</Get>
There are a number of important configuration files with S3pnego that are required. The default values for these configuration files from this
test example are found in the /etc
folder of the Jetty distribution.
- spnego.properties
-
configures the user realm with runtime properties
- krb5.ini
-
configures the underlying kerberos setup
- spnego.conf
-
configures the glue between gssapi and kerberos
It is important to note that the keytab file referenced in the krb5.ini
and the spnego.conf
files needs to contain the keytab for the targetName
for the http server.
To do this use a process similar to this:
On the Windows Active Domain Controller run:
$ setspn -A HTTP/linux.mortbay.org ADUser
To create the keytab file use the following process:
$ ktpass -out c:\dir\krb5.keytab -princ HTTP/linux.mortbay.org@MORTBAY.ORG -mapUser ADUser -mapOp set -pass ADUserPWD -crypto RC4-HMAC-NT -pType KRB5_NT_PRINCIPAL
This step will give you the keytab file which should then be copied to the machine running the http server and referenced from the configuration files.
For our testing we put the keytab into the /etc
directory of Jetty and referenced it from there.
Configuring Firefox
The follows steps have been required to inform Firefox that it should use a negotiation dialog to authenticate.
-
Browse to about:config and agree to the warnings
-
Search through to find the 'network' settings
-
Set
network.negotiate-auth.delegation-uris
to http://,https:// -
Set
network.negotiate-auth.trusted-uris
to http://,https://
Configuring Internet Explorer
The follows steps have been required to inform Internet Explorer that it should use a negotiation dialog to authenticate.
-
Tools → Options → Security → Local Intranet → Sites (everything should be checked here)
-
Tools → Options → Security → Local Intranet → Sites → Advanced (add url to server (
http://
and/orhttps://
— use the hostname, not the IP) -
Tools → Options → Security → Local Intranet → Sites → Advanced → Close
-
Tools → Options → Security → Local Intranet → Sites → Ok
-
Tools → Options → Advanced → Security (in the checkbox list)
-
Locate and select
Enable Integrated Windows Authentication
-
Tools → Options → Advanced → Security → Ok
-
Close IE then reopen and browse to your SPNEGO protected resource
You must use hostname and not the IP. If you use the IP it will default to NTLM authentication. The following conditions must be true for SPNEGO authentication to work:
-
You must be within the Intranet Zone of the network
-
Access the server using a Hostname rather than IP
-
Integrated Windows Authentication in IE is enabled and/or the host is trusted in Firefox
-
The server is not local to the browser; it can’t be running on localhost
-
The client’s Kerberos system is authenticated to a domain controller
OpenID Support
External Setup
Registering an App with OpenID Provider
You must register the app with an OpenID Provider such as Google or Amazon.
This will give you a Client ID and Client Secret.
Once set up you must also register all the possible URI’s for your webapp with the path /j_security_check
so that the OpenId Provider will allow redirection back to the webapp.
These may look like
Distribution Configuration
OpenID Provider Configuration
To enable OpenID support, you first need to activate the openid
module in your implementation.
java -jar {JETTY_HOME}/start.jar --add-to-start=openid
To configure OpenID Authentication with Jetty you will need to specify the OpenID Provider’s issuer identifier (case sensitive URL using the https
scheme) 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 can be set as properties in the start.ini
or start.d/openid.ini
files.
WebApp Specific Configuration in web.xml
The 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, an init param is set at "org.eclipse.jetty.security.openid.error_page"
, its value should be a path relative to the webapp where authentication errors should be redirected.
Example:
<login-config>
<auth-method>OPENID</auth-method>
<realm-name>https://accounts.google.com</realm-name>
</login-config>
<context-param>
<param-name>org.eclipse.jetty.security.openid.error_page</param-name>
<param-value>/error</param-value>
</context-param>
Embedded Configuration
Define the OpenIdConfiguration
for a specific OpenID Provider.
If the OpenID Provider allows metadata discovery then you can use.
OpenIdConfiguration openIdConfig = new OpenIdConfiguration(ISSUER, CLIENT_ID, CLIENT_SECRET);
Otherwise you can manually enter the necessary information:
OpenIdConfiguration openIdConfig = new OpenIdConfiguration(ISSUER, TOKEN_ENDPOINT, AUTH_ENDPOINT, CLIENT_ID, CLIENT_SECRET);
Configuring a LoginService
and Authenticator
.
// Configure a LoginService with the OpenID configuration.
OpenIdLoginService loginService = new OpenIdLoginService(openIdConfig);
securityHandler.setLoginService(loginService);
// Configure an Authenticator with errors to be redirected to the "/error" path.
OpenIdAuthenticator authenticator = new OpenIdAuthenticator(openIdConfig, "/error");
securityHandler.setAuthenticator(authenticator);
An IdentityService will be automatically created for the SecurityHandler if a realm name is set, otherwise you will need to manually set an IdentityService on the SecurityHandler.
// Set realm name of SecurityHandler to be the URL of the OpenID provider.
securityHandler.setRealmName(ISSUER);
// Set an IdentityService on the SecurityHandler.
securityHandler.setIdentityService(new DefaultIdentityService());
Usage
Claims and Access Token
Claims about the user can be found using attributes on the session attribute "org.eclipse.jetty.security.openid.claims"
, and the full response containing the OAuth 2.0 Access Token can be found with the session attribute "org.eclipse.jetty.security.openid.response"
.
Example:
Map<String, Object> claims = (Map)request.getSession().getAttribute("org.eclipse.jetty.security.openid.claims");
String userId = claims.get("sub");
Map<String, Object> response = (Map)request.getSession().getAttribute("org.eclipse.jetty.security.openid.response");
String accessToken = response.get("access_token");
Scopes
The OpenID scope is always used but additional scopes can be requested which can give you additional resources or privileges.
For the Google OpenID Provider it can be useful to request the scopes profile
and email
which will give you additional user claims.
Additional scopes can be requested through the start.ini
or start.d/openid.ini
files, or with OpenIdConfiguration.addScopes(…);
in embedded code.
Roles
If security roles are required they can be configured through a wrapped LoginService
which is deferred to for role information by the OpenIdLoginService
.
This can be configured in XML through etc/openid-baseloginservice.xml
in the Distribution, or in embedded code using the constructor for the OpenIdLoginService
.
LoginService wrappedLoginService = ...; // Optional LoginService for Roles
LoginService loginService = new OpenIdLoginService(openIdConfig, wrappedLoginService);
When using authorization roles, the setting authenticateNewUsers
becomes significant.
If set to true
users not found by the wrapped LoginService
will still be authenticated but will have no roles.
If set to false
those users will be not be allowed to authenticate and are redirected to the error page.
This setting is configured through the property jetty.openid.authenticateNewUsers
in the start.ini
or start.d/openid.ini
file, or with OpenIdLoginService.setAuthenticateNewUsers(…);
in embedded code.
Configuring JSP Support
Configuring JSP
This document provides information about configuring Java Server Pages (JSP) for Jetty.
Which JSP Implementation
Jetty uses Jasper from Apache as the default JSP container implementation.
By default the Jetty distribution enables the JSP module, and by default, this module is set to Apache Jasper.
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
Enables JSP for all webapplications deployed on the server.
[depend]
servlet
annotations
apache-jsp
Note that the availability of some JSP features may depend on which JSP container implementation you are using. Note also that it may not be possible to precompile your JSPs with one container and deploy to the other.
JSPs and Embedding
If you have an embedded setup for your webapp and wish to use JSPs, you will need to ensure that a JSP engine is correctly initialized.
For Apache, a Servlet Specification 3.1 style ServletContainerInitializer is used to accomplish this. You will need to ensure that this ServletContainerInitializer is run by jetty. Perhaps the easiest way to do this is to enable annotations processing so that Jetty automatically discovers and runs it. The Embedded Examples section includes a worked code example of how to do this.
Alternatively, you can manually wire in the appropriate ServletContainerInitializer as shown in the embedded-jetty-jsp example on GitHub, in which case you will not need the jetty-annotations jar on your classpath, nor include the AnnotationConfiguration in the list of configuration classes.
Precompiling JSPs
You can either follow the instructions on precompilation provided by Apache, or if you are using Maven for your builds, you can use the jetty-jspc-maven plugin to do it for you.
If you have precompiled your JSPs, and have customized the output package prefix (which is org.apache.jsp
by default), you should configure your webapp context to tell Jetty about this custom package name.
You can do this using a servlet context init-param called org.eclipse.jetty.servlet.jspPackagePrefix
.
For example, suppose you have precompiled your JSPs with the custom package prefix of com.acme
, then you would add the following lines to your web.xml
file:
<context-param>
<param-name>org.eclipse.jetty.servlet.jspPackagePrefix</param-name>
<param-value>com.acme</param-value>
</context-param>
Both Jetty Maven plugins - jetty-jspc-maven-plugin and the jetty-maven-plugin - will only use Apache Jasper. |
Apache JSP Container
By default, the Apache JSP container will look for the Eclipse Java Compiler (jdt).
The Jetty distribution ships a copy of this in {$jetty.home}/lib/apache-jsp
.
If you wish to use a different compiler, you will need to configure the compilerClassName
init-param on the JspServlet
with the name of the class.
init param | Description | Default | webdefault.xml |
---|---|---|---|
classpath |
|
- |
- |
classdebuginfo |
Include debugging info in class file. |
TRUE |
- |
checkInterval |
Interval in seconds between background recompile checks. Only relevant if ` development=false`. |
0 |
- |
development |
|
TRUE |
- |
displaySourceFragment |
Should a source fragment be included in exception messages |
TRUE |
- |
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 |
Should Ant fork its Java compiles of JSP pages? |
TRUE |
FALSE |
keepgenerated |
Do you want to keep the generated Java files around? |
TRUE |
- |
trimSpaces |
Should white spaces between directives or actions be trimmed? |
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. |
- |
- |
mappedFile |
Support for mapped Files. Generates a servlet that has a print statement per line of the JSP file |
TRUE |
- |
suppressSmap |
Generation of SMAP info for JSR45 debugging. |
FALSE |
- |
dumpSmap |
Dump SMAP JSR45 info to a file. |
FALSE |
- |
genStrAsCharArray |
Option for generating Strings. |
FALSE |
- |
ieClassId |
The class-id value to be sent to Internet Explorer when using <jsp:plugin> tags. |
clsid:8AD9C840-044E-11D1-B3E9-00805F499D93 |
- |
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 |
- |
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 |
- |
scratchDir |
Directory where servlets are generated. |
- |
- |
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.7 |
- |
compilerSourceVM |
Sets source compliance level for the jdt compiler. |
1.7 |
- |
javaEncoding |
Pass through the encoding to use for the compilation. |
UTF8 |
- |
modificationTestInterval |
If |
4 |
- |
xpoweredBy |
Generate an X-Powered-By response header. |
FALSE |
FALSE |
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. |
- |
- |
Configuration
The JSP engine has many configuration parameters.
Some parameters affect only precompilation, and some affect runtime recompilation checking.
Parameters also differ among the various versions of the JSP engine.
This page lists the configuration parameters, their meanings, and their default settings.
Set all parameters on the org.apache.jasper.servlet.JspServlet
instance defined in the webdefault.xml
file.
Be careful: for all of these parameters, 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 JSP is inconsistent in its parameter naming strategy. |
Modifying Configuration
Overriding webdefault.xml
You can make a copy of the {$jetty.home}/etc/webdefault.xml that ships with Jetty, apply your changes, and use it instead of the shipped version. The example below shows how to do this when using the Jetty Maven plugin.
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<webApp>
<defaultsDescriptor>src/main/resources/webdefault.xml</defaultsDescriptor>
</webApp>
</plugin>
If you are using the Jetty distribution, and you want to change the JSP settings for just one or a few of your webapps, copy the {$jetty.home}/etc/webdefault.xml
file somewhere, modify it, and then use a context xml file to set this file as the defaultsDescriptor
for your webapp. Here’s a snippet:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/foo</Set>
<Set name="war"><Property name="jetty.home" default="."/>/webapps/foobar.war</Set>
<Set name="defaultsDescriptor">/home/smith/dev/webdefault.xml</Set>
</Configure>
If you want to change the JSP settings for all webapps, edit the {$jetty.home}/etc/webdefaults.xml
file directly instead.
Configuring the JSP Servlet in web.xml
Another option is to add an entry for the JSPServlet to the WEB-INF/web.xml
file of your webapp and change or add init-params.
You may also add (but not remove) servlet-mappings.
You can use the entry in {$jetty.home}/etc/webdefault.xml as a starting point.
<servlet id="jsp">
<servlet-name>jsp</servlet-name>
<servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
<init-param>
<param-name>logVerbosityLevel</param-name>
<param-value>DEBUG</param-value>
</init-param>
<init-param>
<param-name>fork</param-name>
<param-value>>false</param-value>
</init-param>
<init-param>
<param-name>keepgenerated</param-name>
<param-value>>true</param-value>
</init-param>
...
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspf</url-pattern>
<url-pattern>*.jspx</url-pattern>
<url-pattern>*.xsp</url-pattern>
<url-pattern>*.JSP</url-pattern>
<url-pattern>*.JSPF</url-pattern>
<url-pattern>*.JSPX</url-pattern>
<url-pattern>*.XSP</url-pattern>
</servlet-mapping>
<servlet id="my-servlet">
<servlet-name>myServlet</servlet-name>
<servlet-class>com.acme.servlet.MyServlet</servlet-class>
...
Configuring Async Support
By default, Jetty does not enable async support for the JSP servlet.
Configuring the JSP servlet for async is relatively easy - simply define the async-supported
parameter as true
in either your webdefault.xml
or the web.xml
for a specific context.
<servlet id="jsp">
<servlet-name>jsp</servlet-name>
<async-supported>true</async-supported>
</servlet>
Using JSTL Taglibs
The JavaServer Pages Standlard Tag Library (JSTL) is part of the Jetty distribution and is automatically put on the classpath when you select your flavour of JSP. It is also automatically on the classpath for the Jetty Maven plugin, which uses the Apache JSP engine.
Embedding
If you are using Jetty in an embedded scenario, and you need to use JSTL, then you must ensure that the JSTL jars are included on the container’s classpath - that is the classpath that is the parent of the webapp’s classpath. This is a restriction that arises from the JavaEE specification.
Apache JSP
You will need to put the jars that are present in the {$jetty.home}/lib/apache-jstl
directory onto the container’s classpath.
The Apache JSP engine will find the JSTL tag definitions inside these jars during startup.
As an efficiency enhancement, you can have jetty examine the JSTL jars to find the tags, and pre-feed them into the Apache JSP engine. This is more efficient, because jetty will only scan the jars you tell it to, whereas the Apache JSP engine will scan every jar, which can be time-consuming in applications with a lot of jars on the container classpath.
To take advantage of this efficiency enhancement, set up the org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern to include a pattern that will match the names of the JSTL jars. The Embedded Examples section includes a worked code example of how to do this. Below is a snippet from the example:
webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*/[^/]*taglibs.*\\.jar$");
Using JSF Taglibs
The following sections provide information about using JSF TagLibs with Jetty Standalone and the Jetty Maven Plugin.
Using JSF Taglibs with Jetty Distribution
If you want to use JSF with your webapp, you need to copy the JSF implementation Jar (whichever Jar contains the META-INF/*.tld
files from your chosen JSF implementation) into Jetty’s shared container lib directory.
You can either put them into the lib directory for Apache {$jetty.home}/lib/apache-jsp
or put them into {$jetty.home}/lib/ext
.
Using JSF Taglibs with Jetty Maven Plugin
You should make your JSF jars dependencies of the plugin and not the webapp itself. For example:
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<webApp>
<contextPath>/${artifactId}</contextPath>
</webApp>
<scanIntervalSeconds>5</scanIntervalSeconds>
</configuration>
<dependencies>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.0.8</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.0.8</version>
</dependency>
</dependencies>
</plugin>
Jetty Administration Guide
Starting Jetty
Startup Overview
The start.jar
bootstrap manages the startup of standalone Jetty.
It is responsible for:
- Building the classpath
-
The
start.jar
bootstrap builds a classpath for all the required Jetty features and their dependencies. It builds the classpath using either the--lib
option tostart.jar
to add an individual classpath entry, or with the--module
option that includes all the libs and their dependencies for a module (a named Jetty feature). - Instantiating the Server Components
-
The server and its components are instantiated using either Jetty IoC XML or Spring. The Jetty server is a collection of POJOs for the server, connectors, session managers and others. These are instantiated, injected, and wired up together in XML files, commonly one per module/feature, that are passed as arguments to
start.jar
. - Resolving Server Filesystem Locations
-
The
start.jar
mechanism resolves canonical locations for the${jetty.home}
and the${jetty.base}
directories. The${jetty.home}
directory is the location of the standard distribution of Jetty. The${jetty.base}
directory is the location of the local server customization and configurations. + If you want to modify the Jetty distribution, base and home can be the same directory. Separating the base and home directories allows the distribution to remain unmodified, with all customizations in the base directory, and thus simplifies subsequent server version upgrades. - Parameterizing the Server Configuration
-
XML files primarily determine the server configuration. Many of these files are parameterized to allow simple injection of host names, ports, passwords and more. The
start.jar
mechanism allows you to set parameters on the command line or in properties files.
To achieve these start up mechanisms, the start.jar
uses:
- Command line arguments
-
You can configure the entire server with command line arguments that specify libraries, properties and XML files. However in practice the INI and modules mechanisms (below) reduce the verbosity of the command line.
- INI files
-
The
start.jar
mechanism uses the contents of the${jetty.base}/start.ini
and${jetty.base}/start.d/*.ini
files with each line equivalent to astart.jar
command line argument. This means that either a globalstart.ini
file or multiplestart.d/feature.ini
files control the configuration of the server.
It is important to chose either |
- Modules
-
Instead of explicitly listing all the libraries, properties and XML files for a feature, the
start.jar
mechanism allows you to create modules. A module is defined in amodules/.mod
file, including the libraries, dependencies, XML, and template INI files for a Jetty feature. Thus you can use a single--module=name
command line option as the equivalent of specifying--lib=location
,feature.xml
orname=value
arguments for a feature and all its dependencies. Modules also use their dependencies to control the ordering of libraries and XML files. There are several module files included with the Jetty distribution that cover the most common server features, such as HTTP, HTTPS, SSL, Logging, Annotations…etc. These module files should *only be edited if you are making structural changes to the way the feature will perform. For more information, refer to the section on managing startup modules later in this chapter. - XML Files
-
XML files in either Jetty IoC or Spring format instantiate the actual POJO components of the server. This includes all major components such as connectors, keystores, session managers, and data sources. Typically there are one or more XML files per module, and these are defined and activated in the corresponding module.
Startup Example
The simplest way to start Jetty is via the start.jar
mechanism using the following Java command line:
[user]$ cd jetty-distribution-{VERSION}
[jetty-distribution-{VERSION}]$ java -jar start.jar --module=http jetty.http.port=8080
This command uses the start.jar
mechanism to bootstrap the classpath, properties, and XML files with the metadata obtained from the http
module.
Specifically the http
module is defined in the ${jetty.home}/modules/http.mod
file, and includes the following:
[jetty-distribution-{VERSION}]$ cat modules/http.mod
[depend]
server
[xml]
etc/jetty-http.xml
[ini-template]
jetty.http.port=8080
http.timeout=30000
The http
module declares that http
depends on the server module, uses the jetty-http.xml
file, and can be parameterized with jetty.http.port
and http.timeout
parameters.
The INI-template section is not actually used by the command above, so the jetty.http.port
must still be defined on the command line.
Following the server dependency, the ${jetty.home}/modules/server.mod
file includes:
[jetty-distribution-{VERSION}]$ cat modules/server.mod
[lib]
lib/servlet-api-3.1.jar
lib/jetty-http-${jetty.version}.jar
lib/jetty-server-${jetty.version}.jar
lib/jetty-xml-${jetty.version}.jar
lib/jetty-util-${jetty.version}.jar
lib/jetty-io-${jetty.version}.jar
[xml]
etc/jetty.xml
[ini-template]
threads.min=10
threads.max=200
The server
module declares the libraries the server needs and to use jetty.xml
file.
The combined metadata of the http
and server
modules results in start.jar
generating the effective Java command line required to start Jetty.
Another way to see this is by asking Jetty what its configuration looks like by appending --list-config to the command line:
[jetty-distribution-{VERSION}]$ java -jar start.jar --module=http jetty.http.port=9099 --list-config
Java Environment:
-----------------
java.home=/user/lib/jvm/jdk-7u21-x64/jre
java.vm.vendor=Oracle Corporation
java.vm.version=23.25-b01
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
java.vm.info=mixed mode
java.runtime.name=Java(TM) SE Runtime Environment
java.runtime.version=1.7.0_25-b15
java.io.tmpdir=/tmp
Jetty Environment:
-----------------
jetty.home=/opt/jetty/jetty-distribution-{VERSION}
jetty.base=/opt/jetty/jetty-distribution-{VERSION}
jetty.version={VERSION}
JVM Arguments:
--------------
(no jvm args specified)
System Properties:
------------------
jetty.home = /opt/jetty/jetty-distribution-{VERSION}
jetty.base = /opt/jetty/jetty-distribution-{VERSION}
Properties:
-----------
jetty.http.port = 9099
Jetty Server Classpath:
-----------------------
Version Information on 7 entries in the classpath.
Note: order presented here is how they would appear on the classpath.
changes to the --module=name command line options will be reflected here.
0: 3.1.0 | ${jetty.home}/lib/servlet-api-3.1.jar
1: 3.1.RC0 | ${jetty.home}/lib/jetty-schemas-3.1.jar
2: {VERSION} | ${jetty.home}/lib/jetty-http-{VERSION}.jar
3: {VERSION} | ${jetty.home}/lib/jetty-server-{VERSION}.jar
4: {VERSION} | ${jetty.home}/lib/jetty-xml-{VERSION}.jar
5: {VERSION} | ${jetty.home}/lib/jetty-util-{VERSION}.jar
6: {VERSION} | ${jetty.home}/lib/jetty-io-{VERSION}.jar
Jetty Active XMLs:
------------------
${jetty.home}/etc/jetty.xml
${jetty.home}/etc/jetty-http.xml
This represents the entirety of the configuration that is applied to start Jetty.
If you don’t want to use the start.jar
bootstrap, you can start Jetty using a traditional Java command line.
The following is the equivalent Java command line for what the start.jar
bootstrap above performs.
[user]$ cd jetty-distribution-{VERSION}
[jetty-distribution-{VERSION}]$ echo jetty.http.port=8080 > /tmp/jetty.properties
[jetty-distribution-{VERSION}]$ export JETTY_HOME=`pwd`
[jetty-distribution-{VERSION}]$ export JETTY_BASE=`pwd`
[jetty-distribution-{VERSION}]$ export JETTY_VERSION="${project.version}"
[jetty-distribution-{VERSION}]$ java -Djetty.home=$JETTY_HOME \
-Djetty.base=$JETTY_BASE \
-cp \
$JETTY_HOME/lib/servlet-api-3.1.jar\
:$JETTY_HOME/lib/jetty-schemas-3.1.jar\
:$JETTY_HOME/lib/jetty-http-$JETTY_VERSION.jar\
:$JETTY_HOME/lib/jetty-server-$JETTY_VERSION.jar \
:$JETTY_HOME/lib/jetty-xml-$JETTY_VERSION.jar\
:$JETTY_HOME/lib/jetty-util-$JETTY_VERSION.jar\
:$JETTY_HOME/lib/jetty-io-$JETTY_VERSION.jar\
org.eclipse.jetty.xml.XmlConfiguration \
/tmp/jetty.properties \
$JETTY_HOME/etc/jetty.xml \
$JETTY_HOME/etc/jetty-http.xml
The Java command line sets up the classpath with the core Jetty jars and the servlet API, executes the XmlConfiguration class and passes it some XML files that define the server and an HTTP connector running on the port defined in the jetty.properties
file.
You can further simplify the startup of this server by using the INI template defined by the modules to create a start.ini
file with the command:
[user]$ cd jetty-distribution-{VERSION}
[jetty-distribution-{VERSION}]$ mkdir example-base
[example-base]$ cd example-base
[example-base]$ ls -la
total 8
drwxrwxr-x 2 user webgroup 4096 Oct 4 11:49 ./
drwxrwxr-x 12 user webgroup 4096 Oct 4 11:49 ../
[example-base]$ java -jar $JETTY_HOME/start.jar --add-to-start=http
WARNING: http initialised in ${jetty.base}/start.ini (appended)
WARNING: http enabled in ${jetty.base}/start.ini
WARNING: server initialised in ${jetty.base}/start.ini (appended)
WARNING: server enabled in ${jetty.base}/start.ini
[example-base]$ ls -la
total 12
drwxrwxr-x 2 user webgroup 4096 Oct 4 11:55 ./
drwxrwxr-x 12 user webgroup 4096 Oct 4 11:49 ../
-rw-rw-r-- 1 user webgroup 250 Oct 4 11:55 start.ini
Once complete, you can edit the start.ini
file to modify any parameters and you can run the server with the simple command:
[example-base]$ java -jar $JETTY_HOME/start.jar
Using start.jar
The most basic way of starting the Jetty standalone server is to execute the start.jar
, which is a bootstrap for starting Jetty with the configuration you want.
[jetty-distribution-{VERSION}]$ java -jar start.jar
2013-09-23 11:27:06.654:INFO:oejs.Server:main: jetty-{VERSION}
...
Jetty is a highly modularized web server container. Very little is mandatory and required, and most components are optional; you enable or disable them according to the needs of your environment.
At its most basic, you configure Jetty from two elements:
-
A set of libraries and directories that make up the server classpath.
-
A set of Jetty XML configuration files (IoC style) that establish how to build the Jetty server and its components.
Instead of editing these directly, Jetty 9.1 introduced more options on how to configure Jetty (these are merely syntactic sugar that eventually resolve into the two basic configuration components).
Jetty Startup Features include:
-
A separation of the Jetty distribution binaries in
${jetty.home}
and the environment specific configurations (and binaries) found in${jetty.base}
(detailed in Managing Jetty Base and Jetty Home.) -
You can enable a set of libraries and XML configuration files via the newly introduced module system.
-
All of the pre-built XML configuration files shipped in Jetty are now parameterized with properties that you can specify in your
${jetty.base}/start.ini
(demonstrated in Quick Start Configuration).
These are powerful new features, made to support a variety of styles of configuring Jetty, from a simple property based configuration, to handling multiple installations on a server, to customized stacks of technology on top of Jetty, and even the classic, custom XML configurations of old.
For example, if you use the ${jetty.base}
concepts properly, you can upgrade the Jetty distribution without having to remake your entire tree of modifications to Jetty.
Simply separate out your specific modifications to the ${jetty.base}
, and in the future, just upgrade your ${jetty.home}
directory with a new Jetty distribution.
Executing start.jar
When executed start.jar
performs the following actions:
-
Loads and parses all INIs found in
${jetty.base}/start.d/*.ini
as command line arguments. -
Loads and parses
${jetty.base}/start.ini
as command line arguments.-
Please see Start.ini vs. Start.d for more information on the difference between these.
-
-
Parses actual command line arguments used to execute
start.jar
itself. -
Resolves any XML configuration files, modules, and libraries using base vs. home resolution steps:
-
Checks whether file exists as relative reference to
${jetty.base}.
-
Checks whether file exists as relative reference to
${jetty.home}.
-
Uses default behavior of
java.io.File
(Relative toSystem.getProperty
("user.dir") and then as absolute file system path).
-
-
Loads any dependent modules (merges XXNK, library, and properties results with active command line).
-
Builds out server classpath.
-
Determines run mode as one of:
-
Shows informational command line options and exit.
-
Executes Jetty normally, waits for Jetty to stop.
-
Executes a forked JVM to run Jetty in, waits for forked JVM to exit.
-
start.jar Command Line Options
Command Line Options
- --help
-
Obtains the current list of command line options and some basic usage help.
- --version
-
Shows the list of server classpath entries, and prints version information found for each entry.
- --list-classpath
-
Similar to --version, shows the server classpath.
- --list-config
-
Lists the resolved configuration that will start Jetty.
-
Java environment
-
Jetty environment
-
JVM arguments
-
Properties
-
Server classpath
-
Server XML configuration files
-
- --dry-run
-
Print the command line that the start.jar generates, then exit. This may be used to generate command lines when the start.ini includes -X or -D arguments:
$ java -jar start.jar --dry-run > jetty.sh $ . jetty.sh
- --dry-run=<parts>
-
Print specific parts of the command line. The parts are a comma separated list of:
-
"java" - the JVM to run
-
"opts" - the JVM options (eg -D and -X flags)
-
"path" - the JVM class path or JPMS modules options
-
"main" - the main class to run
-
"args" - the arguments passed to the main class
-
It is possible to decompose the start command:
$ 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) $ java $OPTS -Dextra=opt $MAIN $ARGS extra=arg
Alternatively to create an args file for java:
$ java -jar start.jar --dry-run=opts,path,main,args > /tmp/args $ java @/tmp/args
- --exec
-
Forces the start to use a forked instance of java to run Jetty. Some modules include
--exec
in order to set java command line options. Some start options, such as--jpms
also imply--exec
- --exec-properties=<filename>
-
Assign a fixed name to the file used to transfer properties to the sub process. This allows the generated properties file to be saved and reused. Without this option, a temporary file is used.
- --commands=<filename>
-
Instructs
start.jar
to use each line of the specified file as arguments on the command line.
Debug and Start Logging
- --debug
-
Enables debugging output of the startup procedure.
Note: This does not set up debug logging for Jetty itself. For information on logging, please see the section on Configuring Jetty Logging.]
- --start-log-file=<filename>
-
Sends all startup output to the filename specified. Filename is relative to
${jetty.base}
. This is useful for capturing startup issues where the Jetty-specific logger has not yet kicked in due to a possible startup configuration error.
Module Management
- --list-modules
-
Lists all the modules defined by the system. Looks for module files using the normal
${jetty.base}
and${jetty.home}
resolution logic. Also lists enabled state based on information present on the command line, and all active startup INI files. - --list-modules=<tag>(,<tag>)*
-
List modules by tag. Use '*' for all tags. Prefix a tag with '-' to exclude the tag. The special tag "internal" is always excluded unless it is explicitly included.
- --list-all-modules
-
List all modules.
- --module=<name>,(<name>)*
-
Enables one or more modules by name (use
--list-modules
to see the list of available modules). This enables all transitive (dependent) modules from the module system as well. If you use this from the shell command line, it is considered a temporary effect, useful for testing out a scenario. If you want this module to always be enabled, add this command to your${jetty.base}/start.ini.
- --add-to-start=<name>,(<name>)*
-
Enables a module by appending lines to the
${jetty.base}/start.ini
file. The lines that are added are provided by the module-defined INI templates. Note: Transitive modules are also appended. If a module contains an .ini template with properties, you can also edit these properties when activating the module. To do this, simply list the property and its value after the-add-to-start
command, such as in the following example:$ java -jar start.jar --add-to-start=http jetty.http.port=8379 jetty.http.host=1.2.3.4
Doing this will uncomment the property in the associated .ini file and set it to the value specified.
- --update-ini
-
Used to update a specified property or properties that exist in an existing .ini file. Jetty scans the command line,
${jetty.base}
and${jetty.home}
for .ini files that have the specified property and update it accordingly.$ java -jar ../start.jar --update-ini jetty.http.port=8417 ConfigSource <command-line> ConfigSource ${jetty.base} INFO : http property updated jetty.http.port=8417 INFO : http updated ${jetty.base}/start.d/http.ini ConfigSource ${jetty.home}
- --create-startd
-
Creates a
${jetty.base}/start.d/
directory. If a${jetty.base}/start.ini
file already exists, it is copied to the${jetty.base}/start.d
directory.
With respect to |
- --write-module-graph=<filename>
-
Advanced feature: Creates a graphviz dot file of the module graph as it exists for the active
${jetty.base}
.# generate module.dot $ java -jar start.jar --module=websocket --write-module-graph=modules.dot # post process to a PNG file $ dot -Tpng -o modules.png modules.dot
See graphviz.org for details on how to post-process this dotty file into the output best suited for your needs.
- --create-files
-
Create any missing files that are required by initialized modules. This may download a file from the network if the module provides a URL.
- --skip-file-validation=<modulename>(,<modulename)*
-
Disable the [files] section validation of content in the
${jetty.base}
directory for a specific module. Useful for modules that have downloadable content that is being overridden with alternatives in the${jetty.base}`
directory.
This advanced option is for administrators that fully understand the configuration of their |
- --approve-all-licenses
-
Approve all license questions. Useful for enabling modules from a script that does not require user interaction.
Startup / Shutdown Command Line
- --stop
-
Sends a stop signal to the running Jetty instance.
Note: The server must have been started with various stop properties for this to work.
- STOP.PORT=<number>
-
The port to use to stop the running Jetty server. This is an internal port, opened on localhost, used solely for stopping the running Jetty server. Choose a port that you do not use to serve web traffic.
Required for
--stop
to function. - STOP.KEY=<alphanumeric>
-
The passphrase defined to stop the server.
Required for
--stop
to function. - STOP.WAIT=<number>
-
The time (in seconds) to wait for confirmation that the running Jetty server has stopped. If not specified, the stopper waits indefinitely for the server to stop.
If the time specified elapses, without a confirmation of server stop, then the
--stop
command exits with a non-zero return code.
You can configure a port number for Jetty to listen on for a stop command, so you are able to stop it from a different terminal.
This requires the use of a "secret" key, to prevent malicious or accidental termination.
Use the STOP.PORT
and STOP.KEY
(or -DSTOP.PORT=
and -DSTOP.KEY=
, respectively, which will set these as system parameters) parameters as arguments to the start.jar
:
> java -jar ${JETTY_HOME}/start.jar STOP.PORT=1234 STOP.KEY=secretpassword
Then, to stop Jetty from a different terminal, you need to supply this port and key information.
You can either use a copy of the Jetty distribution, the jetty-maven-plugin, the jetty-ant plugin, or a custom class to accomplish this.
Here’s how to use the Jetty distribution, leveraging start.jar
, to perform a stop:
> java -jar start.jar STOP.PORT=8181 STOP.KEY=abc123 --stop
To perform a graceful shutdown of Jetty, the |
Advanced Commands
- --lib=<classpath>
-
Add arbitrary classpath entries to the the server classpath.
- --include-jetty-dir=<path>
-
Include an extra Jetty directory to use as a source for configuration details. This directory behaves similarly to
${jetty.base}
but sits at a layer between${jetty.base}
and${jetty.home}
. This allows for some complex hierarchies of configuration details. - --download=<http-uri>|<location>
-
If the file does not exist at the given location, download it from the given http URI. Note: location is always relative to
${jetty.base}
. You might need to escape the pipe "\|" to use this on some environments. - maven.repo.uri=[url]
-
The url to use to download Maven dependencies. Default is https://repo1.maven.org/maven2/.
Shaded Start.jar
If you have a need for a shaded version of start.jar
(such as for Gradle), you can achieve this via a Maven dependency.
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-start</artifactId>
<version>{VERSION}</version>
<classifier>shaded</classifier>
</dependency>
Start.jar without exec or forking.
Some Jetty modules include the --exec
option so that java command line options can be set.
Also some start.jar
options (eg. --jpms
) include an implicit --exec
.
To start jetty without forking a new JVM instance from the start JVM, the --dry-run
option can be used to generate a command line:
$ CMD=$(java -jar start.jar --dry-run) $ $CMD
It is possible to decompose the start command so that it can be modified:
$ 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) $ java $OPTS -Dextra=opt $MAIN $ARGS extra=arg
Alternatively to create an args file for java:
$ java -jar start.jar --dry-run=opts,path,main,args > /tmp/args $ java @/tmp/args
Managing Jetty Base and Jetty Home
Instead of managing multiple Jetty implementations out of several different distribution 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}
).
In addition to easy management of multiple server instances, is allows for quick, drop-in upgrades of Jetty.
There should always only be one Jetty Home (per version of Jetty), but there can be multiple Jetty Base directories that reference it.
- Jetty Base
-
-
Also known as the
${jetty.base}
property. -
This is the location for your configurations and customizations to the Jetty distribution.
-
- Jetty Home
-
-
Also known as the
${jetty.home}
property. -
This is the location for the Jetty distribution binaries, default XML IoC configurations, and default module definitions.
-
Jetty Home should always be treated as a standard of truth. All configuration modifications, changes and additions should be made in the appropriate Jetty Base directory. |
Potential configuration is resolved from these 2 directory locations. When Jetty starts up in processes configuration from them as follows:
- Check Jetty Base First
-
If the referenced configuration exists, relative to the defined Jetty base, it is used.
- Check Jetty Home Second
-
If the referenced configuration exists, relative to the defined Jetty home, it is used.
- Use java.io.File(String pathname) Logic
-
Lastly, use the reference as a
java.io.File(String pathname)
reference, following the default resolution rules outlined by that constructor. In brief, the reference will be used as-is, be it relative (to current working directory, aka $\{user.dir}) or absolute path, or even network reference (such as on Windows and use of UNC paths).
For more details on how startup with start.jar works, see Using start.jar: Executing
Demo-Base in the Jetty Distribution
The Jetty Distribution comes with an example ${jetty.base}
which enables the various demonstration webapps and server configurations.
[jetty-distribution-{VERSION}]$ ls -la
total 496
drwxrwxr-x 11 user group 4096 Oct 8 15:23 ./
drwxr-xr-x 14 user group 4096 Oct 8 13:04 ../
drwxrwxr-x 2 user group 4096 Oct 8 06:54 bin/
drwxrwxr-x 6 user group 4096 Oct 8 06:54 demo-base/
drwxrwxr-x 2 user group 4096 Oct 11 15:14 etc/
drwxrwxr-x 11 user group 4096 Oct 8 06:54 lib/
-rw-rw-r-- 1 user group 30012 Sep 30 19:55 license-eplv10-aslv20.html
drwxrwxr-x 2 user group 4096 Oct 8 06:54 logs/
drwxrwxr-x 2 user group 4096 Oct 8 06:54 modules/
-rw-rw-r-- 1 user group 6262 Sep 30 19:55 notice.html
-rw-rw-r-- 1 user group 1249 Sep 30 19:55 README.TXT
drwxrwxr-x 2 user group 4096 Oct 8 06:54 resources/
drwxrwxr-x 2 user group 4096 Oct 8 06:54 start.d/
-rw-rw-r-- 1 user group 1780 Sep 30 19:55 start.ini
-rw-rw-r-- 1 user group 71921 Sep 30 19:55 start.jar
-rw-rw-r-- 1 user group 336468 Sep 30 19:55 VERSION.txt
drwxrwxr-x 2 user group 4096 Oct 8 06:54 webapps/
[jetty-distribution-{VERSION}]$ cd demo-base
[demo-base]$ java -jar $JETTY_HOME/start.jar
2013-10-16 09:08:47.800:WARN::main: demo test-realm is deployed. DO NOT USE IN PRODUCTION!
2013-10-16 09:08:47.802:INFO:oejs.Server:main: jetty-{VERSION}
2013-10-16 09:08:47.817:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/home/user/jetty-distribution-{VERSION}/demo-base/webapps/] at interval 1
2013-10-16 09:08:48.072:WARN::main: async-rest webapp is deployed. DO NOT USE IN PRODUCTION!
...
If you want to see what the Jetty base looks like without executing Jetty, you can simply list the configuration by using the --list-config
command.
[demo-base]$ java -jar $JETTY_HOME/start.jar --list-config
Java Environment:
-----------------
java.home=/usr/lib/jvm/jdk-7u21-x64/jre
java.vm.vendor = Oracle Corporation
java.vm.version = 25.92-b14
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
java.vm.info = mixed mode
java.runtime.name = Java(TM) SE Runtime Environment
java.runtime.version = 1.8.0_92-b14
java.io.tmpdir = /var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/
user.dir = /home/user/jetty-distribution-{VERSION}
user.language = en
user.country = US
Jetty Environment:
-----------------
jetty.home=/home/user/jetty-distribution-{VERSION}
jetty.tag.version = master
jetty.base=/home/user/jetty-distribution-{VERSION}/demo-base
jetty.version={VERSION}
Config Search Order:
--------------------
<command-line>
${jetty.base} -> /home/user/jetty-distribution-{VERSION}/demo-base
${jetty.home} -> /home/user/Desktop/jetty-distribution-{VERSION}
JVM Arguments:
--------------
(no jvm args specified)
System Properties:
------------------
jetty.base = /home/user/jetty-distribution-{VERSION}/demo-base
jetty.home = /home/user/jetty-distribution-{VERSION}
Properties:
-----------
demo.realm = etc/realm.properties
https.port = 8443
https.timeout = 30000
jaas.login.conf = etc/login.conf
jetty.dump.start = false
jetty.dump.stop = false
jetty.keymanager.password = OBF:1u2u1wml1z7s1z7a1wnl1u2g
jetty.keystore = etc/keystore
jetty.keystore.password = OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
jetty.http.port = 8080
jetty.secure.port = 8443
jetty.truststore = etc/keystore
jetty.truststore.password = OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
org.eclipse.jetty.websocket.jsr356 = false
threads.max = 200
threads.min = 10
threads.timeout = 60000
Jetty Server Classpath:
-----------------------
Version Information on 42 entries in the classpath.
Note: order presented here is how they would appear on the classpath.
changes to the --module=name command line options will be reflected here.
0: {VERSION} | ${jetty.home}/lib/jetty-client-{VERSION}.jar
1: 1.4.1.v201005082020 | ${jetty.base}/lib/ext/javax.mail.glassfish-1.4.1.v201005082020.jar
2: {VERSION} | ${jetty.base}/lib/ext/test-mock-resources-{VERSION}.jar
3: (dir) | ${jetty.home}/resources
4: 3.1.0 | ${jetty.home}/lib/servlet-api-3.1.jar
5: 3.1.RC0 | ${jetty.home}/lib/jetty-schemas-3.1.jar
6: {VERSION} | ${jetty.home}/lib/jetty-http-{VERSION}.jar
7: {VERSION} | ${jetty.home}/lib/jetty-continuation-{VERSION}.jar
8: {VERSION} | ${jetty.home}/lib/jetty-server-{VERSION}.jar
9: {VERSION} | ${jetty.home}/lib/jetty-xml-{VERSION}.jar
10: {VERSION} | ${jetty.home}/lib/jetty-util-{VERSION}.jar
11: {VERSION} | ${jetty.home}/lib/jetty-io-{VERSION}.jar
12: {VERSION} | ${jetty.home}/lib/jetty-jaas-{VERSION}.jar
13: {VERSION} | ${jetty.home}/lib/jetty-jndi-{VERSION}.jar
14: 1.1.0.v201105071233 | ${jetty.home}/lib/jndi/javax.activation-1.1.0.v201105071233.jar
15: 1.4.1.v201005082020 | ${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
16: 1.3 | ${jetty.home}/lib/jndi/javax.transaction-api-1.3.jar
17: {VERSION} | ${jetty.home}/lib/jetty-rewrite-{VERSION}.jar
18: {VERSION} | ${jetty.home}/lib/jetty-security-{VERSION}.jar
19: {VERSION} | ${jetty.home}/lib/jetty-servlet-{VERSION}.jar
20: 3.0.0 | ${jetty.home}/lib/jsp/javax.el-3.0.0.jar
21: 1.2.0.v201105211821 | ${jetty.home}/lib/jsp/javax.servlet.jsp.jstl-1.2.0.v201105211821.jar
22: 2.3.2 | ${jetty.home}/lib/jsp/javax.servlet.jsp-2.3.2.jar
23: 2.3.1 | ${jetty.home}/lib/jsp/javax.servlet.jsp-api-2.3.1.jar
24: 2.3.3 | ${jetty.home}/lib/jsp/jetty-jsp-jdt-2.3.3.jar
25: 1.2.0.v201112081803 | ${jetty.home}/lib/jsp/org.apache.taglibs.standard.glassfish-1.2.0.v201112081803.jar
26: 3.8.2.v20130121-145325 | ${jetty.home}/lib/jsp/org.eclipse.jdt.core-3.8.2.v20130121.jar
27: {VERSION} | ${jetty.home}/lib/jetty-plus-{VERSION}.jar
28: {VERSION} | ${jetty.home}/lib/jetty-webapp-{VERSION}.jar
29: {VERSION} | ${jetty.home}/lib/jetty-annotations-{VERSION}.jar
30: 4.1 | ${jetty.home}/lib/annotations/asm-4.1.jar
31: 4.1 | ${jetty.home}/lib/annotations/asm-commons-4.1.jar
32: 1.2 | ${jetty.home}/lib/annotations/javax.annotation-api-1.2.jar
33: {VERSION} | ${jetty.home}/lib/jetty-deploy-{VERSION}.jar
34: 1.0 | ${jetty.home}/lib/websocket/javax.websocket-api-1.0.jar
35: {VERSION} | ${jetty.home}/lib/websocket/javax-websocket-client-impl-{VERSION}.jar
36: {VERSION} | ${jetty.home}/lib/websocket/javax-websocket-server-impl-{VERSION}.jar
37: {VERSION} | ${jetty.home}/lib/websocket/websocket-api-{VERSION}.jar
38: {VERSION} | ${jetty.home}/lib/websocket/websocket-client-{VERSION}.jar
39: {VERSION} | ${jetty.home}/lib/websocket/websocket-common-{VERSION}.jar
40: {VERSION} | ${jetty.home}/lib/websocket/websocket-server-{VERSION}.jar
41: {VERSION} | ${jetty.home}/lib/websocket/websocket-servlet-{VERSION}.jar
Jetty Active XMLs:
------------------
${jetty.home}/etc/jetty.xml
${jetty.home}/etc/jetty-webapp.xml
${jetty.home}/etc/jetty-plus.xml
${jetty.home}/etc/jetty-annotations.xml
${jetty.home}/etc/jetty-deploy.xml
${jetty.home}/etc/jetty-http.xml
${jetty.home}/etc/jetty-ssl.xml
${jetty.home}/etc/jetty-ssl-context.xml
${jetty.home}/etc/jetty-https.xml
${jetty.home}/etc/jetty-jaas.xml
${jetty.home}/etc/jetty-rewrite.xml
${jetty.base}/etc/demo-rewrite-rules.xml
${jetty.base}/etc/test-realm.xml
The --list-config
command line option displays what the configuration will look like when starting Jetty.
This includes information on the Java environment to the system properties, the classpath and the Active Jetty IoC XML used to build up the Jetty server configuration.
Of note, is that the output will make it known where the configuration elements came from, be it in either in ${jetty.home}
or ${jetty.base}
.
If you look at the ${jetty.base}/start.ini
you will see a layout similar to below.
[my-base]$ cat start.ini
# Enable security via jaas, and configure it
--module=jaas
jaas.login.conf=etc/login.conf
# Enable rewrite examples
--module=rewrite
etc/demo-rewrite-rules.xml
# Websocket chat examples needs websocket enabled
# Don't start for all contexts (set to true in test.xml context)
org.eclipse.jetty.websocket.jsr356=false
--module=websocket
# Create and configure the test realm
etc/test-realm.xml
demo.realm=etc/realm.properties
# Initialize module server
--module=server
threads.min=10
threads.max=200
threads.timeout=60000
jetty.dump.start=false
jetty.dump.stop=false
--module=deploy
--module=jsp
--module=ext
--module=resources
--module=client
--module=annotations
In this example, ${jetty.base}/start.ini
is the main startup configuration entry point for Jetty.
You will see that we are enabling a few modules for Jetty, specifying some properties, and also referencing some Jetty IoC XML files (namely the etc/demo-rewrite-rules.xml
and etc/test-realm.xml
files)
When Jetty’s start.jar
resolves the entries in the start.ini
, it will follow the resolution rules above.
For example, the reference to etc/demo-rewrite-rules.xml
was found in ${jetty.base}/etc/demo-rewrite-rules.xml
.
Declaring Jetty Base
The Jetty distribution’s start.jar
is the component that manages the behavior of this separation.
The Jetty start.jar
and XML files always assume that both ${jetty.home}
and ${jetty.base}
are defined when starting Jetty.
You can opt to manually define the ${jetty.home}
and ${jetty.base}
directories, such as this:
[jetty-distribution-{VERSION}]$ pwd
/home/user/jetty-distribution-{VERSION}
[jetty-distribution-{VERSION}]$ java -jar start.jar \
jetty.home=/home/user/jetty-distribution-{VERSION} \
jetty.base=/home/user/my-base
2013-10-16 09:08:47.802:INFO:oejs.Server:main: jetty-{VERSION}
2013-10-16 09:08:47.817:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/home/user/my-base/webapps/] at interval 1
...
Alternately, you can declare one directory and let the other one be discovered.
The following example uses default discovery of ${jetty.home}
by using the parent directory of wherever start.jar
itself is, and a manual declaration of ${jetty.base}
.
[jetty-distribution-{VERSION}]$ pwd
/home/user/jetty-distribution-{VERSION}
[jetty-distribution-{VERSION}]$ java -jar start.jar jetty.base=/home/user/my-base
2013-10-16 09:08:47.802:INFO:oejs.Server:main: jetty-{VERSION}
2013-10-16 09:08:47.817:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/home/user/my-base/webapps/] at interval 1
...
But Jetty recommends that you always start Jetty from the directory that is your ${jetty.base}
and starting Jetty by referencing
the start.jar
in your {$jetty.home}
remotely.
The following demonstrates this by allowing default discovery of ${jetty.home}
via locating the start.jar
, and using the user.dir
System Property for ${jetty.base}
.
[jetty-distribution-{VERSION}]$ pwd
/home/user/jetty-distribution-{VERSION}
[jetty-distribution-{VERSION}]$ cd /home/user/my-base
[my-base]$ java -jar /home/user/jetty-distribution-{VERSION}/start.jar
2013-10-16 09:08:47.802:INFO:oejs.Server:main: jetty-{VERSION}
2013-10-16 09:08:47.817:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/home/user/my-base/webapps/] at interval 1
...
Be aware of the |
Managing Server Classpath
Jetty Server Classpath is determined by a combination of factors.
- The java.class.path System Property
-
If you start Jetty with a JVM specified classpath, then Jetty will use the java.class.path System Property to populate the initial classpath.
- Module specified Libraries
-
The module system declares various libraries that are required for that module to operate. These module defined libraries are added to the Jetty Server classpath when any module is activated with library declarations.
- Command Line Libraries
-
The command line option
--lib=<path>
can be used as a final means to add arbitrary entries to the Jetty Server classpath.
Of special note, there are 2 structural modules defined to ease some of this for you.
- --module=ext
-
The
ext
module will enable thelib/ext/*.jar
logic. + If this module is activated, then all jar files found in the lib/ext/ paths will be automatically added to the Jetty Server Classpath. - --module=resources
-
The
resources
module will add theresources/
directory the classpath. + If you have 3rd party libraries that lookup resources from the classpath, put your files in here. + Logging libraries often have classpath lookup of their configuration files (eg:log4j.properties
,log4j.xml
,logging.properties
, andlogback.xml
), so this would be the ideal setup for this sort of configuration demand.
Both the |
Interrogating the Server Classpath
The Jetty start.jar
has the ability to resolve the classpath from the command line, modules and configuration, and to list the classpath entries it will use to start jetty.
The --list-classpath
command line option is used as such.
(Demonstrated with the demo-base from the Jetty Distribution)
[demo-base]$ java -jar $JETTY_HOME/start.jar --list-classpath
Jetty Server Classpath:
-----------------------
Version Information on 42 entries in the classpath.
Note: order presented here is how they would appear on the classpath.
changes to the --module=name command line options will be reflected here.
0: {VERSION} | ${jetty.home}/lib/jetty-client-{VERSION}.jar
1: 1.4.1.v201005082020 | ${jetty.base}/lib/ext/javax.mail.glassfish-1.4.1.v201005082020.jar
2: {VERSION} | ${jetty.base}/lib/ext/test-mock-resources-{VERSION}.jar
3: (dir) | ${jetty.home}/resources
4: 3.1.0 | ${jetty.home}/lib/servlet-api-3.1.jar
5: 3.1.RC0 | ${jetty.home}/lib/jetty-schemas-3.1.jar
6: {VERSION} | ${jetty.home}/lib/jetty-http-{VERSION}.jar
7: {VERSION} | ${jetty.home}/lib/jetty-continuation-{VERSION}.jar
8: {VERSION} | ${jetty.home}/lib/jetty-server-{VERSION}.jar
9: {VERSION} | ${jetty.home}/lib/jetty-xml-{VERSION}.jar
10: {VERSION} | ${jetty.home}/lib/jetty-util-{VERSION}.jar
11: {VERSION} | ${jetty.home}/lib/jetty-io-{VERSION}.jar
12: {VERSION} | ${jetty.home}/lib/jetty-jaas-{VERSION}.jar
13: {VERSION} | ${jetty.home}/lib/jetty-jndi-{VERSION}.jar
14: 1.1.0.v201105071233 | ${jetty.home}/lib/jndi/javax.activation-1.1.0.v201105071233.jar
15: 1.4.1.v201005082020 | ${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
16: 1.3 | ${jetty.home}/lib/jndi/javax.transaction-api-1.3.jar
17: {VERSION} | ${jetty.home}/lib/jetty-rewrite-{VERSION}.jar
18: {VERSION} | ${jetty.home}/lib/jetty-security-{VERSION}.jar
19: {VERSION} | ${jetty.home}/lib/jetty-servlet-{VERSION}.jar
20: 3.0.0 | ${jetty.home}/lib/jsp/javax.el-3.0.0.jar
21: 1.2.0.v201105211821 | ${jetty.home}/lib/jsp/javax.servlet.jsp.jstl-1.2.0.v201105211821.jar
22: 2.3.2 | ${jetty.home}/lib/jsp/javax.servlet.jsp-2.3.2.jar
23: 2.3.1 | ${jetty.home}/lib/jsp/javax.servlet.jsp-api-2.3.1.jar
24: 2.3.3 | ${jetty.home}/lib/jsp/jetty-jsp-jdt-2.3.3.jar
25: 1.2.0.v201112081803 | ${jetty.home}/lib/jsp/org.apache.taglibs.standard.glassfish-1.2.0.v201112081803.jar
26: 3.8.2.v20130121-145325 | ${jetty.home}/lib/jsp/org.eclipse.jdt.core-3.8.2.v20130121.jar
27: {VERSION} | ${jetty.home}/lib/jetty-plus-{VERSION}.jar
28: {VERSION} | ${jetty.home}/lib/jetty-webapp-{VERSION}.jar
29: {VERSION} | ${jetty.home}/lib/jetty-annotations-{VERSION}.jar
30: 4.1 | ${jetty.home}/lib/annotations/asm-4.1.jar
31: 4.1 | ${jetty.home}/lib/annotations/asm-commons-4.1.jar
32: 1.2 | ${jetty.home}/lib/annotations/javax.annotation-api-1.2.jar
33: {VERSION} | ${jetty.home}/lib/jetty-deploy-{VERSION}.jar
34: 1.0 | ${jetty.home}/lib/websocket/javax.websocket-api-1.0.jar
35: {VERSION} | ${jetty.home}/lib/websocket/javax-websocket-client-impl-{VERSION}.jar
36: {VERSION} | ${jetty.home}/lib/websocket/javax-websocket-server-impl-{VERSION}.jar
37: {VERSION} | ${jetty.home}/lib/websocket/websocket-api-{VERSION}.jar
38: {VERSION} | ${jetty.home}/lib/websocket/websocket-client-{VERSION}.jar
39: {VERSION} | ${jetty.home}/lib/websocket/websocket-common-{VERSION}.jar
40: {VERSION} | ${jetty.home}/lib/websocket/websocket-server-{VERSION}.jar
41: {VERSION} | ${jetty.home}/lib/websocket/websocket-servlet-{VERSION}.jar
Of note is that an attempt is made to list the internally declared version of each artifact on the Server Classpath, which can potentially help when diagnosing classpath issues.
Managing Startup Modules
The standard Jetty Distribution ships with several modules defined in ${jetty.home}/modules/
.
Modules interact with Jetty XML files to configure options and parameters for the server and are the primary configuration method for Jetty distributions.
Modules allow flexibility for implementations and their plug-and-play nature makes adding or removing server functionality virtually painless.
Enabling Modules
The default distribution has a co-mingled |
Enabling a module is a simple process: simply add the --add-to-start=<module-name1>,<module-name2>,…etc.
syntax on the command line.
Doing this will enable the specified module and any dependent modules.
An example of this with a new, empty, base directory:
If we try to start the Jetty server with no configuration or modules enabled, it will promptly exit:
[jetty]$ mkdir mybase
[jetty]$ cd mybase
[mybase]$ ls -la
total 0
drwxr-xr-x 2 staff staff 68 Jul 12 17:29 .
drwxr-xr-x 20 staff staff 680 Jul 12 17:29 ..
[mybase]$ java -jar $JETTY_HOME/start.jar
WARNING: Nothing to start, exiting ...
Usage: java -jar start.jar [options] [properties] [configs]
java -jar start.jar --help # for more information
By using the --list-config
parameter to our startup command, we can see that there are no modules enabled and no Jetty XML files are active:
[mybase]$ java -jar $JETTY_HOME/start.jar --list-config
Java Environment:
-----------------
java.home = /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre
java.vm.vendor = Oracle Corporation
java.vm.version = 25.92-b14
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
java.vm.info = mixed mode
java.runtime.name = Java(TM) SE Runtime Environment
java.runtime.version = 1.8.0_92-b14
java.io.tmpdir = /var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/
user.dir = /Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase
user.language = en
user.country = US
Jetty Environment:
-----------------
jetty.version = {VERSION}
jetty.tag.version = master
jetty.home = /Users/staff/installs/repository/jetty-distribution-{VERSION}
jetty.base = /Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase
Config Search Order:
--------------------
<command-line>
${jetty.base} -> /Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase
${jetty.home} -> /Users/staff/installs/repository/jetty-distribution-{VERSION}
JVM Arguments:
--------------
(no jvm args specified)
System Properties:
------------------
(no system properties specified)
Properties:
-----------
java.version = 1.8.0_92
Jetty Server Classpath:
-----------------------
No classpath entries and/or version information available show.
Jetty Active XMLs:
------------------
(no xml files specified)
Let’s try adding some basic support for webapps, with automatic deploy (hot deploy), and a single basic HTTP/1.1 connector.
[mybase]$ java -jar $JETTY_HOME/start.jar --add-to-start=http,webapp,deploy
INFO : webapp initialized in ${jetty.base}/start.ini
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : security transitively enabled
INFO : servlet transitively enabled
INFO : http initialized in ${jetty.base}/start.ini
INFO : deploy initialized in ${jetty.base}/start.ini
MKDIR : ${jetty.base}/webapps
INFO : Base directory was modified
This creates the webapps directory in our mybase
directory and appended the start.ini
file with the ini template arguments from the associated module files.
Additionally, where needed, Jetty enabled any module dependencies.
Now that we have added some modules to our server, let’s run --list-config
again to review our new configuration.
[mybase]$ java -jar $JETTY_HOME/start.jar --list-config
Java Environment:
-----------------
java.home = /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre
java.vm.vendor = Oracle Corporation
java.vm.version = 25.92-b14
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
java.vm.info = mixed mode
java.runtime.name = Java(TM) SE Runtime Environment
java.runtime.version = 1.8.0_92-b14
java.io.tmpdir = /var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/
user.dir = /Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase
user.language = en
user.country = US
Jetty Environment:
-----------------
jetty.version = {VERSION}
jetty.tag.version = master
jetty.home = /Users/staff/installs/repository/jetty-distribution-{VERSION}
jetty.base = /Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase
Config Search Order:
--------------------
<command-line>
${jetty.base} -> /Users/staff/installs/repository/jetty-distribution-{VERSION}/mybase
${jetty.home} -> /Users/staff/installs/repository/jetty-distribution-{VERSION}
JVM Arguments:
--------------
(no jvm args specified)
System Properties:
------------------
(no system properties specified)
Properties:
-----------
java.version = 1.8.0_92
Jetty Server Classpath:
-----------------------
Version Information on 11 entries in the classpath.
Note: order presented here is how they would appear on the classpath.
changes to the --module=name command line options will be reflected here.
0: 3.1.0 | ${jetty.home}/lib/servlet-api-3.1.jar
1: 3.1.0.M0 | ${jetty.home}/lib/jetty-schemas-3.1.jar
2: {VERSION} | ${jetty.home}/lib/jetty-http-{VERSION}.jar
3: {VERSION} | ${jetty.home}/lib/jetty-server-{VERSION}.jar
4: {VERSION} | ${jetty.home}/lib/jetty-xml-{VERSION}.jar
5: {VERSION} | ${jetty.home}/lib/jetty-util-{VERSION}.jar
6: {VERSION} | ${jetty.home}/lib/jetty-io-{VERSION}.jar
7: {VERSION} | ${jetty.home}/lib/jetty-security-{VERSION}.jar
8: {VERSION} | ${jetty.home}/lib/jetty-servlet-{VERSION}.jar
9: {VERSION} | ${jetty.home}/lib/jetty-webapp-{VERSION}.jar
10: {VERSION} | ${jetty.home}/lib/jetty-deploy-{VERSION}.jar
Jetty Active XMLs:
------------------
${jetty.home}/etc/jetty.xml
${jetty.home}/etc/jetty-webapp.xml
${jetty.home}/etc/jetty-deploy.xml
${jetty.home}/etc/jetty-http.xml
You now have a configured and functional server, albeit with no webapps deployed.
At this point you can place a webapp (war file) in the mybase/webapps/
directory and and start Jetty.
Start.ini vs. Start.d
In the above example, when a module is activated the contents of that module file are added in ${jetty.base}/start.ini
.
As additional modules are added, their contents are appended to this file.
This can be beneficial if you want all of your module configurations in a single file, but for large server instances with lots of modules it can pose a challenge to quickly find and make changes or to remove a module.
As an alternative to a single start.ini
file you can opt to house modules in a ${jetty.base}/start.d
directory.
Modules activated when a start.d
directory exists will be stored as a single file per module.
Below is an example of a fresh ${jetty.base}
that will create a start.d
directory and activate several modules.
[jetty.home]$ mkdir mybase
[jetty.home]$ cd mybase/
[mybase]$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
[mybase]$ ls -all
total 0
drwxr-xr-x 3 staff staff 102 Aug 29 15:16 .
drwxr-xr-x@ 26 staff staff 884 Aug 29 15:16 ..
drwxr-xr-x 6 staff staff 204 Aug 29 15:19 start.d
[mybase]$ java -jar ../start.jar --add-to-start=server,client,webapp,websocket
INFO : webapp initialised in ${jetty.base}/start.d/webapp.ini
INFO : server initialised in ${jetty.base}/start.d/server.ini
INFO : websocket initialised in ${jetty.base}/start.d/websocket.ini
INFO : client initialised in ${jetty.base}/start.d/client.ini
INFO : Base directory was modified
[mybase]$ cd start.d/
[mybase]$ ls -all
total 32
drwxr-xr-x 6 staff staff 204 Aug 29 15:19 .
drwxr-xr-x 3 staff staff 102 Aug 29 15:16 ..
-rw-r--r-- 1 staff staff 175 Aug 29 15:19 client.ini
-rw-r--r-- 1 staff staff 2250 Aug 29 15:19 server.ini
-rw-r--r-- 1 staff staff 265 Aug 29 15:19 webapp.ini
-rw-r--r-- 1 staff staff 177 Aug 29 15:19 websocket.ini
In the example, we first create a new ${jetty.base}
and then create the start.d
directory with the --create-startd
command.
Next, we use the --add-to-start
command which activates the modules and creates their respective ini files in the start.d
directory.
If you have an existing start.ini
file but would like to use the start.d
structure for additional modules, you can use the --create-startd
command as well.
Doing this will create the start.d
directory and copy your existing start.ini
file in to it.
Any new modules added to the server will have their own <module name>.ini
file created in the start.d
directory.
[mybase]$ java -jar ../start.jar --add-to-start=server,client,webapp,websocket
INFO : webapp initialised in ${jetty.base}/start.ini
INFO : server initialised in ${jetty.base}/start.ini
INFO : websocket initialised in ${jetty.base}/start.ini
INFO : client initialised in ${jetty.base}/start.ini
INFO : Base directory was modified
[mybase]$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
[mybase]$ tree
.
└── start.d
└── start.ini
[mybase]$ java -jar ../start.jar --add-to-start=ssl
INFO : ssl initialised in ${jetty.base}/start.d/ssl.ini
INFO : Base directory was modified
[mybase]$ tree
.
├── etc
│ └── keystore
└── start.d
├── ssl.ini
└── start.ini
It is not recommended to use both a |
Configuring Modules
Once a module has been enabled for the server, it can be further configured to meet your needs.
This is done by editing the associated ini file for the module.
If your server setup is using a centralized ini configuration, you will edit the ${jetty.base}/server.ini
file.
If you have elected to manage each module within it’s own ini file, you can find these files in the ${jetty.base}/start.d
directory.
It is important that you do not modify the module files in the |
When a module is activated, a number of properties are set by default. To view these defaults, open up the associated ini file. Listed in the ini file is the associated module file and any properties that can be set.
Below is an example of the requestlog.ini
file:
# ---------------------------------------
# Module: requestlog
--module=requestlog
## Logging directory (relative to $jetty.base)
# jetty.requestlog.dir=logs
## File path
# jetty.requestlog.filePath=${jetty.requestlog.dir}/yyyy_mm_dd.request.log
## Date format for rollovered files (uses SimpleDateFormat syntax)
# jetty.requestlog.filenameDateFormat=yyyy_MM_dd
## How many days to retain old log files
# jetty.requestlog.retainDays=90
## Whether to append to existing file
# jetty.requestlog.append=true
## Whether to use the extended log output
# jetty.requestlog.extended=true
## Whether to log http cookie information
# jetty.requestlog.cookies=true
## Timezone of the log entries
# jetty.requestlog.timezone=GMT
## Whether to log LogLatency
# jetty.requestlog.loglatency=false
The first lines name the module file being called (located in {$jetty.home/modules}
).
Subsequent lines list properties that can be changed as well as a description for each property.
To edit a property, first un-comment the line by deleting the #
at the start of the line, then make the change after =
sign (such as changing a true
value to false
).
Disabling Modules
Disabling a module is an easy process.
To disable a module, comment out the --module=
line in the associated ini file.
Deleting the ini file associated with module is another option, but may not be practical in all situations.
Listing Available and Active Modules
To see which modules are available, use the --list-modules
command line argument.
This command will also show you which modules are enabled.
Modules are sorted by the value in the [tags]
section of the associated .mod
file.
If there are multiple entries in the [tags]
section, it sorts by the first tag in the list.
By default, the |
Here’s an example of the --list-modules
command:
[mybase]$ java -jar ../start.jar --list-modules
Available Modules:
==================
tags: [-internal]
Modules for tag '*':
--------------------
Module: alpn
: Enables the ALPN (Application Layer Protocol Negotiation) TLS extension.
Depend: ssl, alpn-impl
LIB: lib/jetty-alpn-client-${jetty.version}.jar
LIB: lib/jetty-alpn-server-${jetty.version}.jar
XML: etc/jetty-alpn.xml
Module: alpn-impl
: Selects an ALPN (Application Layer Protocol Negotiation) implementation by java version.
Depend: alpn-impl/alpn-${java.version.platform}
Module: annotations
: Enables Annotation scanning for deployed webapplications.
Depend: plus
LIB: lib/jetty-annotations-${jetty.version}.jar
LIB: lib/annotations/*.jar
XML: etc/jetty-annotations.xml
Enabled: ${jetty.base}\start.d\annotations.ini
Module: apache-jsp
: Enables use of the apache implementation of JSP
LIB: lib/apache-jsp/*.jar
Enabled: transitive provider of apache-jsp for jsp
Module: apache-jstl
: Enables the apache version of JSTL
LIB: lib/apache-jstl/*.jar
Enabled: transitive provider of apache-jstl for jstl
Module: cdi2
: Jetty setup to support Weld/CDI2 with WELD inside the webapp
Depend: deploy
XML: etc/cdi2/jetty-cdi2.xml
Module: client
: Adds the Jetty HTTP client to the server classpath.
LIB: lib/jetty-client-${jetty.version}.jar
Enabled: ${jetty.base}\start.d\client.ini
Module: continuation
: Enables support for Continuation style asynchronous
: Servlets. Now deprecated in favour of Servlet 3.1
: API
LIB: lib/jetty-continuation-${jetty.version}.jar
Enabled: ${jetty.base}\start.d\continuation.ini
Module: deploy
: Enables webapplication deployment from the webapps directory.
Depend: webapp
LIB: lib/jetty-deploy-${jetty.version}.jar
XML: etc/jetty-deploy.xml
Enabled: ${jetty.base}\start.d\deploy.ini
Module: fcgi
: Adds the FastCGI implementation to the classpath.
Depend: servlet, client
LIB: lib/jetty-proxy-${jetty.version}.jar
LIB: lib/fcgi/*.jar
Module: flight-recorder
Depend: server
JVM: -XX:+UnlockCommercialFeatures
JVM: -XX:+FlightRecorder
Module: global-webapp-common
: Enables Deployer to apply common configuration to all webapp deployments
Depend: deploy
XML: etc/global-webapp-common.xml
Module: hazelcast-embedded-sessions
Depend: annotations, webapp
LIB: lib/hazelcast/*.jar
XML: etc/sessions/hazelcast/default.xml
Module: hazelcast-remote-sessions
Depend: annotations, webapp
LIB: lib/hazelcast/*.jar
XML: etc/sessions/hazelcast/remote.xml
Module: home-base-warning
: Generates a warning that server has been run from $JETTY_HOME
: rather than from a $JETTY_BASE.
XML: etc/home-base-warning.xml
Module: jaas
: Enable JAAS for deployed webapplications.
Depend: server
LIB: lib/jetty-jaas-${jetty.version}.jar
XML: etc/jetty-jaas.xml
Enabled: ${jetty.base}\start.d\demo.ini
Module: jaspi
: Enable JASPI authentication for deployed webapplications.
Depend: security
LIB: lib/jetty-jaspi-${jetty.version}.jar
LIB: lib/jaspi/*.jar
Module: jmx
: Enables JMX instrumentation for server beans and
: enables JMX agent.
Depend: server
LIB: lib/jetty-jmx-${jetty.version}.jar
XML: etc/jetty-jmx.xml
Module: jmx-remote
: Enables remote RMI access to JMX
Depend: jmx
XML: etc/jetty-jmx-remote.xml
Module: jndi
: Adds the Jetty JNDI implementation to the classpath.
Depend: server, mail
LIB: lib/jetty-jndi-${jetty.version}.jar
LIB: lib/jndi/*.jar
Enabled: ${jetty.base}\start.d\jndi.ini
Module: jsp
: Enables JSP for all webapplications deployed on the server.
Depend: servlet, annotations, apache-jsp
Enabled: ${jetty.base}\start.d\jsp.ini
Module: jstl
: Enables JSTL for all webapplications deployed on the server
Depend: jsp, apache-jstl
Enabled: ${jetty.base}\start.d\jstl.ini
Module: jvm
: A noop module that creates an ini template useful for
: setting JVM arguments (eg -Xmx )
Module: lowresources
: Enables a low resource monitor on the server
: that can take actions if threads and/or connections
: cross configured threshholds.
Depend: server
XML: etc/jetty-lowresources.xml
Module: mail
: Adds the javax.mail implementation to the classpath.
LIB: lib/mail/*.jar
Enabled: transitive provider of mail for jndi
Module: plus
: Enables JNDI and resource injection for webapplications
: and other servlet 3.x features not supported in the core
: jetty webapps module.
Depend: server, security, jndi, webapp, transactions
LIB: lib/jetty-plus-${jetty.version}.jar
XML: etc/jetty-plus.xml
Enabled: transitive provider of plus for annotations
Module: proxy
: Enable the Jetty Proxy, that allows the server to act
: as a non-transparent proxy for browsers.
Depend: servlet, client
LIB: lib/jetty-proxy-${jetty.version}.jar
XML: etc/jetty-proxy.xml
Module: proxy-protocol
: Enables the Proxy Protocol on the HTTP Connector.
: http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
: This allows a proxy operating in TCP mode to
: transport details of the proxied connection to
: the server.
: Both V1 and V2 versions of the protocol are supported.
Depend: http
XML: etc/jetty-proxy-protocol.xml
Module: quickstart
: Enables the Jetty Quickstart module for rapid
: deployment of preconfigured webapplications.
Depend: server, plus, annotations
LIB: lib/jetty-quickstart-${jetty.version}.jar
Module: rewrite
: Enables the jetty-rewrite handler. Specific rewrite
: rules must be added to either to etc/jetty-rewrite.xml or a custom xml/module
Depend: server
LIB: lib/jetty-rewrite-${jetty.version}.jar
XML: etc/jetty-rewrite.xml
Enabled: ${jetty.base}\start.d\demo.ini
Module: rewrite-compactpath
: Add a rule to the rewrite module to compact paths so that double slashes
: in the path are treated as a single slash.
Depend: rewrite
XML: etc/rewrite-compactpath.xml
Module: rewrite-customizer [rewrite]
: Enables a rewrite Rules container as a request customizer on
: the servers default HttpConfiguration instance
Depend: server
LIB: lib/jetty-rewrite-${jetty.version}.jar
XML: etc/jetty-rewrite-customizer.xml
Module: security
: Adds servlet standard security handling to the classpath.
Depend: server
LIB: lib/jetty-security-${jetty.version}.jar
Enabled: transitive provider of security for webapp
Enabled: transitive provider of security for plus
Module: server
: Enables the core Jetty server on the classpath.
Depend: threadpool
Optional: jvm, ext, resources, logging
LIB: lib/servlet-api-3.1.jar
LIB: lib/jetty-schemas-3.1.jar
LIB: lib/jetty-http-${jetty.version}.jar
LIB: lib/jetty-server-${jetty.version}.jar
LIB: lib/jetty-xml-${jetty.version}.jar
LIB: lib/jetty-util-${jetty.version}.jar
LIB: lib/jetty-io-${jetty.version}.jar
XML: etc/jetty.xml
Enabled: ${jetty.base}\start.d\server.ini
Module: servlet
: Enables standard Servlet handling.
Depend: server
LIB: lib/jetty-servlet-${jetty.version}.jar
Enabled: transitive provider of servlet for webapp
Enabled: transitive provider of servlet for servlets
Enabled: transitive provider of servlet for jsp
Module: servlets
: Puts a collection of jetty utility servlets and filters
: on the server classpath (CGI, CrossOriginFilter, DosFilter,
: MultiPartFilter, PushCacheFilter, QoSFilter, etc.) for
: use by all webapplications.
Depend: servlet
LIB: lib/jetty-servlets-${jetty.version}.jar
Enabled: ${jetty.base}\start.d\servlets.ini
Module: setuid
: Enables the unix setUID configuration so that the server
: may be started as root to open privileged ports/files before
: changing to a restricted user (eg jetty).
Depend: server
LIB: lib/setuid/jetty-setuid-java-1.0.3.jar
XML: etc/jetty-setuid.xml
Module: spring
: Enable spring configuration processing so all jetty style
: xml files can optionally be written as spring beans
Depend: server
LIB: lib/spring/*.jar
Module: stop
: This module causes jetty to stop immediately after starting. This is good for testing configuration and/or precompiling quickstart webapps
XML: etc/jetty-stop.xml
Module: threadpool
: Enables the Server thread pool.
XML: etc/jetty-threadpool.xml
Enabled: ${jetty.base}\start.d\threadpool.ini
Module: transactions
: Puts javax.transaction api on the classpath
LIB: lib/transactions/*.jar
Enabled: transitive provider of transactions for plus
Module: webapp
: Adds support for servlet specification webapplication to the server
: classpath. Without this, only Jetty specific handlers may be deployed.
Depend: servlet, security
LIB: lib/jetty-webapp-${jetty.version}.jar
XML: etc/jetty-webapp.xml
Enabled: transitive provider of webapp for plus
Enabled: transitive provider of webapp for deploy
Module: websocket
: Enable websockets for deployed web applications
Depend: client, annotations
LIB: lib/websocket/*.jar
Enabled: ${jetty.base}\start.d\demo.ini
Modules for tag '3rdparty':
---------------------------
Module: conscrypt [alpn-impl]
: Installs the Conscrypt JSSE provider
Tags: 3rdparty
Depend: ssl
LIB: lib/conscrypt/**.jar
LIB: lib/jetty-alpn-conscrypt-server-${jetty.version}.jar
XML: etc/conscrypt.xml
Module: gcloud
: Control GCloud API classpath
Tags: 3rdparty, gcloud
LIB: lib/gcloud/*.jar
Module: gcloud-datastore
: Enables GCloud Datastore API and implementation
Tags: 3rdparty, gcloud
Depend: gcloud, jcl-slf4j, jul-impl
Module: hawtio
: Deploys the Hawtio console as a webapplication.
Tags: 3rdparty
Depend: stats, deploy, jmx
XML: etc/hawtio.xml
Module: jamon
: Deploys the JAMon webapplication
Tags: 3rdparty
Depend: stats, deploy, jmx, jsp
LIB: lib/jamon/**.jar
XML: etc/jamon.xml
Module: jminix
: Deploys the Jminix JMX Console within the server
Tags: 3rdparty
Depend: stats, jmx, jcl-api, jcl-impl
LIB: lib/jminix/**.jar
XML: etc/jminix.xml
Module: jolokia
: Deploys the Jolokia console as a web application.
Tags: 3rdparty
Depend: stats, deploy, jmx
XML: etc/jolokia.xml
Modules for tag 'classpath':
----------------------------
Module: ext
: Adds all jar files discovered in $JETTY_HOME/lib/ext
: and $JETTY_BASE/lib/ext to the servers classpath.
Tags: classpath
LIB: lib/ext/**.jar
Enabled: ${jetty.base}\start.d\ext.ini
Module: resources
: Adds the $JETTY_HOME/resources and/or $JETTY_BASE/resources
: directory to the server classpath. Useful for configuration
: property files (eg jetty-logging.properties)
Tags: classpath
LIB: resources/
Enabled: ${jetty.base}\start.d\resources.ini
Modules for tag 'connector':
----------------------------
Module: acceptratelimit
: Enable a server wide accept rate limit
Tags: connector
Depend: server
XML: etc/jetty-acceptratelimit.xml
Module: connectionlimit
: Enable a server wide connection limit
Tags: connector
Depend: server
XML: etc/jetty-connectionlimit.xml
Module: http
: Enables a HTTP connector on the server.
: By default HTTP/1 is support, but HTTP2C can
: be added to the connector with the http2c module.
Tags: connector, http
Depend: server
XML: etc/jetty-http.xml
Enabled: ${jetty.base}\start.d\http.ini
Module: http-forwarded
: Adds a forwarded request customizer to the HTTP Connector
: to process forwarded-for style headers from a proxy.
Tags: connector
Depend: http
XML: etc/jetty-http-forwarded.xml
Module: http2
: Enables HTTP2 protocol support on the TLS(SSL) Connector,
: using the ALPN extension to select which protocol to use.
Tags: connector, http2, http, ssl
Depend: ssl, alpn
LIB: lib/http2/*.jar
XML: etc/jetty-http2.xml
Module: http2c
: Enables the HTTP2C protocol on the HTTP Connector
: The connector will accept both HTTP/1 and HTTP/2 connections.
Tags: connector, http2, http
Depend: http
LIB: lib/http2/*.jar
XML: etc/jetty-http2c.xml
Module: https
: Adds HTTPS protocol support to the TLS(SSL) Connector
Tags: connector, https, http, ssl
Depend: ssl
Optional: http-forwarded, http2
XML: etc/jetty-https.xml
Enabled: ${jetty.base}\start.d\https.ini
Module: proxy-protocol-ssl
: Enables the Proxy Protocol on the TLS(SSL) Connector.
: http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
: This allows a Proxy operating in TCP mode to transport
: details of the proxied connection to the server.
: Both V1 and V2 versions of the protocol are supported.
Tags: connector, ssl
Depend: ssl
XML: etc/jetty-proxy-protocol-ssl.xml
Module: ssl
: Enables a TLS(SSL) Connector on the server.
: This may be used for HTTPS and/or HTTP2 by enabling
: the associated support modules.
Tags: connector, ssl
Depend: server
XML: etc/jetty-ssl.xml
XML: etc/jetty-ssl-context.xml
Enabled: transitive provider of ssl for https
Module: unixsocket
: Enables a Unix Domain Socket Connector that can receive
: requests from a local proxy and/or SSL offloader (eg haproxy) in either
: HTTP or TCP mode. Unix Domain Sockets are more efficient than
: localhost TCP/IP connections as they reduce data copies, avoid
: needless fragmentation and have better dispatch behaviours.
: When enabled with corresponding support modules, the connector can
: accept HTTP, HTTPS or HTTP2C traffic.
Tags: connector
Depend: server
LIB: lib/jetty-unixsocket-${jetty.version}.jar
LIB: lib/jnr/*.jar
XML: etc/jetty-unixsocket.xml
Module: unixsocket-forwarded
: Adds a forwarded request customizer to the HTTP configuration used
: by the Unix Domain Socket connector, for use when behind a proxy operating
: in HTTP mode that adds forwarded-for style HTTP headers. Typically this
: is an alternate to the Proxy Protocol used mostly for TCP mode.
Tags: connector
Depend: unixsocket-http
XML: etc/jetty-unixsocket-forwarded.xml
Module: unixsocket-http
: Adds a HTTP protocol support to the Unix Domain Socket connector.
: It should be used when a proxy is forwarding either HTTP or decrypted
: HTTPS traffic to the connector and may be used with the
: unix-socket-http2c modules to upgrade to HTTP/2.
Tags: connector, http
Depend: unixsocket
XML: etc/jetty-unixsocket-http.xml
Module: unixsocket-http2c
: Adds a HTTP2C connetion factory to the Unix Domain Socket Connector
: It can be used when either the proxy forwards direct
: HTTP/2C (unecrypted) or decrypted HTTP/2 traffic.
Tags: connector, http2
Depend: unixsocket-http
LIB: lib/http2/*.jar
XML: etc/jetty-unixsocket-http2c.xml
Module: unixsocket-proxy-protocol
: Enables the proxy protocol on the Unix Domain Socket Connector
: http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
: This allows information about the proxied connection to be
: efficiently forwarded as the connection is accepted.
: Both V1 and V2 versions of the protocol are supported and any
: SSL properties may be interpreted by the unixsocket-secure
: module to indicate secure HTTPS traffic. Typically this
: is an alternate to the forwarded module.
Tags: connector
Depend: unixsocket
XML: etc/jetty-unixsocket-proxy-protocol.xml
Module: unixsocket-secure
: Enable a secure request customizer on the HTTP Configuration
: used by the Unix Domain Socket Connector.
: This looks for a secure scheme transported either by the
: unixsocket-forwarded, unixsocket-proxy-protocol or in a
: HTTP2 request.
Tags: connector
Depend: unixsocket-http
XML: etc/jetty-unixsocket-secure.xml
Modules for tag 'debug':
------------------------
Module: debug
: Enables the DebugListener to generate additional
: logging regarding detailed request handling events.
: Renames threads to include request URI.
Tags: debug
Depend: deploy
XML: etc/jetty-debug.xml
Module: debuglog
: Deprecated Debug Log using the DebugHandle.
: Replaced with the debug module.
Tags: debug
Depend: server
XML: etc/jetty-debuglog.xml
Modules for tag 'handler':
--------------------------
Module: gzip
: Enable GzipHandler for dynamic gzip compression
: for the entire server.
Tags: handler
Depend: server
XML: etc/jetty-gzip.xml
Module: ipaccess
: Enable the ipaccess handler to apply a white/black list
: control of the remote IP of requests.
Tags: handler
Depend: server
XML: etc/jetty-ipaccess.xml
Module: stats
: Enable detailed statistics collection for the server,
: available via JMX.
Tags: handler
Depend: server
XML: etc/jetty-stats.xml
Module: threadlimit
Tags: handler
Depend: server
XML: etc/jetty-threadlimit.xml
Modules for tag 'logging':
--------------------------
Module: console-capture
: Redirects JVMs console stderr and stdout to a log file,
: including output from Jetty's default StdErrLog logging.
Tags: logging
LIB: resources/
XML: etc/console-capture.xml
Module: logging-jetty [logging]
: Configure jetty logging mechanism.
: Provides a ${jetty.base}/resources/jetty-logging.properties.
Tags: logging
Depend: resources
Module: logging-jul [logging]
: Configure jetty logging to use Java Util Logging (jul)
: SLF4J is used as the core logging mechanism.
Tags: logging
Depend: slf4j-jul, jul-impl
JVM: -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
Module: logging-log4j [logging]
: Configure jetty logging to use Log4j Logging
: SLF4J is used as the core logging mechanism.
Tags: logging
Depend: slf4j-log4j, log4j-impl
JVM: -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
Module: logging-log4j2 [logging]
: Configure jetty logging to use log4j version 2
: SLF4J is used as the core logging mechanism.
Tags: logging
Depend: slf4j-log4j2, log4j2-impl
JVM: -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
Module: logging-logback [logging]
: Configure jetty logging to use Logback Logging.
: SLF4J is used as the core logging mechanism.
Tags: logging
Depend: slf4j-logback, logback-impl
JVM: -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
Module: logging-slf4j [logging]
: Configure jetty logging to use slf4j.
: Any slf4j-impl implementation is used
Tags: logging
Depend: slf4j-api, slf4j-impl
JVM: -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
Modules for tag 'requestlog':
-----------------------------
Module: logback-access [requestlog]
: Enables logback request log.
Tags: requestlog, logging, logback
Depend: server, logback-impl, resources
LIB: lib/logback/logback-access-${logback.version}.jar
XML: etc/jetty-logback-access.xml
Module: requestlog
: Enables a NCSA style request log.
Tags: requestlog
Depend: server
XML: etc/jetty-requestlog.xml
Modules for tag 'session':
--------------------------
Module: session-cache-hash [session-cache]
: Enable first level session cache in ConcurrentHashMap.
: If not enabled, sessions will use a HashSessionCache by default, so enabling
: via this module is only needed if the configuration properties need to be
: changed.
Tags: session
Depend: sessions
XML: etc/sessions/session-cache-hash.xml
Module: session-cache-null [session-cache]
: A trivial SessionCache that does not actually cache sessions.
Tags: session
Depend: sessions
XML: etc/sessions/session-cache-null.xml
Module: session-store-cache
: Enables caching of SessionData in front of a SessionDataStore.
Tags: session
Depend: session-store, sessions/session-data-cache/${session-data-cache}
XML: etc/sessions/session-data-cache/session-caching-store.xml
Module: session-store-file [session-store]
: Enables session persistent storage in files.
Tags: session
Depend: sessions
XML: etc/sessions/file/session-store.xml
Module: session-store-gcloud [session-store]
: Enables GCloudDatastore session management.
Tags: session, gcloud
Depend: gcloud-datastore, annotations, webapp, sessions
LIB: lib/jetty-gcloud-session-manager-${jetty.version}.jar
XML: etc/sessions/gcloud/session-store.xml
Module: session-store-hazelcast-embedded [session-store]
: Enables session data store in an embedded Hazelcast Map
Tags: session
Depend: sessions
LIB: lib/jetty-hazelcast-${jetty.version}.jar
LIB: lib/hazelcast/*.jar
XML: etc/sessions/hazelcast/default.xml
Module: session-store-hazelcast-remote [session-store]
: Enables session data store in a remote Hazelcast Map
Tags: session
Depend: sessions
LIB: lib/jetty-hazelcast-${jetty.version}.jar
LIB: lib/hazelcast/*.jar
XML: etc/sessions/hazelcast/remote.xml
Module: session-store-infinispan-embedded [session-store-infnispan-embedded, session-store]
: Enables session data store in a local Infinispan cache
Tags: session
Depend: sessions
LIB: lib/jetty-infinispan-${jetty.version}.jar
LIB: lib/infinispan/*.jar
XML: etc/sessions/infinispan/default.xml
Module: session-store-infinispan-embedded-910 [session-store-infinispan-embedded, session-store]
: Enables session data store in a local Infinispan cache
Tags: session
Depend: sessions
LIB: lib/jetty-infinispan-${jetty.version}.jar
LIB: lib/infinispan/*.jar
XML: etc/sessions/infinispan/default.xml
Module: session-store-infinispan-remote [session-store]
: Enables session data store in a remote Infinispan cache
Tags: session
Depend: sessions
LIB: lib/jetty-infinispan-${jetty.version}.jar
LIB: lib/infinispan/*.jar
XML: etc/sessions/infinispan/remote.xml
Module: session-store-infinispan-remote-910 [session-store-infinispan-remote, session-store]
: Enables session data store in a remote Infinispan cache
Tags: session
Depend: sessions
LIB: lib/jetty-infinispan-${jetty.version}.jar
LIB: lib/infinispan/*.jar
XML: etc/sessions/infinispan/remote.xml
Module: session-store-jdbc [session-store]
: Enables JDBC persistent/distributed session storage.
Tags: session
Depend: sessions, sessions/jdbc/${db-connection-type}
XML: etc/sessions/jdbc/session-store.xml
Module: session-store-mongo [session-store]
: Enables NoSql session management with a MongoDB driver.
Tags: session
Depend: sessions, sessions/mongo/${connection-type}
LIB: lib/jetty-nosql-${jetty.version}.jar
LIB: lib/nosql/*.jar
Module: sessions
: The session management. By enabling this module, it allows
: session management to be configured via the ini templates
: created or by enabling other session-cache or session-store
: modules. Without this module enabled, the server may still
: use sessions, but their management cannot be configured.
Tags: session
Depend: server
XML: etc/sessions/id-manager.xml
Searching Modules
Since the introduction of the module system, many new modules have been added.
As a result, looking at the module list as a whole can be somewhat overwhelming.
To narrow down which modules you would like to choose from, you can search by values listed under the [tags]
section.
Note that when you search this way, all modules that include your criteria in it’s [tags]
section, including internal modules, will be shown.
To filter out internal modules when searching a specific module tag, simply add -internal
to the command line.
For example, if you wanted to look at only the logging modules (excluding the internal implementation modules), you would use --list-modules=logging,-internal
.
[mybase]$ java -jar $JETTY_HOME/start.jar --list-modules=logging,-internal
Available Modules:
==================
tags: [logging, -internal]
Modules for tag 'logging':
--------------------------
Module: console-capture
: Redirects JVMs console stderr and stdout to a log file,
: including output from Jetty's default StdErrLog logging.
Tags: logging
LIB: resources/
XML: etc/console-capture.xml
Module: logging-jcl [logging]
: Configure jetty logging to use Java Commons Logging (jcl)
: SLF4J is used as the core logging mechanism.
Tags: logging
Depend: jcl-impl, slf4j-jcl
JVM: -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
Module: logging-jetty [logging]
: Configure jetty logging mechanism.
: Provides a ${jetty.base}/resources/jetty-logging.properties.
Tags: logging
Depend: console-capture, resources
Module: logging-jul [logging]
: Configure jetty logging to use Java Util Logging (jul)
: SLF4J is used as the core logging mechanism.
Tags: logging
Depend: jul-impl, slf4j-jul
JVM: -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
Module: logging-log4j [logging]
: Configure jetty logging to use Log4j Logging
: SLF4J is used as the core logging mechanism.
Tags: logging
Depend: log4j-impl, slf4j-log4j
JVM: -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
Module: logging-log4j2 [logging]
: Configure jetty logging to use log4j version 2
: SLF4J is used as the core logging mechanism.
Tags: logging
Depend: slf4j-log4j2, log4j2-impl
JVM: -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
Module: logging-logback [logging]
: Configure jetty logging to use Logback Logging.
: SLF4J is used as the core logging mechanism.
Tags: logging
Depend: logback-impl, slf4j-logback
JVM: -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
Module: logging-slf4j [logging]
: Configure jetty logging to use slf4j.
: Any slf4j-impl implementation is used
Tags: logging
Depend: slf4j-api, slf4j-impl
JVM: -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
Modules for tag 'requestlog':
-----------------------------
Module: logback-access [requestlog]
: Enables logback request log.
Tags: requestlog, logging, logback
Depend: server, logback-core, resources
LIB: lib/logback/logback-access-${logback.version}.jar
XML: etc/jetty-logback-access.xml
Custom Modules
In addition to the modules that come packaged with the Jetty distribution, users are able to create and define their own custom modules for use with their Jetty implementation. Custom modules can be used for a number of reasons - they can extend features in Jetty, add new features, manage additional libraries available to the server…etc.
At the heart of a Jetty module is the {name}.mod
file itself.
A jetty .mod
file defines the following:
It is important to note that when creating your own module, none of these sections are required - simply use those which are applicable to your implementation. |
- Module Description -
[description]
-
The description of the module. This will be showing when viewing the
.mod
file itself or using the--list-modules
command. - List of Dependent Modules -
[depend]
-
All modules can declare that they depend on other modules with the
[depend]
section. The list of dependencies is used to transitively resolve other modules that are deemed to be required based on the modules that you activate. The order of modules defined in the graph of active modules is used to determine various execution order for configuration, such as Jetty IoC XML configurations, and to resolve conflicting property declarations.- Optional Modules -
[optional]
-
Of note: there is a special section
[optional]
used to describe structurally dependent modules that are not technically required, but might be of use to your specific configuration.
- Optional Modules -
- List of Libraries -
[lib]
-
Modules can optionally declare that they have libraries that they need to function properly. The
[lib]
section declares a set of pathnames that follow the Jetty Base and Jetty Home path resolution rules. - List of Jetty IoC XML Configurations -
[xml]
-
A Module can optionally declare a list of Jetty IoC XML configurations used to wire up the functionality that this module defines. The
[xml]
section declares a set of pathnames that follow the Jetty Base and Jetty Home path resolution rules. Ideally, all XML files are parameterized to accept properties to configure the various elements of the standard configuration. Allowing for a simplified configuration of Jetty for the vast majority of deployments. The execution order of the Jetty IoC XML configurations is determined by the graph of active module dependencies resolved via the[depend]
sections. If the default XML is not sufficient to satisfy your needs, you can override this XML by making your own in the${jetty.base}/etc/
directory, with the same name. The resolution steps for Jetty Base and Jetty Home will ensure that your copy from${jetty.base}
will be picked up over the default one in${jetty.home}
. - List of Module Tags -
[tags]
-
For ease of sorting, modules can be assigned tags. When using the
--list-modules
command, modules will be groups by the first tag that exists in this section. Modules can also be listed specifically by these tags using--list-modules=<tag name>
on the command line. - Ini Variables -
[ini]
-
The
[ini]
section is used to add or change server parameters at startup. The[ini]
section can also include a the path of a file or several files which should be made available to the server only. This is helpful when you want to control what jars are available to deployed webapps. - Jetty INI Template -
[ini-template]
-
Each module can optionally declare a startup ini template that is used to insert/append/inject sample configuration elements into the
start.ini
orstart.d/*.ini
files when using the--add-to-start=<name>
command line argument instart.jar
. Commonly used to present some of the parameterized property options from the Jetty IoC XML configuration files also referenced in the same module. - Required Files and Directories -
[files]
-
If the activation of a module requires some paths to exist, the
[files]
section defines them. There are 2 modes of operation of the entries in this section.- Ensure Directory Exists
-
If you add a pathname that ends in
"/"
(slash), such as"webapps/"
, then that directory will be created if it does not yet exist in${jetty.base}/<pathname>
(eg:"webapps/"
will result in${jetty.base}/webapps/
being created). - Download File
-
There is a special syntax to allow you to download a file into a specific location if it doesn’t exist yet:
<url>:<pathname>
. Currently, the<url>
must be ahttp://
scheme URL (please let us know if you need more schemes supported). The<pathname>
portion follows the Jetty Base and Jetty Home path resolution rules. Example:http://repo.corp.com/maven/corp-security-policy-1.0.jar:lib/corp-security-policy.jar
This will check for the existence oflib/corp-security-policy.jar
, and if it doesn’t exist, it will download the jar file fromhttp://repo.corp.com/maven/corp-security-policy-1.0.jar
- Licenses -
[license]
-
If you are implementing a software/technology that has a license, it’s text can be placed here. When a user attempts to activate the module they will be asked if they accept the license agreement. If a user does not accept the license agreement, the module will not be activated.
- Additional Startup Commands -
[exec]
-
The
[exec]
section is used to define additional parameters specific to the module. These commands are added to the server startup. - JPMS Module-Path Definitions -
[jpms]
-
The
[jpms]
section is used to add JPMS modules to the module-path for startup when using the--jpms
command.
Module Properties
Properties are used to parameterize:
-
XML files using the
<Property name="pname"/>
element -
Module files using the
${pname}
syntax
Properties and System Properties may be set on the command line, in a ini file or in a [ini]
section of a module using the following syntax.
name=value
-
Set a property that can be expanded in XML files with the <Property> element.
name+=value
-
Append value to an existing property value.
name+=,value
-
Append value to an existing property value, using a comma separator if needed.
name?=value
-
Set a property only if it is not already set.
If any of the previous formats is preceded by -D
, then a system property is set as well as a start property.
Location of Modules
Jetty comes with dozens of modules as part of the distribution package.
By default these are located in the ${JETTY_HOME}/modules
directory.
These modules should not be modified.
In the unlikely circumstance you need to make changes to a stock module, copy it to your ${JETTY_BASE}
in a modules
directory.
Custom modules should also be maintained separately as part of the ${JETTY_BASE}/modules
directory, though you can optionally place them in ${JETTY_HOME}/modules
for convenience if you have several {$JETTY_BASE}
locations in your implementation.
Creating Custom Modules
As shown above, there are several options that can be utilized when creating custom module files. This may seem daunting, but the good news is that creating custom modules is actually quite easy.
For example, here is a look at the http.mod
file which defines parameters for enabling HTTP features for the server:
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
Enables an HTTP connector on the server.
By default HTTP/1 is support, but HTTP2C can
be added to the connector with the http2c module.
[tags]
connector
http
[depend]
server
[xml]
etc/jetty-http.xml
[ini-template]
### HTTP Connector Configuration
## Connector host/address to bind to
# jetty.http.host=0.0.0.0
## Connector port to listen on
# jetty.http.port=8080
## Connector idle timeout in milliseconds
# jetty.http.idleTimeout=30000
## Number of acceptors (-1 picks default based on number of cores)
# jetty.http.acceptors=-1
## Number of selectors (-1 picks default based on number of cores)
# jetty.http.selectors=-1
## ServerSocketChannel backlog (0 picks platform default)
# jetty.http.acceptQueueSize=0
## Thread priority delta to give to acceptor threads
# jetty.http.acceptorPriorityDelta=0
## The requested maximum length of the queue of incoming connections.
# jetty.http.acceptQueueSize=0
## Enable/disable the SO_REUSEADDR socket option.
# jetty.http.reuseAddress=true
## Enable/disable TCP_NODELAY on accepted sockets.
# jetty.http.acceptedTcpNoDelay=true
## The SO_RCVBUF option to set on accepted sockets. A value of -1 indicates that it is left to its default value.
# jetty.http.acceptedReceiveBufferSize=-1
## The SO_SNDBUF option to set on accepted sockets. A value of -1 indicates that it is left to its default value.
# jetty.http.acceptedSendBufferSize=-1
## Connect Timeout in milliseconds
# jetty.http.connectTimeout=15000
## HTTP Compliance: RFC7230, RFC7230_LEGACY, RFC2616, RFC2616_LEGACY, LEGACY or CUSTOMn
# jetty.http.compliance=RFC7230_LEGACY
You’ll notice that the http.mod
file only includes a handful of the possible sections available - [description]
, [tags]
, [depend]
, [xml]
, and [ini-template]
.
When configuring your own modules, you are free to pick and choose what you include.
As an example, below is a module file that defines a custom XML and lib, and activates a number of additional modules. A module like this could be used to enable a set of standard modules and resources for a new JETTY_BASE without having to define them all manually.
[description]
Enables the standard set of modules and resources for ACME Corp servers.
[tags]
core
[depend]
server
client
http
http2
jsp
console-capture
requestlog
stats
gzip
deploy
jmx
[files]
basehome:modules/acme/acme.xml|etc/acme.xml
[lib]
lib/acme/ACMECustom.jar
Activating this module will activate all the dependent modules, create any required directories and copy in any required files:
java -jar ../start.jar --add-to-start=acme
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: alpn-impl/alpn-8
+ ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
+ ALPN replaces/modifies OpenJDK classes in the sun.security.ssl package.
+ http://github.com/jetty-project/jetty-alpn
+ http://openjdk.java.net/legal/gplv2+ce.html
Proceed (y/N)? y
INFO : webapp transitively enabled, ini template available with --add-to-start=webapp
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : requestlog transitively enabled, ini template available with --add-to-start=requestlog
INFO : alpn transitively enabled, ini template available with --add-to-start=alpn
INFO : jsp transitively enabled
INFO : servlet transitively enabled
INFO : alpn-impl/alpn-8 dynamic dependency of alpn
INFO : annotations transitively enabled
INFO : gzip transitively enabled, ini template available with --add-to-start=gzip
INFO : ssl transitively enabled, ini template available with --add-to-start=ssl
INFO : plus transitively enabled
INFO : deploy transitively enabled, ini template available with --add-to-start=deploy
INFO : alpn-impl/alpn-1.8.0_92 dynamic dependency of alpn-impl/alpn-8
INFO : security transitively enabled
INFO : jmx transitively enabled
INFO : apache-jsp transitively enabled
INFO : stats transitively enabled, ini template available with --add-to-start=stats
INFO : acme initialized in ${jetty.base}/start.d/acme.ini
INFO : jndi transitively enabled
INFO : console-capture transitively enabled, ini template available with --add-to-start=console-capture
INFO : client transitively enabled
INFO : http transitively enabled, ini template available with --add-to-start=http
INFO : http2 transitively enabled, ini template available with --add-to-start=http2
MKDIR : ${jetty.base}/logs
MKDIR : ${jetty.base}/lib
MKDIR : ${jetty.base}/lib/alpn
MKDIR : ${jetty.base}/etc
COPY : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
MKDIR : ${jetty.base}/webapps
DOWNLD: https://repo1.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.8.v20160420/alpn-boot-8.1.8.v20160420.jar to ${jetty.base}/lib/alpn/alpn-boot-8.1.8.v20160420.jar
COPY : ${jetty.home}/modules/acme/acme.xml to ${jetty.base}/etc/acme.xml
INFO : Base directory was modified
Dependencies
When dependent modules are enabled, they are done so transitively by default.
This means that any ini
files for dependent modules are not created in the ${JETTY_BASE}/start.d
directory (or added to ${JETTY_BASE}/start.ini
) and are as such not configurable.
For Jetty to create/add the ini-template
parameters to start.d
or start.ini
the associated module must be enabled explicitly.
For example, if I activate the http
module, it will be enabled, and the server
module will be enabled transitively:
$ java -jar ../start.jar --add-to-start=http
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : http initialized in ${jetty.base}/start.d/http.ini
INFO : Base directory was modified
You’ll notice that Jetty informs you of what modules were enabled, and where there associated ini files are located (when applicable).
It also tells the user what command they would need to run to enable any missing or desired ini files for the selected modules, in this case --add-to-start=server
.
$ java -jar ../start.jar --add-to-start=server
INFO : server initialized in ${jetty.base}/start.d/server.ini
INFO : Base directory was modified
It is important to keep in mind that when activating a dependency, Jetty does not just go one layer down. If a dependent module also has dependencies they too will be enabled. |
Managing XML Based Startup Configuration
When you see XML files on the command line for startup of Jetty, they are always part of the Jetty IoC Configuration mechanism.
Internally, Jetty uses these XML files to build up Jetty with the features that you wan to use.
The module mechanism present in Jetty determines the load order of the XML files.
The Jetty Base and Jetty Home resolution logic also applies, which allows you to override a XML file declared by a module with your XML by simply having the same named XML in your ${jetty.base}/etc
directory location.
Startup a Unix Service using jetty.sh
The standalone Jetty distribution ships with a bin/jetty.sh
script that can be used by various Unix distros (including OSX) to manage Jetty as a startup service.
This script is suitable for setting up Jetty as a service in Unix.
Quick-Start a Jetty Service
The minimum steps to get Jetty to run as a Service include:
[/opt/jetty]# tar -zxf /home/user/downloads/jetty-distribution-{VERSION}.tar.gz
[/opt/jetty]# cd jetty-distribution-{VERSION}/
[/opt/jetty/jetty-distribution-{VERSION}]# ls
bin lib modules resources start.jar
demo-base license-eplv10-aslv20.html notice.html start.d VERSION.txt
etc logs README.TXT start.ini webapps
[/opt/jetty/jetty-distribution-{VERSION}]# cp bin/jetty.sh /etc/init.d/jetty
[/opt/jetty/jetty-distribution-{VERSION}]# echo JETTY_HOME=`pwd` > /etc/default/jetty
[/opt/jetty/jetty-distribution-{VERSION}]# cat /etc/default/jetty
JETTY_HOME=/opt/jetty/jetty-distribution-{VERSION}
[/opt/jetty/jetty-distribution-{VERSION}]# service jetty start
Starting Jetty: OK Wed Nov 20 10:26:53 MST 2013
From this demonstration we can see that Jetty started successfully as a Unix Service from the /opt/jetty/jetty-distribution-9.4.53.v20231009
directory.
This configuration works well but it is running Jetty as the root user.
Practical Setup of a Jetty Service
There are various ways this can be accomplished, mostly depending on your Unix environment (and possibly corporate policies).
The techniques outlined here assume an installation on Linux (demonstrated on Ubuntu 12.04.3 LTS).
Prepare some empty directories to work with.
# mkdir -p /opt/jetty
# mkdir -p /opt/web/mybase
# mkdir -p /opt/jetty/temp
The directory purposes are as follows:
- /opt/jetty
-
Where the Jetty Distribution will be unpacked into
- /opt/web/mybase
-
Where your specific set of webapps will be located, including all of the configuration required of the server to make them operational.
- /opt/jetty/temp
-
This is the temporary directory assigned to Java by the Service Layer (this is what Java sees as the
java.io.tmpdir
System Property).This is intentionally kept separate from the standard temp directory of
/tmp
, as this location doubles as the Servlet Spec work directory. It is our experience that the standard temp directory is often managed by various cleanup scripts that wreak havoc on a long running Jetty server.
Jetty 9.3 requires Java 8 (or greater) to run. Make sure you have it installed.
# apt-get install openjdk-8-jdk
Or download Java 8 from: http://www.oracle.com/technetwork/java/javase/downloads/index.html
# java -version
java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1ubuntu0.12.04.2)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)
# update-alternatives --list java
/usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java
/usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java
# update-alternatives --config java
There are 2 choices for the alternative java (providing /usr/bin/java).
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java 1061 auto mode
1 /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java 1061 manual mode
2 /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java 1051 manual mode
Press enter to keep the current choice[*], or type selection number: 2
update-alternatives: using /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java to provide /usr/bin/java (java) in manual mode.
# java -version
java version "1.7.0_25"
OpenJDK Runtime Environment (IcedTea 2.3.10) (7u25-2.3.10-1ubuntu0.12.04.2)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)
It is recommended that you create a user to specifically run Jetty. This user should have the minimum set of privileges needed to run Jetty.
# useradd --user-group --shell /bin/false --home-dir /opt/jetty/temp jetty
This will create a user called jetty
, belonging to the group called jetty
, with no shell access (aka /bin/false
), and home directory at /opt/jetty/temp
.
Download a copy of the Jetty distribution from the Official Eclipse Download Site
Unpack it into place.
[/opt/jetty]# tar -zxf /home/user/Downloads/jetty-distribution-{VERSION}.tar.gz
[/opt/jetty]# ls -F
jetty-distribution-{VERSION}/
[/opt/jetty]# mkdir /opt/jetty/temp
It might seem strange or undesirable to unpack the first portion of the jetty-distribution directory name too.
But starting with Jetty 9 the split between ${jetty.home}
and ${jetty.base}
allows for easier upgrades of Jetty itself while isolating your webapp specific configuration.
For more information on the Jetty home and base concepts see the section on managing a Jetty installation earlier in this Chapter.
The /opt/jetty/temp
directory is created as a durable place for Jetty to use for temp and working directories.
Many Unix systems will periodically clean out the /tmp directory, this behavior is undesired in a Servlet container and has been known to cause problems.
This durable directory at /opt/jetty/temp
solves for that behavior.
The directory at /opt/web/mybase
is going to be a ${jetty.base}
, so lets configure it to hold your webapp and its configuration.
In past versions of Jetty, you would configure / modify / add to the |
# cd /opt/web/mybase/
[/opt/web/mybase]# ls
[/opt/web/mybase]# java -jar /opt/jetty/jetty-distribution-{VERSION}/start.jar \
--add-to-start=deploy,http,console-capture
INFO : webapp transitively enabled, ini template available with --add-to-start=webapp
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : security transitively enabled
INFO : servlet transitively enabled
INFO : console-capture initialized in ${jetty.base}/start.ini
INFO : http initialized in ${jetty.base}/start.ini
INFO : deploy initialized in ${jetty.base}/start.ini
MKDIR : ${jetty.base}/logs
MKDIR : ${jetty.base}/webapps
INFO : Base directory was modified
[/opt/web/mybase]# ls -F
start.ini webapps/
At this point you have configured your /opt/web/mybase
to enable the following modules:
- deploy
-
This is the module that will perform deployment of web applications (WAR files or exploded directories), or Jetty IoC XML context deployables, from the
/opt/web/mybase/webapps
directory. - http
-
This sets up a single Connector that listens for basic HTTP requests.
See the created
start.ini
for configuring this connector. - console-capture
-
When running Jetty as a service it is very important to have logging enabled. This module will enable the basic STDOUT and STDERR capture logging to the
/opt/web/mybase/logs/
directory.
Additionally, the webapp
, server
, security
and servlet
modules were enabled as they are dependencies for other modules.
See Using start.jar for more details and options on setting up and configuring a ${jetty.base}
directory.
Copy your war file into place.
# cp /home/user/projects/mywebsite.war /opt/web/mybase/webapps/
Most service installations will want Jetty to run on port 80, now is the opportunity to change this from the default value of 8080
to 80
.
Edit the /opt/web/mybase/start.ini
and change the jetty.http.port
value.
# grep jetty.http.port /opt/web/mybase/start.ini
jetty.port=80
Change the permissions on the Jetty distribution and webapp directories so that the user you created can access it.
# chown --recursive jetty /opt/jetty
# chown --recursive jetty /opt/web/mybase
Next we need to make the Unix System aware that we have a new Jetty Service that can be managed by the standard service
calls.
# cp /opt/jetty/jetty-distribution-{VERSION}/bin/jetty.sh /etc/init.d/jetty
# echo "JETTY_HOME=/opt/jetty/jetty-distribution-{VERSION}" > /etc/default/jetty
# echo "JETTY_BASE=/opt/web/mybase" >> /etc/default/jetty
# echo "JETTY_USER=jetty" >> /etc/default/jetty
# echo "TMPDIR=/opt/jetty/temp" >> /etc/default/jetty
Test out the configuration:
# service jetty status
Checking arguments to Jetty:
START_INI = /opt/web/mybase/start.ini
JETTY_HOME = /opt/jetty/jetty-distribution-{VERSION}
JETTY_BASE = /opt/web/mybase
JETTY_CONF = /opt/jetty/jetty-distribution-{VERSION}/etc/jetty.conf
JETTY_PID = /var/run/jetty.pid
JETTY_START = /opt/jetty/jetty-distribution-{VERSION}/start.jar
CLASSPATH =
JAVA = /usr/bin/java
JAVA_OPTIONS = -Djetty.state=/opt/web/mybase/jetty.state
-Djetty.logs=/opt/web/mybase/logs
-Djetty.home=/opt/jetty/jetty-distribution-{VERSION}
-Djetty.base=/opt/web/mybase
-Djava.io.tmpdir=/opt/jetty/temp
JETTY_ARGS = console-capture.xml jetty-started.xml
RUN_CMD = /usr/bin/java
-Djetty.state=/opt/web/mybase/jetty.state
-Djetty.logs=/opt/web/mybase/logs
-Djetty.home=/opt/jetty/jetty-distribution-{VERSION}
-Djetty.base=/opt/web/mybase
-Djava.io.tmpdir=/opt/jetty/temp
-jar /opt/jetty/jetty-distribution-{VERSION}/start.jar
console-capture.xml
jetty-started.xml
You now have a configured ${jetty.base}
in /opt/web/mybase
and a ${jetty.home}
in /opt/jetty/jetty-distribution-9.4.53.v20231009
, along with the service level files necessary to start the service.
Test the service to make sure it starts up and runs successfully.
# service jetty start
Starting Jetty: OK Wed Nov 20 12:35:28 MST 2013
# service jetty check
..(snip)..
Jetty running pid=2958
[/opt/web/mybase]# ps u 2958
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
jetty 2958 5.3 0.1 11179176 53984 ? Sl 12:46 0:00 /usr/bin/java -Djetty...
You should now have your server running.
Startup via Windows Service
There are no components that ship with the Jetty Distribution to make it a formal Windows Service.
However, we recommend the use of Apache ProcRun’s Daemon.
The techniques outlined here are based on Windows 7 (64-bit), using JDK 8 (64-bit), running on an Intel i7 architecture machine.
Prepare some empty directories to work with.
C:\> mkdir opt
C:\> cd opt
C:\opt> mkdir jetty
C:\opt> mkdir logs
C:\opt> mkdir myappbase
C:\opt> mkdir temp
C:\opt> dir
Volume in drive C has no label.
Volume Serial Number is DEAD-BEEF
Directory of C:\opt
11/21/2013 04:06 PM <DIR> .
11/21/2013 04:06 PM <DIR> ..
11/21/2013 04:06 PM <DIR> jetty
11/21/2013 04:06 PM <DIR> logs
11/21/2013 04:06 PM <DIR> myappbase
11/21/2013 04:06 PM <DIR> temp
0 File(s) 0 bytes
The directory purposes are as follows:
- C:\opt
-
Where the service layer utilities, scripts, and binaries will eventually be.
- C:\opt\logs
-
Where the logs for the service layer will put its own logs.
Typically you will see the audit logs (install/update/delete), StdOutput, and StdError logs here.
- C:\opt\jetty
-
Where the Jetty Distribution will be unpacked into.
- C:\opt\myappbase
-
Where your specific set of webapps will be located, including all of the configuration required of the server to make them operational.
- C:\opt\temp
-
This is the temporary directory assigned to Java by the Service Layer (this is what Java sees as the
java.io.tmpdir
System Property).This is intentionally kept separate from the standard temp directories of Windows, as this location doubles as the Servlet Spec work directory.
Or download Java 8 from: http://www.oracle.com/technetwork/java/javase/downloads/index.html
C:\opt>java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
Download a copy of the ZIP distribution from the Official Eclipse Download Site
Extract the contents of the jetty-distribution-9.4.53.v20231009
directory to C:\opt\jetty
Once complete, the contents of the C:\opt\jetty
directory should look like this:
C:\opt\jetty>dir
Volume in drive C has no label.
Volume Serial Number is C8CF-820B
Directory of C:\opt\jetty
11/21/2013 12:13 PM <DIR> .
11/21/2013 12:13 PM <DIR> ..
11/21/2013 12:13 PM <DIR> bin
11/21/2013 12:13 PM <DIR> demo-base
11/21/2013 12:13 PM <DIR> etc
11/21/2013 12:13 PM <DIR> lib
11/21/2013 12:13 PM 30,012 license-eplv10-aslv20.html
11/21/2013 12:13 PM <DIR> logs
11/21/2013 12:13 PM <DIR> modules
11/21/2013 12:13 PM 6,262 notice.html
11/21/2013 12:13 PM 1,249 README.TXT
11/21/2013 12:13 PM <DIR> resources
11/21/2013 12:13 PM <DIR> start.d
11/21/2013 12:13 PM 2,126 start.ini
11/21/2013 12:13 PM 72,226 start.jar
11/21/2013 12:13 PM 341,784 VERSION.txt
11/21/2013 12:13 PM <DIR> webapps
6 File(s) 453,659 bytes
11 Dir(s) 306,711,420,928 bytes free
Download a copy of the Apache ProcRun native binaries.
You should have downloaded a file named commons-daemon-1.0.15-bin-windows.zip
(the version might be different).
Open the ZIP file and extract the prunmgr.exe
and prunsrv.exe
files into the C:\opt
directory.
Make sure to get the right version of prunsrv.exe
for your environment.
The ZIP file has both 32 bit and 64 bit versions of this file.
Once you are complete, the contents of C:\opt
directory should look like this:
C:\opt> dir
Volume in drive C has no label.
Volume Serial Number is DEAD-BEEF
Directory of C:\opt
11/21/2013 04:06 PM <DIR> .
11/21/2013 04:06 PM <DIR> ..
11/21/2013 04:06 PM <DIR> jetty
11/21/2013 04:06 PM <DIR> logs
11/21/2013 04:06 PM <DIR> myappbase
11/21/2013 04:06 PM <DIR> temp
11/21/2013 04:11 PM 104,448 prunmgr.exe
11/21/2013 04:11 PM 80,896 prunsrv.exe
2 File(s) 185,344 bytes
Now it’s time to setup your new ${jetty.base}
directory to have all of your WebApps and the configurations that they need.
We’ll start by specifying which modules we want to use (this will create a start.ini file and also create a few empty directories for you)
C:\opt\myappbase>java -jar ..\jetty\start.jar --add-to-start=deploy,http,console-capture
WARNING: deploy initialised in ${jetty.base}\start.ini (appended)
WARNING: deploy enabled in ${jetty.base}\start.ini
MKDIR: ${jetty.base}\webapps
WARNING: server initialised in ${jetty.base}\start.ini (appended)
WARNING: server enabled in ${jetty.base}\start.ini
WARNING: http initialised in ${jetty.base}\start.ini (appended)
WARNING: http enabled in ${jetty.base}\start.ini
WARNING: server enabled in ${jetty.base}\start.ini
WARNING: logging initialised in ${jetty.base}\start.ini (appended)
WARNING: logging enabled in ${jetty.base}\start.ini
MKDIR: ${jetty.base}\logs
C:\opt\myappbase>dir
Volume in drive C has no label.
Volume Serial Number is C8CF-820B
Directory of C:\opt\myappbase
11/21/2013 12:49 PM <DIR> .
11/21/2013 12:49 PM <DIR> ..
11/21/2013 12:49 PM <DIR> logs
11/21/2013 12:49 PM 1,355 start.ini
11/21/2013 12:49 PM <DIR> webapps
1 File(s) 1,355 bytes
4 Dir(s) 306,711,064,576 bytes free
At this point you have configured your C:\opt\myappbase
to enable the following modules:
- deploy
-
This is the module that will perform deployment of web applications (WAR files or exploded directories), or Jetty IoC XML context deployables, from the
C:\opt\myappbase\webapps
directory. - http
-
This sets up a single Connector that listens for basic HTTP requests.
See the created
start.ini
for configuring this connector. - logging
-
When running Jetty as a service it is very important to have logging enabled. This module will enable the basic STDOUT and STDERR capture logging to the
C:\opt\myappbase\logs
directory.
See the section on Using start.jar for more details and options on setting up and configuring a ${jetty.base}
directory.
At this point you merely have to copy your WAR files into the {$jetty.base}/webapps
directory.
C:\opt\myappbase> copy C:\projects\mywebsite.war webapps\
At this point you should have your directories, Java, the Jetty distribution, and your webapp specifics setup and ready for operation.
We will use the Apache ProcRun’s prunsrv.exe to install a Jetty Service.
The basic command line syntax is outlined in the link above.
A example install-jetty-service.bat
is provided here as an example, based on the above directories.
@echo off
set SERVICE_NAME=JettyService
set JETTY_HOME=C:\opt\jetty
set JETTY_BASE=C:\opt\myappbase
set STOPKEY=secret
set STOPPORT=50001
set PR_INSTALL=C:\opt\prunsrv.exe
@REM Service Log Configuration
set PR_LOGPREFIX=%SERVICE_NAME%
set PR_LOGPATH=C:\opt\logs
set PR_STDOUTPUT=auto
set PR_STDERROR=auto
set PR_LOGLEVEL=Debug
@REM Path to Java Installation
set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_45
set PR_JVM=%JAVA_HOME%\jre\bin\server\jvm.dll
set PR_CLASSPATH=%JETTY_HOME%\start.jar;%JAVA_HOME%\lib\tools.jar
@REM JVM Configuration
set PR_JVMMS=128
set PR_JVMMX=512
set PR_JVMSS=4000
set PR_JVMOPTIONS=-Duser.dir="%JETTY_BASE%";-Djava.io.tmpdir="C:\opt\temp";-Djetty.home="%JETTY_HOME%";-Djetty.base="%JETTY_BASE%"
@REM Startup Configuration
set JETTY_START_CLASS=org.eclipse.jetty.start.Main
set PR_STARTUP=auto
set PR_STARTMODE=java
set PR_STARTCLASS=%JETTY_START_CLASS%
set PR_STARTPARAMS=STOP.KEY="%STOPKEY%";STOP.PORT=%STOPPORT%
@REM Shutdown Configuration
set PR_STOPMODE=java
set PR_STOPCLASS=%JETTY_START_CLASS%
set PR_STOPPARAMS=--stop;STOP.KEY="%STOPKEY%";STOP.PORT=%STOPPORT%;STOP.WAIT=10
"%PR_INSTALL%" //IS/%SERVICE_NAME% ^
--DisplayName="%SERVICE_NAME%" ^
--Install="%PR_INSTALL%" ^
--Startup="%PR_STARTUP%" ^
--LogPath="%PR_LOGPATH%" ^
--LogPrefix="%PR_LOGPREFIX%" ^
--LogLevel="%PR_LOGLEVEL%" ^
--StdOutput="%PR_STDOUTPUT%" ^
--StdError="%PR_STDERROR%" ^
--JavaHome="%JAVA_HOME%" ^
--Jvm="%PR_JVM%" ^
--JvmMs="%PR_JVMMS%" ^
--JvmMx="%PR_JVMMX%" ^
--JvmSs="%PR_JVMSS%" ^
--JvmOptions=%PR_JVMOPTIONS% ^
--Classpath="%PR_CLASSPATH%" ^
--StartMode="%PR_STARTMODE%" ^
--StartClass="%JETTY_START_CLASS%" ^
--StartParams="%PR_STARTPARAMS%" ^
--StopMode="%PR_STOPMODE%" ^
--StopClass="%PR_STOPCLASS%" ^
--StopParams="%PR_STOPPARAMS%"
if not errorlevel 1 goto installed
echo Failed to install "%SERVICE_NAME%" service. Refer to log in %PR_LOGPATH%
goto end
:installed
echo The Service "%SERVICE_NAME%" has been installed
:end
Configuration’s of note in this batch file:
- SERVICE_NAME
-
This is the name of the service that Windows sees. The name in the Services window will show this name.
- STOPKEY
-
This is the secret key (password) for the ShutdownMonitor, used to issue a formal command to stop the server.
- STOPPORT
-
The port that the Shutdown Monitor listens on for the stop command.
If you have multiple Jetty servers on the same machine, this port will need to be different for each Service.
Once you have run prunsrv.exe //IS/<service-name>
(done for you in the above batch file) to install the service, you can use the standard Windows utilities to manage (start/stop/restart) the Jetty service.
Open the Service View and start your service.
Startup using the Java Platform Module System (JPMS)
Jetty modules also act as automatic JPMS modules via the Automatic-Module-Name
attribute in the jar’s MANIFEST.MF
file.
This makes possible to run Jetty from the module-path, rather than the class-path.
We recommend using JDK 11 or greater due to the fact that JDK 11 removed all the "enterprise" modules from the JDK, and therefore it guarantees a more stable platform to base your application’s dependencies on. The classes in these "enterprise" modules were bundled with JDK 8, and present in "enterprise" modules in JDK 9 and JDK 10. With JDK 11, these "enterprise" classes are either not available in the JDK (because their corresponding module was removed), or they are present in a different module.
Because some of these "enterprise" classes are required by Jetty or by applications running in Jetty, it is better to use a stable source for those classes - in this case by using JDK 11 or greater, and explicitly referencing the "enterprise" classes as dependencies, rather than assuming they are bundled with the JDK.
Starting Jetty on the module-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:
$ mkdir my-jetty-base
$ cd my-jetty-base
$ java -jar $JETTY_HOME/start.jar --add-to-start=http
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : http initialized in ${jetty.base}/start.ini
INFO : threadpool transitively enabled, ini template available with --add-to-start=threadpool
INFO : Base directory was modified
$ java -jar $JETTY_HOME/start.jar --jpms
The example above creates a Jetty base directory and enables the http
module using the --add-to-start
command.
The server then starts Jetty on the module-path using the --jpms
option.
[NOTE] 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. You will have two JVMs running: one that runs `start.jar` and one that runs Jetty on the module-path.
If you are interested in the details of how the command line to run Jetty on the module-path looks like, you can add the --dry-run
option:
$ java -jar $JETTY_HOME/start.jar --jpms --dry-run
This will give an output looking something like this (broken in sections for clarity):
/opt/openjdk-11+28/bin/java
--module-path /opt/jetty/lib/servlet-api-3.1.jar:/opt/jetty/lib/jetty-schemas-3.1.jar:/opt/jetty/lib/jetty-http-9.4.13-SNAPSHOT.jar:...
--patch-module servlet.api=/opt/jetty/lib/jetty-schemas-3.1.jar
--module org.eclipse.jetty.xml/org.eclipse.jetty.xml.XmlConfiguration /opt/jetty/etc/jetty-threadpool.xml /opt/jetty/etc/jetty.xml ...
The --module-path
option specifies the list of Jetty jars.
This list depends on the Jetty modules that have been enabled via the --add-to-start
command.
The --patch-module
option is necessary for Servlet and JSP Containers to find XML DTDs and XML Schemas required to validate the various XML files present in web applications (such as web.xml
and others).
The --module
option tells the JVM to run main class XmlConfiguration
from the org.eclipse.jetty.xml
module, with the given XML files as program arguments.
When the JVM starts, module org.eclipse.jetty.xml
is added to the set of JPMS root modules; all other Jetty modules, being automatic, will be resolved and added to the module graph.
JAR files that are not modules, such as servlet-api-3.1.jar
, are on the module-path and therefore will be made automatic modules by the JVM (hence the derived module name servlet.api
for this jar, referenced by the --patch-module
command line option above).
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
(such as com.zaxxer.hikari.HikariDataSource
) or a reference directly to the JDBC driver’s DataSource
(com.mysql.jdbc.jdbc2.optional.MysqlDataSource
).
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 custom module:
[description]
MySQL module
[lib]
lib/mysql/mysql-connector-java-*.jar
However, when running on the module-path, things are quite different.
Class javax.sql.DataSource
is in a JDK bundled module named java.sql
, which is not automatic (it’s a proper JPMS module) and it is not in the root modules set.
Because it is not an automatic module, it is not added to the module graph, and therefore needs to be added explicitly using the JVM command line --add-modules
.
To add the JPMS module java.sql
to the module graph, you need to modify your custom module in the following way, using our mysql.mod
as an example:
[description]
MySQL module
[lib]
lib/mysql/mysql-connector-java-*.jar
[jpms]
add-modules: java.sql
The new [jpms]
section is only used when Jetty is started on the module-path via the --jpms
command line option.
Assuming that mysql-connector-java-.jar
is a non JPMS modular jar, or an automatic JPMS modular jar, the Jetty start mechanism will add mysql-connector-java-.jar
to the module-path, and will add the JVM command line option --add-modules java.sql
.
If mysql-connector-java-*.jar
were a proper JPMS modular jar with name (for example) com.mysql.jdbc
, then it would need to be explicitly added to the module graph, in this way:
[description]
MySQL module
[lib]
lib/mysql/mysql-connector-java-*.jar
[jpms]
add-modules: com.mysql.jdbc
The JPMS module java.sql
does not need to be explicitly added because it would be a dependency of the com.mysql.jdbc
module and therefore automatically added to the module graph.
The [jpms]
section has the following format:
[jpms]
add-modules: <module name>(,<module name>)*
patch-module: <module>=<file>(:<file>)*
add-opens: <module>/<package>=<target-module>(,<target-module>)*
add-exports: <module>/<package>=<target-module>(,<target-module>)*
add-reads: <module>=<target-module>(,<target-module>)*
Alternative way to start Jetty on the module-path
The section above uses the --jpms
command line option to start Jetty on the module-path.
An alternative way of achieving the same result is to use a Jetty module, $JETTY_BASE/modules/jpms.mod
,
that specifies that you want to run using JPMS (and possibly add some JPMS specific configuration).
[ini]
--jpms
[jpms]
# Additional JPMS configuration.
The [ini]
section is equivalent to passing the --jpms
option to the command line.
The [jpms]
section (see also the advanced JPMS configuration section)
allows you specify additional JPMS configuration.
$ mkdir jetty-base-jpms
$ cd jetty-base-jpms
$ mkdir modules
# Copy the jpms.mod file above into the $JETTY_BASE/modules/ directory.
$ cp /tmp/jpms.mod modules/
# Add both the http and the jpms modules.
$ java -jar $JETTY_HOME/start.jar --add-to-start=http,jpms
# Jetty will start on the module-path.
$ java -jar $JETTY_HOME/start.jar
Session Management
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. Choosing the correct session manager implementation is an important consideration for every application as each can fit and perform optimally in different situations. If you need a simple in-memory session manager that can persist to disk then session management using the local file system can be a good place to start. If you need a session manager that can work in a clustered scenario with multiple instances of Jetty, then the JDBC session manager can be an excellent option. Jetty also offers more niche session managers that leverage backends such as MongoDB, Inifinispan, or even Google’s Cloud Data Store.
Session Architecture
Changes in Session Architecture
The architecture of Session Management Jetty changed significantly in Jetty 9.4. These changes have resulted in Sessions not only being easier to configure but making them much more pluggable for various technologies.
In previous versions of Jetty, users were required to configure a separate SessionIdManager
for each kind of session clustering technology being implemented (JDBC, MongoDB..etc.).
In Jetty 9.4, there is now a single SessionIdManager
implementation which works across all types of session clustering technologies.
Likewise, prior to Jetty 9.4 there were several different instances of the SessionManager
class.
Instead of a single SessionManager
though, it has been done away with entirely, with most of it’s functionality moved to the SesssionHandler
class.
Additionally, Jetty 9.4 introduced the concepts of a SessionCache
and an associated SessionDataStore
(both explained below).
Finally, Session scavenging has been re-worked.
Where previously each SessionManager
instance would periodically scan the in-memory (or clustered) sessions for expired sessions, there is now a single generic scavenger thread which instructs the SessionHandler
to clean up expired sessions.
Session expiration has been changed to use a much more efficient timer-based mechanism that avoids constant iteration over all current sessions in memory by the scavenger.
Session Architecture Hierarchy
Each Jetty instance has a singular SessionIdManager
to handle all session requests, regardless of clustering technology.
For each context on the server there is one (1) SessionCache
which contains all of the Session objects for the given context.
The benefit of the SessionCache
is to ensure that simultaneous requests accessing the same Session Id in the same context always operate on the same Session object.
The SessionCache implementation supplied with the Jetty distribution does just that: keeps Session objects in memory so that they can be shared between simultaneous requests.
However, it is possible to provide your own implementation that never shares Session objects should you require it.
Where the SessionCache
handles Session information, Session data is stored in a SessionDataStore
that is specific to the clustering technology being implemented.
There is only one (1) SessionDataStore
per SessionCache
.
Visually the session architecture can be represented like this:

Configuring Sessions in the Jetty Distribution
Configuring session management involves selecting a module for the desired type of session caching behavior, and a module for the type of session persistence.
Jetty provides two different session caches: the DefaultSessionCache
which holds sessions in memory, and the NullSessionCache
which does not.
There is more information on both of these types of session caching and the circumstances which would lead you to select one or the other in the Session Components section, and more information on the configuration options of each in the L1 Session Cache section.
For session persistence, Jetty provides a number of different implementations from which to choose including non-persistence, local file storage, clustered technologies such as JDBC, MongoDB, Inifinispan, Google Cloud Datastore, and Hazelcast.
Depending on your persistence technology, to enhance performance, you may want to use an L2 cache for session data, in which case Jetty provides the memcached L2 session data cache.
Session Components
SessionIdManager
There is a maximum of one (1) SessionIdManager
per Jetty Server instance.
Its purpose is to generate fresh, unique session ids and to coordinate the re-use of session ids amongst co-operating contexts.
Unlike in previous versions of Jetty, the SessionIdManager
is agnostic with respect to the type of clustering technology chosen.
Jetty provides a default implementation - the DefaultSessionIdManager
- which should meet the needs of most users.
If you do not explicitly enable one of the session modules or otherwise configure a SessionIdManager
, the DefaultSessionIdManager
will be used.
If the DefaultSessionIdManager
does not meet your needs, you can extend the org.eclipse.jetty.server.session.AbstractSessionIdManager
or do a fresh implementation of the org.eclipse.jetty.server.session.SessionIdManager
interface.
See Configuring the SessionIdManager and HouseKeeper for details on configuration.
HouseKeeper
There is a maximum of one (1) HouseKeeper
per SessionIdManager
.
Its purpose is to periodically poll the SessionHandlers
to clean out expired sessions.
By default the HouseKeeper
will poll the SessionHandlers
every 10 mins to find and delete expired sessions, although this interval is configurable.
See Configuring the SessionIdManager and HouseKeeper for details on configuration.
SessionCache
There is one (1) SessionCache
per context.
Its purpose is to provide an L1 cache of Session objects.
Having a working set of Session objects in memory allows multiple simultaneous requests for the same session to share the same Session object.
Jetty provides two (2) SessionCache
implementations: the DefaultSessionCache
and the NullSessionCache
.
The DefaultSessionCache
retains Session objects in memory in a cache and has a number of configuration options to control cache behavior.
It is the default that is used if no other SessionCache
has been configured.
It is suitable for non-clustered and clustered deployments with a sticky load balancer, as well as clustered deployments with a non-sticky load balancer, with some caveats.
The NullSessionCache
does not actually cache any objects: each request uses a fresh Session object.
It is suitable for clustered deployments without a sticky load balancer and non-clustered deployments when purely minimal support for sessions is needed.
SessionCaches
always write out a Session to the SessionDataStore
whenever the last request for the Session exits.
They can also be configured to do an immediate, eager write of a freshly created session. This can be useful if you are likely to experience multiple, near simultaneous requests referencing the same session, e.g. with HTTP/2 and you don’t have a sticky load balancer. Alternatively, if the eager write is not done, application paths which create and then invalidate a session within a single request never incur the cost of writing to persistent storage.
Additionally, if the EVICT_ON_INACTIVITY
eviction policy is in use, you can configure the DefaultSessionCache
to force a write of the Session to the SessionDataStore
just before the Session is evicted.
See the L1 Session Cache for more information.
SessionDataStore
There is one (1) SessionDataStore
per context.
Its purpose is to handle all persistence related operations on sessions.
The common characteristics for all SessionDataStores
are whether or not they support passivation, and the length of the grace period.
Supporting passivation means that session data is serialized. Some persistence mechanisms serialize, such as JDBC, GCloud Datastore etc, whereas others may store an object in shared memory, e.g. Infinispan, when configured with a local cache.
Whether or not a clustering technology entails passivation controls whether or not the session passivation/activation listeners will be called.
The grace period is an interval, configured in seconds, that attempts to deal with the non-transactional nature of sessions with regard to finding sessions that have expired.
Due to the lack of transactionality, in a clustered configuration, even with a sticky load balancer, it is always possible that a Session is live on a node but has not yet been updated in the persistent store.
When SessionDataStores
search their persistent store to find sessions that have expired, they typically perform a few sequential searches:
-
The first verifies the expiration of a list of candidate session ids suggested by the SessionCache
-
The second finds sessions in the store that have expired which were last live on the current node
-
The third finds sessions that expired a "while" ago, irrespective of on which node they were last used: the definition of "a while" is based on the grace period.
Jetty instantiates the trivial NullSessionDataStore
- which does not persist sessions - as the default.
The distribution provides a number of alternative SessionDataStore
implementations such as FileSessionDataStore, GCloudSessionDataStore, JDBCSessionDataStore, MongoSessionDataStore, InfinispanSessionDataStore, HazelcastSessionDataStore.
CachingSessionDataStore
The CachingSessionDataStore
is a special type of SessionDataStore
that inserts an L2 cache of Session data - the SessionDataMap
- in front of a delegate SessionDataStore
.
The SessionDataMap
is preferentially consulted before the actual SessionDataStore on reads.
This can improve the performance of slow stores.
Jetty provides one implementation of the this L2 cache based on Memcached
, the MemcachedSessionDataMap
.
See the L2 SessionData Cachefor additional information.
The SessionIdManager and the Housekeeper
Default Settings
By default, Jetty will instantiate a single instance of the DefaultSessionIdManager
and HouseKeeper
at startup with default settings.
The default settings are:
- DefaultSessionIdManager: worker name
-
This uniquely identifies the jetty server instance within a cluster. It is set from the value of the
JETTY_WORKER_INSTANCE
environment variable, ornode0
if the environment value is not set. If you have more than one Jetty instance, it is crucial that you explicitly configure the worker name on each Jetty instance (see below for how to configure). - HouseKeeper: scavenge interval
-
This is the period in seconds between runs of the session scavenger, and by default is set to the equivalent of 10 minutes. As a rule of thumb, you should ensure that the scavenge interval is shorter than the
maxInactiveInterval
of your sessions to ensure that they are promptly scavenged. See below for instructions on how to configure this.
Configuration
To change the default values, use the module system to enable the sessions
module.
This will enable the $jetty.home/etc/sessions/id-manager.xml
file and generate a $jetty.base/start.d/sessions.ini
file.
The id-manager.xml
file instantiates a single DefaultSessionIdManager
and HouseKeeper
and configures them using the properties from the sessions.ini
file.
Edit the ini file to change the properties to easily customize the DefaultSessionIdManager
and HouseKeeper
:
- jetty.sessionIdManager.workerName
-
By default it is
node1
. This uniquely identifies the Jetty server instance within a cluster. If you have more than one Jetty instance, it is crucial that you configure the worker name differently on each jetty instance. - jetty.sessionScavengeInterval.seconds
-
This is the period in seconds between runs of the session scavenger. By default it will run every 600 secs (ie 10 mins). As a rule of thumb, you should ensure that the scavenge interval is shorter than the maxInactiveInterval of your sessions to ensure that they are promptly scavenged.
The L1 Session Cache
The DefaultSessionCache
In the absence of any explicit configuration, Jetty will instantiate an instance of the DefaultSessionCache
per context.
If you wish to change any of the default values, you need to enable the session-cache-hash
module.
Once the session-cache-hash
module has been enabled, you can view a list of all the configurable values by opening start.d/session-cache-hash.ini
:
--module=session-cache-hash
#jetty.session.evictionPolicy=-1
#jetty.session.saveOnInactiveEvict=false
#jetty.session.saveOnCreate=false
#jetty.session.removeUnloadableSessions=false
#jetty.session.flushOnResponseCommit=false
- jetty.session.evictionPolicy
-
Integer. Controls whether session objects that are held in memory are subject to eviction from the memory cache. Evicting sessions can reduce the memory footprint of the cache. Eviction is usually used in conjunction with a
SessionDataStore
that persists sessions. Values are:-
-1 : sessions are never evicted from the cache
-
0 : sessions are evicted from the cache as soon as the last active request for it finishes
-
>= 1 : 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
-
If you are not using a |
- jetty.session.saveOnInactiveEvict
-
Boolean, default
false
. Controls whether a session will be saved to theSessionDataStore
just prior to its eviction. - jetty.session.saveOnCreate
-
Boolean, default
false
. Controls whether a session that is newly created will be immediately saved to theSessionDataStore
or lazily saved as the last request for the session exits. - jetty.session.removeUnloadableSessions
-
Boolean, default
false
. Controls whether a session that cannot be restored - for example because it is corrupted - from theSessionDataStore
is deleted by theSessionDataStore
. - 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.
For more general information on the uses of these configuration properties, see Session Components.
The NullSessionCache
The NullSessionCache
is a trivial implementation of the SessionCache
that does not cache any session information.
You may need to use it if your clustering setup does not have a sticky load balancer, or if you want absolutely minimal support for sessions.
If you use this in conjunction with the NullSessionDataStore
, then sessions will neither be retained in memory nor persisted.
To enable the NullSessionCache
, enable the sesssion-cache-null
module.
Configuration options are:
- jetty.session.saveOnCreate
-
Boolean, default
false
. Controls whether a session that is newly created will be immediately saved to theSessionDataStore
or lazily saved as the last request for the session exits. - jetty.session.removeUnloadableSessions
-
Boolean, default
false
. Controls whether a session that cannot be restored - for example because it is corrupted - from theSessionDataStore
is deleted by theSessionDataStore
. - 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.
For more general information on the uses of these configuration properties, see Session Components.
Non-Persistent Sessions
Non-clustered, non-persistent, in-memory-only is the default style of session management.
In previous versions of Jetty this was referred to as "hash" sessions, as they were stored in a HashMap
in memory.
This is delivered by a combination of the DefaultSessionCache
(to keep sessions in memory) and a NullSessionDataStore
(to avoid session persistence).
If you do nothing, Jetty will instantiate one of each of these objects for each context at startup time using hard-coded defaults.
To explicitly set up non-persisted sessions using modules, use both the session-cache-hash
and the session-store-null
modules.
Enabling the modules allows you to configure behavior - see the L1 Session Cache for detailed information on configuration options for the DefaultSessionCache
.
The NullSessionDataStore
has no customizable options.
Persistent Sessions: File System
Note: Persisting sessions to the local file system should not be used in a clustered environment.
Enabling File System Sessions
When using the Jetty distribution, you will first need to enable the session-store-file
module for your Jetty base using the --add-to-start
argument on the command line.
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-file
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : session-store-file initialized in ${jetty.base}/start.d/session-store-file.ini
MKDIR : ${jetty.base}/sessions
INFO : Base directory was modified
Doing this enables the File System Session module and any dependent modules or files needed for it to run on the server.
The example above is using a fresh ${jetty.base}
with nothing else enabled.
When the --add-to-start
argument was added to the command line, it enabled the the session-store-file
module as well as the sessions
and server
modules, which are required for the File System session management to operate.
Additionally a ${jetty.base}/sessions
directory was created.
By default Session files will be saved to this directory.
In addition to adding these modules to the classpath of the server, several ini configuration files were added to the ${jetty.base}/start.d
directory.
Session data is now only loaded when requested.
Previous functionality such as |
Configuring File System Session Properties
Opening start.d/session-store-file.ini
will show a list of all the configurable options for the file system session module:
# ---------------------------------------
# Module: session-store-file
# Enables session persistent storage in files.
# ---------------------------------------
--module=session-store-file
jetty.session.file.storeDir=${jetty.base}/sessions
#jetty.session.file.deleteUnrestorableFiles=false
#jetty.session.savePeriod.seconds=0
- jetty.session.storeDir
-
This defines the location for storage of Session files.
- jetty.session.file.deleteUnrestorableFiles
-
Boolean. 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.savePeriod.seconds=0
-
By default whenever the last concurrent request leaves a session, that session is always persisted via the
SessionDataStore
, even if the only thing that changed on the session is its updated last access time. A non-zero value means that theSessionDataStore
will skip persisting the session if only the access time changed, and it has been less thansavePeriod
seconds since the last time the session was written.Configuring
savePeriod
is useful if your persistence technology is very slow/costly for writes. In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up tosavePeriod
seconds. This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of themaxIdleTime
of the session when setting thesavePeriod
is imperative - there is no point in setting asavePeriod
that is larger than themaxIdleTime
.
Persistent Sessions: JDBC
Enabling JDBC Sessions
When using the Jetty distribution, you will first need to enable the session-store-jdbc
module for your Jetty base using the --add-to-start
argument on the command line.
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-jdbc
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : sessions/jdbc/datasource dynamic dependency of session-store-jdbc
INFO : session-store-jdbc initialized in ${jetty.base}/start.d/session-store-jdbc.ini
INFO : Base directory was modified
Doing this enables the JDBC Session module and any dependent modules or files needed for it to run on the server.
The example above is using a fresh ${jetty.base}
with nothing else enabled.
When the --add-to-start
argument was added to the command line, it enabled the the session-store-jdbc
module as well as the sessions
and server
modules, which are required for JDBC session management to operate.
In addition to adding these modules to the classpath of the server, several ini configuration files were added to the ${jetty.base}/start.d
directory.
Configuring JDBC Session Properties
Opening the start.d/session-store-jdbc.ini
will show a list of all the configurable options for the JDBC module:
# ---------------------------------------
# Module: session-store-jdbc
# Enables JDBC persistent/distributed session storage.
# ---------------------------------------
--module=session-store-jdbc
##
##JDBC Session properties
##
#jetty.session.gracePeriod.seconds=3600
## Connection type:Datasource
db-connection-type=datasource
#jetty.session.jdbc.datasourceName=/jdbc/sessions
## Connection type:driver
#db-connection-type=driver
#jetty.session.jdbc.driverClass=
#jetty.session.jdbc.driverUrl=
## Session table schema
#jetty.session.jdbc.schema.accessTimeColumn=accessTime
#jetty.session.jdbc.schema.contextPathColumn=contextPath
#jetty.session.jdbc.schema.cookieTimeColumn=cookieTime
#jetty.session.jdbc.schema.createTimeColumn=createTime
#jetty.session.jdbc.schema.expiryTimeColumn=expiryTime
#jetty.session.jdbc.schema.lastAccessTimeColumn=lastAccessTime
#jetty.session.jdbc.schema.lastSavedTimeColumn=lastSavedTime
#jetty.session.jdbc.schema.idColumn=sessionId
#jetty.session.jdbc.schema.lastNodeColumn=lastNode
#jetty.session.jdbc.schema.virtualHostColumn=virtualHost
#jetty.session.jdbc.schema.maxIntervalColumn=maxInterval
#jetty.session.jdbc.schema.mapColumn=map
#jetty.session.jdbc.schema.table=JettySessions
# Optional name of the schema used to identify where the session table is defined in the database:
# "" - empty string, no schema name
# "INFERRED" - special string meaning infer from the current db connection
# name - a string defined by the user
#jetty.session.jdbc.schema.schemaName
# Optional name of the catalog used to identify where the session table is defined in the database:
# "" - empty string, no catalog name
# "INFERRED" - special string meaning infer from the current db connection
# name - a string defined by the user
#jetty.session.jdbc.schema.catalogName
- jetty.session.gracePeriod.seconds
-
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
- jetty.session.savePeriod.seconds=0
-
By default whenever the last concurrent request leaves a session, that session is always persisted via the
SessionDataStore
, even if the only thing that changed on the session is its updated last access time. A non-zero value means that theSessionDataStore
will skip persisting the session if only the access time changed, and it has been less thansavePeriod
seconds since the last time the session was written.Configuring
savePeriod
is useful if your persistence technology is very slow/costly for writes. In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up tosavePeriod
seconds. This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of themaxIdleTime
of the session when setting thesavePeriod
is imperative - there is no point in setting asavePeriod
that is larger than themaxIdleTime
. - db-connection-type
-
Set to either
datasource
ordriver
depending on the type of connection being used. - jetty.session.jdbc.datasourceName
-
Name of the remote datasource.
- 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
.
The jetty.session.jdbc.schema.*
values represent the names of the table and columns in the JDBC database used to store sessions and can be changed to suit your environment.
There are also two special, optional properties: jetty.session.jdbc.schema.schemaName
and jetty.session.jdbc.schema.catalogName
.
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.
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.
Persistent Sessions: MongoDB
Enabling MongoDB Sessions
When using the Jetty distribution, you will first need to enable the session-store-mongo
module for your Jetty base using the --add-to-start
argument on the command line.
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-mongo
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: session-store-mongo
+ The java driver for the MongoDB document-based database system is hosted on GitHub and released under the Apache 2.0 license.
+ http://www.mongodb.org/
+ http://www.apache.org/licenses/LICENSE-2.0.html
Proceed (y/N)? y
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : session-store-mongo initialized in ${jetty.base}/start.d/session-store-mongo.ini
INFO : sessions/mongo/address dynamic dependency of session-store-mongo
MKDIR : ${jetty.base}/lib/nosql
DOWNLD: https://repo1.maven.org/maven2/org/mongodb/mongo-java-driver/2.13.2/mongo-java-driver-2.13.2.jar to ${jetty.base}/lib/nosql/mongo-java-driver-2.13.2.jar
INFO : Base directory was modified
Doing this enables the MongoDB Session module and any dependent modules or files needed for it to run on the server.
The example above is using a fresh ${jetty.base}
with nothing else enabled.
Because MongoDB is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the --add-to-start
argument was added to the command line, it enabled the the session-store-mongo
module as well as the sessions
and server
modules, which are required for MongoDB session management to operate..
It also downloaded the needed Mongo-specific jar file and created a directory named ${jetty.base}/lib/nosql/
to house it.
In addition to adding these modules to the classpath of the server, several ini configuration files were added to the ${jetty.base}/start.d
directory.
If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated |
Configuring MongoDB Session Properties
Opening the start.d/session-store-mongo.ini
will show a list of all the configurable options for the MongoDB module:
# ---------------------------------------
# Module: session-store-mongo
# Enables NoSql session management with a MongoDB driver.
# ---------------------------------------
--module=session-store-mongo
#jetty.session.mongo.dbName=HttpSessions
#jetty.session.mongo.collectionName=jettySessions
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
connection-type=address
#jetty.session.mongo.host=localhost
#jetty.session.mongo.port=27017
#connection-type=uri
#jetty.session.mongo.connectionString=mongodb://localhost
- jetty.session.gracePeriod.seconds
-
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
- jetty.session.savePeriod.seconds=0
-
By default whenever the last concurrent request leaves a session, that session is always persisted via the
SessionDataStore
, even if the only thing that changed on the session is its updated last access time. A non-zero value means that theSessionDataStore
will skip persisting the session if only the access time changed, and it has been less thansavePeriod
seconds since the last time the session was written.Configuring
savePeriod
is useful if your persistence technology is very slow/costly for writes. In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up tosavePeriod
seconds. This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of themaxIdleTime
of the session when setting thesavePeriod
is imperative - there is no point in setting asavePeriod
that is larger than themaxIdleTime
. - jetty.session.mongo.dbName
-
Name of the database in Mongo used to store the Session collection.
- jetty.session.mongo.collectionName
-
Name of the collection in Mongo used to keep all of the Sessions.
- jetty.session.gracePeriod.seconds
-
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
- connection-type=address
-
Used when utilizing a direct connection to the Mongo server.
- jetty.session.mongo.host
-
Host name or address for the remote Mongo instance.
- jetty.session.mongo.port
-
Port number for the remote Mongo 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 official documentation for mongo.You will only use one
connection-type
at a time,address
oruri
. If both are utilized in yoursession-store-mongo.ini
, only the lastconnection-type
configured in the file will be used. By default, theconnection-type
ofaddress
is used.
Persistent Sessions: Inifinspan
Enabling Infinispan Sessions
When using the Jetty distribution, you will first need to enable the session-store-infinispan-remote
module for your Jetty base using the --add-to-start
argument on the command line.
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-infinispan-remote
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: session-store-infinispan-remote
+ Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
+ http://infinispan.org/
+ http://www.apache.org/licenses/LICENSE-2.0.html
Proceed (y/N)? y
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : session-store-infinispan-remote initialized in ${jetty.base}/start.d/session-store-infinispan-remote.ini
MKDIR : ${jetty.base}/lib/infinispan
DOWNLD: https://repo1.maven.org/maven2/org/infinispan/infinispan-remote-it/9.4.8.Final/infinispan-remote-it-9.4.8.Final.jar to ${jetty.base}/lib/infinispan/infinispan-remote-it-9.4.8.Final.jar
MKDIR : ${jetty.base}/resources
COPY : ${jetty.home}/modules/session-store-infinispan-remote/resources/hotrod-client.properties to ${jetty.base}/resources/hotrod-client.properties
INFO : Base directory was modified
Doing this enables the remote Infinispan Session module and any dependent modules or files needed for it to run on the server.
The example above is using a fresh ${jetty.base}
with nothing else enabled.
Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the --add-to-start
argument was added to the command line, it enabled the the session-store-infinispan-remote
module as well as the sessions
and server
modules, which are required for Infinispan session management to operate.
It also downloaded the needed Infinispan-specific jar files and created a directory named ${jetty.base}/lib/infinispan/
to house them.
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.
If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated |
Configuring Inifinspan Remote Properties
Opening the start.d/session-store-infinispan-remote.ini
will show a list of all the configurable options for the JDBC module:
# ---------------------------------------
# Module: session-store-infinispan-remote
# Enables session data store in a remote Infinispan cache
# ---------------------------------------
--module=session-store-infinispan-remote
#jetty.session.infinispan.remoteCacheName=sessions
#jetty.session.infinispan.idleTimeout.seconds=0
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
- jetty.session.infinispan.remoteCacheName
-
Name of the cache in Infinispan where sessions will be stored.
- jetty.session.infinispan.idleTimeout.seconds
-
Amount of time, in seconds, that a session entry in infinispan can be idle (ie not read or written) before infinispan will delete its entry. Usually, you do not want to set a value for this, as you want jetty to handle all session expiration (and call any SessionListeners). However, if 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), then you might want to use this feature. You should make sure that the number of seconds you specify is sufficiently large to avoid the situation where a session is still being referenced by jetty, but is rarely accessed and thus deleted by infinispan. Alternatively, you can enable the
infinispan-remote-query
module, which will allow jetty to search the infinispan session cache to proactively find and properly (ie calling any SessionListeners) scavenge defunct sessions. - jetty.session.gracePeriod.seconds
-
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
- jetty.session.savePeriod.seconds=0
-
By default whenever the last concurrent request leaves a session, that session is always persisted via the
SessionDataStore
, even if the only thing that changed on the session is its updated last access time. A non-zero value means that theSessionDataStore
will skip persisting the session if only the access time changed, and it has been less thansavePeriod
seconds since the last time the session was written.
Configuring |
Configuring the Remote Infinispan Query Module
Enabling this module allows jetty to search infinispan for expired sessions that are no longer being referenced by any jetty node.
Note that this is an additional module, to be used in conjuction with the session-store-infinispan-remote
module.
java -jar ../start.jar --add-to-start=infinispan-remote-query
There are no configuration properties associated with this module.
Configuring Embedded Inifinspan Clustering
During testing, it can be helpful to run an in-process instance of Infinispan.
To enable this you will first need to enable the session-store-infinispan-embedded
module for your Jetty base using the --add-to-start
argument on the command line.
If you are running Jetty with JDK 9 or greater, enable |
java -jar ../start.jar --add-to-start=session-store-infinispan-embedded
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: session-store-infinispan-embedded
+ Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
+ http://infinispan.org/
+ http://www.apache.org/licenses/LICENSE-2.0.html
Proceed (y/N)? y
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini
INFO : session-store-infinispan-embedded initialised in ${jetty.base}/start.d/session-store-infinispan-embedded.ini
DOWNLOAD: https://repo1.maven.org/maven2/org/infinispan/infinispan-embedded-it/9.4.8.Final/infinispan-embedded-it-9.4.8.Final.jar to ${jetty.base}/lib/infinispan/infinispan-embedded-it-9.4.8.Final.jar
INFO : Base directory was modified
Doing this enables the embedded Infinispan Session module and any dependent modules or files needed for it to run on the server.
The example above is using a fresh ${jetty.base}
with nothing else enabled.
Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the --add-to-start
argument was added to the command line, it enabled the the session-store-infinispan-embedded
module as well as the sessions
and server
modules, which are required for Infinispan session management to operate.
It also downloaded the needed Infinispan-specific jar files and created a directory named ${jetty.base}/lib/infinispan/
to house them.
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.
Configuring Inifinspan Embedded Properties
Opening the start.d/session-store-infinispan-remote.ini
will show a list of all the configurable options for the JDBC module:
# ---------------------------------------
# Module: session-store-infinispan-embedded
# Enables session data store in a local Infinispan cache
# ---------------------------------------
--module=session-store-infinispan-embedded
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
- jetty.session.gracePeriod.seconds
-
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
- jetty.session.savePeriod.seconds=0
-
By default whenever the last concurrent request leaves a session, that session is always persisted via the
SessionDataStore
, even if the only thing that changed on the session is its updated last access time. A non-zero value means that theSessionDataStore
will skip persisting the session if only the access time changed, and it has been less thansavePeriod
seconds since the last time the session was written.Configuring
savePeriod
is useful if your persistence technology is very slow/costly for writes. In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up tosavePeriod
seconds. This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of themaxIdleTime
of the session when setting thesavePeriod
is imperative - there is no point in setting asavePeriod
that is larger than themaxIdleTime
.==== Configuring Inifinspan Embedded Query
Similarly to the session-store-infinispan-remote
module, the session-store-infinispan-embedded
module has an adjunct module infinispan-embedded-query
, which when enabled, will allow jetty to detect and properly scavenge defunct sessions stranded in infinispan.
java -jar ../start.jar --add-to-start=infinispan-embedded-query
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/eclipse/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.
We recommend that you backup your stored sessions before running the conversion program. |
How to use the converter:
java -cp servlet-api-3.1.jar:jetty-util-9.4.13.jar:jetty-server-9.4.13.jar:infinispan-remote-9.1.0.Final.jar:jetty-infinispan-9.4.13.jar:[other classpath] org.eclipse.jetty.session.infinispan.InfinispanSessionLegacyConverter
Usage: InfinispanSessionLegacyConverter [-Dhost=127.0.0.1] [-Dverbose=true|false] <cache-name> [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 bothcache-name
andcheck
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:
java -cp servlet-api-3.1.jar:jetty-util-9.4.13.jar:jetty-server-9.4.13.jar:infinispan-remote-9.1.0.Final.jar:jetty-infinispan-9.4.13.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.
Persistent Sessions: Hazelcast
Enabling Hazelcast Sessions
When using the Jetty distribution, you will first need to enable the session-store-hazelcast-remote
module for your Jetty base using the --add-to-start
argument on the command line.
$ java -jar ../start.jar --create-startd
MKDIR : ${jetty.base}/start.d
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-hazelcast-remote
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: session-store-hazelcast-remote
+ Hazelcast is an open source project hosted on Github and released under the Apache 2.0 license.
+ https://hazelcast.org/
+ http://www.apache.org/licenses/LICENSE-2.0.html
Proceed (y/N)? y
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : session-store-hazelcast-remote initialized in ${jetty.base}/start.d/session-store-hazelcast-remote.ini
MKDIR : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2
DOWNLD: https://repo1.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
MKDIR : ${jetty.base}/lib/hazelcast
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-3.8.2.jar
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast-client/3.8.2/hazelcast-client-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-client-3.8.2.jar
INFO : Base directory was modified
Doing this enables the remote Hazelcast Session module and any dependent modules or files needed for it to run on the server.
The example above is using a fresh ${jetty.base}
with nothing else enabled.
Because Hazelcast is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the --add-to-start
argument was added to the command line, it enabled the the session-store-hazelcast-remote
module as well as the sessions
and server
modules, which are required for Hazelcast session management to operate.
It also downloaded the needed Hazelcast-specific jar files and created a directory named ${jetty.base}/lib/hazelcast/
to house them.
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.
If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated |
Configuring Hazelcast Remote Properties
Opening the start.d/session-store-hazelcast-remote.ini
will show a list of all the configurable options for the Hazelcast module:
# ---------------------------------------
# Module: session-store-hazelcast-remote
# Enables session data store in a remote Hazelcast Map
# ---------------------------------------
--module=session-store-hazelcast-remote
#jetty.session.hazelcast.mapName=jetty_sessions
#jetty.session.hazelcast.onlyClient=true
#jetty.session.hazelcast.configurationLocation=
jetty.session.hazelcast.scavengeZombies=false
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
- jetty.session.hazelcast.mapName
-
Name of the Map in Hazelcast where sessions will be stored.
- jetty.session.hazelcast.onlyClient
-
Hazelcast instance will be configured in client mode
- jetty.session.hazelcast.configurationLocation
-
Path to an an Hazelcast xml configuration file
- jetty.session.hazelcast.scavengeZombies
-
True/False.
False
by default. Iftrue
, jetty will use hazelcast queries to find sessions that are no longer being used on any jetty node and whose expiry time has passed. If you enable this option, and your session stores attributes that reference classes from inside your webapp, or jetty classes, you will need to ensure that these classes are available on each of your hazelcast instances. - jetty.session.gracePeriod.seconds
-
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
- jetty.session.savePeriod.seconds=0
-
By default whenever the last concurrent request leaves a session, that session is always persisted via the
SessionDataStore
, even if the only thing that changed on the session is its updated last access time. A non-zero value means that theSessionDataStore
will skip persisting the session if only the access time changed, and it has been less thansavePeriod
seconds since the last time the session was written.Configuring
savePeriod
is useful if your persistence technology is very slow/costly for writes. In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up tosavePeriod
seconds. This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of themaxIdleTime
of the session when setting thesavePeriod
is imperative - there is no point in setting asavePeriod
that is larger than themaxIdleTime
.Be aware using the
scavengeZombies
option that if your session attributes contain classes from inside your webapp (or jetty classes) then you will need to put these classes onto the classpath of all of your hazelcast instances.==== Configuring Embedded Hazelcast Clustering
During testing, it can be helpful to run an in-process instance of Hazelcast.
To enable this you will first need to enable the session-store-hazelcast-embedded
module for your Jetty base using the --add-to-start
argument on the command line.
$ java -jar ../start.jar --create-startd
MKDIR : ${jetty.base}/start.d
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-hazelcast-embedded
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: session-store-hazelcast-embedded
+ Hazelcast is an open source project hosted on Github and released under the Apache 2.0 license.
+ https://hazelcast.org/
+ http://www.apache.org/licenses/LICENSE-2.0.html
Proceed (y/N)? y
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : session-store-hazelcast-embedded initialized in ${jetty.base}/start.d/session-store-hazelcast-embedded.ini
MKDIR : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2
DOWNLD: https://repo1.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
MKDIR : ${jetty.base}/lib/hazelcast
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-3.8.2.jar
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast-client/3.8.2/hazelcast-client-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-client-3.8.2.jar
Doing this enables the embedded Hazelcast Session module and any dependent modules or files needed for it to run on the server.
The example above is using a fresh ${jetty.base}
with nothing else enabled.
Because Hazelcast is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the --add-to-start
argument was added to the command line, it enabled the the session-store-hazelcast-embedded
module as well as the sessions
and server
modules, which are required for Hazelcast session management to operate.
It also downloaded the needed Hazelcast-specific jar files and created a directory named ${jetty.base}/lib/hazelcast/
to house them.
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.
Configuring Hazelcast Embedded Properties
Opening the start.d/start.d/session-store-hazelcast-embedded.ini
will show a list of all the configurable options for the Hazelcast module:
# ---------------------------------------
# Module: session-store-hazelcast-embedded
# Enables session data store in an embedded Hazelcast Map
# ---------------------------------------
--module=session-store-hazelcast-embedded
#jetty.session.hazelcast.mapName=jetty_sessions
#jetty.session.hazelcast.configurationLocation=
jetty.session.hazelcast.scavengeZombies=false
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
- jetty.session.hazelcast.mapName
-
Name of the Map in Hazelcast where sessions will be stored.
- jetty.session.hazelcast.configurationLocation
-
Path to an an Hazelcast xml configuration file
- jetty.session.hazelcast.scavengeZombies
-
True/False.
False
by default. Iftrue
, jetty will use hazelcast queries to find sessions that are no longer being used on any jetty node and whose expiry time has passed. If you enable this option, and your sessions contain attributes that reference classes from inside your webapp (or jetty classes) you will need to ensure that these classes are available on each of your hazelcast instances. - jetty.session.gracePeriod.seconds
-
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
- jetty.session.savePeriod.seconds=0
-
By default whenever the last concurrent request leaves a session, that session is always persisted via the
SessionDataStore
, even if the only thing that changed on the session is its updated last access time. A non-zero value means that theSessionDataStore
will skip persisting the session if only the access time changed, and it has been less thansavePeriod
seconds since the last time the session was written.Configuring
savePeriod
is useful if your persistence technology is very slow/costly for writes. In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up tosavePeriod
seconds. This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of themaxIdleTime
of the session when setting thesavePeriod
is imperative - there is no point in setting asavePeriod
that is larger than themaxIdleTime
.Be aware using the
scavengeZombies
option that if your session attributes contain classes from inside your webapp (or jetty classes) then you will need to put these classes onto the classpath of all of your hazelcast instances. In the cast of embedded hazelcast, as it is started before your webapp, it will NOT have access to your webapp’s classes - you will need to extract these classes and put them onto the jetty server’s classpath.
Persistent Sessions: Google Cloud DataStore
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_PROJECT
with the project id you created in the preparation step. -
Generate a JSON 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 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 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
When using the Jetty distribution, you will first need to enable the session-store-gcloud
module for your Jetty base using the --add-to-start
argument on the command line.
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-gcloud
ALERT: There are enabled module(s) with licenses.
The following 2 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: gcloud
+ GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
+ https://github.com/GoogleCloudPlatform/gcloud-java
+ http://www.apache.org/licenses/LICENSE-2.0.html
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : webapp transitively enabled, ini template available with --add-to-start=webapp
INFO : jul-impl transitively enabled
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : servlet transitively enabled
INFO : gcloud transitively enabled, ini template available with --add-to-start=gcloud
INFO : annotations transitively enabled
INFO : plus transitively enabled
INFO : slf4j-api transitively enabled
INFO : security transitively enabled
INFO : gcloud-datastore transitively enabled
INFO : jcl-slf4j transitively enabled
INFO : session-store-gcloud initialized in ${jetty.base}/start.d/session-store-gcloud.ini
INFO : jndi transitively enabled
MKDIR : ${jetty.base}/etc
COPY : ${jetty.home}/modules/jul-impl/etc/java-util-logging.properties to ${jetty.base}/etc/java-util-logging.properties
MKDIR : ${jetty.base}/lib/slf4j
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
MKDIR : ${jetty.base}/lib/gcloud
COPY : /Users/admin/.m2/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jar to ${jetty.base}/lib/gcloud/aopalliance-1.0.jar
COPY : /Users/admin/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.1.3/jackson-core-2.1.3.jar to ${jetty.base}/lib/gcloud/jackson-core-2.1.3.jar
COPY : /Users/admin/.m2/repository/com/google/api-client/google-api-client-appengine/1.21.0/google-api-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-api-client-appengine-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/api-client/google-api-client/1.20.0/google-api-client-1.20.0.jar to ${jetty.base}/lib/gcloud/google-api-client-1.20.0.jar
COPY : /Users/admin/.m2/repository/com/google/api-client/google-api-client-servlet/1.21.0/google-api-client-servlet-1.21.0.jar to ${jetty.base}/lib/gcloud/google-api-client-servlet-1.21.0.jar
DOWNLD: https://repo1.maven.org/maven2/com/google/api/gax/0.0.21/gax-0.0.21.jar to ${jetty.base}/lib/gcloud/gax-0.0.21.jar
COPY : /Users/admin/.m2/repository/com/google/api/grpc/grpc-google-common-protos/0.1.0/grpc-google-common-protos-0.1.0.jar to ${jetty.base}/lib/gcloud/grpc-google-common-protos-0.1.0.jar
COPY : /Users/admin/.m2/repository/com/google/api/grpc/grpc-google-iam-v1/0.1.0/grpc-google-iam-v1-0.1.0.jar to ${jetty.base}/lib/gcloud/grpc-google-iam-v1-0.1.0.jar
COPY : /Users/admin/.m2/repository/com/google/auth/google-auth-library-credentials/0.3.1/google-auth-library-credentials-0.3.1.jar to ${jetty.base}/lib/gcloud/google-auth-library-credentials-0.3.1.jar
COPY : /Users/admin/.m2/repository/com/google/auth/google-auth-library-oauth2-http/0.3.1/google-auth-library-oauth2-http-0.3.1.jar to ${jetty.base}/lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
DOWNLD: https://repo1.maven.org/maven2/com/google/auto/value/auto-value/1.2/auto-value-1.2.jar to ${jetty.base}/lib/gcloud/auto-value-1.2.jar
DOWNLD: https://repo1.maven.org/maven2/com/google/cloud/datastore/datastore-v1-proto-client/1.3.0/datastore-v1-proto-client-1.3.0.jar to ${jetty.base}/lib/gcloud/datastore-v1-proto-client-1.3.0.jar
DOWNLD: https://repo1.maven.org/maven2/com/google/cloud/datastore/datastore-v1-protos/1.3.0/datastore-v1-protos-1.3.0.jar to ${jetty.base}/lib/gcloud/datastore-v1-protos-1.3.0.jar
DOWNLD: https://repo1.maven.org/maven2/com/google/cloud/google-cloud-core/0.5.1/google-cloud-core-0.5.1.jar to ${jetty.base}/lib/gcloud/google-cloud-core-0.5.0.jar
DOWNLD: https://repo1.maven.org/maven2/com/google/cloud/google-cloud-datastore/0.5.1/google-cloud-datastore-0.5.1.jar to ${jetty.base}/lib/gcloud/google-cloud-datastore-0.5.1.jar
COPY : /Users/admin/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar to ${jetty.base}/lib/gcloud/jsr305-1.3.9.jar
COPY : /Users/admin/.m2/repository/com/google/code/gson/gson/2.3/gson-2.3.jar to ${jetty.base}/lib/gcloud/gson-2.3.jar
COPY : /Users/admin/.m2/repository/com/google/guava/guava/19.0/guava-19.0.jar to ${jetty.base}/lib/gcloud/guava-19.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-appengine/1.21.0/google-http-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-appengine-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-jackson2/1.19.0/google-http-client-jackson2-1.19.0.jar to ${jetty.base}/lib/gcloud/google-http-client-jackson2-1.19.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-jackson/1.21.0/google-http-client-jackson-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-jackson-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client/1.21.0/google-http-client-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-jdo/1.21.0/google-http-client-jdo-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-jdo-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-protobuf/1.20.0/google-http-client-protobuf-1.20.0.jar to ${jetty.base}/lib/gcloud/google-http-client-protobuf-1.20.0.jar
COPY : /Users/admin/.m2/repository/com/google/inject/guice/4.0/guice-4.0.jar to ${jetty.base}/lib/gcloud/guice-4.0.jar
COPY : /Users/admin/.m2/repository/com/google/oauth-client/google-oauth-client-appengine/1.21.0/google-oauth-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-oauth-client-appengine-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/oauth-client/google-oauth-client/1.21.0/google-oauth-client-1.21.0.jar to ${jetty.base}/lib/gcloud/google-oauth-client-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/oauth-client/google-oauth-client-servlet/1.21.0/google-oauth-client-servlet-1.21.0.jar to ${jetty.base}/lib/gcloud/google-oauth-client-servlet-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/protobuf/protobuf-java/3.0.0/protobuf-java-3.0.0.jar to ${jetty.base}/lib/gcloud/protobuf-java-3.0.0.jar
COPY : /Users/admin/.m2/repository/com/google/protobuf/protobuf-java-util/3.0.0/protobuf-java-util-3.0.0.jar to ${jetty.base}/lib/gcloud/protobuf-java-util-3.0.0.jar
COPY : /Users/admin/.m2/repository/commons-codec/commons-codec/1.3/commons-codec-1.3.jar to ${jetty.base}/lib/gcloud/commons-codec-1.3.jar
COPY : /Users/admin/.m2/repository/io/grpc/grpc-context/1.0.1/grpc-context-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-context-1.0.1.jar
COPY : /Users/admin/.m2/repository/io/grpc/grpc-core/1.0.1/grpc-core-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-core-1.0.1.jar
COPY : /Users/admin/.m2/repository/io/grpc/grpc-protobuf/1.0.1/grpc-protobuf-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-protobuf-1.0.1.jar
COPY : /Users/admin/.m2/repository/io/grpc/grpc-protobuf-lite/1.0.1/grpc-protobuf-lite-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-protobuf-lite-1.0.1.jar
COPY : /Users/admin/.m2/repository/javax/inject/javax.inject/1/javax.inject-1.jar to ${jetty.base}/lib/gcloud/javax.inject-1.jar
COPY : /Users/admin/.m2/repository/javax/jdo/jdo2-api/2.3-eb/jdo2-api-2.3-eb.jar to ${jetty.base}/lib/gcloud/jdo2-api-2.3-eb.jar
COPY : /Users/admin/.m2/repository/javax/transaction/transaction-api/1.1/transaction-api-1.1.jar to ${jetty.base}/lib/gcloud/transaction-api-1.1.jar
COPY : /Users/admin/.m2/repository/joda-time/joda-time/2.9.2/joda-time-2.9.2.jar to ${jetty.base}/lib/gcloud/joda-time-2.9.2.jar
COPY : /Users/admin/.m2/repository/org/apache/httpcomponents/httpclient/4.0.1/httpclient-4.0.1.jar to ${jetty.base}/lib/gcloud/httpclient-4.0.1.jar
COPY : /Users/admin/.m2/repository/org/apache/httpcomponents/httpcore/4.0.1/httpcore-4.0.1.jar to ${jetty.base}/lib/gcloud/httpcore-4.0.1.jar
COPY : /Users/admin/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.9.11/jackson-core-asl-1.9.11.jar to ${jetty.base}/lib/gcloud/jackson-core-asl-1.9.11.jar
COPY : /Users/admin/.m2/repository/org/json/json/20151123/json-20151123.jar to ${jetty.base}/lib/gcloud/json-20151123.jar
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.21/jcl-over-slf4j-1.7.21.jar to ${jetty.base}/lib/slf4j/jcl-over-slf4j-1.7.21.jar
COPY : ${jetty.home}/modules/gcloud/index.yaml to ${jetty.base}/etc/index.yaml
INFO : Base directory was modified
ERROR : Module jcl-slf4j requires a module providing slf4j-impl from one of [slf4j-simple-impl, slf4j-logback, slf4j-jul, slf4j-log4j2, slf4j-log4j]
ERROR : Unsatisfied module dependencies: jcl-slf4j
Usage: java -jar $JETTY_HOME/start.jar [options] [properties] [configs]
java -jar $JETTY_HOME/start.jar --help # for more information
Doing this enables the GCloud Session module and any dependent session modules or files needed for it to run on the server.
The example above is using a fresh ${jetty.base}
with nothing else enabled.
Because the Google Cloud DataStore is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
You will notice, however, that the above output presented a warning: GCloud requires certain Java Commons Logging features to work correctly.
GCloud has a dependency on Java Commons Logging, and by default Jetty will route this through SLF4J.
Enabling the GCloud Sessions module will also enable the jcl-slf4j
module, which sends JCL logging information to SLF4J.
It does not, however, configure a SLF4J implementation for the users.
As such, you will also need to enable one of the SLF4J implementation modules listed.
In this example, we will enable the slf4j-simple-impl
module to provide a SLF4J implementation.
$ java -jar ../start.jar --add-to-start=slf4j-simple-impl
INFO : slf4j-simple-impl initialized in ${jetty.base}/start.d/slf4j-simple-impl.ini
INFO : resources transitively enabled
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/1.7.21/slf4j-simple-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-simple-1.7.21.jar
MKDIR : ${jetty.base}/resources
COPY : ${jetty.home}/modules/slf4j-simple-impl/resources/simplelogger.properties to ${jetty.base}/resources/simplelogger.properties
INFO : Base directory was modified
When the --add-to-start
argument was added to the command line the first time, it enabled the the session-store-gcloud
module as well as several others, such as as server
, sessions
, webapp
and others which are required for GCloud session management to operate; the slf4j-simple-impl
and its dependent modules were added when the the command was run the second time.
In addition to adding these modules to the classpath of the server it also added the respective configuration files to the ${jetty.base}start.d
directory.
If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated |
Configuring GCloud Session Properties
Opening the start.d/session-store-gcloud.ini
will display a list of all the configurable properties for the Google Cloud DataStore module:
# ---------------------------------------
# Module: session-store-gcloud
# Enables GCloudDatastore session management.
# ---------------------------------------
--module=session-store-gcloud
## GCloudDatastore Session config
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
#jetty.session.gcloud.maxRetries=5
#jetty.session.gcloud.backoffMs=1000
#jetty.session.gcloud.namespace=
#jetty.session.gcloud.model.kind=GCloudSession
#jetty.session.gcloud.model.id=id
#jetty.session.gcloud.model.contextPath=contextPath
#jetty.session.gcloud.model.vhost=vhost
#jetty.session.gcloud.model.accessed=accessed
#jetty.session.gcloud.model.lastAccessed=lastAccessed
#jetty.session.gcloud.model.createTime=createTime
#jetty.session.gcloud.model.cookieSetTime=cookieSetTime
#jetty.session.gcloud.model.lastNode=lastNode
#jetty.session.gcloud.model.expiry=expiry
#jetty.session.gcloud.model.maxInactive=maxInactive
#jetty.session.gcloud.model.attributes=attributes
- jetty.session.gracePeriod.seconds
-
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
- jetty.session.savePeriod.seconds=0
-
By default whenever the last concurrent request leaves a session, that session is always persisted via the
SessionDataStore
, even if the only thing that changed on the session is its updated last access time. A non-zero value means that theSessionDataStore
will skip persisting the session if only the access time changed, and it has been less thansavePeriod
seconds since the last time the session was written.Configuring
savePeriod
is useful if your persistence technology is very slow/costly for writes. In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up tosavePeriod
seconds. This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of themaxIdleTime
of the session when setting thesavePeriod
is imperative - there is no point in setting asavePeriod
that is larger than themaxIdleTime
. - jetty.session.gcloud.maxRetries
-
Maxmium number of tries to connect to GCloud DataStore to write sessions.
- jetty.session.gcloud.backoffMs
-
Amount of time, in milliseconds, between attempts to connect to the GCloud DataStore to write sessions.
- jetty.session.gcloud.namespace
-
Optional. Sets the namespace for GCloud Datastore to use. If set, partitions the visibility of session data between webapps, which is helpful for multi-tenant deployments. More information can be found here.
The other values listed are simply the names of properties that represent stored session data, and can be changed if needed.
Persistent 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.
To enable it with the Jetty distribution, enable the session-store-cache
module, along with your chosen session-store-xxxx
module, and optionally the session-cache-hash
or session-cache-null
modules.
After enabling, the $jetty.base/start.d/session-store-cache.ini
file will be generated:
--module=session-store-cache
## Session Data Cache type: xmemcached
session-data-cache=xmemcached
#jetty.session.memcached.host=localhost
#jetty.session.memcached.port=11211
#jetty.session.memcached.expirySec=
#jetty.session.memcached.heartbeats=true
The configuration properties are:
- 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 or not the memcached system should generate heartbeats.
Session Use Cases
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 DefaultSessionCache
can be used to keep in-use Session objects in memory.
You can fine-tune the cache by controlling how long Session objects remain in memory with the 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 NullSessionCache
or to de-tune the 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 brought 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 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 unloadable 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 it’s attributes, and after a redeployment there in an incompatible class change.
Using the setter SessionCache.setRemoveUnloadableSessions(true)
will allow the SessionDataStore
to delete the unreadable session from persistent storage.
This can be useful from preventing the scavenger from continually generating errors on the same expired, but un-restorable, session.
Configuring Sessions via Jetty XML
With the provided session modules, there is no need to configure a context xml or jetty-web.xml
file for sessions.
That said, if a user wishes to configure sessions this way, it is possible using Jetty IoC XML format.
Below is an example of how you could configure a the FileSessionDataStore
, but the same concept would apply to any of the *SessionDataStores discussed in this chapter:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Call id="sh" name="getSessionHandler">
<Set name="sessionCache">
<New class="org.eclipse.jetty.server.session.DefaultSessionCache">
<Arg><Ref id="sh"/></Arg>
<Set name="sessionDataStore">
<New class="org.eclipse.jetty.server.session.FileSessionDataStore">
<Set name="storeDir">/tmp/sessions</Set>
</New>
</Set>
</New>
</Set>
</Call>
</Configure>
The example above functions in either a jetty-web.xml
file or a context xml descriptor file.
If you explicitly configure the |
Jetty Logging
This chapter discusses various options for configuring logging.
Configuring Jetty Logging
Jetty provides logging via its own org.eclipse.jetty.util.log.Logger
layer, and does not natively use any existing Java logging framework.
All logging events, produced via the Jetty logging layer, have a name, a level, and a message.
The name is a FQCN (fully qualified class name) similar to how all existing Java logging frameworks operate.
Jetty logging, however, has a slightly different set of levels that it uses internally:
- WARN
-
For events serious enough to inform and log, but not fatal.
- INFO
-
Informational events.
- DEBUG
-
Debugging events (very noisy).
- IGNORE
-
Exception events that you can safely ignore, but useful for some people. You might see this level as DEBUG under some Java logging framework configurations, where it retains the ignore phrase somewhere in the logging.
Jetty logging produces no FATAL or SEVERE events. |
Selecting the Log Framework
Configure the Jetty logging layer via the org.eclipse.jetty.util.log.Log
class, following these rules.
-
Load Properties
-
First from a Classpath Resource called
jetty-logging.properties
(if found). -
Then from the
System.getProperties()
.
-
-
Determine the log implementation.
-
If property
org.eclipse.jetty.util.log.class
is defined, load the class it defines as the logger implementation from the serverclasspath
. -
If the class
org.slf4j.Logger
exists in server classpath, the Jetty implementation becomesorg.eclipse.jetty.util.log.Slf4jLog
. -
If no logger implementation is specified, default to
org.eclipse.jetty.util.log.StdErrLog
.
-
You can create your own custom logging by providing an implementation of the Jetty Logger API. For an example of a custom logger, see JavaUtilLog.java.
The jetty-logging.properties file
By default, the internal Jetty Logging discovery mechanism will load logging specific properties from a classpath resource called jetty-logging.properties
and then initialize the Logging from a combination of properties found in that file, along with any System Properties.
A typical jetty-logging.properties file will include at least the declaration of which logging implementation you want to use by defining a value for the org.eclipse.jetty.util.log.class
property.
Examples for various logging frameworks can be found later in this documentation.
-
Default Logging with Jetty’s StdErrLog
-
Using Logback via SLF4J
Default Logging with Jetty’s StdErrLog
StdErrLog Configuration
If you do nothing to configure a separate logging framework, Jetty will default to using an internal org.eclipse.jetty.util.log.StdErrLog
implementation.
This will output all logging events to STDERR (aka System.err
).
Simply use Jetty and StdErrLog
-based logging is output to the console.
Included in the Jetty distribution is a logging module named console-capture
that is capable of performing simple capturing of all STDOUT (System.out
) and STDERR (System.err
) output to a file that is rotated daily.
To enable this feature, simply activate the console-capture
module on the command line:
[my-base]$ java -jar ../start.jar --add-to-start=console-capture
INFO : console-capture initialized in ${jetty.base}/start.d/console-capture.ini
MKDIR : ${jetty.base}/logs
INFO : Base directory was modified
[my-base]$ tree
.
├── logs
└── start.d
└── console-capture.ini
The default configuration for logging output will create a file ${jetty.base}/logs/yyyy_mm_dd.stderrout.log
which allows configuration of the output directory by setting the jetty.logs
property.
By default, logs are not set to be appended, meaning a the log file is wiped clean upon sever restart.
You can change this setting by editing the |
Just enabling the console-capture
will simply output the values of STDERR and STDOUT to a log file.
To customize the log further, a module named logging-jetty
is available to provides a default properties file to configure.
As with console-capture
, you activate the logging-jetty
on the command line.
[my-base]$ java -jar ../start.jar --add-to-start=logging-jetty
INFO : logging-jetty initialized in ${jetty.base}/start.d/logging-jetty.ini
INFO : resources transitively enabled
MKDIR : ${jetty.base}/resources
COPY : ${jetty.home}/modules/logging-jetty/resources/jetty-logging.properties to ${jetty.base}/resources/jetty-logging.properties
INFO : Base directory was modified
[my-base]$ tree
.
├── logs
├── resources
│ └── jetty-logging.properties
└── start.d
├── console-capture.ini
└── logging-jetty.ini
Once activated, you can find the properties file at ${jetty.base}/resources/jetty-logging.properties
.
By default, the following parameters are defined.
To change them, un-comment the line and substitute your naming scheme and configuration choices.
## Force jetty logging implementation
#org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
## Set logging levels from: ALL, DEBUG, INFO, WARN, OFF
#org.eclipse.jetty.LEVEL=INFO
#com.example.LEVEL=INFO
## Hide stacks traces in logs?
#com.example.STACKS=false
## Show the source file of a log location?
#com.example.SOURCE=false
There are a number of properties that can be defined in the configuration that will affect the behavior of StdErr logging with console-capture
.
<name>.LEVEL=<level>
-
Sets the logging level for all loggers within the
name
specified to the level, which can be (in increasing order of restriction)ALL
,DEBUG
,INFO
,WARN
,OFF
. The name (or hierarchy) can be a specific fully qualified class or a package namespace. For example,org.eclipse.jetty.http.LEVEL=DEBUG
is a package namespace approach to turn all loggers in the Jetty HTTP package to DEBUG level, andorg.eclipse.jetty.io.ChanelEndPoint.LEVEL=ALL
turns on all logging events for the specific class, includingDEBUG
,INFO
,WARN
(and even special internally ignored exception classes). If more than one system property specifies a logging level, the most specific one applies. <name>.SOURCE=<boolean>
-
Named Logger specific, attempts to print the Java source file name and line number from where the logging event originated. Name must be a fully qualified class name (this configurable does not support package name hierarchy). Default is false. Be aware that this is a slow operation and has an impact on performance.
<name>.STACKS=<boolean>
-
Named Logger specific, controls the display of stacktraces. Name must be a fully qualified class name (this configurable does not support package name hierarchy). Default is true.
org.eclipse.jetty.util.log.stderr.SOURCE=<boolean>
-
Special Global Configuration. Attempts to print the Java source file name and line number from where the logging event originated. Default is false.
org.eclipse.jetty.util.log.stderr.LONG=<boolean>
-
Special Global Configuration. When true, outputs logging events to
STDERR
using long form, fully qualified class names. When false, uses abbreviated package names. Default is false.-
Example when set to false:
2016-10-21 15:31:01.248:INFO::main: Logging initialized @332ms to org.eclipse.jetty.util.log.StdErrLog 2016-10-21 15:31:01.370:INFO:oejs.Server:main: jetty-9.4.0-SNAPSHOT 2016-10-21 15:31:01.400:INFO:oejs.AbstractConnector:main: Started ServerConnector@2c330fbc{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} 2016-10-21 15:31:01.400:INFO:oejs.Server:main: Started @485ms
-
Example when set to true:
2016-10-21 15:31:35.020:INFO::main: Logging initialized @340ms to org.eclipse.jetty.util.log.StdErrLog 2016-10-21 15:31:35.144:INFO:org.eclipse.jetty.server.Server:main: jetty-9.4.0-SNAPSHOT 2016-10-21 15:31:35.174:INFO:org.eclipse.jetty.server.AbstractConnector:main: Started ServerConnector@edf4efb{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} 2016-10-21 15:31:35.175:INFO:org.eclipse.jetty.server.Server:main: Started @495ms
-
Deprecated Parameters
These parameters existed in prior versions of Jetty, and are no longer supported. They are included here for historical (and search engine) reasons.
org.eclipse.jetty.util.log.DEBUG
-
Formerly used to enable DEBUG level logging on any logger used within Jetty (not just Jetty’s own logger).
-
Replaced with using the logger implementation specific configuration and level filtering.
-
org.eclipse.jetty.util.log.stderr.DEBUG
-
Formerly used to enable DEBUG level logging on the internal Jetty
StdErrLog
implementation.-
Replaced with level specific equivalent. Example:
org.eclipse.jetty.LEVEL=DEBUG
-
DEBUG
-
Ancient debugging flag that turned on all debugging, even non-logging debugging.
-
Jetty no longer uses because many third party libraries employ this overly simple property name, which would generate far too much console output.
-
Configuring Jetty Request Logs
Request logs are a record of the requests that the server has processed. There is one entry per request received, and commonly in the standard NCSA format, so you can use tools like Webalizer to analyze them conveniently.
Constructing a Request Log Entry
A standard request log entry includes the client IP address, date, method, URL, result, size, referrer, user agent and latency. For example:
123.4.5.6 - - [20/Jul/2016:10:16:17 +0000] "GET /jetty/tut/XmlConfiguration.html HTTP/1.1" 200 76793 "http://localhost:8080/jetty/tut/logging.html" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040614 Firefox/0.8" 342
Implementing a Request Log
Jetty provides an implementation called NCSARequestLog
which supports the NCSA format in files that will roll over on a daily basis.
The Logback Project offers another implementation of a RequestLog
interface, providing rich and powerful HTTP-access log functionality.
If neither of these options meets your needs, you can implement a custom request logger by implementing Jetty’s RequestLog.java
interface and plugging it in similar to the NCSARequestLog
, as shown below.
Configuring the Request Log module
To enable the Request Log module for the entire server via the Jetty distribution, it first needs to be enabled on the command line:
$ java -jar ../start.jar --add-to-start=requestlog
INFO: requestlog initialised in ${jetty.base}/start.d/requestlog.ini
MKDIR: ${jetty.base}/logs
INFO: Base directory was modified
The above command will add a new requestlog.ini
file to your {$jetty.base}/start.d
directory.
By default, request logs are not set to be appended, meaning a the log file is wiped clean upon sever restart.
You can change this setting by editing the |
The equivalent code for embedded usages of Jetty is:
NCSARequestLog requestLog = new NCSARequestLog("/var/logs/jetty/jetty-yyyy_mm_dd.request.log");
requestLog.setAppend(true);
requestLog.setExtended(false);
requestLog.setLogTimeZone("GMT");
requestLog.setLogLatency(true);
requestLog.setRetainDays("90");
server.setRequestLog(requestLog);
This configures a request log in {$jetty.home}/logs
with filenames including the date.
Existing log files are appended to and the extended NCSA format is used in the GMT time zone.
The above configuration enables Log Latency, which is the amount of time it took the server to handle the request. This value is measured in milliseconds and is appended to the the log file for each request.
You can also customize the number of days you wish to keep request logs.
By default, log files are kept for 90 days before being deleted.
The value for retainDays
(xml) or setRetainDays
(Java) should be configured as 1 + n days.
For example, if you wanted to keep the logs for the current day and the day prior you would set the retainDays
(or setRetainDays
) value to 2.
Introducing RequestLog.Writer
The concept of a RequestLog.Writer
, introduced in Jetty 9.4.15, manages the writing to a log the string generated by the RequestLog
.
This allows the CustomRequestLog
to match the functionality of other RequestLogger
implementations by plugging in any RequestLog.Writer
and a custom format string.
Jetty currently has implementations of RequestLog.Writer
, RequestLogWriter
, AsyncRequestLogWriter
, and Slf4jRequestLogWriter
.
So, the way to create an asynchronous RequestLog
using the extended NCSA format has been changed from:
new AsyncNcsaRequestLog(filename)
to:
new CustomRequestLog(new AsyncRequestLogWriter(filename), CustomRequestLog.EXTENDED_NCSA_FORMAT)
Additionally, there are now two settings for the log timezone to be configured.
There is the configuration for logging the request time, which is set in the timeZone
parameter in the %t
format code of the string, given in the format %{format|timeZone|locale}t
.
The other timeZone
parameter relates to the generation of the log file name (both at creation and roll over).
This is configured in the requestlog
module file, or can be used as a setter on RequestLogWriter
via XML.
Both timezones are set to GMT by default.
Configuring a Separate Request Log For a Web Application
To configure a separate request log for specific a web application, add the following to the context XML file.
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
...
<Call name="insertHandler">
<Arg>
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler">
<Set name="requestLog">
<New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
<Set name="filename"><Property name="jetty.logs" default="./logs"/>/test-yyyy_mm_dd.request.log</Set>
<Set name="filenameDateFormat">yyyy_MM_dd</Set>
<Set name="LogTimeZone">GMT</Set>
<Set name="retainDays">90</Set>
<Set name="append">true</Set>
<Set name="LogLatency">true</Set>
</New>
</Set>
</New>
</Arg>
</Call>
...
</Configure>
Jetty Logging Integrations (SLF4J, Log4j, Logback, JCL, JUL)
Jetty provides support for several logging frameworks including SLF4J, Java Commons Logging (JCL), Java Util Logging (JUL), Log4j (including version 2), and Logback. This page includes examples of how to enable the associated modules for these different frameworks. These modules are designed to capture container/server logs; request logs and application logs need to be configured separately. Please note that enabling these modules provides typical and basic functionality for each framework; advanced implementations may require their own modules or additional configuration.
Enabling these frameworks in the Jetty distribution is as easy as activating any other module, by adding --add-to-start=<module name>
to the start command for your server, such as:
[my-base]$ java -jar ../start.jar --add-to-start=logging-jetty
INFO : logging-jetty initialized in ${jetty.base}/start.d/logging-jetty.ini
INFO : resources transitively enabled
MKDIR : ${jetty.base}/resources
COPY : ${jetty.home}/modules/logging-jetty/resources/jetty-logging.properties to ${jetty.base}/resources/jetty-logging.properties
INFO : Base directory was modified
As noted above, Jetty supports a wide array of logging technologies. If a particular logging framework requires additional jar files, Jetty will automatically download these as part of enabling the associated module and any dependent modules will be transitively enabled.
A list of the base Jetty logging modules by running java -jar <path-to-jetty.home>/start.jar --list-modules=logging,-internal
.
- logging-jcl
-
Configures Jetty logging to use Java Commons Logging (JCL), using SLF4J as a binding.
- logging-jetty
-
Standard Jetty logging that captures
System.err
andSystem.out
output. - logging-jul
-
Configures Jetty logging to use Java Util Logging (JUL), using SLF4J as a binding.
- logging-log4j
-
Configures Jetty logging to use Log4j as the logging implementation, using SLF4J as a binding.
- logging-log4j2
-
Configures Jetty logging to use Log4j2 as the logging implementation, using SLF4J as a binding.
- logging-logback
-
Configures Jetty logging to use Logback as the logging implementation, using SLF4J as a binding.
- logging-slf4j
-
Configures Jetty logging to use SLF4J and provides a
slf4j-impl
which can be used by other logging frameworks. If no other logging is configured,slf4j-simple
is used.
You can view a list of all the Jetty logging modules by running java -jar <path-to-jetty.home>/start.jar --list-modules=logging
.
This will display all logging modules, including implementation and binding modules.
All these modules (with the exception of logging-jetty
) arrange for the Jetty private logging API to be routed to the named technology to actually be logged.
For example, enabling the logging-log4j
module will do several things:
-
it enables an internal Log4j API module so that any container code that uses Log4j will find the API.
-
it enables an internal Log4j Implementation so that any container code that uses the Log4j API will also use a Log4j implementation to handle the logs (and all the normal Log4j configuration mechanisms etc.)
-
it enables the internal
slf4j-log4j
logging binding so that any container code that uses the SLF4j API to also use the Log4j implementation via the Log4j API. -
it configures the Jetty logging API to use the SLF4J API, which is then bound to Log4j.
So, after enabling logging-log4j
, within the server container there are 3 logging APIs available: Jetty, SLF4J and Log4J.
But there is only a single logging implementation - Log4j; the 3 APIs act only as facades over the Log4j implementation.
Note that you can add additional APIs to this configuration.
For example, enabling the internal module jcl-slf4j
would add in a Java Commons Logging facade that also would use the Log4j implementation via the SLF4J binding.
Most other top level logging modules work in the same way: logging-jcl
, logging-jul
, logging-slf4j
, logging-log4j2
and logging-logback
all bind their implementation via SLF4J.
Logging with SLF4J
Jetty uses the SLF4J api as a binding to provide logging information to additional frameworks such as Log4j or Logback.
It can also be used on it’s own to provide simple server logging.
To enable the SLF4J framework, you need to activate the logging-slf4j
module.
[my-base]$ java -jar ../start.jar --add-to-start=logging-slf4j
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitively enabled
INFO : logging-slf4j initialized in ${jetty.base}/start.d/logging-slf4j.ini
MKDIR : ${jetty.base}/lib/slf4j
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
INFO : Base directory was modified
ERROR : Module logging-slf4j requires a module providing slf4j-impl from one of [slf4j-simple-impl, slf4j-logback, slf4j-jul, slf4j-log4j2, slf4j-log4j]
ERROR : Unsatisfied module dependencies: logging-slf4j
Usage: java -jar $JETTY_HOME/start.jar [options] [properties] [configs]
java -jar $JETTY_HOME/start.jar --help # for more information
As you probably noticed, the system gives an ERROR
when trying to enable the logging-slf4j
on it’s own.
The logging-slf4j
module itself provides the SLF4J api, but as SLF4J is often used as a binding for other logging frameworks does not by default provide an implementation.
To enable the simple SLF4J implementation, we will also need to activate the slf4j-simple-impl
module.
[my-base]$ java -jar ../start.jar --add-to-start=slf4j-simple-impl
INFO : slf4j-simple-impl initialized in ${jetty.base}/start.d/slf4j-simple-impl.ini
INFO : resources transitively enabled
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/1.7.21/slf4j-simple-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-simple-1.7.21.jar
MKDIR : ${jetty.base}/resources
COPY : ${jetty.home}/modules/slf4j-simple-impl/resources/simplelogger.properties to ${jetty.base}/resources/simplelogger.properties
INFO : Base directory was modified
[my-base]$ tree
.
├── lib
│ └── slf4j
│ ├── slf4j-api-1.7.21.jar
│ └── slf4j-simple-1.7.21.jar
├── resources
│ └── simplelogger.properties
└── start.d
├── logging-slf4j.ini
└── slf4j-simple-impl.ini
Jetty is now configured to log using the SLF4J framework.
A standard SLF4J properties file is located in ${jetty.base}/resources/simplelogger.properties
.
Logging with Log4j and Log4j2
It is possible to have the Jetty Server logging configured so that Log4j or Log4j2 controls the output of logging events produced by Jetty.
This is accomplished by configuring Jetty for logging to Apache Log4j via Slf4j and the Slf4j binding layer for Log4j.
Implementation of Log4j can be done by enabling the logging-log4j
module.
[my-base]$ java -jar ../start.jar --add-to-start=logging-log4j
ALERT: There are enabled module(s) with licenses.
The following 2 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: log4j-impl
+ Log4j is released under the Apache 2.0 license.
+ http://www.apache.org/licenses/LICENSE-2.0.html
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitively enabled
INFO : log4j-impl transitively enabled
INFO : resources transitively enabled
INFO : slf4j-log4j transitively enabled
INFO : logging-log4j initialized in ${jetty.base}/start.d/logging-log4j.ini
MKDIR : ${jetty.base}/lib/slf4j
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
MKDIR : ${jetty.base}/lib/log4j
COPY : /Users/admin/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar to ${jetty.base}/lib/log4j/log4j-1.2.17.jar
MKDIR : ${jetty.base}/resources
COPY : ${jetty.home}/modules/log4j-impl/resources/log4j.xml to ${jetty.base}/resources/log4j.xml
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-log4j12/1.7.21/slf4j-log4j12-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-log4j12-1.7.21.jar
INFO : Base directory was modified
[my-base]$ tree
.
├── lib
│ ├── log4j
│ │ └── log4j-1.2.17.jar
│ └── slf4j
│ ├── slf4j-api-1.7.21.jar
│ └── slf4j-log4j12-1.7.21.jar
├── resources
│ └── log4j.xml
└── start.d
└── logging-log4j.ini
Jetty is now configured to log using the Log4j framework.
A standard Log4j configuration file is located in ${jetty.base}/resources/log4j.xml
.
Or, to set up Log4j2, enable the logging-log4j2
module.
[my-base]$ java -jar ../start.jar --add-to-start=logging-log4j2
ALERT: There are enabled module(s) with licenses.
The following 2 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: log4j2-api
+ Log4j is released under the Apache 2.0 license.
+ http://www.apache.org/licenses/LICENSE-2.0.html
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitively enabled
INFO : logging-log4j2 initialized in ${jetty.base}/start.d/logging-log4j2.ini
INFO : log4j2-api transitively enabled
INFO : resources transitively enabled
INFO : slf4j-log4j2 transitively enabled
INFO : log4j2-impl transitively enabled
MKDIR : ${jetty.base}/lib/slf4j
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
MKDIR : ${jetty.base}/lib/log4j2
DOWNLD: https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-api/2.6.1/log4j-api-2.6.1.jar to ${jetty.base}/lib/log4j2/log4j-api-2.6.1.jar
MKDIR : ${jetty.base}/resources
DOWNLD: https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.6.1/log4j-slf4j-impl-2.6.1.jar to ${jetty.base}/lib/log4j2/log4j-slf4j-impl-2.6.1.jar
DOWNLD: https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-core/2.6.1/log4j-core-2.6.1.jar to ${jetty.base}/lib/log4j2/log4j-core-2.6.1.jar
COPY : ${jetty.home}/modules/log4j2-impl/resources/log4j2.xml to ${jetty.base}/resources/log4j2.xml
INFO : Base directory was modified
[my-base]$ tree
.
├── lib
│ ├── log4j2
│ │ ├── log4j-api-2.6.1.jar
│ │ ├── log4j-core-2.6.1.jar
│ │ └── log4j-slf4j-impl-2.6.1.jar
│ └── slf4j
│ └── slf4j-api-1.7.21.jar
├── resources
│ └── log4j2.xml
└── start.d
└── logging-log4j2.ini
At this point Jetty is configured so that the Jetty server itself will log using Log4j2, using the Log4j2 configuration found in {$jetty.base}/resources/log4j2.xml
.
Logging with Logback
It is possible to have the Jetty Server logging configured so that Logback controls the output of logging events produced by Jetty.
This is accomplished by configuring Jetty for logging to Logback
, which uses Slf4j and the Logback Implementation for Slf4j.
To set up Jetty logging via Logback, enable the logging-logback
module.
[my-base]$ java -jar ../start.jar --add-to-start=logging-logback
ALERT: There are enabled module(s) with licenses.
The following 2 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: logback-impl
+ Logback: the reliable, generic, fast and flexible logging framework.
+ Copyright (C) 1999-2012, QOS.ch. All rights reserved.
+ This program and the accompanying materials are dual-licensed under
+ either:
+ the terms of the Eclipse Public License v1.0
+ as published by the Eclipse Foundation:
+ http://www.eclipse.org/legal/epl-v10.html
+ or (per the licensee's choosing) under
+ the terms of the GNU Lesser General Public License version 2.1
+ as published by the Free Software Foundation:
+ http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitively enabled
INFO : logback-impl transitively enabled
INFO : slf4j-logback transitively enabled
INFO : logging-logback initialized in ${jetty.base}/start.d/logging-logback.ini
INFO : resources transitively enabled
MKDIR : ${jetty.base}/lib/slf4j
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
MKDIR : ${jetty.base}/lib/logback
DOWNLD: https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.1.7/logback-core-1.1.7.jar to ${jetty.base}/lib/logback/logback-core-1.1.7.jar
MKDIR : ${jetty.base}/resources
COPY : ${jetty.home}/modules/logback-impl/resources/logback.xml to ${jetty.base}/resources/logback.xml
DOWNLD: https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.1.7/logback-classic-1.1.7.jar to ${jetty.base}/lib/logback/logback-classic-1.1.7.jar
INFO : Base directory was modified
[my-base]$ tree
.
├── lib
│ ├── logback
│ │ ├── logback-classic-1.1.7.jar
│ │ └── logback-core-1.1.7.jar
│ └── slf4j
│ └── slf4j-api-1.7.21.jar
├── resources
│ └── logback.xml
└── start.d
└── logging-logback.ini
At this point Jetty is configured so that the Jetty server itself will log using Logback, using the Logback configuration found in {$jetty.base}/resources/logback.xml
.
Logging with Java Util Logging
Java Util Logging with SLF4J
It is possible to have the Jetty Server logging configured so that java.util.logging
controls the output of logging events produced by Jetty.
This example demonstrates how to configuring Jetty for logging to java.util.logging
via SLF4J as a binding layer.
[my-base]$ java -jar ../start.jar --add-to-start=logging-jul
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : jul-impl transitively enabled
INFO : slf4j-api transitively enabled
INFO : slf4j-jul transitively enabled
INFO : logging-jul initialized in ${jetty.base}/start.d/logging-jul.ini
INFO : resources transitively enabled
MKDIR : ${jetty.base}/etc
COPY : ${jetty.home}/modules/jul-impl/etc/java-util-logging.properties to ${jetty.base}/etc/java-util-logging.properties
MKDIR : ${jetty.base}/lib/slf4j
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-jdk14/1.7.21/slf4j-jdk14-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-jdk14-1.7.21.jar
INFO : Base directory was modified
[my-base]$ tree
.
├── etc
│ └── java-util-logging.properties
├── lib
│ └── slf4j
│ ├── slf4j-api-1.7.21.jar
│ └── slf4j-jdk14-1.7.21.jar
└── start.d
└── logging-jul.ini
Jetty is now configured to log using the JUL framework.
A standard JUL properties file is located in ${jetty.base}/etc/java-util-logging.properties
.
Capturing Console Output
By default, enabling the above modules will output log information to the console.
Included in the distribution is the console-capture
module, which can be used in lieu of additional configuration to the selected logging module to capture this output to a logs
directory in your ${jetty.base}
.
To enable this functionality, activate the console-capture
module.
[my-base]$ java -jar ../start.jar --add-to-start=console-capture
INFO : console-capture initialized in ${jetty.base}/start.d/console-capture.ini
MKDIR : ${jetty.base}/logs
INFO : Base directory was modified
[my-base]$ tree
.
├── logs
└── start.d
└── console-capture.ini
As an example, here is the output from Logback before using the console-capture
module:
[my-base]$ java -jar ../start.jar
419 [main] INFO org.eclipse.jetty.util.log - Logging initialized @508ms to org.eclipse.jetty.util.log.Slf4jLog
540 [main] INFO org.eclipse.jetty.server.Server - jetty-9.4.0-SNAPSHOT
575 [main] INFO o.e.jetty.server.AbstractConnector - Started ServerConnector@3c0ecd4b{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
575 [main] INFO org.eclipse.jetty.server.Server - Started @668ms
After enabling console-capture
, the output is as follows, which displays the location the log is being saved to:
[my-base]$ java -jar ../start.jar
151 [main] INFO org.eclipse.jetty.util.log - Logging initialized @238ms to org.eclipse.jetty.util.log.Slf4jLog
196 [main] INFO org.eclipse.jetty.util.log - Console stderr/stdout captured to /installs/jetty-distribution/mybase/logs/2016_10_21.jetty.log
Centralized Logging using Logback
The term Centralized Logging refers to a forced logging configuration for the Jetty Server and all web applications that are deployed on the server. It routes all logging events from the web applications to a single configuration on the Server side.
The example below shows how to accomplish this with Jetty and Slf4j, using Logback
to manage the final writing of logs to disk.
This mechanism forces all webapps to use the server’s configuration for logging, something that isn’t 100% appropriate for all webapps. An example would be having Jenkins-CI deployed as an webapp, if you force its logging configuration to the server side, you lose the ability on Jenkins-CI to see the logs from the various builds (as now those logs are actually going to the main server log). |
This configuration is essentially the multiple logger configuration with added configuration to the deployers to force a WebAppClassLoader
change to use the server classpath over the webapps classpath for the logger specific classes.
The technique used by this configuration is to provide an AppLifeCycle.Binding against the `"deploying"`node that modifies the WebAppContext.getSystemClasspathPattern().add(String) for the common logging classes. See org.eclipse.jetty.logging.CentralizedWebAppLoggingBinding for actual implementation.
A convenient replacement logging
module has been created to bootstrap your ${jetty.base}
directory for capturing all Jetty server logging from multiple logging frameworks into a single logging output file managed by Logback.
[mybase]$ curl -O https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-webapp-logging/9.4.27/jetty-webapp-logging-9.4.27-config.jar
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 3402 100 3402 0 0 15823 0 --:--:-- --:--:-- --:--:-- 15750
[mybase]$ jar -xf jetty-webapp-logging-9.4.27-config.jar
[mybase]$ java -jar /opt/jetty-hom/start.jar --create-startd --add-to-start=centralized-webapp-logging
ALERT: There are enabled module(s) with licenses.
The following 2 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: logback-impl
+ Logback: the reliable, generic, fast and flexible logging framework.
+ Copyright (C) 1999-2012, QOS.ch. All rights reserved.
+ This program and the accompanying materials are dual-licensed under
+ either:
+ the terms of the Eclipse Public License v1.0
+ as published by the Eclipse Foundation:
+ http://www.eclipse.org/legal/epl-v10.html
+ or (per the licensee's choosing) under
+ the terms of the GNU Lesser General Public License version 2.1
+ as published by the Free Software Foundation:
+ http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitively enabled
INFO : log4j-over-slf4j transitively enabled
INFO : jcl-slf4j transitively enabled
INFO : logback-impl transitively enabled
INFO : jul-slf4j transitively enabled
INFO : slf4j-logback transitively enabled
INFO : centralized-webapp-logging initialized in ${jetty.base}/start.d/centralized-webapp-logging.ini
INFO : logging-logback transitively enabled
INFO : resources transitively enabled
MKDIR : ${jetty.base}/lib/slf4j
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.25.jar
MKDIR : ${jetty.base}/lib/logging
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.7.25/log4j-over-slf4j-1.7.25.jar to ${jetty.base}/lib/logging/log4j-over-slf4j-1.7.25.jar
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.25/jcl-over-slf4j-1.7.25.jar to ${jetty.base}/lib/slf4j/jcl-over-slf4j-1.7.25.jar
MKDIR : ${jetty.base}/lib/logback
DOWNLD: https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar to ${jetty.base}/lib/logback/logback-core-1.2.3.jar
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar to ${jetty.base}/lib/slf4j/jul-to-slf4j-1.7.25.jar
COPY : ${jetty.home}/modules/jul-slf4j/etc/java-util-logging.properties to ${jetty.base}/etc/java-util-logging.properties
DOWNLD: https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar to ${jetty.base}/lib/logback/logback-classic-1.2.3.jar
MKDIR : ${jetty.base}/logs
DOWNLD: https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-webapp-logging/9.4.27/jetty-webapp-logging-9.4.27.jar to ${jetty.base}/lib/logging/jetty-webapp-logging-9.4.27.jar
INFO : Base directory was modified
$
This replacement centralized-webapp-logging.mod
performs a number of tasks.
-
mybase
is a${jetty.base}
directory. -
The jetty-distribution is unpacked (and untouched) into
/opt/jetty-dist/
and becomes the${jetty.home}
directory for this demonstration. -
The
curl
command downloads the replacement config overlay for the${jetty.base}/modules/
directory to use. -
The
start.jar --add-to-start=centralized-webapp-logging
command performs a number of steps to make the centralized-webapp-logging module available to the${jetty.base}
configuration.-
A new
${jetty.base}/start.d/centralized-webapp-logging.ini
configuration was created. -
Required
${jetty.base}
directories are created:${jetty.base}/logs
and${jetty.base}/resources
. -
Required logging libraries are downloaded (if not present already) to the
${jetty.base}/lib/logging/
directory:-
slf4j-api.jar
- API jar for Slf4j (used by most of the rest of the jars) -
log4j-over-slf4j.jar
- Slf4j jar that captures all log4j emitted logging events -
jul-to-slf4j.jar
- Slf4j jar that captures all java.util.logging events -
jcl-over-slf4j.jar
- Slf4j jar that captures all commons-logging events -
logback-classic.jar
- the Slf4j adapter jar that routes all of the captured logging events to logback itself. -
logback-core.jar
- the logback implementation jar, that handles all of the filtering and output of the logging events.
-
-
Required webapp-logging library is downloaded (if not present already) to the
${jetty.base}/lib/webapp-logging/
directory:-
jetty-webapp-logging.jar
- the Jetty side deployment manger app-lifecycle bindings for modifying theWebAppClassloaders
of deployed webapps.
-
-
At this point the Jetty mybase
is configured so that the jetty server itself will log using slf4j, and all other logging events from other Jetty Server components (such as database drivers, security layers, jsp, mail, and other 3rd party server components) are routed to logback for filtering and output.
All webapps deployed via the DeploymentManager
have their WebAppClassLoader
modified to use server side classes and configuration for all logging implementations.
The server classpath can be verified by using the start.jar --list-config
command.
In essence, Jetty is now configured to emit its own logging events to slf4j, and various slf4j bridge jars are acting on behalf of log4j
, java.util.logging
, and commons-logging
, routing all of the logging events to logback
(a slf4j implementation) for routing (to console, file, etc…).
Jetty Server Dump
The dump feature in Jetty provides a snapshot of the bean containment tree of the main Jetty components together with a summary of their configuration. This includes threadpool, connectors, contexts, webapplications, servlets and so forth.
Configuring the Jetty Server Dump
You can request that Jetty do a dump immediately after starting and just before stopping by calling the appropriate setters on the Server
instance.
For embedded usage this can be used by calling the setters directly.
server.setDumpAfterStart(true);
server.setDumpBeforeStop(true);
Standalone Jetty uses two properties to control this behaviour which are referenced in jetty.xml
to call these setters.
These properties are jetty.server.dumpAfterStart
and jetty.server.dumpBeforeStop
.
These can be temporarily enabled by supplying these properties as command line arguments,
or they can be enabled via the server.ini
file (see An Introduction to Jetty Configuration).
java -jar $JETTY_HOME/start.jar jetty.server.dumpAfterStart=true jetty.server.dumpBeforeStop=true
Extra ThreadPool Information
To get maximum detail from the QueuedThreadPool
in the dump, you need to setDetailDump(true)
on any instances of QueuedThreadPool
you are using.
This extra detail in the detailed dump consists of full stack traces for every running thread, and a list of queued jobs waiting to be run.
For embedded usage this can be used by calling the setters directly.
threadPool.setDetailedDump(true);
For standalone jetty you can enable the threadpool
module and configure the jetty.threadPool.detailedDump
property.
See Managing Startup Modules for information on how to enable a module.
This same property can also be set via the command line the same as the server dump property.
Using the Dump Feature via JMX
The dump
method is on the Server instance and many of its nested components (Handlers, Connectors, and so forth).
Dumps may be obtained by calling these methods either in code or via JMX (see Using JMX with Jetty).
The Server MBean has a dump()
method, which dumps everything, plus a dumpStdErr()
operation that dumps to StdErr rather than replying to JConsole.
Explanation of the Dump Key
-
+- bean
is a java POJO that is contained by the parent object as a bean added with the addBean method. -
+= managed
is a bean that is also a LifeCycle that is started and stopped with the parent object. -
+~ unmanaged
is a bean that is also a LifeCycle that is started and stopped with the parent object. It is typically shared with other objects (hence its children are not dumped). -
+? auto
is a bean that has been added to an unstarted parent. If it is a LifeCycle that is not started when the parent is started, then it is started and becomes a managed bean, otherwise it becomes either unmanaged or just a bean. -
+: iterable
is an object that is contained within an iterable field of the parent (eg a list, set etc). -
+] array
is an object that is contained within an array field of the parent. -
+@ map
is an object that is contained within an map field of the parent. -
+> undefined
is an object that is contained within the parent by an undefined relationship.
Jetty Server Dump Example
This is a dump of the OneServletContext embedded example with extra threadpool information:
Server@59906517{STARTED}[9.4.32-SNAPSHOT] - STARTED += QueuedThreadPool[qtp488044861]@1d16f93d{STARTED,8<=8<=200,i=2,r=4,q=0}[ReservedThreadExecutor@16267862{s=2/4,p=0}] - STARTED | += ReservedThreadExecutor@16267862{s=2/4,p=0} - STARTED | +> threads size=8 | | +> qtp488044861-13 RUNNABLE tid=13 prio=5 SELECTING | | +> qtp488044861-15-acceptor-0@296e0338-ServerConnector@1e6d1014{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} RUNNABLE tid=15 prio=3 ACCEPTING | | +> qtp488044861-17 TIMED_WAITING tid=17 prio=5 RESERVED | | +> qtp488044861-19 RUNNABLE tid=19 prio=5 | | | +> app//org.eclipse.jetty.http.pathmap.PathMappings.getMatch(PathMappings.java:130) | | | +> app//org.eclipse.jetty.servlet.ServletHandler.getMappedServlet(ServletHandler.java:591) | | | +> app//org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:474) | | | +> app//org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1582) | | | +> app//org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) | | | +> app//org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349) | | | +> app//org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) | | | +> app//org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) | | | +> app//org.eclipse.jetty.server.Server.handle(Server.java:516) | | | +> app//org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383) | | | +> app//org.eclipse.jetty.server.HttpChannel$$Lambda$102/0x000000010016d440.dispatch(Unknown Source) | | | +> app//org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:556) | | | +> app//org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375) | | | +> app//org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273) | | | +> app//org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) | | | +> app//org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) | | | +> app//org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) | | | +> app//org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) | | | +> app//org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) | | | +> app//org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) | | | +> app//org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) | | | +> app//org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:375) | | | +> app//org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:773) | | | +> app//org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:905) | | | +> java.base@11.0.5/java.lang.Thread.run(Thread.java:834) | | +> qtp488044861-16 TIMED_WAITING tid=16 prio=5 RESERVED | | +> qtp488044861-21 RUNNABLE tid=21 prio=5 SELECTING | | +> qtp488044861-18 TIMED_WAITING tid=18 prio=5 IDLE | | +> qtp488044861-14 TIMED_WAITING tid=14 prio=5 IDLE | +> jobs size=0 += ServerConnector@1e6d1014{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} - STARTED | +~ Server@59906517{STARTED}[9.4.32-SNAPSHOT] - STARTED | +~ QueuedThreadPool[qtp488044861]@1d16f93d{STARTED,8<=8<=200,i=2,r=4,q=0}[ReservedThreadExecutor@16267862{s=2/4,p=0}] - STARTED | += ScheduledExecutorScheduler@453da22c{STARTED} - STARTED | | +> java.base@11.0.5/jdk.internal.misc.Unsafe.park(Native Method) | | +> java.base@11.0.5/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234) | | +> java.base@11.0.5/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2123) | | +> java.base@11.0.5/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1182) | | +> java.base@11.0.5/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899) | | +> java.base@11.0.5/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1054) | | +> java.base@11.0.5/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1114) | | +> java.base@11.0.5/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) | | +> java.base@11.0.5/java.lang.Thread.run(Thread.java:834) | +- org.eclipse.jetty.io.ArrayByteBufferPool@71248c21 | += HttpConnectionFactory@3fd7a715[HTTP/1.1] - STARTED | | +- HttpConfiguration@442675e1{32768/8192,8192/8192,https://:0,[]} | | +> customizers size=0 | | +> formEncodedMethods size=2 | | | +> POST | | | +> PUT | | +> outputBufferSize=32768 | | +> outputAggregationSize=8192 | | +> requestHeaderSize=8192 | | +> responseHeaderSize=8192 | | +> headerCacheSize=1024 | | +> secureScheme=https | | +> securePort=0 | | +> idleTimeout=-1 | | +> blockingTimeout=-1 | | +> sendDateHeader=true | | +> sendServerVersion=true | | +> sendXPoweredBy=false | | +> delayDispatchUntilContent=true | | +> persistentConnectionsEnabled=true | | +> maxErrorDispatches=10 | | +> minRequestDataRate=0 | | +> minResponseDataRate=0 | | +> cookieCompliance=RFC6265 | | +> setRequestCookieCompliance=RFC6265 | | +> notifyRemoteAsyncErrors=true | | +> relativeRedirectAllowed=false | += SelectorManager@ServerConnector@1e6d1014{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} - STARTED | | += ManagedSelector@38364841{STARTED} id=0 keys=0 selected=0 updates=0 - STARTED | | | += EatWhatYouKill@28c4711c/SelectorProducer@59717824/PRODUCING/p=false/QueuedThreadPool[qtp488044861]@1d16f93d{STARTED,8<=8<=200,i=2,r=4,q=0}[ReservedThreadExecutor@16267862{s=2/4,p=0}][pc=0,pic=0,pec=0,epc=0]@2020-09-04T10:57:20.077669+10:00 - STARTED | | | | +- SelectorProducer@59717824 | | | | +~ QueuedThreadPool[qtp488044861]@1d16f93d{STARTED,8<=8<=200,i=2,r=4,q=0}[ReservedThreadExecutor@16267862{s=2/4,p=0}] - STARTED | | | +> updates @ 2020-09-04T10:57:20.058489+10:00 size=0 | | | +> keys @ 2020-09-04T10:57:20.061714+10:00 size=0 | | += ManagedSelector@146044d7{STARTED} id=1 keys=1 selected=0 updates=0 - STARTED | | += EatWhatYouKill@1e9e725a/SelectorProducer@15d9bc04/PRODUCING/p=false/QueuedThreadPool[qtp488044861]@1d16f93d{STARTED,8<=8<=200,i=2,r=4,q=0}[ReservedThreadExecutor@16267862{s=2/4,p=0}][pc=0,pic=0,pec=1,epc=14]@2020-09-04T10:57:20.082696+10:00 - STARTED | | | +- SelectorProducer@15d9bc04 | | | +~ QueuedThreadPool[qtp488044861]@1d16f93d{STARTED,8<=8<=200,i=2,r=4,q=0}[ReservedThreadExecutor@16267862{s=2/4,p=0}] - STARTED | | +> updates @ 2020-09-04T10:57:20.078661+10:00 size=0 | | +> keys @ 2020-09-04T10:57:20.082035+10:00 size=1 | | +> SelectionKey@74bb45ed{i=0}->SocketChannelEndPoint@569ef11f{l=/127.0.0.1:8080,r=/127.0.0.1:58702,OPEN,fill=-,flush=-,to=3/30000}{io=0/0,kio=0,kro=1}->HttpConnection@25b03990[p=HttpParser{s=CONTENT,0 of -1},g=HttpGenerator@218fb9fe{s=START}]=>HttpChannelOverHttp@648d33ab{s=HttpChannelState@717b7e16{s=HANDLING rs=BLOCKING os=OPEN is=IDLE awp=false se=false i=true al=0},r=54,c=false/false,a=HANDLING,uri=//localhost:8080/,age=4} | +- sun.nio.ch.ServerSocketChannelImpl[/0:0:0:0:0:0:0:0:8080] | +- qtp488044861-15-acceptor-0@296e0338-ServerConnector@1e6d1014{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} += AttributeContainerMap@473b46c3{size=0} - STARTED += o.e.j.s.ServletContextHandler@3ffcd140{/,file:///tmp/,AVAILABLE} - STARTED | += org.eclipse.jetty.server.session.SessionHandler1089504328==dftMaxIdleSec=-1 - STARTED | | += ServletHandler@516be40f{STARTED} - STARTED | | | +> listeners ServletHandler@516be40f{STARTED} size=2 | | | | +> ListenerHolder@3c0a50da{STARTED}: org.eclipse.jetty.embedded.OneServletContext$InitListener - STARTED | | | | +> ListenerHolder@646be2c3{STARTED}: org.eclipse.jetty.embedded.OneServletContext$RequestListener - STARTED | | | +> filters ServletHandler@516be40f{STARTED} size=2 | | | | +> org.eclipse.jetty.embedded.OneServletContext$TestFilter-e874448@e874448==org.eclipse.jetty.embedded.OneServletContext$TestFilter,inst=true,async=true - STARTED | | | | | +> org.eclipse.jetty.embedded.OneServletContext$TestFilter@797badd3 | | | | +> org.eclipse.jetty.embedded.OneServletContext$TestFilter-60285225@60285225==org.eclipse.jetty.embedded.OneServletContext$TestFilter,inst=true,async=true - STARTED | | | | +> org.eclipse.jetty.embedded.OneServletContext$TestFilter@77be656f | | | +> filterMappings ServletHandler@516be40f{STARTED} size=2 | | | | +> [/test/*]/[]/[REQUEST]=>org.eclipse.jetty.embedded.OneServletContext$TestFilter-e874448 | | | | +> [*.test]/[]/[ASYNC, REQUEST]=>org.eclipse.jetty.embedded.OneServletContext$TestFilter-60285225 | | | +> servlets ServletHandler@516be40f{STARTED} size=3 | | | | +> org.eclipse.jetty.embedded.HelloServlet-58c1670b@d20bf05b==org.eclipse.jetty.embedded.HelloServlet,jsp=null,order=-1,inst=false,async=true - STARTED | | | | | +> class org.eclipse.jetty.embedded.HelloServlet | | | | +> debug@5b09653==org.eclipse.jetty.embedded.DumpServlet,jsp=null,order=-1,inst=false,async=true - STARTED | | | | | +> class org.eclipse.jetty.embedded.DumpServlet | | | | +> org.eclipse.jetty.servlet.DefaultServlet-6b9651f3@8eb381d1==org.eclipse.jetty.servlet.DefaultServlet,jsp=null,order=-1,inst=true,async=true - STARTED | | | | +> org.eclipse.jetty.servlet.DefaultServlet@78a2da20 | | | +> servletMappings ServletHandler@516be40f{STARTED} size=4 | | | +> [/hello/*]=>org.eclipse.jetty.embedded.HelloServlet-58c1670b | | | +> [/dump/*]=>debug | | | +> [*.dump]=>debug | | | +> [/]=>org.eclipse.jetty.servlet.DefaultServlet-6b9651f3 | | += org.eclipse.jetty.server.session.DefaultSessionCache@dd3b207[evict=-1,removeUnloadable=false,saveOnCreate=false,saveOnInactiveEvict=false] - STARTED | | | += org.eclipse.jetty.server.session.NullSessionDataStore@551bdc27[passivating=false,graceSec=3600] - STARTED | | +~ DefaultSessionIdManager@58fdd99{STARTED}[worker=node0] - STARTED | +> No ClassLoader | +> eventListeners o.e.j.s.ServletContextHandler@3ffcd140{/,file:///tmp/,AVAILABLE} size=2 | | +> org.eclipse.jetty.embedded.OneServletContext$InitListener@6b1274d2 | | +> org.eclipse.jetty.embedded.OneServletContext$RequestListener@7bc1a03d | +> handler attributes o.e.j.s.ServletContextHandler@3ffcd140{/,file:///tmp/,AVAILABLE} size=1 | | +> org.eclipse.jetty.server.Executor=QueuedThreadPool[qtp488044861]@1d16f93d{STARTED,8<=8<=200,i=2,r=4,q=0}[ReservedThreadExecutor@16267862{s=2/4,p=0}] | +> context attributes o.e.j.s.ServletContextHandler@3ffcd140{/,file:///tmp/,AVAILABLE} size=2 | | +> org.eclipse.jetty.util.DecoratedObjectFactory=org.eclipse.jetty.util.DecoratedObjectFactory[decorators=1] | | +> X-Init=true | +> initparams o.e.j.s.ServletContextHandler@3ffcd140{/,file:///tmp/,AVAILABLE} size=0 += ErrorHandler@ba8d91c{STARTED} - STARTED += DefaultSessionIdManager@58fdd99{STARTED}[worker=node0] - STARTED | += HouseKeeper@60438a68{STARTED}[interval=660000, ownscheduler=true] - STARTED +> jdk.internal.loader.ClassLoaders$AppClassLoader@2c13da15 +> jdk.internal.loader.ClassLoaders$PlatformClassLoader@7364985f key: +- bean, += managed, +~ unmanaged, +? auto, +: iterable, +] array, +@ map, +> undefined
Configuring JNDI
Jetty supports java:comp/env
lookups in webapps.
This is an optional feature for which some configuration is required.
Quick Setup
If you are using the standard distribution of Jetty, you must enable the JNDI module to obtain Jetty’s JNDI implementation, and the plus module which provides classes for interacting with JNDI.
As the plus module depends on the JNDI module, you only need to enable the plus module to enable both.
Assuming you have Jetty installed in /opt/jetty
, and you have made a jetty base in /opt/jetty/my-base
, do:
cd /opt/jetty
cd my-base
java -jar $JETTY_HOME/start.jar --add-to-start=plus
You can now start Jetty and use JNDI within your webapps. See Using JNDI for information on how to add entries to the JNDI environment that Jetty can look up within webapps.
If you have extra jars associated with your JNDI resources, for example a database driver jar, and you haven’t made a custom module for it, you can put the jars into your {$jetty base}ext/
directory.
You will then need to enable the ext module to ensure the jars in the ext/
directory are on the classpath.
Assuming you have Jetty installed in /opt/jetty
, and you have made a jetty base in /opt/jetty/my-base
, do:
cd /opt/jetty
cd my-base
java -jar $JETTY_HOME/start.jar --add-to-start=ext
Working with Jetty JNDI
Defining the web.xml
You can configure naming resources to reference in a web.xml
file and access from within the java:comp/env
naming environment of the webapp during execution.
Specifically, you can configure support for the following web.xml
elements:
<env-entry/>
<resource-ref/>
<resource-env-ref/>
Configuring env-entries shows you how to set up overrides for env-entry
elements in web.xml
, while Configuring resource-refs
and resource-env-refs
discusses how to configure support resources such as javax.sql.DataSource
.
You can also plug a JTA javax.transaction.UserTransaction
implementation into Jetty so that webapps can look up java:comp/UserTransaction
to obtain a distributed transaction manager: see Configuring XA Transactions.
Declaring Resources
You must declare the objects you want bound into the Jetty environment so that you can then hook into your webapp via env-entry
, resource-ref
and resource-env-refs
in web.xml
.
You create these bindings by using declarations of the following types:
org.eclipse.jetty.plus.jndi.EnvEntry
-
For
env-entry
type of entries org.eclipse.jetty.plus.jndi.Resource
-
For all other type of resources
org.eclipse.jetty.plus.jndi.Transaction
-
For a JTA manager
org.eclipse.jetty.plus.jndi.Link
-
For the link between a
web.xml
resource name and a naming entry
Declarations of each of these types follow the same general pattern:
<New class="org.eclipse.jetty.plus.jndi.xxxx">
<Arg><!-- scope --></Arg>
<Arg><!-- name --></Arg>
<Arg><!-- value --></Arg>
</New>
You can place these declarations into three different files, depending on your needs and the scope of the resources being declared.
Deciding Where to Declare Resources
You can define naming resources in three places:
- jetty.xml
-
Naming resources defined in a
jetty.xml
file are scoped at either the JVM level or the Server level. The classes for the resource must be visible at the Jetty container level. If the classes for the resource only exist inside your webapp, you must declare it in aWEB-INF/jetty-env.xml
file. - WEB-INF/jetty-env.xml
-
Naming resources in a
WEB-INF/jetty-env.xml
file are scoped to the web app in which the file resides. While you can enter JVM or Server scopes if you choose, we do not recommend doing so. The resources defined here may use classes from inside your webapp. This is a Jetty-specific mechanism. - Context xml file
-
Entries in a context xml file should be scoped at the level of the webapp to which they apply, although you can supply a less strict scoping level of Server or JVM if you choose. As with resources declared in a
jetty.xml
file, classes associated with the resource must be visible on the container’s classpath.
Scope of Resource Names
Naming resources within Jetty belong to one of three different scopes, in increasing order of restrictiveness:
- JVM scope
-
The name is unique across the JVM instance, and is visible to all application code. You represent this scope by a
null
first parameter to the resource declaration. For example:<New id="cf" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg></Arg> <!-- empty arg --> <Arg>jms/connectionFactory</Arg> <Arg> <New class="org.apache.activemq.ActiveMQConnectionFactory"> <Arg>vm://localhost?broker.persistent=false</Arg> </New> </Arg> </New>
- Server scope
-
The name is unique to a Server instance, and is only visible to code associated with that instance. You represent this scope by referencing the Server instance as the first parameter to the resource declaration. For example:
<Configure id="Server" class="org.eclipse.jetty.Server"> <New id="cf" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref refid="Server"/></Arg> <!-- reference to Server instance --> <Arg>jms/connectionFactory</Arg> <Arg> <New class="org.apache.activemq.ActiveMQConnectionFactory"> <Arg>vm://localhost?broker.persistent=false</Arg> </New> </Arg> </New> </Configure>
- Webapp scope
-
The name is unique to the WebAppContext instance, and is only visible to code associated with that instance. You represent this scope by referencing the
WebAppContext
instance as the first parameter to the resource declaration. For example:<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> <New id="cf" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref refid='wac'/></Arg> <!-- reference to WebAppContext --> <Arg>jms/connectionFactory</Arg> <Arg> <New class="org.apache.activemq.ActiveMQConnectionFactory"> <Arg>vm://localhost?broker.persistent=false</Arg> </New> </Arg> </New> </Configure>
What Can Be Bound as a Resource?
You can bind four types of objects into a Jetty JNDI reference:
-
An ordinary POJO instance.
-
A javax.naming.Reference instance.
-
An object instance that implements the javax.naming.Referenceable interface.
-
A link between a name as referenced in
web.xml
and as referenced in the Jetty environment.
Configuring JNDI
Configuring JNDI env-entries
Sometimes it is useful to pass configuration information to a webapp 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 even override an entry of the same name in web.xml
.
<New class="org.eclipse.jetty.plus.jndi.EnvEntry">
<Arg></Arg>
<Arg>mySpecialValue</Arg>
<Arg type="java.lang.Integer">4000</Arg>
<Arg type="boolean">true</Arg>
</New>
This example defines a virtual env-entry
called mySpecialValue
with value 4000
that is scoped to the JVM.
It is put into JNDI at java:comp/env/mySpecialValue
for every web app deployed.
Moreover, the boolean argument indicates that this value overrides an env-entry
of the same name in web.xml
.
If you don’t want to override, omit this 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
That being said, Jetty is a little more flexible and allows you to also bind custom POJOs, javax.naming.References
and javax.naming.Referenceables
.
Be aware that if you take advantage of this feature, your web application is not portable.
To use the env-entry
configured above, use code in your servlet/filter/etc.
, such as:
import javax.naming.InitialContext;
public class MyClass {
public void myMethod() {
InitialContext ic = new InitialContext();
Integer mySpecialValue = (Integer)ic.lookup("java:comp/env/mySpecialValue");
...
}
}
Configuring resource-refs and resource-env-refs
You can configure any type of resource that you want to refer to in a web.xml
file as a resource-ref
or resource-env-ref
, 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 a POJO instance or a javax.naming.Reference
instance or javax.naming.Referenceable
instance.
The J2EE Specification recommends storing DataSources in java:comp/env/jdbc
, JMS connection factories under java:comp/env/jms
, JavaMail connection factories under java:comp/env/mail
and URL connection factories under java:comp/env/url
.
For example:
Resource Type | Name in jetty.xml |
Environment Lookup |
---|---|---|
javax.sql.DataSource |
jdbc/myDB |
java:comp/env/jdbc/myDB |
javax.jms.QueueConnectionFactory |
jms/myQueue |
java:comp/env/jms/myQueue |
javax.mail.Session |
mail/myMailService |
java:comp/env/mail/myMailService |
Configuring DataSources
Here is an example of configuring a javax.sql.DataSource
.
Jetty can use any DataSource implementation available on its classpath.
In this example, the DataSource is from the Derby relational database, but you can use any implementation of a javax.sql.DataSource
.
This example configures it as scoped to a web app with the id of wac:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
<New id="myds" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid="wac"/></Arg>
<Arg>jdbc/myds</Arg>
<Arg>
<New class="org.apache.derby.jdbc.EmbeddedDataSource">
<Set name="DatabaseName">test</Set>
<Set name="createDatabase">create</Set>
</New>
</Arg>
</New>
</Configure>
The code above creates an instance of org.apache.derby.jdbc.EmbeddedDataSource
, calls the two setter methods setDatabaseName("test"),
and setCreateDatabase("create"),
and binds it into the JNDI scope for the web app.
If you do not have the appropriate resource-ref
set up in your web.xml
, it is available from application lookups as java:comp/env/jdbc/myds
.
Here’s an example web.xml
declaration for the datasource above:
<resource-ref>
<res-ref-name>jdbc/myds</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
To look up your DataSource in your servlet/filter/etc.
:
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class MyClass {
public void myMethod() {
InitialContext ic = new InitialContext();
DataSource myDS = (DataSource)ic.lookup("java:comp/env/jdbc/myds");
...
}
}
Careful! When configuring Resources, ensure that the type of object you configure matches the type of object you expect to look up in |
For more examples of datasource configurations, see Datasource Examples.
Configuring JMS Queues, Topics and ConnectionFactories
Jetty can bind any implementation of the JMS destinations and connection factories. You just need to ensure the implementation Jars are available on Jetty’s classpath. Here is an example of binding an ActiveMQ in-JVM connection factory:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
<New id="cf" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid='wac'/></Arg>
<Arg>jms/connectionFactory</Arg>
<Arg>
<New class="org.apache.activemq.ActiveMQConnectionFactory">
<Arg>vm://localhost?broker.persistent=false</Arg>
</New>
</Arg>
</New>
</Configure>
The entry in web.xml
would be:
<resource-ref>
<res-ref-name>jms/connectionFactory</res-ref-name>
<res-type>javax.jms.ConnectionFactory</res-type>
<res-auth>Container</res-auth>
</resource-ref>
TODO: put in an example of a QUEUE from progress demo
Configuring Mail
Jetty also provides infrastructure for access to javax.mail.Sessions
from within an application:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
<New id="mail" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid="wac"/></Arg>
<Arg>mail/Session</Arg>
<Arg>
<New class="org.eclipse.jetty.jndi.factories.MailSessionReference">
<Set name="user">fred</Set>
<Set name="password">OBF:1xmk1w261z0f1w1c1xmq</Set>
<Set name="properties">
<New class="java.util.Properties">
<Put name="mail.smtp.host">XXX</Put>
<Put name="mail.from">me@me</Put>
<Put name="mail.debug">true</Put>
</New>
</Set>
</New>
</Arg>
</New>
</Configure>
This setup creates an instance of the org.eclipse.jetty.jndi.factories.MailSessionReference
class, calls it’s setter methods to set up the authentication for the mail system, and populates a set of Properties, setting them on the MailSessionReference
instance.
The result is that an application can look up java:comp/env/mail/Session
at runtime and obtain access to a javax.mail.Session
that has the necessary configuration to permit it to send email via SMTP.
You can set the password to be plain text, or use Jetty’s Secure Password Obfuscation (OBF:) mechanism to make the config file a little more secure from prying eyes. Remember that you cannot use the other Jetty encryption mechanisms of MD5 and Crypt because they do not allow you to recover the original password, which the mail system requires. |
Configuring XA Transactions
If you want to perform distributed transactions with your resources, you need a transaction manager that supports the JTA interfaces, and that you can look up as java:comp/UserTransaction
in your webapp.
Jetty does not ship with one as standard, but you can plug in the one you prefer.
You can configure a transaction manager using the JNDI Transaction object in a Jetty config file.
The following example configures the Atomikos transaction manager:
<New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction">
<Arg>
<New class="com.atomikos.icatch.jta.J2eeUserTransaction"/>
</Arg>
</New>
Configuring Links
Generally, the name you set for your Resource
should be the same name you use for it in web.xml
.
For example:
In a context xml file:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
<New id="myds" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid="wac"/></Arg>
<Arg>jdbc/mydatasource</Arg>
<Arg>
<New class="org.apache.derby.jdbc.EmbeddedDataSource">
<Set name="DatabaseName">test</Set>
<Set name="createDatabase">create</Set>
</New>
</Arg>
</New>
</Configure>
In a web.xml
file:
<resource-ref>
<res-ref-name>jdbc/mydatasource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<injection-target>
<injection-target-class>com.acme.JNDITest</injection-target-class>
<injection-target-name>myDatasource</injection-target-name>
</injection-target>
</resource-ref>
However, you can refer to it in web.xml
by a different name, and link it to the name in your org.eclipse.jetty.plus.jndi.Resource
by using an org.eclipse.jetty.plus.jndi.Link
.
For the example above, you can refer to the jdbc/mydatasource
resource as jdbc/mydatasource1
as follows:
In a context xml file declare jdbc/mydatasource
:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
<New id="myds" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid="wac"/></Arg>
<Arg>jdbc/mydatasource</Arg>
<Arg>
<New class="org.apache.derby.jdbc.EmbeddedDataSource">
<Set name="DatabaseName">test</Set>
<Set name="createDatabase">create</Set>
</New>
</Arg>
</New>
</Configure>
Then in a WEB-INF/jetty-env.xml
file, link the name jdbc/mydatasource
to the name you want to reference it as in
web.xml
, which in this case is jdbc/mydatasource1
:
<New id="map1" class="org.eclipse.jetty.plus.jndi.Link">
<Arg><Ref refid='wac'/></Arg>
<Arg>jdbc/mydatasource1</Arg> <!-- name in web.xml -->
<Arg>jdbc/mydatasource</Arg> <!-- name in container environment -->
</New>
Now you can refer to jdbc/mydatasource1
in the web.xml
like this:
<resource-ref>
<res-ref-name>jdbc/mydatasource1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<injection-target>
<injection-target-class>com.acme.JNDITest</injection-target-class>
<injection-target-name>myDatasource</injection-target-name>
</injection-target>
</resource-ref>
This can be useful when you cannot change a JNDI resource directly in the web.xml
but need to link it to a specific resource in your deployment environment.
Using JNDI with Jetty Embedded
Setting up the Classpath
In addition to the jars that you require for your application, and the jars needed for core Jetty, you will need to place the following jars onto your classpath:
jetty-jndi.jar jetty-plus.jar
If you are using transactions, you will also need the javax.transaction
api.
You can obtain this jar here.
If you wish to use mail, you will also need the javax.mail
api and implementation which you can download here.
Note that this jar also requires the javax.activation
classes, which is available at this link.
Example Code
Here is an example class that sets up some JNDI entries and deploys a webapp that references these JNDI entries in code. We’ll use some mocked up classes for the transaction manager and the DataSource in this example for simplicity:
import java.util.Properties;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* ServerWithJNDI
*
*
*/
public class ServerWithJNDI
{
public static void main(String[] args) throws Exception
{
//Create the server
Server server = new Server(8080);
//Enable parsing of jndi-related parts of web.xml and jetty-env.xml
org.eclipse.jetty.webapp.Configuration.ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration");
//Create a WebApp
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setWar("./my-foo-webapp.war");
server.setHandler(webapp);
//Register new transaction manager in JNDI
//At runtime, the webapp accesses this as java:comp/UserTransaction
org.eclipse.jetty.plus.jndi.Transaction transactionMgr = new org.eclipse.jetty.plus.jndi.Transaction(new com.acme.MockUserTransaction());
//Define an env entry with Server scope.
//At runtime, the webapp accesses this as java:comp/env/woggle
//This is equivalent to putting an env-entry in web.xml:
//<env-entry>
// <env-entry-name>woggle</env-entry-name>
// <env-entry-type>java.lang.Integer</env-entry-type>
// <env-entry-value>4000</env-entry-value>
//</env-entry>
org.eclipse.jetty.plus.jndi.EnvEntry woggle = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "woggle", new Integer(4000), false);
//Define an env entry with webapp scope.
//At runtime, the webapp accesses this as java:comp/env/wiggle
//This is equivalent to putting a web.xml entry in web.xml:
//<env-entry>
// <env-entry-name>wiggle</env-entry-name>
// <env-entry-value>100</env-entry-value>
// <env-entry-type>java.lang.Double</env-entry-type>
//</env-entry>
//Note that the last arg of "true" means that this definition for "wiggle" would override an entry of the
//same name in web.xml
org.eclipse.jetty.plus.jndi.EnvEntry wiggle = new org.eclipse.jetty.plus.jndi.EnvEntry(webapp, "wiggle", new Double(100), true);
//Register a reference to a mail service scoped to the webapp.
//This must be linked to the webapp by an entry in web.xml:
// <resource-ref>
// <res-ref-name>mail/Session</res-ref-name>
// <res-type>javax.mail.Session</res-type>
// <res-auth>Container</res-auth>
// </resource-ref>
//At runtime the webapp accesses this as java:comp/env/mail/Session
org.eclipse.jetty.jndi.factories.MailSessionReference mailref = new org.eclipse.jetty.jndi.factories.MailSessionReference();
mailref.setUser("CHANGE-ME");
mailref.setPassword("CHANGE-ME");
Properties props = new Properties();
props.put("mail.smtp.auth", "false");
props.put("mail.smtp.host","CHANGE-ME");
props.put("mail.from","CHANGE-ME");
props.put("mail.debug", "false");
mailref.setProperties(props);
org.eclipse.jetty.plus.jndi.Resource xxxmail = new org.eclipse.jetty.plus.jndi.Resource(webapp, "mail/Session", mailref);
// Register a mock DataSource scoped to the webapp
//This must be linked to the webapp via an entry in web.xml:
//<resource-ref>
// <res-ref-name>jdbc/mydatasource</res-ref-name>
// <res-type>javax.sql.DataSource</res-type>
// <res-auth>Container</res-auth>
//</resource-ref>
//At runtime the webapp accesses this as java:comp/env/jdbc/mydatasource
org.eclipse.jetty.plus.jndi.Resource mydatasource = new org.eclipse.jetty.plus.jndi.Resource(webapp, "jdbc/mydatasource",
new com.acme.MockDataSource());
server.start();
server.join();
}
}
Datasource Examples
Here are examples of configuring a JNDI datasource for various databases.
Read Configuring DataSources in Configuring JNDI for more information about configuring datasources. |
All of these examples correspond to a resource-ref
in web.xml
.
<resource-ref>
<description>My DataSource Reference</description>
<res-ref-name>jdbc/DSTest</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
These examples assume that all of the datasources are declared at the JVM scope, but you can use other scopes if desired.
You can configure all JNDI resources in a jetty.xml
file, a WEB-INF/jetty-env.xml
file, or a context XML file.
See the section Deciding Where to Declare Resources for more information.
You must provide Jetty with the libraries necessary to instantiate the datasource you have configured by putting the corresponding Jar in |
Pooling DataSources
Pooling datasources enables connection pooling, which lets you reuse an existing connection instead of creating a new connection to the database. This is highly efficient in terms of memory allocation and speed of the request to the database. We highly recommend this option for production environments.
The following is a list of the pooled datasource examples we have worked with in the past:
HikariCP
Connection pooling, available at HikariCP Download. All configuration options for HikariCP are described here: HikariCP documentation.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.zaxxer.hikari.HikariDataSource">
<Arg>
<New class="com.zaxxer.hikari.HikariConfig">
<Set name="minimumPoolSize">5</Set>
<Set name="maximumPoolSize">20</Set>
<Set name="dataSourceClassName">com.mysql.jdbc.jdbc2.optional.MysqlDataSource</Set>
<Set name="username">jdbc.user</Set>
<Set name="password">jdbc.pass</Set>
<Call name="addDataSourceProperty">
<Arg>url</Arg>
<Arg>jdbc.url</Arg>
</Call>
</New>
</Arg>
</New>
</Arg>
</New>
BoneCP
Connection pooling, available at BoneCP Download. All configuration options for BoneCP are described here: BoneCP API.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.jolbox.bonecp.BoneCPDataSource">
<Set name="driverClass">com.mysql.jdbc.Driver</Set>
<Set name="jdbcUrl">jdbc.url</Set>
<Set name="username">jdbc.user</Set>
<Set name="password">jdbc.pass</Set>
<Set name="minConnectionsPerPartition">5</Set>
<Set name="maxConnectionsPerPartition">50</Set>
<Set name="acquireIncrement">5</Set>
<Set name="idleConnectionTestPeriod">30</Set>
</New>
</Arg>
</New>
c3p0
Connection pooling, available at c3p0 Jar.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.mchange.v2.c3p0.ComboPooledDataSource">
<Set name="driverClass">org.some.Driver</Set>
<Set name="jdbcUrl">jdbc.url</Set>
<Set name="user">jdbc.user</Set>
<Set name="password">jdbc.pass</Set>
</New>
</Arg>
</New>
DBCP
Connection pooling, available at dbcp Jar.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="org.apache.commons.dbcp.BasicDataSource">
<Set name="driverClassName">org.some.Driver</Set>
<Set name="url">jdbc.url</Set>
<Set name="username">jdbc.user</Set>
<Set name="password">jdbc.pass</Set>
</New>
</New>
</Arg>
</New>
Atomikos 3.3.2+
Connection pooling + XA transactions.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.atomikos.jdbc.AtomikosDataSourceBean">
<Set name="minPoolSize">2</Set>
<Set name="maxPoolSize">50</Set>
<Set name="xaDataSourceClassName">com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</Set>
<Set name="UniqueResourceName">DSTest</Set>
<Get name="xaProperties">
<Call name="setProperty">
<Arg>url</Arg>
<Arg>jdbc:mysql://localhost:3306/databasename</Arg>
</Call>
<Call name="setProperty">
<Arg>user</Arg>
<Arg>some_username</Arg>
</Call>
<Call name="setProperty">
<Arg>password</Arg>
<Arg>some_password</Arg>
</Call>
</Get>
</New>
</Arg>
</New>
MySQL
Implements javax.sql.DataSource
and javax.sql.ConnectionPoolDataSource
.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
<Set name="Url">jdbc:mysql://localhost:3306/databasename</Set>
<Set name="User">user</Set>
<Set name="Password">pass</Set>
</New>
</Arg>
</New>
PostgreSQL
Implements javax.sql.ConnectionPoolDataSource
.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="org.postgresql.ds.PGConnectionPoolDataSource">
<Set name="User">user</Set>
<Set name="Password">pass</Set>
<Set name="DatabaseName">dbname</Set>
<Set name="ServerName">localhost</Set>
<Set name="PortNumber">5432</Set>
</New>
</Arg>
</New>
DB2
Implements javax.sql.ConnectionPoolDataSource
.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.ibm.db2.jcc.DB2ConnectionPoolDataSource">
<Set name="DatabaseName">dbname</Set>
<Set name="User">user</Set>
<Set name="Password">pass</Set>
<Set name="ServerName">servername</Set>
<Set name="PortNumber">50000</Set>
</New>
</Arg>
</New>
Non-pooling DataSources
If you are deploying in a production environment, we highly recommend using a Pooling DataSource. Since that is not always an option we have a handful of examples for non-pooling datasources listed here as well.
The following is a list of the non-pooled datasource examples:
SQL Server 2000
Implements javax.sql.DataSource
and javax.sql.ConnectionPoolDataSource
.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="net.sourceforge.jtds.jdbcx.JtdsDataSource">
<Set name="User">user</Set>
<Set name="Password">pass</Set>
<Set name="DatabaseName">dbname</Set>
<Set name="ServerName">localhost</Set>
<Set name="PortNumber">1433</Set>
</New>
</Arg>
</New>
Oracle 9i/10g
Implements javax.sql.DataSource
and javax.sql.ConnectionPoolDataSource
.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="oracle.jdbc.pool.OracleDataSource">
<Set name="DriverType">thin</Set>
<Set name="URL">jdbc:oracle:thin:@fmsswdb1:10017:otcd</Set>
<Set name="User">xxxx</Set>
<Set name="Password">xxxx</Set>
<Set name="connectionCachingEnabled">true</Set>
<Set name="connectionCacheProperties">
<New class="java.util.Properties">
<Call name="setProperty">
<Arg>MinLimit</Arg>
<Arg>5</Arg>
</Call>
<!-- put the other properties in here too -->
</New>
</Set>
</New>
</Arg>
</New>
For more information, refer to: Oracle Database JDBC documentation.
PostgreSQL
Implements javax.sql.DataSource
.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="org.postgresql.ds.PGSimpleDataSource">
<Set name="User">user</Set>
<Set name="Password">pass</Set>
<Set name="DatabaseName">dbname</Set>
<Set name="ServerName">localhost</Set>
<Set name="PortNumber">5432</Set>
</New>
</Arg>
</New>
Sybase
Implements javax.sql.DataSource
.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.sybase.jdbc2.jdbc.SybDataSource">
<Set name="DatabaseName">dbname</Set>
<Set name="User">user</Set>
<Set name="Password">pass</Set>
<Set name="ServerName">servername</Set>
<Set name="PortNumber">5000</Set>
</New>
</Arg>
</New>
DB2
Implements javax.sql.DataSource
.
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.ibm.db2.jcc.DB2SimpleDataSource">
<Set name="DatabaseName">dbname</Set>
<Set name="User">user</Set>
<Set name="Password">pass</Set>
<Set name="ServerName">servername</Set>
<Set name="PortNumber">50000</Set>
</New>
</Arg>
</New>
Annotations
Jetty supports the servlet specification annotations. It is not enable by default, so the following sections show you how to enable it, and how to use them.
Quick Setup
Jetty Distribution
If you are using the jetty distribution, then annotations are enabled by default. The annotations module and its transitive dependencies are responsible for making annotation processing available.
Note that annotations that relate to JNDI, such as @Resource and @Resources are enabled via the JNDI module, which is a transitive dependency on the annotations module.
Jetty Maven Plugin
Annotations and JNDI are pre-enabled for the Maven plugin.
Embedding
To use annotations in an embedded scenario, you will need to include the jetty-annotations
jar and all its dependencies onto your classpath.
You will also need to include the org.eclipse.jetty.annotations.AnnotationConfiguration
class into the list of Configuration classes applied to the org.eclipse.jetty.webapp.WebAppContext
class representing your webapp.
Below is an example application that sets up the standard test-spec.war
webapp from the distribution in embedded fashion.
It can also be found in the Jetty GitHub repository on the examples/embedded page as ServerWithAnnotations.java
.
Note that the test-spec.war
uses not only annotations, but also JNDI, so this example also enables their processing (via the org.eclipse.jetty.plus.webapp.EnvConfiguration, org.eclipse.jetty.plus.webapp.PlusConfiguration and their related jars).
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.embedded;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;
import javax.naming.NamingException;
import org.eclipse.jetty.plus.jndi.EnvEntry;
import org.eclipse.jetty.plus.jndi.NamingDump;
import org.eclipse.jetty.plus.jndi.Resource;
import org.eclipse.jetty.plus.jndi.Transaction;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* ServerWithAnnotations
*/
public class ServerWithAnnotations
{
public static Server createServer(int port) throws NamingException, FileNotFoundException
{
// Create the server
Server server = new Server(port);
// Enable parsing of jndi-related parts of web.xml and jetty-env.xml
Configuration.ClassList classlist = Configuration.ClassList
.setServerDefault(server);
classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration",
"org.eclipse.jetty.plus.webapp.EnvConfiguration",
"org.eclipse.jetty.plus.webapp.PlusConfiguration");
classlist.addBefore(
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
// Create a WebApp
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
File warFile = JettyDistribution.resolve("demo-base/webapps/test-spec.war").toFile();
webapp.setWar(warFile.getAbsolutePath());
webapp.setAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$");
server.setHandler(webapp);
// Register new transaction manager in JNDI
// At runtime, the webapp accesses this as java:comp/UserTransaction
new Transaction(new com.acme.MockUserTransaction());
// Define an env entry with webapp scope.
// THIS ENTRY IS OVERRIDDEN BY THE ENTRY IN jetty-env.xml
new EnvEntry(webapp, "maxAmount", 100d, true);
// Register a mock DataSource scoped to the webapp
new Resource(server, "jdbc/mydatasource", new com.acme.MockDataSource());
// Add JNDI context to server for dump
server.addBean(new NamingDump());
// Configure a LoginService
String realmResourceName = "etc/realm.properties";
ClassLoader classLoader = ServerWithAnnotations.class.getClassLoader();
URL realmProps = classLoader.getResource(realmResourceName);
if (realmProps == null)
throw new FileNotFoundException("Unable to find " + realmResourceName);
HashLoginService loginService = new HashLoginService();
loginService.setName("Test Realm");
loginService.setConfig(realmProps.toExternalForm());
server.addBean(loginService);
return server;
}
public static void main(String[] args) throws Exception
{
int port = ExampleUtil.getPort(args, "jetty.http.port", 8080);
Server server = createServer(port);
server.start();
server.dumpStdErr();
server.join();
}
}
Working with Annotations
Which Annotations Are Supported
Jetty supports interpretation and application of the following annotations:
-
@Resource
-
@Resources
-
@PostConstruct
-
@PreDestroy
-
@DeclaredRoles
-
@RunAs
-
@MultipartConfig
-
@WebServlet
-
@WebFilter
-
@WebListener
-
@WebInitParam
-
@ServletSecurity, @HttpConstraint, @HttpMethodConstraint
-
@HandlesTypes (on ServletContainerInitializers)
Discovered vs Introspected Annotations
Some types of annotation can be placed on any class, not necessarily just those with which the container interacts directly.
These type of annotations are referred to as "discovered" to indicate that the container must take proactive action to go out and find them.
The other type of annotation is call "introspected", meaning that they occur on classes with which the container interacts during their lifecycle (e.g. javax.servlet.Servlet
, javax.servlet.Filter
, …etc.), and hence can be found by simple inspection of the class at that point.
Some examples of discovered annotations are:
-
@WebServlet
-
@WebFilter
-
@WebListener
Some examples of introspected annotations are:
-
@PostConstruct
-
@PreDestroy
-
@Resource
Which Jar Files Are Scanned For Discovered Annotations
The web.xml file can contain the attribute metadata-complete
.
If this is set to true
, then no scanning of discoverable annotations takes place.
However, scanning of classes may still occur because of javax.servlet.ServletContainerInitializers.
Classes implementing this interface are found by Jetty using the 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 in the container’s path or in the webapp’s WEB-INF/lib.
If scanning is to take place - because either metadata-complete
is false
or missing, or because there are one or more javax.servlet.ServletContainerIntializers with @HandlesTypes - then Jetty must consider both the container’s classpath and the webapp’s classpath.
By default, Jetty will not scan any classes that are on the container’s classpath.
If you need to cause jars and classes that are on the container’s classpath to be scanned, then you can use the org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern
context attribute to specify a pattern for jars and directories from the container’s classpath to scan.
By default Jetty will scan allclasses 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 webapp contains many jar files, you can significantly speed up deployment by omitting them from scanning.
To do this, use the org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern context attribute to define the patterns of jars that you specifically want to be scanned.
Note that if you have configured an extraClasspath for the webapp, then it participates in the scanning process too. Any classes dirs are treated the same for scanning purposes as if they were in WEB-INF/classes and jars are treated as if they were in WEB-INF/lib.
See also the next section on ServletContainerInitializers if you need to control the order in which they are applied.
Multi-threaded Annotation Scanning
If annotation scanning is to be performed, by default Jetty will do it in a multi-threaded manner in order to complete it in the minimum amount of time.
If for some reason you don’t want multi-threaded scanning, you can configure Jetty to revert to single-threaded scanning. There are several ways to configure this:
-
Set the context attribute
org.eclipse.jetty.annotations.multiThreaded
tofalse
-
Set the Server attribute
org.eclipse.jetty.annotations.multiThreaded
tofalse
-
Set the System property
org.eclipse.jetty.annotations.multiThreaded
tofalse
Method 1 will only affect the current webapp. Method 2 will affect all webapps deployed to the same Server instance. Method 3 will affect all webapps deployed in the same JVM.
By default, Jetty will wait a maximum of 60 seconds for all of 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 Server attribute
org.eclipse.jetty.annotations.maxWait
-
Set the System property
org.eclipse.jetty.annotations.maxWait
Method 1 will only affect the current webapp. Method 2 will affect all webapps deployed to the same Server instance. Method 3 will affect all webapps deployed in the same JVM.
ServletContainerInitializers
The javax.servlet.ServletContainerInitializer class can exist in: the container’s classpath, the webapp’s WEB-INF/classes
directory, the webapp’s WEB-INF/lib
jars, or any external extraClasspath that you have configured on the webapp.
The Servlet Specification does not define any order in which a ServletContainerInitializer
must be called when the webapp 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/lib jars in the order established in web.xml, or in the order that the SCI is returned by the javax.util.ServiceLoader if there is no ordering
As is the case with annotation scanning, the extraClasspath is fully considered for ServletContainerInitializer
callbacks. ServletContainerInitializer
derived from a classes directory on the extraClasspath
and jars from an extraClasspath
for the webapp are called in step 2 and 3, respectively.
As of Jetty-9.4.4, unless the |
Controlling the order of ServletContainerInitializer invocation
If you need ServletContainerInitializer
classes called in a specific order that is different from that outlined above, you can use the context attribute org.eclipse.jetty.containerInitializerOrder
.
Set them to a list of comma separated class names of ServletContainerInitializers
in the order that you want them applied.
You may optionally use the wildcard character "" *once in the list.
It will match all ServletContainerInitializer
classed not explicitly named in the list.
Here is an example, setting the context attribute in code (although you can also do the same in xml):
WebAppContext context = new WebAppContext();
context.setAttribute("org.eclipse.jetty.containerInitializerOrder",
"org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer, com.acme.Foo.MySCI, *");
In this example, we ensure that the WebSocketServerContainerInitializer
is the very first ServletContainerInitializer
that is called, followed by MySCI and then any other ServletContainerInitializer
instances that were discovered but not yet called.
Excluding ServletContainerInitializers
By default, as according to the Servlet Specification, all ServletContainerInitializer
that are discovered are invoked (see above for how to control the invocation order).
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 patterns of classnames that you want to exclude.
Here’s an example, setting the context attribute in code, although you may do exactly the same in xml:
WebAppContext context = new WebAppContext();
context.setAttribute("org.eclipse.jetty.containerInitializerExclusionPattern",
"com.acme.*|com.corp.SlowContainerInitializer");
In this example we exclude all ServletContainerInitializer
instances in the com.acme package, and the SlowContainerInitializer
.
It is possible to use exclusion and ordering together to control ServletContainerInitializer
invocation - the exclusions will be applied before the ordering.
Using Annotations with Jetty Embedded
Setting up the Classpath
You will need to place the following Jetty jar files onto the classpath of your application. You can obtain them from the Jetty distribution, or the Maven repository:
jetty-plus.jar jetty-annotations.jar
You will also need the asm jar, which you can obtain from this link.
Example
Here’s an example application that sets up a Jetty server, performs some setup to ensure that annotations are scanned, and then deploys a webapp that uses annotations. This example also uses the @Resource annotation which involves JNDI, so we would also add the necessary JNDI jars to the classpath. The example also adds in the configuration classes that are responsible for JNDI (see line 19).
The code is as follows:
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* ServerWithAnnotations
*
*
*/
public class ServerWithAnnotations
{
public static final void main(String args[]) throws Exception
{
//Create the server
Server server = new Server(8080);
//Enable parsing of jndi-related parts of web.xml and jetty-env.xml
org.eclipse.jetty.webapp.Configuration.ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration");
classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.annotations.AnnotationConfiguration");
//Create a WebApp
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setWar("../../tests/test-webapps/test-servlet-spec/test-spec-webapp/target/test-spec-webapp-9.0.4-SNAPSHOT.war");
server.setHandler(webapp);
//Register new transaction manager in JNDI
//At runtime, the webapp accesses this as java:comp/UserTransaction
org.eclipse.jetty.plus.jndi.Transaction transactionMgr = new org.eclipse.jetty.plus.jndi.Transaction(new com.acme.MockUserTransaction());
//Define an env entry with webapp scope.
org.eclipse.jetty.plus.jndi.EnvEntry maxAmount = new org.eclipse.jetty.plus.jndi.EnvEntry (webapp, "maxAmount", new Double(100), true);
// Register a mock DataSource scoped to the webapp
org.eclipse.jetty.plus.jndi.Resource mydatasource = new org.eclipse.jetty.plus.jndi.Resource(webapp, "jdbc/mydatasource", new com.acme.MockDataSource());
// Configure a LoginService
HashLoginService loginService = new HashLoginService();
loginService.setName("Test Realm");
loginService.setConfig("src/test/resources/realm.properties");
server.addBean(loginService);
server.start();
server.join();
}
}
On line 19 the configuration classes responsible for setting up JNDI and java:comp/env
are added.
On line 20 we add in the configuration class that ensures annotations are inspected.
On lines 30, 33 and 37 JNDI resources that we will be able to reference with @Resource annotations are configured.
With the setup above, a servlet that uses annotations and Jetty will honour the annotations when the webapp is deployed can be created:
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RunAs;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import javax.transaction.UserTransaction;
/**
* AnnotationTest
*
* Use servlet 3.0 annotations from within Jetty.
*
* Also uses servlet 2.5 resource injection and lifecycle callbacks
*/
@RunAs("special")
@WebServlet(urlPatterns = {"/","/test/*"}, name="AnnotationTest", initParams={@WebInitParam(name="fromAnnotation", value="xyz")})
@DeclareRoles({"user","client"})
public class AnnotationTest extends HttpServlet
{
private DataSource myDS;
@Resource(mappedName="UserTransaction")
private UserTransaction myUserTransaction;
@Resource(mappedName="maxAmount")
private Double maxAmount;
@Resource(mappedName="jdbc/mydatasource")
public void setMyDatasource(DataSource ds)
{
myDS=ds;
}
@PostConstruct
private void myPostConstructMethod ()
{
System.err.println("PostConstruct called");
}
@PreDestroy
private void myPreDestroyMethod()
{
System.err.println("PreDestroy called");
}
public void init(ServletConfig config) throws ServletException
{
super.init(config);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request, response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
try
{
response.setContentType("text/html");
ServletOutputStream out = response.getOutputStream();
out.println("<html>");
out.println("<body>");
out.println("<h1>Results</h1>");
out.println(myDS.toString());
out.println("<br/>");
out.println(maxAmount.toString());
out.println("</body>");
out.println("</html>");
out.flush();
}
catch (Exception e)
{
throw new ServletException(e);
}
}
}
Java Management Extensions (JMX)
The Java Management Extensions (JMX) API is a standard API for managing and monitoring resources such as applications, devices, services, and the Java virtual machine.
Typical uses of the JMX technology include:
-
Consulting and changing application configuration
-
Accumulating and making available statistics about application behavior
-
Notifying of state changes and erroneous conditions
The JMX API includes remote access, so a remote management program can interact with a running application for these purposes.
Using JMX with Jetty
Jetty’s architecture is based on POJO components (see Jetty Architecture).
These components are organized in a tree and each component may have a lifecycle that spans the Server
lifetime, or a web application lifetime, or even shorter lifetimes such as that of a TCP connection.
Every time a component is added or removed from the component tree, an event is emitted, and Container.Listener
implementations can listen to those events and perform additional actions.
One such Container.Listener
is MBeanContainer
that uses ObjectMBean
to create an MBean from an arbitrary POJO, and register/unregister the MBean to/from the platform MBeanServer
.
Jetty components are annotated with Jetty JMX Annotations and provide specific JMX details so that ObjectMBean
can build a more precise representation of the JMX metadata associated with the component POJO.
Therefore, when a component is added to the component tree, MBeanContainer
is notified, it creates the MBean from the component POJO and registers it to the MBeanServer
.
Similarly, when a component is removed from the tree, MBeanContainer
is notified, and unregisters the MBean from the MBeanServer
.
The Jetty MBeans can be accessed via any JMX console such as Java Mission Control (JMC), VisualVM, JConsole or others.
Configuring JMX
This guide describes the various ways to initialize and configure the Jetty JMX integration.
Configuring the Jetty JMX integration only registers the Jetty MBeans into the platform MBeanServer
, and therefore the MBeans can only be accessed locally (from the same machine), not from remote machines.
This means that this configuration is enough for development, where you have easy access (with graphical user interface) to the machine where Jetty runs, but it is typically not enough when the machine Jetty where runs is remote, or only accessible via SSH or otherwise without graphical user interface support. In these cases, you have to enable JMX Remote Access.
Standalone Jetty Server
JMX is not enabled by default in the Jetty distribution.
To enable JMX in the Jetty distribution run the following, where {$jetty.home}
is the directory where you have the Jetty distribution installed, and ${jetty.base}
is the directory where you have your Jetty configuration (see the documentation for Jetty base vs. home examples):
$ cd ${jetty.base}
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx
Running the above command will append the available configurable elements of the jmx
module to the {$jetty.base}/start.ini
file, or create the ${jetty.base}/start.d/jmx.ini
file.
Embedded Jetty Server
When running Jetty embedded into an application, create and configure an MBeanContainer
instance as follows:
Server server = new Server();
// Setup JMX.
MBeanContainer mbeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
server.addBean(mbeanContainer);
// Export the loggers as MBeans.
server.addBean(Log.getLog());
Because logging is initialized prior to the MBeanContainer
(even before the Server
itself), it is necessary to register the logger manually via server.addBean()
so that the loggers may show up in the JMX tree as MBeans.
Using the Jetty Maven Plugin with JMX
If you are using the Jetty Maven plugin you should copy the ${jetty.home}/etc/jetty-jmx.xml
file into your webapp project somewhere, such as src/main/config/etc/
, then add a <jettyXml>
element to the <configuration>
element of the Jetty Maven Plugin:
<plugin>
<groupid>org.eclipse.jetty</groupid>
<artifactid>jetty-maven-plugin</artifactid>
<version>{VERSION}</version>
<configuration>
<scanintervalseconds>10</scanintervalseconds>
<jettyXml>src/main/config/etc/jetty-jmx.xml</jettyXml>
</configuration>
</plugin>
Using JConsole or Java Mission Control to Access Jetty MBeans
The simplest way to access the MBeans that Jetty publishes is to use Java Mission Control (JMC) or JConsole.
Both these tools can connect to local or remote JVMs to display the MBeans.
For local access, you just need to start JConsole or JMC and then choose from their user interface the local JVM you want to connect to.
For remote access, you need first to enable JMX Remote Access in Jetty.
Enabling JMX Remote Access
There are two ways of enabling remote connectivity so that JConsole or JMC can connect to the remote JVM to visualize MBeans.
-
Use the
com.sun.management.jmxremote
system property on the command line. Unfortunately, this solution does not work well with firewalls and is not flexible. -
Use Jetty’s
jmx-remote
module or - equivalently - theConnectorServer
class.
ConnectorServer
will use by default RMI to allow connection from remote clients,
and it is a wrapper around the standard JDK class JMXConnectorServer
, which is the class that provides remote access to JMX clients.
Connecting to the remote JVM is a two step process:
-
First, the client will connect to the RMI registry to download the RMI stub for the
JMXConnectorServer
; this RMI stub contains the IP address and port to connect to the RMI server, i.e. the remoteJMXConnectorServer
. -
Second, the client uses the RMI stub to connect to the RMI server (i.e. the remote
JMXConnectorServer
) typically on an address and port that may be different from the RMI registry address and port.
The configuration for the RMI registry and the RMI server is specified by a JMXServiceURL
.
The string format of an RMI JMXServiceURL
is:
service:jmx:rmi://<rmi_server_host>:<rmi_server_port>/jndi/rmi://<rmi_registry_host>:<rmi_registry_port>/jmxrmi
Default values are:
rmi_server_host = localhost
rmi_server_port = 1099
rmi_registry_host = localhost
rmi_registry_port = 1099
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. With this configuration it would still be possible to access the MBeans from remote using a SSH tunnel.
By specifying an appropriate JMXServiceURL
, you can fine tune the network interfaces 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 a 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.
Examples:
service:jmx:rmi:///jndi/rmi:///jmxrmi
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
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
rmi_server_host = loopback address
rmi_server_port = 1100
rmi_registry_host = loopback address
rmi_registry_port = 1099
When To control the IP address stored in the RMI stub you need to set the system property |
Enabling JMX Remote Access in Standalone Jetty Server
Similarly to enabling JMX in a standalone Jetty server, you enable the jmx-remote
module:
$ cd ${jetty.base}
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx-remote
Enabling JMX Remote Access in Embedded Jetty
When running Jetty embedded into an application, create and configure a ConnectorServer
:
Server server = new Server();
// Setup JMX
MBeanContainer mbeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
server.addBean(mbeanContainer);
// Setup ConnectorServer
JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1999, "/jndi/rmi:///jmxrmi");
ConnectorServer jmxServer = new ConnectorServer(jmxURL, "org.eclipse.jetty.jmx:name=rmiconnectorserver");
server.addBean(jmxServer);
The JMXServiceURL
above specifies that the RMI server binds to the wildcard address on port 1999, while the RMI registry binds to the wildcard address on port 1099 (the default RMI registry port).
JMX Remote Access Authorization
The standard JMXConnectorServer
provides several options to authorize access.
To authorize access to the JMXConnectorServer
you can use this configuration, where the jmx.password
and jmx.access
files have the format specified in the blog entry above:
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
<Arg>
<New class="javax.management.remote.JMXServiceURL">
<Arg type="java.lang.String">rmi</Arg>
<Arg type="java.lang.String" />
<Arg type="java.lang.Integer">1099</Arg>
<Arg type="java.lang.String">/jndi/rmi:///jmxrmi</Arg>
</New>
</Arg>
<Arg>
<Map>
<Entry>
<Item>jmx.remote.x.access.file</Item>
<Item>
<New class="java.lang.String"><Arg><Property name="jetty.base" default="." />/resources/jmx.access</Arg></New>
</Item>
</Entry>
<Entry>
<Item>jmx.remote.x.password.file</Item>
<Item>
<New class="java.lang.String"><Arg><Property name="jetty.base" default="." />/resources/jmx.password</Arg></New>
</Item>
</Entry>
</Map>
</Arg>
<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
<Call name="start" />
</New>
Similarly, in code:
JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1099, "/jndi/rmi:///jmxrmi");
Map<String, Object> env = new HashMap<>();
env.put("jmx.remote.x.access.file", "resources/jmx.access");
env.put("jmx.remote.x.password.file", "resources/jmx.password");
ConnectorServer jmxServer = new ConnectorServer(jmxURL, env, "org.eclipse.jetty.jmx:name=rmiconnectorserver");
jmxServer.start();
Calling ConnectorServer.start()
may be explicit as in the examples above, or can be skipped when adding the ConnectorServer
as a bean to the Server
, so that starting the Server
will also start the ConnectorServer
.
Securing JMX Remote Access with TLS
The JMX communication via RMI happens by default in clear-text.
It is possible to configure the ConnectorServer
with a SslContextFactory
so that the JMX communication via RMI is encrypted:
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
<Arg>
<New class="javax.management.remote.JMXServiceURL">
<Arg type="java.lang.String">rmi</Arg>
<Arg type="java.lang.String" />
<Arg type="java.lang.Integer">1099</Arg>
<Arg type="java.lang.String">/jndi/rmi:///jmxrmi</Arg>
</New>
</Arg>
<Arg />
<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
<Arg><Ref refid="sslContextFactory" /></Arg>
</New>
Similarly, in code:
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath("/path/to/keystore");
sslContextFactory.setKeyStorePassword("secret");
JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1099, "/jndi/rmi:///jmxrmi");
ConnectorServer jmxServer = new ConnectorServer(jmxURL, null, "org.eclipse.jetty.jmx:name=rmiconnectorserver", sslContextFactory);
It is possible to use the same SslContextFactory
used to configure the Jetty ServerConnector
that supports TLS for the HTTP protocol.
This is used in the XML example above: the SslContextFactory
configured for the TLS ServerConnector
is registered with an id of sslContextFactory
which is referenced in the XML via the Ref
element.
The keystore must contain a valid certificate signed by a Certification Authority.
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 server 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 both hosts.
Having certificates signed by a Certification Authority simplifies by a lot the configuration needed to get the JMX communication over TLS working properly.
If that is not the case (for example the certificate is self-signed), then you need to specify the required system properties that allow RMI (especially when acting as an RMI client) to retrieve the cryptographic material necessary to establish the TLS connection.
For example, trying to connect using the JDK standard JMXConnector
with both the RMI server and the RMI registry to domain.com
:
// System properties necessary for an RMI client to trust a self-signed certificate.
System.setProperty("javax.net.ssl.trustStore", "/path/to/trustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "secret");
JMXServiceURL jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://domain.com:1100/jmxrmi")
Map<String, Object> clientEnv = new HashMap<>();
// Required to connect to the RMI registry via TLS.
clientEnv.put(ConnectorServer.RMI_REGISTRY_CLIENT_SOCKET_FACTORY_ATTRIBUTE, new SslRMIClientSocketFactory());
try (JMXConnector client = JMXConnectorFactory.connect(jmxURL, clientEnv))
{
Set<ObjectName> names = client.getMBeanServerConnection().queryNames(null, null);
}
Similarly, to launch JMC:
$ jmc -vmargs -Djavax.net.ssl.trustStore=/path/to/trustStore -Djavax.net.ssl.trustStorePassword=secret
Note that these system properties are required when launching the ConnectorServer
too, on the server, because it acts as an RMI client with respect to the RMI registry.
JMX Remote 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 a SSH tunnel.
In this case you want to configure the ConnectorServer
with a JMXServiceURL
that binds the RMI server and the RMI registry to the loopback interface only: service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi
.
Then you setup the local port forwarding with the SSH tunnel:
$ ssh -L 1099:localhost:1099 <user>@<machine_host>
Now you can use JConsole or JMC to connect to localhost:1099
on your local computer.
The traffic will be forwarded to machine_host
and when there, SSH will forward the traffic to localhost:1099
, which is exactly where the ConnectorServer
listens.
When you configure ConnectorServer
in this way, you must set the system property -Djava.rmi.server.hostname=localhost
, on the server.
This is required because when the RMI server is exported, its address and port are stored in the RMI stub. You want the address in the RMI stub to be localhost
so that when the RMI stub is downloaded to the remote client, the RMI communication will go through the SSH tunnel.
Jetty JMX Annotations
When the jetty-jmx
libraries are present on startup and the wiring is enabled for exposing Jetty MBeans to JMX, there are three annotations that govern when and how MBeans are created and exposed.
Annotation Introspection
When JMX is configured and enabled in Jetty, any time an object is registered with the Server it is introspected as a potential MBean to be exposed.
This introspection proceeds as follows assuming the class is named com.acme.Foo
:
-
All influences for
com.acme.Foo
determined. These include each class in the chain of super classes, and by convention each of these classes following a form ofcom.acme.jmx.FooMBean
. All super classes and their corresponding MBean representations are then used in the next step. -
Each potential influencing class is checked for the
@ManagedObject
annotation. Should this annotation exist at any point in the chain of influencers then an MBran is created with the description of the version@ManagedObject
discovered. -
Once a MBean has been created for an object then each potential influencing object is introspected for
@ManagedAttribute
and@ManagedOperation
annotations and the corresponding type is exposed to the MBean.
The convention of looking for @ManagedObject
annotations on .jmx.ClassMBean
allows for a normal POJOs to be wrapped in an MBean without itself without requiring it being marked up with annotations.
Since the POJO is passed to these wrapped derived Mbean instances and is an internal variable then the MBean can be used to better expose a set of attributes and operations that may not have been anticipated when the original object was created.
@ManagedObject
The @ManagedObject
annotation is used on a class at the top level to indicate that it should be exposed as an MBean.
It has only one attribute to it which is used as the description of the MBean.
Should multiple @ManagedObject
annotations be found in the chain of influence then the first description is used.
The list of attributes available are:
- value
-
The description of the Managed Object.
@ManagedAttribute
The @ManagedAttribute
annotation is used to indicate that a given method exposes a JMX attribute.
This annotation is placed always on the reader method of a given attribute.
Unless it is marked as read-only in the configuration of the annotation a corresponding setter is looked for following normal naming conventions.
For example if this annotation is on a method called getFoo()
then a method called setFoo()
would be looked for and if found wired automatically into the JMX attribute.
The list of attributes available are:
- value
-
The description of the Managed Attribute.
- name
-
The name of the Managed Attribute.
- proxied
-
Value is true if the corresponding MBean for this object contains the method of this JMX attribute in question.
- readonly
-
By default this value is false which means that a corresponding setter will be looked for an wired into the attribute should one be found. Setting this to true make the JMX attribute read only.
- setter
-
This attribute can be used when the corresponding setter for a JMX attribute follows a non-standard naming convention and it should still be exposed as the setter for the attribute.
@ManagedOperation
The @ManagedOperation
annotation is used to indicate that a given method should be considered a JMX operation.
The list of attributes available are:
- value
-
The description of the Managed Operation.
- impact
-
The impact of an operation. By default this value is "UNKNOWN" and acceptable values are "ACTION", "INFO", "ACTION_INFO" and should be used according to their definitions with JMX.
- proxied
-
Value is true if the corresponding MBean for this object contains the method of this JMX operation in question.
@Name
A fourth annotation is often used in conjunction with the JMX annotations mentioned above. This annotation is used to describe variables in method signatures so that when rendered into tools like JConsole it is clear what the parameters are. For example:
The list of attributes available are:
- value
-
The name of the parameter.
- description
-
The description of the parameter.
Example
The following is an example of each of the annotations mentioned above in practice.
package com.acme;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.annotation.Name;
@ManagedObject("Test MBean Annotations")
public class Derived extends Base implements Signature
{
String fname="Full Name";
@ManagedAttribute(value="The full name of something", name="fname")
public String getFullName()
{
return fname;
}
public void setFullName(String name)
{
fname=name;
}
@ManagedOperation("Doodle something")
public void doodle(@Name(value="doodle", description="A description of the argument") String doodle)
{
System.err.println("doodle "+doodle);
}
}
Managing Jetty with JConsole and JMC
JConsole and the Java Mission Control (JMX) are graphical tools; they allow you to remotely manage and monitor your server and web application status using JMX. When following the instructions given below, please also ensure that you make any necessary changes to any anti-virus software you may be using which may prevent JConsole or JMC from running.
Starting Jetty Standalone
The simplest way to enable support is to add the JMX-Remote support module to your {$jetty.base}
.
[mybase]$ java /opt/jetty-dist/start.jar --add-to-start=jmx-remote, jmx
INFO: jmx-remote initialised in ${jetty.base}/start.ini
INFO: jmx initialised in ${jetty.base}/start.ini
Then open the {$jetty.base}/start.ini
(or {$jetty.base}/start.d/jmx-remote.ini
) file and edit the properties to suit your needs:
#
# Initialize module jmx-remote
#
--module=jmx-remote
## JMX Configuration
## Enable for an open port accessible by remote machines
jetty.jmxrmihost=localhost
jetty.jmxrmiport=1099
Monitoring Jetty with JConsole
To monitor Jetty’s server status with JConsole, start Jetty and then start JConsole by typing jconsole
on the command line.
Connecting to your server process
After you start Jetty, you will see a dialog box in JConsole with a list of running processes to which you can connect. It should look something like so:
If you don’t see your Jetty process in the list of processes you can connect to, quickly switch tabs, or close and reopen a new "New Connection" dialog window. This forces JConsole to refresh the list, and recognize your newly-started Jetty process. |
Select the start.jar entry and click the "Connect" button. A new JConsole window opens:
From this window you can monitor memory usage, thread usage, classloading and VM statistics. You can also perform operations such as a manual garbage collect. JConsole is an extremely powerful and useful tool.
Managing Jetty Objects with JConsole
The MBean tab of JConsole allows access to managed objects within the Java application, including MBeans the JVM provides. If you also want to interact with the Jetty JMX implementation via JConsole, you need to start Jetty JMX in a form that JConsole can access. See Using JMX with Jetty for more information.
Monitoring Jetty with JMC
To monitor Jetty’s server status with JMC, start Jetty and then start JMC by typing jmc
on the command line.
Connecting to your server process
After you start Jetty, you will see a dialog box in JMC with a list of running processes to which you can connect. It should look something like so:
If you don’t see your Jetty process in the list of processes you can connect to, quickly switch tabs, or close and reopen a new "New Connection" dialog window. This forces JMC to refresh the list, and recognize your newly-started Jetty process. |
Double-click the start.jar entry or right-click the start.jar entry and select "Start JMX Console". A new JMC window opens on the right:
From this window you can monitor memory usage, thread usage, classloading and VM statistics. You can also perform operations such as a manual garbage collect. JMC is an extremely powerful and useful tool.
Managing Jetty Objects with JConsole
The MBean tab of JMC allows access to managed objects within the Java application, including MBeans the JVM provides. If you also want to interact with the Jetty JMX implementation via JMC, you need to start Jetty JMX in a form that JMC can access. See Using JMX with Jetty for more information.
Application Layer Protocol Negotiation (ALPN)
The development of new web protocols such as HTTP/2 raised the need of protocol negotiation within a Transport Layer Security (TLS) handshake. A protocol negotiation called ALPN (Application Layer Protocol Negotiation - RFC7301) has been defined to accomplish this.
ALPN has now replaced the older (and now fully deprecated) NPN in the general Web as of 2016.
For those browsers that support HTTP/2, they all now support ALPN. Starting with Jetty 9.3.0, only ALPN is supported by Jetty.
Introducing ALPN
Application Layer Protocol Negotiation (ALPN) is a TLS extension that allows client and server to negotiate the application protocol that they will use to communicate within the encryption provided by TLS.
Any protocol can be negotiated by ALPN within a TLS connection; the protocols that are most commonly negotiated are HTTP/2 and HTTP/1.1.
Browsers only support HTTP/2 over TLS by negotiating the HTTP/2 protocol via ALPN. You need to configure the server to support TLS and ALPN if you want browsers to use the HTTP/2 protocol, otherwise they will default to HTTP/1.1.
In the Jetty project, ALPN is used in two artifacts: jetty-alpn-client
and jetty-alpn-server
, respectively for the client and for the server.
When using Jetty as a standalone server via the Jetty distribution, the jetty-alpn-server
artifact is automatically included in the server classpath by the Jetty module system.
When using Jetty embedded, the jetty-alpn-client
and jetty-alpn-server
artifacts must be included in the classpath, respectively for client and server use cases.
The ALPN implementation is provided to these two artifacts with the following options:
-
For Java 8 only, a provider based on a pure Java implementation (no native code)
-
For Java 8 up to
1.8.0_242
included, this provider uses modified OpenJDK classes and requires the-Xbootclasspath/p:
option on command line -
For Java 8 from
1.8.0_252
included and later, this provider uses the standard OpenJDK ALPN APIs introduced in Java 9 (see below) that have been backported to1.8.0_252
and does not require the-Xbootclasspath/p:
option on command line
-
-
For Java 8 or later, a provider based on the Conscrypt security provider
-
Works with JDK 8 or later and provides improved performance
-
Binds to the OpenSSL native library shipped by Conscrypt and is therefore only available on the platforms supported by Conscrypt
-
-
For Java 9 or later, a provider based on the standard OpenJDK ALPN APIs
-
Works with JDK 9 or later, pure Java implementation (no native code)
-
Lower performance than Conscrypt
-
Each provider above provides an ALPN service implementation; Jetty uses the ServiceLoader
mechanism to load these service implementations.
At least one valid provider must be present in the server classpath.
For example, using JDK 8 with the JDK 9 ALPN provider is an invalid combination.
The absence of valid implementations is an error at startup (see also the troubleshooting section).
There may be multiple ALPN service providers in the server classpath.
When a new connection is created, an SSLEngine
instance is associated to it; each SSLEngine
is passed all service implementations, until one accepts it.
It is therefore possible to have multiple providers active at the same time, for example the JDK 9 provider and the Conscrypt provider, and at runtime the correct one will be chosen by the Jetty runtime.
ALPN and OpenJDK 8
When using JDKs based on OpenJDK 8 (for JDK 9 see here), and you do not or
cannot use Conscrypt, the ALPN implementation is provided by the
jetty-alpn-openjdk8-client
or jetty-alpn-openjdk8-server
artifacts.
For Java 8 versions up to 1.8.0_242
included, you also need the Jetty’s ALPN boot library
to provide the ALPN service implementation, via the alpn-boot
artifact.
For Java 8 versions from 1.8.0_252
included and later, Jetty’s ALPN boot library is not
necessary because the OpenJDK ALPN APIs have been backported to 1.8.0_252
and the
jetty-alpn-openjdk8-*
artifacts can use these backported APIs if their presence is detected.
Alternatively, you can use the Jetty ALPN agent, that in turn uses theJetty ALPN boot library to transform the relevant OpenJDK classes when they are loaded.
The Jetty ALPN boot library modifies the relevant OpenJDK classes to add ALPN support and provides an ALPN API that application can use to enable ALPN.
When using Jetty as a standalone server via the Jetty distribution, ALPN support is automatically enabled when the http2
module is enabled.
This enables transitively the alpn-8
module which puts the jetty-alpn-openjdk8-server
artifact in the server classpath, providing the ALPN OpenJDK 8 service implementation.
When using Jetty embedded, the ALPN support is provided by the jetty-alpn-openjdk8-client
and jetty-alpn-openjdk8-server
artifacts, respectively for client usage and server usage.
To get ALPN working with Java 8, you must have the jetty-alpn-openjdk8-client
artifact or
the jetty-alpn-openjdk8-server
artifact in the classpath.
Additionally, if you are using OpenJDK 1.8.0_242
or earlier, you need the Jetty ALPN boot
library (corresponding to the exact OpenJDK version you are using) in the boot classpath,
or alternatively you need the Jetty ALPN agent.
In the case of the Jetty ALPN boot library, start the JVM as follows:
java -Xbootclasspath/p:<path_to_alpn_boot_jar> ...
Where path_to_alpn_boot_jar
is the path on the file system for the alpn-boot
artifact, such as the one at the Maven coordinates org.mortbay.jetty.alpn:alpn-boot
.
Be certain to get the ALPN boot artifact version that matches the version of your JRE. |
ALPN agent and OpenJDK 8
The Jetty Project also maintains the Jetty ALPN agent, which is a JVM agent that provides the ALPN implementation. The Jetty ALPN agent can be use in alternative (never together) with the ALPN boot library.
The Jetty ALPN agent contains the ALPN boot libraries for every JDK 8 version. The agent can be used only with Java 8, but works with any Java 8 version.
The Jetty ALPN agent detects the JDK version currently running, picks the correspondent
ALPN boot library (or picks none if the JDK version is 1.8.0_252
or later), and
transforms, if necessary, the relevant OpenJDK classes to provide the ALPN support.
To use the Jetty ALPN agent, start the JVM as follows:
java -javaagent:<path_to_alpn_agent_jar> ...
The Jetty ALPN agent works with any Java 8 version. It is required if you use
an OpenJDK version up to The Jetty ALPN agent can be left on the command line even when using an OpenJDK version
equal or greater than |
ALPN and Conscrypt
When using JDK 8 or later, you can use the Conscrypt security provider to provide the ALPN service implementation.
Conscrypt binds natively to BoringSSL (a fork of OpenSSL by Google), so ALPN will be supported via the support provided by BoringSSL (bundled together with Conscrypt).
When using Jetty as a standalone server via the Jetty distribution, ALPN is enabled by enabling the conscrypt
module.
When using Jetty embedded, ALPN is enabled by the jetty-alpn-conscrypt-client
and jetty-alpn-conscrypt-server
artifacts, respectively for client usage and server usage.
In addition, you also need the Conscrypt artifacts, typically the org.conscrypt:conscrypt-openjdk-uber
artifact.
All these artifacts must be added to the classpath.
ALPN and JDK 9
When using JDK 9 or later and Jetty as a standalone server via the Jetty distribution, ALPN support is automatically enabled when the http2
module is enabled.
This enables transitively the alpn-9
module which puts the jetty-alpn-java-server
artifact in the server classpath, providing the ALPN JDK 9 service implementation.
When using JDK 9 or later and Jetty embedded, the ALPN service implementation is provided by the jetty-alpn-java-client
and jetty-alpn-java-server
artifacts, respectively for client usage and server usage, and must be added to the classpath.
Starting in OSGi
To use ALPN in an OSGi environment, in addition to what described above, you will also need to deploy the jetty-osgi-alpn
jar.
This jar contains a Fragment-Host
directive that ensures the ALPN classes will be available from the system bundle.
You can download the jetty-osgi-alpn jar from Maven Central.
OSGi requires a |
ALPN Troubleshooting
When starting the Jetty server, especially when using Jetty embedded, it may be possible that you see an error similar to this:
IllegalStateException: no ALPN processor
The error means that you don’t have the ALPN dependencies setup correctly in your classpath.
For example, you may have the jetty-alpn-java-server
artifact in the classpath (which is correct when using JDK 9), but run your application with JDK 8.
Another example is when you have correctly put the alpn-boot
artifact in the boot classpath, but you don’t have the jetty-alpn-openjdk8-server
artifact in the classpath.
Details about ALPN and OpenJDK 8
The following sections only refer to the API and implementation of ALPN using the Jetty boot library.
The Jetty ALPN boot library is conceptually made of two parts: the ALPN APIs and the ALPN implementation.
The ALPN API is provided by the org.eclipse.jetty.alpn:alpn-api
artifact.
This artifact is only needed by application code that uses the ALPN APIs.
The ALPN implementation is provided by the org.mortbay.jetty.alpn:alpn-boot
artifact and consist of modifications to the OpenJDK classes.
The org.mortbay.jetty.alpn:alpn-boot
artifact contains also the classes present in the org.eclipse.jetty.alpn:alpn-api
artifact.
Understanding the ALPN API
Applications need to interact with ALPN TLS extension protocol negotiations. For example, server applications need to know whether the client supports ALPN, and client applications needs to know whether the server supports ALPN.
To implement this interaction, Jetty’s ALPN implementation provides an API to applications, hosted at Maven coordinates org.eclipse.jetty.alpn:alpn-api
.
You need to declare this dependency as provided, because the alpn-boot
jar already includes it (see the previous section), and it is therefore available from the boot classpath.
The API consists of a single class, org.eclipse.jetty.alpn.ALPN
, and applications need to register instances of SSLSocket
or SSLEngine
with a ClientProvider
or ServerProvider
(depending on whether the application is a client application or server application).
Refer to ALPN
Javadocs and to the examples below for further details about client and server provider methods.
Client Example
SSLContext sslContext = ...;
SSLSocket sslSocket = (SSLSocket)context.getSocketFactory().createSocket("localhost", server.getLocalPort());
ALPN.put(sslSocket, new ALPN.ClientProvider()
{
@Override
public List<String> protocols()
{
return Arrays.asList("h2", "http/1.1");
}
@Override
public void unsupported()
{
ALPN.remove(sslSocket);
}
@Override
public void selected(String protocol)
{
ALPN.remove(sslSocket);
System.out.println("Protocol Selected is: " + protocol);
}
});
The ALPN implementation calls ALPN.ClientProvider
methods protocols()
, unsupported()
and selected(String)
, so that the client application can:
-
Decide whether to support ALPN
-
Provide the protocols supported
-
Know whether the server supports ALPN
-
Know the protocol chosen by the server
Server Example
The example for SSLEngine
is identical, and you just need to replace the SSLSocket
instance with an SSLEngine
instance.
SSLEngine sslEngine = ...;
ALPN.put(sslEngine, new ALPN.ServerProvider()
{
@Override
public void unsupported()
{
ALPN.remove(sslEngine);
}
@Override
public String select(List<String> protocols);
{
ALPN.remove(sslEngine);
return protocols.get(0);
}
});
The ALPN implementation calls ALPN.ServerProvider
methods unsupported()
, and select(List<String>),
so that the server application can:
-
know whether the client supports ALPN.
-
select one of the protocols the client supports.
Implementation Details
It is important that implementations of ALPN.ServerProvider
and ALPN.ClientProvider
remove the sslSocket
or sslEngine
when the negotiation is complete, like shown in the examples above.
Failing to do so will cause a memory leak.
Unit Tests
You can write and run unit tests that use the ALPN implementation. The solution that we use with Maven is to specify an additional command line argument to the Surefire plugin:
<project>
<properties>
<alpn-boot-version>8.1.4.v20150727</alpn-boot-version>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn-boot-version}/alpn-boot-${alpn-boot-version}.jar
</argLine>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
Debugging
You can enable debug logging for the ALPN implementation in this way:
ALPN.debug = true;
Since the ALPN class is in the boot classpath, we chose not to use logging libraries because we do not want to override application logging library choices; therefore the logging is performed directly on System.err
.
License Details
The ALPN implementation relies on modification of a few OpenJDK classes and on a few new classes that need to live in the sun.security.ssl
package.
These classes are released under the same GPLv2+exception
license of OpenJDK.
The ALPN class and its nested classes are released under same license as the classes of the Jetty project.
Versions
The ALPN implementation, relying on modifications of OpenJDK classes, updates every time there are updates to the modified OpenJDK classes.
OpenJDK version | ALPN version |
---|---|
1.7.0u40 |
7.1.0.v20141016 |
1.7.0u45 |
7.1.0.v20141016 |
1.7.0u51 |
7.1.0.v20141016 |
1.7.0u55 |
7.1.0.v20141016 |
1.7.0u60 |
7.1.0.v20141016 |
1.7.0u65 |
7.1.0.v20141016 |
1.7.0u67 |
7.1.0.v20141016 |
1.7.0u71 |
7.1.2.v20141202 |
1.7.0u72 |
7.1.2.v20141202 |
1.7.0u75 |
7.1.3.v20150130 |
1.7.0u76 |
7.1.3.v20150130 |
1.7.0u79 |
7.1.3.v20150130 |
1.7.0u80 |
7.1.3.v20150130 |
1.8.0 |
8.1.0.v20141016 |
1.8.0u05 |
8.1.0.v20141016 |
1.8.0u11 |
8.1.0.v20141016 |
1.8.0u20 |
8.1.0.v20141016 |
1.8.0u25 |
8.1.2.v20141202 |
1.8.0u31 |
8.1.3.v20150130 |
1.8.0u40 |
8.1.3.v20150130 |
1.8.0u45 |
8.1.3.v20150130 |
1.8.0u51 |
8.1.4.v20150727 |
1.8.0u60 |
8.1.5.v20150921 |
1.8.0u65 |
8.1.6.v20151105 |
1.8.0u66 |
8.1.6.v20151105 |
1.8.0u71 |
8.1.7.v20160121 |
1.8.0u72 |
8.1.7.v20160121 |
1.8.0u73 |
8.1.7.v20160121 |
1.8.0u74 |
8.1.7.v20160121 |
1.8.0u77 |
8.1.7.v20160121 |
1.8.0u91 |
8.1.7.v20160121 |
1.8.0u92 |
8.1.8.v20160420 |
1.8.0u101 |
8.1.9.v20160720 |
1.8.0u102 |
8.1.9.v20160720 |
1.8.0u111 |
8.1.9.v20160720 |
1.8.0u112 |
8.1.10.v20161026 |
1.8.0u121 |
8.1.11.v20170118 |
1.8.0u131 |
8.1.11.v20170118 |
1.8.0u141 |
8.1.11.v20170118 |
1.8.0u144 |
8.1.11.v20170118 |
1.8.0u151 |
8.1.11.v20170118 |
1.8.0u152 |
8.1.11.v20170118 |
1.8.0u161 |
8.1.12.v20180117 |
1.8.0u162 |
8.1.12.v20180117 |
1.8.0u171 |
8.1.12.v20180117 |
1.8.0u172 |
8.1.12.v20180117 |
1.8.0u181 |
8.1.12.v20180117 |
1.8.0u191 |
8.1.13.v20181017 |
1.8.0u192 |
8.1.13.v20181017 |
1.8.0u201 |
8.1.13.v20181017 |
1.8.0u202 |
8.1.13.v20181017 |
1.8.0u211[1] |
8.1.13.v20181017 |
1.8.0u212 |
8.1.13.v20181017 |
1.8.0u221[1] |
8.1.13.v20181017 |
1.8.0u222 |
8.1.13.v20181017 |
1.8.0u231[1] |
8.1.13.v20181017 |
1.8.0u232 |
8.1.13.v20181017 |
1.8.0u241[1] |
8.1.13.v20181017 |
1.8.0u242 |
8.1.13.v20181017 |
1.8.0u252 and later |
NOT NECESSARY |
[1] These are Oracle releases for which the source code is not available, or it is unclear what exactly is because there is no correspondent tag in the OpenJDK repository. We assume that the source code for these releases is equivalent (at least for the files modified to make ALPN work) to the release that follows (for example, for 1.8.0u211 we assume that the source code is equivalent to 1.8.0u212, for 1.8.0u221 we assume 1.8.0u222, etc.).
How to build ALPN
This section is for Jetty developers that need to update the ALPN implementation with the OpenJDK versions.
Clone the OpenJDK repository with the following command:
$ hg clone https://hg.openjdk.java.net/jdk8u/jdk8u jdk8u
$ cd !$
$ ./get_source.sh
To update the source to a specific tag, use the following command:
$ ./make/scripts/hgforest.sh update <tag-name>
The list of OpenJDK tags can be obtained from this page: OpenJDK 8 Tags.
You will then need to compare and incorporate the OpenJDK source changes into the modified OpenJDK classes at the ALPN GitHub Repository, branch master
.
HTTP/2
Introducing HTTP/2
Jetty supports both a client and a server implementation for the HTTP/2 protocol as defined by RFC 7540.
The requirements for running HTTP/2 are JDK 8 or greater, and typically also ALPN support (see Application Layer Protocol Negotiation (ALPN)).
A server deployed over TLS (SSL) normally advertises the HTTP/2 protocol via the TLS extension Application Layer Protocol Negotiation (ALPN).
To use HTTP/2 in Jetty via a TLS connector you need to add the ALPN boot jar in the boot classpath. This is done automatically when using the Jetty distribution’s start.jar module system, but must be configured directly otherwise. |
Jetty HTTP/2 Security Update
In mid-2019, there were a number of CVEs were issued warning against vulnerable HTTP/2 implementations. These CVEs (CVE-2019-9511 thru CVE-2019-9518) generally centered around attackers manipulating and flooding HTTP/2 servers and creating a denial of service (DOS). These vulnerabilities were patched with Jetty 9.4.21.
As a result of these CVEs, Jetty introduced a new, configurable denial of service (DOS) protection feature in Jetty 9.4.22.
Jetty’s HTTP/2 implementation now features a new Rate Control parameter, jetty.http2.rateControl.maxEventsPerSecond
, that defaults to 50 events per second, per connection for all pings, bad frames, settings frames, priority changes etc.
Jetty HTTP/2 Sub Projects
The Jetty HTTP/2 implementation consists of the following sub-projects (each producing a jar file):
-
http2-common
: Contains the HTTP/2 API and a partial implementation shared across other modules. -
http2-hpack
: Contains the HTTP/2 HPACK implementation for HTTP header compression. -
http2-server
: Provides the server-side implementation of HTTP/2. -
http2-client
: Provides the implementation of HTTP/2 client with a low level HTTP/2 API, dealing with HTTP/2 streams, frames, etc. -
http2-http-client-transport
: Provides the implementation of the HTTP/2 transport forHttpClient
(see HTTP Client). Applications can use the higher level API provided byHttpClient
to send HTTP requests and receive HTTP responses, and the HTTP/2 transport will take care of converting them in HTTP/2 format (see also this blog entry).
Enabling HTTP/2
This section is written assuming that a Jetty base directory is being used. A demo Jetty base that supports HTTP/1, HTTPS/1 and deployment from a webapps directory can be created with the commands:
$ JETTY_BASE=http2-demo
$ mkdir $JETTY_BASE
$ cd $JETTY_BASE
$ java -jar $JETTY_HOME/start.jar --add-to-start=http,https,deploy
The commands above create a $JETTY_BASE
directory called http2-demo
, and initializes the http,
https
and deploy
modules (and their dependencies) to run a typical Jetty Server on port 8080 (for HTTP/1) and 8443 (for HTTPS/1).
Note that the HTTPS module downloads a demo keystore file with a self signed certificate, which needs to be replaced by a Certificate Authority issued certificate for real deployment.
To add HTTP/2 to this demo base, it is just a matter of enabling the http2
module with the following command:
$ java -jar $JETTY_HOME/start.jar --add-to-start=http2
This command does not create a new connector, but instead simply adds the HTTP/2 protocol to the existing HTTPS/1 connector, so that it now supports both protocols on port 8443. To do this, it also transitively enables the ALPN module for protocol negotiation. The support for each protocol can be seen in the info logging when the server is started:
$ java -jar $JETTY_HOME/start.jar
...
2015-06-17 14:16:12.549:INFO:oejs.ServerConnector:main: Started ServerConnector@34c9c77f{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2015-06-17 14:16:12.782:INFO:oejs.ServerConnector:main: Started ServerConnector@711f39f9{SSL,[ssl, alpn, h2, h2-17, http/1.1]}{0.0.0.0:8443}
...
This log shows that port 8080 supports only HTTP/1.1 (which by specification includes HTTP/1.0 support), while port 8443 supports the SSL protocol, with ALPN negotiation to select between several versions of HTTP/2 (h2 & the draft h2-17) and HTTP/1.1. What is not shown is that HTTP/1.1 is the default ALPN protocol, so that if a client connects that does not speak ALPN, then HTTP/1.1 will be assumed.
A browser can now be pointed at https://localhost:8443/
and if it supports HTTP/2 then it will be used (often indicated by a lightening bolt icon in the address bar).
Note that a browser pointed at this server with URL starting with http://localhost:8080/
will still talk HTTP/1.1, as HTTP/2 has not been enabled on the plain text connector.
HTTP/2 can be enabled on the plain text connector and the server restarted with the following command:
$ java -jar $JETTY_HOME/start.jar --add-to-start=http2c
$ java -jar $JETTY_HOME/start.jar
..
2015-06-17 14:16:12.549:INFO:oejs.ServerConnector:main: Started ServerConnector@6f32cd1e{HTTP/1.1,[http/1.1, h2c, h2c-17]}{0.0.0.0:8080}
2015-06-17 14:16:12.782:INFO:oejs.ServerConnector:main: Started ServerConnector@711f39f9{SSL,[ssl, alpn, h2, h2-17, http/1.1]}{0.0.0.0:8443}
..
No major browser currently supports plain text HTTP/2, so the 8080 port will only be able to use HTTP/2 with specific clients (eg curl
) that use the upgrade mechanism or assume HTTP/2.
Configuring HTTP/2
Enabling the HTTP/2 module in the Jetty server does not create a HTTP/2 specific connector, but rather it adds a HTTP/2 Connection factory to an existing connector. Thus configuring HTTP/2 is a combination of configuring common properties on the connector and HTTP/2 specific properties on the connection factory. The modules and XML files involved can be seen with the following commands:
$ java -jar $JETTY_HOME/start.jar --list-modules
...
1) alpn-impl <transitive>
...
2) http ${jetty.base}/start.d/http.ini
2) ssl ${jetty.base}/start.d/ssl.ini
3) alpn ${jetty.base}/start.d/alpn.ini
3) http2c ${jetty.base}/start.d/http2c.ini
...
4) http2 ${jetty.base}/start.d/http2.ini
5) https ${jetty.base}/start.d/https.ini
$ java -jar $JETTY_HOME/start.jar --list-config
...
${jetty.home}/etc/jetty-ssl.xml
${jetty.home}/etc/jetty-ssl-context.xml
${jetty.home}/etc/jetty-alpn.xml
${jetty.home}/etc/jetty-http2c.xml
${jetty.home}/etc/jetty-http.xml
...
${jetty.home}/etc/jetty-http2.xml
${jetty.home}/etc/jetty-https.xml
The common properties associated with connectors (host,port, timeouts, etc.) can be set in the module ini files (or start.ini
if --add-to-start
was used): ${jetty.base}/start.d/http.ini
and ${jetty.base}/start.d/ssl.ini
.
These properties are instantiated in the associated XML files: ${jetty.home}/etc/jetty-http.xml
; ${jetty.home}/etc/jetty-ssl.xml
, plus the SSL keystore is instantiated in ${jetty.home}/etc/jetty-ssl-context.xml
.
If you are planning to edit XML files, make sure to copy them to your |
HTTP/2 specific properties can be set in the module ini files: ${jetty.base}/start.d/http2.ini
and ${jetty.base}/start.d/http2c.ini
, which are instantiated in the associated XML files: ${jetty.home}/etc/jetty-http2.xml
; ${jetty.home}/etc/jetty-http2c.xml
, respectively.
Currently there are very few HTTP/2 configuration properties and the default values are reasonable:
Property | Description |
---|---|
jetty.http2.maxConcurrentStreams |
The maximum number of concurrently open streams allowed on a single HTTP/2 connection (default 128). Larger values increase parallelism but cost a memory commitment. |
jetty.http2.initialSessionRecvWindow |
The initial receive flow control window size for a new session (default 1048576). Larger values may allow greater throughput but also risk head of line blocking if TCP/IP flow control is triggered. |
jetty.http2.initialStreamRecvWindow |
The initial receive flow control window size for a new stream (default 524288). Larger values may allow greater throughput but also risk head of line blocking if TCP/IP flow control is triggered. |
Configuring HTTP/2 Push
HTTP/2 Push is a mechanism that allows the server to send multiple resources to the client for a single client request. This will reduce the amount of round-trips necessary to retrieve all the resources that make up a web page and can significantly improve the page load time.
HTTP/2 Push can be automated in your application by configuring a PushCacheFilter
in the web.xml
, in this way:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
metadata-complete="true"
version="3.1">
...
<filter>
<filter-name>PushFilter</filter-name>
<filter-class>org.eclipse.jetty.servlets.PushCacheFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>PushFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
PushCacheFilter
analyzes the HTTP requests for resources that arrive to your web application.
Some of these requests contain the HTTP Referer
header that points to a resource that has been requested previously.
This allows the PushCacheFilter
to organize resources in a tree, for example a root index.html
resource having two children resources, styles.css
and application.js
, and styles.css
having a child resource, background.png
.
The root resource is called the primary resource, while descendant resources are called secondary resources.
The resource tree is built using a time window so that when a root resource is requested, only subsequent requests that are made within the time window will be added to the resource tree. The resource tree can also be limited in size so that the number of secondary resources associated to a primary resource is limited.
By default, only the resource path (without the query string) is used to associate secondary resources to the primary resource, but you can configure PushCacheFilter
to take the query string into account.
PushCacheFilter
can be configured with the following init-params
:
-
associatePeriod
: the time window, in milliseconds, within which a request for a secondary resource will be associated to a primary resource; defaults to 4000 ms -
maxAssociations
: the max number of secondary resources that may be associated to a primary resource; defaults to 16 -
hosts
: a comma separated list of hosts that are allowed in theReferer
header; defaults to the host in theHost
header -
ports
: a comma separated list of ports that are allowed in theReferer
header; defaults to the port in theHost
header -
useQueryInKey
: a boolean indicating whether the query string of the request should be considered when associating secondary resources to primary resources; defaults tofalse
Configuring HAProxy and Jetty
Typical website deployments have Apache (or Nginx) configured as reverse proxy to talk to one or more backend Jetty instances. This configuration cannot be used for HTTP/2 because Apache does not yet support HTTP/2 (nor does Nginx).
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 and has the major benefit that supports HTTP/2. It also offers load balancing and several other features which can position it as a complete replacement for Apache or Nginx.
The deployment proposed here will have HAProxy play the role that Apache and Nginx usually do: to perform the TLS offloading (that is, decrypt and encrypt TLS) and then forwarding the now clear-text traffic to a backend Jetty server, speaking either HTTP/1.1 or HTTP/2.
The instructions that follow are for Linux.
Installing HAProxy
You will need HAProxy 1.5 or later, because it provides support for SSL and ALPN, both required by HTTP/2. Most Linux distributions have the HAProxy package available to be installed out of the box. For example on Ubuntu 15.04:
$ sudo apt-get install haproxy
Alternatively you can download the HAProxy source code and build it on your environment by following the README bundled with the HAProxy source code tarball.
HAProxy supports ALPN only if built with OpenSSL 1.0.2 or greater.
Use |
Setup SSL for HAProxy
HAProxy will perform the TLS decryption and encryption much more efficiently than a Java implementation.
HAProxy will need a single file containing the X509 certificates and the private key, all in 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.
Let’s use keytool
to generate a self signed certificate:
$ keytool -genkeypair -keyalg RSA -keystore keystore.p12 -storetype pkcs12 -storepass storepwd -ext SAN=DNS:domain.com
What is your first and last name?
[Unknown]: *.domain.com
What is the name of your organizational unit?
[Unknown]: Unit
What is the name of your organization?
[Unknown]: Domain
What is the name of your City or Locality?
[Unknown]: Torino
What is the name of your State or Province?
[Unknown]: TO
What is the two-letter country code for this unit?
[Unknown]: IT
Is CN=*.domain.com, OU=Unit, O=Domain, L=Torino, ST=TO, C=IT correct?
[no]: yes
The above command will generate a self signed certificate and private key for domain.com
and subdomains, stored in the keystore.p12
file in PKCS#12 format.
We need to extract the certificate and the private key in PEM format.
To extract the certificate into certificate.pem
:
$ keytool -exportcert -keystore keystore.p12 -storetype pkcs12 -storepass storepwd -rfc -file certificate.pem
To export the private key into private_key.pem
:
$ openssl pkcs12 -in keystore.p12 -nodes -nocerts -out private_key.pem -passin pass:storepwd
At this point you just need to concatenate the two files into one, in the correct order:
$ cat certificate.pem private_key.pem > domain.pem
The domain.pem
file will be used later by HAProxy.
HAProxy Configuration File
Now we can setup haproxy.cfg
to configure HAProxy.
This is a minimal configuration:
global
tune.ssl.default-dh-param 1024
defaults
timeout connect 10000ms
timeout client 60000ms
timeout server 60000ms
frontend fe_http
mode http
bind *:80
# Redirect to https
redirect scheme https code 301
frontend fe_https
mode tcp
bind *:443 ssl no-sslv3 crt domain.pem ciphers TLSv1.2 alpn h2,http/1.1
default_backend be_http
backend be_http
mode tcp
server domain 127.0.0.1:8282
The HAProxy configuration file works in the following way.
The fe_http
front-end accepts connections on port 80 and redirects them to use the https
scheme.
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 domain.pem
part), the ciphers that are suitable for HTTP/2 (the ciphers TLSv1.2
), and the ALPN protocols supported (the alpn h2,http/1.1
).
This front-end then forwards the now decrypted bytes to the back-end in mode tcp
. The mode tcp
says that HAProxy will not try to interpret the bytes as HTTP/1.1 but instead opaquely forward them to the back-end.
The be_http
back-end 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.
Setup Jetty for HTTP/2 and HTTP/1.1
The Jetty setup follows the steps of having Jetty installed in the JETTY_HOME
directory, creating a JETTY_BASE
directory and initializing it using Jetty’s command line tools.
You must enable the http2c
module, that is the module that speaks clear-text HTTP/2.
Since the http2c
module depends on the http
module, the http
module will be enabled transitively, and the final setup will therefore support both HTTP/2 and HTTP/1.1 in clear text.
Additionally, you will also enable the deploy
module to be able to deploy a sample web application:
$ JETTY_BASE=haproxy-jetty-http2
$ mkdir $JETTY_BASE
$ cd $JETTY_BASE
$ java -jar $JETTY_HOME/start.jar --add-to-start=http2c,deploy
Now let’s deploy a demo web application and start Jetty:
$ cd $JETTY_BASE
$ cp $JETTY_HOME/demo-base/webapps/async-rest.war $JETTY_BASE/webapps/
$ java -jar $JETTY_HOME/start.jar jetty.http.host=127.0.0.1 jetty.http.port=8282
Now you can browse https://domain.com/async-rest (replace domain.com
with your own domain, or with localhost
, to make this example work).
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 |
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
module (and therefore transitively with the http
module) 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.
FastCGI Support
FastCGI Introduction
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 PHP, but also Python, Ruby, Perl and others.
Web servers that supports FastCGI are, among others, Apache, Nginx, and Jetty. Web servers typically act as 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 a HTTP response that is then returned to the client.
The most well known FastCGI server is the PHP FastCGI Process Manager, or php-fpm
.
In the following we will assume that php-fpm
is used as FastCGI server.
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 HTTP/2, the unique support that Jetty provides for HTTP/2 Push, Jetty’s scalability, and of course Jetty’s native support for Java Web Standards such as Servlets, JSPs, etc.
Configuring Jetty for FastCGI
In this section you will see how to configure Jetty to serve WordPress via FastCGI.
The first step is to have WordPress installed on your server machine, for example under /var/www/wordpress
.
For more information about how to install WordPress, please refer to the WordPress Installation Guide.
The second step is to install php-fpm
and make sure it is configured to listen on a TCP socket; typically it is configured to listen to localhost:9000
.
The third step is to install Jetty, for example under /opt/jetty
, called in the following $JETTY_HOME
.
Refer to Downloading Jetty for more information about how to install Jetty.
The fourth step is to create a Jetty base directory (see Managing Jetty Base and Jetty Home), called in the following $JETTY_BASE
, where you setup the configuration needed to support FastCGI in Jetty, and configure the fcgi
, http
and deploy
modules, so that Jetty will be able to accept HTTP requests from browsers, convert them in FastCGI, and proxy them to php-fpm
:
$ mkdir -p /usr/jetty/wordpress
$ cd /usr/jetty/wordpress
$ java -jar $JETTY_HOME/start.jar --add-to-start=fcgi,http,deploy
Therefore $JETTY_BASE=/usr/jetty/wordpress
.
The fifth step is to deploy the web application that provides the proxying of client requests to the FastCGI server, php-fpm
.
Typically this is done by deploying a *.war
file in the $JETTY_BASE/webapps
directory.
For FastCGI there is no web application that needs developed - all the work has already been done for you by Jetty.
As such you only need to deploy a Jetty context XML file that configures the web application directly.
Copy and paste the following content as $JETTY_BASE/webapps/jetty-wordpress.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.servlet.ServletContextHandler">
<New id="root" class="java.lang.String">
<Arg>/var/www/wordpress</Arg>
</New>
<Set name="contextPath">/</Set>
<Set name="resourceBase"><Ref refid="root" /></Set>
<Set name="welcomeFiles">
<Array type="string"><Item>index.php</Item></Array>
</Set>
<Call name="addFilter">
<Arg>org.eclipse.jetty.fcgi.server.proxy.TryFilesFilter</Arg>
<Arg>/*</Arg>
<Arg>
<Call name="of" class="java.util.EnumSet">
<Arg><Get name="REQUEST" class="javax.servlet.DispatcherType" /></Arg>
</Call>
</Arg>
<Call name="setInitParameter">
<Arg>files</Arg>
<Arg>$path /index.php?p=$path</Arg>
</Call>
</Call>
<Call name="addServlet">
<Arg>
<New class="org.eclipse.jetty.servlet.ServletHolder">
<Arg>default</Arg>
<Arg>
<Call name="forName" class="java.lang.Class">
<Arg>org.eclipse.jetty.servlet.DefaultServlet</Arg>
</Call>
</Arg>
<Call name="setInitParameter">
<Arg>dirAllowed</Arg>
<Arg>false</Arg>
</Call>
</New>
</Arg>
<Arg>/</Arg>
</Call>
<Call name="addServlet">
<Arg>org.eclipse.jetty.fcgi.server.proxy.FastCGIProxyServlet</Arg>
<Arg>*.php</Arg>
<Call name="setInitParameter">
<Arg>proxyTo</Arg>
<Arg>http://localhost:9000</Arg>
</Call>
<Call name="setInitParameter">
<Arg>prefix</Arg>
<Arg>/</Arg>
</Call>
<Call name="setInitParameter">
<Arg>scriptRoot</Arg>
<Arg><Ref refid="root" /></Arg>
</Call>
<Call name="setInitParameter">
<Arg>scriptPattern</Arg>
<Arg>(.+?\\.php)</Arg>
</Call>
</Call>
</Configure>
An explanation of the above contents:
-
Linne 6 specifies the WordPress installation directory, in this example
/var/www/wordpress
(as defined in the first step). -
Line 9 it is specified the context path at which WordPress will be served, in this example at the root context path
/
. -
Line 10 specifies the resource base of the context, also set to the WordPress installation directory. This allows Jetty to serve static resources directly from the WordPress installation directory.
-
Line 12 specifies the welcome file as
index.php
, so that Jetty can perform the proper redirects in case of URIs ending with the/
character. -
Line 15 specifies the
TryFilesFilter
, a Servlet Filter that has been inspired by the try_files functionality offered by Nginx. This filter tries to serve the resource from the file system first, and if the resource is not found it forwards the request asindex.php?p=$path
, which will match the proxy servlet defined below. Refer to the TryFilesFilter documentation for further information. -
Line 29specifies Jetty’s
DefaultServlet
to serve static content such as CSS files, JavaScript files, etc.DefaultServlet
will serve these files by looking in the resource base of the context, defined at line 10 (see above). -
Line 47 specifies the
FastCGIProxyServlet
, a Servlet that proxies HTTP requests arriving from clients to FastCGI requests to the FastCGI server. -
Line 52 specifies the TCP address of the FastCGI server (
php-fpm
), where HTTP requests are forwarded as FastCGI requests. -
Line 60 specifies once again the WordPress installation directory, so that the
FastCGIProxyServlet
can pass this information to the FastCGI server. -
Line 64 specifies a regular expression that matches request URIs performed to this servlet, in addition to the standard URL mapping defined by Servlet at line 49. Refer to the FastCGIProxyServlet documentation for further information.
The last step is to start Jetty (see Starting Jetty) and navigate to http://localhost:8080
with your browser and enjoy WordPress:
$ cd $JETTY_BASE
$ java -jar /opt/jetty/start.jar
Configuring Jetty to Proxy HTTP/2 to FastCGI
In order to configure Jetty to listen for HTTP/2 requests from clients that are HTTP/2 enabled and forward them to the FastCGI server as FastCGI requests, you need to enable the http2
module, which in turn will require a TLS connector and consequently a keystore to read the key material required by TLS.
Enabling the http2
is easy; in additions to the modules you have enabled above, add the http2
module:
$ cd $JETTY_BASE
$ java -jar $JETTY_HOME/start.jar --add-to-start=http2
The command above adds the http2
module (and its dependencies) to the existing modules and uses the default Jetty keystore to provide the key material required by TLS.
You will want to use your own keystore with your own private key and certificate for your own domain.
Remember that by adding the http2
module, you will start two JVMs: one that reads the configuration, and one that has the ALPN boot boot jar in the boot classpath, as explained in Configuring HTTP/2.
Since now your site will run over TLS, you need to make sure that the WordPress URL is also configured so.
If you have followed the steps of the previous section, your WordPress site is served at http://localhost:8080
.
You will need to change that to be https://localhost:8443
from the WordPress administration web interface, or follow the WordPress instructions to do so without using the administration web interface.
The minimal modules required to run WordPress with Jetty on HTTP/2 are therefore: http2
, http
, fcgi
and deploy
.
These will setup a clear text connector on port 8080 for HTTP/1.1 and a TLS connector on port 8443 for HTTP/2 and HTTP/1.1.
At this point, you can start Jetty (see Starting Jetty), hit http://localhost:8080
with your browser and enjoy WordPress via HTTP/2 using a HTTP/2 enabled browser:
$ cd $JETTY_BASE
$ java -jar $JETTY_HOME/start.jar
If you don’t have a HTTP/2 enabled browser, WordPress will still be available over HTTP/1.1.