How to Self-Host Homepage with Docker Compose: Modern, Highly-Customizable YAML Dashboard for Homelabs & DevOps

Cloud-Architektin konfiguriert ein modernes Homelab-Dashboard in Homepage mit Live-Metriken an einem Curved-Monitor
Organize your self-hosted infrastructure with Homepage: fast, declarative YAML dashboard with live Docker container stats and service integration widgets.

As self-hosted environments grow from a single media server into multi-node homelabs and edge clusters, organizing access to dozens of running services becomes an operational challenge. Remembering port numbers, internal IP addresses, and DNS subdomains across separate Docker hosts, hypervisors, and storage appliances quickly leads to browser tab chaos. Without a centralized application gateway, finding services like Nextcloud, Vaultwarden, Grafana, or Proxmox requires rummaging through browser bookmarks or terminal command histories.

Early self-hosters turned to first-generation application dashboards such as Heimdall, Flame, or Organizr. While visually appealing, many of these legacy tools suffer from noticeable drawbacks: they require manual UI form inputs for every new service, rely on internal databases that complicate backup automation, lack native Docker socket auto-discovery, and impose noticeable resource bloat. Conversely, heavy configurable dashboards like Dashy offer extensive feature sets but can suffer from steep configuration complexity and sluggish client-side rendering performance.

Homepage (developed by the gethomepage team) has rapidly emerged as the gold standard for modern infrastructure dashboards. Built with Next.js and Tailwind CSS, Homepage is a blazing-fast, statically compiled, highly responsive application dashboard configured entirely through declarative YAML files. It requires no database, boots in milliseconds, and features first-class Docker socket integration. It automatically detects container lifecycles, displays real-time CPU and memory usage, and connects directly with over 100 native service API widgets (including Pi-hole, AdGuard Home, Proxmox VE, TrueNAS, Plex, and Uptime Kuma) without requiring custom code.

In this comprehensive guide, you will learn how to deploy Homepage in Docker Compose, configure a secure read-only Docker socket proxy, structure declarative YAML configurations, integrate real-time service widgets, and implement security hardening for production peace of mind.

Architecture: Declarative Configuration and Service Discovery

Homepage’s design philosophy separates operational state from configuration. Rather than maintaining state inside an opaque database blob, Homepage reads a clean set of YAML files from a mounted configuration folder on every reload. Changes made to your YAML files or Docker container labels are immediately reflected in the browser without container restarts.

The following diagram illustrates how Homepage communicates with local container engines, remote API endpoints, and client web browsers:

+-----------------------------------------------------------------------+
|                    Client Browser / Admin Device                      |
|                       (HTTPS / Port 443 / 3000)                       |
+-----------------------------------+-----------------------------------+
                                    |
                            (Secure Web Traffic)
                                    v
+-----------------------------------------------------------------------+
|                      Reverse Proxy (Caddy / Traefik)                  |
|                - TLS Termination, Let's Encrypt SSL, SSO              |
+-----------------------------------+-----------------------------------+
                                    |
                            (Internal Network)
                                    v
+-----------------------------------------------------------------------+
|                      Homepage Container (Docker)                      |
|  +-----------------------------------------------------------------+  |
|  |                 Next.js Frontend & API Aggregator               |  |
|  |   - Server-Side Rendering (SSR) for Instant Load Times          |  |
|  |   - Live Background Polling of Remote Widgets                   |  |
|  +----------------+-------------------------------+----------------+  |
|                   |                               |                   |
| (Mount: /app/config)                              | (REST / Metrics)  |
|                   v                               v                   |
|  +--------------------------------+   +----------------------------+  |
|  |     Declarative YAML Config    |   |     Integrated Services    |  |
|  |   - settings.yaml (Layout)     |   |   - Pi-hole / AdGuard DNS  |  |
|  |   - services.yaml (App Cards)  |   |   - Proxmox VE Nodes       |  |
|  |   - widgets.yaml (Weather/HW)  |   |   - TrueNAS Storage Pools  |  |
|  |   - docker.yaml (Sockets)      |   |   - Uptime Kuma Statuses   |  |
|  +--------------------------------+   +----------------------------+  |
|                   |                                                   |
|                   v                                                   |
|  +-----------------------------------------------------------------+  |
|  |           Docker Socket Proxy (Tecativa / Wollomatic)           |  |
|  |   - Read-Only Security Boundary on /var/run/docker.sock         |  |
|  |   - Filters Out Write / Delete / Exec Capabilities              |  |
|  +--------------------------------+--------------------------------+  |
+-----------------------------------|-----------------------------------+
                                    v
                 [ Local Docker Daemon Engine (/var/run) ]

