Database intermediate ⏱ 45 minutes

InfluxDB: Time-Series Database for Metrics and IoT

Purpose-built database for metrics, events, and IoT data. Telegraf integration and Grafana dashboards.

By homelabbing.io • 2025-12-17
#influxdb#time-series#metrics#iot#telegraf

Introduction

InfluxDB is a purpose-built time-series database designed to handle high write and query loads for timestamped data. Whether you’re collecting server metrics, IoT sensor readings, application performance data, or real-time analytics, InfluxDB provides the performance and features needed to store, query, and visualize time-series data efficiently.

For homelabbers, InfluxDB is the cornerstone of a comprehensive monitoring stack, working seamlessly with Telegraf for data collection and Grafana for visualization.

What You’ll Learn:

  • Deploy InfluxDB 2.x with Docker and understand the architecture
  • Install and configure Telegraf for automated metrics collection
  • Write Flux queries to analyze time-series data
  • Set up data retention policies and downsampling
  • Integrate InfluxDB with Grafana for powerful visualizations
  • Configure alerting and notifications
  • Monitor InfluxDB itself for health and performance
  • Collect IoT sensor data and Home Assistant metrics

Prerequisites:

  • Docker and Docker Compose installed
  • Basic understanding of time-series data concepts
  • Command-line proficiency
  • Homelab server with minimum 2GB RAM, 20GB storage
  • Recommended: 4GB+ RAM for production monitoring workloads

Part 1: Understanding InfluxDB

What is InfluxDB?

InfluxDB is an open-source time-series database (TSDB) optimized for fast, high-availability storage and retrieval of time-series data. Unlike general-purpose databases, InfluxDB is specifically designed for data that includes timestamps—metrics, events, and analytics.

Key Characteristics:

  • Purpose-Built for Time-Series: Optimized data structures for timestamped data
  • High Write Throughput: Handles millions of data points per second
  • Efficient Storage: Automatic compression and retention policies
  • Powerful Query Language: Flux (InfluxDB 2.x) for complex time-series analysis
  • Built-in UI: Web-based interface for queries, dashboards, and tasks
  • Ecosystem Integration: Native Telegraf, Grafana, and third-party support
  • Downsampling: Automatically aggregate old data for storage efficiency

Why InfluxDB for Homelabs?

Technical Advantages:

  1. Optimized for Time-Series Workloads

    • Write-optimized storage engine
    • Timestamp-based indexing
    • Automatic data retention and compaction
    • Efficient time-range queries
  2. Complete Monitoring Stack

    • InfluxDB: Storage
    • Telegraf: Data collection (100+ plugins)
    • Flux: Query language
    • Built-in visualization and alerts
  3. Scalability

    • Single-node for homelabs (millions of points/sec)
    • Clustering for enterprise (optional)
    • Efficient compression (10:1 typical)
  4. Rich Feature Set

    • Continuous queries (InfluxDB 1.x)
    • Tasks (InfluxDB 2.x) for data transformation
    • User-defined functions
    • Anomaly detection
    • Forecasting and predictions

Common Homelab Use Cases:

  • System Monitoring: CPU, memory, disk, network metrics
  • Container Metrics: Docker, Kubernetes resource usage
  • Network Monitoring: SNMP, ping, bandwidth
  • IoT Sensors: Temperature, humidity, power consumption
  • Home Automation: Home Assistant state changes
  • Application Metrics: Response times, error rates, throughput
  • Energy Monitoring: Solar panels, smart plugs, power meters
  • Weather Stations: Personal weather data collection

InfluxDB vs. Alternatives

FeatureInfluxDBPrometheusTimescaleDBGraphite
TypePurpose TSDBTSDBPostgreSQL extTSDB
Write SpeedExcellentGoodGoodExcellent
Query LanguageFlux/InfluxQLPromQLSQLFunctions
Data ModelTags/FieldsLabels/ValuesRelationalHierarchical
RetentionBuilt-inBasicManualCarbon rules
DownsamplingContinuous queriesRecording rulesContinuous aggAggregation
UIBuilt-inBasicNoneGraphite-web
Push/PullPushPullPushPush
Best ForGeneral TSDBMetricsSQL usersLegacy apps

InfluxDB 2.x Architecture

Data Model:

Bucket (like a database)
├── Measurement (like a table)
│   ├── Tags (indexed metadata)
│   │   ├── host=server1
│   │   ├── region=us-east
│   │   └── datacenter=dc1
│   ├── Fields (actual values)
│   │   ├── cpu_usage=45.2
│   │   ├── memory_used=2048
│   │   └── disk_free=500000
│   └── Timestamp
│       └── 2024-12-16T10:30:00Z

