Files
2026-07-12 10:17:17 -04:00

6.0 KiB

name, description, tags
name description tags
homarr-dashboard-setup Deploy, configure, and populate a Homarr dashboard — Docker setup, user management, bulk-adding services via direct SQLite manipulation, layout planning, and troubleshooting.
homarr
dashboard
self-hosted
homelab
sqlite
docker

Homarr Dashboard Setup

Populate a Homarr dashboard with all self-hosted services. Homarr stores everything in SQLite -- apps, items (widgets), layout positions. For bulk operations, direct database manipulation is faster than the web UI.

Quick reference

Path Value
Container homarr
Image ghcr.io/homarr-labs/homarr:latest
Port 8080:7575
Config dir ./appdata (bind mount to /appdata)
DB location <config>/db/db.sqlite
CLI tool docker exec homarr homarr <command>

User management

Create first admin (no users exist)

docker exec homarr homarr recreate-admin --username ray
# Shows a generated password

Set a specific password

docker exec homarr homarr users update-password \
  --username ray \
  --password 'your-password-here'

Reset password to random (all sessions terminated)

docker exec homarr homarr reset-password --username ray

List users

docker exec homarr homarr users list

Database schema (key tables)

app -- service definitions

id          TEXT PRIMARY KEY  -- 25-char alphanumeric ID
name        TEXT              -- display name
description TEXT              -- optional tooltip
icon_url    TEXT              -- URL to icon
href        TEXT              -- click target URL
ping_url    TEXT              -- optional separate status-check URL

item -- widgets on the board

id              TEXT PRIMARY KEY
board_id        TEXT              -- FK to board.id
kind            TEXT              -- 'app' for app widgets, 'clock', 'weather', etc.
options         TEXT              -- JSON: {"json":{"appId":"<app_id>","openInNewTab":true,"showTitle":true}}
advanced_options TEXT             -- usually {"json":{}}

item_layout -- position/size on the grid

item_id    TEXT  -- FK to item.id
section_id TEXT  -- FK to section.id
layout_id  TEXT  -- FK to layout.id
x_offset   INTEGER
y_offset   INTEGER
width      INTEGER
height     INTEGER

board -- the dashboard page

id       TEXT PRIMARY KEY
name     TEXT    -- unique name

section -- a column/grid area on a board

id       TEXT PRIMARY KEY
board_id TEXT -- FK to board.id

section_layout -- which layout template a section uses

id         TEXT PRIMARY KEY
section_id TEXT  -- FK to section.id

Bulk-adding services via SQLite

When adding 10+ services, direct SQLite inserts beat the UI. Steps:

1. Discover running services and their ports

docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}'
ss -tlnp | grep LISTEN

2. Get board/section/layout IDs

SELECT id, name FROM board;
SELECT id, board_id FROM section;
SELECT id, section_id FROM section_layout;

3. Icon URLs

Use the Homarr dashboard-icons repository:

https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/<name>.png
https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/svg/<name>.svg

Common icons: immich.png, home-assistant.png, paperless-ngx.png, plex.png, audiobookshelf.png, mealie.png, qbittorrent.png, pihole.png, portainer.png, uptime-kuma.png, scrutiny.png, vaultwarden.png, pocketbase.png, glitchtip.png, searxng.png, sunshine.png

For missing icons, fall back to chrome-beta.png or another generic icon.

4. Generate IDs

Homarr uses ~25-char alphanumeric IDs. Generate them in Python:

import secrets
def gen_id():
    return secrets.token_urlsafe(16)[:25].replace('-','0').replace('_','1')

5. Insert apps

INSERT INTO app (id, name, icon_url, href) VALUES
  ('<id>', '<Name>', '<icon_url>', '<href>');

6. Insert items (one per app)

INSERT INTO item (id, board_id, kind, options, advanced_options) VALUES
  ('<item_id>', '<board_id>', 'app',
   '{"json":{"appId":"<app_id>","openInNewTab":true,"showTitle":true}}',
   '{"json":{}}');

7. Insert layout records

INSERT INTO item_layout (item_id, section_id, layout_id, x_offset, y_offset, width, height) VALUES
  ('<item_id>', '<section_id>', '<layout_id>', 0, 0, 1, 1);

8. Restart container

docker restart homarr

9. Verify

sqlite3 <db_path> \
  "SELECT l.x_offset, l.y_offset, l.width, l.height, a.name
   FROM item_layout l
   JOIN item i ON l.item_id = i.id
   LEFT JOIN app a ON json_extract(i.options, '$.json.appId') = a.id
   ORDER BY l.y_offset, l.x_offset;"

Pitfalls

  • DB owned by root: The SQLite file is created by the Docker container and owned by root:root. Use sudo or docker exec for DB access.
  • Duplicate apps: Homarr auto-discovers Docker containers and inserts into the app table. You may see duplicate entries -- e.g. the auto-discovered homarr + your manually created Homarr. Clean up old items/layouts if needed.
  • Layout columns are x_offset, y_offset: Not x/y. Forgetting this causes silent misplacement.
  • IDs must be unique across item and app tables: The random generator collisions are astronomically unlikely but verify if you suspect overlap.
  • Restart required: Direct DB writes are not live-reloaded. Always docker restart homarr after inserts.
  • Container restarts reset uncommitted changes: The DB is on a bind mount, but if your insert script hasn't committed before the container exits, changes are lost. Use explicit connection.commit().
  • json_extract in joins: When joining item to app, use json_extract(i.options, '$.json.appId') to extract the app reference from the item's JSON options field.
  • Nginx proxy vs direct access: For services behind nginx on the same host, use 127.0.0.1:<port>. For services reaching other hosts or directly exposed, use 192.168.50.98:<port>.