Dashboard beginner ⏱ 30 minutes

Dashy: Ultimate Customizable Dashboard

Highly configurable dashboard with themes, widgets, and status monitoring. YAML-powered personalization.

By homelabbing.io • 2025-12-16
#dashy#dashboard#customization#yaml#widgets

Overview

Dashy is a highly customizable, privacy-respecting dashboard that puts configuration-as-code first. Unlike point-and-click dashboards, Dashy uses YAML configuration files that can be version-controlled, backed up, and shared. With 50+ built-in themes, dozens of widgets, status checks for every service, and advanced features like keyboard shortcuts and multi-page layouts, Dashy is for homelabbers who want complete control.

Built with privacy in mind, Dashy doesn’t phone home, doesn’t track usage, and runs completely locally. Every feature works offline, and your data never leaves your network unless you explicitly configure external integrations.

What you’ll learn:

  • Installing Dashy with Docker Compose
  • Writing YAML configuration for services and sections
  • Configuring themes and visual customization
  • Adding widgets (weather, system stats, RSS, crypto, etc.)
  • Setting up status checks and health monitoring
  • Implementing authentication and access control
  • Advanced features: keyboard shortcuts, search, icons
  • Configuration best practices and troubleshooting

Why Dashy for Homelabs?

Your dashboard configuration lives in Git. Share your config with the community. Switch between dozens of themes instantly. Check the health of 50 services at a glance. Search across all your services with keyboard shortcuts. Customize every pixel with CSS. This is the power-user’s dashboard.


Prerequisites

Before starting, ensure you have:

  • Docker and Docker Compose installed
  • Basic YAML knowledge (we’ll cover the syntax)
  • Text editor for editing configuration files
  • Hardware requirements:
    • 256 MB RAM minimum (runs lighter than most dashboards)
    • 500 MB storage
    • Network: Port 8080 (customizable)

Optional but helpful:

  • Git for version control
  • Services to add to dashboard
  • Basic CSS knowledge for advanced customization

Understanding Dashy’s Philosophy

Configuration-as-Code Approach

Traditional dashboards:

  • Point and click in web UI
  • Configuration stored in database
  • Hard to backup, version, or share

Dashy:

  • YAML configuration file
  • Version control friendly
  • Backup = copy file
  • Share configs with community

Example configuration:

pageInfo:
  title: My Homelab
  description: Welcome to my services

sections:
  - name: Media
    items:
      - title: Plex
        url: http://plex.local:32400
        icon: plex.png

Privacy-First Design

What Dashy does NOT do:

  • Send telemetry or analytics
  • Call external APIs (unless you configure widgets to do so)
  • Track your usage
  • Require internet connection
  • Store data in cloud

What this means:

  • Fully functional offline
  • No privacy concerns
  • Complete data control
  • Faster load times (no external dependencies)

Core Features

Multi-Section Layout:

  • Organize services into logical groups
  • Collapsible sections
  • Search within/across sections

Extensive Theming:

  • 50+ built-in themes
  • Custom theme creation
  • Per-section theming
  • CSS customization

Status Checks:

  • HTTP ping checks
  • Custom status endpoints
  • Visual health indicators
  • Automatic retry logic

Widgets:

  • Weather, calendar, RSS feeds
  • System stats, crypto prices
  • Custom HTML/JS widgets
  • Iframe embeddings

Authentication:

  • Simple auth (built-in)
  • Keycloak integration
  • Per-user configurations
  • Guest access control

Installation with Docker Compose

Basic Installation

Create docker-compose.yml:

version: '3.8'

services:
  dashy:
    image: lissy93/dashy:latest
    container_name: dashy
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./dashy/conf.yml:/app/public/conf.yml
      - ./dashy/item-icons:/app/public/item-icons
    environment:
      - NODE_ENV=production
      - UID=1000
      - GID=1000

Create initial configuration:

Create dashy/conf.yml:

---
pageInfo:
  title: My Homelab Dashboard
  description: Welcome to my self-hosted services
  navLinks:
    - title: GitHub
      path: https://github.com
    - title: Documentation
      path: https://dashy.to/docs

appConfig:
  theme: nord
  layout: auto
  iconSize: medium
  language: en
  startingView: default
  defaultOpeningMethod: newtab
  statusCheck: true
  statusCheckInterval: 60

sections:
  - name: Getting Started
    icon: fas fa-rocket
    items:
      - title: Dashy Documentation
        description: Read the documentation
        icon: hl-dashy
        url: https://dashy.to/docs
        target: newtab

Start Dashy:

