<-
Apache > HTTP Server > Documentation > Version 2.5 > Modules

Apache Module mod_proxy_beacon

Available Languages:  en  |  fr 

Description:Dynamic Balancer membership where backends announce themselves to the reverse proxy over unicast UDP datagrams
Status:Extension
Module Identifier:proxy_beacon_module
Source File:mod_proxy_beacon.c
Compatibility:Available in Apache 2.5 and later

Summary

This module lets backend servers announce themselves to a front-end reverse proxy, which then adds each announcing backend as a live member (worker) of a mod_proxy_balancer balancer. When a backend stops announcing, the proxy takes it out of rotation. This provides self-registering, self-healing balancer membership without editing the proxy configuration or driving the balancer-manager by hand.

Communication uses plain unicast UDP datagrams (not multicast, which is filtered on most networks and does not traverse the public Internet). The data flows from backend to proxy:

Datagrams are fire-and-forget: a lost announcement is recovered by the next periodic one, and reordering is rejected by a per-backend timestamp check, so no connection, reconnect, or framing layer is needed.

On the proxy, ProxyBeaconBalancer names the balancer that announced backends are added to. Membership changes are applied using the same internal mechanism as the balancer-manager web interface, so a backend added this way behaves exactly like a statically configured or manually added BalancerMember, and is visible and editable in the balancer-manager.

This module requires the service of mod_watchdog and mod_proxy_balancer. The background work (listening, publishing, adding and evicting members) runs in a single mod_watchdog child process, so it is not available under the prefork MPM behaviour where that singleton cannot run.

Authentication

Any host that can reach the proxy's receive port could otherwise announce an arbitrary backend URL and cause the proxy to send client traffic to it (and a UDP source address is trivially spoofable). ProxyBeaconSecret is therefore required: it must be set to the same value on the proxy and on every backend, and the server fails to start if any participating server omits it. Announcements are authenticated with a keyed message-authentication code (MAC) and a timestamp, and the proxy drops any announcement that is not validly signed and recent. There is no unauthenticated mode.

Confidentiality

Announcements are authenticated but not encrypted; the payload is operational metadata (backend URLs), not secret data. Transport confidentiality (e.g. DTLS) is not currently provided and would be a separate future layer.

Topics

Directives

Bugfix checklist

See also

top

Usage example

The following pair of configurations sets up a self-registering balancer. The backends require no knowledge of each other and the proxy needs no pre-declared BalancerMember entries — only an empty balancer with room to grow.

On the reverse proxy:

# Receive backend announcements on the cluster network interface (UDP).
ProxyBeaconListen 0.0.0.0:5555
ProxyBeaconSecret    "hex:00112233445566778899aabbccddeeff"
ProxyBeaconBalancer  cluster

# A backend is dropped from rotation if it does not announce for 30 seconds.
ProxyBeaconTimeout   30

# An initially-empty balancer with spare slots for the dynamic members.
<Proxy balancer://cluster>
  ProxySet growth=16
</Proxy>
ProxyPass        "/" "balancer://cluster/"
ProxyPassReverse "/" "balancer://cluster/"

On each backend server:

# Announce this backend's routable origin to the proxy every 10 seconds (UDP).
ProxyBeaconAddress   proxy.example.com:5555
ProxyBeaconAdvertise http://10.0.0.5:8080
ProxyBeaconSecret    "hex:00112233445566778899aabbccddeeff"
ProxyBeaconInterval  10

When a backend starts it begins sending announcements. The proxy verifies each announcement against the shared secret, adds http://10.0.0.5:8080 as a member of balancer://cluster, and enables it. If that backend later stops announcing for longer than ProxyBeaconTimeout, the proxy disables the member (taking it out of rotation); a subsequent announcement re-enables it.

A backend added at runtime occupies one of the balancer's growth slots for the lifetime of the server process; it is disabled rather than removed when it stops announcing, matching the behaviour of the balancer-manager (which can add, but not remove, workers at runtime). Size growth for the maximum number of backends you expect to register.

