Skip to content

blackoutsecure/docker-graphs1090

graphs1090 logo

blackoutsecure/graphs1090

GitHub Stars Docker Pulls GitHub Release Blackout Secure Launchpad License: MIT Made by BlackoutSecure

Unofficial community image for graphs1090, built with LinuxServer.io style container patterns (s6, hardened defaults, practical runtime options) for ADS-B performance graphing workloads. Sponsored and maintained by Blackout Secure.

Important

This repository is not an official LinuxServer.io image release. Want to help make it an officially supported LinuxServer.io Community image? Add your support in linuxserver/discussions/112.

Links: Docker Hub · Balena block · GitHub · Upstream graphs1090

balena deploy button


Table of Contents


Quick Start

docker run -d \
  --name=graphs1090 \
  --restart unless-stopped \
  -e TZ=Etc/UTC \
  -e GRAPHS1090_DECODER_DIR=/run/readsb \
  -p 8080:8080 \
  -v graphs1090-config:/config \
  -v collectd-rrd:/var/lib/collectd/rrd \
  -v /path/to/readsb/json:/run/readsb:ro \
  blackoutsecure/graphs1090:latest

Access the web UI at http://<host-ip>:8080/graphs1090/.

For compose files, balena, and more examples, see Usage below.


Image Availability

Docker Hub (Recommended):

  • All images published to Docker Hub
  • Simple pull command: docker pull blackoutsecure/graphs1090:latest
  • Multi-arch support: amd64, arm64
  • No registry prefix needed (defaults to Docker Hub)
# Pull latest
docker pull blackoutsecure/graphs1090

# Pull specific version
docker pull blackoutsecure/graphs1090:1.0.1

# Pull architecture-specific (rarely needed)
docker pull blackoutsecure/graphs1090:latest@amd64

About The graphs1090 Application

graphs1090 generates performance graphs for readsb / dump1090-fa ADS-B receivers, providing visual insight into signal strength, message rate, aircraft count, range, CPU, and other metrics over time.

Author and maintenance credits (upstream):


Supported Architectures

This image is published as a multi-arch manifest. Pulling blackoutsecure/graphs1090:latest retrieves the correct image for your host architecture.

The architectures supported by this image are:

Architecture Tag
x86-64 amd64-latest
arm64 arm64v8-latest

Usage

docker-compose (recommended, click here for more info)

---
services:
  graphs1090:
    image: blackoutsecure/graphs1090:latest
    container_name: graphs1090
    environment:
      - TZ=Etc/UTC
      - GRAPHS1090_DECODER_DIR=/run/readsb
    volumes:
      - config:/config
      - collectd-rrd:/var/lib/collectd/rrd
      - /path/to/readsb/json:/run/readsb:ro
    ports:
      - 8080:8080  # Web UI (HTTP)
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - DAC_OVERRIDE
      - FOWNER
      - SETUID
      - SETGID
    security_opt:
      - no-new-privileges:true
    tmpfs:
      - /tmp
      - /run:exec
    restart: unless-stopped

volumes:
  config:
  collectd-rrd:

docker-compose paired with readsb

---
services:
  readsb:
    image: blackoutsecure/readsb:latest
    container_name: readsb
    environment:
      - TZ=Etc/UTC
    volumes:
      - readsb-config:/config
      - readsb-run:/run/readsb
    devices:
      - /dev/bus/usb:/dev/bus/usb
    tmpfs:
      - /tmp
      - /run:exec
    restart: unless-stopped

  graphs1090:
    image: blackoutsecure/graphs1090:latest
    container_name: graphs1090
    environment:
      - TZ=Etc/UTC
      - GRAPHS1090_DECODER_DIR=/run/readsb
    volumes:
      - graphs1090-config:/config
      - collectd-rrd:/var/lib/collectd/rrd
      - readsb-run:/run/readsb:ro
    ports:
      - 8080:8080
    depends_on:
      - readsb
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - DAC_OVERRIDE
      - FOWNER
      - SETUID
      - SETGID
    security_opt:
      - no-new-privileges:true
    tmpfs:
      - /tmp
      - /run:exec
    restart: unless-stopped

