Httpd mod proxy Concepts

From NovaOrdis Knowledge Base
Jump to navigation Jump to search

Internal

Overview

mod_proxy implements generic forward and reverse proxying functionality: a request is received by httpd and forwarded to another server, commonly referred to as the origin server.

Proxying does not necessarily involve load balancing. However, httpd is capable of proxying to a set of equivalent origin servers, which is commonly referred to as load balancing. For that, mod_proxy_balancer must be installed and configured.

Reverse Proxy (Gateway)

A reverse proxy (or gateway), appears to the client just like an ordinary web server. No special configuration on the client is necessary. The client makes ordinary requests for content in the name-space of the reverse proxy. The reverse proxy then decides on what origin server to use to forward the requests, and returns the content as if it was itself the origin. The reverse proxy may also employ configurable logic to modify the response headers set by the origin server so the response appears as originating from the proxy. For more details see ProxyPassReverse, ProxyPassReverseCookieDomain and ProxyPassReverseCookiePath.

A typical usage of a reverse proxy is to provide Internet users access to an origin server sitting is behind a firewall. Reverse proxies can also be used to balance load among several back-end servers, or to provide caching for a slower back-end server. In addition, reverse proxies can be used simply to bring several servers into the same URL space.

The configuration of a reverse proxy starts with the declaration of a ProxyPass directive, which is the entry point that maps an origin server(s) URL into the proxy's URL space. ProxyPass defines a worker, which can be a direct worker, when there is only one origin server or a balancer worker, when there are several load-balanced origin servers.

httpd implements a reverse proxy with using mod_proxy modules. Various protocols can be proxied. The most common are HTTP and AJP. For an explanation of how mod_proxy modules work together, see the "mod_proxy Modules and How they Work Together" section below.

Forward Proxy

A forward proxy is an intermediate server that sits between the client and the origin server. In order to get content from the origin server, the client sends a request to the proxy naming the origin server as the target and the proxy then requests the content from the origin server and returns it to the client. The client must be specially configured to use the forward proxy to access other sites. httpd can be used to implement a forward proxy with mod_proxy. The forward proxy is activated using the ProxyRequests directive.

The ProxyPass Directive

The ProxyPass directive is the configuration entry point that maps one or more origin servers URLs into the proxy's main server or virtual host URL space. ProxyPass defines a worker, which can be a direct worker, when there is only one origin server or a balancer worker, when there are several load-balanced origin servers.

A ProxyPass configuration options reference is available here:

ProxyPass Directive

Workers

A worker is an object maintained by the httpd server to manage the configuration and communication parameters for one origin server or for a group of origin servers, as it is the case for a balancer worker. The worker object itself does not have the concept of forward or reverse proxying, it just encapsulates the concept of communication with an origin server. There are two built-in workers: the default forward proxy and the default reverse proxy worker. The built-in workers do not use HTTP Keep-Alive, they open TCP connections to the origin server for each request. They do not do connection pooling.

ProxyPass and ProxyRequests define explicit workers. An explicit worker is identified by its URL, which includes the path that maps the origin server(s) into the proxy's URL space, the address of the origin server or the balancer group and optionally connection configuration elements. For a reverse proxy, an explicit worker is created and configured using the ProxyPass and ProxyPassMatch directives. Each worker defined as such uses a separate connection pool and configuration. Declaring explicit workers for forward proxies is not very common.

Worker Status

The initial worker status can be set via configuration and is reported by mod_status.

D: worker is disabled and will not accept any requests.

S: worker is administratively stopped.

I: worker is in ignore-errors mode and will be always considered available.

H: worker is in hot-standby mode and will only be used if no other viable workers are available.

E: worker is in error state.

N: worker is in drain mode and will only accept existing sticky sessions destined for itself and ignore all other requests.

Direct Workers

A direct worker is defined with a simple ProxyPass directive, where its URL entry represents just one origin server.

ProxyPass "/example" "http://backend.example.com" connectiontimeout=5 timeout=30

