Configuring a remote cluster connection in Elasticsearch allows cross-cluster search and cross-cluster replication to reach data in another deployment without copying indices or widening trust between clusters.
On current self-managed clusters, the recommended model is to authenticate the local cluster with a cross-cluster API key over the dedicated remote cluster interface, which defaults to port 9443. The local cluster stores that credential in its keystore, trusts the remote cluster server certificate, and registers the remote alias through the cluster update settings API in either sniff mode or proxy mode.
The remote cluster server interface is disabled by default on self-managed remotes, so it must be enabled before the alias can connect. Nodes that originate CCS or CCR traffic must keep the remote_cluster_client role, sniff mode requires the remote publish addresses to be reachable from the local cluster, and from Elasticsearch 8.15 onward the default for skip_unavailable changed to true, so set it explicitly when the remote must be treated as required.
API-key authentication for self-managed remote clusters requires Elasticsearch security to be enabled on both clusters, nodes on both sides to run Elastic Stack 8.14 or later, the cluster versions to remain mutually compatible, and a license that covers the intended cross-cluster feature.
$ sudo /usr/share/elasticsearch/bin/elasticsearch-certutil cert --out /tmp/cross-cluster.p12 --pass=CERT_PASSWORD --ca-cert /tmp/ca/ca.crt --ca-key /tmp/ca/ca.key --dns remote-es.example.net --ip 198.51.100.20
If no CA exists yet, create one first with elasticsearch-certutil ca, or use an equivalent certificate and key pair issued by the PKI already trusted in the environment. The certificate must cover the DNS name or IP that the local cluster will use for the remote-cluster endpoint.
$ sudo install -o root -g elasticsearch -m 640 /tmp/cross-cluster.p12 /etc/elasticsearch/certs/cross-cluster.p12
remote_cluster_server.enabled: true remote_cluster.host: 198.51.100.20 remote_cluster.port: 9443 xpack.security.remote_cluster_server.ssl.enabled: true xpack.security.remote_cluster_server.ssl.keystore.path: certs/cross-cluster.p12
Do not leave remote_cluster.host on loopback or another unroutable publish address, or the local cluster will fail to connect even when the alias is accepted by the settings API.
$ sudo /usr/share/elasticsearch/bin/elasticsearch-keystore add xpack.security.remote_cluster_server.ssl.keystore.secure_password Enter value for xpack.security.remote_cluster_server.ssl.keystore.secure_password:
$ sudo systemctl restart elasticsearch
$ curl --silent --show-error --user elastic:strong-password --header "Content-Type: application/json" --request POST "https://remote-es.example.net:9200/_security/cross_cluster/api_key?pretty" --data '{
"name": "dr-site-ccs",
"access": {
"search": [
{
"names": ["logs-*", "metrics-*"]
}
]
}
}'
{
"id" : "VuaCfGcBCdbkQm-e5aOx",
"name" : "dr-site-ccs",
"expiration" : null,
"api_key" : "VuaC...",
"encoded" : "VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6VnVhQy4uLg=="
}
Authenticate this request with a user or credential that can manage security on the remote cluster, not with an API key. Save the encoded value for the local-cluster keystore step.
$ sudo install -o root -g elasticsearch -m 644 /tmp/ca/ca.crt /etc/elasticsearch/remote-cluster-ca.crt
xpack.security.remote_cluster_client.ssl.enabled: true xpack.security.remote_cluster_client.ssl.certificate_authorities: ["remote-cluster-ca.crt"]
If the remote cluster server uses a publicly trusted certificate, omit the certificate_authorities line and rely on the system CA bundle instead.
$ sudo /usr/share/elasticsearch/bin/elasticsearch-keystore add cluster.remote.dr-site.credentials Enter value for cluster.remote.dr-site.credentials: VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6VnVhQy4uLg==
The alias in the secure setting name (dr-site in this example) must match the alias configured later in cluster.remote.dr-site.* settings.
$ sudo systemctl restart elasticsearch
If only the API key value changes later and the TLS client settings are already in place, use POST /_nodes/reload_secure_settings instead of restarting the cluster.
$ curl --silent --show-error --user elastic:strong-password --header "Content-Type: application/json" --request PUT "https://local-es.example.net:9200/_cluster/settings?pretty" --data '{
"persistent": {
"cluster": {
"remote": {
"dr-site": {
"mode": "sniff",
"seeds": [
"remote-es.example.net:9443"
],
"skip_unavailable": false
}
}
}
}
}'
{
"acknowledged" : true,
"persistent" : {
"cluster" : {
"remote" : {
"dr-site" : {
"mode" : "sniff",
"seeds" : [
"remote-es.example.net:9443"
],
"skip_unavailable" : "false"
}
}
}
},
"transient" : { }
}
The account calling _cluster/settings needs the cluster manage privilege. Set skip_unavailable to true only when the remote should be optional for cross-cluster search.
Use proxy mode with proxy_address instead of sniff mode when the remote cluster is behind Elastic Cloud, ECE, ECK, NAT, or any network path where the remote nodes' publish addresses are not directly reachable from the local cluster.
$ curl --silent --show-error --user elastic:strong-password "https://local-es.example.net:9200/_remote/info?pretty&filter_path=*.connected,*.mode,*.num_nodes_connected,*.cluster_credentials"
{
"dr-site" : {
"connected" : true,
"mode" : "sniff",
"num_nodes_connected" : 1,
"cluster_credentials" : "::es_redacted::"
}
}
connected must be true, and cluster_credentials confirms the alias is using API-key authentication. Send CCS or CCR requests to nodes that keep the remote_cluster_client role. If the alias stays disconnected, confirm the remote cluster server is enabled, the endpoint and port are correct, and the local cluster trusts the remote server certificate.