Deploy OpenObserve [Updated Sep '26]
Observability in one binary: logs, metrics, traces, RUM. Data on a volume.
OpenObserve
Just deployed
Deploy and Host OpenObserve on Railway
OpenObserve is an open source observability platform for logs, metrics, traces, RUM and session replay. It ships as a single Rust binary and stores data as compressed Parquet, which is why its authors measure roughly 140x lower storage cost than an Elasticsearch based stack for the same data.
About Hosting OpenObserve
This template runs OpenObserve v0.92.2 as one service backed by a Railway volume
mounted at /data. It runs in local mode, so metadata lives in an embedded
store and data lives on the volume. No Postgres, no etcd and no object storage
bucket are involved, and there is nothing to wire together after deploy.
The root user is created on first boot from two variables. You supply the login email, the password is generated for you, and both stay visible in the service's Variables tab so you can retrieve them at any time. Telemetry to the upstream vendor is turned off.
Ingestion works over several protocols on the same instance: OpenTelemetry OTLP
for logs, traces and metrics, a plain JSON endpoint, Elasticsearch _bulk and
Loki. Most collectors and shippers you already run can point at it with only a
URL and a basic auth header changed.
Common Use Cases
- Central log search for a group of Railway services, replacing scattered per service log tabs with one queryable store
- An OTLP endpoint for an OpenTelemetry Collector already running traces and metrics, without paying per host for a hosted vendor
- Frontend RUM and session replay for a small product, kept on infrastructure you control
- A cheap long retention tier for logs that would be expensive to keep in a hosted observability service
Dependencies for OpenObserve Hosting
None. The binary is self contained and this template provisions everything it needs.
Deployment Dependencies
- Upstream project: https://github.com/openobserve/openobserve
- Container image:
openobserve/openobserve:v0.92.2on Docker Hub - Documentation: https://openobserve.ai/docs/
- A Railway volume, created automatically by this template
Implementation Details
Logging in. ZO_ROOT_USER_EMAIL defaults to admin@example.com and is
prompted at deploy so you can set your own. ZO_ROOT_USER_PASSWORD is generated
and readable in the Variables tab. Open the public URL and sign in with that
pair. Editing the variables later does not rotate an existing user's password,
because the root account is seeded only when the volume is empty.
Sending logs.
curl -u "$EMAIL:$PASSWORD" -H 'Content-Type: application/json' \
-d '[{"level":"info","msg":"hello","service":"my-app"}]' \
https://YOUR-DOMAIN/api/default/my_stream/_json
OpenTelemetry endpoints, all requiring an Authorization: Basic header
built from the same email and password:
https://YOUR-DOMAIN/api/default/v1/logs
https://YOUR-DOMAIN/api/default/v1/traces
https://YOUR-DOMAIN/api/default/v1/metrics
Querying from the API. Search window timestamps are in microseconds, not milliseconds. A window in the wrong unit returns zero hits and no error, which is the single most common cause of a "my data vanished" report.
Retention. There is no retention limit by default, so the volume grows for
as long as you ingest. Set a per stream retention in the stream's settings, or
set ZO_COMPACT_DATA_RETENTION_DAYS globally, and resize the volume in the
Railway dashboard before it fills. A full volume fails ingestion while the UI
keeps serving, so it looks like a data problem rather than a disk problem.
Configuration choices worth knowing. The port is pinned to 5080 on the app,
on PORT and on the service domain, because Railway's port autodetection is
unreliable against this image. ZO_HTTP_IPV6_ENABLED=true so Railway's IPv6
private network can reach the container, and the IPv4 healthcheck on /healthz
was confirmed to still pass with it enabled. The image is distroless and has no
shell, so the template runs the image's own entrypoint rather than a wrapped
start command.
Scaling past one node. Local mode is deliberate and is the right shape for a
single instance. For a cluster, switch to ZO_LOCAL_MODE=false with
ZO_META_STORE=postgres and S3 compatible object storage for data. That is a
multi service topology and is not what this template deploys.
Troubleshooting.
- Blank page or a redirect loop right after deploy: the app is still doing first boot directory initialisation on a new volume. Give it a minute and reload.
- Searches return nothing although ingestion returned
successful: check the time range unit, microseconds, and check the stream name in the Streams page. - Ingestion suddenly returns errors while the UI works: the volume is full. Resize it and set retention.
- 401 on every ingest call: the credentials are the root email and password from the Variables tab, sent as HTTP basic auth, not a bearer token.
Why Deploy OpenObserve on Railway?
Railway gives OpenObserve the two things it actually needs, a persistent volume and a public HTTPS domain, without any of the cluster machinery its HA mode would otherwise pull in. The pinned image means your instance does not change version underneath you, the volume means a redeploy does not lose the data you have already ingested, and scaling is a volume resize rather than a migration.
Both were verified empirically before publishing: the template was click deployed into a clean project, logs were ingested and read back through the search API, and the data was still queryable after a full redeploy.
Template Content
OpenObserve
openobserve/openobserve:v0.92.2