Worker Sharing


The order in which ProxyPass directives are declared matters.

If two different ProxyPass directives that share a URL fragment are declared in the same configuration file, and the shortest one is declared first, only one worker is created, for the shorter URL. The requests that are matched for the ProxyPass with the longer URL will be proxied using the only worker, and all configuration attributes given explicitly for the later worker will be ignored.

If the longer URL is declared first, two different workers will be created.

Also see

ProxyPass Order

Balancer Workers

Balancer workers are virtual workers that use direct workers, known as their members, to handle requests. The balancer worker does not really communicate with a backend server. It is only responsible with the management of its members and load balancing of the request among them.

A balancer worker is declared with a ProxyPass directive where the URL entry uses "balancer://" as the protocol scheme. The balancer URL uniquely identifies the balancer worker.

Each balancer can have multiple members. The member the next request is sent to is chosen based on the load balancer algorithm in effect. Members are added to a balancer by declaring them with the BalancerMember directive, within a Proxy container, as shown below. If the Proxy directive's URL starts with "balancer://", then any path information in the URL is ignored.

ProxyPass "/example" "balancer://mycluster/"

<Proxy balancer://mycluster>
    BalancerMember http://node1/
    BalancerMember http://node2/
</Proxy>

The concepts behind the mod_proxy load balancing are presented here:

Load Balancing

Connection Pooling




Httpd mod proxy connection pooling.png


This section provides more details on connection pooling for explicit workers. Each explicit (direct or balancer) worker defined with a ProxyPass directive, retains the TCP/IP connections created to forward requests to the backend nodes in a connection pool, for further reuse, even if the browser closes the original connection that required proxying. This behavior saves system resources by opening and closing fewer TCP connections, and it reduces the latency on subsequent requests since there is no time spent with the TCP connection opening handshake.

The connection pools such defined can be configured independently on a per-ProxyPass basis, subject to worker sharing rules. Explicit connection pool configuration can be declared in the form of "key=value" parameters, trailing the ProxyPass declaration.

For a httpd proxy running in worker MPM mode, the connection pool can the thought as logically spanning all httpd child processes active at a time: connections can be opened and maintained from any httpd child process, and they are subject to connection pool capacity rules described below.

Connection Creation

The connections are lazily initiated. A connection is created only when there is a request to forward, and there aren't other available connections in the pool that can be used to forward that request. If the backend servers are not available when the httpd proxy starts, this fact won't become obvious until the first request to be proxied arrives at the server. If at that time there are still no backend servers available, the proxy will respond with 503 Service Temporarily Unavailable. After the request is handled, the newly created connection is retained in the pool.

Initial connection creation is subject to timeout. The httpd proxy process will wait for the configured number of seconds for the creation process to complete, and it will timeout if the connection is not established. Connection creation timeout is controlled by the connectiontimeout parameter.

No Pooling

Connection pooling can be explicitly disabled with the disablereuse parameter. Setting this parameter to "On" forces mod_proxy to immediately close a connection to the backend after being used, effectively disabling its persistent connection pool for the backend. This is useful in various situations where a firewall between httpd and the backend server silently drops connections.

Connection Pool Capacity

For a httpd proxy running in worker MPM mode, the maximum number of connections in the ProxyPass’ logical connection pool spanning all children processes is given by default by the value of the MaxClient directive. This assumes there is just one ProxyPass declaration per server configuration. The number of connections permitted for just one httpd child process is limited to the value of ThreadsPerChild directive, per worker MPM sizing rules.

ProxyPass exposes options that can be used to override the generic sizing directives mentioned above.

"max" configuration element sets an upper limit on the number of connections for the corresponding ProxyPass that can be maintain by one worker MPM child process. This limits the total number of connection in the connection pool for the corresponding ProxyPass directive to max * number_of_httpd_children_processes. max cannot exceed the value of ThreadsPerChild directive, if set to a value higher than ThreadsPerChild, it will be silently disregarded.