top

Member identity

An announced URL identifies a backend origin: scheme://host[:port], and nothing more. The proxy uses the same string as the member's identity everywhere: as the key under which it tracks the backend's lease and replay state, and as the worker name it creates in the balancer. To keep those identities equal, the proxy:

Paths are refused because the balancer finds a member by longest prefix match. Announcements for http://10.0.0.5:8080/one and http://10.0.0.5:8080/one/two would be tracked as two members with separate leases but resolve to a single worker, so the lapse of one lease could disable a worker whose other lease was still current. Choose request paths on the proxy with ProxyPass, not through the advertised URL.

A backend that is announced successfully is confirmed to exist in the balancer before it is reported as added, enabled or evicted; an announcement that the proxy cannot turn into a member is logged and retried after a back-off rather than reported as a success.

top

Ownership and watchdog hand-off

Every worker that mod_proxy_beacon creates is marked with the Bcn status (flag B), which is stored in the worker's shared state and shown by the balancer-manager. The module only enables or evicts workers that carry this mark. A worker of the same name that does not — a BalancerMember from the configuration, or one added by an administrator — is left alone; an announcement for it is dropped and logged as member not managed by beacon.

The announcements are received and the leases kept by a single mod_watchdog child process. If that process exits or is killed, the watchdog singleton moves to another child, which starts with no record of the members it did not add itself. When a child becomes the owner it therefore takes over every worker in the balancer carrying the Bcn mark (logged as took over N existing member(s)):

A dead backend can therefore stay in rotation for up to one ProxyBeaconTimeout after a hand-off. The per-member replay high-water mark is not carried over either: during the hand-off a captured announcement that is still inside the ProxyBeaconMaxSkew freshness window can be replayed once per member, which refreshes that member's lease for one timeout. It does not allow a new member to be added without the shared secret.

A new owner can only start once the watchdog's callback mutex has been released by the process that held it. Whether the default mutex mechanism is released when its holder is killed depends on the platform; if prompt hand-off after a crash matters, select a mechanism that is released on process death for the watchdog-callback mutex with the Mutex directive (for example Mutex sysvsem watchdog-callback).

top

Administrator control of members

Beacon uses the Disabled status flag to take a member out of rotation when its lease expires, and clears it when the member announces again; it owns that flag for the members it manages. An administrator who disables such a member in the balancer-manager is therefore overridden by the next announcement after an eviction.

To hold a member out of rotation regardless of what it announces, set it to Stopped or Drain instead. Beacon never changes those flags, nor the flag set by an active health check (mod_proxy_hcheck); they combine with the lease state, so a stopped member stays stopped through any number of evictions and re-enablements.

top

Message validation and limits

The receiver validates every datagram before acting on it:

The proxy tracks at most 256 announced URLs. A record is released once it belongs to an evicted member, or to an add that failed, and has been silent for more than twice ProxyBeaconMaxSkew (by then a replay of its last message would be stale anyway, so no replay protection is lost). Until then a flood of distinct URLs from a holder of the secret can fill the table and keep new backends out; the members themselves remain in the balancer, and a backend that announces again after its record was released is re-adopted. A balancer's own limit (growth, at most 100) caps how many members can ever be added.

If the UDP socket cannot be opened (an unresolvable address, a port in use), opening is retried with a delay that starts at 30 seconds and doubles up to 10 minutes. Name lookups are synchronous and run on the single mod_watchdog thread that serves every beacon configuration of the server, so a name that fails to resolve can stall them for as long as the resolver takes to give up. Prefer an IP address in ProxyBeaconAddress and ProxyBeaconListen.

top

ProxyBeaconAddress Directive

Description:Address of the reverse proxy to which a backend sends its announcements
Syntax:ProxyBeaconAddress address:port
Context:server config, virtual host
Status:Extension
Module:mod_proxy_beacon