Key highlights of this architecture include:

  • Zero Database Overhead: Backing up your dashboard requires nothing more than copying your /config folder or version-controlling it in Git. There are no database tables to corrupt or migrate.
  • Hardened Socket Isolation: Directly mounting /var/run/docker.sock into web applications presents severe privilege escalation risks. By interposing a read-only Docker socket proxy, Homepage can query container states and resource metrics while remaining strictly blocked from modifying or starting containers.
  • Unified API Aggregation: Instead of loading heavy third-party JavaScript tracking scripts inside client browsers, Homepage queries remote API endpoints server-side and serves pre-formatted, sanitized widget data directly to the user interface.

Prerequisites and Host Directory Preparation

Before launching the deployment, ensure your host environment meets the following requirements:

  • A modern Linux server (Ubuntu 24.04/22.04 LTS, Debian 12, or AlmaLinux 9).
  • Docker Engine v24.0+ and Docker Compose v2.20+ installed.
  • A dedicated directory for Homepage configuration files and custom icons.

Create the directory structure on your host filesystem:

sudo mkdir -p /opt/homepage/config
sudo mkdir -p /opt/homepage/config/icons

# Ensure proper permissions for container execution
sudo chown -R 1000:1000 /opt/homepage
chmod -R 750 /opt/homepage
cd /opt/homepage

Production Docker Compose Configuration

To adhere to security best practices, we deploy Homepage alongside docker-socket-proxy. This proxy restricts the Docker API, exposing only read-only endpoints (/containers/json, /version) while blocking destructive operations.

Create /opt/homepage/compose.yaml:

services:
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    restart: unless-stopped
    ports:
      # Bind to localhost; route via reverse proxy
      - "127.0.0.1:3000:3000"
    volumes:
      # Declarative YAML configuration directory
      - /opt/homepage/config:/app/config
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=UTC
    depends_on:
      docker-proxy:
        condition: service_started
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1024M
        reservations:
          memory: 256M
    security_opt:
      - no-new-privileges:true
    networks:
      - homepage-net

  docker-proxy:
    image: ghcr.io/tecnativa/docker-socket-proxy:latest
    container_name: homepage-docker-proxy
    restart: unless-stopped
    environment:
      # Grant read-only access to container status and information
      - CONTAINERS=1
      - INFO=1
      - VERSION=1
      # Deny all write, delete, and execution endpoints
      - POST=0
      - DELETE=0
      - BUILD=0
      - COMMIT=0
      - EXEC=0
      - VOLUMES=0
      - NETWORKS=0
    volumes:
      # Mount host docker daemon into proxy
      - /var/run/docker.sock:/var/run/docker.sock:ro
    security_opt:
      - no-new-privileges:true
    networks:
      - homepage-net

networks:
  homepage-net:
    driver: bridge

Launch the stack:

docker compose up -d

Check the container logs to ensure clean initialization:

docker compose logs -f homepage

Configuring Declarative YAML Files

Upon initial startup, Homepage automatically populates /opt/homepage/config with default configuration templates. We will customize four core files: settings.yaml, docker.yaml, widgets.yaml, and services.yaml.

1. settings.yaml: Visual Layout and Theme Settings

Edit /opt/homepage/config/settings.yaml to establish dashboard layout, appearance, and search provider:

---
title: "Operations Hub"
favicon: https://raw.githubusercontent.com/gethomepage/homepage/main/public/favicon.ico
background:
  opacity: 50
theme: dark
color: slate
layout:
  Core Infrastructure:
    style: row
    columns: 3
  Monitoring & Observability:
    style: row
    columns: 3
  Media & Storage:
    style: row
    columns: 2

headerStyle: clean
statusStyle: dot

2. docker.yaml: Connecting to the Docker Socket Proxy

Configure Homepage to connect to the internal socket proxy in /opt/homepage/config/docker.yaml:

---
my-docker:
  host: docker-proxy
  port: 2375

Because both containers reside on the shared homepage-net network, Homepage connects securely to the proxy over unencrypted HTTP on port 2375 inside the isolated Docker network, while the host Docker socket remains completely isolated from external exposure.

3. widgets.yaml: Top Bar Diagnostic Widgets

Configure top-level metrics in /opt/homepage/config/widgets.yaml to display greeting, system resources, and search:

---
- greeting:
    text_size: xl
    text: "DevOps & Homelab Operations"

- resources:
    cpu: true
    memory: true
    disk: /app/config
    cputemp: false
    units: metric

- search:
    provider: duckduckgo
    target: _blank

4. services.yaml: Service Cards with Live API Widgets

This is where Homepage truly shines. In /opt/homepage/config/services.yaml, define your applications grouped by category. Each service card can be enhanced with container monitoring and real-time status indicators:

---
- Core Infrastructure:
    - Dockge:
        icon: dockge.png
        href: "https://dockge.yourdomain.com"
        description: "Docker Compose Stack Manager"
        container: dockge
        server: my-docker
        widget:
          type: customapi
          url: "http://dockge:5001/api/health"
          mappings:
            - field: ok
              label: Status

    - Vaultwarden:
        icon: vaultwarden.png
        href: "https://vault.yourdomain.com"
        description: "Zero-Knowledge Password Vault"
        container: vaultwarden
        server: my-docker

- Monitoring & Observability:
    - Uptime Kuma:
        icon: uptime-kuma.png
        href: "https://status.yourdomain.com"
        description: "Service Availability & SLA Tracking"
        container: uptime-kuma
        server: my-docker
        widget:
          type: uptimekuma
          url: "http://uptime-kuma:3001"
          slug: default

    - ChangeDetection:
        icon: changedetection.png
        href: "https://changedetection.yourdomain.com"
        description: "Web & API Change Monitor"
        container: changedetection
        server: my-docker

- Network & Security:
    - AdGuard Home:
        icon: adguard-home.png
        href: "https://adguard.yourdomain.com"
        description: "Network-Wide DNS Sinkhole"
        widget:
          type: adguard
          url: "http://192.168.1.5:80"
          username: admin
          password: YourAdguardPassword

Save the file and refresh your browser. Homepage immediately renders a stunning, dark-mode dashboard displaying live container CPU usage, memory consumption, DNS query stats from AdGuard, and active service statuses.

Integrating Proxmox VE and Storage Appliances

Beyond container-level monitoring, Homepage excels at centralizing bare-metal and hypervisor metrics. For administrators running Proxmox Virtual Environment (PVE), you can display active virtual machine counts, LXC container allocations, CPU core loads, and cluster memory usage directly on your primary node card. To achieve this without granting root hypervisor access, create a dedicated Proxmox API token with PVEAuditor read-only privileges. In services.yaml, supply the node endpoint, token ID, and secret. Homepage will periodically poll the Proxmox REST API asynchronously, ensuring your dashboard presents live node utilization without incurring virtualization lag.

Similarly, storage appliances like TrueNAS SCALE or TrueNAS CORE can expose ZFS storage pool health, allocated capacity, and dataset compression ratios. By configuring TrueNAS API keys within Homepage’s widget definitions, system administrators can instantly spot pool degradation or capacity warnings before hard drives suffer catastrophic hardware failure.