Another per-ProxyPass connection pool capacity configuration element is smax. If smax is set and it is lower than max, the connections above the smax limit are shut down after ttl.

Connection Time to Live

Once established, the connections to the backend will last forever, unless the child process that created them is stopped, the ttl parameter was configured and the value is reached, or a connection failure is detected. If ttl is specified, and if a connection is inactive for ttl seconds, the connection will not be used again. However, that connection won't be immediately closed, but will be closed later time. Based on experiments with httpd 2.2, it seems that an "expired" connection is closed when a new request for that backend arrives to the proxy. At that time, the "expired" connection is closed and a new one is created.

Connection Behavior

Once a new request arrives to the child process, a free connection is retrieved from the pool and used to service the requests. If acquire is set, the server will only wait for the specified number of milliseconds, and if no free connection is available, it will return SERVER_BUSY status to the client.

The proxy will wait for the configured number of seconds to receive a response from the backend server, and if the answer does not arrive in time, it returns a 502 Proxy Error to the client. The underlying connection is not closed. This event surfaces in the httpd proxy error log as "(70007) The timeout specified has expired: proxy: error reading status line from remote server ...". The timeout can be configured, in the order of precedence, with ProxyPass timeout parameter, the ProxyTimeout configuration directive, and finally with Timeout configuration directive.

A failure detected on the connection puts the connection in an error state. The error state of a connection can also be detected also with pinging. The worker will not forward any request to a connection in an error state until the retry timeout expires. A value of zero means aways retry workers in an error state with no timeout.

Backend Pinging

The proxy can ping the backend before forwarding a request over a certain connection in the pool, in order to ensure the connection is valid. For HTTP, mod_proxy_httpd implements it by sending a 100-Continue request to the backend. This will only work with HTTP/1.1 backends. For AJP, mod_proxy_ajp implements it by sending a CPING request, which works with Tomcat 3.3.2+, 4.1.28+, 5.0.13+. The number of seconds to wait for the answer can be configured as ping.

TCP Keep-Alive

If there is no further traffic, and no ttl is explicitly configured, the connection in the pool are left to idle indefinitely. If there is a firewall between the proxy and the backend server, it may close them. In order to prevent that, httpd allows configuration of a keepalive flag, that turns on TCP keep-alive mechanism.

Miscellaneous

Connection Pooling Configuration Reference

ProxyPass Connection Pool Configuration Reference

Load Balancing

mod_proxy supports several different load balancing algorithms, described below. A specific algorithm is configured for a load balancer by using the lbmethod configuration element.

The load balancer monitors the balancer members - and implicitly the backend nodes - for errors and avoids sending new requests to members that are designated to be in error state. A member can be marked to be in error state if the backend returns any of the HTTP status codes configured with failonstatus, or if there is a timeout (configured with failontimeout) on receiving the response from the backend.

Worker recovery.

The load balancer supports session stickiness: if the balancer identifies a request as being associated to a known session, and it was configured to ensure session stickiness, it will forward the request to the backend node known to handle that session. mod_proxy_balancer implements session stickiness in two different ways: with cookies and URL encoding: the session is maintained between invocations as a value of a specific session cookie or the session ID is encoded within the URL. The name of the cookie can be configured with stickysession. The content of the cookie can be configured with stickysessionsep and scolonpathdelim. Providing the cookie can be either done by the back-end or by the Apache web server itself. The URL encoding is usually done on the back-end. When session stickiness is implemented with cookies, the balancer extracts the value of the cookie and looks for a member worker with route equals with the value extracted from the cookie. For more details on how to configure the route, see route. Apache Tomcat adds the name of the Tomcat instance to the end of its session ID cookie, separated with a dot (.) from the session ID. Thus if the Apache web server finds a dot in the value of the stickyness cookie, it only uses the part behind the dot to search for the route. In order to let Tomcat know about its instance name, you need to set the attribute jvmRoute<.tt> inside the Tomcat configuration file conf/server.xml to the value of the route of the worker that connects to the respective Tomcat.

