H2O

the optimized HTTP/1.x, HTTP/2, HTTP/3 server

Powered by Oktavia

Configure > Proxy Directives

Proxy module is the proxy implementation for H2O - it implements a reverse HTTP proxy and a CONNECT proxy.

A reverse HTTP proxy is setup using the proxy.reverse.url directive. A CONNECT proxy is setup using the proxy.connect directive.

When acting as a reverse HTTP proxy, following request headers are added and forwarded to the backend server:

By default, all requests to the backend server are sent using HTTP/1.1. Use of HTTP/2 and HTTP/3 to backend servers is considered experimental; their use can be controlled via directives proxy.http2.ratio and proxy.http3.ratio.

Following sections describe the configuration directives defined for the module.

Description:

Forwards the requests to the specified backends, and proxies the response.

Example. Forwarding the requests to application server running on 127.0.0.1:8080
proxy.reverse.url: "http://127.0.0.1:8080/"
Example. Forwarding the requests to multiple application server with different weight
proxy.reverse.url:
  - http://10.0.0.1:8080/
  - url: http://10.0.0.2:8080/different-path
    weight: 2
Example. Forwarding the requests to multiple application server with least connection
proxy.reverse.url:
  backends:
    - http://10.0.0.1:8080/
    - http://10.0.0.2:8080/
  balancer: least-conn

When more than one backend is declared, the load is distributed among the backends using the strategy specified by the balancer property. Currently we support round-robin (the default) and least-conn as the value of the property. The strategies are applied when establishing a new connection becomes necessary (i.e. when no pooled connections exist).

weight can be assigned to each backend as an integer between 1 and 256. The default value is 1.

For the round-robin balancer, weight is respected in this way: each backend would be selected exactly weight times before next backend would be selected, except when the backend is not accessable.

For least-conn balancer, weight is respected in this way: the selected backend should have the minimum value of (request count) / (weight).

H2O will try to reconnect to different backends (in the order determined by the load balancing strategy) until it successfully establishes a connection. It returns an error when it fails to connect to all of the backends.

