Elasticsearch cross-cluster replication (CCR) keeps a read-only follower index synchronized with a leader index in a separate cluster for disaster recovery, regional read locality, and maintenance windows without losing recent writes.

CCR is configured on the follower cluster by connecting to the leader cluster as a remote cluster and starting a follow task with the _ccr/follow API. The follower index continuously pulls operations from the leader index and applies them locally while inheriting the leader’s mappings and most index settings.

CCR requires a license that includes CCR features and version compatibility between clusters, plus network reachability to the leader cluster’s transport endpoints. When security is enabled, API calls require authentication and appropriate cluster/index privileges, and cluster-level objects (templates, ILM policies, ingest pipelines) may require separate synchronization when needed.

Steps to set up Elasticsearch cross-cluster replication:

  1. Confirm the leader index exists on the leader cluster.
    $ curl --silent --show-error "http://leader-es:9200/_cat/indices/logs-2026.01.08?v"
    health status index           uuid                   pri rep docs.count docs.deleted store.size pri.store.size dataset.size
    green  open   logs-2026.01.08 HbML1itSS_CJMVF8Spi1qA   1   1          5            0     30.6kb         15.3kb       15.3kb

    Use the correct http or https scheme for the cluster endpoint, and include authentication options as required.

  2. Configure a remote cluster alias on the follower cluster for the leader cluster.

    Remote cluster connections use the transport port (typically 9300), not the HTTP port.

  3. Confirm the remote cluster alias is connected from the follower cluster.
    $ curl --silent --show-error "http://follower-es:9200/_remote/info?pretty"
    {
      "dr-site" : {
        "connected" : true,
        "mode" : "sniff",
        "seeds" : [
          "192.0.2.51:9300",
          "192.0.2.52:9300"
        ],
        "num_nodes_connected" : 2,
        "max_connections_per_cluster" : 3,
        "initial_connect_timeout" : "30s",
        "skip_unavailable" : true
      }
    }

    The response should show connected: true for the remote alias.

  4. Create the follower index using the _ccr/follow API on the follower cluster.
    $ curl -s -H "Content-Type: application/json" -X PUT "http://follower-es:9200/logs-follow/_ccr/follow?pretty" -d '{
      "remote_cluster": "dr-site",
      "leader_index": "logs-2026.01.08"
    }'
    {
      "follow_index_created" : true,
      "follow_index_shards_acked" : false,
      "index_following_started" : false
    }

    Direct writes to the follower index are rejected; ingest operations must target the leader index.

  5. Check the follower index follow state using the _ccr/info API.
    $ curl -s "http://follower-es:9200/logs-follow/_ccr/info?pretty"
    {
      "follower_indices" : [
        {
          "follower_index" : "logs-follow",
          "remote_cluster" : "dr-site",
          "leader_index" : "logs-2026.01.08",
          "status" : "active"
        }
      ]
    }
  6. Check follower shard replication metrics using the _ccr/stats API.
    $ curl -s "http://follower-es:9200/logs-follow/_ccr/stats?pretty"
    {
      "indices" : [
        {
          "index" : "logs-follow",
          "shards" : [
            {
              "shard_id" : 0,
              "remote_cluster" : "dr-site",
              "leader_index" : "logs-2026.01.08",
              "follower_index" : "logs-follow",
              "operations_read" : 1,
              "operations_written" : 1,
              "read_exceptions" : [ ]
            }
          ]
        }
      ]
    }
  7. Index a test document into the leader index on the leader cluster.
    $ curl --silent --show-error -H "Content-Type: application/json" -X POST "http://leader-es:9200/logs-2026.01.08/_doc/ccr-smoke-test-01?refresh=true" -d '{
      "message": "ccr smoke test",
      "service": "orders",
      "@timestamp": "2026-01-08T07:55:00Z"
    }'
    {
      "_index" : "logs-2026.01.08",
      "_id" : "ccr-smoke-test-01",
      "_version" : 1,
      "result" : "created",
      "forced_refresh" : true,
      "_shards" : {
        "total" : 2,
        "successful" : 2,
        "failed" : 0
      },
      "_seq_no" : 6,
      "_primary_term" : 1
    }
  8. Search the follower index for the test document on the follower cluster.
    $ curl -s -H "Content-Type: application/json" -X POST "http://follower-es:9200/logs-follow/_search?pretty" -d '{
      "query": {
        "ids": {
          "values": ["ccr-smoke-test-01"]
        }
      }
    }'
    {
      "took" : 2,
      "timed_out" : false,
      "hits" : {
        "total" : {
          "value" : 1,
          "relation" : "eq"
        },
        "hits" : [
          {
            "_index" : "logs-follow",
            "_id" : "ccr-smoke-test-01",
            "_source" : {
              "message" : "ccr smoke test",
              "service" : "orders",
              "@timestamp" : "2026-01-08T07:55:00Z"
            }
          }
        ]
      }
    }

    Replication is asynchronous; allow a short delay if the document is not immediately visible.