---
title: "Send OpenTelemetry from Docker Compose to your Mac"
description: "A container cannot reach 127.0.0.1 on the host. Point OTEL_EXPORTER_OTLP_ENDPOINT at host.docker.internal and read your container's telemetry in one window."
source: "https://getloggerhead.com/docs/send-telemetry/docker-compose/"
---

# Send OpenTelemetry from Docker Compose to your Mac

> A container cannot reach 127.0.0.1 on the host. Point OTEL_EXPORTER_OTLP_ENDPOINT at host.docker.internal and read your container's telemetry in one window.

Your app already sends OpenTelemetry, and now it runs in a container. One address changes.

## The one thing to change

Inside a container, `127.0.0.1` is the container. The Mac is `host.docker.internal`, which Docker Desktop and OrbStack both provide.

```yaml title="compose.yaml"
services:
  api:
    build: .
    environment:
      OTEL_SERVICE_NAME: my-api
      OTEL_EXPORTER_OTLP_ENDPOINT: http://host.docker.internal:4318
      OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
```

Confirm the port first. Open **Collectors → Loggerhead receiver → Connection** and copy the HTTP port. A Docker port forward often holds 4318 itself, and the receiver then moves along the ladder to 14318. See [Ports and the effective port](/docs/getting-started/ports-and-the-effective-port/).

:::caution[Linux hosts]
`host.docker.internal` is not automatic on a Linux engine. Add it yourself:

```yaml
    extra_hosts:
      - "host.docker.internal:host-gateway"
```
:::

## Many services at once

Set the shared variables once and let every service read them:

```yaml title="compose.yaml"
x-otel: &otel
  OTEL_EXPORTER_OTLP_ENDPOINT: http://host.docker.internal:4318
  OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf

services:
  api:
    environment:
      <<: *otel
      OTEL_SERVICE_NAME: api
  worker:
    environment:
      <<: *otel
      OTEL_SERVICE_NAME: worker
```

Each service keeps its own `OTEL_SERVICE_NAME`, so Loggerhead colours them apart.

## Tag the environment

A record with no tag lands in the Local environment. To send a deployment somewhere else, name an environment that the workspace has:

```yaml
  OTEL_RESOURCE_ATTRIBUTES: deployment.environment.name=staging
```

See [Workspaces and environments](/docs/getting-started/workspaces-and-environments/).

## Or send through one branch collector

A branch collector in the same Compose file gives you one place to drop noisy records and one identity for the whole stack. The app then points at the branch instead of the Mac. See [Docker branch example](/docs/collectors/docker-branch-example/).

## Then read it with your agent

1. Run `docker compose up` and call one endpoint. Open **Logs** in Loggerhead.
2. Connect your coding agent once, and it reads the same data. See [Claude Code](/docs/connect-your-ai-tool/claude-code/).
