Skip to Content

How to Deploy Netdata with Docker Compose and Cloudflare Tunnel

Build a secure, internet-accessible monitoring stack without opening inbound ports

When teams move fast, infrastructure monitoring often gets deferred until the first outage. A common pattern is that dashboards exist internally, but nobody can safely access them when they are off-network or on-call from outside the office VPN. In this guide, we deploy Netdata with Docker Compose and expose it securely through a Cloudflare Tunnel, so you get real-time visibility without opening inbound firewall ports.

This approach works well for startups and growing engineering teams that need practical observability now, not after a six-month platform project. You will set up a production-oriented baseline: persistent configuration, controlled secrets, health checks, explicit verification, and failure-mode troubleshooting. The result is a secure monitoring endpoint you can share with authenticated operators while keeping your origin private.

Architecture and flow overview

The deployment has three layers. First, Netdata runs as a container and collects host and container metrics. Second, Cloudflared runs as a sidecar tunnel client that creates an outbound-only connection to Cloudflare Edge. Third, Cloudflare Access policies enforce identity checks before users can reach the monitoring URL.

  • No inbound ports are exposed on your public interface.
  • Outbound-only tunnel keeps the origin hidden.
  • Identity-aware access protects dashboards from anonymous traffic.
  • Composable operations: update tunnel config and Netdata independently.

Prerequisites

  • A Linux host (Ubuntu 22.04+ recommended) with Docker Engine and Docker Compose plugin.
  • A Cloudflare account with a domain managed in Cloudflare DNS.
  • Ability to create a Cloudflare Tunnel token from Zero Trust dashboard.
  • Basic shell access with sudo privileges.
  • A dedicated directory for infrastructure configs (for example /opt/netdata-stack).

Step 1: Prepare host directories and least-privilege layout

Create a deterministic filesystem layout before writing Compose files. Keeping runtime, cache, and config paths explicit makes upgrades safer and helps incident responders reason about state quickly.

sudo mkdir -p /opt/netdata-stack/{netdata-config,netdata-lib,netdata-cache,cloudflared}
sudo chown -R $USER:$USER /opt/netdata-stack
cd /opt/netdata-stack

If the copy button does not work in your browser, select the code block manually and copy it.

For teams using configuration management, mirror this path in Ansible or Terraform local-exec so every environment uses identical conventions. Consistent paths reduce drift between staging and production.

Step 2: Create Docker Compose stack

Use a pinned image strategy in production. Avoid broad tags when possible; pin to tested versions and rotate intentionally during maintenance windows.

version: "3.9"
services:
  netdata:
    image: netdata/netdata:v1.45.3
    container_name: netdata
    restart: unless-stopped
    cap_add:
      - SYS_PTRACE
    security_opt:
      - apparmor:unconfined
    ports: []
    volumes:
      - ./netdata-config:/etc/netdata
      - ./netdata-lib:/var/lib/netdata
      - ./netdata-cache:/var/cache/netdata
      - /etc/passwd:/host/etc/passwd:ro
      - /etc/group:/host/etc/group:ro
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /etc/os-release:/host/etc/os-release:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - DO_NOT_TRACK=1

  cloudflared:
    image: cloudflare/cloudflared:2026.4.0
    container_name: cloudflared-netdata
    restart: unless-stopped
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=${TUNNEL_TOKEN}
    depends_on:
      - netdata

If the copy button does not work in your browser, select the code block manually and copy it.

Notice that no public port is published. Netdata remains private to the Docker network, and cloudflared handles secure egress to Cloudflare.

Step 3: Store tunnel secret safely

Never hardcode tunnel tokens in Git or inline Compose files committed to source control. Use an external secret store where possible. At minimum, use an untracked environment file with strict permissions.

cd /opt/netdata-stack
cat > .env <<'EOF'
TUNNEL_TOKEN=replace-with-your-cloudflare-tunnel-token
EOF
chmod 600 .env

If the copy button does not work in your browser, select the code block manually and copy it.

If you already use Vault, Doppler, SOPS, or 1Password Secrets Automation, inject TUNNEL_TOKEN at deploy time and avoid static files on disk.

Step 4: Launch and inspect containers

Start in detached mode, then immediately verify startup logs. Do not skip log inspection; tunnel auth failures are easiest to catch right away.

