Full configuration export/import system for Homarr with excellent DX: - Export/import boards, apps, integrations (with re-encrypted secrets), users (with bcrypt hashes), groups (with permissions and memberships), search engines, and server settings - Homepage services.yaml import with widget-type mapping - Generic resolveEntities() utility eliminates per-entity boilerplate - Declarative entity-fields.ts: adding a new user preference requires only one line change (no export/import/schema edits needed) - User schema uses .catchall(z.unknown()) for forward-compatible prefs - groupByKey() utility replaces manual Map-building - CONFIG_ENTITY_KEYS as single source of truth for entity metadata - Reuse existing entities (apps by name+icon+href, integrations by kind+name+url, users by email, groups by name, boards by name) - Skip duplicates with warnings rather than failing - Onboarding flow skips user creation step when config includes users - Reuse existing admin group during onboarding after config import
154 lines
5.6 KiB
YAML
154 lines
5.6 KiB
YAML
# Homarr Docker label discovery example.
|
|
# This compose file demonstrates all supported label combinations for testing.
|
|
# Prerequisites: Homarr with Docker socket mounted.
|
|
# In Manage → Tools → Import/Export, use the Docker Discovery panel to scan.
|
|
|
|
services:
|
|
# ─── Full Homarr labels (all fields) ─────────────────────────────────────────
|
|
sonarr:
|
|
image: lscr.io/linuxserver/sonarr:latest
|
|
container_name: homarr-sonarr
|
|
ports:
|
|
- "8989:8989"
|
|
restart: unless-stopped
|
|
labels:
|
|
homarr.name: "Sonarr"
|
|
homarr.group: "Media"
|
|
homarr.href: "http://sonarr:8989"
|
|
homarr.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/sonarr.svg"
|
|
homarr.description: "TV series management"
|
|
homarr.ping: "http://sonarr:8989/ping"
|
|
homarr.id: "sonarr-main"
|
|
homarr.board: "homelab"
|
|
homarr.integration: "sonarr"
|
|
homarr.widget: "downloads"
|
|
|
|
radarr:
|
|
image: lscr.io/linuxserver/radarr:latest
|
|
container_name: homarr-radarr
|
|
ports:
|
|
- "7878:7878"
|
|
restart: unless-stopped
|
|
labels:
|
|
homarr.name: "Radarr"
|
|
homarr.group: "Media"
|
|
homarr.href: "http://radarr:7878"
|
|
homarr.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/radarr.svg"
|
|
homarr.description: "Movie management"
|
|
homarr.ping: "http://radarr:7878/ping"
|
|
homarr.integration: "radarr"
|
|
homarr.widget: "downloads"
|
|
|
|
# ─── Minimal Homarr labels (required fields only) ────────────────────────────
|
|
portainer:
|
|
image: portainer/portainer-ce:latest
|
|
container_name: homarr-portainer
|
|
ports:
|
|
- "9000:9000"
|
|
restart: unless-stopped
|
|
labels:
|
|
homarr.name: "Portainer"
|
|
homarr.group: "Infrastructure"
|
|
homarr.href: "http://portainer:9000"
|
|
|
|
# ─── Homepage labels only (migration scenario) ───────────────────────────────
|
|
grafana:
|
|
image: grafana/grafana:latest
|
|
container_name: homarr-grafana
|
|
ports:
|
|
- "3000:3000"
|
|
restart: unless-stopped
|
|
labels:
|
|
homepage.name: "Grafana"
|
|
homepage.group: "Monitoring"
|
|
homepage.href: "http://grafana:3000"
|
|
homepage.icon: "grafana"
|
|
homepage.description: "Metrics and dashboards"
|
|
|
|
prometheus:
|
|
image: prom/prometheus:latest
|
|
container_name: homarr-prometheus
|
|
ports:
|
|
- "9090:9090"
|
|
restart: unless-stopped
|
|
labels:
|
|
homepage.name: "Prometheus"
|
|
homepage.group: "Monitoring"
|
|
homepage.href: "http://prometheus:9090"
|
|
homepage.icon: "prometheus"
|
|
|
|
# ─── Both label sets (homarr takes priority) ─────────────────────────────────
|
|
qbittorrent:
|
|
image: lscr.io/linuxserver/qbittorrent:latest
|
|
container_name: homarr-qbittorrent
|
|
ports:
|
|
- "8080:8080"
|
|
restart: unless-stopped
|
|
labels:
|
|
homarr.name: "qBittorrent"
|
|
homarr.group: "Downloads"
|
|
homarr.href: "http://qbittorrent:8080"
|
|
homarr.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/qbittorrent.svg"
|
|
homarr.description: "Torrent client"
|
|
homarr.ping: "http://qbittorrent:8080"
|
|
homarr.integration: "qBittorrent"
|
|
homarr.widget: "downloads"
|
|
homepage.name: "qBittorrent (homepage)"
|
|
homepage.group: "Downloads (homepage)"
|
|
homepage.href: "http://qbittorrent:8080/homepage"
|
|
homepage.icon: "qbittorrent"
|
|
homepage.description: "Should be ignored"
|
|
|
|
# ─── Hidden container (excluded from discovery) ──────────────────────────────
|
|
watchtower:
|
|
image: containrrr/watchtower:latest
|
|
container_name: homarr-watchtower
|
|
restart: unless-stopped
|
|
labels:
|
|
homarr.hide: "true"
|
|
homarr.name: "Watchtower"
|
|
homarr.group: "Infrastructure"
|
|
homarr.href: "http://watchtower:8080"
|
|
|
|
# ─── Targeting a specific board ──────────────────────────────────────────────
|
|
traefik:
|
|
image: traefik:latest
|
|
container_name: homarr-traefik
|
|
ports:
|
|
- "80:80"
|
|
- "8081:8080"
|
|
restart: unless-stopped
|
|
labels:
|
|
homarr.name: "Traefik"
|
|
homarr.group: "Networking"
|
|
homarr.href: "http://traefik:8080"
|
|
homarr.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/traefik.svg"
|
|
homarr.board: "networking"
|
|
homarr.ping: "http://traefik:8080/ping"
|
|
|
|
# ─── Custom external ID ──────────────────────────────────────────────────────
|
|
jellyfin:
|
|
image: jellyfin/jellyfin:latest
|
|
container_name: homarr-jellyfin
|
|
ports:
|
|
- "8096:8096"
|
|
restart: unless-stopped
|
|
labels:
|
|
homarr.name: "Jellyfin"
|
|
homarr.group: "Media"
|
|
homarr.href: "http://jellyfin:8096"
|
|
homarr.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/jellyfin.svg"
|
|
homarr.description: "Media streaming"
|
|
homarr.ping: "http://jellyfin:8096/health"
|
|
homarr.id: "jellyfin-production"
|
|
homarr.integration: "jellyfin"
|
|
homarr.widget: "mediaServer"
|
|
|
|
# ─── No discovery labels (should be completely ignored) ──────────────────────
|
|
redis:
|
|
image: redis:alpine
|
|
container_name: homarr-redis
|
|
ports:
|
|
- "6379:6379"
|
|
restart: unless-stopped
|