Architecture
Private intake and storage, with a public Kibana interface.
Data flow
Application in the Railway environment
→ Logstash HTTP intake (Basic auth)
→ Elasticsearch (restricted writer)
→ Kibana Discover
Browser → Railway HTTPS → Kibana loginLogstash writes to its persistent queue before output processing. Permanent indexing errors can enter the dead letter queue. Kibana queries Elasticsearch and stores saved objects there.
Service boundaries
| Service | Interface | Storage |
|---|---|---|
| Elasticsearch | Private HTTP 9200; readiness 8081 | Mounted data volume |
| Logstash | Private intake 8080; management 9600 | Mounted queue and DLQ volume |
| Kibana | Public HTTPS to UI 5601; readiness 8082 | Saved objects in Elasticsearch |
Ports come from the template Dockerfiles, pipeline, and Railway configuration. Private traffic is unencrypted HTTP. Do not create public Elasticsearch or Logstash endpoints with this configuration.
Identities
elastic is the administrator used for provisioning and recovery. Kibana uses its dedicated system identity. Logstash uses a restricted writer. Applications authenticate to intake as shipper with INPUT_PASSWORD, which is separate from the Elasticsearch writer password.
Delivery semantics
HTTP success confirms intake acceptance. It does not confirm indexing or field validity. Timeouts can occur after acceptance, so retries may produce duplicate events. This design does not guarantee exactly-once delivery.
The persistent queue and DLQ each have a configured 64mb ceiling in logstash/logstash.yml. A full queue can block or time out intake. DLQ drop_newer preserves older rejects and loses newer rejects when full.
Availability and backup
The template uses a single Elasticsearch node. Persistent volumes survive compatible redeploys but do not supply high availability or automatic backups. External snapshots require owner-provided storage and verification. See Upgrades and OPERATIONS.md.