Skip to content

Configuration reference

A collector runs one of two runtimes — Grafana Alloy (config via remotecfg) or otelcol-contrib (config via OpAMP) — and each leaves a different set of files on the host. The optional linkmesh-agent onboarding helper, when present, leaves its own files too. This page lists every location that matters — what owns it, when to touch it, and when to leave it alone. The server’s own storage and database configuration is further down.

Source-of-truth model

Read this once before editing anything.

┌────────────────────────────┐
│ LinkMesh server │
Operator edits ────► │ (UI / API / git-backed │
│ config store) │
└────────────┬────────────────┘
│ remotecfg poll (Alloy)
│ OpAMP push (otelcol-contrib)
┌────────────────────────────┐
│ Collector runtime │
│ (upstream Alloy or │
│ upstream otelcol-contrib) │
└────────────────────────────┘

The collector fetches its config directly from the server — over Alloy’s remotecfg (Connect-RPC) or otelcol’s OpAMP (WebSocket). The collector process itself is self-managed: Alloy applies the config it pulls via remotecfg, and otelcol-contrib is supervised by opampsupervisor. The optional LinkMesh agent, when present, does service / log-source discovery and reports host context for onboarding; it does not install, supervise, or configure the collector and is not in the config path. See Native remote config for the framing.

Rule of thumb:

File / surfaceOwned bySurvives apt upgrade?Survives server config push?
/etc/linkmesh/config.yaml (optional agent, VM)Operator / enrollment scriptyes (config|noreplace)yes — the server never rewrites it
/etc/alloy/config.alloy (bootstrap)Operator (Alloy runtime)yesyes — the pipeline arrives via remotecfg, not this file
/etc/otelcol-contrib/config.yaml (bootstrap)Operator (otelcol + OpAMP runtime)yesyes — the pipeline arrives via OpAMP, not this file

If you edited a pipeline component on the host and your change vanished from the topology, you edited the wrong layer — bootstrap files on disk only carry the connection back to the server. The real pipeline lives in the LinkMesh UI and is delivered to the collector at runtime; it is not persisted to disk by default.

/etc/linkmesh/config.yaml — agent config (optional onboarding agent)

The agent’s config file. On a VM (.deb / .rpm) it lives at /etc/linkmesh/config.yaml — the systemd unit runs linkmesh-agent --config /etc/linkmesh/config.yaml. In a container / the Kubernetes DaemonSet it is mounted at /etc/linkmesh-agent/config.yaml. The --config flag is required; there is no built-in default path.

A minimal config is just the server URL and the enrollment token:

server:
url: https://your-server.example.com # HTTPS base URL; the control channel is
# a WebSocket at /v1/agent
token: <enrollment-token> # Bearer credential, sent on the WS upgrade

The agent connects outbound over HTTPS/WSS — there is no inbound port and no mTLS client certificate. Its identity is bound server-side from the enrollment token; see Enrollment tokens.

Full config surface

Block / keyTypeDefaultNotes
server.urlstringrequiredHTTPS base URL, e.g. https://app.linkmesh.io. A legacy grpcs://…:50051 value is accepted and normalised to the WSS /v1/agent endpoint.
server.tokenstringEnrollment token, sent as a Bearer credential on the WebSocket upgrade.
agent.idstringderivedOptional stable agent identifier.
agent.environmentstringproductionFree-form environment label.
certificates.caCertPathstringsystem trust storeOptional CA bundle used to verify the server’s TLS certificate.
certificates.insecureSkipVerifyboolfalseLab-only; skips server-cert verification (see the aside below).
collector.binaryPath / configPath / serviceName / collectorTypestringauto-detectedThe managed collector. Unset → the agent detects an installed Alloy / otelcol-contrib.
collector.nativeRemoteConfigbool (nullable)alloytrue, else falseWhen true, the collector self-manages its config (Alloy remotecfg / OpAMP) and the agent does not deliver config. An explicit value wins over the per-type default. See Native remote config.
collector.metricsUrlstringalloy:12345/metrics, else :8888/metricsLiveness-probe endpoint only.
collectors[]listMulti-collector form; supersedes the single collector block when set. Each entry needs a unique name (derived from serviceName or position if left blank).
logging.levelstringinfodebug / info / warn / error.
logging.filestringOptional log file; default is journald / stdout only.
customFingerprints[]listOperator-defined service-detection matchers + pipeline templates (extends detect).

Log browsing (browse)

