571 lines
21 KiB
ReStructuredText
571 lines
21 KiB
ReStructuredText
.. program:: nghttpx
|
|
|
|
nghttpx - HTTP/2 proxy - HOW-TO
|
|
===============================
|
|
|
|
:doc:`nghttpx.1` is a proxy translating protocols between HTTP/2 and
|
|
other protocols (e.g., HTTP/1). It operates in several modes and each
|
|
mode may require additional programs to work with. This article
|
|
describes each operation mode and explains the intended use-cases. It
|
|
also covers some useful options later.
|
|
|
|
Default mode
|
|
------------
|
|
|
|
If nghttpx is invoked without :option:`--http2-proxy`, it operates in
|
|
default mode. In this mode, it works as reverse proxy (gateway) for
|
|
both HTTP/2 and HTTP/1 clients to backend servers. This is also known
|
|
as "HTTP/2 router".
|
|
|
|
By default, frontend connection is encrypted using SSL/TLS. So
|
|
server's private key and certificate must be supplied to the command
|
|
line (or through configuration file). In this case, the frontend
|
|
protocol selection will be done via ALPN or NPN.
|
|
|
|
To turn off encryption on frontend connection, use ``no-tls`` keyword
|
|
in :option:`--frontend` option. HTTP/2 and HTTP/1 are available on
|
|
the frontend, and an HTTP/1 connection can be upgraded to HTTP/2 using
|
|
HTTP Upgrade. Starting HTTP/2 connection by sending HTTP/2 connection
|
|
preface is also supported.
|
|
|
|
nghttpx can listen on multiple frontend addresses. This is achieved
|
|
by using multiple :option:`--frontend` options. For each frontend
|
|
address, TLS can be enabled or disabled.
|
|
|
|
By default, backend connections are not encrypted. To enable TLS
|
|
encryption on backend connections, use ``tls`` keyword in
|
|
:option:`--backend` option. Using patterns and ``proto`` keyword in
|
|
:option:`--backend` option, backend application protocol can be
|
|
specified per host/request path pattern. It means that you can use
|
|
both HTTP/2 and HTTP/1 in backend connections at the same time. Note
|
|
that default backend protocol is HTTP/1.1. To use HTTP/2 in backend,
|
|
you have to specify ``h2`` in ``proto`` keyword in :option:`--backend`
|
|
explicitly.
|
|
|
|
The backend is supposed to be a Web server. For example, to make
|
|
nghttpx listen to encrypted HTTP/2 requests at port 8443, and a
|
|
backend Web server is configured to listen to HTTP requests at port
|
|
8080 on the same host, run nghttpx command-line like this:
|
|
|
|
.. code-block:: text
|
|
|
|
$ nghttpx -f0.0.0.0,8443 -b127.0.0.1,8080 /path/to/server.key /path/to/server.crt
|
|
|
|
Then an HTTP/2 enabled client can access the nghttpx server using HTTP/2. For
|
|
example, you can send a GET request using nghttp:
|
|
|
|
.. code-block:: text
|
|
|
|
$ nghttp -nv https://localhost:8443/
|
|
|
|
HTTP/2 proxy mode
|
|
-----------------
|
|
|
|
If nghttpx is invoked with :option:`--http2-proxy` (or its shorthand
|
|
:option:`-s`) option, it operates in HTTP/2 proxy mode. The supported
|
|
protocols in frontend and backend connections are the same as in `default
|
|
mode`_. The difference is that this mode acts like a forward proxy and
|
|
assumes the backend is an HTTP proxy server (e.g., Squid, Apache Traffic
|
|
Server). HTTP/1 requests must include an absolute URI in request line.
|
|
|
|
By default, the frontend connection is encrypted. So this mode is
|
|
also called secure proxy.
|
|
|
|
To turn off encryption on the frontend connection, use ``no-tls`` keyword
|
|
in :option:`--frontend` option.
|
|
|
|
The backend must be an HTTP proxy server. nghttpx supports multiple
|
|
backend server addresses. It translates incoming requests to HTTP
|
|
request to backend server. The backend server performs real proxy
|
|
work for each request, for example, dispatching requests to the origin
|
|
server and caching contents.
|
|
|
|
The backend connection is not encrypted by default. To enable
|
|
encryption, use ``tls`` keyword in :option:`--backend` option. The
|
|
default backend protocol is HTTP/1.1. To use HTTP/2 in backend
|
|
connection, use :option:`--backend` option, and specify ``h2`` in
|
|
``proto`` keyword explicitly.
|
|
|
|
For example, to make nghttpx listen to encrypted HTTP/2 requests at
|
|
port 8443, and a backend HTTP proxy server is configured to listen to
|
|
HTTP/1 requests at port 8080 on the same host, run nghttpx command-line
|
|
like this:
|
|
|
|
.. code-block:: text
|
|
|
|
$ nghttpx -s -f'*,8443' -b127.0.0.1,8080 /path/to/server.key /path/to/server.crt
|
|
|
|
At the time of this writing, Firefox 41 and Chromium v46 can use
|
|
nghttpx as HTTP/2 proxy.
|
|
|
|
To make Firefox or Chromium use nghttpx as HTTP/2 proxy, user has to
|
|
create proxy.pac script file like this:
|
|
|
|
.. code-block:: javascript
|
|
|
|
function FindProxyForURL(url, host) {
|
|
return "HTTPS SERVERADDR:PORT";
|
|
}
|
|
|
|
``SERVERADDR`` and ``PORT`` is the hostname/address and port of the
|
|
machine nghttpx is running. Please note that both Firefox and
|
|
Chromium require valid certificate for secure proxy.
|
|
|
|
For Firefox, open Preference window and select Advanced then click
|
|
Network tab. Clicking Connection Settings button will show the
|
|
dialog. Select "Automatic proxy configuration URL" and enter the path
|
|
to proxy.pac file, something like this:
|
|
|
|
.. code-block:: text
|
|
|
|
file:///path/to/proxy.pac
|
|
|
|
For Chromium, use following command-line:
|
|
|
|
.. code-block:: text
|
|
|
|
$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
|
|
|
|
As HTTP/1 proxy server, Squid may work as out-of-box. Traffic server
|
|
requires to be configured as forward proxy. Here is the minimum
|
|
configuration items to edit:
|
|
|
|
.. code-block:: text
|
|
|
|
CONFIG proxy.config.reverse_proxy.enabled INT 0
|
|
CONFIG proxy.config.url_remap.remap_required INT 0
|
|
|
|
Consult Traffic server `documentation
|
|
<http://trafficserver.readthedocs.org/en/latest/admin-guide/configuration/transparent-forward-proxying.en.html>`_
|
|
to know how to configure traffic server as forward proxy and its
|
|
security implications.
|
|
|
|
ALPN support
|
|
------------
|
|
|
|
ALPN support requires OpenSSL >= 1.0.2.
|
|
|
|
Disable frontend SSL/TLS
|
|
------------------------
|
|
|
|
The frontend connections are encrypted with SSL/TLS by default. To
|
|
turn off SSL/TLS, use ``no-tls`` keyword in :option:`--frontend`
|
|
option. If this option is used, the private key and certificate are
|
|
not required to run nghttpx.
|
|
|
|
Enable backend SSL/TLS
|
|
----------------------
|
|
|
|
The backend connections are not encrypted by default. To enable
|
|
SSL/TLS encryption, use ``tls`` keyword in :option:`--backend` option.
|
|
|
|
Enable SSL/TLS on memcached connection
|
|
--------------------------------------
|
|
|
|
By default, memcached connection is not encrypted. To enable
|
|
encryption, use ``tls`` keyword in
|
|
:option:`--tls-ticket-key-memcached` for TLS ticket key, and
|
|
:option:`--tls-session-cache-memcached` for TLS session cache.
|
|
|
|
Specifying additional server certificates
|
|
-----------------------------------------
|
|
|
|
nghttpx accepts additional server private key and certificate pairs
|
|
using :option:`--subcert` option. It can be used multiple times.
|
|
|
|
Specifying additional CA certificate
|
|
------------------------------------
|
|
|
|
By default, nghttpx tries to read CA certificate from system. But
|
|
depending on the system you use, this may fail or is not supported.
|
|
To specify CA certificate manually, use :option:`--cacert` option.
|
|
The specified file must be PEM format and can contain multiple
|
|
certificates.
|
|
|
|
By default, nghttpx validates server's certificate. If you want to
|
|
turn off this validation, knowing this is really insecure and what you
|
|
are doing, you can use :option:`--insecure` option to disable
|
|
certificate validation.
|
|
|
|
Read/write rate limit
|
|
---------------------
|
|
|
|
nghttpx supports transfer rate limiting on frontend connections. You
|
|
can do rate limit per frontend connection for reading and writing
|
|
individually.
|
|
|
|
To perform rate limit for reading, use :option:`--read-rate` and
|
|
:option:`--read-burst` options. For writing, use
|
|
:option:`--write-rate` and :option:`--write-burst`.
|
|
|
|
Please note that rate limit is performed on top of TCP and nothing to
|
|
do with HTTP/2 flow control.
|
|
|
|
Rewriting location header field
|
|
-------------------------------
|
|
|
|
nghttpx automatically rewrites location response header field if the
|
|
following all conditions satisfy:
|
|
|
|
* In the default mode (:option:`--http2-proxy` is not used)
|
|
* :option:`--no-location-rewrite` is not used
|
|
* URI in location header field is an absolute URI
|
|
* URI in location header field includes non empty host component.
|
|
* host (without port) in URI in location header field must match the
|
|
host appearing in ``:authority`` or ``host`` header field.
|
|
|
|
When rewrite happens, URI scheme is replaced with the ones used in
|
|
frontend, and authority is replaced with which appears in
|
|
``:authority``, or ``host`` request header field. ``:authority``
|
|
header field has precedence over ``host``.
|
|
|
|
Hot swapping
|
|
------------
|
|
|
|
nghttpx supports hot swapping using signals. The hot swapping in
|
|
nghttpx is multi step process. First send USR2 signal to nghttpx
|
|
process. It will do fork and execute new executable, using same
|
|
command-line arguments and environment variables.
|
|
|
|
As of nghttpx version 1.20.0, that is all you have to do. The new
|
|
master process sends QUIT signal to the original process, when it is
|
|
ready to serve requests, to shut it down gracefully.
|
|
|
|
For earlier versions of nghttpx, you have to do one more thing. At
|
|
this point, both current and new processes can accept requests. To
|
|
gracefully shutdown current process, send QUIT signal to current
|
|
nghttpx process. When all existing frontend connections are done, the
|
|
current process will exit. At this point, only new nghttpx process
|
|
exists and serves incoming requests.
|
|
|
|
If you want to just reload configuration file without executing new
|
|
binary, send SIGHUP to nghttpx master process.
|
|
|
|
Re-opening log files
|
|
--------------------
|
|
|
|
When rotating log files, it is desirable to re-open log files after
|
|
log rotation daemon renamed existing log files. To tell nghttpx to
|
|
re-open log files, send USR1 signal to nghttpx process. It will
|
|
re-open files specified by :option:`--accesslog-file` and
|
|
:option:`--errorlog-file` options.
|
|
|
|
Multiple frontend addresses
|
|
---------------------------
|
|
|
|
nghttpx can listen on multiple frontend addresses. To specify them,
|
|
just use :option:`--frontend` (or its shorthand :option:`-f`) option
|
|
repeatedly. TLS can be enabled or disabled per frontend address
|
|
basis. For example, to listen on port 443 with TLS enabled, and on
|
|
port 80 without TLS:
|
|
|
|
.. code-block:: text
|
|
|
|
frontend=*,443
|
|
frontend=*,80;no-tls
|
|
|
|
|
|
Multiple backend addresses
|
|
--------------------------
|
|
|
|
nghttpx supports multiple backend addresses. To specify them, just
|
|
use :option:`--backend` (or its shorthand :option:`-b`) option
|
|
repeatedly. For example, to use ``192.168.0.10:8080`` and
|
|
``192.168.0.11:8080``, use command-line like this:
|
|
``-b192.168.0.10,8080 -b192.168.0.11,8080``. In configuration file,
|
|
this looks like:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=192.168.0.10,8080
|
|
backend=192.168.0.11,8008
|
|
|
|
nghttpx can route request to different backend according to request
|
|
host and path. For example, to route request destined to host
|
|
``doc.example.com`` to backend server ``docserv:3000``, you can write
|
|
like so:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=docserv,3000;doc.example.com/
|
|
|
|
When you write this option in command-line, you should enclose
|
|
argument with single or double quotes, since the character ``;`` has a
|
|
special meaning in shell.
|
|
|
|
To route, request to request path ``/foo`` to backend server
|
|
``[::1]:8080``, you can write like so:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=::1,8080;/foo
|
|
|
|
If the last character of path pattern is ``/``, all request paths
|
|
which start with that pattern match:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=::1,8080;/bar/
|
|
|
|
The request path ``/bar/buzz`` matches the ``/bar/``.
|
|
|
|
You can use ``*`` at the end of the path pattern to make it wildcard
|
|
pattern. ``*`` must match at least one character:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=::1,8080;/sample*
|
|
|
|
The request path ``/sample1/foo`` matches the ``/sample*`` pattern.
|
|
|
|
Of course, you can specify both host and request path at the same
|
|
time:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=192.168.0.10,8080;example.com/foo
|
|
|
|
We can use ``*`` in the left most position of host to achieve wildcard
|
|
suffix match. If ``*`` is the left most character, then the remaining
|
|
string should match the request host suffix. ``*`` must match at
|
|
least one character. For example, ``*.example.com`` matches
|
|
``www.example.com`` and ``dev.example.com``, and does not match
|
|
``example.com`` and ``nghttp2.org``. The exact match (without ``*``)
|
|
always takes precedence over wildcard match.
|
|
|
|
One important thing you have to remember is that we have to specify
|
|
default routing pattern for so called "catch all" pattern. To write
|
|
"catch all" pattern, just specify backend server address, without
|
|
pattern.
|
|
|
|
Usually, host is the value of ``Host`` header field. In HTTP/2, the
|
|
value of ``:authority`` pseudo header field is used.
|
|
|
|
When you write multiple backend addresses sharing the same routing
|
|
pattern, they are used as load balancing. For example, to use 2
|
|
servers ``serv1:3000`` and ``serv2:3000`` for request host
|
|
``example.com`` and path ``/myservice``, you can write like so:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=serv1,3000;example.com/myservice
|
|
backend=serv2,3000;example.com/myservice
|
|
|
|
You can also specify backend application protocol in
|
|
:option:`--backend` option using ``proto`` keyword after pattern.
|
|
Utilizing this allows ngttpx to route certain request to HTTP/2, other
|
|
requests to HTTP/1. For example, to route requests to ``/ws/`` in
|
|
backend HTTP/1.1 connection, and use backend HTTP/2 for other
|
|
requests, do this:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=serv1,3000;/;proto=h2
|
|
backend=serv1,3000;/ws/;proto=http/1.1
|
|
|
|
The default backend protocol is HTTP/1.1.
|
|
|
|
TLS can be enabled per pattern basis:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=serv1,8443;/;proto=h2;tls
|
|
backend=serv2,8080;/ws/;proto=http/1.1
|
|
|
|
In the above case, connection to serv1 will be encrypted by TLS. On
|
|
the other hand, connection to serv2 will not be encrypted by TLS.
|
|
|
|
Dynamic hostname lookup
|
|
-----------------------
|
|
|
|
By default, nghttpx performs backend hostname lookup at start up, or
|
|
configuration reload, and keeps using them in its entire session. To
|
|
make nghttpx perform hostname lookup dynamically, use ``dns``
|
|
parameter in :option:`--backend` option, like so:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=foo.example.com,80;;dns
|
|
|
|
nghttpx will cache resolved addresses for certain period of time. To
|
|
change this cache period, use :option:`--dns-cache-timeout`.
|
|
|
|
Enable PROXY protocol
|
|
---------------------
|
|
|
|
PROXY protocol can be enabled per frontend. In order to enable PROXY
|
|
protocol, use ``proxyproto`` parameter in :option:`--frontend` option,
|
|
like so:
|
|
|
|
.. code-block:: text
|
|
|
|
frontend=*,443;proxyproto
|
|
|
|
Session affinity
|
|
----------------
|
|
|
|
Two kinds of session affinity are available: client IP, and HTTP
|
|
Cookie.
|
|
|
|
To enable client IP based affinity, specify ``affinity=ip`` parameter
|
|
in :option:`--backend` option. If PROXY protocol is enabled, then an
|
|
address obtained from PROXY protocol is taken into consideration.
|
|
|
|
To enable HTTP Cookie based affinity, specify ``affinity=cookie``
|
|
parameter, and specify a name of cookie in ``affinity-cookie-name``
|
|
parameter. Optionally, a Path attribute can be specified in
|
|
``affinity-cookie-path`` parameter:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=127.0.0.1,3000;;affinity=cookie;affinity-cookie-name=nghttpxlb;affinity-cookie-path=/
|
|
|
|
Secure attribute of cookie is set if client connection is protected by
|
|
TLS.
|
|
|
|
PSK cipher suites
|
|
-----------------
|
|
|
|
nghttpx supports pre-shared key (PSK) cipher suites for both frontend
|
|
and backend TLS connections. For frontend connection, use
|
|
:option:`--psk-secrets` option to specify a file which contains PSK
|
|
identity and secrets. The format of the file is
|
|
``<identity>:<hex-secret>``, where ``<identity>`` is PSK identity, and
|
|
``<hex-secret>`` is PSK secret in hex, like so:
|
|
|
|
.. code-block:: text
|
|
|
|
client1:9567800e065e078085c241d54a01c6c3f24b3bab71a606600f4c6ad2c134f3b9
|
|
client2:b1376c3f8f6dcf7c886c5bdcceecd1e6f1d708622b6ddd21bda26ebd0c0bca99
|
|
|
|
nghttpx server accepts any of the identity and secret pairs in the
|
|
file. The default cipher suite list does not contain PSK cipher
|
|
suites. In order to use PSK, PSK cipher suite must be enabled by
|
|
using :option:`--ciphers` option. The desired PSK cipher suite may be
|
|
listed in `HTTP/2 cipher black list
|
|
<https://tools.ietf.org/html/rfc7540#appendix-A>`_. In order to use
|
|
such PSK cipher suite with HTTP/2, disable HTTP/2 cipher black list by
|
|
using :option:`--no-http2-cipher-black-list` option. But you should
|
|
understand its implications.
|
|
|
|
At the time of writing, even if only PSK cipher suites are specified
|
|
in :option:`--ciphers` option, certificate and private key are still
|
|
required.
|
|
|
|
For backend connection, use :option:`--client-psk-secrets` option to
|
|
specify a file which contains single PSK identity and secret. The
|
|
format is the same as the file used by :option:`--psk-secrets`
|
|
described above, but only first identity and secret pair is solely
|
|
used, like so:
|
|
|
|
.. code-block:: text
|
|
|
|
client2:b1376c3f8f6dcf7c886c5bdcceecd1e6f1d708622b6ddd21bda26ebd0c0bca99
|
|
|
|
The default cipher suite list does not contain PSK cipher suites. In
|
|
order to use PSK, PSK cipher suite must be enabled by using
|
|
:option:`--client-ciphers` option. The desired PSK cipher suite may
|
|
be listed in `HTTP/2 cipher black list
|
|
<https://tools.ietf.org/html/rfc7540#appendix-A>`_. In order to use
|
|
such PSK cipher suite with HTTP/2, disable HTTP/2 cipher black list by
|
|
using :option:`--client-no-http2-cipher-black-list` option. But you
|
|
should understand its implications.
|
|
|
|
TLSv1.3
|
|
-------
|
|
|
|
As of nghttpx v1.34.0, if it is built with OpenSSL 1.1.1 or later, it
|
|
supports TLSv1.3. 0-RTT data is supported, but by default its
|
|
processing is postponed until TLS handshake completes to mitigate
|
|
replay attack. This costs extra round trip and reduces effectiveness
|
|
of 0-RTT data. :option:`--tls-no-postpone-early-data` makes nghttpx
|
|
not wait for handshake to complete before forwarding request included
|
|
in 0-RTT to get full potential of 0-RTT data. In this case, nghttpx
|
|
adds ``Early-Data: 1`` header field when forwarding a request to a
|
|
backend server. All backend servers should recognize this header
|
|
field and understand that there is a risk for replay attack. See
|
|
https://tools.ietf.org/html/draft-ietf-httpbis-replay-04 for
|
|
``Early-Data`` header field.
|
|
|
|
nghttpx disables anti replay protection provided by OpenSSL. The anti
|
|
replay protection of OpenSSL requires that a resumed request must hit
|
|
the same server which generates the session ticket. Therefore it
|
|
might not work nicely in a deployment where there are multiple nghttpx
|
|
instances sharing ticket encryption keys via memcached.
|
|
|
|
Because TLSv1.3 completely changes the semantics of cipher suite
|
|
naming scheme and structure, nghttpx provides the new option
|
|
:option:`--tls13-ciphers` and :option:`--tls13-client-ciphers` to
|
|
change preferred cipher list for TLSv1.3.
|
|
|
|
Migration from nghttpx v1.18.x or earlier
|
|
-----------------------------------------
|
|
|
|
As of nghttpx v1.19.0, :option:`--ciphers` option only changes cipher
|
|
list for frontend TLS connection. In order to change cipher list for
|
|
backend connection, use :option:`--client-ciphers` option.
|
|
|
|
Similarly, :option:`--no-http2-cipher-black-list` option only disables
|
|
HTTP/2 cipher black list for frontend connection. In order to disable
|
|
HTTP/2 cipher black list for backend connection, use
|
|
:option:`--client-no-http2-cipher-black-list` option.
|
|
|
|
``--accept-proxy-protocol`` option was deprecated. Instead, use
|
|
``proxyproto`` parameter in :option:`--frontend` option to enable
|
|
PROXY protocol support per frontend.
|
|
|
|
Migration from nghttpx v1.8.0 or earlier
|
|
----------------------------------------
|
|
|
|
As of nghttpx 1.9.0, ``--frontend-no-tls`` and ``--backend-no-tls``
|
|
have been removed.
|
|
|
|
To disable encryption on frontend connection, use ``no-tls`` keyword
|
|
in :option:`--frontend` potion:
|
|
|
|
.. code-block:: text
|
|
|
|
frontend=*,3000;no-tls
|
|
|
|
The TLS encryption is now disabled on backend connection in all modes
|
|
by default. To enable encryption on backend connection, use ``tls``
|
|
keyword in :option:`--backend` option:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=127.0.0.1,8080;tls
|
|
|
|
As of nghttpx 1.9.0, ``--http2-bridge``, ``--client`` and
|
|
``--client-proxy`` options have been removed. These functionality can
|
|
be used using combinations of options.
|
|
|
|
Use following option instead of ``--http2-bridge``:
|
|
|
|
.. code-block:: text
|
|
|
|
backend=<ADDR>,<PORT>;;proto=h2;tls
|
|
|
|
Use following options instead of ``--client``:
|
|
|
|
.. code-block:: text
|
|
|
|
frontend=<ADDR>,<PORT>;no-tls
|
|
backend=<ADDR>,<PORT>;;proto=h2;tls
|
|
|
|
Use following options instead of ``--client-proxy``:
|
|
|
|
.. code-block:: text
|
|
|
|
http2-proxy=yes
|
|
frontend=<ADDR>,<PORT>;no-tls
|
|
backend=<ADDR>,<PORT>;;proto=h2;tls
|
|
|
|
We also removed ``--backend-http2-connections-per-worker`` option. It
|
|
was present because previously the number of backend h2 connection was
|
|
statically configured, and defaulted to 1. Now the number of backend
|
|
h2 connection is increased on demand. We know the maximum number of
|
|
concurrent streams per connection. When we push as many request as
|
|
the maximum concurrency to the one connection, we create another new
|
|
connection so that we can distribute load and avoid delay the request
|
|
processing. This is done automatically without any configuration.
|