In addition to TCP/IP over IPv4 and IPv6, the proxy handler can also connect to an HTTP server listening to a Unix socket. Path to the unix socket should be surrounded by square brackets, and prefixed with unix: (e.g. http://[unix:/path/to/socket]/path).

Level:
path
experimental

"proxy.connect"

Description:

Setup a CONNECT proxy, taking an access control list as the argument.

Each element of the access control list starts with either + or - followed by an wildcard (*) or an IP address with an optional netmask and an optional port number.

When a CONNECT request is received and the name resolution of the connect target is complete, the access control list is searched from top to bottom. If the first entry that contains a matching address (and optionally the port number) starts with a +, the request is accepted and a tunnel is established. If the entry starts with a -, the request is rejected.

If none of the entries match, the request is also rejected.

Example. Simple HTTPS proxy
proxy.connect:
- "-192.168.0.0/24"  # reject any attempts to local network
- "+*:443"           # accept attempts to port 443 of any host

Note: The precise syntax of the access control list element is address:port/netmask. This is because the URL parser is reused.

Level:
path
Description:

A boolean flag (ON or OFF) designating if a proxy-status response header should be sent.

Level:
global, host, path, extension
Default:
proxy.connect.emit-proxy-status: OFF
See also:
proxy.proxy-status.identity
Description:

A boolean flag(ON or OFF) indicating if the server will append or add the x-forwarded-proto and x-forwarded-for request headers.

By default, when forwarding an HTTP request H2O sends its own x-forwarded-proto and x-forwarded-for request headers (or might append its value in the x-forwarded-proto case, see proxy.preserve-x-forwarded-proto). This might not be always desirable. Please keep in mind security implications when setting this of OFF, since it might allow an attacker to spoof the originator or the protocol of a request.

Level:
global
Default:
proxy.emit-x-forwarded-headers: ON
See also:
proxy.emit-via-header
Description:

A boolean flag (ON or OFF) indicating if the server adds or appends an entry to the via request header.

Level:
global
Default:
proxy.emit-via-header: ON
See also:
proxy.emit-x-forwarded-headers
Description:

A boolean flag (ON or OFF) indicating if H2O should add a date header to the response, if that header is missing from the upstream response.

Level:
global
Default:
proxy.emit-missing-date-header: ON
Description:

A boolean flag indicating if closure of the backend connection should trigger the closure of the frontend HTTP/1.1 connection.

Level:
global, host, path, extension
Default:
proxy.forward.close-connection: OFF
Description:

Connection Attempt Delay parameter of Happy Eyeballs v2.

When trying to establish a connection to the CONNECT target, H2O uses Happy Eyeballs v2 (RFC 8305). This parameter controls the Connection Attempt Delay parameter of Happy Eyeballs v2 in the unit of milliseconds.

At the moment, Happy Eyeballs is used only when acting as a CONNECT proxy. It is not used when running as an HTTP reverse proxy.

Level:
global, host, path, extension
Default:
proxy.happy-eyeballs.connection-attempt-delay: 250
Description:

Name Resolution Delay parameter of Happy Eyeballs v2.

For detail, see proxy.happy-eyeballs.connection-attempt-delay.

Level:
global, host, path, extension
Default:
proxy.happy-eyeballs.name-resolution-delay: 50
since v2.2

"proxy.header.add"

Description:

Modifies the request headers sent to the application server.

The behavior is identical to header.add except for the fact that it affects the request headers sent to the application server rather than the response headers sent to the client. Please refer to the documentation of the headers handler to see how the directives can be used to mangle the headers.

Level:
global, host, path, extension
Description:

Modifies the request headers sent to the application server.

The behavior is identical to header.append except for the fact that it affects the request headers sent to the application server rather than the response headers sent to the client. Please refer to the documentation of the headers handler to see how the directives can be used to mangle the headers.

Level:
global, host, path, extension
Description:

Modifies the request headers sent to the application server.

The behavior is identical to header.merge except for the fact that it affects the request headers sent to the application server rather than the response headers sent to the client. Please refer to the documentation of the headers handler to see how the directives can be used to mangle the headers.

Level:
global, host, path, extension
since v2.2

"proxy.header.set"

Description:

Modifies the request headers sent to the application server.

The behavior is identical to header.set except for the fact that it affects the request headers sent to the application server rather than the response headers sent to the client. Please refer to the documentation of the headers handler to see how the directives can be used to mangle the headers.

Level:
global, host, path, extension
Description:

Modifies the request headers sent to the application server.

The behavior is identical to header.setifempty except for the fact that it affects the request headers sent to the application server rather than the response headers sent to the client. Please refer to the documentation of the headers handler to see how the directives can be used to mangle the headers.

Level:
global, host, path, extension
Description:

Modifies the request headers sent to the application server.

The behavior is identical to header.unset except for the fact that it affects the request headers sent to the application server rather than the response headers sent to the client. Please refer to the documentation of the headers handler to see how the directives can be used to mangle the headers.

Level:
global, host, path, extension
Description:

Modifies the request headers sent to the application server.

The behavior is identical to header.unsetunless except for the fact that it affects the request headers sent to the application server rather than the response headers sent to the client. Please refer to the documentation of the headers handler to see how the directives can be used to mangle the headers.

Level:
global, host, path, extension
Description:

Removes cookies in the requests with given name.

Level:
global, host, path, extension
See also:
header.unset/a>
Description:

Removes all cookies in the requests but those with given names.

Level:
global, host, path, extension
See also:
header.unsetunless
Description:

See proxy.http2.ratio.

Level:
global, host, path, extension
Default:
proxy.http2.force-cleartext: OFF
Description:

Maxium number of concurrent requests issuable on one HTTP/2 connection to the backend server.

Actual number of maximum requests inflight will be capped to the minimum of this setting and the value advertised in the HTTP/2 SETTINGS frame of the bakend server.

Level:
global, host, path, extension
Default:
proxy.http2.max-concurrent-streams: 100
See also:
proxy.http2.ratio
experimental

"proxy.http2.ratio"

Description:

Ratio of forwarded HTTP requests with which use of HTTP/2 should be attempted.

When the backend protocol is HTTPS, for given ratio of HTTP requests, h2o will either attempt to create or reuse an existing HTTP/2 connection. Connection attempts to use HTTP/2 will be indicated to the server via ALPN, with fallback to HTTP/1.1.

When the backend protocol is cleartext HTTP, this directive has impact only when the ratio is set to 100 with proxy.http2.force-cleartext set to ON. In such case, all backend connection will use HTTP/2 without negotiation.

Level:
global, host, path, extension
Default:
proxy.http2.ratio: 0
experimental

"proxy.http3.ratio"

Description:

Ratio of forwarded HTTP requests with which use of HTTP/3 should be attempted.

When the backend protocol is HTTPS, for given ratio of HTTP requests, h2o will either attempt to create or reuse an existing HTTP/3 connection.

When the backend protocol is cleartext HTTP, this directive has no impact.

Level:
global, host, path, extension
Default:
proxy.http3.ratio: 0
Description:

This setting specifies the maximum amount of userspace memory / disk space used for buffering each HTTP response being forwarded, in the unit of bytes.

By default, h2o buffers unlimited amount of data being sent from backend servers. The intention behind this approach is to free up backend connections as soon as possible, under the assumption that the backend server might have lower concurrency limits than h2o. But if the backend server has enough concurrency, proxy.max-buffer-size can be used to restrict the memory / disk pressure caused by h2o at the cost of having more connections to the backend server.

Level:
global, host, path, extension
See also:
temp-buffer-threshold
Description:

A boolean flag (ON or OFF) designating whether or not to pass Host header from incoming request to upstream.

Level:
global, host, path, extension
Default:
proxy.preserve-host: OFF
Description:

A boolean flag(ON or OFF) indicating if the server preserve the received x-forwarded-proto request header.

By default, when transmitting a HTTP request to an upstream HTTP server, H2O removes the received x-forwarded-proto request header and sends its own, as a precaution measure to prevent an attacker connecting through HTTP to lie that they are connected via HTTPS. However in case H2O is run behind a trusted HTTPS proxy, such protection might not be desirable, and this configuration directive can be used to modify the behaviour.

Level:
global
Default:
proxy.preserve-x-forwarded-proto: OFF
Description:

A boolean flag (ON or OFF) indicating if PROXY protocol should be used when connecting to the application server.

When using the PROXY protocol, connections to the application server cannot be persistent (i.e. proxy.timeout.keepalive must be set to zero).

Level:
global, host, path, extension
Default:
proxy.proxy-protocol: OFF
See also:
proxy.timeout.keepalive
Description:

Specifies the name of the server to be emitted as part of the proxy-status header field.

Level:
global, host, path, extension
See also:
proxy.connect.proxy-status
since v2.0

"proxy.ssl.cafile"

Description:

Specifies the file storing the list of trusted root certificates.

By default, H2O uses share/h2o/ca-bundle.crt. The file contains a set of trusted root certificates maintained by Mozilla, downloaded and converted using mk-ca-bundle.pl.

Level:
global, host, path, extension
See also:
proxy.ssl.verify-peer
Description:

Specifies whether if and how a session cache should be used for TLS connections to the application server.

Since version 2.1, result of the TLS handshakes to the application server is memoized and later used to resume the connection, unless set to OFF using this directive. If the value is a mapping, then the following two attributes must be specified:

lifetime:
validity of session cache entries in seconds
capacity:
maxmum number of entries to be kept in the session cache
If set to ON, lifetime and capacity will be set to 86,400 (one day) and 4,096.

Level:
global, host, path, extension
Default:
proxy.ssl.session-cache: ON
Description:

A boolean flag (ON or OFF) indicating if the server certificate and hostname should be verified.

If set to ON, the HTTP client implementation of H2O verifies the peer's certificate using the list of trusted certificates as well as compares the hostname presented in the certificate against the connecting hostname.

Level:
global, host, path, extension
Default:
proxy.ssl.verify-peer: ON
See also:
proxy.ssl.cafile
Description:

Sets the timeout before establishing the upstream in milliseconds.

When connecting to a TLS upstream, this timeout will run until the end of the SSL handshake.

Level:
global, host, path, extension
Default:
proxy.timeout.connect: 30000
Description:

Sets the timeout before receiving the first byte from upstream.

This sets the maxium time we will wait for the first byte from upstream, after the establishment of the connection.

Level:
global, host, path, extension
Default:
proxy.timeout.first_byte: 30000
Description:

Sets the upstream I/O timeout in milliseconds.

This value will be used for proxy.timeout.connect and proxy.timeout.first_byte as well, unless these parameters are explicitely set.

Level:
global, host, path, extension
Default:
proxy.timeout.io: 30000
Description:

Sets the upstream timeout for idle connections in milliseconds.

Upstream connection becomes non-persistent if the value is set to zero. The value should be set to something smaller than that being set at the upstream server.

Level:
global, host, path, extension
Default:
proxy.timeout.keepalive: 2000
experimental

"proxy.tunnel"

Description:

A boolean flag (ON or OFF) indicating whether or not to allow tunnelling to the backend server.

When set to ON, CONNECT requests and WebSocket handshakes are forwarded to the backend server. Then, if the backend server accepts those requests, H2O forwards the HTTP response to the client and acts as a bi-directional tunnel.

Timeouts are governed by properties proxy.timeout.connect and proxy.timeout.io.

Level:
global, host, path, extension
Default:
proxy.tunnel: OFF
experimental

"proxy.zerocopy"

Description:

Sets the use of zerocopy operations for forwarding the response body.

By default, this flag is set to OFF, in which case the response bytes are read from the upstream socket to an internal buffer as they arrive, then shipped to the client. Maximum size of this buffer is controlled by proxy.max-buffer-size. The drawback of this approach is that it causes pressure on memory bandwidth.

This knob provides two alternative modes to remedy the pressure:

When set to enabled, if zerocopy operation in supported by the downstream connection (i.e., downstream connection being cleoartext or encrypted using kernel TLS), h2o uses a pipe as an internal buffer instead of using userspace memory. Data is moved to the pipe using the splice system call, then shipped to the downstream connection by another call to splice. Pressure to memory bandwidth is eliminated, as the splice system call merely moves the references to kernel memory between file descriptors.

When set to always, data from upstream is spliced into a pipe regardless of downstream connection providing support for zerocopy. When the downstream connection does not support zerocopy, data is intially moved into the pipe, then gets read and written to the socket (as well as being encrypted, if necessary) as late as it becomes possible to send the data. This approach does not reduce the total amount of bytes flowing through the CPU, but reduces the amount of userspace memory used by h2o by delaying the reads, thereby reducing cache spills.

Level:
global
Default:
proxy.zerocopy: OFF
See also:
ssl-offload