Sending parsed events from Logstash to Elasticsearch turns an ingest pipeline into searchable documents for dashboards, alerts, and retention policies. The output block decides which cluster receives the events, how Logstash authenticates, and which index name is created when new documents are written.
The elasticsearch output plugin sends batches through the Elasticsearch Bulk API to one or more HTTP(S) endpoints. This configuration uses index mode with an explicit daily index pattern so the destination stays easy to check with a read-only count query.
Modern Logstash releases use ssl_enabled and ssl_certificate_authorities for TLS trust, and packaged 9.x installs block superuser runs unless allow_superuser is changed. Keep the output password in the Logstash keystore, and pair a custom index pattern with ilm_enabled ⇒ false when daily index names must not be replaced by an ILM rollover alias.
Elasticsearch URL: https://elasticsearch.example.net:9200
CA certificate: /etc/logstash/certs/http_ca.crt
Output user: logstash_internal
Index pattern: logs-%{+YYYY.MM.dd}
The hosts value should point at Elasticsearch HTTP nodes, not dedicated master-only nodes. Use a read-only account later for the verification query instead of reusing the write-only output account.
$ sudo /usr/share/logstash/bin/logstash-keystore --path.settings /etc/logstash add LOGSTASH_INTERNAL_PASSWORD Enter value for LOGSTASH_INTERNAL_PASSWORD: Added 'LOGSTASH_INTERNAL_PASSWORD' to the Logstash keystore.
The key name must match the ${LOGSTASH_INTERNAL_PASSWORD} placeholder used in the pipeline file.
Related: How to create a Logstash keystore
Related: How to add a secret to a Logstash keystore
output {
elasticsearch {
hosts => ["https://elasticsearch.example.net:9200"]
ssl_enabled => true
ssl_certificate_authorities => ["/etc/logstash/certs/http_ca.crt"]
user => "logstash_internal"
password => "${LOGSTASH_INTERNAL_PASSWORD}"
ilm_enabled => false
index => "logs-%{+YYYY.MM.dd}"
}
}
Use a higher numeric prefix such as 30-output.conf so the output block loads after lower-numbered inputs and filters. Use ssl_certificate_authorities for a private or self-signed Elasticsearch HTTP CA; on Elastic Cloud, use cloud_id plus cloud_auth or api_key instead of the self-managed host and CA settings.
$ sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash --path.data /tmp/logstash-output-configtest --config.test_and_exit Using bundled JDK: /usr/share/logstash/jdk Configuration OK [2026-06-18T15:20:00,000][INFO ][logstash.runner ] Using config.test_and_exit mode. Config Validation Result: OK. Exiting Logstash
The temporary --path.data directory must be writable by the logstash user. This validation confirms pipeline syntax and plugin settings only; it does not prove credentials, TLS trust, or index privileges until the service starts and sends events.
$ sudo rm -rf /tmp/logstash-output-configtest
$ sudo systemctl restart logstash
Restarting Logstash briefly stops pipeline workers and can pause ingestion while outputs reconnect and queues drain.
$ sudo journalctl --unit logstash --since "5 minutes ago" --no-pager
Jun 18 15:20:01 logstash-node logstash[24814]: [2026-06-18T15:20:01,510][INFO ][logstash.outputs.elasticsearch][main] Elasticsearch pool URLs updated {changes: {removed: [], added: [https://elasticsearch.example.net:9200/]}}
Jun 18 15:20:01 logstash-node logstash[24814]: [2026-06-18T15:20:01,681][INFO ][logstash.outputs.elasticsearch][main] Connected to ES instance {url: "https://elasticsearch.example.net:9200/"}
Jun 18 15:20:01 logstash-node logstash[24814]: [2026-06-18T15:20:01,742][INFO ][logstash.outputs.elasticsearch][main] Data streams auto configuration (`data_stream => auto` or unset) resolved to `false`
Jun 18 15:20:02 logstash-node logstash[24814]: [2026-06-18T15:20:02,125][INFO ][logstash.javapipeline ][main] Pipeline started {"pipeline.id"=>"main"}
401 or 403 responses usually mean the output credential is missing the required role or index privileges, while TLS failures usually mention certificate trust, hostname mismatch, or protocol negotiation.
$ curl --silent --show-error --fail \
--cacert /etc/logstash/certs/http_ca.crt \
--user reader_user:reader-password \
"https://elasticsearch.example.net:9200/logs-*/_count?pretty"
{
"count" : 42,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
}
}
A nonzero count with failed shards at 0 confirms Elasticsearch can read documents from the target index pattern. If the count remains 0, send a fresh event through the pipeline and review the Logstash journal for bulk indexing, template, or lifecycle errors.