Shard allocation filters are the controlled way to keep Elasticsearch shards on the right hardware, drain a node before maintenance, or confine data to a specific rack, zone, or tier without editing every index individually.
Cluster-wide filters are set through the dynamic /_cluster/settings API with cluster.routing.allocation.include, require, and exclude keys. They can match built-in node attributes such as _name, _host_ip, _publish_ip, _ip, _host, _id, and _tier, or custom node.attr.* values such as zone and rack, and they work together with per-index filters and allocation awareness.
Elastic recommends persistent cluster settings for routine allocation changes because transient overrides can disappear if the cluster becomes unstable. Shards only relocate when another node satisfies every routing rule and disk constraint, so an overly strict filter can leave shards UNASSIGNED instead of moving them. Secure clusters usually require https, authentication, and a trusted CA file, while Elastic Cloud Hosted and ECE deployments generally rely on tier-based placement rather than custom node attributes.
$ curl -sS "http://localhost:9200/_cluster/health?pretty"
{
"cluster_name" : "search-cluster",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 12,
"active_shards" : 24,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"unassigned_primary_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
Resolve a red cluster, unassigned primary shards, or an ongoing master instability problem before applying a new allocation rule, otherwise relocation results become harder to interpret.
$ curl -sS "http://localhost:9200/_cat/nodes?v&h=ip,name,node.role,master" ip name node.role master 192.0.2.40 es-data-1 cdfhilmrstw * 192.0.2.41 es-data-2 cdfhilmrstw - 192.0.2.42 es-data-3 cdfhilmrstw -
Use built-in attributes such as _name, _ip, or _tier when a stable node attribute already exists. On secured clusters, switch to https and add the required credentials and CA file for the same request.
$ curl -sS "http://localhost:9200/_cat/nodeattrs?v&h=node,attr,value" node attr value es-data-1 zone rack-a es-data-2 zone rack-b es-data-3 zone rack-c
Custom filters use values from node.attr.* on each node. If no custom attribute is available, keep the filter on a built-in attribute instead of inventing one during live maintenance.
$ curl -sS "http://localhost:9200/_cluster/settings?pretty&flat_settings=true"
{
"persistent" : { },
"transient" : { }
}
GET /_cluster/settings returns only explicit overrides by default. An empty response means the cluster is currently using defaults or static settings instead of an API-set filter.
$ curl -sS -H "Content-Type: application/json" --request PUT "http://localhost:9200/_cluster/settings?pretty&flat_settings=true" --data '{
"persistent": {
"cluster.routing.allocation.exclude._name": "es-data-3"
}
}'
{
"acknowledged" : true,
"persistent" : {
"cluster.routing.allocation.exclude._name" : "es-data-3"
},
"transient" : { }
}
Use cluster.routing.allocation.require.zone to keep shards on one attribute value, cluster.routing.allocation.include._tier to allow one or more data tiers, or cluster.routing.allocation.exclude._ip to drain nodes by address. include matches at least one listed value, require demands all listed values, and exclude blocks any listed value.
Comma-separated values and wildcards such as 192.0.2.* are supported where the attribute value makes sense.
Update calls on secured clusters need a credential with cluster manage privilege.
$ curl -sS "http://localhost:9200/_cluster/settings?pretty&flat_settings=true"
{
"persistent" : {
"cluster.routing.allocation.exclude._name" : "es-data-3"
},
"transient" : { }
}
Elastic recommends persistent settings for normal allocation changes. Avoid transient filters unless the short-lived behavior and rollback path are both deliberate.
$ curl -sS "http://localhost:9200/_cluster/health?wait_for_no_relocating_shards=true&timeout=30m&pretty"
{
"cluster_name" : "search-cluster",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 12,
"active_shards" : 24,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"unassigned_primary_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
Increase timeout for larger clusters or slower storage. Use /_cat/recovery?v&active_only=true when per-index recovery progress is needed during a long drain.
$ curl -sS "http://localhost:9200/_cat/allocation?v&h=shards,disk.percent,node" shards disk.percent node 12 64 es-data-1 12 67 es-data-2 0 61 es-data-3
If the blocked node still shows shards, another routing rule, disk watermark, or tier constraint is still preventing relocation. Use the allocation explain API before tightening the filter further.
$ curl -sS -H "Content-Type: application/json" --request PUT "http://localhost:9200/_cluster/settings?pretty&flat_settings=true" --data '{
"persistent": {
"cluster.routing.allocation.exclude._name": null
}
}'
{
"acknowledged" : true,
"persistent" : { },
"transient" : { }
}
Set every active filter key to null when clearing multiple rules in one request, for example both require.zone and exclude._name.
$ curl -sS "http://localhost:9200/_cluster/settings?pretty&flat_settings=true"
{
"persistent" : { },
"transient" : { }
}
$ curl -sS "http://localhost:9200/_cluster/health?pretty"
{
"cluster_name" : "search-cluster",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 12,
"active_shards" : 24,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"unassigned_primary_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}