Public DNS
- Console/API
<CONSOLE_DNS>- S3 endpoint
<S3_DNS>- Virtual-host buckets
*.<S3_DNS>
Production traffic
Select the X2 Node platform, then configure a production load balancer that preserves S3 signatures and streaming, verifies every backend, and removes unhealthy nodes from rotation.
The load balancer can run separately; these categories tailor paths, validation, and operating guidance to the X2 nodes behind it.
Platform preparation
Replace every value enclosed in <...>. The console
and S3 endpoints may share one load balancer, while the inter-node
mesh on port 9443 must never pass through it.
<CONSOLE_DNS><S3_DNS>*.<S3_DNS>X2 accepts valid forwarded headers from any peer when no trusted CIDRs are configured. If the X2 listener is also exposed to untrusted networks, use the optional allowlist later in this guide to limit forwarding to your load-balancer addresses.
Install the public certificate on the load balancer. Keep HTTPS between the load balancer and X2, and give it the CA that issued the X2 public-listener certificates. Do not disable upstream verification in production.
Every X2 upstream certificate must contain
<X2_UPSTREAM_TLS_NAME>. The initial
x2-node configure certificate includes the host from
--public-url; operator-issued certificates can use a
separate shared internal name.
NGINX
Put the map and upstream blocks in the
NGINX http context and the server block in the enabled
virtual host.
Install NGINX on one or more dedicated Linux load-balancer hosts. Confirm the distribution in the official package matrix.
sudo apt-get update
sudo apt-get install -y nginx
sudo systemctl enable --now nginx
Use production NGINX on a dedicated Linux host and point its upstream pool at the Windows node addresses. The native NGINX Windows build is beta and is not intended for high-performance production use.
# Run on each dedicated Linux load-balancer host
sudo apt-get update
sudo apt-get install -y nginx
sudo systemctl enable --now nginx
Use production NGINX on a dedicated Linux host and point its upstream pool at the macOS node addresses.
# Run on each dedicated Linux load-balancer host
sudo apt-get update
sudo apt-get install -y nginx
sudo systemctl enable --now nginx
map $http_upgrade $x2_connection_upgrade {
default upgrade;
'' '';
}
upstream x2_nodes {
least_conn;
server <X2_NODE_1_IP>:8443 max_fails=3 fail_timeout=10s;
server <X2_NODE_2_IP>:8443 max_fails=3 fail_timeout=10s;
keepalive 64;
}
server {
listen 443 ssl;
server_name <CONSOLE_DNS> <S3_DNS> *.<S3_DNS>;
ssl_certificate /etc/nginx/tls/x2-public.crt;
ssl_certificate_key /etc/nginx/tls/x2-public.key;
client_max_body_size 0;
location / {
proxy_pass https://x2_nodes;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Forwarded "";
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $x2_connection_upgrade;
proxy_request_buffering off;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_ssl_server_name on;
proxy_ssl_name <X2_UPSTREAM_TLS_NAME>;
proxy_ssl_trusted_certificate /etc/nginx/tls/x2-upstream-ca.crt;
proxy_ssl_verify on;
proxy_ssl_verify_depth 3;
}
}
This baseline uses HTTP/1.1 for broad package compatibility and streaming S3 requests. If the installed NGINX build includes the HTTP/2 module and uses the current directive syntax, enable http2 on; at server scope; the older listen ... http2 parameter is deprecated.
sudo nginx -t
sudo systemctl reload nginx
max_fails and fail_timeout react after proxied requests fail; this open-source configuration does not poll /health/ready in advance. A node can therefore receive a client request before NGINX marks it unavailable. Use the HAProxy example when active readiness checks are required, or deploy an independently verified NGINX health-check mechanism.
HAProxy
Install HAProxy on one or more dedicated Linux load-balancer hosts. For vendor packages, use the official HAProxy downloads.
sudo apt-get update
sudo apt-get install -y haproxy
sudo systemctl enable --now haproxy
Run HAProxy on a dedicated Linux host and point its backend pool at the Windows node addresses.
# Run on each dedicated Linux load-balancer host
sudo apt-get update
sudo apt-get install -y haproxy
sudo systemctl enable --now haproxy
Run HAProxy on a dedicated Linux host and point its backend pool at the macOS node addresses.
# Run on each dedicated Linux load-balancer host
sudo apt-get update
sudo apt-get install -y haproxy
sudo systemctl enable --now haproxy
frontend x2_public
bind :443 ssl crt /etc/haproxy/tls/x2-public.pem alpn h2,http/1.1
mode http
option httplog
http-request del-header Forwarded
http-request del-header X-Forwarded-For
http-request set-header X-Forwarded-Host %[req.hdr(Host)]
http-request set-header X-Forwarded-Proto https
http-request set-header X-Forwarded-For %[src]
default_backend x2_nodes
backend x2_nodes
mode http
balance leastconn
option httpchk GET /health/ready
http-check expect status 200
timeout connect 10s
timeout server 1h
server node1 <X2_NODE_1_IP>:8443 ssl verify required ca-file /etc/haproxy/tls/x2-upstream-ca.crt verifyhost <X2_UPSTREAM_TLS_NAME> check
server node2 <X2_NODE_2_IP>:8443 ssl verify required ca-file /etc/haproxy/tls/x2-upstream-ca.crt verifyhost <X2_UPSTREAM_TLS_NAME> check
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl reload haproxy
option httpchk polls /health/ready and the check parameter removes a backend that fails the expected HTTP 200 check. This detects readiness independently of a client request, while application requests still preserve the original host, streaming body, and verified upstream TLS.
Optional X2 configuration
No X2 load-balancer allowlist is required for the basic configurations
above. When trusted_proxy_cidrs is absent or empty,
X2 accepts valid forwarded headers from any immediate peer. Add an
allowlist only when the X2 listener is reachable by networks or
clients that must not be allowed to assert forwarded host or HTTPS
information.
The public URL and S3 host values are useful when publishing distinct DNS names. The trusted CIDRs are an independent, optional hardening control. Configure the immediate load-balancer connection addresses—not browser or S3 client addresses.
sudo /usr/lib/x2/x2-node configure \
--metadata '<METADATA_PATH>' \
--public-url 'https://<CONSOLE_DNS>' \
--s3-hosts '<S3_DNS>' \
--trusted-proxy-cidrs '<PROXY_IP_OR_NETWORK_CIDR>'
& 'C:\Program Files\X2\x2-node.exe' configure `
--metadata '<METADATA_PATH>' `
--public-url 'https://<CONSOLE_DNS>' `
--s3-hosts '<S3_DNS>' `
--trusted-proxy-cidrs '<PROXY_IP_OR_NETWORK_CIDR>'
sudo /usr/local/lib/x2/x2-node configure \
--metadata '<METADATA_PATH>' \
--public-url 'https://<CONSOLE_DNS>' \
--s3-hosts '<S3_DNS>' \
--trusted-proxy-cidrs '<PROXY_IP_OR_NETWORK_CIDR>'
Multiple load-balancer instances use a comma-separated list.
A same-host instance normally uses
127.0.0.1/32,::1/128. Once any CIDR
is configured, X2 rejects forwarded headers from every peer
outside that allowlist.
public:
base_url: "https://<CONSOLE_DNS>"
s3_endpoint_hosts:
- "<S3_DNS>"
trusted_proxy_cidrs:
- "<PROXY_IP_OR_NETWORK_CIDR>"
When the public listener uses a non-default HTTPS port, include
that external port in public.base_url (or
--public-url). X2 applies the externally advertised
port to the configured S3 domain; the node backend port is not
published. The NGINX example preserves the complete public
Host authority for S3 signature verification.
X2 updates its cluster-issued node certificate when S3 domains change, including each domain and its wildcard bucket name. If public TLS ends at the load balancer, install a certificate covering those names on the load balancer separately.
To return to unrestricted forwarded-header trust, remove
trusted_proxy_cidrs or set it to an empty list,
then restart the node through the normal service workflow.
Forwarded values are still syntax-checked, conflicting hosts
are rejected, and the forwarded public scheme must be HTTPS.
If the load balancer verifies X2 upstream TLS using a different name,
install a certificate containing
<X2_UPSTREAM_TLS_NAME> with the
--tls-cert and --tls-key options.
Verification
curl --fail https://<CONSOLE_DNS>/health/ready
curl --head https://<CONSOLE_DNS>/
xc alias set x2 https://<S3_DNS> '<ACCESS_KEY>' '<SECRET_KEY>'
xc mb x2/proxy-smoke
xc cp ./large-object.bin x2/proxy-smoke/large-object.bin
xc stat x2/proxy-smoke/large-object.bin
Without a CIDR allowlist, a valid forwarded header is accepted from any peer. When the optional allowlist is configured, a request carrying forwarded headers from an address outside that list must return HTTP 400.
Confirm every upstream passes readiness, large uploads do not buffer to load-balancer disk, WebSocket upgrades succeed, and requests continue without session stickiness when one X2 node is drained.
Admit public traffic only after DNS, certificate names, upstream verification, optional load-balancer CIDRs, console login, and signed S3 operations all pass.
Continue to operations →