blob: 0a482df1efd7321b27c50930814a2aea042198b0 [file] [log] [blame]
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Configuring HAProxy and Jetty</title><link rel="stylesheet" type="text/css" href="css/docbook.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"><meta name="keywords" content="jetty, servlet, servlet-api, cometd, http, websocket, eclipse, maven, java, server, software"><link rel="home" href="index.html" title="Jetty"><link rel="up" href="http2.html" title="Chapter&nbsp;16.&nbsp;HTTP/2"><link rel="prev" href="http2-configuring-push.html" title="Configuring HTTP/2 Push"><link rel="next" href="fastcgi.html" title="Chapter&nbsp;17.&nbsp;FastCGI Support"><link xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times" rel="shortcut icon" href="images/favicon.ico"><link rel="stylesheet" href="css/highlighter/foundation.css"><script src="js/highlight.pack.js"></script><script>
hljs.initHighlightingOnLoad();
</script><link type="text/css" rel="stylesheet" href="css/font-awesome/font-awesome.min.css"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times"><tr><td style="width: 25%"><a href="http://www.eclipse.org/jetty"><img src="images/jetty-header-logo.png" alt="Jetty Logo"></a><br><span style="font-size: small">
Version: 9.4.28-SNAPSHOT</span></td><td style="width: 50%"></td></tr></table><div xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times" class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Configuring HAProxy and Jetty</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="http2-configuring-push.html"><i class="fa fa-chevron-left" aria-hidden="true"></i> Previous</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;16.&nbsp;HTTP/2<br><a accesskey="p" href="index.html"><i class="fa fa-home" aria-hidden="true"></i> Home</a></th><td width="20%" align="right">&nbsp;<a accesskey="n" href="fastcgi.html">Next <i class="fa fa-chevron-right" aria-hidden="true"></i></a></td></tr></table><hr></div><div xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times" class="jetty-callout"><h5 class="callout"><a href="http://www.webtide.com/">Contact the core Jetty developers at
<span class="website">www.webtide.com</span></a></h5><p>
private support for your internal/customer projects ... custom extensions and distributions ... versioned snapshots for indefinite support ...
scalability guidance for your apps and Ajax/Comet projects ... development services for sponsored feature development
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="http2-configuring-haproxy"></a>Configuring HAProxy and Jetty</h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="section"><a href="http2-configuring-haproxy.html#http2-haproxy-install">Installing HAProxy</a></span></dt><dt><span class="section"><a href="http2-configuring-haproxy.html#http2-haproxy-ssl">Setup SSL for HAProxy</a></span></dt><dt><span class="section"><a href="http2-configuring-haproxy.html#http2-haproxy-cfg">HAProxy Configuration File</a></span></dt><dt><span class="section"><a href="http2-configuring-haproxy.html#http2-haproxy-jetty">Setup Jetty for HTTP/2 and HTTP/1.1</a></span></dt></dl></div><p>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).</p><p><a class="link" href="http://haproxy.org" target="_top">HAProxy</a> 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.</p><p>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.</p><p>The instructions that follow are for Linux.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="http2-haproxy-install"></a>Installing HAProxy</h3></div></div></div><p>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:</p><div class="screenexample"><pre class="screen">$ sudo apt-get install haproxy</pre></div><p>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.</p><div class="blockquote"><blockquote class="blockquote"><div xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times" class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title"><i class="fa fa-asterisk" aria-hidden="true"></i> Note</h3><p>HAProxy supports ALPN only if built with OpenSSL 1.0.2 or greater.
Use <code class="literal">haproxy -vv</code> to know with which OpenSSL version HAProxy has been built.</p></div></blockquote></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="http2-haproxy-ssl"></a>Setup SSL for HAProxy</h3></div></div></div><p>HAProxy will perform the TLS decryption and encryption much more efficiently than a Java implementation.</p><p>HAProxy will need a single file containing the X509 certificates and the private key, all in <a class="link" href="https://en.wikipedia.org/wiki/X.509" target="_top">PEM format</a>, with the following order:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">The site certificate; this certificate&#8217;s Common Name refers to the site domain (for example: CN=*.webtide.com) and is signed by Certificate Authority #1.</li><li class="listitem">The Certificate Authority #1 certificate; this certificate may be signed by Certificate Authority #2.</li><li class="listitem">The Certificate Authority #2 certificate; this certificate may be signed by Certificate Authority #3; and so on until the Root Certificate Authority.</li><li class="listitem">The Root Certificate Authority certificate.</li><li class="listitem">The private key corresponding to the site certificate.</li></ol></div><p>Let&#8217;s use <code class="literal">keytool</code> to generate a self signed certificate:</p><div class="screenexample"><pre class="screen">$ 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</pre></div><p>The above command will generate a self signed certificate and private key for <code class="literal">domain.com</code> and subdomains, stored in the <code class="literal">keystore.p12</code> file in PKCS#12 format.
We need to extract the certificate and the private key in PEM format.</p><p>To extract the certificate into <code class="literal">certificate.pem</code>:</p><div class="screenexample"><pre class="screen">$ keytool -exportcert -keystore keystore.p12 -storetype pkcs12 -storepass storepwd -rfc -file certificate.pem</pre></div><p>To export the private key into <code class="literal">private_key.pem</code>:</p><div class="screenexample"><pre class="screen">$ openssl pkcs12 -in keystore.p12 -nodes -nocerts -out private_key.pem -passin pass:storepwd</pre></div><p>At this point you just need to concatenate the two files into one, in the correct order:</p><div class="screenexample"><pre class="screen">$ cat certificate.pem private_key.pem &gt; domain.pem</pre></div><p>The <code class="literal">domain.pem</code> file will be used later by HAProxy.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="http2-haproxy-cfg"></a>HAProxy Configuration File</h3></div></div></div><p>Now we can setup <code class="literal">haproxy.cfg</code> to configure HAProxy.
This is a minimal configuration:</p><pre class="screen">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</pre><p>The HAProxy configuration file works in the following way.
The <code class="literal">fe_http</code> front-end accepts connections on port 80 and redirects them to use the <code class="literal">https</code> scheme.</p><p>The <code class="literal">fe_https</code> 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 <code class="literal">crt domain.pem</code> part), the ciphers that are suitable for HTTP/2 (the <code class="literal">ciphers TLSv1.2</code>), and the ALPN protocols supported (the <code class="literal">alpn h2,http/1.1</code> ).
This front-end then forwards the now decrypted bytes to the back-end in <code class="literal">mode tcp</code>. The <code class="literal">mode tcp</code> says that HAProxy will not try to interpret the bytes as HTTP/1.1 but instead opaquely forward them to the back-end.</p><p>The <code class="literal">be_http</code> back-end will forward (again in <code class="literal">mode tcp</code>) the clear-text bytes to a Jetty connector that talks clear-text HTTP/2 and HTTP/1.1 on port 8282.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="http2-haproxy-jetty"></a>Setup Jetty for HTTP/2 and HTTP/1.1</h3></div></div></div><p>The Jetty setup follows the steps of having Jetty installed in the <code class="literal">JETTY_HOME</code> directory, creating a <code class="literal">JETTY_BASE</code> directory and initializing it using Jetty&#8217;s command line tools.
You must enable the <code class="literal">http2c</code> module, that is the module that speaks clear-text HTTP/2.
Since the <code class="literal">http2c</code> module depends on the <code class="literal">http</code> module, the <code class="literal">http</code> module will be enabled transitively, and the final setup will therefore support both HTTP/2 and HTTP/1.1 in clear text.</p><p>Additionally, you will also enable the <code class="literal">deploy</code> module to be able to deploy a sample web application:</p><div class="screenexample"><pre class="screen">$ JETTY_BASE=haproxy-jetty-http2
$ mkdir $JETTY_BASE
$ cd $JETTY_BASE
$ java -jar $JETTY_HOME/start.jar --add-to-start=http2c,deploy</pre></div><p>Now let&#8217;s deploy a demo web application and start Jetty:</p><div class="screenexample"><pre class="screen">$ 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</pre></div><p>Now you can browse <a class="link" href="https://domain.com/async-rest" target="_top">https://domain.com/async-rest</a> (replace <code class="literal">domain.com</code> with your own domain, or with <code class="literal">localhost</code>, to make this example work).</p><div class="blockquote"><blockquote class="blockquote"><div xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times" class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title"><i class="fa fa-asterisk" aria-hidden="true"></i> Note</h3><p>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 <code class="literal">jetty.http.host</code> property on the command line (or in <code class="literal">start.ini</code>/ <code class="literal">start.d/http.ini</code> 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 <code class="literal">jetty.http.host</code> property to match accordingly.</p></div></blockquote></div><p>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.</p><p>The Jetty connector, configured with the <code class="literal">http2c</code> module (and therefore transitively with the <code class="literal">http</code> module) is able to distinguish whether the incoming bytes are HTTP/2 or HTTP/1.1 and will handle the request accordingly.</p><p>The response is relayed back to HAProxy, which will encrypt it and send it back to the remote client.</p><p>This configuration offers you efficient TLS offloading, HTTP/2 support and transparent fallback to HTTP/1.1 for clients that don&#8217;t support HTTP/1.1.</p></div></div><script type="text/javascript">
SyntaxHighlighter.all()
</script><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="http2-configuring-push.html"><i class="fa fa-chevron-left" aria-hidden="true"></i> Previous</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="http2.html"><i class="fa fa-chevron-up" aria-hidden="true"></i> Top</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="fastcgi.html">Next <i class="fa fa-chevron-right" aria-hidden="true"></i></a></td></tr><tr><td width="40%" align="left" valign="top">Configuring HTTP/2 Push&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html"><i class="fa fa-home" aria-hidden="true"></i> Home</a></td><td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;17.&nbsp;FastCGI Support</td></tr></table></div><p xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times"><div class="jetty-callout">
See an error or something missing?
<span class="callout"><a href="http://github.com/eclipse/jetty.project">Contribute to this documentation at
<span class="website"><i class="fa fa-github" aria-hidden="true"></i> Github!</span></a></span><span style="float: right"><i>(Generated: 2020-03-10)</i></span></div></p></body></html>