Merge pull request #758 from WalkerWatch/docupdates/chapter16
Chapter 16 updates
This commit is contained in:
commit
e800e616d6
|
@ -20,10 +20,10 @@
|
|||
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).
|
||||
|
||||
http://haproxy.org[HAProxy] is an open source solution that offers load balancing and proxying for TCP and HTTP based application, and can be used as a replacement for Apache (or Nginx) when these are used as reverse proxies, and has the major benefit that supports HTTP/2.
|
||||
It also offers load balancing and a ton of other features, so you can probably use it as a replacement for Apache (or Nginx).
|
||||
http://haproxy.org[HAProxy] is an open source solution that offers load balancing and proxying for TCP and HTTP based application, and can be used as a replacement for Apache or Nginx when these are used as reverse proxies 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 (or 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 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.
|
||||
|
||||
|
@ -32,20 +32,18 @@ The instructions that follow are for Linux.
|
|||
|
||||
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:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source,screen, subs="{sub-order}"]
|
||||
....
|
||||
$ 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.
|
||||
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.
|
||||
|
||||
____
|
||||
[NOTE]
|
||||
HAProxy supports ALPN only if built with OpenSSL 1.0.2 or greater.
|
||||
Alternatively, HAProxy supports NPN when built with OpenSSL 1.0.1 or greater.
|
||||
You must upgrade OpenSSL if you have a version earlier than 1.0.1.
|
||||
|
||||
Use `haproxy -vv` to know with which OpenSSL version HAProxy has been built.
|
||||
____
|
||||
|
||||
|
@ -56,7 +54,7 @@ HAProxy will perform the TLS decryption and encryption much more efficiently tha
|
|||
|
||||
HAProxy will need a single file containing the X509 certificates and the private key, all in https://en.wikipedia.org/wiki/X.509[PEM format], with the following order:
|
||||
|
||||
1. The site certificate; this certificate's Common Name refers to the site domain (for example: CN=*.webtide.com) and it's signed by Certificate Authority #1.
|
||||
1. 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.
|
||||
2. The Certificate Authority #1 certificate; this certificate may be signed by Certificate Authority #2.
|
||||
3. The Certificate Authority #2 certificate; this certificate may be signed by Certificate Authority #3; and so on until the Root Certificate Authority.
|
||||
4. The Root Certificate Authority certificate.
|
||||
|
@ -64,8 +62,8 @@ HAProxy will need a single file containing the X509 certificates and the private
|
|||
|
||||
Let's use `keytool` to generate a self signed certificate:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source,screen, subs="{sub-order}"]
|
||||
....
|
||||
$ 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
|
||||
|
@ -81,35 +79,31 @@ 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`:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source,screen, subs="{sub-order}"]
|
||||
....
|
||||
$ keytool -exportcert -keystore keystore.p12 -storetype pkcs12 -storepass storepwd -rfc -file certificate.pem
|
||||
|
||||
----
|
||||
....
|
||||
|
||||
To export the private key into `private_key.pem`:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source,screen, subs="{sub-order}"]
|
||||
....
|
||||
$ 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:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source,screen, subs="{sub-order}"]
|
||||
....
|
||||
$ cat certificate.pem private_key.pem > domain.pem
|
||||
|
||||
----
|
||||
....
|
||||
|
||||
The `domain.pem` file will be used later by HAProxy.
|
||||
|
||||
|
@ -119,6 +113,7 @@ The `domain.pem` file will be used later by HAProxy.
|
|||
Now we can setup `haproxy.cfg` to configure HAProxy.
|
||||
This is a minimal configuration:
|
||||
|
||||
[source, ,subs="{sub-order}"]
|
||||
....
|
||||
global
|
||||
tune.ssl.default-dh-param 1024
|
||||
|
@ -142,52 +137,49 @@ 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` part), and the ALPN (or NPN if you are using old OpenSSL versions) protocols supported (the `alpn h2,http/1.1` part).
|
||||
This front-end then forwards the now decrypted bytes to the back-end in `mode tcp`. The `mode tcp`) means that HAProxy will not try to interpret the bytes as HTTP/1.1 but just opaquely forward them to the back-end.
|
||||
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.
|
||||
|
||||
[[http2-haproxy-jetty]]
|
||||
==== Setup Jetty for HTTP/2 and HTTP/1.1
|
||||
|
||||
The Jetty setup follows the usual steps of having Jetty installed in the `JETTY_HOME` directory, creating a `JETTY_BASE` directory and initializing it using Jetty's command line tools.
|
||||
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:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source,screen, subs="{sub-order}"]
|
||||
....
|
||||
$ 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:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source,screen, subs="{sub-order}"]
|
||||
....
|
||||
$ 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).
|
||||
|
||||
____
|
||||
[NOTE]
|
||||
You want the Jetty connector that listens on port 8282 to be available only to HAProxy, and not to remote clients.
|
||||
For this reason, you want to specify the `jetty.http.host` property on the command line (or in `start.ini` to make this setting persistent) to bind the Jetty connector only on the loopback interface (127.0.0.1), making it available to HAProxy but not to remote clients.
|
||||
For this reason, you want to specify the `jetty.http.host` property on the command line (or in `start.ini`/ `start.d/http.ini` to make this setting persistent) to bind the Jetty connector only on the loopback interface (127.0.0.1), making it available to HAProxy but not to remote clients.
|
||||
If your Jetty instance runs on a different machine and/or on a different (sub)network, you may want to adjust both the back-end section of the HAProxy configuration file and the `jetty.http.host` property to match accordingly.
|
||||
____
|
||||
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
[[http2-configuring]]
|
||||
=== 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
|
||||
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:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source,screen, subs="{sub-order}"]
|
||||
....
|
||||
$ java -jar $JETTY_HOME/start.jar --list-modules
|
||||
...
|
||||
1) protonego-boot <transitive>
|
||||
|
@ -46,13 +46,17 @@ $ java -jar $JETTY_HOME/start.jar --list-config
|
|||
...
|
||||
${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` `${jetty.base}/start.d/ssl.ini`.
|
||||
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`.
|
||||
|
||||
HTTP/2 specific properties can be set in the module ini files: `${jetty.base}/start.d/http2.ini`; `${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`.
|
||||
[NOTE]
|
||||
If you are planning to edit XML files, make sure to copy them to your `{$jetty.base}/etc/` directory before doing so.
|
||||
The XML files that come with the Jetty distribution should *not* be modified directly.
|
||||
----
|
||||
|
||||
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:
|
||||
|
||||
.HTTP/2 Configuration Properties
|
||||
|
|
|
@ -18,13 +18,12 @@
|
|||
=== 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.
|
||||
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 simply configuring a link:{JDURL}/org/eclipse/jetty/servlets/PushCacheFilter.html[`PushCacheFilter`] in your `web.xml`, in this way:
|
||||
HTTP/2 Push can be automated in your application by configuring a link:{JDURL}/org/eclipse/jetty/servlets/PushCacheFilter.html[`PushCacheFilter`] in the `web.xml`, in this way:
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app
|
||||
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
|
@ -34,7 +33,6 @@ HTTP/2 Push can be automated in your application by simply configuring a link:{J
|
|||
version="3.1">
|
||||
|
||||
...
|
||||
|
||||
<filter>
|
||||
<filter-name>PushFilter</filter-name>
|
||||
<filter-class>org.eclipse.jetty.servlets.PushCacheFilter</filter-class>
|
||||
|
@ -44,17 +42,14 @@ HTTP/2 Push can be automated in your application by simply configuring a link:{J
|
|||
<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 `Referrer` header that points to a resource that has been requested previously.
|
||||
This allows the `PushCacheFilter` to organize resources in _primary_ resources (those referenced by the `Referrer` header) and _secondary_ resources (those that have the `Referer` header).
|
||||
This allows the `PushCacheFilter` to organize resources in to two categories: _primary_ resources (those referenced by the `Referrer` header) and _secondary_ resources (those that have the `Referer` header).
|
||||
|
||||
`PushCacheFilter` associates secondary resources to primary resources.
|
||||
Only secondary resources that have been requested within a time window from the request of the primary resource are associated with the primary resource.
|
||||
|
@ -62,4 +57,3 @@ Only secondary resources that have been requested within a time window from the
|
|||
`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.
|
||||
* `maxAssociations`: the max number of secondary resources that may be associated to a primary resource.
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
[[http2-enabling]]
|
||||
=== Enabling HTTP/2
|
||||
|
||||
This section is written assuming that a jetty base directory is being used and a demo jetty base that support HTTP/1, HTTPS/1 and deployment from a webapps directory can be created with the commands:
|
||||
This section is written assuming that a link:#startup-base-and-home[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:
|
||||
|
||||
[source, screen, subs="{sub-order}"]
|
||||
....
|
||||
|
@ -28,20 +29,20 @@ $ java -jar $JETTY_HOME/start.jar --add-to-startd=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.
|
||||
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:
|
||||
To add HTTP/2 to this demo base, it is just a matter of enabling the `http2` module with the following command:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source, screen, subs="{sub-order}"]
|
||||
....
|
||||
$ java -jar $JETTY_HOME/start.jar --add-to-startd=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:
|
||||
|
||||
[source,shell]
|
||||
[source,screen, subs="{sub-order}"]
|
||||
----
|
||||
$ java -jar $JETTY_HOME/start.jar
|
||||
...
|
||||
|
@ -51,21 +52,21 @@ $ java -jar $JETTY_HOME/start.jar
|
|||
----
|
||||
|
||||
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.
|
||||
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:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
[source,screen]
|
||||
....
|
||||
$ java -jar $JETTY_HOME/start.jar --add-to-startd=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}
|
||||
...
|
||||
----
|
||||
..
|
||||
....
|
||||
|
||||
However, 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
|
||||
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.
|
||||
|
|
|
@ -25,18 +25,18 @@ A server deployed over TLS (SSL) normally advertises the HTTP/2 protocol via the
|
|||
|
||||
____
|
||||
[IMPORTANT]
|
||||
To use HTTP/2 in Jetty via a TLS connector you need to add the link:#alpn-starting[ALPN boot Jar in the boot classpath.]
|
||||
This is done automatically when using the jetty distributions start.jar module system, but must be configured directly otherwise.
|
||||
To use HTTP/2 in Jetty via a TLS connector you need to add the link:#alpn-starting[ALPN boot jar] in the boot classpath.
|
||||
This is done automatically when using the Jetty distribution's start.jar link:#startup-modules[module system], but must be configured directly otherwise.
|
||||
____
|
||||
|
||||
[[http2-modules]]
|
||||
==== Jetty HTTP/2 Sub Projects
|
||||
=== Jetty HTTP/2 Sub Projects
|
||||
|
||||
The Jetty HTTP/2 implementation consists of the following sub-projects (each producing a jar):
|
||||
The Jetty HTTP/2 implementation consists of the following sub-projects (each producing a jar file):
|
||||
|
||||
1. `http2-common`: contains the HTTP/2 API and a partial implementation shared across other modules.
|
||||
2. `http2-hpack`: contains the HTTP/2 HPACK implementation for HTTP header compression.
|
||||
3. `http2-server`: provides the server-side implementation of HTTP/2.
|
||||
4. `http2-client`: provides the implementation of HTTP/2 client with a low level HTTP/2 API, dealing with HTTP/2 streams, frames, etc.
|
||||
5. `http2-http-client-transport`: provides the implementation of the HTTP/2 transport for `HttpClient` (see xref:http-client[]).
|
||||
1. `http2-common`: Contains the HTTP/2 API and a partial implementation shared across other modules.
|
||||
2. `http2-hpack`: Contains the HTTP/2 HPACK implementation for HTTP header compression.
|
||||
3. `http2-server`: Provides the server-side implementation of HTTP/2.
|
||||
4. `http2-client`: Provides the implementation of HTTP/2 client with a low level HTTP/2 API, dealing with HTTP/2 streams, frames, etc.
|
||||
5. `http2-http-client-transport`: Provides the implementation of the HTTP/2 transport for `HttpClient` (see xref:http-client[]).
|
||||
Applications can use the higher level API provided by `HttpClient` 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 https://webtide.com/http2-support-for-httpclient/[this blog entry]).
|
Loading…
Reference in New Issue