volumes:
  readsb-config:
  readsb-run:
  graphs1090-config:
  collectd-rrd:
docker run -d \
  --name=graphs1090 \
  -e TZ=Etc/UTC \
  -e GRAPHS1090_DECODER_DIR=/run/readsb \
  -p 8080:8080 \
  -v /path/to/graphs1090/config:/config \
  -v /path/to/collectd/rrd:/var/lib/collectd/rrd \
  -v /path/to/readsb/json:/run/readsb:ro \
  --restart unless-stopped \
  blackoutsecure/graphs1090:latest

Balena Deployment

This image can be deployed to Balena-powered IoT devices using the included docker-compose.yml file (which contains the required Balena labels):

balena push <your-app-slug>

For deployment via the web interface, use the deploy button in this repository. See Balena documentation for details.

Parameters

Ports

Parameter Function
-p 8080:8080 Web UI (HTTP)

Environment Variables

Parameter Function Required
-e TZ=Etc/UTC Timezone (TZ database) Optional
-e GRAPHS1090_DECODER_DIR=/run/readsb Path to decoder JSON directory (stats.json, aircraft.json) Optional
-e GRAPHS1090_UAT_DIR= Path to 978 MHz UAT decoder directory (enables UAT graphs) Optional
-e GRAPHS1090_PORT=8080 HTTP port for the web UI Optional
-e GRAPHS1090_USER=abc Runtime user Optional
-e PUID=911 User ID for file ownership Optional
-e PGID=911 Group ID for file ownership Optional

Storage Mounts

Parameter Function Required
-v /config Persistent configuration Recommended
-v /var/lib/collectd/rrd RRD database storage — preserves graph history across restarts Recommended
-v /run/readsb Decoder JSON input directory (mount read-only) Required

Volume Details

The container uses three volumes:

/config — Configuration & Persistence

  • Purpose: Stores persistent configuration and application state
  • Example: -v /path/to/graphs1090/config:/config or -v graphs1090-config:/config

/var/lib/collectd/rrd — RRD Database Storage

  • Purpose: Preserves graph history (RRD databases) across container restarts
  • Example: -v /path/to/collectd/rrd:/var/lib/collectd/rrd or -v collectd-rrd:/var/lib/collectd/rrd

/run/readsb — Decoder JSON Input

  • Purpose: Read-only mount of the decoder JSON output directory from readsb or dump1090-fa
  • Required files: stats.json, aircraft.json
  • Example: -v /path/to/readsb/json:/run/readsb:ro

Configuration

Environment variables are set using -e flags in docker run or the environment: section in docker-compose.

The graphs1090 config file is /etc/default/graphs1090 inside the container. To customize, either mount a file into the container or edit it via docker exec.

Common Options

Variable Default Description
colorscheme default Color scheme: default or dark
range nautical Range unit: nautical, statute, or metric
fahrenheit 0 Set to 1 for Fahrenheit
graph_size default Graph size: small, default, large, huge, custom
WWW_TITLE graphs1090 Browser tab title
WWW_HEADER Performance Graphs Page heading
DRAW_INTERVAL 60 Graph redraw interval in seconds
HIDE_SYSTEM no Set yes to hide system resource graphs
disk (blank) Block device for disk I/O graphs (e.g. mmcblk0)
ether (blank) Network interface for wired stats (e.g. eth0)
enable_scatter no Enable scatter plot data collection

All options: upstream default config

Custom Configuration via Volume Mount

volumes:
  - ./my-graphs1090-config:/etc/default/graphs1090:ro

User / Group Identifiers

By default, this container runs as the LSIO abc user (non-root) for better security isolation. The abc user is created by the LinuxServer.io base image with UID/GID 911 and remapped at container start via PUID/PGID.

  • collectd, graphs1090, and nginx all run as the abc user — no root privileges required for normal operation.
  • Set PUID and PGID only if you need file ownership on /config and /var/lib/collectd/rrd to match a specific host user.
  • The mounted decoder JSON directory (/run/readsb) is read-only — graphs1090 never writes to your decoder's output.

Application Setup