Automatic Docker Service Discovery via Labels

If you prefer not to edit services.yaml every time you spin up a new container, Homepage supports automatic container discovery via Docker labels. Simply add the following labels to any service in your Compose files:

services:
  whoami:
    image: traefik/whoami
    container_name: whoami
    labels:
      - "gethomepage.name=WhoAmI Service"
      - "gethomepage.group=Development"
      - "gethomepage.icon=whoami.png"
      - "gethomepage.href=https://whoami.yourdomain.com"
      - "gethomepage.description=HTTP Request Header Debugger"

When the container starts, the socket proxy informs Homepage, which automatically creates a card under the “Development” group without editing a single configuration file.

Production Hardening and Reverse Proxy Setup

Because Homepage aggregates links to all your internal tools, securing the dashboard is non-negotiable. Follow these production hardening measures:

1. Terminate TLS with a Reverse Proxy (Caddy)

Bind Homepage strictly to 127.0.0.1:3000 and enforce automatic HTTPS using Caddy:

hub.yourdomain.com {
    reverse_proxy 127.0.0.1:3000 {
        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }

    # Restrict to internal management subnets or VPN
    @internal {
        remote_ip 10.0.0.0/8 192.168.1.0/24 100.64.0.0/10
    }
    handle @internal {
        # Allow internal network access
    }

    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
}

2. Gate Behind Single Sign-On (Authentik or Cloudflare Access)

Since Homepage does not have built-in multi-user database authentication by design, place it behind an identity-aware proxy such as Authentik or Cloudflare Zero Trust Access. This guarantees that only authorized administrators with active MFA can access the dashboard.

Troubleshooting Common Homepage Issues

Even with clean YAML files, configuration mistakes can occur. Here are three common issues and their tested solutions:

1. Widget Displays “API Error” or 401 Unauthorized

Symptom: A service card appears, but the embedded widget (e.g., Pi-hole or AdGuard) displays an orange “API Error” badge.

Root Cause: Incorrect credentials, missing API tokens, or network unreachability between the Homepage container and the target service.

Fix: Verify network reachability from inside the Homepage container using curl:

docker exec -it homepage curl -I http://192.168.1.5:80

Ensure that credentials in services.yaml match the target API requirements (e.g., for Pi-hole v5/v6, verify whether an API token or web password is required by checking Homepage’s official widget documentation).

2. Docker Stats Not Appearing on Cards

Symptom: Container status dots remain grey, and CPU/memory stats do not populate.

Root Cause: The container name in services.yaml does not match the exact container_name running in Docker, or the server reference does not match docker.yaml.

Fix: Run docker ps --format "{{.Names}}" to inspect exact container identifiers. Ensure your service entry explicitly includes both server: my-docker and container: exact_name.

3. YAML Indentation Syntax Errors

Symptom: The web page fails to load, showing a red “YAML Parse Error” traceback.

Root Cause: YAML strictly forbids tab characters and requires exact two-space indentations. Accidental tabs or mismatched dashes break the parser.

Fix: Validate your configuration files on the host using Python’s built-in YAML parser or yamllint:

python3 -c "import yaml; yaml.safe_load(open('/opt/homepage/config/services.yaml'))"
echo "YAML syntax is valid!"

Conclusion and Next Steps

Homepage provides the ultimate front door for modern self-hosted infrastructure. By combining declarative YAML configuration, secure read-only Docker socket proxying, and comprehensive real-time widget support, Homepage delivers unmatched visual elegance without sacrificing system security or performance.

To further enhance your centralized operations hub, consider pairing Homepage with:

  • Dockge: Jump directly from Homepage into interactive Compose stack editing and live terminal inspection.
  • Git Version Control: Store your /opt/homepage/config directory in a private Git repository to track layout updates and enable one-command disaster recovery.
  • Uptime Kuma: Embed live status badges on every service card to maintain real-time visibility into infrastructure availability.