The ProxyBeaconAddress directive marks a server as an announcement sender (a backend). It sends UDP datagrams to the proxy's ProxyBeaconListen address given by address:port, e.g. proxy.example.com:5555 (a leading scheme such as tcp:// is accepted and ignored). Because UDP is connectionless, a backend may be started before the proxy is available: early datagrams are simply dropped and the next interval retries.

Use ProxyBeaconAdvertise to specify the routable URL the backend announces. ProxyBeaconAddress and ProxyBeaconListen are mutually exclusive on the same server.

top

ProxyBeaconAdvertise Directive

Description:The routable URL a backend announces to the reverse proxy
Syntax:ProxyBeaconAdvertise url
Context:server config, virtual host
Status:Extension
Module:mod_proxy_beacon

The ProxyBeaconAdvertise directive sets the backend's own reachable origin (for example http://10.0.0.5:8080) that the proxy will add as a BalancerMember. It must be a full scheme://host[:port] URL that the proxy can reach — not the local listen address — and is validated when the configuration is parsed. The URL names an origin only: a path, query string, fragment or user information is rejected with a configuration error (see Member identity). The URL is announced in its canonical form.

This directive is used on a backend, alongside ProxyBeaconAddress. If it is omitted, the backend still sends a heartbeat but advertises no URL, so the proxy logs the announcement without adding a member.

top

ProxyBeaconBalancer Directive

Description:Name of the balancer that announced backends are added to
Syntax:ProxyBeaconBalancer name
Context:server config, virtual host
Status:Extension
Module:mod_proxy_beacon

