Grafana Dashboards Backup

This role backs up all Grafana dashboards using the Grafana API to dual NAS storage.

ARA Ansible Bash Grafana HTTPS JSON NAS Proxmox

Grafana Dashboards Backup Role

Overview

This role backs up all Grafana dashboards using the Grafana API to dual NAS storage. It downloads dashboard JSON definitions, creates compressed archives, and automatically manages retention by keeping only the last 5 backups per NAS. The exported JSON format is compatible with Grafana’s import functionality.

Purpose

  • Disaster Recovery: Protect dashboard configurations against data loss
  • Version Control: Maintain timestamped history of dashboard changes
  • Migration: Transfer dashboards to new Grafana instances
  • Dual Redundancy: Backs up to two separate NAS devices (Synology DS418 and Proxmox OMV)
  • API-Based: Uses Grafana API for programmatic backup (no filesystem access needed)
  • Clean JSON Export: Saves dashboards without API wrapper metadata

Requirements

  • Ansible 2.9 or higher
  • Collection: community.general (for archive module)
  • Grafana with API access enabled
  • Grafana API token with appropriate permissions (stored in Ansible Vault)
  • NAS mount points must be accessible and writable
  • Network connectivity to Grafana server (typically port 3000)

Role Variables

Required Variables

VariableRequiredDescription
vault_grafana_ansibleuser_api_tokenYesGrafana API token (stored in Ansible Vault)

Optional Variables

VariableDefaultDescription
grafana_dashboards_backup_host{{ hostvars['grafana']['ansible_host'] }}:3000Grafana host and port
grafana_dashboards_backup_port3000Grafana web interface port
grafana_dashboards_backup_validate_certstrueValidate SSL certificates
grafana_dashboards_backup_syno_mount_point/mnt/synology-ds418/grafana/dashboardsSynology NAS backup destination
grafana_dashboards_backup_prxmxomv_mount_point/mnt/prxmx-omv/grafana/dashboardsProxmox OMV NAS backup destination

Variable Details

vault_grafana_ansibleuser_api_token

Grafana API token with permissions to read dashboards. Create in Grafana UI: Configuration → API Keys.

Required permissions:

  • Read dashboards
  • Read folders (to get dashboard list)

Example vault variable:

vault_grafana_ansibleuser_api_token: "glsa_1234567890abcdefghijklmnopqrstuvwxyz"

grafana_dashboards_backup_validate_certs

Set to false if using self-signed certificates.

Example:

grafana_dashboards_backup_validate_certs: false

Dependencies

This role has no dependencies on other Ansible roles, but requires:

  • Grafana instance accessible via HTTPS
  • NAS mounts configured (see nas_mount or nas_mount_systemd roles)
  • Grafana API token configured

Example Playbook

Basic Usage

---
- name: Backup Grafana Dashboards
  hosts: localhost
  become: true

  roles:
    - grafana_dashboards_backup

With Custom Grafana Host

---
- name: Backup Grafana Dashboards from Custom Host
  hosts: localhost
  become: true

  vars:
    grafana_dashboards_backup_host: "monitoring.example.com:3000"
    grafana_dashboards_backup_validate_certs: false

  roles:
    - grafana_dashboards_backup

Scheduled Backup with Cron

---
- name: Schedule Daily Grafana Dashboards Backup
  hosts: localhost
  become: true

  tasks:
    - name: Create cron job for daily Grafana dashboards backup
      ansible.builtin.cron:
        name: "Daily Grafana Dashboards Backup"
        minute: "0"
        hour: "3"
        job: "ansible-playbook /path/to/grafana_dashboards_backup.yml"