mkdir -p ~/dashy/dashy
cd ~/dashy

# Create conf.yml (above)
nano dashy/conf.yml

# Start container
docker-compose up -d

# Check logs
docker-compose logs -f dashy

Access Dashy:

Navigate to http://localhost:8080 or http://YOUR-SERVER-IP:8080


YAML Configuration Deep Dive

Configuration File Structure

---
# Page metadata
pageInfo:
  title: Dashboard Title
  description: Dashboard description
  navLinks: []  # Top navigation links
  footerText: Footer content

# App-wide settings
appConfig:
  theme: nord
  layout: auto
  language: en
  statusCheck: true

# Service sections
sections:
  - name: Section Name
    icon: section-icon
    items:
      - title: Service Name
        url: https://service.url
        icon: service-icon

Page Info Configuration

pageInfo:
  title: My Homelab
  description: Self-hosted services dashboard

  # Top navigation links
  navLinks:
    - title: GitHub
      path: https://github.com/yourusername
    - title: Documentation
      path: https://docs.homelab.local
    - title: Status Page
      path: https://status.homelab.local

  # Footer customization
  footerText: 'Built with [Dashy](https://dashy.to) | Homelab 2025'

  # Optional logo
  logo: https://example.com/logo.png

App Config Options

appConfig:
  # Theming
  theme: nord  # Or: default, colorful, nord, dracula, etc.
  customColors:
    primary: '#3B82F6'
    background: '#1F2937'

  # Layout
  layout: auto  # Or: horizontal, vertical, auto
  iconSize: medium  # Or: small, medium, large
  colCount: 1  # Number of columns (or 'auto')

  # Behavior
  startingView: default  # Or: minimal, workspace
  defaultOpeningMethod: newtab  # Or: sametab, modal, workspace
  statusCheck: true
  statusCheckInterval: 60  # Seconds

  # Search
  enableFuzzySearch: true
  searchHotkey: '/'

  # Authentication
  auth:
    enableAuth: true
    users:
      - user: admin
        hash: 4D3F...  # bcrypt hash
        type: admin

Service Items Configuration

Basic service:

items:
  - title: Portainer
    description: Container management platform
    url: http://portainer.local:9443
    icon: hl-portainer
    target: newtab

Service with status check:

items:
  - title: Jellyfin
    url: http://jellyfin.local:8096
    icon: hl-jellyfin
    statusCheck: true
    statusCheckUrl: http://jellyfin.local:8096/health
    statusCheckAllowInsecure: true  # For self-signed certs

Service with custom icon:

items:
  - title: Custom Service
    url: http://custom.local
    icon: /item-icons/custom-icon.png  # Local file
    # Or use Font Awesome
    icon: fas fa-server
    # Or use Homelab Icons library
    icon: hl-proxmox

Sections and Organization

Creating Service Sections

sections:
  - name: Media Services
    icon: fas fa-photo-video
    displayData:
      sortBy: default  # Or: most-used, last-used, alphabetical
      rows: 1
      cols: 1
      collapsed: false
      hideForGuests: false
    items:
      - title: Jellyfin
        url: http://jellyfin.local:8096
        icon: hl-jellyfin
        statusCheck: true

      - title: Plex
        url: http://plex.local:32400
        icon: hl-plex
        statusCheck: true

      - title: Sonarr
        url: http://sonarr.local:8989
        icon: hl-sonarr
        statusCheck: true

Section Organization Patterns

By service category:

sections:
  - name: Media
    items: [...]

  - name: Downloads
    items: [...]

  - name: Infrastructure
    items: [...]

  - name: Monitoring
    items: [...]

By environment:

sections:
  - name: Production Services
    items: [...]

  - name: Development Services
    items: [...]

  - name: Staging Environment
    items: [...]

By physical location:

sections:
  - name: Main Server
    items: [...]

  - name: NAS Services
    items: [...]

  - name: Raspberry Pi Services
    items: [...]

Collapsible and Hidden Sections

sections:
  - name: Rarely Used Services
    displayData:
      collapsed: true  # Start collapsed
      hideForGuests: true  # Hide from unauthenticated users
    items: [...]

Themes and Visual Customization

Built-in Themes

Popular themes:

appConfig:
  theme: nord          # Nord color palette
  # Or:
  theme: dracula       # Dracula dark theme
  theme: colorful      # Vibrant colors
  theme: nord-frost    # Nord with blue accent
  theme: material-dark # Material design dark
  theme: material-light # Material design light
  theme: gruvbox       # Gruvbox color scheme
  theme: high-contrast-light
  theme: high-contrast-dark