The ProxyBeaconBalancer directive names the balancer, on the reverse proxy, into which announced backends are inserted as members. Give the bare balancer name (for example cluster for balancer://cluster); a leading balancer:// is accepted and stripped.

The named balancer must exist and have spare capacity. Declare it with a <Proxy> block and a growth setting (or rely on BalancerGrowth) so there are free slots for the dynamically added members. This directive is used together with ProxyBeaconListen.

top

ProxyBeaconInterval Directive

Description:How often a backend publishes its announcement
Syntax:ProxyBeaconInterval interval
Default:ProxyBeaconInterval 5
Context:server config, virtual host
Status:Extension
Module:mod_proxy_beacon

The ProxyBeaconInterval directive sets how frequently a backend (a ProxyBeaconAddress server) publishes its announcement. It uses the time-interval directive syntax and defaults to seconds; the default is 5 seconds.

The interval must be meaningfully smaller than the proxy's ProxyBeaconTimeout, so that the occasional lost or delayed announcement does not cause a healthy backend to be evicted.

top

ProxyBeaconListen Directive

Description:Address on which the reverse proxy receives backend beacons
Syntax:ProxyBeaconListen [address][:port]
Context:server config, virtual host
Status:Extension
Module:mod_proxy_beacon

The ProxyBeaconListen directive marks a server as the beacon receiver (the reverse proxy). It binds a UDP socket to the given address, e.g. 0.0.0.0:5555 to receive on all interfaces. A leading scheme (such as tcp://) is accepted and ignored.

The address and port are both optional and, when omitted, are inherited from this server's own address and port (its Listen/ServerName). With no argument at all, the beacon listener binds the server's own address and port; given just an address it inherits the port, and so on. Because UDP and TCP are independent port spaces, binding the beacon socket to the server's port does not collide with the server's TCP listener — letting the beacon channel share the service endpoint, which also identifies the proxy to backends by its real address. (The listener binds in an unprivileged child, so a privileged port such as 80 or 443 cannot be shared this way; use the server's port only when it is non-privileged.)

Backends send to this address via ProxyBeaconAddress. The directive should be used together with ProxyBeaconBalancer; without it, announcements are received and logged but no members are added. ProxyBeaconListen and ProxyBeaconAddress are mutually exclusive on the same server.

top

ProxyBeaconMaxSkew Directive

Description:Maximum allowed age of a signed announcement
Syntax:ProxyBeaconMaxSkew interval
Context:server config, virtual host
Status:Extension
Module:mod_proxy_beacon

The ProxyBeaconMaxSkew directive sets the anti-replay window used when ProxyBeaconSecret is configured: the proxy rejects any announcement whose signed timestamp differs from the current time by more than this amount, in either direction. It uses the time-interval directive syntax and defaults to seconds.

If unset, the default is 30 seconds. Sub-second values are honoured (for example 500ms). A larger window tolerates greater clock skew between hosts; a smaller window bounds the freshness check. Note that the per-backend strictly-increasing-timestamp check (see ProxyBeaconSecret) blocks replays regardless of this window. This directive is used on the proxy.

top

ProxyBeaconSecret Directive

Description:Pre-shared secret used to authenticate announcements
Syntax:ProxyBeaconSecret secret|hex:key
Context:server config, virtual host
Status:Extension
Module:mod_proxy_beacon

The ProxyBeaconSecret directive sets a pre-shared cluster secret. It must be configured with the same value on the reverse proxy and on every backend. The backend (sender) signs each announcement with a keyed message-authentication code (a SipHash MAC) derived from the secret, together with a timestamp; the proxy (receiver) recomputes the MAC and checks the timestamp, dropping any announcement that is forged, tampered with, or replayed. Replayed messages are caught two ways: a freshness window (ProxyBeaconMaxSkew) rejects old timestamps, and a per-backend check rejects any announcement whose timestamp does not strictly advance, so a captured-and-resent message (for example, one replayed to keep a dead backend from being evicted) is dropped.

This directive is required on every server that participates in the beacon channel — the proxy (ProxyBeaconListen) and every backend (ProxyBeaconAddress). If any such server omits it, the server fails to start; there is no unauthenticated mode.

Every announcement must carry a valid, recent MAC or it is rejected. If the secrets on the proxy and a backend differ, that backend's announcements are silently rejected (and logged), which appears as the backend never joining the balancer.

Use a random key. Generate one with openssl rand -hex 16 and configure it as hex: followed by the 32 hex digits; that value is used directly as the 128-bit MAC key, so there is nothing to guess. Any other value is treated as a passphrase: it must be at least 16 characters, and the MAC key is derived from it with a fast hash. Because the authentication tag is 64 bits, anyone who captures a single announcement can test passphrase guesses offline at full speed, so a passphrase protects only as well as it is random and long. A value that begins with hex: is always read as a key and is rejected if it is not exactly 32 hex digits.

The secret is a membership credential

A valid MAC proves only that the sender holds the secret. It does not prove that the sender owns the URL it announces, may speak for another backend, or is ready to serve. Every holder can therefore register any backend origin the proxy can reach, announce on behalf of other members (keeping their leases alive), and use up the balancer's growth slots and the tracking table. Treat the secret as an administrator credential for the balancer, and share it only among hosts that you would trust with that. It is not a boundary between partially trusted workloads.

Because the secret is stored in the configuration file, restrict that file's permissions as you would for a private key.

Clock synchronisation

The timestamp-based replay protection compares the announcement's time against the proxy's clock, so the proxy and backends must have reasonably synchronised clocks (for example via NTP). See ProxyBeaconMaxSkew.

top

ProxyBeaconTimeout Directive

Description:How long the proxy waits, without an announcement, before a backend is taken out of rotation
Syntax:ProxyBeaconTimeout interval
Default:ProxyBeaconTimeout 0
Context:server config, virtual host
Status:Extension
Module:mod_proxy_beacon

The ProxyBeaconTimeout directive sets how long the reverse proxy will wait for an announcement from a backend before disabling that backend's balancer member (taking it out of rotation). A later announcement from the same backend re-enables it. It uses the time-interval directive syntax and defaults to seconds.

The default, 0, disables eviction entirely: backends are added when they announce but are never automatically removed. Set this to a small multiple of the backends' ProxyBeaconInterval to enable self-healing membership. This directive is used on the proxy.

Available Languages:  en  |  fr