What This Role Does

  1. Ensures backup directories exist on both NAS mount points
  2. Retrieves dashboard list from Grafana API (/api/search?type=dash-db)
  3. Creates temporary directory for staging dashboard files
  4. Downloads each dashboard individually using dashboard UID (/api/dashboards/uid/{uid})
  5. Extracts pure JSON (removes API wrapper metadata)
  6. Saves each dashboard as separate JSON file with sanitized filename
  7. Creates timestamped tar.gz archive of all JSON files
  8. Copies archive to both NAS devices
  9. Cleans up temporary files and local archive
  10. Removes old backups, keeping only the 5 most recent per NAS

Backup Format

Dashboards are saved as pure JSON files, one file per dashboard:

Directory Structure (inside archive)

grafana_dashboards_20260107T143022.tar.gz
├── abc123_System_Overview.json
├── def456_Application_Metrics.json
├── ghi789_Infrastructure_Dashboard.json
└── jkl012_Database_Performance.json

JSON File Naming

{dashboard_uid}_{dashboard_title}.json

Examples:

  • abc123_System_Overview.json
  • def456_Application_Metrics.json

Special characters in titles are replaced with underscores for filesystem safety.

JSON Content Format

The dashboard JSON is pure Grafana dashboard format (without API wrapper):

{
  "id": null,
  "uid": "abc123",
  "title": "System Overview",
  "tags": ["system", "monitoring"],
  "timezone": "browser",
  "panels": [
    {
      "id": 1,
      "type": "graph",
      "title": "CPU Usage",
      "targets": [...]
    }
  ],
  "templating": {...},
  "annotations": {...},
  "schemaVersion": 38
}

This format:

  • Can be imported directly into Grafana UI (Dashboards → Import)
  • Is compatible with Grafana provisioning
  • Can be restored using grafana_dashboards_restore role
  • Is human-readable and diff-friendly for version control

Backup Content

The backup includes:

  • All dashboards from all folders
  • Panel configurations (visualizations, queries, thresholds)
  • Template variables
  • Annotations
  • Dashboard settings (time range, refresh, tags)
  • Panel layouts and positioning

The backup does NOT include:

  • Dashboard permissions
  • Dashboard versions/history
  • Folder structure (only dashboard content)
  • Datasource configurations (use grafana_datasource_create role)
  • Alert rules (use grafana_alerts_backup role)

Backup Retention

The role implements automatic retention management:

  • Keeps: Last 5 backups per NAS
  • Deletes: Backups older than the 5th most recent
  • Per-NAS logic: Each NAS independently maintains 5 backups

This ensures you have:

  • 5 backups on Synology DS418
  • 5 backups on Proxmox OMV
  • Total: Up to 10 backup copies across both devices

File Naming Convention

Backup archives are named using ISO 8601 basic short format:

grafana_dashboards_YYYYMMDDTHHMMSS.tar.gz

Examples:

  • grafana_dashboards_20260107T143022.tar.gz
  • grafana_dashboards_20260107T190530.tar.gz

API Wrapper Removal

Grafana API returns dashboards wrapped in metadata:

{
  "meta": {
    "type": "db",
    "canSave": true,
    "canEdit": true,
    ...
  },
  "dashboard": {
    "id": 1,
    "uid": "abc123",
    "title": "My Dashboard",
    ...
  }
}

The role extracts only the dashboard object for cleaner backups:

content: "{{ item.json.dashboard | to_nice_json }}"

This ensures:

  • ✅ Backed up JSON is directly importable
  • ✅ No API-specific metadata pollutes the backup
  • ✅ Smaller file sizes
  • ✅ Cleaner version control diffs

API Endpoints Used

1. Search Dashboards

GET /api/search?type=dash-db
Authorization: Bearer {api_token}

Returns list of all dashboards with:

  • Dashboard UID
  • Dashboard title
  • Folder information
  • Dashboard type

2. Get Dashboard by UID

GET /api/dashboards/uid/{uid}
Authorization: Bearer {api_token}

Returns complete dashboard JSON including:

  • Panel configurations
  • Template variables
  • Annotations
  • Dashboard settings

Restoration

To restore from a backup, use the companion grafana_dashboards_restore role or manually:

Via Grafana UI

  1. Extract the archive: tar -xzf grafana_dashboards_20260107T143022.tar.gz
  2. In Grafana: Dashboards → Import
  3. Upload or paste JSON content
  4. Configure datasource mappings if needed
  5. Click “Import”

Via Provisioning

# Extract the archive
tar -xzf grafana_dashboards_20260107T143022.tar.gz

# Place JSON files in provisioning directory
sudo cp *.json /etc/grafana/provisioning/dashboards/

# Restart Grafana
sudo systemctl restart grafana-server

Security Considerations

  • API Token Protection: Token used in HTTP headers (HTTPS recommended)
  • Vault Storage: API token must be stored in Ansible Vault
  • Certificate Validation: Enabled by default, only disable for trusted networks
  • File Permissions: Backup files created with mode 0644
  • Sensitive Data: Dashboard queries may contain sensitive information

Tags

This role does not define any tags. Use playbook-level tags if needed:

- hosts: localhost
  roles:
    - grafana_dashboards_backup
  tags:
    - backup
    - grafana
    - monitoring
    - dashboards

Notes

  • The role uses Grafana’s stable REST API
  • Each dashboard is downloaded individually for better error handling
  • Dashboard titles with special characters are sanitized in filenames
  • Temporary files are always cleaned up, even if the backup fails
  • The role processes all dashboards regardless of folder

Troubleshooting

”Unauthorized” or 401 errors

Verify the API token:

  • Check token is valid in Grafana UI
  • Ensure token has read permissions for dashboards
  • Confirm token hasn’t expired

Test manually:

curl -H "Authorization: Bearer YOUR_TOKEN" https://grafana:3000/api/search?type=dash-db

“Connection refused” errors

Verify:

  • Grafana is running: systemctl status grafana-server
  • Port 3000 is accessible: nc -zv grafana-host 3000
  • Firewall allows connections

”Permission denied” when writing to NAS

Ensure:

  • NAS is mounted: mount | grep synology
  • Backup directories exist and are writable
  • User has write permissions

No dashboards backed up (but you have dashboards)

Check:

  • API token permissions include dashboard access
  • Dashboards are not in “General Alerting” or system folders
  • Search API returns results: curl -H "Authorization: Bearer TOKEN" https://grafana:3000/api/search?type=dash-db

SSL certificate verification fails

If using self-signed certificates:

grafana_dashboards_backup_validate_certs: false

Backup archive is very large

Dashboards with many panels create larger JSON files. This is normal. To reduce size:

  • Remove unused dashboards
  • Archive old dashboards manually
  • Consider compressing with higher compression levels

Performance Considerations

  • Download time depends on number of dashboards (typically 1-2 seconds per dashboard)
  • Archive creation is fast (typically < 1 second)
  • Network bandwidth to NAS may be the bottleneck
  • API calls are sequential to avoid overwhelming Grafana

Typical performance:

  • 10 dashboards: ~15-20 seconds
  • 50 dashboards: ~1-2 minutes
  • 100 dashboards: ~2-3 minutes

Grafana Version Compatibility

  • Grafana 6.0+: Full support
  • Grafana 7.0+: Full support
  • Grafana 8.0+: Full support
  • Grafana 9.0+: Full support with enhanced features
  • Grafana 10.0+: Full support

The role uses stable API endpoints that have been consistent across versions.

  • grafana_dashboards_restore: Restores dashboards from backups created by this role
  • grafana_alerts_backup: Backs up Grafana alert rules
  • grafana_install: Installs and configures Grafana server
  • grafana_datasource_create: Configures datasources used by dashboards

Best Practices

  1. Schedule regular backups (daily or weekly depending on change frequency)
  2. Test restore procedures periodically to verify backup integrity
  3. Version control dashboard JSON for tracking changes over time
  4. Document datasource mappings for restoration to different environments
  5. Keep backups offsite (the dual NAS approach provides good redundancy)

License

MIT

Author

Created for homelab infrastructure management.