Docs

Connect a source inside your network.

The Perfloop relay is a small program you run inside your network for telemetry and private code hosts. It opens outbound connections to Perfloop and collects nothing. For telemetry: It reads Prometheus® and VictoriaMetrics for metrics, Loki for logs, and Go pprof for live profiles of Go processes.

The relay is open source under the Apache License 2.0 at github.com/perfloop/relay. The image Perfloop publishes is built from that repository, so you can read what runs in your network.

Access you need

Setup

For a telemetry relay on Kubernetes®, docs/setup.md in the repository gives a checkpoint after each step and a table of what each failure means.

1 · choose the image

On the machine that runs the relay, install Docker Engine with its buildx plugin, and cosign from Sigstore. The commands below use both.

The repository's Image workflow publishes ghcr.io/perfloop/relay tagged with the commit it built, on each push to main. Pick the commit of the latest successful Image run on main, listed under Actions in the repository. Replace <full-commit-sha> in both commands below with that same 40-character commit SHA, and resolve its digest.

docker buildx imagetools inspect ghcr.io/perfloop/relay:<full-commit-sha> \
  --format '{{.Manifest.Digest}}'

Run the image by that digest, as ghcr.io/perfloop/relay@<digest>. Each digest is signed with keyless cosign by the workflow that built it. Verify the signature before you run the image.

cosign verify \
  --certificate-identity https://github.com/perfloop/relay/.github/workflows/image.yml@refs/heads/main \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-sha <full-commit-sha> \
  ghcr.io/perfloop/relay@<digest>

Each image carries an SPDX® SBOM attestation. To compare the binary with your own build of the same commit, see docs/image.md.

2 · create the relay token

In Perfloop Setup, in Model inputs, find Relay tokens under Telemetry. With telemetry off, Relay tokens is in its own Relay section. Press Add relay token, enter a token name and press Create relay token. Copy the token now; Perfloop shows it once. Hold it in your shell's environment, never in a file or on a command line that shell history records.

read -rs PERFLOOP_RELAY_TOKEN && export PERFLOOP_RELAY_TOKEN   # paste the token, then Enter
read -rs VM_READ_TOKEN && export VM_READ_TOKEN                  # the provider's read token, if it needs one

3 · write the configuration

Name each upstream with one lowercase label, its provider kind (the provider name in lowercase, as in the example), its URL inside your network, and the headers it needs. A value written as ${NAME} is read from the environment when the relay starts.

api: https://app.perfloop.ai
token: ${PERFLOOP_RELAY_TOKEN}
upstreams:
  - name: vm
    kind: victoriametrics
    url: http://vmselect.monitoring.svc:8481/select/0/prometheus
    headers:
      Authorization: Bearer ${VM_READ_TOKEN}
  - name: logs
    kind: loki
    url: http://loki-gateway.monitoring.svc
    headers:
      X-Scope-OrgID: <loki tenant>

A provider path prefix, such as a VictoriaMetrics tenant path, belongs in the upstream URL. For a multi-tenant Loki, set X-Scope-OrgID in the upstream headers, as above; Setup takes no tenant for a relay source. Leave the headers block out for an upstream that needs none. Every field is in docs/configuration.md.

Before you run the relay, print every request this file lets it forward. Placeholder values are enough for the secrets here.

docker run --rm -v "$PWD/relay.yaml:/etc/perfloop-relay/relay.yaml:ro" \
  -e PERFLOOP_RELAY_TOKEN=placeholder -e VM_READ_TOKEN=placeholder \
  ghcr.io/perfloop/relay@<digest> -print-routes

Go processes that expose net/http/pprof are an upstream of kind pprof. It has no URL; it lists targets, one lowercase label naming each process and the http(s) base its handler is served from, and Perfloop names one target per read. This upstream, on its own, is a complete configuration:

api: https://app.perfloop.ai
token: ${PERFLOOP_RELAY_TOKEN}
upstreams:
  - name: go
    kind: pprof
    targets:
      api-1: http://api-1.prod.svc:6060
      worker-1: http://worker-1.prod.svc:6060
    # Optional. The longest CPU profile a read may ask for, in seconds:
    # default 30, at most 45.
    max_seconds: 30
    # Optional. Profile reads in flight across these targets, in this relay
    # process: default 1, at most 8.
    max_concurrent: 1

The relay forwards only GET requests to /debug/pprof/profile, heap, allocs, goroutine, mutex, and block.

Private code hosts

