Railway

Deploy Monoscope

API-first monitoring and observability platform for engineers.

Deploy Monoscope

Just deployed

Just deployed

/var/lib/postgresql

Deploy and Host Monoscope on Railway

Monoscope is an open-source observability platform. It ingests logs, traces, and metrics over HTTP and OpenTelemetry, stores them in TimescaleDB, and lets you query in natural language. This template self-hosts the official compose stack on Railway — the Haskell server (ghcr.io/monoscope-tech/monoscope:latest) plus TimescaleDB 2.29 on PostgreSQL 18.

Deploy on Railway

About Hosting Monoscope

Hosting Monoscope means running two containers on Railway’s private network: a public app (HTTP UI + API on $PORT, OTLP gRPC on 4317) and TimescaleDB for metadata and telemetry. Railway terminates TLS, so the app speaks HTTP inside the container (HOST_URL is still the public https:// origin). You attach one volume — TimescaleDB at /var/lib/postgresql — generate POSTGRES_PASSWORD once on timescaledb, point DATABASE_URL and TIMEFUSION_PG_URL at timescaledb.railway.internal, and let the entrypoint wait over IPv6, then exec monoscope-server. Migrations run on boot (MIGRATE_AND_INITIALIZE_ON_START=True). First boot can take a few minutes. After that, log in with basic auth and send OTLP to the private gRPC port.

Common Use Cases

  • Self-host OpenTelemetry for a SaaS or internal platform without sending traces to a third-party vendor
  • Keep years of logs, traces, and metrics in your own TimescaleDB volume on Railway
  • Natural-language incident search (optional OPENAI_API_KEY) plus live tail over SSE
  • MCP / agent workflows against /api/v1/mcp with an API key you create in the UI
  • Private OTLP collection from other Railway services via monoscope.railway.internal:4317

Dependencies for Monoscope Hosting

  • Monoscope image: ghcr.io/monoscope-tech/monoscope:latest (HTTP UI/API + OTLP gRPC + background jobs)
  • TimescaleDB 2.29 on PostgreSQL 18 (timescale/timescaledb:2.29.2-pg18) — metadata, users, and the self-host telemetry store
  • Railway private networkingtimescaledb.railway.internal:5432 (IPv6)
  • One persistent volume (drive) — see Implementation Details
  • Basic auth on the public UI (Auth0 is optional)

Name the database service timescaledb. Set each service Root Directory to its folder (monoscope/, timescaledb/). Keep TimescaleDB private; only monoscope gets a public HTTP domain.

Upstream: Monoscope · Self-host compose · Configuration · License AGPL-3.0

Implementation Details

Clone the template to see how it works:

monoscope/        # public web service
  Dockerfile      # FROM ghcr.io/monoscope-tech/monoscope:latest
  entrypoint.sh   # IPv6 wait-for TimescaleDB, then exec monoscope-server
  railway.toml    # healthcheck /ping, 300s timeout
timescaledb/
  Dockerfile      # timescale/timescaledb:2.29.2-pg18 + PGDATA
  entrypoint.sh   # listen_addresses=*, TimescaleDB preload
  railway.toml    # restart on failure

This kit follows the official docker-compose.yml (TimescaleDB + app). It does not run TimeFusion or MinIO. Telemetry is written to TimescaleDB (ENABLE_POSTGRES_TELEMETRY_WRITES=True, TimeFusion reads/writes off). TIMEFUSION_PG_URL still has to be a real Postgres URL because the process always opens a second pool — it is set to the same TimescaleDB URL.

Patroni from timescale/timescaledb-ha is omitted on purpose. Railway is the orchestrator; the non-HA image uses the official Postgres entrypoint, PGDATA=/var/lib/postgresql/data, and will not boot-loop on a volume mount.

Topology

Name the services exactly as written. Private DNS is .railway.internal. If you rename them, update DB_HOST, DATABASE_URL, and TIMEFUSION_PG_URL.

ServiceRoleRoot DirectoryVolumeMemoryPublic
timescaledbTimescaleDB (Postgres 18)timescaledb/var/lib/postgresql1 GB floor, 2 GB betterNo
monoscopeUI, HTTP API, OTLP gRPCmonoscopeNone1 GB floor, 2 GB betterYes (HTTP)
Volumes (drives) — what to mount

Attach before the first successful start. Skip this and init lands on ephemeral disk; the next deploy wipes projects, users, and telemetry.

ServiceMount pathWhat is storedStart size
timescaledb/var/lib/postgresqlRoles, projects, API keys, telemetry (otel_logs_and_spans). PGDATA=/var/lib/postgresql/data is already set.5 GB (20 GB+ as ingest grows)
monoscopedo not mount anythingStateless. Railway terminates TLS. Profiling eventlogs stay ephemeral.

Do not mount /etc/letsencrypt, SSL certs, or /opt/monoscope/static. Those are VPS/compose paths. Do not mount /var/lib/postgresql/data (the data directory itself) — mount the parent /var/lib/postgresql so initdb can create data on a clean volume.

Railway: timescaledbSettingsVolumesAdd Volume → paste /var/lib/postgresql exactly.

Environment variables

Generate secrets once on the owning service. Other services reference them. Do not paste the same ${{ secret(32) }} on two services — that mints two different values.

timescaledb (owner of the database password):

VariableValueDescription
POSTGRES_USERpostgresSuperuser. Keep in sync with DATABASE_URL.
POSTGRES_DBmonoscopeDatabase name. Keep in sync with DATABASE_URL.
POSTGRES_PASSWORD${{ secret(32) }}Generated once here. Referenced by monoscope.
PGDATA/var/lib/postgresql/dataMust sit under the volume mount.
TZUTCDatabase timezone.

monoscope (public app):

VariableValueDescription
DB_HOST${{timescaledb.RAILWAY_PRIVATE_DOMAIN}}Private DNS used by the IPv6 wait-for probe.
DB_PORT5432TimescaleDB port.
DATABASE_URLhost=${{timescaledb.RAILWAY_PRIVATE_DOMAIN}} user=postgres password=${{timescaledb.POSTGRES_PASSWORD}} dbname=monoscope port=5432 sslmode=disablelibpq keyword form — safe with IPv6 hostnames and unescaped passwords.
TIMEFUSION_PG_URLhost=${{timescaledb.RAILWAY_PRIVATE_DOMAIN}} user=postgres password=${{timescaledb.POSTGRES_PASSWORD}} dbname=monoscope port=5432 sslmode=disableSecond pool; same TimescaleDB on this self-host path.
HOST_URLhttps://${{RAILWAY_PUBLIC_DOMAIN}}Public HTTPS origin. Railway terminates TLS.
GRPC_PORT4317In-container OTLP gRPC. Not the Railway HTTP $PORT.
MIGRATIONS_DIR/opt/monoscope/static/migrations/Path inside the image.
ENVIRONMENTPRODDEV / STAGING / PROD.
LOGGING_DESTINATIONStdOutContainer logs.
LOG_LEVELInfoTrace is too noisy for production.
BASIC_AUTH_ENABLEDTrueSelf-host login.
BASIC_AUTH_USERNAMEadminFirst UI login.
BASIC_AUTH_PASSWORD${{ secret(32) }}Generated once on this service. Copy from Variables after first deploy.
API_KEY_ENCRYPTION_SECRET_KEY${{ secret(32) }}Min 32 chars. Rotating it invalidates stored API keys.
MIGRATE_AND_INITIALIZE_ON_STARTTrueRun SQL migrations before serving.
ENABLE_BACKGROUND_JOBSTrueAnomaly jobs, reports, maintenance.
ENABLE_PUBSUB_SERVICEFalseNo Kafka/Pub/Sub on this kit.
ENABLE_OTLP_GRPC_SERVICETrueBind gRPC on GRPC_PORT.
ENABLE_POSTGRES_TELEMETRY_WRITESTrueWrite telemetry into TimescaleDB.
ENABLE_TIMEFUSION_WRITESFalseNo TimeFusion service in this kit.
ENABLE_TIMEFUSION_READSFalseQuery TimescaleDB, not TimeFusion.
ENABLE_BROWSER_MONITORINGTrueBrowser spans in the UI.
SHOW_DEMO_PROJECTFalseHide the demo project.
AUTH0_LOGOUT_REDIRECThttps://${{RAILWAY_PUBLIC_DOMAIN}}Used only if you enable Auth0.
AUTH0_CALLBACKhttps://${{RAILWAY_PUBLIC_DOMAIN}}/auth_callbackUsed only if you enable Auth0.
SLACK_REDIRECT_URIhttps://${{RAILWAY_PUBLIC_DOMAIN}}/slack/oauth/callback/Used only if you set Slack OAuth.

Baked in — leave alone: PORT (Railway injects it; the app binds 0.0.0.0:$PORT), MIGRATIONS_DIR, ENABLE_PUBSUB_SERVICE=False.

Do not set: HTTP_SCHEME=https, in-container TLS certs, or Railway’s managed Postgres plugin as a substitute for timescaledb.

Optional (set on monoscope when you need the feature):

VariableDescription
OPENAI_API_KEYNatural-language queries and AI agents
OPENAI_BASE_URLCompatible OpenAI endpoint
SMTP_HOST SMTP_PORT SMTP_USERNAME SMTP_PASSWORD SMTP_SENDEREmail reports
SENDGRIDAPIKEYSendGrid instead of SMTP
POSTMARK_TOKENPostmark instead of SMTP
SLACK_CLIENT_ID SLACK_CLIENT_SECRETSlack OAuth alerts
AUTH0_DOMAIN AUTH0_CLIENT_ID AUTH0_SECRETSSO; then set BASIC_AUTH_ENABLED=False

If you rename services: change DB_HOST and the host= / interpolation prefix in DATABASE_URL to the new private DNS name.

Why Deploy Monoscope on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Monoscope on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.


Template Content

More templates in this category

View Template
NEW
Betterlytics
Betterlytics is a cookieless analytics platform GDPR-compliant.

OpenSource Templates
27
View Template
NEW
Finance Tracker
Private multi-user household finance ledger with budgets and CSV import.

wotonews
0
View Template
Matomo Analytics + MariaDB
Privacy-friendly analytics with MariaDB and persistent volumes.

leodev
1