Key Concepts:

  • Bucket: Container for time-series data (replaces “database” in 1.x)
  • Measurement: Collection of data points (like a table)
  • Tags: Indexed key-value metadata for filtering
  • Fields: Actual metric values (not indexed)
  • Timestamp: When the data point was recorded
  • Organization: Top-level container for buckets and users

InfluxDB 2.x Stack:

InfluxDB 2.x Server
├── Storage Engine (TSM - Time-Structured Merge Tree)
│   ├── WAL (Write-Ahead Log)
│   ├── Cache (in-memory)
│   └── TSM Files (compressed on disk)
├── Query Engine (Flux)
│   ├── Parser
│   ├── Optimizer
│   └── Executor
├── Tasks Engine
│   ├── Downsampling
│   ├── Alerting
│   └── Data transformation
└── HTTP API
    ├── /api/v2/write
    ├── /api/v2/query
    └── UI endpoints

Part 2: Installing InfluxDB with Docker

Quick Start Deployment

Create project directory:

mkdir -p ~/influxdb-homelab
cd ~/influxdb-homelab

Create docker-compose.yml:

version: '3.8'

services:
  influxdb:
    image: influxdb:2.7-alpine
    container_name: influxdb
    hostname: influxdb
    restart: unless-stopped

    environment:
      # Initial setup (only used on first run)
      DOCKER_INFLUXDB_INIT_MODE: setup
      DOCKER_INFLUXDB_INIT_USERNAME: admin
      DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUXDB_PASSWORD:-ChangeMe123!}
      DOCKER_INFLUXDB_INIT_ORG: homelab
      DOCKER_INFLUXDB_INIT_BUCKET: metrics
      DOCKER_INFLUXDB_INIT_RETENTION: 30d
      DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: ${INFLUXDB_TOKEN}

    ports:
      - "8086:8086"

    volumes:
      # Data persistence
      - influxdb-data:/var/lib/influxdb2

      # Configuration
      - influxdb-config:/etc/influxdb2

    networks:
      - influxdb-network

    healthcheck:
      test: ["CMD", "influx", "ping"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 30s

    # Resource limits
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4G
        reservations:
          cpus: '0.5'
          memory: 512M

volumes:
  influxdb-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /mnt/storage/influxdb-data
  influxdb-config:
    driver: local

networks:
  influxdb-network:
    driver: bridge

Create secure credentials (.env):

# Generate strong password and token
INFLUXDB_PASSWORD=$(openssl rand -base64 32)
INFLUXDB_TOKEN=$(openssl rand -base64 32)

# Save to .env
cat > .env <<EOF
INFLUXDB_PASSWORD=$INFLUXDB_PASSWORD
INFLUXDB_TOKEN=$INFLUXDB_TOKEN
EOF

chmod 600 .env

echo "InfluxDB admin password: $INFLUXDB_PASSWORD"
echo "InfluxDB admin token: $INFLUXDB_TOKEN"
echo "Save these credentials securely!"

Deploy InfluxDB:

# Start InfluxDB
docker-compose up -d

# View logs
docker-compose logs -f influxdb

# Verify status
docker-compose ps
docker exec influxdb influx ping

Access InfluxDB UI:

Navigate to http://your-server-ip:8086

Login with:

  • Username: admin
  • Password: Your generated password

Initial Configuration via UI

  1. Create Additional Buckets:

    • Click “Load Data” → “Buckets”
    • Click “Create Bucket”
    • Name: iot_sensors
    • Retention: 90d
    • Click “Create”
  2. Create API Tokens:

    • Click “Load Data” → “API Tokens”
    • Click “Generate API Token”
    • Choose “Read/Write Token”
    • Select buckets and permissions
    • Copy token and save securely
  3. Explore Data:

    • Click “Data Explorer”
    • Select bucket and measurement
    • Build queries visually

Part 3: Telegraf for Data Collection

Installing Telegraf

Add to docker-compose.yml:

version: '3.8'

services:
  influxdb:
    # ... (previous influxdb config)

  telegraf:
    image: telegraf:1.29-alpine
    container_name: telegraf
    hostname: telegraf
    restart: unless-stopped

    environment:
      # InfluxDB connection
      INFLUX_URL: http://influxdb:8086
      INFLUX_TOKEN: ${INFLUXDB_TOKEN}
      INFLUX_ORG: homelab
      INFLUX_BUCKET: metrics

    volumes:
      # Configuration
      - ./telegraf.conf:/etc/telegraf/telegraf.conf:ro

      # System access for metrics
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /sys:/host/sys:ro
      - /proc:/host/proc:ro
      - /etc:/host/etc:ro

    networks:
      - influxdb-network

    depends_on:
      influxdb:
        condition: service_healthy

    # Privileged mode for full system access
    privileged: true

volumes:
  influxdb-data:
    driver: local
  influxdb-config:
    driver: local

networks:
  influxdb-network:
    driver: bridge

Configuring Telegraf

Create telegraf.conf:

# Telegraf Configuration

# Global settings
[agent]
  interval = "10s"
  round_interval = true
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  collection_jitter = "0s"
  flush_interval = "10s"
  flush_jitter = "0s"
  precision = "0s"
  hostname = "homelab-server"
  omit_hostname = false

###############################################################################
#                            OUTPUT PLUGINS                                   #
###############################################################################

# InfluxDB v2 output plugin
[[outputs.influxdb_v2]]
  urls = ["${INFLUX_URL}"]
  token = "${INFLUX_TOKEN}"
  organization = "${INFLUX_ORG}"
  bucket = "${INFLUX_BUCKET}"
  timeout = "5s"

###############################################################################
#                            INPUT PLUGINS                                    #
###############################################################################

# System metrics
[[inputs.cpu]]
  percpu = true
  totalcpu = true
  collect_cpu_time = false
  report_active = false

[[inputs.disk]]
  ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]