The container runs three services under s6-overlay:

  1. collectd — polls the decoder's JSON output every 60 seconds via Python plugins and writes metrics to RRD databases
  2. graphs1090 — periodically generates PNG graph images from the RRD data with escalating intervals (1 min, 5 min, 15 min, 60 min depending on graph timespan)
  3. nginx — serves the HTML interface and graph images

Data Persistence

During normal operation, collectd writes to /run/collectd (memory-backed tmpfs) to minimize disk I/O.

On container start, RRD data is restored from /var/lib/collectd/rrd/localhost.tar.gz to memory, with a fallback cascade: primary tarball, raw folder, this week's auto-backup, last week's auto-backup, or fresh start.

On container stop, RRD data is compressed and written back to disk. A weekly rotating backup is kept automatically with 60-day retention.


Troubleshooting

No data / empty graphs

  1. Verify the decoder JSON directory is mounted and populated:

    docker exec graphs1090 ls -la /run/readsb/
    docker exec graphs1090 head -c 200 /run/readsb/stats.json
  2. If stats.json is missing, the decoder container is not providing data. Check that:

    • The readsb/dump1090-fa container is running
    • The shared volume is mounted correctly (not an empty volume)
    • The decoder is writing JSON output

Graphs take time to appear

Initial data collection takes up to 10 minutes. Graphs with longer timespans (7-day, 30-day) will fill in gradually.

Port conflict

Map to a different host port:

docker run ... -p 8081:8080 ...

View logs

docker logs graphs1090
docker logs graphs1090 --tail 100 -f

Check service status

docker exec graphs1090 s6-svstat /run/service/svc-collectd
docker exec graphs1090 s6-svstat /run/service/svc-graphs1090
docker exec graphs1090 s6-svstat /run/service/svc-nginx

Getting help


Health Monitoring

The container includes built-in health monitoring at multiple levels:

Docker HEALTHCHECK

The image includes a HEALTHCHECK that performs an HTTP GET against the nginx web UI (http://127.0.0.1:${GRAPHS1090_PORT:-8080}/graphs1090/). Docker marks the container as unhealthy after 3 consecutive failures.

Setting Value
Interval 30s
Timeout 5s
Start period 30s
Retries 3
# Check container health status
docker inspect --format='{{.State.Health.Status}}' graphs1090

# View health check history
docker inspect --format='{{json .State.Health}}' graphs1090 | jq .

s6 Service Supervision

All long-running services are supervised by s6-overlay and automatically restarted on crash:

# Check individual service status
docker exec graphs1090 s6-svstat /run/service/svc-collectd
docker exec graphs1090 s6-svstat /run/service/svc-graphs1090
docker exec graphs1090 s6-svstat /run/service/svc-nginx

Quick Status Commands

# Container health
docker inspect --format='{{.State.Health.Status}}' graphs1090

# Confirm decoder JSON input is reaching the container
docker exec graphs1090 ls -la /run/readsb/
docker exec graphs1090 head -c 200 /run/readsb/stats.json

# Web UI reachability from inside the container
docker exec graphs1090 wget -qO- http://127.0.0.1:8080/graphs1090/ | head -n 5

# Service uptime (all services)
docker exec graphs1090 s6-svstat /run/service/svc-collectd
docker exec graphs1090 s6-svstat /run/service/svc-graphs1090
docker exec graphs1090 s6-svstat /run/service/svc-nginx

Release & Versioning

This project uses semantic versioning:

  • Releases published on GitHub Releases
  • Multi-arch images (amd64, arm64v8) built automatically
  • Docker Hub tags: version-specific, latest, and architecture-specific

Update to latest:

docker pull blackoutsecure/graphs1090:latest
docker-compose up -d  # if using compose

Check image version:

docker inspect -f '{{ index .Config.Labels "build_version" }}' blackoutsecure/graphs1090:latest

Resources


License

MIT — see LICENSE. The upstream graphs1090 project is also MIT licensed.

Sponsored and maintained by Blackout Secure.

About

LinuxServer.io-style containerized build of graphs1090 — performance graphs for readsb / dump1090-fa ADS-B receivers.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

  •  

Contributors