The load balancer exports session stickiness-specific environment variables:

mod_proxy Environment Variables

The load balancer manages the session failover, which is triggered when it is enabled (nofailover="Off") and the member that was handling the session becomes unavailable. The load balancer can be configured to attempt failover for a set number of times, after which will return an error status to the client. The number of failover attempts is configured with maxattemtps. There are situations when the failover should be disabled: in in the case the backend severs do not replicate the session. In this case, session failover is pointless.


Load balancing methods:

byrequests

This method performs weighted request counting.

https://httpd.apache.org/docs/current/mod/mod_lbmethod_byrequests.html

bytraffic

This method performs weighted traffic byte counting.

https://httpd.apache.org/docs/current/mod/mod_lbmethod_bytraffic.html

bybusyness

This method performs pending request counting.

https://httpd.apache.org/docs/current/mod/mod_lbmethod_bybusyness.html

heartbeat

https://httpd.apache.org/docs/current/mod/mod_lbmethod_heartbeat.html

httpd offers functionality to display the status and dynamically manage load balancer members. For more details see:

mod_status Load Balancing Management and Status

This article offers hints on how to troubleshoot load balancing and stickiness problems:

Troubleshooting httpd Load Balancer Stickiness


For load-balancer specific configuration, see:

ProxyPass Load-Balancer Specific Configuration

mod_proxy Modules and How they Work Together

The proxy functionality requires a set of modules to be loaded and work together. For more details on how to load a module, see mod_proxy Installation section.

mod_proxy

This module lets the server act as proxy for data transferred over AJP, FTP, CONNECT (for SSL, the Secure Sockets Layer), and HTTP. To serve specific protocols, mod_proxy relies on specialized implementations provided by mod_proxy_http, mod_proxy_ajp, mod_proxy_ftp, mod_proxy_wstunnel, etc. The load balancing algorithms are implemented by mod_proxy_balancer.

Also see:

mod_cluster's mod_proxy_cluster

More details:

https://httpd.apache.org/docs/current/mod/mod_proxy.html

mod_proxy Compilation

mod_proxy Compilation

mod_proxy_http

mod_proxy_http proxies HTTP and HTTPS requests and it supports HTTP/1.0 and HTTP/1.1. It requires mod_proxy. It does not provide any caching capabilities.

More details:

https://httpd.apache.org/docs/current/mod/mod_proxy_http.html

Reverse Proxy Request Headers

When implementing a reverse proxy, mod_proxy_http adds the following request headers that carry additional information to the origin server:

  • X-Forwarded-For - the IP address of the client
  • X-Forwarded-Host - the original host requested by the client in the Host HTTP request header
  • X-Forwarded-Server - the hostname of the proxy server.

mod_proxy_ajp

mod_proxy_ajp is a httpd module that provides support for AJP proxying. mod_proxy.so is required to use this module.

Also see:

mod_cluster's mod_proxy_cluster

mod_proxy_ajp Compilation

mod_proxy_ajp Compilation

TODO (integrate and deplete): https://home.feodorov.com:9443/wiki/Wiki.jsp?page=Mod_proxy_ajp

mod_proxy_balancer

Proxying does not necessarily involve load balancing. httpd is capable of providing load balancing functionality, in addition to reverse proxying, if is installed and configured. mod_proxy_balancer provides load balancing logic. It is dependent on mod_proxy. The load balancing scheduler algorithm is not provided by this module, but by additional, specialized modules that must be loaded explicitly. Those modules are mod_lbmethod_byrequests, mod_lbmethod_bytraffic, mod_lbmethod_bybusiness and mod_lbmethod_heartbeat.

More details:

https://httpd.apache.org/docs/current/mod/mod_proxy_balancer.html

Also see:

Load Balancing

<Proxy> Control Block

Proxy

Proxying Requests that Contain Bodies

Also see HTTP Request Body.


Configuration

httpd mod_proxy Configuration