cd /opt/netdata-stack
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=80 cloudflared
docker compose logs --tail=80 netdata

If the copy button does not work in your browser, select the code block manually and copy it.

Expected signal: cloudflared logs should show a successful connector registration and active tunnel route. Netdata logs should show normal collector initialization.

Step 5: Configure DNS and Cloudflare Access policy

Create a public hostname in Cloudflare Tunnel settings (for example metrics.yourdomain.com) mapped to the service URL for Netdata (typically http://netdata:19999 inside the tunnel context). Then enforce an Access policy so only authenticated users can reach it.

  • Policy action: Allow
  • Include: your company email domain or specific identity provider group
  • Session duration: short for privileged dashboards (for example 8–12 hours)
  • MFA: required for admin/operator groups

This gives you layered protection: hidden origin, identity checks, and conditional access.

Configuration and secret-handling best practices

Production reliability comes from disciplined config hygiene. Keep deployment variables in one place and document ownership for each secret. Rotate tunnel tokens on a schedule and immediately after team-role changes.

  • Pin image versions and test updates in staging before production rollout.
  • Use file permissions (600) for local secret files.
  • Prefer short-lived credentials from your secret manager.
  • Back up /opt/netdata-stack/netdata-config and netdata-lib before major upgrades.
  • Track deployment changes in git with peer review, even for infra-only repos.

Verification checklist

Run this checklist after deployment and after each upgrade.

# Container health
cd /opt/netdata-stack
docker compose ps

# Tunnel reachability signal
docker compose logs --tail=120 cloudflared | egrep -i "connected|registered|error"

# Netdata local response from host namespace
curl -I http://127.0.0.1:19999 2>/dev/null || true

# Public endpoint (should require Access auth)
curl -I https://metrics.yourdomain.com

If the copy button does not work in your browser, select the code block manually and copy it.

  • Cloudflared logs show stable connections without repeated reconnect storms.
  • Public endpoint resolves and prompts Access authentication.
  • Authorized users can load dashboards and inspect host/container charts.
  • No direct public inbound port is open for Netdata on the host firewall.

Common issues and fixes

Tunnel shows connected but hostname is unreachable

Check that your public hostname route in Cloudflare Tunnel points to the correct internal service URL. A typo like http://netdata:1999 instead of 19999 is common.

Access policy loops or denies valid users

Review include rules and identity provider mappings. If you recently changed IdP groups, session cache may lag. Re-authenticate and verify policy precedence.

Netdata container restarts repeatedly

Inspect mounted volumes and permissions. Incorrect ownership on netdata-lib and netdata-cache can cause startup failures.

High CPU from collectors

Disable unneeded collectors in Netdata config for workloads you do not run. Start with default metrics, then tune noisy collectors after baseline observation.

Token rotation causes downtime

Plan token rotation as a two-step deploy: update secret, then restart only cloudflared container. Validate connection before broader stack changes.

FAQ

1) Can I run this without exposing any inbound ports on my firewall?

Yes. That is one of the main benefits. Cloudflared creates outbound connections only, so your Netdata origin can stay private.

2) Is Cloudflare Tunnel enough, or do I still need Cloudflare Access?

Use both. Tunnel protects origin exposure; Access protects user authentication and authorization.

3) How do I upgrade safely in production?

Pin versions, test in staging, snapshot config/data volumes, then roll out during a maintenance window with post-deploy checks.

4) What is the minimum backup set for recovery?

Back up Netdata config and library state directories plus your Compose and secret management metadata.

5) Can multiple operators access dashboards concurrently?

Yes. Netdata supports multiple viewers; use Access groups to control who can authenticate.

6) How do I revoke access quickly when someone leaves the team?

Remove the user from your IdP group mapped in Access policy, invalidate active sessions, and rotate tunnel token if needed.

7) Should I keep Docker socket mounted read-only?

Yes, keep it read-only unless you have a specific need. This reduces unnecessary risk while preserving container visibility.

Related guides

Talk to us

If you want this deployed with hardened access policies, backup automation, and monitored upgrades, our team can help you design and operate it end to end.

Contact Us

Production Guide: Deploy NetBird with Kubernetes + Helm + cert-manager on Ubuntu
A production-first, zero-trust deployment blueprint for NetBird with secure TLS, secret hygiene, and operational verification.