Switch themes easily:

Settings (cog icon) → Theme → Select from dropdown → Apply

Creating Custom Themes

appConfig:
  customColors:
    primary: '#3B82F6'           # Primary accent color
    background: '#1F2937'         # Main background
    background-darker: '#111827'  # Darker background areas
    item-background: '#374151'    # Service tile background
    item-background-hover: '#4B5563'
    item-text-color: '#F9FAFB'
    heading-text-color: '#F9FAFB'
    settings-background: '#1F2937'

Custom CSS

Add custom CSS:

Create dashy/custom.css:

/* Glassmorphism effect */
section {
  background: rgba(255, 255, 255, 0.05) !important;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

/* Larger service tiles */
.item {
  min-height: 80px;
  padding: 1rem;
}

/* Custom hover effects */
.item:hover {
  transform: translateY(-4px);
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
  transition: all 0.3s ease;
}

/* Custom section headers */
.section-title {
  font-size: 1.5rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 2px;
}

Reference in conf.yml:

appConfig:
  customCss: '/item-icons/custom.css'

Icon Customization

Icon sources:

  1. Homelab Icons (built-in):

    icon: hl-plex
    icon: hl-sonarr
    icon: hl-proxmox
  2. Font Awesome:

    icon: fas fa-server
    icon: fab fa-github
    icon: far fa-chart-bar
  3. Emoji:

    icon: emoji-rocket
    icon: emoji-gear
  4. Custom local icons:

    icon: /item-icons/my-icon.png
  5. External URLs:

    icon: https://example.com/icon.png

Upload custom icons:

Place in /dashy/item-icons/ directory:

cp my-icon.png ~/dashy/dashy/item-icons/

Reference in config:

icon: /item-icons/my-icon.png

Widgets

Adding Widgets

Widget configuration structure:

sections:
  - name: Widgets
    displayData:
      hideForGuests: false
    widgets:
      - type: weather
        options:
          apiKey: your-api-key
          city: New York

      - type: clock
        options:
          format: en-US

Weather widget:

widgets:
  - type: weather
    options:
      apiKey: your-openweather-api-key
      city: New York
      units: imperial  # Or: metric
      hideDetails: false

System info widget:

widgets:
  - type: glances
    options:
      hostname: http://glances.local:61208
      username: optional-username
      password: optional-password

Install Glances for system stats:

docker run -d   --name glances   --restart=always   -p 61208:61208   -e GLANCES_OPT="-w"   -v /var/run/docker.sock:/var/run/docker.sock:ro   nicolargo/glances

RSS feed widget:

widgets:
  - type: rss-feed
    options:
      rssUrl: https://news.ycombinator.com/rss
      apiKey: optional-rss2json-key
      limit: 10
      orderBy: pubDate

Crypto price widget:

widgets:
  - type: crypto-watch-list
    options:
      assets:
        - bitcoin
        - ethereum
        - cardano
      currency: USD
      sortBy: marketCap
      limit: 10

Public IP widget:

widgets:
  - type: public-ip
    options: {}

Iframe widget (embed any site):

widgets:
  - type: iframe
    options:
      url: https://grafana.local/dashboard
      height: 400

Widget Layout

Arrange widgets in grid:

sections:
  - name: Dashboard Widgets
    displayData:
      cols: 2  # Two columns of widgets
      rows: 2  # Two rows
    widgets:
      - type: weather
        options: [...]

      - type: clock
        options: [...]

      - type: rss-feed
        options: [...]

      - type: crypto-watch-list
        options: [...]

Status Checks and Health Monitoring

Enabling Global Status Checks

appConfig:
  statusCheck: true
  statusCheckInterval: 60  # Seconds between checks

Per-Service Status Checks

Basic HTTP ping:

items:
  - title: Jellyfin
    url: http://jellyfin.local:8096
    statusCheck: true
    statusCheckUrl: http://jellyfin.local:8096  # Optional: different check URL

Custom health endpoint:

items:
  - title: API Server
    url: http://api.local
    statusCheck: true
    statusCheckUrl: http://api.local/health
    statusCheckHeaders:
      Authorization: Bearer token123

Accept self-signed certificates:

items:
  - title: Proxmox
    url: https://proxmox.local:8006
    statusCheck: true
    statusCheckAllowInsecure: true

Expected status codes:

items:
  - title: Service
    url: http://service.local
    statusCheck: true
    statusCheckAcceptCodes: '200,201,204'  # Accept any of these

Status Indicators

Visual feedback:

  • Green dot: Service is up (200-299 status)
  • Red dot: Service is down (timeout or error)
  • Orange dot: Service returned unexpected status code
  • Grey dot: Status check disabled or pending

Click status indicator to see details:

  • Last check time
  • Response time (ms)
  • Status code
  • Error message (if any)

Authentication and Access Control

Enabling Authentication

Simple authentication:

appConfig:
  auth:
    enableAuth: true
    users:
      - user: admin
        hash: 5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8  # SHA-256 hash of 'password'
        type: admin

      - user: viewer
        hash: 1BA3D16E9881959F8C9A9762854F72C6E6321AC8F4748538BE0A

91C258F63BB  # Hash of 'viewer123'
        type: normal

Generate password hash:

# Using Node.js
node -e "console.log(require('crypto').createHash('sha256').update('your-password').digest('hex'))"

# Or online tool (use with caution)
# https://emn178.github.io/online-tools/sha256.html

Keycloak integration (advanced):

appConfig:
  auth:
    enableAuth: true
    authType: keycloak
    keycloak:
      serverUrl: https://keycloak.local
      realm: homelab
      clientId: dashy

Guest Access

Allow guest with limited access:

appConfig:
  auth:
    enableAuth: true
    enableGuestAccess: true

sections:
  - name: Public Services
    displayData:
      hideForGuests: false  # Visible to guests
    items: [...]

  - name: Admin Services
    displayData:
      hideForGuests: true  # Hidden from guests
    items: [...]

Advanced Features

Keyboard Shortcuts

Default shortcuts:

  • / - Focus search
  • Esc - Close search/modal
  • Alt + M - Toggle minimal view
  • Alt + W - Toggle workspace view
  • Alt + T - Toggle theme

Custom keyboard shortcuts:

appConfig:
  customKeyboardShortcuts:
    - key: 'Alt+G'
      action: 'open-search'

    - key: 'Alt+1'
      action: 'open-section'
      section: 0  # First section

    - key: 'Ctrl+R'
      action: 'reload-page'

Multi-Page Layouts

Create separate pages:

pages:
  - name: Home
    path: home.yml

  - name: Media
    path: media.yml

  - name: Infrastructure
    path: infra.yml

Navigation between pages:

Top menu automatically shows page links.

Search Functionality

Global search:

  1. Press / or click search icon
  2. Type service name
  3. Results filter in real-time
  4. Press Enter to open first result

Fuzzy search:

appConfig:
  enableFuzzySearch: true  # Allows typos in search

Web search integration:

appConfig:
  webSearch:
    searchEngine: duckduckgo  # Or: google, bing, brave, etc.
    openingMethod: newtab
    searchBangs:
      /r: reddit
      /gh: github
      /w: wikipedia

Type /r homelab in search to search Reddit for “homelab”

Continuous Status Checks

Monitor services continuously:

appConfig:
  statusCheck: true
  statusCheckInterval: 30  # Check every 30 seconds

  # Get browser notifications on status changes
  enableNotifications: true

Webhook on status change:

appConfig:
  statusCheckWebhook:
    url: https://webhook.site/your-unique-url
    onDown: true
    onUp: true

Configuration Best Practices

Version Control

Track configuration in Git:

cd ~/dashy
git init
git add dashy/conf.yml
git commit -m "Initial Dashy configuration"

# Add remote
git remote add origin https://github.com/yourusername/dashy-config.git
git push -u origin main

Benefits:

  • History of changes
  • Easy rollback
  • Share with community
  • Clone to new instances

Configuration Organization

Modular configs with includes:

# conf.yml
---
pageInfo:
  title: Main Dashboard

sections:
  - !include sections/media.yml
  - !include sections/infrastructure.yml
  - !include sections/monitoring.yml

Separate files:

dashy/
├── conf.yml
├── sections/
│   ├── media.yml
│   ├── infrastructure.yml
│   └── monitoring.yml
└── item-icons/
    └── custom-icons...

Secrets Management

Don’t commit API keys:

# Use environment variables
appConfig:
  auth:
    users:
      - user: admin
        hash: ${ADMIN_PASSWORD_HASH}

widgets:
  - type: weather
    options:
      apiKey: ${OPENWEATHER_API_KEY}

Set environment variables:

# docker-compose.yml
services:
  dashy:
    environment:
      - ADMIN_PASSWORD_HASH=5E884898DA...
      - OPENWEATHER_API_KEY=your-api-key

Backup Strategy

Automated backups:

#!/bin/bash
# backup-dashy.sh

BACKUP_DIR=~/dashy-backups
DATE=$(date +%Y%m%d_%H%M%S)

# Create backup
cp ~/dashy/dashy/conf.yml $BACKUP_DIR/conf-$DATE.yml

# Keep only last 30 backups
ls -t $BACKUP_DIR/conf-*.yml | tail -n +31 | xargs rm -f

echo "Backup created: conf-$DATE.yml"

Schedule with cron:

# Daily backup at 3 AM
0 3 * * * /home/user/backup-dashy.sh

Real-World Configuration Examples

Media-Focused Dashboard

sections:
  - name: Media Servers
    icon: fas fa-play-circle
    items:
      - title: Jellyfin
        url: http://jellyfin.local:8096
        icon: hl-jellyfin
        statusCheck: true

      - title: Plex
        url: http://plex.local:32400
        icon: hl-plex
        statusCheck: true

  - name: Media Management
    icon: fas fa-download
    items:
      - title: Sonarr
        url: http://sonarr.local:8989
        icon: hl-sonarr
        statusCheck: true

      - title: Radarr
        url: http://radarr.local:7878
        icon: hl-radarr
        statusCheck: true

      - title: Prowlarr
        url: http://prowlarr.local:9696
        icon: hl-prowlarr
        statusCheck: true

  - name: Download Clients
    icon: fas fa-cloud-download-alt
    items:
      - title: qBittorrent
        url: http://qbit.local:8080
        icon: hl-qbittorrent
        statusCheck: true

Infrastructure Dashboard

sections:
  - name: Virtualization
    items:
      - title: Proxmox
        url: https://proxmox.local:8006
        icon: hl-proxmox
        statusCheck: true
        statusCheckAllowInsecure: true

      - title: TrueNAS
        url: https://truenas.local
        icon: hl-truenas
        statusCheck: true

  - name: Container Management
    items:
      - title: Portainer
        url: https://portainer.local:9443
        icon: hl-portainer
        statusCheck: true

      - title: Docker Registry
        url: https://registry.local
        icon: fab fa-docker
        statusCheck: true

  - name: Monitoring
    items:
      - title: Grafana
        url: https://grafana.local:3000
        icon: hl-grafana
        statusCheck: true

      - title: Uptime Kuma
        url: https://uptime.local:3001
        icon: hl-uptime-kuma
        statusCheck: true

Troubleshooting

Configuration Not Loading

Symptom: Changes to conf.yml don’t appear

Solutions:

# 1. Check YAML syntax
# Use online validator: https://www.yamllint.com/

# 2. Restart container
docker-compose restart dashy

# 3. Check logs for errors
docker logs dashy

# 4. Verify volume mount
docker inspect dashy | grep -A 5 Mounts

Status Checks Failing

Symptom: All services show red/down

Solutions:

# 1. Allow more time
appConfig:
  statusCheckInterval: 120  # Increase interval

# 2. Allow insecure HTTPS
items:
  - title: Service
    statusCheckAllowInsecure: true

# 3. Use correct URL
statusCheckUrl: http://service.local:port/health  # Include port!

Icons Not Displaying

Symptom: Broken image icons

Solutions:

# 1. Verify icon file exists
ls ~/dashy/dashy/item-icons/

# 2. Check volume mount
docker inspect dashy | grep item-icons

# 3. Use built-in icons
icon: hl-jellyfin  # Instead of custom file

Conclusion and Next Steps

Dashy delivers ultimate customization and privacy with its configuration-as-code approach and extensive feature set. You’ve learned:

  • Installing and configuring Dashy via YAML
  • Creating organized service sections
  • Implementing themes and visual customization
  • Adding interactive widgets
  • Setting up status checks and monitoring
  • Enabling authentication and access control

Key Takeaways

  • Configuration-as-code enables version control and sharing
  • Privacy-first design with no external dependencies
  • Extensive theming with 50+ built-in options
  • Powerful widgets for weather, stats, RSS, and more
  • Status monitoring keeps track of service health
  1. Deploy Dashy and create your configuration
  2. Add all services with status checks enabled
  3. Customize theme to your preference
  4. Add widgets for weather, system stats
  5. Version control config in Git
  • Homarr - Alternative dashboard with Docker focus
  • Homepage - Simpler bookmark dashboard
  • Uptime Kuma - Dedicated uptime monitoring
  • Grafana - Advanced metrics visualization

Resources


Document Version: 1.0 Last Updated: December 16, 2025 Based on: Dashy 2.1+ Estimated Completion Time: 50 minutes

Happy dashboarding!