[[inputs.diskio]]
  # devices = ["sda", "sdb"]

[[inputs.kernel]]
  # no configuration

[[inputs.mem]]
  # no configuration

[[inputs.processes]]
  # no configuration

[[inputs.swap]]
  # no configuration

[[inputs.system]]
  # no configuration

[[inputs.net]]
  # interfaces = ["eth0"]

[[inputs.netstat]]
  # no configuration

# Docker metrics
[[inputs.docker]]
  endpoint = "unix:///var/run/docker.sock"
  gather_services = false
  container_names = []
  container_name_include = []
  container_name_exclude = []
  timeout = "5s"
  perdevice = true
  total = false
  docker_label_include = []
  docker_label_exclude = []

# Temperature sensors (if available)
[[inputs.sensors]]
  remove_numbers = false

# SMART disk health
[[inputs.smart]]
  path_smartctl = "/usr/sbin/smartctl"
  # devices = ["/dev/sda", "/dev/sdb"]
  # attributes = true
  # excludes = []

# Ping connectivity checks
[[inputs.ping]]
  urls = ["8.8.8.8", "1.1.1.1"]
  count = 4
  ping_interval = 1.0
  timeout = 2.0
  interface = ""

# HTTP response time
[[inputs.http_response]]
  urls = [
    "http://google.com",
    "http://homelab.local:3000"
  ]
  response_timeout = "5s"
  method = "GET"
  follow_redirects = true

# InfluxDB monitoring
[[inputs.influxdb]]
  urls = ["http://influxdb:8086/metrics"]

###############################################################################
#                       ADDITIONAL USEFUL INPUTS                              #
###############################################################################

# SNMP (for network devices)
# [[inputs.snmp]]
#   agents = ["192.168.1.1"]
#   version = 2
#   community = "public"
#   [[inputs.snmp.field]]
#     name = "hostname"
#     oid = "RFC1213-MIB::sysName.0"

# MQTT (for IoT devices)
# [[inputs.mqtt_consumer]]
#   servers = ["tcp://mosquitto:1883"]
#   topics = ["homeassistant/#", "sensors/#"]
#   data_format = "json"

# Nginx
# [[inputs.nginx]]
#   urls = ["http://localhost/nginx_status"]

# PostgreSQL
# [[inputs.postgresql]]
#   address = "host=postgres user=telegraf password=password dbname=postgres sslmode=disable"

# Redis
# [[inputs.redis]]
#   servers = ["tcp://redis:6379"]
#   password = "your_redis_password"

Start Telegraf:

docker-compose up -d telegraf
docker-compose logs -f telegraf

Verify data collection:

  1. Go to InfluxDB UI → Data Explorer
  2. Select metrics bucket
  3. You should see measurements like cpu, mem, disk, etc.

Part 4: Flux Query Language

Flux Basics

Flux is InfluxDB 2.x’s functional query language.

Basic query structure:

from(bucket: "metrics")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "cpu")
  |> filter(fn: (r) => r._field == "usage_system")
  |> aggregateWindow(every: 1m, fn: mean)

Breaking it down:

  1. from(bucket: "metrics") - Select data source
  2. |> - Pipe operator (passes data to next function)
  3. range(start: -1h) - Time window (last hour)
  4. filter() - Filter rows
  5. aggregateWindow() - Downsample data

