{
  "manifest_version": "1.0.0",
  "template": {
    "id": "15cb7351-8b53-4381-adff-14eca18fbba8",
    "slug": "clickstack-243",
    "name": "ClickStack 2.43",
    "description": "Open-source observability on ClickHouse: logs, traces, metrics, replays",
    "url": "https://railway.com/deploy/clickstack-243",
    "upstream": {
      "image": "hyperdx/hyperdx-otel-collector:2.43.1"
    }
  },
  "status": "unvalidated",
  "validated_at": null,
  "success_rate_30d": null,
  "services": [
    {
      "name": "ClickHouse",
      "source": {
        "image": "clickhouse/clickhouse-server:26.8.36.3-alpine"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/clickhouse",
      "http": false
    },
    {
      "name": "Collector",
      "source": {
        "image": "hyperdx/hyperdx-otel-collector:2.43.1"
      },
      "needs_volume": false,
      "http": true
    },
    {
      "name": "MongoDB",
      "source": {
        "image": "mongo:7.0.45"
      },
      "needs_volume": true,
      "volume_mount_path": "/data/db",
      "http": false
    },
    {
      "name": "HyperDX",
      "source": {
        "image": "hyperdx/hyperdx:2.43.1"
      },
      "needs_volume": false,
      "http": true
    }
  ],
  "required_inputs": [
    {
      "key": "PORT",
      "service": "ClickHouse",
      "description": "ClickHouse HTTP port (healthcheck)",
      "secret": false,
      "strategy": "default",
      "default": "8123"
    },
    {
      "key": "CLICKHOUSE_DB",
      "service": "ClickHouse",
      "description": "Database for telemetry",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "CLICKHOUSE_USER",
      "service": "ClickHouse",
      "description": "ClickHouse user for HyperDX and the collector",
      "secret": false,
      "strategy": "default",
      "default": "hyperdx"
    },
    {
      "key": "CLICKHOUSE_RUN_SH",
      "service": "ClickHouse",
      "description": "Start script: small internal log tables, then the official entrypoint",
      "secret": false,
      "strategy": "default",
      "default": "# ClickHouse for ClickStack on Railway: keeps ClickHouse's internal log tables\n# small, then starts the official entrypoint (which creates the user from\n# CLICKHOUSE_USER / CLICKHOUSE_PASSWORD on the first start).\n# The image listens on IPv6 and IPv4, which Railway's private network needs.\nset -eu\nrm -rf /var/lib/clickhouse/lost+found\ncat > /etc/clickhouse-server/config.d/railway.xml <<'XML'\n<clickhouse>\n    <listen_host>::</listen_host>\n    <logger><level>warning</level><console>true</console></logger>\n    <timezone>UTC</timezone>\n    <mark_cache_size>536870912</mark_cache_size>\n    <trace_log remove=\"remove\"/>\n    <text_log remove=\"remove\"/>\n    <metric_log remove=\"remove\"/>\n    <asynchronous_metric_log remove=\"remove\"/>\n    <processors_profile_log remove=\"remove\"/>\n    <query_metric_log remove=\"remove\"/>\n    <query_thread_log remove=\"remove\"/>\n    <query_views_log remove=\"remove\"/>\n    <asynchronous_insert_log remove=\"remove\"/>\n    <opentelemetry_span_log remove=\"remove\"/>\n    <session_log remove=\"remove\"/>\n    <latency_log remove=\"remove\"/>\n    <query_log replace=\"1\">\n        <database>system</database>\n        <table>query_log</table>\n        <flush_interval_milliseconds>7500</flush_interval_milliseconds>\n        <engine>ENGINE = MergeTree PARTITION BY event_date ORDER BY (event_time) TTL event_date + interval 3 day SETTINGS ttl_only_drop_parts=1</engine>\n    </query_log>\n    <part_log><ttl>event_date + INTERVAL 3 DAY DELETE</ttl></part_log>\n    <error_log><ttl>event_date + INTERVAL 7 DAY DELETE</ttl></error_log>\n</clickhouse>\nXML\nexec /entrypoint.sh\n"
    },
    {
      "key": "CLICKHOUSE_PASSWORD",
      "service": "ClickHouse",
      "description": "ClickHouse password (generated)",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "ClickHouse",
      "description": "Time to shut down cleanly",
      "secret": false,
      "strategy": "default",
      "default": "60"
    },
    {
      "key": "CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT",
      "service": "ClickHouse",
      "description": "Lets the user manage access",
      "secret": false,
      "strategy": "default",
      "default": "1"
    },
    {
      "key": "PORT",
      "service": "Collector",
      "description": "Collector health check port",
      "secret": false,
      "strategy": "default",
      "default": "13133"
    },
    {
      "key": "CLICKHOUSE_USER",
      "service": "Collector",
      "description": "ClickHouse user",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OPAMP_SERVER_URL",
      "service": "Collector",
      "description": "HyperDX OpAMP server: the collector gets its pipeline and the accepted API keys from it",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "HYPERDX_LOG_LEVEL",
      "service": "Collector",
      "description": "Log level",
      "secret": false,
      "strategy": "default",
      "default": "info"
    },
    {
      "key": "CLICKHOUSE_ENDPOINT",
      "service": "Collector",
      "description": "ClickHouse native endpoint (private network)",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_PASSWORD",
      "service": "Collector",
      "description": "ClickHouse password",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OTLP_PRIVATE_GRPC_ENDPOINT",
      "service": "Collector",
      "description": "OTLP/gRPC endpoint for apps in the same Railway project (API key still required)",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "OTLP_PRIVATE_HTTP_ENDPOINT",
      "service": "Collector",
      "description": "OTLP/HTTP endpoint for apps in the same Railway project (API key still required)",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "OTEL_EXPORTER_OTLP_ENDPOINT",
      "service": "Collector",
      "description": "Public OTLP/HTTP endpoint. Copy to your apps, with the ingestion API key from HyperDX (Team Settings) as the authorization header",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "HYPERDX_OTEL_EXPORTER_TABLES_TTL",
      "service": "Collector",
      "description": "How long telemetry is kept",
      "secret": false,
      "strategy": "default",
      "default": "720h"
    },
    {
      "key": "HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE",
      "service": "Collector",
      "description": "ClickHouse database for logs, traces, metrics and sessions",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA",
      "service": "Collector",
      "description": "Let the exporter create the tables (as in the upstream compose file)",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "MONGO_INITDB_ROOT_PASSWORD",
      "service": "MongoDB",
      "description": "MongoDB root password (generated)",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "MONGO_INITDB_ROOT_USERNAME",
      "service": "MongoDB",
      "description": "MongoDB root user",
      "secret": false,
      "strategy": "default",
      "default": "hyperdx"
    },
    {
      "key": "PORT",
      "service": "HyperDX",
      "description": "Port Railway routes the public domain to",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "MONGO_URI",
      "service": "HyperDX",
      "description": "MongoDB connection for users, dashboards, alerts and saved searches (private network)",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "FRONTEND_URL",
      "service": "HyperDX",
      "description": "Public URL of HyperDX. Change it when you add a custom domain",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "HYPERDX_RUN_SH",
      "service": "HyperDX",
      "description": "Start script: starts HyperDX and creates the admin account on the first start",
      "secret": false,
      "strategy": "default",
      "default": "# HyperDX (ClickStack UI + API + OpAMP server) on Railway.\n# Starts the official entrypoint, then creates the admin account from\n# HYPERDX_ADMIN_EMAIL / HYPERDX_ADMIN_PASSWORD on the first start. HyperDX\n# allows only one team, so once the admin exists nobody else can sign up\n# (new users need an invitation). Creating the team also turns on API-key\n# authentication on the collector's OTLP endpoint.\nset -u\nsh /etc/local/entry.sh &\nMAIN=$!\nnode -e '\nconst api = \"http://127.0.0.1:\" + (process.env.HYPERDX_API_PORT || \"8000\");\nconst email = process.env.HYPERDX_ADMIN_EMAIL, password = process.env.HYPERDX_ADMIN_PASSWORD;\nconst log = (m) => console.log(\"hyperdx-setup: \" + m);\n(async () => {\n  if (!email || !password) { log(\"HYPERDX_ADMIN_EMAIL or HYPERDX_ADMIN_PASSWORD empty, skipping admin creation\"); return; }\n  for (let i = 0; i < 180; i++) {\n    try {\n      const r = await fetch(api + \"/installation\");\n      if (r.ok) {\n        const j = await r.json();\n        if (j.isTeamExisting) { log(\"team already exists, sign-up closed\"); return; }\n        const p = await fetch(api + \"/register/password\", { method: \"POST\", headers: { \"content-type\": \"application/json\" },\n          body: JSON.stringify({ email, password, confirmPassword: password }) });\n        const t = await p.text();\n        if (p.ok) { log(\"admin \" + email + \" created, sign-up closed\"); return; }\n        if (p.status === 409) { log(\"team already exists, sign-up closed\"); return; }\n        log(\"admin creation failed: \" + p.status + \" \" + t.slice(0, 200)); return;\n      }\n    } catch (e) {}\n    await new Promise((r) => setTimeout(r, 2000));\n  }\n  log(\"API did not start within 6 minutes; admin not created\");\n})();\n' &\nwait $MAIN\n"
    },
    {
      "key": "DEFAULT_SOURCES",
      "service": "HyperDX",
      "description": "Log, trace, metric and session sources created for the team on first start",
      "secret": false,
      "strategy": "default",
      "default": "[{\"from\":{\"databaseName\":\"default\",\"tableName\":\"otel_logs\"},\"kind\":\"log\",\"timestampValueExpression\":\"Timestamp\",\"name\":\"Logs\",\"displayedTimestampValueExpression\":\"Timestamp\",\"implicitColumnExpression\":\"Body\",\"serviceNameExpression\":\"ServiceName\",\"bodyExpression\":\"Body\",\"eventAttributesExpression\":\"LogAttributes\",\"resourceAttributesExpression\":\"ResourceAttributes\",\"defaultTableSelectExpression\":\"Timestamp,ServiceName,SeverityText,Body\",\"severityTextExpression\":\"SeverityText\",\"severityNumberExpression\":\"SeverityNumber\",\"eventNameExpression\":\"EventName\",\"traceIdExpression\":\"TraceId\",\"spanIdExpression\":\"SpanId\",\"metadataMaterializedViews\":{\"kvRollupTable\":\"otel_logs_kv_rollup_15m\",\"granularity\":\"15 minute\"},\"connection\":\"Local ClickHouse\",\"traceSourceId\":\"Traces\",\"metricSourceId\":\"Metrics\"},{\"from\":{\"databaseName\":\"default\",\"tableName\":\"otel_traces\"},\"kind\":\"trace\",\"timestampValueExpression\":\"Timestamp\",\"name\":\"Traces\",\"displayedTimestampValueExpression\":\"Timestamp\",\"implicitColumnExpression\":\"SpanName\",\"serviceNameExpression\":\"ServiceName\",\"eventAttributesExpression\":\"SpanAttributes\",\"resourceAttributesExpression\":\"ResourceAttributes\",\"defaultTableSelectExpression\":\"Timestamp,ServiceName,StatusCode,round(Duration/1e6),SpanName\",\"traceIdExpression\":\"TraceId\",\"spanIdExpression\":\"SpanId\",\"durationExpression\":\"Duration\",\"durationPrecision\":9,\"parentSpanIdExpression\":\"ParentSpanId\",\"spanNameExpression\":\"SpanName\",\"spanKindExpression\":\"SpanKind\",\"statusCodeExpression\":\"StatusCode\",\"statusMessageExpression\":\"StatusMessage\",\"spanEventsValueExpression\":\"Events\",\"spanLinksValueExpression\":\"Links\",\"metadataMaterializedViews\":{\"kvRollupTable\":\"otel_traces_kv_rollup_15m\",\"granularity\":\"15 minute\"},\"connection\":\"Local ClickHouse\",\"logSourceId\":\"Logs\",\"sessionSourceId\":\"Sessions\",\"metricSourceId\":\"Metrics\"},{\"from\":{\"databaseName\":\"default\",\"tableName\":\"\"},\"kind\":\"metric\",\"timestampValueExpression\":\"TimeUnix\",\"name\":\"Metrics\",\"resourceAttributesExpression\":\"ResourceAttributes\",\"metricTables\":{\"gauge\":\"otel_metrics_gauge\",\"histogram\":\"otel_metrics_histogram\",\"sum\":\"otel_metrics_sum\",\"summary\":\"otel_metrics_summary\",\"exponential histogram\":\"otel_metrics_exponential_histogram\"},\"connection\":\"Local ClickHouse\",\"logSourceId\":\"Logs\"},{\"from\":{\"databaseName\":\"default\",\"tableName\":\"hyperdx_sessions\"},\"kind\":\"session\",\"timestampValueExpression\":\"TimestampTime\",\"name\":\"Sessions\",\"resourceAttributesExpression\":\"ResourceAttributes\",\"connection\":\"Local ClickHouse\",\"traceSourceId\":\"Traces\"}]"
    },
    {
      "key": "HYPERDX_APP_URL",
      "service": "HyperDX",
      "description": "Public URL of HyperDX (same as FRONTEND_URL)",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "HYPERDX_API_PORT",
      "service": "HyperDX",
      "description": "Port of the API inside the container (the UI proxies /api to it)",
      "secret": false,
      "strategy": "default",
      "default": "8000"
    },
    {
      "key": "HYPERDX_APP_PORT",
      "service": "HyperDX",
      "description": "Port of the web UI (public)",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "HYPERDX_LOG_LEVEL",
      "service": "HyperDX",
      "description": "Log level",
      "secret": false,
      "strategy": "default",
      "default": "info"
    },
    {
      "key": "HYPERDX_OPAMP_PORT",
      "service": "HyperDX",
      "description": "Port of the OpAMP server; the collector gets its pipeline and API keys from it over the private network",
      "secret": false,
      "strategy": "default",
      "default": "4320"
    },
    {
      "key": "DEFAULT_CONNECTIONS",
      "service": "HyperDX",
      "description": "ClickHouse connection created for the team on first start (private network)",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "HYPERDX_ADMIN_EMAIL",
      "service": "HyperDX",
      "description": "Email of the admin account, created on the first start. You log in with it",
      "secret": false,
      "strategy": "default",
      "default": "admin@example.com"
    },
    {
      "key": "USAGE_STATS_ENABLED",
      "service": "HyperDX",
      "description": "Send anonymous usage statistics to HyperDX",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "TOKEN_ENCRYPTION_KEY",
      "service": "HyperDX",
      "description": "Encrypts stored Slack and OAuth tokens (generated, 32 bytes hex)",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "EXPRESS_SESSION_SECRET",
      "service": "HyperDX",
      "description": "Session signing key (generated)",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "HYPERDX_ADMIN_PASSWORD",
      "service": "HyperDX",
      "description": "Admin password (generated). Read it here after deploy. Changing it later has no effect: change it in HyperDX",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "HYPERDX_APP_LISTEN_HOSTNAME",
      "service": "HyperDX",
      "description": "Address the web UI listens on (IPv6 and IPv4)",
      "secret": false,
      "strategy": "default",
      "default": "::"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "clickstack-243"
      }
    },
    "cli": "railway deploy --template clickstack-243",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "15cb7351-8b53-4381-adff-14eca18fbba8",
            "serializedConfig": {
              "services": {
                "25c7d489-fb08-45aa-8de7-4c4480b9c7d0": {
                  "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/clickhouse.svg",
                  "name": "ClickHouse",
                  "deploy": {
                    "startCommand": "/bin/sh -c \"printenv CLICKHOUSE_RUN_SH > /tmp/run.sh && exec sh /tmp/run.sh\"",
                    "healthcheckPath": "/ping",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 300,
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "clickhouse/clickhouse-server:26.8.36.3-alpine"
                  },
                  "variables": {
                    "PORT": {
                      "description": "ClickHouse HTTP port (healthcheck)",
                      "defaultValue": "8123"
                    },
                    "CLICKHOUSE_DB": {
                      "description": "Database for telemetry",
                      "defaultValue": "default"
                    },
                    "CLICKHOUSE_USER": {
                      "description": "ClickHouse user for HyperDX and the collector",
                      "defaultValue": "hyperdx"
                    },
                    "CLICKHOUSE_RUN_SH": {
                      "description": "Start script: small internal log tables, then the official entrypoint",
                      "defaultValue": "# ClickHouse for ClickStack on Railway: keeps ClickHouse's internal log tables\n# small, then starts the official entrypoint (which creates the user from\n# CLICKHOUSE_USER / CLICKHOUSE_PASSWORD on the first start).\n# The image listens on IPv6 and IPv4, which Railway's private network needs.\nset -eu\nrm -rf /var/lib/clickhouse/lost+found\ncat > /etc/clickhouse-server/config.d/railway.xml <<'XML'\n<clickhouse>\n    <listen_host>::</listen_host>\n    <logger><level>warning</level><console>true</console></logger>\n    <timezone>UTC</timezone>\n    <mark_cache_size>536870912</mark_cache_size>\n    <trace_log remove=\"remove\"/>\n    <text_log remove=\"remove\"/>\n    <metric_log remove=\"remove\"/>\n    <asynchronous_metric_log remove=\"remove\"/>\n    <processors_profile_log remove=\"remove\"/>\n    <query_metric_log remove=\"remove\"/>\n    <query_thread_log remove=\"remove\"/>\n    <query_views_log remove=\"remove\"/>\n    <asynchronous_insert_log remove=\"remove\"/>\n    <opentelemetry_span_log remove=\"remove\"/>\n    <session_log remove=\"remove\"/>\n    <latency_log remove=\"remove\"/>\n    <query_log replace=\"1\">\n        <database>system</database>\n        <table>query_log</table>\n        <flush_interval_milliseconds>7500</flush_interval_milliseconds>\n        <engine>ENGINE = MergeTree PARTITION BY event_date ORDER BY (event_time) TTL event_date + interval 3 day SETTINGS ttl_only_drop_parts=1</engine>\n    </query_log>\n    <part_log><ttl>event_date + INTERVAL 3 DAY DELETE</ttl></part_log>\n    <error_log><ttl>event_date + INTERVAL 7 DAY DELETE</ttl></error_log>\n</clickhouse>\nXML\nexec /entrypoint.sh\n"
                    },
                    "CLICKHOUSE_PASSWORD": {
                      "description": "ClickHouse password (generated)",
                      "defaultValue": "{{CLICKHOUSE_PASSWORD}}"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "description": "Time to shut down cleanly",
                      "defaultValue": "60"
                    },
                    "CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT": {
                      "description": "Lets the user manage access",
                      "defaultValue": "1"
                    }
                  },
                  "volumeMounts": {
                    "5dd0ee08-f307-41df-9830-9ecf041b8daa": {
                      "mountPath": "/var/lib/clickhouse"
                    }
                  }
                },
                "a8aacfac-79ba-46b2-929a-1888d94bd7fa": {
                  "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/opentelemetry.svg",
                  "name": "Collector",
                  "deploy": {
                    "healthcheckPath": "/",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 600
                  },
                  "source": {
                    "image": "hyperdx/hyperdx-otel-collector:2.43.1"
                  },
                  "variables": {
                    "PORT": {
                      "description": "Collector health check port",
                      "defaultValue": "13133"
                    },
                    "CLICKHOUSE_USER": {
                      "description": "ClickHouse user",
                      "defaultValue": "${{ClickHouse.CLICKHOUSE_USER}}"
                    },
                    "OPAMP_SERVER_URL": {
                      "description": "HyperDX OpAMP server: the collector gets its pipeline and the accepted API keys from it",
                      "defaultValue": "http://${{HyperDX.RAILWAY_PRIVATE_DOMAIN}}:${{HyperDX.HYPERDX_OPAMP_PORT}}"
                    },
                    "HYPERDX_LOG_LEVEL": {
                      "description": "Log level",
                      "defaultValue": "info"
                    },
                    "CLICKHOUSE_ENDPOINT": {
                      "description": "ClickHouse native endpoint (private network)",
                      "defaultValue": "tcp://${{ClickHouse.RAILWAY_PRIVATE_DOMAIN}}:9000?dial_timeout=10s"
                    },
                    "CLICKHOUSE_PASSWORD": {
                      "description": "ClickHouse password",
                      "defaultValue": "${{ClickHouse.CLICKHOUSE_PASSWORD}}"
                    },
                    "OTLP_PRIVATE_GRPC_ENDPOINT": {
                      "description": "OTLP/gRPC endpoint for apps in the same Railway project (API key still required)",
                      "defaultValue": "http://${{RAILWAY_PRIVATE_DOMAIN}}:4317"
                    },
                    "OTLP_PRIVATE_HTTP_ENDPOINT": {
                      "description": "OTLP/HTTP endpoint for apps in the same Railway project (API key still required)",
                      "defaultValue": "http://${{RAILWAY_PRIVATE_DOMAIN}}:4318"
                    },
                    "OTEL_EXPORTER_OTLP_ENDPOINT": {
                      "description": "Public OTLP/HTTP endpoint. Copy to your apps, with the ingestion API key from HyperDX (Team Settings) as the authorization header",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "HYPERDX_OTEL_EXPORTER_TABLES_TTL": {
                      "description": "How long telemetry is kept",
                      "defaultValue": "720h"
                    },
                    "HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE": {
                      "description": "ClickHouse database for logs, traces, metrics and sessions",
                      "defaultValue": "default"
                    },
                    "HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA": {
                      "description": "Let the exporter create the tables (as in the upstream compose file)",
                      "defaultValue": "true"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>:4318": {
                        "port": 4318
                      }
                    }
                  }
                },
                "b4911025-0044-4bdc-8779-52d090c4a948": {
                  "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/mongodb.svg",
                  "name": "MongoDB",
                  "deploy": {
                    "startCommand": "docker-entrypoint.sh mongod --ipv6 --bind_ip_all --setParameter diagnosticDataCollectionEnabled=false",
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "mongo:7.0.45"
                  },
                  "variables": {
                    "MONGO_INITDB_ROOT_PASSWORD": {
                      "description": "MongoDB root password (generated)",
                      "defaultValue": "{{MONGO_INITDB_ROOT_PASSWORD}}"
                    },
                    "MONGO_INITDB_ROOT_USERNAME": {
                      "description": "MongoDB root user",
                      "defaultValue": "hyperdx"
                    }
                  },
                  "volumeMounts": {
                    "4345ba4e-d398-444c-baac-d62c58cf92f9": {
                      "mountPath": "/data/db"
                    }
                  }
                },
                "ffc2e46a-3edc-451d-b713-294c0b5ce4ae": {
                  "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/hyperdx.svg",
                  "name": "HyperDX",
                  "deploy": {
                    "startCommand": "/bin/sh -c \"printenv HYPERDX_RUN_SH > /tmp/run.sh && exec sh /tmp/run.sh\"",
                    "healthcheckPath": "/api/health",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 600,
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "hyperdx/hyperdx:2.43.1"
                  },
                  "variables": {
                    "PORT": {
                      "description": "Port Railway routes the public domain to",
                      "defaultValue": "8080"
                    },
                    "MONGO_URI": {
                      "description": "MongoDB connection for users, dashboards, alerts and saved searches (private network)",
                      "defaultValue": "mongodb://${{MongoDB.MONGO_INITDB_ROOT_USERNAME}}:${{MongoDB.MONGO_INITDB_ROOT_PASSWORD}}@${{MongoDB.RAILWAY_PRIVATE_DOMAIN}}:27017/hyperdx?authSource=admin"
                    },
                    "FRONTEND_URL": {
                      "description": "Public URL of HyperDX. Change it when you add a custom domain",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "HYPERDX_RUN_SH": {
                      "description": "Start script: starts HyperDX and creates the admin account on the first start",
                      "defaultValue": "# HyperDX (ClickStack UI + API + OpAMP server) on Railway.\n# Starts the official entrypoint, then creates the admin account from\n# HYPERDX_ADMIN_EMAIL / HYPERDX_ADMIN_PASSWORD on the first start. HyperDX\n# allows only one team, so once the admin exists nobody else can sign up\n# (new users need an invitation). Creating the team also turns on API-key\n# authentication on the collector's OTLP endpoint.\nset -u\nsh /etc/local/entry.sh &\nMAIN=$!\nnode -e '\nconst api = \"http://127.0.0.1:\" + (process.env.HYPERDX_API_PORT || \"8000\");\nconst email = process.env.HYPERDX_ADMIN_EMAIL, password = process.env.HYPERDX_ADMIN_PASSWORD;\nconst log = (m) => console.log(\"hyperdx-setup: \" + m);\n(async () => {\n  if (!email || !password) { log(\"HYPERDX_ADMIN_EMAIL or HYPERDX_ADMIN_PASSWORD empty, skipping admin creation\"); return; }\n  for (let i = 0; i < 180; i++) {\n    try {\n      const r = await fetch(api + \"/installation\");\n      if (r.ok) {\n        const j = await r.json();\n        if (j.isTeamExisting) { log(\"team already exists, sign-up closed\"); return; }\n        const p = await fetch(api + \"/register/password\", { method: \"POST\", headers: { \"content-type\": \"application/json\" },\n          body: JSON.stringify({ email, password, confirmPassword: password }) });\n        const t = await p.text();\n        if (p.ok) { log(\"admin \" + email + \" created, sign-up closed\"); return; }\n        if (p.status === 409) { log(\"team already exists, sign-up closed\"); return; }\n        log(\"admin creation failed: \" + p.status + \" \" + t.slice(0, 200)); return;\n      }\n    } catch (e) {}\n    await new Promise((r) => setTimeout(r, 2000));\n  }\n  log(\"API did not start within 6 minutes; admin not created\");\n})();\n' &\nwait $MAIN\n"
                    },
                    "DEFAULT_SOURCES": {
                      "description": "Log, trace, metric and session sources created for the team on first start",
                      "defaultValue": "[{\"from\":{\"databaseName\":\"default\",\"tableName\":\"otel_logs\"},\"kind\":\"log\",\"timestampValueExpression\":\"Timestamp\",\"name\":\"Logs\",\"displayedTimestampValueExpression\":\"Timestamp\",\"implicitColumnExpression\":\"Body\",\"serviceNameExpression\":\"ServiceName\",\"bodyExpression\":\"Body\",\"eventAttributesExpression\":\"LogAttributes\",\"resourceAttributesExpression\":\"ResourceAttributes\",\"defaultTableSelectExpression\":\"Timestamp,ServiceName,SeverityText,Body\",\"severityTextExpression\":\"SeverityText\",\"severityNumberExpression\":\"SeverityNumber\",\"eventNameExpression\":\"EventName\",\"traceIdExpression\":\"TraceId\",\"spanIdExpression\":\"SpanId\",\"metadataMaterializedViews\":{\"kvRollupTable\":\"otel_logs_kv_rollup_15m\",\"granularity\":\"15 minute\"},\"connection\":\"Local ClickHouse\",\"traceSourceId\":\"Traces\",\"metricSourceId\":\"Metrics\"},{\"from\":{\"databaseName\":\"default\",\"tableName\":\"otel_traces\"},\"kind\":\"trace\",\"timestampValueExpression\":\"Timestamp\",\"name\":\"Traces\",\"displayedTimestampValueExpression\":\"Timestamp\",\"implicitColumnExpression\":\"SpanName\",\"serviceNameExpression\":\"ServiceName\",\"eventAttributesExpression\":\"SpanAttributes\",\"resourceAttributesExpression\":\"ResourceAttributes\",\"defaultTableSelectExpression\":\"Timestamp,ServiceName,StatusCode,round(Duration/1e6),SpanName\",\"traceIdExpression\":\"TraceId\",\"spanIdExpression\":\"SpanId\",\"durationExpression\":\"Duration\",\"durationPrecision\":9,\"parentSpanIdExpression\":\"ParentSpanId\",\"spanNameExpression\":\"SpanName\",\"spanKindExpression\":\"SpanKind\",\"statusCodeExpression\":\"StatusCode\",\"statusMessageExpression\":\"StatusMessage\",\"spanEventsValueExpression\":\"Events\",\"spanLinksValueExpression\":\"Links\",\"metadataMaterializedViews\":{\"kvRollupTable\":\"otel_traces_kv_rollup_15m\",\"granularity\":\"15 minute\"},\"connection\":\"Local ClickHouse\",\"logSourceId\":\"Logs\",\"sessionSourceId\":\"Sessions\",\"metricSourceId\":\"Metrics\"},{\"from\":{\"databaseName\":\"default\",\"tableName\":\"\"},\"kind\":\"metric\",\"timestampValueExpression\":\"TimeUnix\",\"name\":\"Metrics\",\"resourceAttributesExpression\":\"ResourceAttributes\",\"metricTables\":{\"gauge\":\"otel_metrics_gauge\",\"histogram\":\"otel_metrics_histogram\",\"sum\":\"otel_metrics_sum\",\"summary\":\"otel_metrics_summary\",\"exponential histogram\":\"otel_metrics_exponential_histogram\"},\"connection\":\"Local ClickHouse\",\"logSourceId\":\"Logs\"},{\"from\":{\"databaseName\":\"default\",\"tableName\":\"hyperdx_sessions\"},\"kind\":\"session\",\"timestampValueExpression\":\"TimestampTime\",\"name\":\"Sessions\",\"resourceAttributesExpression\":\"ResourceAttributes\",\"connection\":\"Local ClickHouse\",\"traceSourceId\":\"Traces\"}]"
                    },
                    "HYPERDX_APP_URL": {
                      "description": "Public URL of HyperDX (same as FRONTEND_URL)",
                      "defaultValue": "${{FRONTEND_URL}}"
                    },
                    "HYPERDX_API_PORT": {
                      "description": "Port of the API inside the container (the UI proxies /api to it)",
                      "defaultValue": "8000"
                    },
                    "HYPERDX_APP_PORT": {
                      "description": "Port of the web UI (public)",
                      "defaultValue": "8080"
                    },
                    "HYPERDX_LOG_LEVEL": {
                      "description": "Log level",
                      "defaultValue": "info"
                    },
                    "HYPERDX_OPAMP_PORT": {
                      "description": "Port of the OpAMP server; the collector gets its pipeline and API keys from it over the private network",
                      "defaultValue": "4320"
                    },
                    "DEFAULT_CONNECTIONS": {
                      "description": "ClickHouse connection created for the team on first start (private network)",
                      "defaultValue": "[{\"name\":\"Local ClickHouse\",\"host\":\"http://${{ClickHouse.RAILWAY_PRIVATE_DOMAIN}}:8123\",\"username\":\"${{ClickHouse.CLICKHOUSE_USER}}\",\"password\":\"${{ClickHouse.CLICKHOUSE_PASSWORD}}\"}]"
                    },
                    "HYPERDX_ADMIN_EMAIL": {
                      "description": "Email of the admin account, created on the first start. You log in with it",
                      "defaultValue": "admin@example.com"
                    },
                    "USAGE_STATS_ENABLED": {
                      "description": "Send anonymous usage statistics to HyperDX",
                      "defaultValue": "false"
                    },
                    "TOKEN_ENCRYPTION_KEY": {
                      "description": "Encrypts stored Slack and OAuth tokens (generated, 32 bytes hex)",
                      "defaultValue": "{{TOKEN_ENCRYPTION_KEY}}"
                    },
                    "EXPRESS_SESSION_SECRET": {
                      "description": "Session signing key (generated)",
                      "defaultValue": "{{EXPRESS_SESSION_SECRET}}"
                    },
                    "HYPERDX_ADMIN_PASSWORD": {
                      "description": "Admin password (generated). Read it here after deploy. Changing it later has no effect: change it in HyperDX",
                      "defaultValue": "{{HYPERDX_ADMIN_PASSWORD}}"
                    },
                    "HYPERDX_APP_LISTEN_HOSTNAME": {
                      "description": "Address the web UI listens on (IPv6 and IPv4)",
                      "defaultValue": "::"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>": {}
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {
    "healthcheck": {
      "service": "Collector",
      "method": "GET",
      "path": "/",
      "expect_status": 200
    }
  },
  "resources": {
    "expected_services": 4,
    "needs_volume": true
  },
  "generated_at": "2026-11-08T22:15:11.842Z",
  "generator_version": "0.1.0"
}