The agent can list directories and sample files on the host so the onboarding UI can preview logs. It’s on by default and log-scoped; every key is optional.

KeyTypeDefaultNotes
browse.enabledbooltrueMaster switch. Set false to refuse all directory listing / file sampling on this host — the UI then shows “log browsing is disabled by agent configuration”.
browse.allowedRootslist/var/log, /var/lib/docker/containers, /optDirectory prefixes the agent may browse. The sentinel "*" (or "/") grants full-filesystem scope — see the warning below.
browse.denyPatternslistkeys/certs (*.key, *.pem, id_rsa*), *shadow*, .ssh, /proc/*, /sys/*, /etc/shadowGlobs that are never browsable, even inside an allowed root. Always enforced.
browse.maxDirEntriesint1000Cap on entries returned per directory listing.
browse.maxSampleLinesint200Cap on lines returned when sampling a file in line mode.
browse.maxSampleBytesint262144 (256 KiB)Cap on bytes returned when sampling a file in byte mode.

/etc/alloy/config.alloy — Alloy bootstrap

Used by the Alloy runtime. The operator writes it once when installing the collector: a remotecfg block pointing at the LinkMesh server plus an optional own_metrics push for the topology canvas. See Onboard Grafana Alloy via remotecfg for the full template.

Key fields:

FieldNotes
remotecfg.urlServer base URL (e.g. https://linkmesh.example.com). Alloy appends the CollectorService path itself — do not add /v1/opamp here (that’s OpAMP, a different protocol).
remotecfg.idStable identifier for this collector. constants.hostname is fine for most fleets.
remotecfg.bearer_tokenPer-collector OTLP token minted in the LinkMesh UI (or via POST /api/v1/collectors/{id}/otlp-token). Bearer scheme only — basic_auth is rejected.
otelcol.exporter.otlphttp.linkmesh Authorization headerSame token as bearer_token, used by own_metrics push to /v1/metrics.

The pipeline itself (sources, processors, exporters) does not live here. Alloy fetches it via remotecfg on every poll and merges it into the runtime config in memory.

/etc/otelcol-contrib/config.yaml — otelcol bootstrap (otelcol + OpAMP runtime)

Bootstrap config for the upstream OpenTelemetry Collector when onboarding it via OpAMP. The collector starts with a nop pipeline; LinkMesh replaces it with the real pipeline over OpAMP within seconds of the first handshake. See Onboard otelcol-contrib via OpAMP for the full template.

Key fields:

FieldNotes
extensions.opamp.server.ws.endpointwss://<server>/v1/opamp — same host/port as the web UI, only the path differs. Use wss:// over any network; ws:// for loopback only.
extensions.opamp.server.ws.headers.AuthorizationBearer <ENROLLMENT_TOKEN>. Single-use enrollment token minted in the UI.
extensions.opamp.capabilitiesOnly reports_effective_config and reports_health. Adding other capability keys makes otelcol-contrib refuse to start with “invalid keys”.

Like Alloy’s bootstrap, the pipeline is delivered at runtime — the YAML on disk only carries the OpAMP wiring.

systemd units

linkmesh-agent.service (optional onboarding agent)

[Unit]
Description=LinkMesh Agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/linkmesh-agent --config /etc/linkmesh/config.yaml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target

The agent does not depend on the collector’s unit, and the collector does not depend on the agent’s. The agent runs independently so it can do discovery and report host context for onboarding.

alloy.service (upstream Grafana package)

Installed by apt install alloy / dnf install alloy from the upstream Grafana package. The unit ships with the package; LinkMesh does not template it. Reads /etc/alloy/config.alloy.

Terminal window
sudo systemctl status alloy
sudo journalctl -u alloy -f

otelcol-contrib.service (upstream OTel release)

Installed by the upstream .deb / .rpm from the OpenTelemetry release. Reads /etc/otelcol-contrib/config.yaml.

Terminal window
sudo systemctl status otelcol-contrib
sudo journalctl -u otelcol-contrib -f

File locations cheat-sheet

PathContentsNotes
/usr/local/bin/linkmesh-agentAgent binary (optional onboarding agent)Installed by the .deb / .rpm
/etc/linkmesh/config.yamlAgent config (VM)server.url + server.token; container path is /etc/linkmesh-agent/config.yaml
/etc/alloy/config.alloyAlloy bootstrap (remotecfg + own_metrics)Pipeline arrives via remotecfg, not from this file
/etc/otelcol-contrib/config.yamlotelcol bootstrap (OpAMP)Pipeline arrives via OpAMP, not from this file
journalctl -u linkmesh-agentAgent logsNo flat-file logs by design
journalctl -u alloyAlloy logsIncludes remotecfg poll lines
journalctl -u otelcol-contribotelcol logsIncludes OpAMP handshake lines

LinkMesh server — public base URL (externalUrl)

Everything above is the agent / collector host. The rest of this page is the server’s own config, read from /etc/linkmesh/config.yaml on the host running linkmesh-server (or from environment variables).

externalUrl is the first key to set on a new install — see Quickstart step 2 for the walkthrough.

KeyTypeDefaultNotes
externalUrlstring (URL)(empty)The public base URL collectors and browsers reach this server on, e.g. https://linkmesh.example.com. No trailing path. Environment: LINKMESH_EXTERNALURL, or the shorter alias EXTERNAL_URL.

What reads it:

  • Collector self-telemetry (OpAMP). The server hands this URL to each OpAMP collector as the endpoint for its own_metrics push. This is what produces per-component throughput, CPU, memory and uptime on the topology canvas and collector detail pages.
  • User invites and password resets. Both mail a link back into this install and use externalUrl as its base.
  • Enrollment scripts and download URLs shown in the UI.
  • CORS. When security.cors.allowedOrigins is empty, externalUrl becomes the single allowed cross-origin. (The bundled UI is served same-origin, so this only affects external API callers.)
externalUrl: "https://linkmesh.example.com"

LinkMesh server — storage & database

This section controls where the server keeps its operational state. See Storage backends for the concepts and Deploy with MongoDB for setup.

storage

KeyTypeDefaultNotes
storage.backendbolt / mongodbboltEmbedded BoltDB database (default, single instance) or external MongoDB (required for high availability).
storage.boltPathpath/data/linkmesh/state.dbWhere the embedded BoltDB file lives. Ignored when backend is mongodb.
storage.auditLogRetentionDaysint365How long audit-log entries survive before the backend prunes them. Applies to both backends; 0 means the 365-day default.

database — only when storage.backend: mongodb

Set database.uri directly, or set the parts and let the server build the connection string. uri wins if both are present.

KeyTypeDefaultNotes
database.uriconnection string(none)Full MongoDB URI. Preferred for mongodb+srv:// (Atlas-style) strings.
database.serverhost or host:port(none)Used to build the URI when uri is unset. A bare hostname builds a mongodb+srv:// URI; host:port builds a plain mongodb:// one.
database.userstring(none)Username, folded into the built URI.
database.passwordstring(none)Password, folded into the built URI. Inject via env rather than committing it.
database.databasestringsignalflowDatabase name. The default keeps the legacy name; set linkmesh on a fresh install.

Embedded default — nothing to set:

storage:
backend: bolt

External MongoDB via a single URI:

storage:
backend: mongodb
database:
uri: "mongodb+srv://linkmesh-app:CHANGEME@cluster.example.mongodb.net/linkmesh?retryWrites=true&w=majority"

External MongoDB from parts (password injected via env):

storage:
backend: mongodb
database:
server: cluster.example.mongodb.net
user: linkmesh-app
database: linkmesh

Environment overrides

Every key takes a LINKMESH_-prefixed environment variable, with dots flattened to underscores and the name upper-cased — handy for containers and secret injection. A few database keys also accept shorter aliases:

Config keyEnvironment variable
storage.backendLINKMESH_STORAGE_BACKEND
storage.boltPathLINKMESH_STORAGE_BOLTPATH
storage.auditLogRetentionDaysLINKMESH_STORAGE_AUDITLOGRETENTIONDAYS
database.uriLINKMESH_DATABASE_URI — aliases DATABASE_URI, MONGODB_URI
database.serverLINKMESH_DATABASE_SERVER — alias MONGODB_SERVER
database.userLINKMESH_DATABASE_USER — alias MONGODB_USER
database.passwordLINKMESH_DATABASE_PASSWORD — alias MONGODB_PASSWORD

When in doubt

The LinkMesh UI is the canonical place to change pipeline / source / destination / route config. Bootstrap files on disk (config.alloy, otelcol-contrib config.yaml) only carry the connection back to the server — edits to pipeline-shaped blocks there will be overridden as soon as remotecfg or OpAMP delivers the real config on the next poll/push.