For a private GitLab server or GitHub Enterprise Server, add an upstream of kind codehost. Its URL must be an HTTPS origin, with no path, query or credentials. Include a non-default port when the server needs one.

api: https://app.perfloop.ai
token: ${PERFLOOP_RELAY_TOKEN}
upstreams:
  - name: git
    kind: codehost
    url: https://git.example.com

Set no headers or ca on this upstream. When you connect the code host, enter the same instance URL, the relay name git and any public root CA certificates, as Connect GitLab or Connect GitHub Enterprise Server describes. Perfloop checks the server's certificate and hostname. The relay carries end-to-end encrypted traffic and cannot read the code-host credential. This connection carries code reads, branch pushes and pull-request or merge-request operations for selected repos; the telemetry GET-only rule does not apply to it.

4 · run it

Run the image with the configuration mounted at /etc/perfloop-relay/relay.yaml and each secret the file names passed from the variables you set in step 2. The image is built for linux/amd64. It needs outbound access to app.perfloop.ai on 443 and to your upstreams. Nothing needs to reach it.

docker run -d --name perfloop-relay \
  -v "$PWD/relay.yaml:/etc/perfloop-relay/relay.yaml:ro" \
  -e PERFLOOP_RELAY_TOKEN -e VM_READ_TOKEN \
  ghcr.io/perfloop/relay@<digest> \
  && unset PERFLOOP_RELAY_TOKEN VM_READ_TOKEN   # once the container holds them

On Kubernetes, start from examples/kubernetes/relay.yaml: a Deployment and the shape of its Secret, with a NetworkPolicy that allows egress to DNS, to the named upstream, and to public addresses on port 443, nothing else. To confine that last rule to Perfloop's host, use an egress gateway or a policy that understands host names.

The log line tunnel open means the relay is connected. More than one relay can run for your workspace. Each relay can carry its own upstreams. Perfloop tries your connected relays in turn until one serves the read's upstream, and for a pprof read, its target. A relay without that upstream or target refuses the read before it contacts anything, but it still receives the read: the upstream name and the query and its time window, or for a profile, the target name, the profile type and the window. A read made by a Session also carries its read ID. Upstream and target names are shared across all relays of your workspace, so give different sources different names, and use one name on two relays only for the same source.

5 · connect the source in Setup

For telemetry in Perfloop Setup, choose the provider and enter relay://vm as the endpoint, with the upstream name you chose. Leave Authorization empty, and for Loki leave Tenant empty too. Register the label selectors as for any other connection. Perfloop checks each selector before it saves the connection.

For Go processes, choose Go pprof, enter relay://go as the endpoint, and register one target name per selector: api-1 and worker-1 here. One connection holds at most eight targets; register further processes as another connection to the same upstream. An Admin's coding agent can also connect a Go pprof source through the Perfloop MCP server, because it needs no token.

Telemetry data that crosses

Every telemetry read starts at Perfloop. The relay can only answer a read; it never starts a request into Perfloop.

The relay does not scan responses for credentials. If a provider or a gateway in front of it writes a request header into a response, that value reaches Perfloop. Give each telemetry upstream a read-only credential.

For telemetry, the relay forwards only GET requests to the read routes of the provider kind you configured. It refuses admin and write routes. It logs one line per read. The route table is in docs/security.md.

While no relay of yours is connected, a read fails with the source reported unavailable.

Repo access

Work on any repo in the workspace can query the scopes and pprof targets of every telemetry connection in the workspace. Keep telemetry that some repos must not read in a separate workspace.

Change or remove access

The relay reads its configuration once, when it starts. After you change the file or a secret it names, start every relay that uses it again with the new values and check each log for tunnel open. On Docker, remove the container and run it again; a restart keeps the old environment. On Kubernetes, scale the Deployment to zero and back; a ConfigMap or Secret change starts no rollout by itself.

To stop all relay traffic, stop every relay of your workspace. To stop reads of one telemetry provider while the relay keeps running, revoke that provider's credential in your network, or remove its upstream from the configuration and start every relay that carries it again.

For a code host, disconnect it in Perfloop Setup and revoke its bot token at the code host. Remove its upstream and start every relay that carries it again to remove the network route too.

Revoke a relay token in Setup, in Relay tokens. A revoked token cannot open a new tunnel, and Perfloop ends the tunnels already open with it within 40 seconds. To rotate a token, create the new one, start the relays again with it, then revoke the old one.

Removing access does not delete connection details or results already stored in Perfloop.

Security questions: security@perfloop.ai