How to Deploy Tempo – Distributed Tracing Backend
How to Deploy Tempo – Distributed Tracing Backend
Deploy Tempo with Docker Compose and Traefik for secure, persistent distributed tracing.

Tempo is an open-source distributed tracing backend that stores and queries traces from your applications. It integrates seamlessly with distributed systems to help you understand request flows, identify performance bottlenecks, and troubleshoot issues across microservices architectures. Tempo requires only object storage and is designed for cost-efficient, high-volume trace data.
In this article, you will deploy Tempo using Docker Compose, configure persistent storage for trace data, and set up Traefik as a reverse proxy to securely access your Tempo instance.
Prerequisites
Before you begin, you need to:
- Have access to an Ubuntu 24.04-based server as a non-root user with
sudoprivileges. - Install Docker and Docker Compose.
- Configure a domain A record pointing to your server’s IP address (for example,
tempo.example.com).
Set Up the Directory Structure and Environment Variables
In this section, you prepare the required directory structure for Tempo and define environment variables in a .env file.
- Create the directory structure for Tempo.
console
$ mkdir -p ~/tempo-tracing/{tempo-data,tempo-config}
These directories store Tempo’s trace blocks and configuration files.
- Navigate into the
tempo-tracingdirectory.console$ cd ~/tempo-tracing
- Set proper ownership for the Tempo data directory. Tempo runs as the
tempouser (UID 10001) inside the container.console$ sudo chown -R 10001:10001 tempo-data
- Create a
.envfile.console$ nano .envAdd the following variables:
iniDOMAIN=tempo.example.com LETSENCRYPT_EMAIL=admin@example.com
Replace:
tempo.example.comwith your domain.admin@example.comwith your email.
Save and close the file.
- Create a Tempo configuration file.
console
$ nano tempo-config/tempo-config.yaml - Add the following content.
yaml
server: http_listen_port: 3200 distributor: receivers: jaeger: protocols: thrift_http: grpc: otlp: protocols: http: grpc: storage: trace: backend: local local: path: /var/tempo/traces wal: path: /var/tempo/wal compactor: compaction: block_retention: 168h
Save and close the file.
This configuration enables trace ingestion via Jaeger and OpenTelemetry protocols, configures local filesystem storage for trace data, and sets a 7-day retention period. The distributor accepts traces in multiple formats while the storage backend persists them to the mounted data directory.
Deploy with Docker Compose
In this section, you create and deploy the Docker Compose stack that runs Tempo behind Traefik. Docker Compose manages both containers, applies the environment variables from your .env file, and automatically configures HTTPS routing through Traefik.
- Create a new Docker Compose manifest.
console
$ nano docker-compose.yaml - Add the following content.
yaml
services: traefik: image: traefik:v3.6 container_name: traefik command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" - "--certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" volumes: - "letsencrypt:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock:ro" restart: unless-stopped tempo: image: grafana/tempo:latest container_name: tempo hostname: tempo expose: - "3200" - "4317" - "4318" - "14250" - "14268" volumes: - "./tempo-config/tempo-config.yaml:/etc/tempo/tempo.yaml" - "./tempo-data:/var/tempo" command: -config.file=/etc/tempo/tempo.yaml labels: - "traefik.enable=true" - "traefik.http.routers.tempo.rule=Host(`${DOMAIN}`)" - "traefik.http.routers.tempo.entrypoints=websecure" - "traefik.http.routers.tempo.tls.certresolver=letsencrypt" - "traefik.http.services.tempo.loadbalancer.server.port=3200" restart: unless-stopped volumes: letsencrypt:
Save and close the file.
Key components in this configuration:
- services: Two cooperating containers implement the tracing backend:
- traefik: Handles HTTP/HTTPS traffic, automatically obtains Let’s Encrypt certificates, and proxies requests to Tempo.
- tempo: Collects trace spans, archives them for querying, and exposes APIs for retrieval.
- image: Container registries on Docker Hub supply the official images.
- container_name: Static naming facilitates service identification during debugging and administrative operations.
- command (Traefik): Establishes behavior including Docker integration, port configuration (80/443), protocol enforcement (HTTPS), and automated Let’s Encrypt certificate requests via HTTP validation.
- command (Tempo): Identifies the configuration file path for service initialization.
- ports (Traefik): Binds host ports 80 and 443 for client connectivity.
- expose (Tempo): Makes multiple ports accessible within the container network without public exposure. Port 3200 handles HTTP queries, while ports 4317, 4318, 14250, and 14268 receive trace data from different protocol implementations.
- volumes:
- File system mounts ensure configuration and trace storage persists beyond container lifecycles.
- Certificate information survives container recreation through the
letsencryptnamed volume. - Traefik accesses Docker’s control socket to perform automatic service detection and routing updates.
- labels (Tempo): Traefik routing metadata that enables proxy behavior, associates domain names with backends, designates the TLS provider, and specifies port 3200 for load balancing.
- restart: unless-stopped: Maintains service continuity by auto-restarting containers following failures or reboots, except when manually terminated.
- services: Two cooperating containers implement the tracing backend:
- Create and start the services.
console
$ docker compose up -d - Verify that the services are running.
console
$ docker compose psOutput:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS tempo grafana/tempo:latest "/tempo -config.file…" tempo 18 seconds ago Up 17 seconds 3200/tcp, 4317/tcp, 4318/tcp, 14250/tcp, 14268/tcp traefik traefik:v3.6 "/entrypoint.sh --pr…" traefik 18 seconds ago Up 17 seconds 0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:443->443/tcp, [::]:443->443/tcpBoth containers are running successfully. Tempo is ready to accept trace data while Traefik accepts connections on ports
80and443. - View the logs of the services.
console
$ docker compose logsFor more information on managing a Docker Compose stack, see the How To Use Docker Compose article.
Access Tempo
In this section, you access the Tempo API to verify your installation by checking service readiness and querying available trace endpoints.
- Check the service readiness endpoint.
console
$ curl https://tempo.example.com/readyOutput:
readyThis confirms Tempo is operational and accepting requests.
- Query the service status to view configuration details.
console
$ curl https://tempo.example.com/statusOutput displays Tempo’s current configuration, including enabled modules, storage backend, and ingestion settings. This endpoint is useful for verifying your deployment configuration.
- Check the build information to verify the Tempo version.
console
$ curl https://tempo.example.com/api/status/buildinfoOutput:
{"version":"v2.9.0","revision":"032d47627","branch":"main","buildUser":"","buildDate":"","goVersion":"go1.25.1"}This confirms Tempo is responding correctly to API requests and displays version information for troubleshooting purposes.
Conclusion
You have successfully deployed Tempo for distributed tracing with HTTPS encryption. The Docker Compose architecture delivers both the tracing backend and reverse proxy with filesystem persistence ensuring trace data durability. Let’s Encrypt automation maintains valid certificates while Traefik performs intelligent traffic management. Tempo now stands ready to accept distributed trace spans from microservices using Jaeger, OpenTelemetry, or alternative instrumentation frameworks through its protocol-agnostic ingestion APIs.