Common Flux Queries

1. CPU usage over time:

from(bucket: "metrics")
  |> range(start: -24h)
  |> filter(fn: (r) => r._measurement == "cpu")
  |> filter(fn: (r) => r._field == "usage_user")
  |> aggregateWindow(every: 5m, fn: mean, createEmpty: false)
  |> yield(name: "mean")

2. Memory usage percentage:

from(bucket: "metrics")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "mem")
  |> filter(fn: (r) => r._field == "used_percent")
  |> aggregateWindow(every: 1m, fn: last)

3. Disk free space:

from(bucket: "metrics")
  |> range(start: -6h)
  |> filter(fn: (r) => r._measurement == "disk")
  |> filter(fn: (r) => r._field == "free")
  |> filter(fn: (r) => r.path == "/")
  |> aggregateWindow(every: 10m, fn: last)
  |> map(fn: (r) => ({ r with _value: r._value / 1024.0 / 1024.0 / 1024.0 }))  // Convert to GB

4. Network traffic rate:

from(bucket: "metrics")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "net")
  |> filter(fn: (r) => r._field == "bytes_recv" or r._field == "bytes_sent")
  |> derivative(unit: 1s, nonNegative: true)
  |> aggregateWindow(every: 1m, fn: mean)

5. Top 5 Docker containers by memory:

from(bucket: "metrics")
  |> range(start: -5m)
  |> filter(fn: (r) => r._measurement == "docker_container_mem")
  |> filter(fn: (r) => r._field == "usage")
  |> last()
  |> group(columns: ["container_name"])
  |> top(n: 5, columns: ["_value"])

6. Calculate rate of change:

from(bucket: "metrics")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "cpu")
  |> filter(fn: (r) => r._field == "usage_system")
  |> derivative(unit: 1s)

7. Alert if value exceeds threshold:

from(bucket: "metrics")
  |> range(start: -5m)
  |> filter(fn: (r) => r._measurement == "cpu")
  |> filter(fn: (r) => r._field == "usage_user")
  |> mean()
  |> map(fn: (r) => ({
      r with
      _level:
        if r._value >= 90.0 then "critical"
        else if r._value >= 70.0 then "warning"
        else "ok"
    }))

Variables in Flux

// Define variables
bucket_name = "metrics"
time_range = -24h
measurement_name = "cpu"

// Use in query
from(bucket: bucket_name)
  |> range(start: time_range)
  |> filter(fn: (r) => r._measurement == measurement_name)

Part 5: Retention Policies and Downsampling

Understanding Data Retention

InfluxDB 2.x uses bucket retention periods to automatically delete old data.

Configure retention via UI:

  1. Load Data → Buckets
  2. Click on bucket name
  3. Edit retention period
  4. Options: Never (∞), or specific duration (7d, 30d, 90d, 1y)

Configure retention via CLI:

# Create bucket with 30-day retention
docker exec influxdb influx bucket create   --name short_term   --org homelab   --retention 720h  # 30 days

# Update existing bucket
docker exec influxdb influx bucket update   --name metrics   --retention 2160h  # 90 days

Creating Downsampling Tasks

Tasks run Flux queries on a schedule to downsample or transform data.

Example: Downsample hourly averages

option task = {
  name: "downsample_hourly",
  every: 1h,
  offset: 5m
}

from(bucket: "metrics")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "cpu")
  |> aggregateWindow(every: 1h, fn: mean, createEmpty: false)
  |> to(bucket: "metrics_hourly", org: "homelab")

Create task via UI:

  1. Tasks → Create Task
  2. Paste Flux script
  3. Click “Save”

Retention strategy example:

Raw data (metrics bucket)
├── 10-second interval
├── 7-day retention
└── Downsampled to hourly → stored in metrics_hourly

Hourly aggregates (metrics_hourly bucket)
├── 1-hour interval
├── 90-day retention
└── Downsampled to daily → stored in metrics_daily

Daily aggregates (metrics_daily bucket)
├── 1-day interval
└── 2-year retention

Part 6: Grafana Integration

Connecting InfluxDB to Grafana

Add InfluxDB as data source in Grafana:

  1. Configuration → Data Sources → Add data source
  2. Select “InfluxDB”
  3. Configure:
    Query Language: Flux
    URL: http://influxdb:8086
    Organization: homelab
    Token: your-influxdb-token
    Default Bucket: metrics
  4. Click “Save & Test”

Creating Grafana Dashboards

Example panel: CPU Usage

  1. Create new dashboard → Add panel
  2. Data source: InfluxDB
  3. Query:
from(bucket: "metrics")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r._measurement == "cpu")
  |> filter(fn: (r) => r._field == "usage_user")
  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
  1. Visualization: Time series
  2. Panel title: “CPU Usage”

Example panel: Memory Usage

from(bucket: "metrics")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r._measurement == "mem")
  |> filter(fn: (r) => r._field == "used_percent")
  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)

Import pre-built dashboards:

  • Dashboard ID: 1443 (System Metrics)
  • Dashboard ID: 13969 (Docker Monitoring)
  • Dashboard ID: 928 (Telegraf System Dashboard)

Part 7: IoT and Home Assistant Integration

Collecting IoT Sensor Data

MQTT to InfluxDB via Telegraf:

Add to telegraf.conf:

[[inputs.mqtt_consumer]]
  servers = ["tcp://mosquitto:1883"]
  topics = [
    "homeassistant/sensor/+/state",
    "zigbee2mqtt/+",
    "sensors/temperature/+"
  ]
  data_format = "json"
  json_string_fields = ["temperature", "humidity", "battery"]
  tag_keys = ["device_name", "room"]

Home Assistant Integration

Configure InfluxDB in Home Assistant:

Add to configuration.yaml:

influxdb:
  host: influxdb
  port: 8086
  api_version: 2
  ssl: false
  token: !secret influxdb_token
  organization: homelab
  bucket: homeassistant
  tags:
    source: ha
  tags_attributes:
    - friendly_name
  default_measurement: state
  include:
    entities:
      - sensor.living_room_temperature
      - sensor.bedroom_humidity
      - sensor.power_consumption
      - binary_sensor.front_door

Query Home Assistant data:

from(bucket: "homeassistant")
  |> range(start: -24h)
  |> filter(fn: (r) => r.entity_id == "sensor.living_room_temperature")
  |> filter(fn: (r) => r._field == "value")
  |> aggregateWindow(every: 5m, fn: mean)

Part 8: Backup and Monitoring

Backup InfluxDB

Backup all data:

# Create backup
docker exec influxdb influx backup /tmp/backup -t ${INFLUXDB_TOKEN}

# Copy backup from container
docker cp influxdb:/tmp/backup ./backup_$(date +%Y%m%d)

# Compress backup
tar -czf influxdb_backup_$(date +%Y%m%d).tar.gz ./backup_$(date +%Y%m%d)

Automated backup script:

#!/bin/bash
BACKUP_DIR="/mnt/backups/influxdb"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

mkdir -p "$BACKUP_DIR"

docker exec influxdb influx backup /tmp/backup -t ${INFLUXDB_TOKEN}
docker cp influxdb:/tmp/backup "$BACKUP_DIR/backup_$TIMESTAMP"
tar -czf "$BACKUP_DIR/influxdb_$TIMESTAMP.tar.gz" "$BACKUP_DIR/backup_$TIMESTAMP"
rm -rf "$BACKUP_DIR/backup_$TIMESTAMP"

# Retention: keep last 7 days
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete

Restore from Backup

# Extract backup
tar -xzf influxdb_backup_20241216.tar.gz

# Copy to container
docker cp backup_20241216 influxdb:/tmp/

# Restore
docker exec influxdb influx restore /tmp/backup_20241216 -t ${INFLUXDB_TOKEN}

Monitoring InfluxDB

Check InfluxDB metrics:

# Via HTTP API
curl http://localhost:8086/metrics

# Via Telegraf
# (Already configured in telegraf.conf under inputs.influxdb)

Grafana dashboard for InfluxDB monitoring:

Import Dashboard ID: 12819 (InfluxDB 2.x Metrics)


Conclusion

You now have a comprehensive InfluxDB deployment optimized for time-series data collection and analysis in your homelab.

Key Takeaways:

  1. Purpose-Built: Optimized specifically for time-series data
  2. Complete Stack: InfluxDB + Telegraf + Grafana for full monitoring
  3. Powerful Queries: Flux language for complex time-series analysis
  4. Efficient Storage: Automatic compression and retention policies
  5. IoT Ready: Perfect for sensor data and Home Assistant integration

Next Steps:

  • Configure additional Telegraf input plugins
  • Create custom Grafana dashboards
  • Set up alerting for critical metrics
  • Implement downsampling tasks for long-term storage
  • Explore ML/AI features for anomaly detection

Resources:

Happy time-series monitoring!


Guide Version: 1.0 Last Updated: December 2024 Target Audience: Homelab administrators, DevOps engineers, IoT enthusiasts Difficulty Level: Intermediate Estimated Time: 55 minutes