Compare commits

..
581 changed files with 44134 additions and 9495 deletions

No files matched your search

+2 -2
View File
@@ -1,6 +1,6 @@
---
name: documentation-sync
description: Keep Homarr's Fumadocs documentation aligned with user-facing code. Use when adding or changing integrations, widgets, APIs, environment variables, CLI commands, authentication, permissions, cron jobs, settings, or UI behavior that users must understand.
description: Keep Homarr's Docusaurus documentation aligned with user-facing code. Use when adding or changing integrations, widgets, APIs, environment variables, CLI commands, authentication, permissions, cron jobs, settings, or UI behavior that users must understand.
---
# Documentation Sync
@@ -48,4 +48,4 @@ For a widget:
2. Keep names, defaults, paths, screenshots, links, and prerequisites consistent with code.
3. Update every affected page and remove superseded guidance.
4. Run the narrowest useful docs validation. Use `pnpm turbo build --filter=@homarr/docs` when links, MDX, generated definitions, or navigation can fail; otherwise run the docs package formatter on touched files.
5. Treat broken links and anchors as failures; run `pnpm --filter @homarr/docs validate:links` after the static build.
5. Treat broken links and anchors as failures; Docusaurus checks them strictly.
+6 -6
View File
@@ -1,20 +1,20 @@
---
name: homarr-custom-widget
description: Author, validate, preview, test, install, or configure API-backed Homarr Custom JSX v2 widgets.
description: Author, validate, preview, test, install, or configure static or API-backed Homarr Custom JSX v2 widgets.
---
# Homarr Custom Widget
Author one widget or a coordinated set of widgets. Load only needed release-matched context. Run lifecycle tools alone; independent reads may run together. For a set, research once and finish each widget's validation, evidence, and persistence before the next.
Author one widget or a coordinated set. Load release-matched context on demand. Run lifecycle tools alone; independent reads may run together. Finish each widget's validation, evidence, and persistence before the next.
1. Read primary API documentation. Use web search when documentation is not supplied or may have changed.
2. Create credential-free definitions with keyed `sources`, `requests`, optional `options`, and safe JSX `template`.
1. For connected widgets, read primary API documentation; use web search when it is missing or may have changed.
2. Create credential-free definitions with keyed `sources`, `requests`, optional `options`, and safe JSX `template`. Static widgets use empty `sources` and `requests`; an API is optional.
3. While drafting, use `customWidget_validateTemplate` for focused JSX diagnostics without resending the manifest.
4. Send the definition once to `customWidget_previewCreate` and test its queries/actions. For a JSX-only fix, validate, call `customWidget_previewReviseTemplate` with its session, and retest; it inherits the manifest and resets evidence. Create a preview only for source/request/option changes.
5. Configure deployment-specific source URLs and credentials through Homarr; never repeat plaintext.
6. Persist each exact final tested preview with `customWidget_createFromPreview`. Do not resend a large definition through `customWidget_create` when a preview session is available.
Treat a supplied sample or successful preview response as the binding contract. Render every core requested field, guard optional arrays and nested values before indexing, and do not silently drop returned items. Humanize numeric enums with indexed literal label arrays, omit absent numeric values instead of inventing zero, and label timestamp timezones. Give recoverable load errors and empty states a clear refresh or retry path.
Use supplied samples or preview responses as the data contract. Render requested fields and all returned items; guard optional nested values. Humanize numeric enums with label arrays, omit absent numbers, and label timestamp timezones. Give load errors and empty states a refresh or retry path.
Use `{option:name}` or `$option` for saved options. Use `{param:name}` or `$param` for values supplied by `SubFetch`, `ActionButton`, or `ToggleSwitch`. Load queries cannot use invocation parameters. Render load queries from `data` and `status` with `RefreshButton`; reserve `SubFetch` for manual parameterized queries. Templates read `data`, `status`, `options`, and temporary `inputs`.
@@ -26,7 +26,7 @@ Plan capabilities. Use one `customWidget_findComponents` search per job. Batch s
Do not simplify a useful workflow merely because the template is interpreted. Freely compose any supported installed components with multiple sources, requests, options, `choicesFrom`, bound filters, charts, responsive detail areas, manual queries, and safe actions when they improve the user's job. Complexity must remain purposeful rather than decorative.
Polish with a divided list or responsive media grid. Make one metric/action asymmetrically primary; keep headers compact, identity/state clear, metadata quiet, and one badge. At base artwork fills its row and caps above xs; never combine full-width media and nowrap.
Use divided lists or responsive media grids, one primary metric/action, compact headers, quiet metadata, and one badge. Full-width artwork wraps at base and caps above xs.
Make initial states actionable and wrap variable labels/values on narrow tiles. Do not use an unlabeled decorative icon as an empty state.
@@ -13,7 +13,7 @@ interface HomarrCustomWidgetV2 {
}
```
The object key `default` is the required source ID; `default` is not a property on a source. Source properties are `name?`, `baseUrl`, `networkScope`, and `auth?`:
Static widgets use empty `sources` and `requests`. Each request must resolve to a defined source; omitting `source` uses `default` only when that ID exists. Source properties are `name?`, `baseUrl`, `networkScope`, and `auth?`:
```json
{
@@ -1,5 +1,7 @@
# Security
Private access includes LAN, Docker DNS, and Tailscale CGNAT addresses. Loopback means the Homarr server or container, not the viewer's browser.
All requests use Homarr's protected server executor. Source origin, network scope, DNS, redirects, SSRF, rate limits, permissions, size limits, timeouts, and encrypted credential injection remain enforced.
The JSX interpreter blocks imports, hooks, refs, raw event callbacks, browser requests, eval, arbitrary functions, prototype access, unsafe URLs, global CSS escape, arbitrary portals, bigint, statement blocks, IIFEs, and recursion. Regex literals must be bounded and reject backreferences, lookbehind, nested quantifiers, excessive length, and unsupported flags.
+6
View File
@@ -93,3 +93,9 @@ HOMARR_WEBSITE_URL=https://homarr.dev
# Whether demo mode is read-only. Defaults to true (the public demo blocks all mutations).
# Set to false for writable preview deployments so the demo user can modify the dashboard.
# DEMO_READ_ONLY=false
# Persistent trusted-widget build cache; activated artifacts are also retained in the database.
# Defaults to /appdata/custom-widgets in production and ./appdata/custom-widgets in development.
# CUSTOM_WIDGET_PACKAGE_PATH=/appdata/custom-widgets
# Maximum concurrently active trusted widget server artifacts per Homarr process.
# CUSTOM_WIDGET_MAX_SERVER_PROCESSES=16
+1 -5
View File
@@ -37,16 +37,12 @@ jobs:
run: pnpm turbo build --filter=@homarr/docs
env:
CI: "true"
- name: Validate exported links and search
run: |
pnpm --filter @homarr/docs validate:links
pnpm --filter @homarr/docs verify:search
- name: Setup Pages
uses: actions/configure-pages@v6
- name: Upload pages artifact
uses: actions/upload-pages-artifact@v5
with:
path: "apps/docs/out"
path: "apps/docs/build"
deploy:
runs-on: ubuntu-latest
@@ -0,0 +1,58 @@
name: "[Docs] Algolia Recrawl"
on:
workflow_run:
workflows: ["[Deployment] Documentation"]
types: [completed]
branches: [dev]
workflow_dispatch:
permissions:
contents: read
jobs:
recrawl:
if: >-
${{
(github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event != 'pull_request')
|| github.event_name == 'workflow_dispatch'
}}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- name: Setup
uses: ./tooling/github/setup
- name: Check Algolia crawler secrets
run: |
missing=0
for secret in ALGOLIA_CRAWLER_ID ALGOLIA_CRAWLER_USER_ID ALGOLIA_CRAWLER_API_KEY; do
if [ -z "${!secret}" ]; then
echo "::warning::Missing repository secret: $secret"
missing=1
fi
done
if [ "$missing" -eq 1 ]; then
echo "Add crawler secrets to enable automatic recrawls."
exit 1
fi
env:
ALGOLIA_CRAWLER_ID: ${{ secrets.ALGOLIA_CRAWLER_ID }}
ALGOLIA_CRAWLER_USER_ID: ${{ secrets.ALGOLIA_CRAWLER_USER_ID }}
ALGOLIA_CRAWLER_API_KEY: ${{ secrets.ALGOLIA_CRAWLER_API_KEY }}
- name: Wait for GitHub Pages to serve the new deployment
run: sleep 60
- name: Trigger Algolia DocSearch recrawl
uses: cssnr/algolia-crawler-action@v2
with:
crawler_id: ${{ secrets.ALGOLIA_CRAWLER_ID }}
crawler_user_id: ${{ secrets.ALGOLIA_CRAWLER_USER_ID }}
crawler_api_key: ${{ secrets.ALGOLIA_CRAWLER_API_KEY }}
- name: Verify search index
working-directory: apps/docs
run: pnpm verify:search
@@ -33,7 +33,7 @@ jobs:
- name: Commit updated contributors
uses: EndBug/add-and-commit@v10
with:
add: "apps/docs/public"
add: "apps/docs/static"
default_author: github_actor
message: "chore(docs): update contributors"
push: true
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
- name: Commit updated spec
uses: EndBug/add-and-commit@v10
with:
add: "apps/docs/public/api/"
add: "apps/docs/static/api/"
default_author: github_actor
message: "chore(docs): update OpenAPI spec"
push: true
+1
View File
@@ -69,6 +69,7 @@ e2e/shared/tmp
#personal backgrounds
apps/nextjs/public/images/background.png
apps/nextjs/public/__widget-editor/
+3 -3
View File
@@ -6,7 +6,7 @@
homarr/
├── apps/
│ ├── nextjs/ # Main Next.js application (port 3000)
│ ├── docs/ # Next.js + Fumadocs documentation site (@homarr/docs)
│ ├── docs/ # Docusaurus 3 documentation site (@homarr/docs)
│ ├── tasks/ # Cron-job initialization and scheduling runtime
│ ├── websocket/ # Standalone tRPC WebSocket server (port 3001)
│ └── workshop/ # Go/PocketBase Workshop service
@@ -57,7 +57,7 @@ homarr/
## Documentation Sync
The documentation site lives at `apps/docs/` (Next.js + Fumadocs, `@homarr/docs`).
The documentation site lives at `apps/docs/` (Docusaurus 3, `@homarr/docs`).
When modifying user-facing code, you MUST also update the corresponding documentation:
@@ -75,7 +75,7 @@ When modifying user-facing code, you MUST also update the corresponding document
- `pnpm dev:cli -- dev` — run the developer CLI without installing a global binary
- `pnpm db:seed` — seed default database data explicitly
- `pnpm docker:dev:up` — start the Redis development service in the background
- `pnpm dev:docs` — Fumadocs site only
- `pnpm dev:docs` — Docusaurus docs site only
- `pnpm turbo build` — build all packages
- `pnpm turbo build --filter=@homarr/docs` — build docs only
- `pnpm turbo typecheck` — typecheck all packages
+1 -2
View File
@@ -13,7 +13,6 @@
# next.js
/.next/
/out/
/.source/
# production
/build
@@ -56,4 +55,4 @@ static/data/configs
# CI Stuff
screenshots
test-results
test-results
-18
View File
@@ -1,18 +0,0 @@
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
<!-- END:nextjs-agent-rules -->
## Fumadocs workflow
- Start with `README.md`, `src/lib/source.ts`, `source.config.ts`, and the matching route under `src/app/`.
- Read current [Fumadocs documentation](https://fumadocs.dev/docs) with Context7 before changing framework APIs. Check the installed version and types; latest examples may use a different search adapter.
- Preserve static export: search uses `staticGET` with the matching static client. Do not introduce a request-time search server into this app.
- Keep integration/widget metadata in the existing typed definitions. Check both rendered HTML and processed Markdown when changing MDX components; JSX alone does not guarantee readable search or AI output.
- Run the README validation commands after content or navigation changes. Search results and table-of-contents links must resolve to rendered anchors.
- Kapa is an independent hosted assistant. Keep its keyboard shortcut disabled so it does not override docs search; follow the README for its build configuration and crawler setup.
-1
View File
@@ -1 +0,0 @@
@AGENTS.md
-37
View File
@@ -1,37 +0,0 @@
# Homarr Documentation
## Register
product
## Users
People who run Homarr, administrators configuring self-hosted infrastructure, and contributors extending Homarr. They arrive with a concrete task such as installing Homarr, connecting a service, configuring a widget, managing users, or building a custom widget, and need an answer they can scan and apply quickly.
## Product Purpose
The documentation is the complete, authoritative operating guide for Homarr. It keeps setup steps, configuration contracts, screenshots, generated integration and widget metadata, API references, and Workshop tooling next to the application code. Success means a reader can find the right page quickly, understand the next action, copy reliable instructions, and verify the result without searching elsewhere.
## Brand Personality
Focused, dependable, and approachable. The writing is direct and practical. The interface should feel calm and familiar during long technical sessions while retaining Homarr's red identity.
## Anti-references
- Generic marketing layouts that replace Homarr's product identity with unrelated slogans or decorative conversion copy.
- Decorative dashboard aesthetics that compete with reading, including glass effects, large radii, card grids, and gratuitous motion.
- Generic generated-docs styling that obscures Homarr's identity or makes navigation feel detached from the main product.
- Dense reference portals that expose structure without giving readers a clear path through a task.
## Design Principles
1. Put the reader's task first: search, navigation, page outline, and the answer must remain easy to reach.
2. Preserve one source of truth: typed Homarr metadata and existing custom components stay connected to the monorepo.
3. Prefer familiar documentation patterns: the interface should disappear while a reader scans, copies, and follows instructions.
4. Make complete content feel manageable through strong hierarchy, progressive disclosure, and precise cross-links.
5. Treat machine readers as users through canonical Markdown, structured metadata, and standard LLM discovery endpoints.
6. Keep the root landing page recognizably Homarr: preserve its self-hosted dashboard promise and real product evidence while documentation routes remain task-first.
## Accessibility & Inclusion
Meet WCAG 2.2 AA for color contrast, keyboard operation, focus visibility, landmarks, headings, and interactive controls. Respect reduced-motion and system color-scheme preferences. Diagrams, screenshots, icons, and emoji must have meaningful text alternatives when they carry information.
+83 -55
View File
@@ -1,84 +1,112 @@
# Homarr documentation (`@homarr/docs`)
# Homarr Documentation (`@homarr/docs`)
The source for [homarr.dev](https://homarr.dev), built with Next.js and Fumadocs UI inside the Homarr monorepo.
The official [homarr.dev](https://homarr.dev) documentation site, built with [Docusaurus 3](https://docusaurus.io/) and living inside the Homarr monorepo.
## Develop
## Why it's in the monorepo
From the repository root:
Having documentation alongside the application code enables:
- **Two-way linking** — the docs app imports from `@homarr/definitions` for type-safe integration/widget metadata, and the main app references doc paths via generated sitemap types
- **Atomic PRs** — code changes and their documentation updates ship in the same pull request
- **Shared tooling** — same Node version, pnpm catalog, oxlint/oxfmt, CI pipeline
- **Build-time validation** — Docusaurus strict mode catches broken links and references at build time
## Development
From the **monorepo root**:
```bash
# Start the docs dev server (port 3003)
pnpm dev:docs
```
The site runs on `http://127.0.0.1:3003`. To use a local Workshop API:
# Or from within this directory
pnpm dev
```bash
# Point the docs at a local PocketBase instance
WORKSHOP_API_URL=http://127.0.0.1:8090 pnpm dev:docs
```
## Validate
The standalone docs use `WORKSHOP_API_URL` for PocketBase and `HOMARR_WEBSITE_URL` for the public site origin. The old
`WORKSHOP_URL` name is a deprecated one-release alias.
## Build
```bash
pnpm --filter @homarr/docs typecheck
pnpm --filter @homarr/docs build
pnpm --filter @homarr/docs validate:links
pnpm --filter @homarr/docs verify:search
# Build docs only
pnpm turbo build --filter=@homarr/docs
# Build everything (docs + main app + tasks + websocket)
pnpm build
```
The static export is written to `out/`. The build validates that every registered integration and widget has a docs
page. The link check validates internal Markdown and MDX links and rendered anchors against that export.
The search check exercises the exported index with title, heading, and body queries and verifies result destinations.
## Lint & Format
## Write content
Uses oxlint and oxfmt (same as the rest of the monorepo):
Documentation lives in `docs/`; project posts live in `blog/`. Navigation is controlled by the nearest `meta.json`.
Integration and widget folders pair typed `index.ts` metadata with `index.mdx` content.
```bash
pnpm lint # oxlint
pnpm format # oxfmt (check)
pnpm format:fix # oxfmt (fix)
```
Use standard Markdown and MDX. Shared components live in `src/components/`. Mermaid fences, tabs, callouts, zoomable
images, and syntax-highlighted code are supported by the Fumadocs pipeline.
## Typecheck
When a user-facing change affects setup or behavior, update the matching page in the same pull request. See the
[documentation-sync skill](../../.agents/skills/documentation-sync/SKILL.md) for the code-to-content map.
```bash
pnpm typecheck
```
## Published formats
## Content Structure
- `/docs` — searchable documentation with typed navigation
- `/api-reference` — interactive reference generated from the OpenAPI schema
- `/llms.txt` — compact documentation and blog index for agents
- `/llms-full.txt` — complete processed Markdown corpus
- `/llms.mdx/docs/.../content.md` — raw Markdown for each docs page
- `/llms.mdx/blog/.../content.md` — raw Markdown for each blog post
- `/blog/rss.xml` — RSS feed for project posts
```
docs/
├── getting-started/ # Installation guides, glossary, prerequisites
├── management/ # Boards, apps, users, integrations, settings, tasks, API
├── integrations/ # 56 integration guides (one folder each)
├── widgets/ # 43 widget guides (one folder each)
├── advanced/ # SSO, env vars, proxy, styling, CLI, development
└── community/ # FAQ, donate, license, translations, get-in-touch
```
Every docs page and blog post includes copy-Markdown and view-source actions. Search is generated at build time and
runs locally in the browser; it does not depend on an external crawler. Markdown exports and search resolve
integration credentials and widget defaults from the same typed metadata used by the pages.
The getting-started overview and complete Custom JSX component catalog are also included, with property types,
binding contracts, and blocked capabilities taken from the published catalog JSON.
Each integration/widget doc follows a consistent pattern:
Published Docusaurus `/docs/category/...` addresses remain available as static compatibility pages. They forward to
the corresponding overview or developer setup guide, preserving query strings and anchors, and provide a direct
link when JavaScript is disabled. Their canonical metadata points to the destination; compatibility pages are
excluded from search and the sitemap.
- `index.ts` — typed metadata (`IntegrationDefinition` / `WidgetDefinition`)
- `index.mdx` — content using shared React components (`IntegrationHeader`, `WidgetHeader`, etc.)
## Kapa AI
## Importing from homarr packages
The **Ask AI** launcher uses Homarr's existing public Kapa Website ID. The root layout loads the widget once across
client-side navigation. **Search** and `Ctrl+K` / `Cmd+K` always use Fumadocs search, including when Kapa is unavailable.
The docs app has `@homarr/definitions` as a workspace dependency. You can import integration kinds, widget kinds, and other definitions directly:
Set `KAPA_WEBSITE_ID` at build time to use a different Kapa Website Widget integration. An explicitly empty value
disables the widget, for example `KAPA_WEBSITE_ID= pnpm --filter @homarr/docs build`. This is a public integration ID
included in exported pages, not a Kapa API key. Rebuild the static export after changing it.
```typescript
import { IntegrationKind } from "@homarr/definitions";
```
In the Kapa dashboard, confirm the integration is live and enable the production and preview domains. Restoring the
script does not verify that the historical integration is still active. Follow the
[Kapa widget setup](https://docs.kapa.ai/integrations/website-widget/quickstart) for domain restrictions and CSP settings.
This enables type-safe references to homarr domain concepts within documentation code.
After changing the documentation structure, review the Website Crawl source in Kapa: use the deployed `/docs` URL as
the start URL and preview `main` as the content selector. Replace any old Docusaurus-specific selector and check that
titles, headings, code samples, and integration details appear in the extracted Markdown. Docs are exported as HTML;
the site also publishes `/sitemap.xml` and permits crawling in `/robots.txt`. The `/llms.txt` exports do not configure
Kapa ingestion automatically. See [Kapa source setup](https://docs.kapa.ai/getting-started/index-your-first-source).
## Search (Algolia DocSearch)
Before publishing, check that Ask AI opens after navigating between pages, ask a documentation question, and verify
its citations point to the current docs. In a separate check, block `widget.kapa.ai` and confirm search still works.
Search uses the `Docusaurus` Algolia index (crawler `cd77a285-2756-4557-bf21-ee703748df15`). A separate `markdown` index is built for LLM markdown indexing.
Crawler reference config: [`docsearch.config.js`](docsearch.config.js).
**Verify search health:**
```bash
pnpm verify:search
```
## Tech Stack
| Layer | Technology |
| -------------- | ------------------------------------------- |
| Site generator | Docusaurus 3 (`@docusaurus/preset-classic`) |
| Styling | Tailwind CSS 4 + Docusaurus Infima |
| Icons | `@tabler/icons-react` |
| Diagrams | Mermaid (`@docusaurus/theme-mermaid`) |
| Search | Algolia DocSearch |
| Analytics | PostHog |
| Charts | @nivo/line |
## Contributing
When a Homarr change affects user-facing behavior, update the corresponding documentation in this app. See the
[documentation-sync skill](../../.agents/skills/documentation-sync/SKILL.md) for the code-to-documentation mapping.
@@ -1,7 +1,6 @@
---
slug: documentation-migration
title: Migration of Documentation
date: 2022-06-22
authors:
- ajnart
- manuel-rw
@@ -13,7 +12,7 @@ The documentation has been re-written partly and includes now many animations, g
We are still figuring things out and highly depend on your feedback.
{/* Historical excerpt boundary. */}
<!-- truncate -->
## Why we migrated
@@ -33,4 +32,4 @@ After we've reviewed your changes, we'll merge your PR and this documentation wi
## TL;DR
The documentation on GitHub Wiki will soon disappear. It will be replaced with this Docusaurus-powered website. You'll find much more information here with higher detail and searchability.
The documentation on GitHub Wiki will soon disappear. It will be replaced with this Docusaurus-powered website. You'll find much more information here with higher detail and searchability.
@@ -1,7 +1,6 @@
---
slug: translations
title: Help us make Homarr multilingual
date: 2022-08-28
authors:
- ajnart
- manuel-rw
@@ -14,8 +13,8 @@ We've been working hard to offer Homarr in many languages. The next update of Ho
![](img/homarr-we-need-you.webp) <br/>
Yes, we need **YOU**! We want to make Homarr accessible to as many people as possible. Thus, we need to translate all content into many different languages. We need your help for that! [You can help us now to translate Homarr into as many languages as possible](/docs/community/translations).
{/* Historical excerpt boundary. */}
<!-- truncate -->
### About global translations / translations per user
We are aware that many people would like to configure translations globally or configure language per user. Currently, translations are stored in the Cookies, which will expire after some time (currently, it's set to 30 days). We will implement more granular language settings in future versions of Homarr, since it requires major changes to Homarr. Stay tuned! 😎
We are aware that many people would like to configure translations globally or configure language per user. Currently, translations are stored in the Cookies, which will expire after some time (currently, it's set to 30 days). We will implement more granular language settings in future versions of Homarr, since it requires major changes to Homarr. Stay tuned! 😎
@@ -1,6 +1,5 @@
---
title: "We present: Homarr 0.11 - the most complex Homarr version yet!"
date: 2023-01-11
authors:
- ajnart
- manuel-rw
@@ -21,7 +20,7 @@ It contains many breaking changes and huge improvements to your favourite dashbo
- Huge design and usability improvements to older components to Homarr
- Better handeling of exceptions and unexpected issues
{/* Historical excerpt boundary. */}
<!-- truncate -->
## Complete implementation of highly customizable drag and drop library "Gridstack"
@@ -1,6 +1,5 @@
---
title: "We present: Homarr 0.12 - The fastest homarr version ever!"
date: 2023-04-16
authors:
- ajnart
- manuel-rw
@@ -16,12 +15,14 @@ This applies to all widgets, but in the case of the IFrame widget, it enables yo
- Integrate monitoring tools like Grafana, Splunk or Elasticsearch
- Integrate your services (for example Sonarr, Radarr and Overseerr) directly into Homarr
![](https://media.discordapp.net/attachments/988335098493542410/1094665745226539168/update-teaser.png?width=1046&height=666)
## Edit mode password
We've added a setting to disable editing completely. This will allow you to restrict edit access without password-protection.
use the `EDIT_MODE_PASSWORD` ENV variable to set a password for edit mode.
turn on `DISABLE_EDIT_MODE=TRUE` to disable edit mode on startup.
{/* Historical excerpt boundary. */}
<!-- truncate -->
## 😎 Blazingly fast
We've implemented a new caching system, that will cache all data in your browser, meaning that Homarr will load within milliseconds, as if it was *powered by rust and blazingly fast* !!!
@@ -71,4 +72,4 @@ Now, you can use the following environment variables to configure this:
- ``DOCKER_HOST``
- ``DOCKER_PORT``
**Full Changelog**: https://github.com/ajnart/homarr/compare/v0.11.5...v0.12.0
**Full Changelog**: https://github.com/ajnart/homarr/compare/v0.11.5...v0.12.0
@@ -1,6 +1,5 @@
---
title: "Authentication in Homarr - 0.14 is here!"
date: 2023-11-10
authors:
- ajnart
- manuel-rw
@@ -24,7 +23,7 @@ provide you a viable solution today.
- 📝 Overhauled notepad widget with a complex graphical editor that enables easy editing right from your browser.
- :globe_with_meridians: Live Translation on Crowdin that enable you to directly translate using images to see what exactly you're translating
{/* Historical excerpt boundary. */}
<!-- truncate -->
## Breaking changes
@@ -84,4 +83,4 @@ We are aware that this update has many breaking changes and may confuse some use
For that reason, we updated our documentation and will enhance it further within the next few weeks.
We've also added this small button at the bottom of the page were you can ask **your questions** to an AI assistant:
![image](https://github.com/ajnart/homarr/assets/30572287/a56f721a-d022-42ad-813a-d85c89462a8c)
![image](https://github.com/ajnart/homarr/assets/30572287/a56f721a-d022-42ad-813a-d85c89462a8c)
@@ -1,6 +1,5 @@
---
title: "Updated documentation with better organization & design"
date: 2023-12-22
authors:
- manuel-rw
tags: [homarr, documentation, design, docs]
@@ -9,7 +8,7 @@ tags: [homarr, documentation, design, docs]
We'd like to let you know that we've updated our documentation and reorganized the pages.
This means, that some links may no longer be valid - we apologise if this causes any inconvenience for you.
{/* Historical excerpt boundary. */}
<!-- truncate -->
A few highlights include:
@@ -19,4 +18,4 @@ A few highlights include:
- Bug fixes for image zoom
- Added documentation for management pages and [new CLI tool](/docs/advanced/command-line/password-recovery/)
Please [let us know](/docs/community/get-in-touch) is something is not working as expected.
Please [let us know](/docs/community/get-in-touch) is something is not working as expected.
@@ -1,10 +1,9 @@
---
title: Homarr 1.0 - complete rewrite of all systems
date: 2024-09-23
authors:
- manuel-rw
---
# Homarr 1.0 - complete rewrite of all systems
We proudly present to you - Homarr ``1.0``.
We have started work on this new version back in 2023 and have worked tirelessly for months on this brand-new dashboard.
@@ -29,7 +28,7 @@ reliability and scalability compared to < ``1.0``.
- **Improved performance**: We have upgraded the underlying framework of Homarr and take advantage
of an in-memory message bus and websockets to deliver data near realtime to you.
{/* Historical excerpt boundary. */}
<!-- truncate -->
## Breaking changes
:::warning
@@ -1,16 +1,16 @@
---
title: Open Beta 1.0
date: 2024-12-17
authors:
- meierschlumpf
---
# Open Beta 1.0
We are proud to announce the open beta of Homarr 1.0. This is a major milestone for us and we are excited to share it with you.
The open beta allows us to polish the last rough edges and gather feedback from you.
We are looking forward to your feedback and hope you enjoy the new features.
Let us know throgh discord or a [github issues](https://github.com/homarr-labs/homarr/issues/new/choose) if you encounter any issues.
{/* Historical excerpt boundary. */}
<!-- truncate -->
## How to use the beta with docker
@@ -36,4 +36,4 @@ services:
Then, run `docker compose up -d` in the same directory. This will start the Homarr container in the background.
Please note that the mounts have changed and it's not backwards compatible with versions before 1.0.0-beta.1.
You can find a list of all breaking changes [here](/blog/2024/09/23/version-1.0)
You can find a list of all breaking changes [here](/blog/2024/09/23/version-1.0)
@@ -1,14 +1,14 @@
---
title: Migrate from 0.15.10+ to 1.0.0
date: 2025-01-19
authors:
- meierschlumpf
---
# Migrate from 0.15.10+ to 1.0.0
In this guide, we will show you how to migrate from Homarr 0.15.10+ to 1.0.0.
If you are still on a version before 0.15.10, please update to 0.15.10 where we introduced the migration export page.
{/* Historical excerpt boundary. */}
<!-- truncate -->
## Preserve your old installation
@@ -22,7 +22,7 @@ Plan to recreate your apps, integrations, and boards manually in the new install
We highly recommend to create a parallel installation of Homarr 1.0.0.
So if something with for example the import does not quite work, the data in the old installation is still available.
To do this you can follow the appropriate [installation guide](/docs/getting-started) for your system.
To do this you can follow the appropriate [installation guide](https://homarr.dev/docs/category/installation-1) for your system.
Please note that if you are using docker you need to specify a diffrent external port for the new installation as the old one had the same port.
So in your compose file the ports would be `7576:7575` instead of `7575:7575`.
@@ -1,14 +1,14 @@
---
title: How to use Argus with Homarr
date: 2025-08-02
authors:
- meierschlumpf
---
# How to use Argus with Homarr
In `v1.32.0` we added the endpoint `/api/info` which returns the current version of Homarr and can therefore be used in Argus to watch for updates.
This guide will show you how to set up a user with apiKey to access the endpoint without providing admin access through it.
{/* Historical excerpt boundary. */}
<!-- truncate -->
![Argus](./img/argus.png)
@@ -64,4 +64,4 @@ Now you can configure Argus to use the user and apiKey we created.
![Argus configuration](./img/argus-configuration.png)
Replace the `<secret>` with the apiKey you created and the deployed version url with the url of your Homarr instance.
Replace the `<secret>` with the apiKey you created and the deployed version url with the url of your Homarr instance.
@@ -1,6 +1,4 @@
---
title: Homarr 2.0.0 - Workshop, Custom Widgets and a rebuilt board
date: 2026-09-03
authors:
- ajnart
tags: [homarr, update, version, assistant, custom widgets, dashboards, docker]
@@ -21,7 +19,7 @@ Homarr 2.0 is an upgrade, not a brand-new app wearing the same logo. Here is wha
![A populated Homarr 2.0 dashboard with compact widgets, an Assistant, and an application rail](./img/homarr-v2-dashboard.webp)
{/* Historical excerpt boundary. */}
<!-- truncate -->
:::warning Back up before upgrading
+1 -1
View File
@@ -5,7 +5,7 @@
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/global.css",
"css": "src/css/custom.css",
"baseColor": "mist",
"cssVariables": true,
"prefix": ""
+9
View File
@@ -0,0 +1,9 @@
{
"label": "Advanced",
"collapsed": true,
"position": 5,
"link": {
"type": "generated-index",
"title": "Advanced Concepts or features"
}
}
@@ -0,0 +1,4 @@
{
"collapsed": true,
"label": "Command line interface"
}
+143 -1
View File
@@ -3,7 +3,8 @@
The Homarr image includes a recovery CLI for operations that cannot be completed in the web interface. It is not an
application API; use the [API](/docs/management/api) or [MCP endpoint](/docs/management/mcp) for automation.
Back up the database and stop Homarr before running a command that changes data.
Back up the database and stop Homarr before running a recovery command that changes database records directly.
Widget project commands and authenticated preview requests can run while Homarr is online.
Failed commands print an error and return a non-zero exit code, so shell scripts can stop safely.
## Run the recovery CLI
@@ -43,6 +44,147 @@ homarr <command>
See the pages in this section for available commands.
## Build and share custom widget packages
The `widgets` commands accept a project directory, a v3 package JSON file, or an offline archive. Scaffolding,
validation, compilation and packing do not need a running Homarr database.
Create a project to edit in your own IDE:
```sh
homarr widgets init my-clock --example clock --id example.my-clock --name "My clock"
homarr widgets validate my-clock
homarr widgets pack my-clock
```
`init` (also `scaffold`) creates a new directory with `homarr-widget.json` and normal TSX, TypeScript, CSS and asset
files. It refuses to overwrite an existing directory. Choose `clock`, `timer`, `beszel`, `checklist`, `downloads`,
`sonarr`, `rack`, `backup`, `household`, `overview`, `media`, `sqlite` or `mqtt` with `--example`; leaving out `--id` generates a unique
local package identity. Edit the manifest and files, then repeat validation and packing. The manifest carries entrypoints,
handlers, connection requirements, options and exact dependency versions; it does not embed the files map in this layout.
Directory loading skips hidden files, symlinks, `node_modules`, `dist`, `coverage`, generated archives and root-level
`package.json`, `package-lock.json` and `tsconfig.json`. Keep all widget source under supported TS/JS, JSON, CSS, SVG,
text, Markdown, image or font files. Build output defaults to `dist/widget.artifact.json`; packing defaults to
`dist/widget.homarr-widget.json`. Remove or rename an existing output before rebuilding, or pass a new `--output`.
The same commands also accept the single-file format:
```sh
homarr widgets validate widget.json
homarr widgets build widget.json --output widget.artifact.json
homarr widgets pack widget.json --output widget.homarr-widget.json
homarr widgets validate widget.homarr-widget.json
```
`validate` checks the package structure or an archive's source and artifact checksums. It does not execute widget code.
`build` compiles JSX/TSX, local modules, CSS and assets into browser and optional server output. `pack` includes the
source, compiled output and dependency lock in one JSON archive for offline installation. Output files must not already exist.
Packages with third-party dependencies need `--trust` to install their exact declared versions:
```sh
homarr widgets pack widget.json --trust
```
Dependency installations are cached in `.homarr-widgets` beside the input file. Installation scripts are disabled;
packages requiring native build steps are not supported by these commands. Compilation does not start the widget's
server handlers. Installed trusted widgets execute with Homarr's privileges; source and artifact checksums establish
integrity, not publisher authenticity. Local connection bindings, credentials and widget state are separate from the archive.
### Preview a local project in Homarr
Set `HOMARR_API_KEY` to an admin API key from your own Homarr instance, then run:
```sh
homarr widgets preview my-clock --url http://homarr.local:7575 --trust
```
The command creates a disabled installation on first use, compiles the current local source on that Homarr instance,
and prints a link to its exact preview session. Open the link while signed in as the API key owner. Repeating the command
replaces the previous preview; it does not activate or overwrite the installation's saved draft. Use `--save-draft` to
also save your local source. Use `--installation-id ID` to target an existing installation. The local
`.homarr-widget.local.json` file remembers installation and preview IDs and is excluded from scaffolded Git projects.
Pass `--bindings bindings.json` for a JSON object mapping declared connection names to existing Homarr connection IDs,
and `--options options.json` for preview option values. Credentials remain in Homarr. `--live-actions` explicitly allows
real mutations during this preview; queries and subscriptions can already execute trusted server code. `--trust` is
required on every invocation. Set `HOMARR_URL` instead of `--url`, or select a different secret variable with
`--api-key-env VARIABLE_NAME`. Preview compilation may install declared dependencies after this explicit trust choice.
Use `--scenario NAME` to select synthetic query data declared in the package's `previewScenarios`. This skips server
startup and configured service requests; unprovided query fixtures fail explicitly and subscriptions are unavailable.
SDK actions stay simulated, so `--scenario` cannot be combined with `--live-actions`. Trusted browser code and dependency
compilation keep their normal privileges. See [synthetic preview scenarios](../../management/custom-widgets/trusted-packages.mdx#synthetic-preview-scenarios).
### Publish the exact offline archive
Set `HOMARR_WORKSHOP_TOKEN` to an authenticated Workshop token, then publish the archive you reviewed:
```sh
homarr widgets publish my-clock/dist/widget.homarr-widget.json
homarr widgets publish next-release.homarr-widget.json --submission-id LISTING_ID --expected-revision 1
```
Use `--url` (or `WORKSHOP_API_URL`) for your own Workshop service, `--token-env` for another token variable,
`--changelog` for release notes, and `--forked-from RELEASE_ID` to attribute a new fork. Existing listings require their
current revision and a new package version. Forks need their own package identity. Published releases are immutable;
publication sends the archive without rebuilding it. You can also import the archive into Homarr and publish through
the package workspace.
### Run a package on another machine
Run an already packed archive on another machine with the optional widget runner:
```sh
export HOMARR_WIDGET_RUNNER_TOKEN="$(openssl rand -hex 32)"
homarr widgets serve widget.homarr-widget.json --trust --host 127.0.0.1 --port 8787
```
`serve` executes the installed package with that machine's operating system privileges. It never downloads packages
or accepts source uploads. Set a custom token variable with `--token-env VARIABLE_NAME`. The token must have at least
32 characters. Interrupting the command stops its worker and subscriptions. See [remote widget runners](../../management/custom-widgets/remote-runners.mdx)
for connection setup, local files, SQL, MQTT, and browser-service adapters.
### Share several widgets as a collection
A collection contains independent compiled widget packages and a shared connection blueprint. Write a collection
manifest with paths to already packed archives:
```json
{
"manifest": { "id": "example.home", "version": "1.0.0", "name": "Home dashboard" },
"connections": { "monitor": { "label": "Monitoring server", "kind": "integration" } },
"widgets": [
{ "key": "clock", "archive": "clock/dist/widget.homarr-widget.json" },
{
"key": "servers",
"archive": "beszel/dist/widget.homarr-widget.json",
"connections": { "beszel": "monitor" }
}
]
}
```
Pack and verify it without compiling or executing the member packages:
```sh
homarr widgets collection pack collection.json --output home.homarr-collection.json
homarr widgets collection validate home.homarr-collection.json
homarr widgets collection import home.homarr-collection.json --url http://homarr.local:7575
```
`import` uses `HOMARR_API_KEY`, or the variable selected with `--api-key-env`. Pass `--bindings bindings.json` to map
each collection slot to an existing local Homarr connection once; all members that reference that slot receive the
binding. Omitted connections can be configured later. Imports create every member as a disabled draft in one database
transaction and print their review links. Trust and activation are separate, explicit steps.
Collections support 1–32 members and up to 128 MiB. Package identities, compiled artifacts, dependency locks and
documented Workshop/fork attribution travel with the archive. The collection and each nested artifact have integrity
checksums. Local connection URLs, IDs and credentials, board placements, stored widget data and local configuration
are excluded. Authored `options` on a member are portable defaults: include only values you intend to share. Package
source is included verbatim, so embedded literals are still part of the archive.
## Build a local branch harness
The repository's host-side CLI can build the current checkout and run it as a named Docker harness:
@@ -1,4 +0,0 @@
{
"title": "Command line interface",
"pages": ["index", "users", "integrations", "password-recovery", "fix-usernames", "development"]
}
@@ -0,0 +1,8 @@
{
"label": "Developer guides",
"position": 6,
"collapsed": true,
"link": {
"type": "generated-index"
}
}
@@ -57,8 +57,8 @@ Homarr becomes the instance administrator.
Use `pnpm docker:dev:up` instead when you only need Redis in the background. Running the migration also seeds the
default data; use `pnpm db:seed` to seed it explicitly later.
Workshop contributors can set up PocketBase and Fumadocs with the dedicated
[Workshop development guide](/docs/advanced/development/workshop).
Workshop contributors can set up PocketBase and Docusaurus with the dedicated
[Workshop development guide](./workshop).
### Useful commands
@@ -69,7 +69,7 @@ Workshop contributors can set up PocketBase and Fumadocs with the dedicated
- `pnpm dev:cli -- build --pr <number>` — build a pull request from a temporary checkout.
- `pnpm dev:cli -- rebuild <name>` — rebuild an image from its recorded checkout or pull request.
- `pnpm dev:cli:install` — optionally install the developer CLI as a `homarr` binary.
- `pnpm dev:docs` — Fumadocs on port 3003.
- `pnpm dev:docs` — Docusaurus only on port 3003.
- `pnpm docker:dev:up` — Redis development service in the background.
- `pnpm cli` — Homarr operations CLI.
- `pnpm db:migration:sqlite:run` — create or update a SQLite database.
@@ -104,21 +104,3 @@ Choose the smallest relevant suite when changing behavior:
Omit `<file>` to run all tests in that command's scope. E2E and screenshot commands use a local image tagged `homarr-e2e`, or an image selected with `HOMARR_E2E_IMAGE`. The default commands run once without automatic retries; coverage is opt-in. The screenshot generator is excluded from both unit and E2E commands.
Keep behavioral coverage for authorization, migrations, persistence, and widget execution. Avoid tests that only search source code for particular component names, JSX, CSS, or documentation wording.
## Documentation development
Run `pnpm dev:docs` to open the Next.js and Fumadocs site at `http://127.0.0.1:3003`. Content lives in
`apps/docs/docs/`; the nearest `meta.json` controls navigation. Keep integration and widget setup metadata in their
typed `index.ts` files alongside the page.
After changing content, navigation, or shared MDX components, run:
```sh
pnpm --filter @homarr/docs build
pnpm --filter @homarr/docs validate:links
pnpm --filter @homarr/docs verify:search
```
The build writes a static site to `apps/docs/out/`. Check heading links, search results, and the page's Markdown export
when changing shared components. The [Fumadocs documentation](https://fumadocs.dev/docs) describes supported components
and source APIs; match examples to the versions installed in this repository.
@@ -1,4 +0,0 @@
{
"title": "Developer guides",
"pages": ["getting-started", "widgets-and-integrations", "kubernetes", "workshop", "workshop-operator"]
}
@@ -34,21 +34,6 @@ Workshop uses PocketBase. The production image serves the Workshop website and A
Public URL variables accept HTTP(S) origins without embedded credentials, query strings, or fragments. Restart the
container after changing runtime configuration.
## Documentation search and AI
The documentation uses Fumadocs search with an index generated during the website build. Search runs in the browser
and needs no hosted search credentials or crawler.
The **Ask AI** launcher connects to Kapa separately. `KAPA_WEBSITE_ID` is a public website integration ID, read when
building the documentation. The default uses Homarr's integration. For a private deployment, pass your own ID or
an empty value to disable it: `docker build --build-arg KAPA_WEBSITE_ID= -f apps/workshop/Dockerfile .`.
Changing this value requires rebuilding the image; setting it on an already-built container has no effect.
For your own Kapa integration, enable the deployment domain in Kapa and configure a Website Crawl source for your
published docs. Preview the `main` content selector and verify extracted headings, code, and integration details.
After a migration, refresh the source and check answer citations. `/llms.txt` alone does not configure Kapa ingestion.
See the [Kapa website widget guide](https://docs.kapa.ai/integrations/website-widget/quickstart).
## Authentication and email
Configure both GitHub OAuth variables and use `https://<workshop-host>/api/oauth2-redirect` as the callback. Supplying
@@ -4,13 +4,13 @@ sidebar_position: 4
tags:
- Workshop
- Developer
- Fumadocs
- Docusaurus
- PocketBase
---
# Workshop development
See the [main development guide](/docs/advanced/development/getting-started) for repository prerequisites.
See the [main development guide](./getting-started) for repository prerequisites.
Start PocketBase:
@@ -19,7 +19,7 @@ cp apps/workshop/.env.example apps/workshop/.env
docker compose --env-file apps/workshop/.env -f apps/workshop/docker-compose.yml up --build workshop
```
Start Fumadocs in another terminal:
Start Docusaurus in another terminal:
```sh
WORKSHOP_API_URL=http://127.0.0.1:8090 pnpm dev:docs
@@ -139,4 +139,15 @@ The advanced deployments environment variables should only be used if you know w
| `DB_MIGRATIONS_DISABLED` | Disable db migrations. For example for helm charts. |
All public URL variables reject non-HTTP protocols, embedded credentials, query strings, and fragments, and normalize
trailing slashes when Homarr or the documentation site starts.
trailing slashes when Homarr or Docusaurus starts.
## Trusted widget packages
| Variable | Purpose | Default |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `CUSTOM_WIDGET_PACKAGE_PATH` | Persistent build and runtime artifact cache. Activated browser/server artifacts and their source are also retained in the database. | `/appdata/custom-widgets` in production; `./appdata/custom-widgets` in development |
| `CUSTOM_WIDGET_MAX_SERVER_PROCESSES` | Maximum active trusted widget server artifacts per Homarr process, from 1 to 128. Source-free packages do not start a server process. | `16` |
Each replica materializes an authorized installed artifact from the database into its own cache. Dashboard requests do
not install npm dependencies. Package dependencies are resolved and bundled when an owner previews or activates a new
source draft; importing a complete compiled archive supports offline activation. See [trusted widget packages](/docs/management/custom-widgets/trusted-packages).
-60
View File
@@ -1,60 +0,0 @@
---
title: Advanced configuration
description: Configure deployment, authentication, networking, styling, automation, and development workflows.
---
import {
IconCode,
IconIcons,
IconKey,
IconKeyboard,
IconNetwork,
IconPalette,
IconTerminal2,
IconUserCog,
IconVariable,
} from "@tabler/icons-react";
These guides cover changes that affect how Homarr is deployed, secured, operated, or extended.
## Deploy and secure
<Cards>
<Card icon={<IconVariable />} title="Environment variables" href="/docs/advanced/environment-variables">
Configure Homarr at deployment time.
</Card>
<Card icon={<IconKey />} title="Single sign-on" href="/docs/advanced/single-sign-on">
Connect an external identity provider.
</Card>
<Card icon={<IconNetwork />} title="Proxies and certificates" href="/docs/advanced/proxy">
Run Homarr behind a reverse proxy.
</Card>
<Card icon={<IconUserCog />} title="Run as a different user" href="/docs/advanced/running-as-different-user">
Change the user and group used by the container.
</Card>
</Cards>
## Customize
<Cards>
<Card icon={<IconPalette />} title="Custom styling" href="/docs/advanced/styling">
Apply custom CSS to Homarr.
</Card>
<Card icon={<IconIcons />} title="Icons" href="/docs/advanced/icons">
Configure icon sources and behavior.
</Card>
<Card icon={<IconKeyboard />} title="Keyboard shortcuts" href="/docs/advanced/keyboard-shortcuts">
Navigate and operate Homarr with the keyboard.
</Card>
</Cards>
## Develop and automate
<Cards>
<Card icon={<IconTerminal2 />} title="Command line interface" href="/docs/advanced/command-line">
Use administrative commands from the terminal.
</Card>
<Card icon={<IconCode />} title="Developer guides" href="/docs/advanced/development/getting-started">
Set up a development environment and contribute code.
</Card>
</Cards>
-19
View File
@@ -1,19 +0,0 @@
{
"title": "Advanced",
"defaultOpen": false,
"pages": [
"index",
"---Deploy and secure---",
"environment-variables",
"single-sign-on",
"proxy",
"running-as-different-user",
"---Customize---",
"styling",
"icons",
"keyboard-shortcuts",
"---Develop and automate---",
"command-line",
"development"
]
}
+3 -3
View File
@@ -9,14 +9,14 @@ tags:
- Security
---
import Tabs from "@/components/mdx/legacy-tabs";
import { TabItem } from "@/components/mdx/legacy-tabs";
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
## Allowing self-signed certificates
Some users may come across a barrier, where they're unable to receive a 200 response from the Ping widget for some apps, while using self-signed certificates or a local certificate authory.
:::note[What's going on?]
:::note What's going on?
Homarr is trying to communicate to your apps via the integrations.
It usually doesn't matter if Homarr is running on `http` or `https`.
+157 -149
View File
@@ -10,11 +10,14 @@ tags:
- Active Directory
---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
# Single Sign On
Homarr supports multiple authentication options, from internal userbase (credentials), to LDAP (with Active directory support), and OIDC.
## Common configuration
### Auth configuration common variables
| Environment Variable | Description | Default Value |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
@@ -23,193 +26,198 @@ Homarr supports multiple authentication options, from internal userbase (credent
| AUTH_SESSION_EXPIRY_TIME | Time for the session to time out. Can be set as pure number, which will automatically be used in seconds, or followed by s, m, h or d for seconds, minutes, hours or days. (ex: "30m") | "30d" |
| AUTH_COOKIE_PREFIX | Prefix used for all authentication cookies (session, csrf, callback, pkce, state, nonce). Change this if you run another Auth.js/NextAuth app on the same hostname as Homarr (browsers scope cookies by host, not by port) to avoid cookie name collisions. Only letters, numbers, hyphens and underscores are allowed. | `homarr` |
## Credentials provider
<Tabs>
<TabItem value="credentials" label="Credentials Provider" default>
This is the default provider.
This is the default provider.
First user is created using the onboarding process and the rest can be created by this user (see [user management](/docs/management/users))
First user is created using the onboarding process and the rest can be created by this user (see [user management](/docs/management/users))
## LDAP provider
</TabItem>
<TabItem value="ldap" label="LDAP provider">
This provider authenticates against an LDAP server.
This provider authenticates against an LDAP server.
Any user in LDAP server that signs in gets created in Homarr database.
Any user in LDAP server that signs in gets created in Homarr database.
Roles are fetched from LDAP groups. Groups with the same name of Homarr will be used to synchronize them.
Roles are fetched from LDAP groups. Groups with the same name of Homarr will be used to synchronize them.
<details>
<summary>
Example Setup
</summary>
<div>
<details>
<summary>
Example Setup
</summary>
<div>
In this setup we are using [lldap](https://github.com/lldap/lldap). Install your server using docker or [as a service](https://github.com/lldap/lldap/blob/main/example_configs/lldap.service).
In this setup we are using [lldap](https://github.com/lldap/lldap). Install your server using docker or [as a service](https://github.com/lldap/lldap/blob/main/example_configs/lldap.service).
Minimal configuration requires 4 env variables, LDAP URI, base, user and password for querying data.
Minimal configuration requires 4 env variables, LDAP URI, base, user and password for querying data.
There's more variables, but all have defaults corresponding to lldap defaults. These might need to be changed if you have different LDAP provider.
```
docker run ...
AUTH_PROVIDERS="ldap"
AUTH_LDAP_URI="ldap://example.com:3890"
AUTH_LDAP_BASE="dc=example,dc=com" // Same as LLDAP_LDAP_BASE_DN
AUTH_LDAP_BIND_DN="uid=admin,ou=People,dc=example,dc=com"
AUTH_LDAP_BIND_PASSWORD="adminpass" // Same as LLDAP_LDAP_USER_PASS
```
```
#Docker compose
version: x
services:
homarr:
environment:
AUTH_PROVIDERS: ldap
AUTH_LDAP_URI: ldap://example.com:3890
AUTH_LDAP_BASE: dc=example,dc=com #Same as LLDAP_LDAP_BASE_DN
AUTH_LDAP_BIND_DN: uid=admin,ou=People,dc=example,dc=com
AUTH_LDAP_BIND_PASSWORD: adminpass #Same as LLDAP_LDAP_USER_PASS
```
There's more variables, but all have defaults corresponding to lldap defaults. These might need to be changed if you have different LDAP provider.
```
docker run ...
AUTH_PROVIDERS="ldap"
AUTH_LDAP_URI="ldap://example.com:3890"
AUTH_LDAP_BASE="dc=example,dc=com" // Same as LLDAP_LDAP_BASE_DN
AUTH_LDAP_BIND_DN="uid=admin,ou=People,dc=example,dc=com"
AUTH_LDAP_BIND_PASSWORD="adminpass" // Same as LLDAP_LDAP_USER_PASS
```
```
#Docker compose
version: x
services:
homarr:
environment:
AUTH_PROVIDERS: ldap
AUTH_LDAP_URI: ldap://example.com:3890
AUTH_LDAP_BASE: dc=example,dc=com #Same as LLDAP_LDAP_BASE_DN
AUTH_LDAP_BIND_DN: uid=admin,ou=People,dc=example,dc=com
AUTH_LDAP_BIND_PASSWORD: adminpass #Same as LLDAP_LDAP_USER_PASS
```
In lldap, create a user and admin group, assign this user to the external admin group configured during onboarding. You can log in using this user and he will be in the group.
In lldap, create a user and admin group, assign this user to the external admin group configured during onboarding. You can log in using this user and he will be in the group.
Here is another example for Active Directory:
Here is another example for Active Directory:
```
AUTH_LDAP_URI="ldap://ldap.abc.xyz:389
AUTH_LDAP_BASE="DC=abc,DC=xyz"
AUTH_LDAP_BIND_DN="CN=Administrator,CN=Users,DC=abc,DC=xyz"
AUTH_LDAP_BIND_PASSWORD="YourAdministratorPassword"
AUTH_LDAP_USERNAME_ATTRIBUTE="sAMAccountName"
AUTH_LDAP_USER_MAIL_ATTRIBUTE="userPrincipalName"
AUTH_LDAP_GROUP_CLASS="group"
AUTH_LDAP_GROUP_MEMBER_ATTRIBUTE="member"
AUTH_LDAP_GROUP_MEMBER_USER_ATTRIBUTE="dn"
AUTH_LDAP_SEARCH_SCOPE="sub"
AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG="(sAMAccountType=805306368)"
```
User mail attribute is set to userPrincipalName as it follows the right schema, but it is recommended to use real emails and the default 'mail' value.
```
AUTH_LDAP_URI="ldap://ldap.abc.xyz:389
AUTH_LDAP_BASE="DC=abc,DC=xyz"
AUTH_LDAP_BIND_DN="CN=Administrator,CN=Users,DC=abc,DC=xyz"
AUTH_LDAP_BIND_PASSWORD="YourAdministratorPassword"
AUTH_LDAP_USERNAME_ATTRIBUTE="sAMAccountName"
AUTH_LDAP_USER_MAIL_ATTRIBUTE="userPrincipalName"
AUTH_LDAP_GROUP_CLASS="group"
AUTH_LDAP_GROUP_MEMBER_ATTRIBUTE="member"
AUTH_LDAP_GROUP_MEMBER_USER_ATTRIBUTE="dn"
AUTH_LDAP_SEARCH_SCOPE="sub"
AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG="(sAMAccountType=805306368)"
```
User mail attribute is set to userPrincipalName as it follows the right schema, but it is recommended to use real emails and the default 'mail' value.
</div>
</details>
</div>
</details>
### LDAP configuration
### Configuration
| Environment Variable | Description | Default value |
|-------------------------------------------|-----------------------------------------------------------|---------------------|
| ``AUTH_LDAP_URI`` | URI of your LDAP server | --- |
| ``AUTH_LDAP_BASE`` | Base dn of your LDAP server | --- |
| ``AUTH_LDAP_BIND_DN`` | User used for finding users and groups | --- |
| ``AUTH_LDAP_BIND_PASSWORD`` | Password for bind user | --- |
| ``AUTH_LDAP_USERNAME_ATTRIBUTE`` | Attribute used for username | uid |
| ``AUTH_LDAP_USER_MAIL_ATTRIBUTE`` | Attribute used for mail field | mail |
| ``AUTH_LDAP_GROUP_CLASS`` | Class used for querying groups | groupOfUniqueNames |
| ``AUTH_LDAP_GROUP_MEMBER_ATTRIBUTE`` | Attribute used for querying group member | member |
| ``AUTH_LDAP_GROUP_MEMBER_USER_ATTRIBUTE`` | User attribute used for comparing with group member | dn |
| ``AUTH_LDAP_SEARCH_SCOPE`` | Serach scopes between base, one and sub | base |
| ``AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG`` | Extra arguments for user search filter (& based) | --- |
| ``AUTH_LDAP_GROUP_FILTER_EXTRA_ARG`` | Extra arguments for user's groups search filter (& based) | --- |
| Environment Variable | Description | Default value |
|-------------------------------------------|-----------------------------------------------------------|---------------------|
| ``AUTH_LDAP_URI`` | URI of your LDAP server | --- |
| ``AUTH_LDAP_BASE`` | Base dn of your LDAP server | --- |
| ``AUTH_LDAP_BIND_DN`` | User used for finding users and groups | --- |
| ``AUTH_LDAP_BIND_PASSWORD`` | Password for bind user | --- |
| ``AUTH_LDAP_USERNAME_ATTRIBUTE`` | Attribute used for username | uid |
| ``AUTH_LDAP_USER_MAIL_ATTRIBUTE`` | Attribute used for mail field | mail |
| ``AUTH_LDAP_GROUP_CLASS`` | Class used for querying groups | groupOfUniqueNames |
| ``AUTH_LDAP_GROUP_MEMBER_ATTRIBUTE`` | Attribute used for querying group member | member |
| ``AUTH_LDAP_GROUP_MEMBER_USER_ATTRIBUTE`` | User attribute used for comparing with group member | dn |
| ``AUTH_LDAP_SEARCH_SCOPE`` | Serach scopes between base, one and sub | base |
| ``AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG`` | Extra arguments for user search filter (& based) | --- |
| ``AUTH_LDAP_GROUP_FILTER_EXTRA_ARG`` | Extra arguments for user's groups search filter (& based) | --- |
## OIDC provider
</TabItem>
<TabItem value="oidc" label="OIDC provider">
This provider authenticates using OIDC protocol.
This provider authenticates using OIDC protocol.
Users signed in using OIDC are created in Homarr.
Users signed in using OIDC are created in Homarr.
Roles are fetched from group claims. This can also be changed to roles for example added to a azure app registration by using the `AUTH_OIDC_GROUPS_ATTRIBUTE`.
Roles are fetched from group claims. This can also be changed to roles for example added to a azure app registration by using the `AUTH_OIDC_GROUPS_ATTRIBUTE`.
If you'd rather manage group memberships for OIDC users locally (instead of via the IdP), set `AUTH_OIDC_GROUPS_LOCAL_MANAGEMENT=true`. While enabled, Homarr stops syncing OIDC users' group memberships from the groups claim, and admins can add/remove OIDC users on a group's members page. If you turn this back to `false`, the next login of each user resumes the regular sync and reconciles their groups with the IdP's claim again, which may remove memberships that were added manually while local management was enabled.
If you'd rather manage group memberships for OIDC users locally (instead of via the IdP), set `AUTH_OIDC_GROUPS_LOCAL_MANAGEMENT=true`. While enabled, Homarr stops syncing OIDC users' group memberships from the groups claim, and admins can add/remove OIDC users on a group's members page. If you turn this back to `false`, the next login of each user resumes the regular sync and reconciles their groups with the IdP's claim again, which may remove memberships that were added manually while local management was enabled.
To let an existing credentials user also sign in with OIDC, set `AUTH_OIDC_ENABLE_DANGEROUS_CREDENTIALS_LINKING=true`. On the first OIDC sign-in, Homarr links a credentials user with the same email address instead of creating a second user. The user keeps their password login, local username and profile, groups, permissions, boards, settings, and API keys. OIDC profile and group claims do not overwrite the credentials-owned data. Homarr requires the OIDC profile to contain `email_verified: true` while this option is enabled. Only enable this when your OIDC provider verifies email addresses, because a matching email could otherwise be used to take over an existing account.
To let an existing credentials user also sign in with OIDC, set `AUTH_OIDC_ENABLE_DANGEROUS_CREDENTIALS_LINKING=true`. On the first OIDC sign-in, Homarr links a credentials user with the same email address instead of creating a second user. The user keeps their password login, local username and profile, groups, permissions, boards, settings, and API keys. OIDC profile and group claims do not overwrite the credentials-owned data. Homarr requires the OIDC profile to contain `email_verified: true` while this option is enabled. Only enable this when your OIDC provider verifies email addresses, because a matching email could otherwise be used to take over an existing account.
<details>
<summary>
Example Setup
</summary>
<div>
<details>
<summary>
Example Setup
</summary>
<div>
In this example we will be using [Authelia](https://github.com/authelia/authelia).
In this example we will be using [Authelia](https://github.com/authelia/authelia).
You can use any setup, but the simplest is [local](https://github.com/authelia/authelia/blob/master/examples/compose/local/authelia/configuration.yml).
You can use any setup, but the simplest is [local](https://github.com/authelia/authelia/blob/master/examples/compose/local/authelia/configuration.yml).
You also have to [enable OIDC in Authelia](https://www.authelia.com/configuration/identity-providers/open-id-connect/).
You also have to [enable OIDC in Authelia](https://www.authelia.com/configuration/identity-providers/open-id-connect/).
Create a client for homarr. To generate client secret you can [use authelia](https://www.authelia.com/integration/openid-connect/frequently-asked-questions/#how-do-i-generate-client-secrets). This is an example config:
Create a client for homarr. To generate client secret you can [use authelia](https://www.authelia.com/integration/openid-connect/frequently-asked-questions/#how-do-i-generate-client-secrets). This is an example config:
```yaml
identity_providers:
oidc:
...
clients:
- id: homarr
secret: <secret_hash>
public: false
authorization_policy: one_factor
redirect_uris:
- https://example.com/api/auth/callback/oidc
- http://localhost:3000/api/auth/callback/oidc
scopes:
- openid
- groups
- profile
- email
userinfo_signing_algorithm: none
consent_mode: implicit # self hosted
```
```yaml
identity_providers:
oidc:
...
clients:
- id: homarr
secret: <secret_hash>
public: false
authorization_policy: one_factor
redirect_uris:
- https://example.com/api/auth/callback/oidc
- http://localhost:3000/api/auth/callback/oidc
scopes:
- openid
- groups
- profile
- email
userinfo_signing_algorithm: none
consent_mode: implicit # self hosted
```
In Homarr use following env variables.
In Homarr use following env variables.
```
AUTH_PROVIDERS="oidc"
AUTH_OIDC_ISSUER="https://auth.example.com"
AUTH_OIDC_CLIENT_SECRET="client_secret"
AUTH_OIDC_CLIENT_ID="homarr"
AUTH_OIDC_CLIENT_NAME="Authelia"
AUTH_OIDC_FORCE_USERINFO="true" --> from v4.39 of authelia and above this is required
```
```
AUTH_PROVIDERS="oidc"
AUTH_OIDC_ISSUER="https://auth.example.com"
AUTH_OIDC_CLIENT_SECRET="client_secret"
AUTH_OIDC_CLIENT_ID="homarr"
AUTH_OIDC_CLIENT_NAME="Authelia"
AUTH_OIDC_FORCE_USERINFO="true" --> from v4.39 of authelia and above this is required
```
For an azure app registration the setup could look like this:
For an azure app registration the setup could look like this:
```
AUTH_PROVIDERS="oidc"
AUTH_OIDC_ISSUER="https://login.microsoftonline.com/<teanant-id>/v2.0"
AUTH_OIDC_CLIENT_SECRET="<client-secret>"
AUTH_OIDC_CLIENT_ID="<client-id>"
AUTH_OIDC_CLIENT_NAME="Azure"
AUTH_OIDC_SCOPE_OVERWRITE="openid email profile" # Groups scope does not exist in azure
AUTH_OIDC_GROUPS_ATTRIBUTE="roles" # We use the roles of the app registration so that we don't need to use uuids as our groups
```
```
AUTH_PROVIDERS="oidc"
AUTH_OIDC_ISSUER="https://login.microsoftonline.com/<teanant-id>/v2.0"
AUTH_OIDC_CLIENT_SECRET="<client-secret>"
AUTH_OIDC_CLIENT_ID="<client-id>"
AUTH_OIDC_CLIENT_NAME="Azure"
AUTH_OIDC_SCOPE_OVERWRITE="openid email profile" # Groups scope does not exist in azure
AUTH_OIDC_GROUPS_ATTRIBUTE="roles" # We use the roles of the app registration so that we don't need to use uuids as our groups
```
</div>
</details>
</div>
</details>
### OIDC configuration
### Configuration
| Environment Variable | Description | Default value |
|-----------------------------|------------------------------------------------------------|---------------|
| ``AUTH_OIDC_ISSUER`` | Issuer URI of OIDC provider. This has generally to be **without trailing slash** except for **Authentik** | --- |
| ``AUTH_OIDC_CLIENT_ID`` | ID of OIDC client (application) | --- |
| ``AUTH_OIDC_CLIENT_SECRET`` | Secret of OIDC client (application) | --- |
| ``AUTH_OIDC_CLIENT_NAME`` | Display name of provider (in login screen) | OIDC |
| ``AUTH_OIDC_AUTO_LOGIN`` | Automatically redirect to OIDC login | false |
| ``AUTH_OIDC_SCOPE_OVERWRITE`` | Overwrite default scopes (openid, profile, email) | openid email profile groups |
| ``AUTH_OIDC_GROUPS_ATTRIBUTE`` | Attribute used for groups (roles) claim. Dot-separated paths such as `resource_access.homarr.roles` are supported. | groups |
| ``AUTH_OIDC_GROUPS_LOCAL_MANAGEMENT`` | Stop syncing group memberships of OIDC users from the groups claim and manage them locally via the group members page instead | false |
| ``AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE`` | Overwrite name attribute. Dot-separated paths are supported. By default it will use preferred_username if it does not contain a `@` and otherwise name. | --- |
| ``AUTH_OIDC_FORCE_USERINFO`` | Force userinfo endpoint to be used for user information. | false |
| ``AUTH_OIDC_ENABLE_DANGEROUS_ACCOUNT_LINKING`` | Enable account linking for OIDC provider. This will link the OIDC accounts by email. Be sure that you have verified emails to prevent stealing accounts. | false |
| ``AUTH_OIDC_ENABLE_DANGEROUS_CREDENTIALS_LINKING`` | Link an OIDC identity to an existing credentials user with the same email. The credentials login and existing user data are preserved. Requires the OIDC profile to contain `email_verified: true`. | false |
| ``AUTH_OIDC_TOKEN_ENDPOINT_AUTH_METHOD`` | Override method for the token endpoint authentication. Supported values are `client_secret_basic`, `client_secret_post`, `client_secret_jwt` and `none`. | client_secret_basic |
| Environment Variable | Description | Default value |
|-----------------------------|------------------------------------------------------------|---------------|
| ``AUTH_OIDC_ISSUER`` | Issuer URI of OIDC provider. This has generally to be **without trailing slash** except for **Authentik** | --- |
| ``AUTH_OIDC_CLIENT_ID`` | ID of OIDC client (application) | --- |
| ``AUTH_OIDC_CLIENT_SECRET`` | Secret of OIDC client (application) | --- |
| ``AUTH_OIDC_CLIENT_NAME`` | Display name of provider (in login screen) | OIDC |
| ``AUTH_OIDC_AUTO_LOGIN`` | Automatically redirect to OIDC login | false |
| ``AUTH_OIDC_SCOPE_OVERWRITE`` | Overwrite default scopes (openid, profile, email) | openid email profile groups |
| ``AUTH_OIDC_GROUPS_ATTRIBUTE`` | Attribute used for groups (roles) claim. Dot-separated paths such as `resource_access.homarr.roles` are supported. | groups |
| ``AUTH_OIDC_GROUPS_LOCAL_MANAGEMENT`` | Stop syncing group memberships of OIDC users from the groups claim and manage them locally via the group members page instead | false |
| ``AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE`` | Overwrite name attribute. Dot-separated paths are supported. By default it will use preferred_username if it does not contain a `@` and otherwise name. | --- |
| ``AUTH_OIDC_FORCE_USERINFO`` | Force userinfo endpoint to be used for user information. | false |
| ``AUTH_OIDC_ENABLE_DANGEROUS_ACCOUNT_LINKING`` | Enable account linking for OIDC provider. This will link the OIDC accounts by email. Be sure that you have verified emails to prevent stealing accounts. | false |
| ``AUTH_OIDC_ENABLE_DANGEROUS_CREDENTIALS_LINKING`` | Link an OIDC identity to an existing credentials user with the same email. The credentials login and existing user data are preserved. Requires the OIDC profile to contain `email_verified: true`. | false |
| ``AUTH_OIDC_TOKEN_ENDPOINT_AUTH_METHOD`` | Override method for the token endpoint authentication. Supported values are `client_secret_basic`, `client_secret_post`, `client_secret_jwt` and `none`. | client_secret_basic |
### OIDC permissions
### Permission System
To give a user special permissions, first create a new group in homarr and assign the permission desired.
For example if the group on homarr is called `homarr-admins` a new group on the oidc provider, for example authentik needs to be created with the same name, that would be `homarr-admins`.
After assigning the group on the oidc provider to the user, and logging again into homarr, the user should automatically get placed in that group and inherit the permissions defined.
To give a user special permissions, first create a new group in homarr and assign the permission desired.
For example if the group on homarr is called `homarr-admins` a new group on the oidc provider, for example authentik needs to be created with the same name, that would be `homarr-admins`.
After assigning the group on the oidc provider to the user, and logging again into homarr, the user should automatically get placed in that group and inherit the permissions defined.
</TabItem>
</Tabs>
## Example setups
@@ -239,7 +247,7 @@ After assigning the group on the oidc provider to the user, and logging again in
Generate `SECRET_ENCRYPTION_KEY` with `openssl rand -hex 32`; do not copy an example key between installs.
```bash
```env
OIDC_CLIENT_ID=<REPLACE_WITH_OIDC_CLIENT_ID>
OIDC_CLIENT_SECRET=<REPLACE_WITH_OIDC_CLIENT_SECRET>
OIDC_SLUG=homarr #Application slug in Authentik
@@ -290,7 +298,7 @@ After assigning the group on the oidc provider to the user, and logging again in
</div>
</details>
See [OIDC configuration](#oidc-configuration) for additional options.
Additional OIDC configuration options are described in the OIDC tab above.
</TabItem>
<TabItem value="google" label="Google (OIDC) Example" default>
@@ -318,7 +326,7 @@ After assigning the group on the oidc provider to the user, and logging again in
Generate `SECRET_ENCRYPTION_KEY` with `openssl rand -hex 32`; do not copy an example key between installs.
```bash
```env
OIDC_CLIENT_ID=<REPLACE_WITH_GOOGLE_CLIENT_ID>
OIDC_CLIENT_SECRET=<REPLACE_WITH_GOOGLE_CLIENT_SECRET>
HOMARR_FQDN=homarr.example.com #Homarr FQDN
@@ -356,7 +364,7 @@ After assigning the group on the oidc provider to the user, and logging again in
</div>
</details>
See [OIDC configuration](#oidc-configuration) for additional options.
Additional OIDC configuration options are described in the OIDC tab above.
</TabItem>
</Tabs>
+8
View File
@@ -0,0 +1,8 @@
{
"label": "Community",
"position": 6,
"collapsed": true,
"link": {
"type": "generated-index"
}
}
-10
View File
@@ -1,10 +0,0 @@
---
title: Community
description: Get help, contribute to Homarr, and support the project.
---
- [Frequently asked questions](/docs/community/faq): resolve common setup and operation issues.
- [Get in touch](/docs/community/get-in-touch): choose the right support or discussion channel.
- [Translations](/docs/community/translations): improve Homarr in your language.
- [Donate](/docs/community/donate): support ongoing development.
- [License](/docs/community/license): understand how Homarr is licensed.
-5
View File
@@ -1,5 +0,0 @@
{
"title": "Community",
"defaultOpen": false,
"pages": ["index", "faq", "get-in-touch", "translations", "donate", "license"]
}
@@ -0,0 +1,9 @@
{
"label": "Getting started",
"position": 1,
"collapsed": false,
"link": {
"type": "generated-index",
"title": "Getting started"
}
}
@@ -6,68 +6,11 @@ tags:
- Configuration
---
import {
IconAdjustments,
IconChecklist,
IconLayoutDashboard,
IconPlugConnected,
IconSearch,
IconSparkles,
} from "@tabler/icons-react";
On first launch, onboarding creates the administrator, connects optional services, and builds the first board. A
compatible SQLite backup can also be restored from the welcome screen.
import onboardingWelcome from "./img/onboarding-v2-welcome.png";
import onboardingBoard from "./img/onboarding-v2-board.png";
import onboardingReview from "./img/onboarding-v2-review.png";
After Homarr starts, open its URL. An unfinished installation redirects to the onboarding screen at `/init`. Choose
**Get started** for a new installation or **Restore backup** to import a compatible SQLite backup.
<Callout type="info" title="Persist /appdata before you continue">
Onboarding writes the administrator and board configuration to the database. If onboarding returns after a restart,
check that `/appdata` is writable and persisted. See the
[Docker installation guide](/docs/getting-started/installation/docker).
</Callout>
## Complete onboarding
Onboarding is split into six short sections. Integrations, Workshop, Assistant, and MCP are optional; skip them when you
only need a working board.
<Cards>
<Card icon={<IconAdjustments />} title="1. Essentials">
Choose the language, theme, usual server address, and anonymous analytics preference.
</Card>
<Card icon={<IconSearch />} title="2. Discover">
Review the database, Docker, Kubernetes, Assistant, and Workshop capabilities Homarr can reach.
</Card>
<Card icon={<IconPlugConnected />} title="3. Connect">
Import detected services or add integrations manually. Unfinished integrations can be skipped.
</Card>
<Card icon={<IconLayoutDashboard />} title="4. Board">
Set the board name, colors, corner radius, column count, and optional sidebars.
</Card>
<Card icon={<IconSparkles />} title="5. Extend">
Optionally connect the Workshop, configure an Assistant provider, or review the MCP endpoint.
</Card>
<Card icon={<IconChecklist />} title="6. Review">
Check the final summary, then build the board. Homarr opens the exact board it configured.
</Card>
</Cards>
The final screen links directly to the new board and the management area. Board layout, integrations, apps, and
appearance can all be changed later.
<Cards>
<Card title="Start or restore">
<img src={onboardingWelcome.src} alt="Homarr onboarding welcome screen with Get started and Restore backup actions" />
</Card>
<Card title="Configure the board">
<img src={onboardingBoard.src} alt="Board onboarding section for colors, columns, corner radius, and sidebars" />
</Card>
<Card title="Review before building">
<img src={onboardingReview.src} alt="Onboarding review showing the board settings Homarr will create" />
</Card>
</Cards>
If onboarding returns after a restart, check that `/appdata` is writable and persisted. See the
[Docker installation guide](/docs/getting-started/installation/docker).
## Core concepts
@@ -97,7 +40,7 @@ Docker. Integrations provide data and actions to widgets. They can also be linke
![Integration catalog with compatible widgets](./img/after-installation-integrations.webp)
See [Managing integrations](/docs/management/integrations) and the
[integration catalog](/docs/integrations).
[integration catalog](/docs/category/integrations).
### Widgets
@@ -106,7 +49,7 @@ supported integrations, and non-obvious limitations are documented on each widge
![Board in edit mode with the add-content menu](./img/after-installation-widgets.webp)
See the [widget catalog](/docs/widgets).
See the [widget catalog](/docs/category/widgets).
### Containers and rails
Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

@@ -0,0 +1,9 @@
{
"label": "Installation",
"position": 1,
"collapsed": true,
"link": {
"type": "generated-index",
"title": "Getting started"
}
}
@@ -1,84 +0,0 @@
---
title: Install Homarr
description: Choose the installation method that matches your infrastructure.
full: true
---
import {
IconApps,
IconBox,
IconBrandDocker,
IconBrandGithub,
IconCloud,
IconContainer,
IconDatabase,
IconHexagons,
IconHome,
IconLayoutDashboard,
IconServer2,
IconTrain,
} from "@tabler/icons-react";
Docker Compose is the best starting point for most self-hosters. Choose a platform-specific guide when Homarr will run inside an existing server manager or managed service.
<Callout type="idea" title="Not sure which guide to choose?">
Start with **Docker Compose**. It is the recommended path, has the broadest community support, and makes updates and
backups straightforward.
</Callout>
## Recommended
<Cards>
<Card icon={<IconBrandDocker />} title="Docker Compose" href="/docs/getting-started/installation/docker">
The recommended installation for most Linux and Windows servers.
</Card>
<Card icon={<IconHexagons />} title="Kubernetes with Helm" href="/docs/getting-started/installation/helm">
Deploy Homarr into an existing Kubernetes cluster.
</Card>
<Card icon={<IconBrandGithub />} title="Build from source" href="/docs/getting-started/installation/source">
Build and run Homarr directly from the repository.
</Card>
</Cards>
## Self-hosting platforms
<Cards>
<Card icon={<IconServer2 />} title="Unraid" href="/docs/getting-started/installation/unraid">
Install Homarr from the Unraid Community Apps catalog.
</Card>
<Card icon={<IconDatabase />} title="Synology" href="/docs/getting-started/installation/synology">
Run Homarr on a Synology NAS with Container Manager.
</Card>
<Card icon={<IconServer2 />} title="Proxmox" href="/docs/getting-started/installation/proxmox">
Add Homarr to a Proxmox-based homelab.
</Card>
<Card icon={<IconHome />} title="Home Assistant Add-on" href="/docs/getting-started/installation/home-assistant">
Install Homarr alongside your Home Assistant environment.
</Card>
<Card icon={<IconContainer />} title="Portainer" href="/docs/getting-started/installation/portainer">
Deploy and manage Homarr through Portainer stacks.
</Card>
<Card icon={<IconDatabase />} title="QNAP" href="/docs/getting-started/installation/qnap">
Run Homarr on a QNAP NAS.
</Card>
<Card icon={<IconApps />} title="Runtipi" href="/docs/getting-started/installation/runtipi">
Add Homarr from the Runtipi app store.
</Card>
</Cards>
## Managed and app platforms
<Cards>
<Card icon={<IconLayoutDashboard />} title="EasyPanel" href="/docs/getting-started/installation/easy-panel">
Deploy Homarr from an Easypanel template.
</Card>
<Card icon={<IconTrain />} title="Railway" href="/docs/getting-started/installation/railway">
Launch Homarr as a managed Railway service.
</Card>
<Card icon={<IconCloud />} title="PikaPods" href="/docs/getting-started/installation/pika-pods">
Use a hosted Homarr instance without managing a server.
</Card>
<Card icon={<IconBox />} title="Saltbox" href="/docs/getting-started/installation/saltbox">
Add Homarr to a Saltbox deployment.
</Card>
</Cards>
@@ -1,24 +0,0 @@
{
"title": "Installation",
"defaultOpen": false,
"pages": [
"index",
"---Recommended---",
"docker",
"helm",
"source",
"---Self-hosting platforms---",
"unraid",
"synology",
"proxmox",
"home-assistant",
"portainer",
"qnap",
"runtipi",
"---Managed and app platforms---",
"easy-panel",
"railway",
"pika-pods",
"saltbox"
]
}
@@ -1,4 +1,4 @@
import Link from "@/components/mdx/link";
import Link from "@docusaurus/Link";
import { IconDownload } from "@tabler/icons-react";
# Unraid
-5
View File
@@ -1,5 +0,0 @@
{
"title": "Getting started",
"defaultOpen": false,
"pages": ["index", "installation", "after-the-installation", "upgrade-v2", "glossary"]
}
-72
View File
@@ -1,72 +0,0 @@
---
title: Homarr documentation
description: Install, configure, operate, and extend Homarr.
---
import {
IconApi,
IconArrowUp,
IconBuildingStore,
IconChecklist,
IconCode,
IconComponents,
IconDownload,
IconLayoutDashboard,
IconPlugConnected,
IconSettings,
IconUsers,
IconVocabulary,
} from "@tabler/icons-react";
Use these guides to get Homarr running, connect your services, build useful boards, and manage an installation over time.
## Install or upgrade
<Cards>
<Card icon={<IconDownload />} title="Install Homarr" href="/docs/getting-started/installation">
Choose the installation method for your system.
</Card>
<Card icon={<IconArrowUp />} title="Upgrade from v1" href="/docs/getting-started/upgrade-v2">
Move an existing Homarr installation to v2.
</Card>
<Card icon={<IconChecklist />} title="Finish setup" href="/docs/getting-started/after-the-installation">
Add apps, integrations, and widgets after installation.
</Card>
<Card icon={<IconVocabulary />} title="Learn the concepts" href="/docs/getting-started">
Understand boards, apps, integrations, and widgets.
</Card>
</Cards>
## Configure Homarr
<Cards>
<Card icon={<IconLayoutDashboard />} title="Boards and content" href="/docs/management">
Configure boards, apps, users, settings, and administration.
</Card>
<Card icon={<IconPlugConnected />} title="Connect services" href="/docs/integrations">
Find the setup guide for an integration.
</Card>
<Card icon={<IconComponents />} title="Choose widgets" href="/docs/widgets">
Find the content and controls available for boards.
</Card>
<Card icon={<IconSettings />} title="Advanced configuration" href="/docs/advanced">
Configure deployment, authentication, networking, and automation.
</Card>
</Cards>
## Extend and contribute
<Cards>
<Card icon={<IconCode />} title="Custom Widgets" href="/docs/management/custom-widgets">
Author and publish Custom JSX widgets.
</Card>
<Card icon={<IconBuildingStore />} title="Community Workshop" href="/docs/workshop">
Use and operate the community extension registry.
</Card>
<Card icon={<IconApi />} title="API reference" href="/api-reference">
Inspect Homarr's HTTP API.
</Card>
<Card icon={<IconUsers />} title="Get help and contribute" href="/docs/community">
Find support and ways to contribute.
</Card>
</Cards>
@@ -0,0 +1,10 @@
{
"label": "Integrations",
"collapsed": true,
"position": 3,
"link": {
"type": "generated-index",
"title": "Integrations",
"description": "Connect Homarr to supported services so widgets can display data and run actions. Choose an integration to see its setup requirements and compatible widgets."
}
}
@@ -21,7 +21,7 @@ import { coolifyWidget } from "../../widgets/coolify";
<AddingIntegration />
:::info[URL configuration]
:::info URL configuration
Use the root URL of your Coolify instance, for example `https://coolify.example.com`. Homarr calls Coolify endpoints under `/api` and `/api/v1` automatically.
:::
+1 -1
View File
@@ -9,7 +9,7 @@ import { IntegrationCapabilites } from "@site/src/components/integrations/widget
import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import { IconDownload } from "@tabler/icons-react";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
import { delugeIntegration } from ".";
import { downloadsWidget } from "@site/docs/widgets/downloads";
+1 -1
View File
@@ -117,7 +117,7 @@ updating a Homarr resource still requires confirmation. If one endpoint is unava
endpoints remain visible.
The `homarr.hide` label excludes a container. Other `homarr.*` labels can provide apps, integrations, groups, and widgets
during onboarding; see [Docker label discovery](/docs/integrations/docker-labels).
during onboarding; see [Docker label discovery](../docker-labels).
## Security
-21
View File
@@ -1,21 +0,0 @@
---
title: Integrations
description: Connect Homarr to the applications and infrastructure you operate.
---
import { DocsDirectory } from "@/components/docs/docs-directory";
An integration stores the connection and authentication details Homarr needs to communicate with another service. Widgets and management tools can then reuse that connection.
Each guide identifies the required URL and credentials, supported capabilities, and the widgets that use the integration.
<DocsDirectory section="integrations" />
## Before you connect a service
1. Confirm that Homarr can reach the service from its own network.
2. Create the least-privileged account, token, or API key supported by the service.
3. Add the integration in **Manage → Integrations**.
4. Test the connection before adding dependent widgets.
See [Manage integrations](/docs/management/integrations) for the shared workflow.
-5
View File
@@ -1,5 +0,0 @@
{
"title": "Integrations",
"defaultOpen": false,
"pages": ["index", "..."]
}
@@ -9,7 +9,7 @@ import { IntegrationCapabilites } from "@site/src/components/integrations/widget
import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import { IconCalendar } from "@tabler/icons-react";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
import { nextcloudIntegration } from ".";
import { calendarWidget } from "@site/docs/widgets/calendar";
import { notificationsWidget } from "@site/docs/widgets/notifications";
+1 -1
View File
@@ -10,7 +10,7 @@ import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import { IconDownload } from "@tabler/icons-react";
import { nzbgetIntegration } from ".";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
import { downloadsWidget } from "@site/docs/widgets/downloads";
<IntegrationHeader integration={nzbgetIntegration} categories={["Usenet client"]} />
@@ -10,7 +10,7 @@ import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import { IconHeartRateMonitor } from "@tabler/icons-react";
import { openMediaVaultIntegration } from ".";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring";
import { systemResourcesWidget } from "@site/docs/widgets/system-resources";
@@ -8,6 +8,7 @@ import { IntegrationHeader } from "@site/src/components/integrations/header";
import { IntegrationCapabilites } from "@site/src/components/integrations/widgets";
import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import Alert from "@theme/Admonition";
import { dnsHoleSummaryWidget } from "@site/docs/widgets/dns-hole-summary";
import { dnsHoleControlsWidget } from "@site/docs/widgets/dns-hole-controls";
import { piHoleIntegration } from ".";
@@ -10,7 +10,7 @@ import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import { IconDownload } from "@tabler/icons-react";
import { qBittorentIntegration } from ".";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
import { downloadsWidget } from "@site/docs/widgets/downloads";
<IntegrationHeader integration={qBittorentIntegration} categories={["Torrent client"]} />
@@ -10,7 +10,7 @@ import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import { IconDownload } from "@tabler/icons-react";
import { sabnzbdIntegration } from ".";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
import { downloadsWidget } from "@site/docs/widgets/downloads";
<IntegrationHeader integration={sabnzbdIntegration} categories={["Usenet client"]} />
@@ -32,3 +32,10 @@ import { calendarWidget } from "@site/docs/widgets/calendar";
},
]}
/>
### Trusted widget packages
The [Sonarr operations reference package](/docs/management/custom-widgets/trusted-packages) can combine two Sonarr
integrations, display upcoming and missing episodes and queue progress, and submit a confirmed search for a missing
episode. Search actions use the existing integration API key on Homarr's server and require interaction access.
A successful command submission means Sonarr queued the search, not that it found or downloaded a release.
@@ -12,7 +12,7 @@ import { synologyIntegration } from ".";
import { systemResourcesWidget } from "@site/docs/widgets/system-resources";
import { systemDisksWidget } from "@site/docs/widgets/system-disks";
import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
<IntegrationHeader integration={synologyIntegration} categories={["NAS", "Hardware"]} />
@@ -8,7 +8,7 @@ import { IntegrationHeader } from "@site/src/components/integrations/header";
import { IntegrationCapabilites } from "@site/src/components/integrations/widgets";
import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
import { technitiumDnsIntegration } from ".";
import { dnsHoleSummaryWidget } from "@site/docs/widgets/dns-hole-summary";
import { dnsHoleControlsWidget } from "@site/docs/widgets/dns-hole-controls";
@@ -21,11 +21,11 @@ import { traefikWidget } from "../../widgets/traefik";
<AddingIntegration />
:::info[URL configuration]
:::info URL configuration
Use the URL where Traefik exposes its dashboard/API, for example `http://traefik:8080` or `https://traefik.example.com`. Homarr calls Traefik endpoints under `/api` automatically.
:::
:::warning[API requirement]
:::warning API requirement
Traefik must have the API enabled. For local or internal setups this is commonly exposed through `api.insecure=true`; for production setups, expose the `api@internal` service through an authenticated router.
:::
@@ -10,7 +10,7 @@ import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import { IconDownload } from "@tabler/icons-react";
import { transmissionIntegration } from ".";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
import { downloadsWidget } from "@site/docs/widgets/downloads";
<IntegrationHeader integration={transmissionIntegration} categories={["Torrent client"]} />
@@ -11,7 +11,7 @@ import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import { truenasIntegration } from ".";
import { systemResourcesWidget } from "@site/docs/widgets/system-resources";
import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring";
import Alert from "@/components/mdx/admonition";
import Alert from "@theme/Admonition";
<IntegrationHeader integration={truenasIntegration} categories={["NAS", "Hardware"]} />
+1 -1
View File
@@ -21,7 +21,7 @@ import { umamiWidget } from "../../widgets/umami";
<AddingIntegration />
:::tip[URL configuration]
:::tip URL configuration
- **Umami Cloud:** Use `https://api.umami.is/v1`
- **Self-hosted:** Use `http://your-umami-host:3000/api`
@@ -23,7 +23,7 @@ The What's Up Docker integration lets Homarr connect to your [WUD](https://githu
<AddingIntegration />
:::info[URL configuration]
:::info URL configuration
Use the root URL of your WUD instance, for example `https://wud.example.com`. Homarr calls the `/api/app` and `/api/containers` endpoints under that URL automatically.
:::
@@ -0,0 +1,9 @@
{
"label": "Management",
"collapsed": true,
"position": 2,
"link": {
"type": "generated-index",
"title": "Management pages"
}
}
+40 -2
View File
@@ -96,5 +96,43 @@ integration fails, the query returns an error.
Authenticated administrators can retrieve the current Custom Widget authoring prompt, schema, component catalog, skill,
and focused references under `/api/custom-widgets/`.
Use [Custom Widget agent authoring](/docs/management/custom-widgets/agent-authoring) for the lifecycle and
[MCP](/docs/management/mcp) when the client supports Model Context Protocol.
Use [Custom Widget agent authoring](../custom-widgets/agent-authoring) for the lifecycle and
[MCP](../mcp) when the client supports Model Context Protocol.
## Trusted widget package lifecycle
The `customWidget.package` tRPC namespace separates authoring from activation. Administrators can save incomplete
source with `saveDraft`, inspect `draftChanges`, run `preview`, and call `activate` after acknowledging trusted code.
`getRaw` and `repair` on `customWidget` recover existing v2 definitions without rendering their code.
The package API also manages named local connections, per-placement guest grants, retained collectors, immutable
archive import/export, forks, Workshop releases, staged updates, and rollback. `get` and `list` return management data
without evaluating submitted package modules. Connection secret values are accepted separately by `saveConnection`
and are not returned by connection listing or package export.
For an existing connection, `secretUpdates` patches only supplied credential keys while retaining the others;
`secrets` replaces the complete credential map. Supply only one. Credential patches require the saved connection
kind and authentication method to match the submitted configuration.
`previewStorageGet` and `previewStorageSet` use the owning administrator's preview session and the same temporary
store as its server handlers. They accept `previewId`, `scope`, and `key`; writes also accept `value`.
Expired, discarded, and other users' sessions cannot read or write preview storage.
Connection configuration accepts `kind: "http" | "integration" | "service"`. A service connection supplies a
`serviceType` and a JSON `settings` object without requiring a URL; encrypted `secrets` remain a separate input.
Package requirements match both `kind` and `serviceType`. Server handlers access these settings through
`getWidgetConnection` in `@homarr/widget-sdk/server`. Service diagnostics distinguish file readability, TCP
reachability and settings-only checks; preview runs the adapter's actual database or protocol operation.
Installed widgets use `widget.customApi.packageQuery`, `packageAction`, `packageSubscription`, `packageStorageGet`,
and `packageStorageSet`. Each invocation is bound to an existing board item and a manifest-declared handler; the host
checks the current board and integration permissions. A public board does not grant action access automatically.
Guest grants name a handler and exact allowed inputs, and are invalidated by changes to server behavior, dependencies,
connection identity, or resource-selecting options.
Compiled surfaces are served through `/api/custom-widgets/artifacts/{itemId}/{digest}/{surface}` after board access
checks. The optional `?asset=css` selects the corresponding stylesheet. Preview surfaces use
`/api/custom-widgets/previews/{previewId}/{surface}` and require the administrator who created the preview.
These routes do not expose server source or connection credentials.
The full package format, SDK examples, trust boundary, and activation behavior are described in
[trusted widget packages](../custom-widgets/trusted-packages).
+4 -4
View File
@@ -27,13 +27,13 @@ model, and enable Assistant. Users can choose another available model for a conv
Provider presets cover common APIs. **Custom endpoint** accepts an OpenAI-compatible Chat Completions API. For a model
server outside the Homarr container, use a hostname that the container can resolve instead of `localhost`.
The [Homarr provider](/docs/workshop/homarr-provider) is available through the Community Workshop without an administrator
The [Homarr provider](../workshop/homarr-provider) is available through the Community Workshop without an administrator
API key and has a daily request allowance.
## Access
Open Assistant from the user menu, with `Shift+A`, from search with `Cmd/Ctrl+/`, or through the
[Assistant widget](/docs/widgets/assistant).
[Assistant widget](../widgets/assistant).
Assistant can work with boards, apps, integrations, widgets, Custom Widgets, and supported connected services. Mention
Homarr resources with `@`; the model loads additional live context only when needed.
@@ -47,8 +47,8 @@ Conversations are stored per user and can be searched, renamed, exported, or del
- Provider keys and custom headers are encrypted and are not returned to the browser.
- Prompts, attachments, tool definitions, and tool results are sent to the selected model provider.
See [MCP](/docs/management/mcp) to connect an external AI client and
[Custom Widget agent authoring](/docs/management/custom-widgets/agent-authoring) for widget generation.
See [MCP](./mcp) to connect an external AI client and
[Custom Widget agent authoring](./custom-widgets/agent-authoring) for widget generation.
## Troubleshooting
+14
View File
@@ -38,3 +38,17 @@ A backup can be restored on another Homarr instance. When its `SECRET_ENCRYPTION
integration secrets for the target instance. Version metadata is used to apply compatible migrations.
The same restore flow is available during first-run onboarding, before the target database contains user data.
## Custom widget packages
Database backups include installed v2 definitions and trusted v3 source, compiled artifacts, current and previous
activation metadata, local connections, placement bindings, guest grants, and managed widget storage/history.
Restoring an encrypted backup re-encrypts widget credentials with the destination instance's key alongside native
integration credentials. Compiled artifacts can be materialized again from the restored database without Workshop.
Keep `SECRET_ENCRYPTION_KEY` with database backups made using MySQL or PostgreSQL administration tools. The built-in
ZIP export/restore remains specific to SQLite. A package export is portable distribution material and deliberately
excludes local connections, credentials, stored values, and collected history; it is not a complete instance backup.
Files created directly by trusted Node code, external databases, remote-runner state, and changes already made to
other applications are outside Homarr's managed widget storage. Include those resources in your own backup process.
+1 -1
View File
@@ -98,4 +98,4 @@ inside a board.
Defaults can be set for a user, group, or the whole server. User settings take priority, followed by matching groups,
the `Everyone` group, and server defaults. Server-wide fallback boards must be public.
See [Users and groups](/docs/management/users) and [Server settings](/docs/management/settings#boards).
See [Users and groups](../users) and [Server settings](../settings#boards).
@@ -0,0 +1,9 @@
{
"label": "Custom Widgets",
"collapsed": true,
"position": 8,
"link": {
"type": "doc",
"id": "management/custom-widgets/index"
}
}
@@ -41,5 +41,5 @@ authenticated administrator completes it in Homarr; the agent receives the statu
Agents can also search, inspect, install, and configure existing Workshop widgets instead of regenerating them.
See [MCP](/docs/management/mcp) for client configuration and [requests and security](/docs/management/custom-widgets/requests-and-security) for the
See [MCP](/docs/management/mcp) for client configuration and [requests and security](./requests-and-security) for the
runtime limits.
@@ -5,21 +5,32 @@ JSON is available when direct editing is faster.
## Workflow
1. Configure each API source, network scope, authentication method, and credential.
2. Add named queries and actions. Values can reference widget options or invocation parameters.
1. Start with a static widget, or add API sources, network access, authentication, and credentials when needed.
2. Add named queries and actions for connected services. Values can reference widget options or invocation parameters.
3. Define widget options and their defaults.
4. Write JSX using `data`, `status`, `options`, and temporary `inputs`.
5. Run **Test and preview**, inspect the response data and redacted request journal, then save.
Changing the definition, options, or credentials invalidates the previous preview. Preview actions are simulated unless
Changing the definition, options, or credentials ends the previous API preview session. The last response remains visible
as a labelled snapshot while you edit JSX. Run **Test and preview** again to refresh data and enable API interactions.
Preview actions are simulated unless
**Run actions against the configured API** is enabled for that preview session.
Use the workbench **Undo** and **Redo** buttons or `Ctrl/Cmd+Z` and `Ctrl/Cmd+Shift+Z` for changes across JSX, sources,
requests, options, and metadata. History is bounded to 100 entries and about two million characters. **Reset to saved**
restores the last saved definition. Credentials are excluded from this history and reset clears unsaved credential values.
Undo and Redo retain pending credentials only when the source origin, network scope, and authentication destination
are unchanged. Otherwise, enter the credentials again for the restored source.
Homarr keeps one recovery draft per signed-in user in this browser, replacing the previous draft as you edit. On returning
to that widget, choose **Restore draft** or **Discard draft**. Saved credentials stay on the server; unsaved credentials must
be entered again. Browser storage is optional, and drafts larger than one million characters are not stored for recovery.
Widget options support text, textarea, number, switch, select, multi-select, slider, date, time, color, icon, URL,
duration, time zone, and JSON controls. Dynamic choices can come from a load query.
See the [safe JSX runtime](/docs/management/custom-widgets/custom-jsx),
[component reference](/docs/management/custom-widgets/component-reference), and
[request reference](/docs/management/custom-widgets/requests-and-security) for the authoring contract.
See the [safe JSX runtime](./custom-jsx), [component reference](./component-reference), and
[request reference](./requests-and-security) for the authoring contract.
## Create with another AI service
@@ -27,4 +38,4 @@ See the [safe JSX runtime](/docs/management/custom-widgets/custom-jsx),
must return one fenced `json` block containing the complete definition. Paste that block into the workbench, add
credentials separately, and validate it against a real preview.
For an MCP-connected agent, use the [Homarr Custom Widget skill](/docs/management/custom-widgets/agent-authoring) instead.
For an MCP-connected agent, use the [Homarr Custom Widget skill](./agent-authoring) instead.
@@ -6,8 +6,14 @@ Templates are JSX expressions interpreted inside a widget-local safety and rende
- `status.requestId` — `{ loading, ok, status, statusText, error }`
- `options.name` — saved widget configuration
- `inputs.name` — temporary values from declarative `bind`
- `host` — the widget's board context, dimensions, scale, and compact or advanced display mode
The v2 manifest requires a `default` source and supports up to eight sources, 64 requests, and 64 options. Source IDs are
Existing callbacks may still use `host` as their parameter name, such as `data.hosts.map(host => host.name)`.
Inside that callback, `host` refers to the current item; outside it, `host` refers to the widget context.
The v2 manifest supports empty `sources` and `requests` for widgets that do not need an API. Connected widgets support
up to eight sources, 64 requests, and 64 options. Each request must reference a defined source; omitting `source` uses
`default` only when a source with that ID exists. Source IDs are
case-insensitively unique. Each request allows up to 32 static headers and 32 invalidation targets; a widget can contain
up to 24 secrets, each up to 8,192 characters, and templates are limited to 50,000 characters. Validation reports the
exact field when a limit is exceeded.
@@ -15,7 +15,10 @@ Custom Widgets may change during the v2 release cycle. Share feedback in the
:::
A **Custom Widget** is a validated `homarr-custom-widget-v2` definition containing API sources, queries and actions,
Custom Widgets supports [trusted widget packages](./trusted-packages) with full TSX, CSS, modules, optional Node
handlers, and advanced views, alongside the restricted v2 authoring format. Both can work without an API.
A **v2 Custom Widget** is a validated `homarr-custom-widget-v2` definition containing optional API sources, queries and actions,
optional settings, and a safe JSX template.
Homarr executes requests on the server and renders the template in a restricted runtime. Source credentials are
@@ -37,12 +40,14 @@ boards; actions require authentication and the permission declared by the reques
## Authoring
- [Create a Custom Widget](/docs/management/custom-widgets/authoring) in the workbench or from a copied AI prompt.
- [Use the safe JSX runtime](/docs/management/custom-widgets/custom-jsx) for data bindings, temporary inputs, and components.
- [Browse the component reference](/docs/management/custom-widgets/component-reference).
- [Configure requests and security](/docs/management/custom-widgets/requests-and-security).
- [Connect an agent](/docs/management/custom-widgets/agent-authoring) through MCP and the Homarr skill.
- [Troubleshoot a definition](/docs/management/custom-widgets/troubleshooting).
- [Build a trusted widget package](./trusted-packages), configure local connections, and manage its Workshop releases.
- [Create a Custom Widget](./authoring) in the workbench or from a copied AI prompt.
- [Use the safe JSX runtime](./custom-jsx) for data bindings, temporary inputs, and components.
- [Browse the component reference](./component-reference).
- [Configure requests and security](./requests-and-security).
- [Connect an agent](./agent-authoring) through MCP and the Homarr skill.
- [Troubleshoot a definition](./troubleshooting).
The workbench validates the same schema used by imports, Workshop, HTTP authoring resources, and MCP. Test every query
and simulate relevant actions before saving. Live preview actions are opt-in because they can change the source service.
@@ -1,12 +0,0 @@
{
"title": "Custom Widgets",
"pages": [
"index",
"authoring",
"agent-authoring",
"custom-jsx",
"component-reference",
"requests-and-security",
"troubleshooting"
]
}
@@ -0,0 +1,104 @@
---
title: Remote widget runners
sidebar_position: 8
---
A trusted widget server normally runs beside Homarr. The optional runner executes one installed widget package on
another machine. Use it when the data lives on a NAS filesystem, a separate Docker network, or a host with a database
or browser service that Homarr cannot reach. The runner has the privileges of the account starting it; its child
process provides cancellation and restart, not security isolation.
## Install a runner
Build an archive using `homarr widgets pack widget.json --trust`, copy the archive to the target machine, and run:
```sh
export HOMARR_WIDGET_RUNNER_TOKEN="$(openssl rand -hex 32)"
homarr widgets serve widget.homarr-widget.json --trust --host 127.0.0.1 --port 8787
```
The runner uses the compiled artifact and bundled JavaScript dependencies. It does not contact an npm registry or
accept package uploads. Restart it with a different archive to update its installed version. Keep the token in the
runner environment and Homarr's encrypted connection store. Use a private interface or an HTTPS reverse proxy when
Homarr runs on another machine. `127.0.0.1` identifies the machine or container running the runner.
In Homarr, create an HTTP connection with the runner's base URL and bearer token. Bind it to the package's named
`runner` connection. Only declared query, action, and subscription handlers are remotely callable. Migration
handlers remain local lifecycle operations. Homarr still authorizes the dashboard placement and its named handler
before calling the runner; the runner token represents the trusted Homarr caller.
## Call a remote handler
The local package's `server.ts` can forward to a handler installed on the runner:
```ts
import { callWidgetRunner, defineWidgetServer, subscribeWidgetRunner } from "@homarr/widget-sdk/server";
export default defineWidgetServer({
status: (input, context) => callWidgetRunner(context, { connection: "runner", handler: "status", input }),
activity: async function* (input, context) {
yield* subscribeWidgetRunner(context, { connection: "runner", handler: "activity", input });
},
});
```
Declare `status` as a query and `activity` as a subscription in both manifests. The remote package accesses its own
environment and filesystem. It has no automatic backchannel to Homarr's storage, native integrations, or connection
credentials. Put those operations in the local forwarding handler when needed.
The pull subscription transport waits up to ten seconds per read, buffers at most 32 values or 8 MiB, and closes
subscriptions that are not read for sixty seconds. Returning from an async generator completes the stream. Use
`context.signal` to release connections and stop work on cancellation.
## Apps without an HTTP API
An API request is optional. A widget may use only JSX, local browser state, a timer, or static information. Trusted
server handlers can read files, speak other protocols, or query a database using the runner's location and account.
For an application that writes a JSON status file, a remote handler can read that file:
```ts
import { readFile } from "node:fs/promises";
import { defineWidgetServer } from "@homarr/widget-sdk/server";
export default defineWidgetServer({
status: async (_input, context) => {
const path = process.env.APP_STATUS_FILE;
if (!path) throw new Error("Set APP_STATUS_FILE on the runner");
return JSON.parse(await readFile(path, { encoding: "utf8", signal: context.signal }));
},
});
```
For an application's SQLite database, Node 24 provides a built-in driver:
```ts
import { DatabaseSync } from "node:sqlite";
import { defineWidgetServer } from "@homarr/widget-sdk/server";
export default defineWidgetServer({
recentJobs: () => {
const path = process.env.APP_DATABASE;
if (!path) throw new Error("Set APP_DATABASE on the runner");
const database = new DatabaseSync(path, { readOnly: true });
try {
return database.prepare("SELECT name, status FROM jobs ORDER BY id DESC LIMIT 20").all();
} finally {
database.close();
}
},
});
```
Adapt the query to the application's actual schema. For PostgreSQL, MySQL, or MQTT, declare an exact version of a
JavaScript client dependency, bundle it when packing, and use the runner environment for service credentials. MQTT
subscriptions fit async generator handlers; close the broker client when the handler's signal aborts. Persistent
history belongs in Homarr's collection and history APIs or the application's database.
A browser-only application can be adapted through an existing browser automation service reachable from the runner.
Call that service from a server handler and return structured data to the tile. Browser binaries and native addons
are not shipped inside portable widget archives. Directly bundling a library that requires native addon loading is
rejected; use an independently installed service for that runtime dependency.
These paths enable adapters for many self-hosted applications. The application must still expose something the
runner can read or control, such as HTTP, a socket, a file, a database, or a browser session.
@@ -1,15 +1,21 @@
# Configure requests and security
Most widgets use a single source named `default`; the manifest must contain it. Extra keyed sources are available for widgets
Widgets can use empty `sources` and `requests` objects when they do not need an API. Connected widgets may use a source
named `default` or explicitly name the source on every request. Extra keyed sources are available for widgets
that combine APIs. Source IDs are case-insensitively unique. Base URLs must use HTTP(S), contain no embedded credentials,
query string, or fragment, and sources can be `public`, `private`, or `loopback`. Authentication is `none`, `bearer`,
`basic`, an API-key header, or an API-key query parameter. Credentials belong to the widget but remain outside its manifest.
Source origins are fixed by the definition and source-setup flow; widget options and invocation parameters cannot redirect a
request to a different origin.
Use `private` for LAN addresses, Docker service names, and Tailscale's `100.64.0.0/10` range. Use `loopback` for
`127.0.0.1` or `::1`. Requests run from Homarr: in Docker, loopback addresses point to the Homarr container, while a
service name such as `http://sonarr:8989` must resolve on its Docker network. Public sources cannot reach private or
loopback addresses. Cloud metadata, link-local, multicast, and other reserved targets remain blocked.
## Named requests
Requests are keyed by ID. `source`, `kind`, `method`, `trigger`, `auth`, and `permission` have sensible defaults, so a load query can be as small as:
Requests are keyed by ID. With a source named `default`, a load query can be as small as:
```json
{ "status": { "path": "/api/status" } }
@@ -39,7 +39,7 @@ stale cached query on another replica.
## Runtime warnings
`UNKNOWN_MANTINE_PROP` means the installed Mantine component does not document that property. Check the
[component reference](/docs/management/custom-widgets/component-reference). `BLOCKED_CAPABILITY` means the runtime rejected an unsafe component,
[component reference](./component-reference). `BLOCKED_CAPABILITY` means the runtime rejected an unsafe component,
property, URL, or style capability.
## Workshop unavailable
@@ -0,0 +1,426 @@
---
title: Trusted widget packages
sidebar_position: 2
tags: [Custom Widgets, JSX, Workshop]
---
# Trusted widget packages
Trusted packages let administrators write complete React/TSX modules, import CSS and dependencies, and optionally run
Node server handlers. A package can provide a dashboard tile, an advanced widget view, and a custom configuration
view. Static content, clocks, interactive local state, and other source-free widgets need no API connection.
Open **Management → Custom Widgets → Packages**. The source-free world clock is the default starter. Thirteen reference starters cover clocks, timers, checklists,
downloads, Sonarr, racks, backups, household controls, service overview, media, Beszel, SQLite, and MQTT. Each new widget receives
its own local package identity. The Beszel
reference package demonstrates a connected widget using Homarr's shared SDK and integration data.
## Trust and execution
Packages are trusted installed code. Browser modules run within Homarr; Node handlers have Homarr's server
privileges. Review the complete source and dependency list before checking the trust acknowledgement. Both
**Run preview** and **Activate saved draft** execute package code. An action simulation is not a security sandbox:
trusted code can make direct network requests and external changes outside the SDK.
Workshop browsing displays screenshots, source text, dependencies, and immutable release metadata. It does not run
package code. Importing a package creates a disabled draft. Connection credentials are entered separately on your
Homarr installation.
A supplied archive can include compiled browser and server code. Its digest verifies that those bytes are intact;
it does not prove they were built from the displayed source. Inspect **Compiled artifact** and the dependency lock
as well as the source before activating a supplied build. Rebuilding from reviewed source produces a new local
artifact; dependency installation happens during that build, never while rendering a dashboard.
## Package, installation, and placement
| Concept | Contains |
| ------------ | ------------------------------------------------------------------------------------------------------------- |
| Package | Portable manifest, source files, exact dependency versions, named connection requirements, option definitions |
| Installation | Saved source draft, active compiled release, previous activation, local connection bindings, enabled state |
| Placement | A tile on a board, its option values, connection overrides, board permissions, widget state |
One installation can appear on several boards. Activating it updates all its placements. A placement's saved option
values survive updates; changing package defaults does not overwrite those saved values.
## Customize a native widget
Administrators can choose **Customize as a widget package** from supported native widget menus. Homarr prepares a
reference package and reuses its existing integration connections. The original native widget remains on the board.
Save the new package, preview and activate it, then add its placement to the board. The package has its own identity
and can be edited independently of the native widget.
## Author a package
The workspace has a file explorer, TSX/CSS/JSON editor, a connection panel, activation and board controls, and a
preview canvas with adjustable width and height. Use `widget.json` to edit package metadata. This is a virtual view
of the package envelope excluding `files`; each source file is edited separately in the explorer.
Use **Add**, **Rename**, and **Remove** to organize source files. When renaming a file, update its imports and any
manifest entrypoints that reference the old path. JSX imports and ordinary React hooks are supported by the trusted
package compiler; the restricted v2 interpreter does not process these files.
The package envelope uses `$schema: "homarr-widget-package-v3"` and contains:
| Field | Purpose |
| -------------- | ------------------------------------------------------------------------------------ |
| `manifest` | Package identity, release version, SDK version, entrypoints, handlers, and metadata |
| `files` | Relative file paths mapped to source text |
| `dependencies` | Additional npm dependencies pinned to exact versions |
| `connections` | Named HTTP, Homarr integration, or service requirements; local bindings are separate |
| `options` | Controls, labels, defaults, and constraints for placement settings |
`manifest.entrypoints.tile` is required. `advanced`, `configuration`, and `server` are optional. Entrypoints must
refer to files in the package. A package with named server handlers needs a server entrypoint. The `manifest.id`
identifies the package across releases; `manifest.version` uses a complete semantic version such as `1.0.0`.
Homarr provides React, Mantine, and `@homarr/widget-sdk` as shared host modules. Referenced Tabler icons are bundled
from Homarr's installed version, which is recorded in the artifact lock. The reference packages show how to use the SDK for host dimensions, theme and locale, options, state, commands, data queries, and advanced
views. Put additional dependencies in the package's dependency map rather than copying Homarr's internal source tree.
Production images include the widget compiler's JavaScript, native esbuild executable, and bundled icon sources.
When customizing Homarr's standalone build, retain these runtime assets and scope tracing includes to their files;
whole-package recursive globs can fail on pnpm dependency directory symlinks.
Use `WidgetScope` to compose components with independent state and command IDs. Commands registered through
`useWidgetCommands` remain registered across unrelated host updates and are removed when their component unmounts.
`useWidgetServices().confirm(...)` resolves to `true` on confirmation and `false` on cancellation or dismissal,
including Escape, a backdrop click, or the close button.
## Convert an existing Custom JSX widget
Choose **Convert to a widget package** from a valid Custom JSX widget's list row or editor. Conversion uses its saved
definition and creates a separate disabled package. The original definition and its board placements remain in
place. Local connections and encrypted credentials are copied on the server, keeping them out of portable source.
The initial package retains a compatible JSX surface and options. Converted dynamic options remain available through
the authored configuration surface. Extend the package with TSX modules, CSS, or an advanced
view in the workspace. Review the generated files, preview, and explicitly activate the package before adding it
to a board. Conversion itself does not execute or replace the original widget. After activation, **Replace an
existing Custom JSX tile** lets you choose one original placement and explicitly replace it. Position, size, refresh
interval and configured values are retained; the original definition and other placements stay available. Use
**Add to board** when you want a separate tile instead.
## Assistant authoring
Choose **Ask Assistant** in the workspace to describe a widget or request changes. Shortcuts help improve the
current widget, add an advanced view, or fix current errors. This opens Homarr's existing Assistant; it uses the
visible unsaved draft, public SDK guidance, reference packages, and source validation diagnostics.
The Assistant reads source on demand. Local connection settings, bindings, credential fields, preview option
values, and runtime response data are excluded. Recognized credential literals are redacted from source context;
keep secrets in local connections. Files with redacted credentials must be edited directly before the Assistant can
replace them. Files omitted because a response reached its context budget must be read separately before proposing changes.
Individual files over 180,000 characters and manifests over 60,000 characters require direct editing.
Proposals display each changed file before and after in the Assistant. **Apply to draft** applies the complete
proposal as one Undo step. If the draft changes while a proposal is waiting, the Assistant must read it again and
propose against the new revision. Applying a proposal does not save, trust, preview, activate, or publish it.
Preview evidence identifies only the exact current candidate that compiled and received a preview session.
Compilation does not prove successful browser rendering or live actions. Source, option, and binding changes
invalidate that evidence; use the preview canvas to verify the final result before activation.
## Save, preview, and activate
Drag the divider between source and preview to resize the workspace. The divider also supports arrow keys,
Home/End, and double-click to reset. The preference is saved in your browser. On smaller screens, switch between
Code and Preview without unmounting the working preview.
The preview offers compact, wide, phone, and tablet viewport presets, independent width/height controls, and a
25–200% display scale. Scaling changes both the visual surface and the SDK's visible dimensions. Light and dark
preview modes stay local to the preview; they do not change your Homarr theme. These presentation controls do not
rebuild code, clear query data, or require another preview session.
The source editor understands the package's TypeScript and TSX files together. Press **Ctrl+Space** for typed
completions, hover a symbol for its type and documentation, or press **F12** to open its definition. Definitions
inside the installed SDK or its dependencies open as read-only excerpts. **F2** renames a symbol across package
files; the complete rename is one Undo operation. **Format** uses TypeScript formatting for TS/TSX files.
Semantic diagnostics appear in the editor and its expandable issue list. They use declarations generated from this
Homarr installation's actual SDK, React, Mantine, and Node dependencies. Include `.d.ts` files when another package
needs declarations that are not installed with Homarr. These editor diagnostics do not block saving a draft or
replace the preview compiler's runtime compatibility checks. Analysis runs in a local browser worker, without
executing your source or downloading code or types from a CDN.
For Homarr development, `pnpm dev` and the Next.js build regenerate the worker and installed declarations. After
editing SDK source while the dev server is already running, run `pnpm --filter @homarr/custom-widgets generate:editor`
and reopen the workspace. Generated assets are included in the standalone image's public directory.
1. **Save draft** persists the current source without building or executing it. Incomplete TSX and metadata JSON can
be saved for later repair. Saving a draft leaves the active dashboard release running.
2. Review the code and dependencies, acknowledge trust, and choose **Run preview**. The preview builds the current
editor contents and runs them in a temporary session. Select tile, advanced, or configuration view when provided.
**Preview options** controls the configuration used for this session.
3. Save your final changes, review the activation's placement count, then choose **Activate saved draft**. The server
validates and builds the saved source before switching the installation. Activation enables the installation.
4. Choose a board and configure the new placement under **Activation & boards → Add to board**.
Changing source, options, local preview bindings, or the live-action mode invalidates execution evidence for the previous candidate.
The last successful view remains visible with a stale label and paused SDK activity while you edit or fix a failed
build. Its session is released after a replacement loads successfully or the workspace closes. Re-run preview to
inspect the changed inputs. Pausing SDK activity does not sandbox arbitrary effects inside trusted code. Preview widget storage is temporary:
frontend storage hooks and server handlers share the same preview-session values, isolated from dashboard storage
and other preview sessions. Completing an action refreshes queries and managed storage in that preview.
SDK named actions are simulated by default. Enable **Allow live SDK actions for this preview session** and run
preview again to operate the real service through SDK actions. The session label shows its mode. Changing source,
bindings, or connection settings turns this option off. Direct behavior inside trusted code remains the owner's responsibility.
## Synthetic preview scenarios
Authors can include `previewScenarios` in package source to review success, loading and partial failures with
synthetic data. A scenario maps declared query handler names to JSON results or errors:
```json
{
"previewScenarios": {
"partialFailure": {
"label": "Storage unavailable",
"queries": {
"memory": { "data": { "usedPercent": 38 } },
"storage": {
"error": { "message": "Synthetic storage collector timeout", "code": "TIMEOUT" },
"delayMs": 700
}
}
}
}
}
```
Select a scenario when creating a preview. Its ID and the exact compiled source are stored in that preview session;
changing the scenario requires a new preview. Required local connections can remain unbound. Fixture queries return
the authored JSON without starting the package's server module or calling a configured service. A query without a
fixture fails explicitly; it never falls back to live data. Each handler receives the same fixture regardless of its
input. Declared input validation still applies.
SDK actions are simulated in fixture mode, and enabling live actions together with a scenario is rejected.
Subscriptions are unavailable in this bounded query-fixture mode. The SDK capability helper remains available so
action controls can display their simulated state. Production dashboard queries always execute the active package's
normal handlers; a preview scenario never changes an installation or its placements.
[Download the complete example](/custom-widgets/preview-scenarios.json) for two independent local metrics with ready,
delayed and partial-failure scenarios. It needs no API or local connection. Import the source, review trust, and
preview its named scenarios. Its ordinary handlers read local memory and filesystem metrics when used without a scenario.
Scenarios support up to 16 names, 64 query fixtures each, 2 MiB of total fixture JSON, and delays of up to 30 seconds.
Errors can use `BAD_REQUEST`, `NOT_FOUND`, `TIMEOUT` or `INTERNAL_SERVER_ERROR`; the latter is the default. Request
cancellation and discarding the session cancel pending fixture delays.
Fixtures are explicitly authored package source and are included in source exports, offline archives and Workshop
releases. Homarr does not capture live responses into scenarios. Use invented values and review fixture contents
before sharing. This is SDK simulation, not a security sandbox: trusted browser code can still make direct requests,
and compiling uncached dependencies can require registry access. Review source and acknowledge trust as usual.
## Local connections
The **Unified downloads** starter accepts a primary and optional second download integration. Each source has its
own queue, loading state, error and retry control, so a failed client leaves the other queue usable. Advanced view
adds filtering, sorting, per-client and per-item controls, and pause/resume for all or selected clients. Batch
results identify successful and failed clients individually. Per-item actions resolve the current item from the
selected client, and confirmed removal keeps downloaded files. The composed overview reuses the same modules.
Controls consult the current viewer's capabilities. Guests need an explicit grant for an exact input such as
`{"connection":"secondary","operation":"pause"}` on `control`; batch grants additionally list every target in
`connections`. No guest action is enabled merely by installing the starter.
Choose **Service** for MQTT, SQLite, SSH, local files or another protocol. Service connections require a
`serviceType` matching the package requirement, arbitrary nonsecret JSON settings, and optional encrypted
credentials. They do not require an HTTP URL. For example, declare
`{kind: "service", serviceType: "sqlite", label: "Database"}` in a package and bind a local connection with
settings such as `{"path":"/data/app.sqlite"}`. MQTT commonly uses `{"url":"mqtt://mosquitto:1883","topics":["sensors/#"]}`;
put its username and password in the encrypted credentials field. Leave that field blank to keep existing
credentials, or select **Replace saved credentials** to clear them explicitly.
Server handlers call `getWidgetConnection(context, {connection: "database", serviceType: "sqlite"})` from
`@homarr/widget-sdk/server` to obtain the local settings and secrets for a Node library. These credentials are
never returned by the browser connection API. Authors must keep this object server-side and return only the
data their widget needs. File paths resolve inside Homarr's container/process; mount the required files there
and give the Homarr process access. Use a remote runner when the adapter must execute on another machine.
Diagnostics report what they actually verify: SQLite/file connections check regular-file readability, and MQTT
connections check TCP reachability. Neither check claims database-query validity or MQTT authentication. Run
preview to exercise the real query or authenticated subscription. Other service types report configured settings
and require their adapter's preview for a protocol check. The **SQLite and local status** and **MQTT live topics**
starters include complete adapters; MQTT pins its reviewed `mqtt` dependency, while SQLite uses Node's built-in
module. Their package READMEs document connection settings, limits, cancellation and deployment details.
Declare named requirements in the package and bind them to reusable local connections in **Connections**. A
connection can point to an existing Homarr integration or an HTTP endpoint. HTTP setup supports a separate server
and browser URL, Basic authentication, bearer tokens, secret headers or query parameters, cookies, TLS verification, and a timeout.
Server requests originate from Homarr's server or container. Examples include `http://sonarr:8989`,
`http://192.168.1.20:8080`, and a Tailscale address. `127.0.0.1` addresses the network namespace running Homarr; it does
not address the dashboard viewer's browser or a different container. Enter full URLs including the protocol. For a bare address such as `sonarr:7573`, the connection form offers an
explicit **Use http://sonarr:7573** suggestion. Choosing it adds the protocol while preserving the supplied host,
port, and path; use HTTPS when required by the service.
**Diagnose** shows the reached stage, resolved addresses, HTTP status and timing, and top-level JSON field names
without response values. The primary result distinguishes name resolution, network, TLS, HTTP and authentication
failures; expand **Technical details** for the full diagnostic. **Save installation bindings** changes the defaults inherited by every placement.
Individual placements can override connections in their board configuration. **Edit connection** updates a reusable
connection for every widget that uses it. Empty credential fields retain stored credentials; changing authentication
requires entering the credentials for the new method.
For Basic authentication, you can update the username or password independently: leaving the other field blank
preserves its saved value. Updating a bearer token, cookie, username, or password also preserves a saved TLS private key.
Connection credentials are encrypted in Homarr's database. Connection forms and their credential fields are not
included in the package editor's Undo/Redo or browser recovery. Keep credentials out of source files: source files
are portable and can be exported or published.
## Recovery and operational rollback
Disabling an enabled guest action does not depend on the validity of its edited input JSON. You can revoke access
immediately from the action's Disable control while repairing those inputs.
Activation also coordinates with widget settings, board saves, additions, and board duplication. If a package
changes while one of these saves is waiting, Homarr asks you to reload before saving again so an older
configuration cannot overwrite its migration. Changing a placement's connection overrides invalidates guest
action approvals tied to the previous bindings.
**Undo/Redo** covers the whole source document: metadata, files, and installation name. History is bounded to 100
entries and 2 MB in the current editor session. **Reset to saved** restores the saved draft. Homarr keeps one browser
recovery draft per signed-in owner, up to 1 MB, and offers to restore it when opening the matching package.
Recognized credential literals are redacted from recovery source; use connection fields for secrets.
Package release history is separate from editor Undo/Redo. **Roll back previous activation** restores the previous
compiled release and its activation snapshot of local bindings, placement options, and widget data. You must
acknowledge discarding newer widget data. Calls already made to an external service cannot be reversed by rollback.
Your source draft remains available for further work.
**Disable installation** stops that installation across all placements. It is independent of saving a source draft.
## Import, export, fork, and update
**Import package** accepts source JSON or a `homarr-widget-archive-v3` archive. Archives contain source plus a compiled
artifact; compatible matching artifacts can be activated without rebuilding dependencies. Imports create disabled
drafts for review. **Export source draft** exports current editor contents, including incomplete work.
**Export active archive** exports the activated release and its compiled artifact. Local connection credentials and
board placements are not part of these exports.
**Stage archive update** replaces the installation's saved draft after explicit acknowledgement and keeps its active
release running. **Review saved draft changes** shows changed files before and after, dependency changes, connection
requirements, and configuration changes. **Fork as a new package** copies saved source to a new disabled installation
with a new package identity; it does not change the original installation's board placements.
## Portable widget collections
A `homarr-widget-collection-v1` archive groups several independent packages with named shared connection slots.
Import binds a slot once and fans it out to every member that needs it. All imported packages start as disabled
drafts; importing does not install dependencies or execute widget code. Each package keeps its own identity,
activation, updates, settings and dashboard placements.
The complete collection is validated before creating installations. Invalid member code checksums, mismatched
connection types or invalid portable option defaults reject the import with no new installations. Installation
records are committed together; immutable artifact cache entries from a database failure may remain until cleanup.
Export uses the selected installations' activated archives. Shared local bindings become named requirements, while
their connection IDs, URLs and credentials stay local. Export also excludes placement settings and widget storage.
Only explicit authored defaults belong in the portable blueprint. Workshop and fork attribution is retained, and
normal package updates retain the collection's membership and connection mapping. Review code literals before
sharing, since package source is exported verbatim.
From the installed package library, choose **Collections** to export selected active packages or resume an imported
collection. Import its JSON archive using **Import**. The setup page asks for shared connections once, lets you
choose widgets and their options, and activates the selected packages after you acknowledge trust. **Activate and
add missing widgets** places them on the selected board. Each member reports its own result, and retrying skips
placements already present on that board. You can stop after the current member finishes.
See the [collection CLI commands](../../advanced/command-line/index.mdx#share-several-widgets-as-a-collection) for
packing, validation and importing through an admin API key. Collections support up to 32 widgets and 128 MiB.
## Workshop lifecycle
In Workshop, select a release, inspect source files and dependencies, and optionally bind its named connections.
**Import for review** opens the package workspace with a disabled local installation. Preview and activate it after
reviewing trust, then add it to a board.
The **Packages** library shows each installation’s version, author, and **View on Workshop** link. Choose
**Check for updates**, then **Review update** to load a release into the editor. If your saved draft has local
changes, confirm its replacement first. The active release continues running until you activate the reviewed draft.
Use **Duplicate** or export local changes you want to keep before replacing them.
Choose **Publish to Workshop** from the package’s action menu or its editor. Packages and Custom JSX widgets use the
same publishing form: sign in, add a title, description, and optional screenshots, then publish. The signed-in Workshop
account receives attribution. Homarr updates your existing listing or creates an attributed copy of another author’s
package automatically. **Release details** contains the version and optional release notes; updates suggest the next
patch version. Review source, dependencies, and fixtures before publishing. Local bindings and credentials remain
on the Homarr installation.
The management sidebar can collapse to icons using its toggle. It collapses automatically in the package editor to
leave more room for code and preview; expand it whenever you need the full labels. On mobile, use the header menu.
## Reference packages with local services
**Sonarr operations** supports two native Sonarr connections, upcoming and missing episodes, queue progress, source
filtering, and confirmed episode-search actions. Compact view shows four rows; the advanced view shows all loaded
rows with text filtering. Each server contributes up to 100 missing or queued episodes. An unavailable second
server does not hide the primary server's results. Searching requires native integration interaction access and
submits a Sonarr command; a queued command does not prove an eligible release was found or downloaded.
**Filesystem backup monitor** reads backup metadata and an optional JSON status report mounted into Homarr. Its
README contains the success/failure/running report format, timestamps, duration, size and retained run history.
The optional **Run backup** action uses a fixed executable and argument array deliberately configured in
`command.ts`. It runs through Node `execFile` without a shell, requires full placement permission, and never accepts
command text from the browser. Preview simulates it. Mount the executable into Homarr, then review and activate its
configuration. Backup activity and status reports do not verify restore integrity.
**Media and camera wall** combines native media sessions with optional authenticated camera snapshots and an Immich
image gallery. Camera paths share a bound HTTP connection; its credentials stay on the server. Immich uses a secret
`x-api-key` header with `asset.read` and `asset.view`. The package fetches images server-side and returns bounded
image data to the widget. It supports up to eight camera snapshots and twelve Immich thumbnails. Clicking an image
opens the advanced view with shared selection. Camera snapshots poll; this reference does not stream RTSP or other
continuous video, and individual images must remain under 675 KiB.
## Optional history collection
A placement’s **History collection** shows its latest retained sample and time. Expand the sampled-point table for
recent values or **Technical details** for the stored record.
Expand a placement’s **History collection** to select a named query handler, input JSON, value path, unit, sampling
interval, retention period, and maximum sample count. Collection is disabled by default. Enabling it runs the query
on Homarr’s server even when the dashboard is closed. Pause it without deleting samples, or explicitly discard
the collection and its history. The collection panel shows recent samples and request errors; package code can
consume retained history through the widget SDK.
## Guest actions
A package can declare a named action as available for guest grants. Under a placement's **Guest actions**, the owner
enables that specific handler for an explicit JSON array of permitted inputs. Other inputs remain denied. Changing
server code, dependencies, or bound connection configuration invalidates the grant and requires owner renewal.
Board access and the package's declared permissions still govern normal authenticated usage.
## Repair a v2 widget
The existing restricted v2 workbench remains available from the installed widgets tab. Invalid v2 definitions expose
**Repair widget**, which shows validation issues and editable source without changing the widget's dashboard ID.
Save repaired source or export a repair draft. Credentials are retained only when the original source and
authentication binding remain unchanged; configure credentials again when those bindings change.
## Build cache maintenance
Administrators can call `customWidget.package.cleanupArtifacts` through the authenticated API. Start with
`{ "dryRun": true }` to inspect candidate artifact IDs and local directories, then call it with `dryRun: false` to
remove those that are still unused. Cleanup preserves active and previous releases, every valid saved source draft
(including disabled offline imports), and artifacts leased by recent imports, builds or previews. Unreferenced data
must be at least seven days old. Preview sessions themselves expire after one hour.
Each call removes at most 100 database artifacts and 20 local directories by default. Adjust `maximumArtifacts`
(up to 500) and `maximumDirectories` (up to 100), or repeat when the result reports `limited: true`. Directory cleanup
applies to the current Homarr replica's runtime and dependency cache. Other replicas can clean their own local cache
through the same procedure. Cleanup coordinates reference changes across replicas and never invokes package code.
This is explicit maintenance; no automatic build-cache cleanup job is enabled.
For an external editor workflow with normal files, local previews and immutable release publishing, see the
[widget CLI commands](../../advanced/command-line/index.mdx#build-and-share-custom-widget-packages).
Each server worker runs at most eight handlers concurrently and queues at most 64 more for up to 30 seconds.
Extra requests receive a capacity error; one failing source does not block successful results from other requests.
## Webhook lifecycle and advanced links
Each placement can issue a separate token for a named action with an input schema. Homarr displays the POST URL and
bearer token once. Tokens stay outside source drafts, recovery and exports. Code or local binding changes invalidate
existing tokens; create a new one for the updated placement. Explicitly revoked tokens remain revoked after rollback.
The webhook accepts JSON matching the action schema, up to 1 MiB, and runs with its owner's current authorization.
A board URL can link directly to an installed widget's advanced view using `#widget=<placementId>`. The viewer still
needs access to the board and widget. This opens the dashboard widget surface rather than a standalone app route.
-82
View File
@@ -1,82 +0,0 @@
---
title: Manage Homarr
description: Configure boards, content, access, automation, and server-wide behavior.
---
import {
IconApi,
IconApps,
IconCertificate,
IconChecklist,
IconComponents,
IconDatabaseExport,
IconLayoutDashboard,
IconLogs,
IconPhoto,
IconPlugConnected,
IconRobot,
IconSearch,
IconSettings,
IconTerminal2,
IconUsers,
} from "@tabler/icons-react";
## Everyday configuration
<Cards>
<Card icon={<IconLayoutDashboard />} title="Boards" href="/docs/management/boards">
Create, organize, share, and configure boards.
</Card>
<Card icon={<IconApps />} title="Apps" href="/docs/management/apps">
Add the services and links shown on boards.
</Card>
<Card icon={<IconPlugConnected />} title="Integrations" href="/docs/management/integrations">
Configure reusable service connections.
</Card>
<Card icon={<IconUsers />} title="Users and groups" href="/docs/management/users">
Control access and permissions.
</Card>
<Card icon={<IconSettings />} title="Settings" href="/docs/management/settings">
Change server and user preferences.
</Card>
</Cards>
## Content and extensions
<Cards>
<Card icon={<IconPhoto />} title="Media" href="/docs/management/media">
Manage uploaded assets.
</Card>
<Card icon={<IconSearch />} title="Search engines" href="/docs/management/search-engines">
Configure search shortcuts.
</Card>
<Card icon={<IconComponents />} title="Custom Widgets" href="/docs/management/custom-widgets">
Build Custom JSX widgets.
</Card>
<Card icon={<IconRobot />} title="Assistant" href="/docs/management/assistant">
Configure Homarr's assistant features.
</Card>
</Cards>
## Operations
<Cards>
<Card icon={<IconApi />} title="API" href="/docs/management/api">
Configure API keys and use the generated reference.
</Card>
<Card icon={<IconTerminal2 />} title="Model Context Protocol" href="/docs/management/mcp">
Connect external assistants to Homarr.
</Card>
<Card icon={<IconChecklist />} title="Tasks" href="/docs/management/tasks">
Inspect scheduled and background tasks.
</Card>
<Card icon={<IconLogs />} title="Logs" href="/docs/management/logs">
Inspect application logs.
</Card>
<Card icon={<IconCertificate />} title="Certificates" href="/docs/management/certificates">
Trust certificates used by connected services.
</Card>
<Card icon={<IconDatabaseExport />} title="Backups" href="/docs/management/backup">
Export and restore Homarr data.
</Card>
</Cards>
@@ -14,7 +14,7 @@ actions to widgets and can be linked to apps.
![The integration catalog](../img/integrations-catalog.png)
See the [integration catalog](/docs/integrations) for service-specific URLs, credentials, and supported
See the [integration catalog](/docs/category/integrations) for service-specific URLs, credentials, and supported
widgets.
## Browser and server routes
@@ -57,6 +57,6 @@ If a connection test fails:
1. Check the integration page for the required base URL and credentials.
2. Test name resolution and HTTP access from the Homarr container or pod, not only from the host or browser.
3. Check Homarr and upstream-service logs, then any reverse proxy, firewall, VLAN, VPN, or DNS between them.
4. For a self-signed certificate, add the expected certificate under [Certificates](/docs/management/certificates).
4. For a self-signed certificate, add the expected certificate under [Certificates](../certificates).
Do not disable upstream security controls as a general troubleshooting step.
+2 -2
View File
@@ -64,10 +64,10 @@ Inspect the **AI / MCP** tab or your client's tool list for available actions.
Custom Widget and Workshop authoring tools, prompts, and resources require administrator access.
For Custom Widgets, install the official skill and follow the preview-and-evidence workflow described in
[Connect an agent](/docs/management/custom-widgets/agent-authoring). Secret values are configured in Homarr and are never returned
[Connect an agent](./custom-widgets/agent-authoring). Secret values are configured in Homarr and are never returned
through MCP.
The built-in [Assistant](/docs/management/assistant) uses the same tool catalog with the current Homarr session and asks for approval
The built-in [Assistant](./assistant) uses the same tool catalog with the current Homarr session and asks for approval
before mutations by default.
## Verify the connection
-25
View File
@@ -1,25 +0,0 @@
{
"title": "Management",
"defaultOpen": false,
"pages": [
"index",
"---Everyday configuration---",
"boards",
"apps",
"integrations",
"users",
"settings",
"---Content and extensions---",
"search-engines",
"media",
"custom-widgets",
"assistant",
"---Operations---",
"api",
"mcp",
"tasks",
"logs",
"certificates",
"backup"
]
}
+12
View File
@@ -20,3 +20,15 @@ Each task exposes:
![The scheduled Tasks management page](../img/tasks.png)
Disabling a task stops scheduled runs but does not prevent a manual run.
## Widget history collectors
Trusted widget installations can opt into background sampling from their **Activation & boards** workspace tab.
Each collector names a declared query, input, optional response field, interval, and retention limit. Collection is
separate from viewer refresh; Redis admits one sampling run per interval across serving replicas. New collectors are
disabled until the owner enables them. The owner must retain administrator access for collection to continue.
The production application schedules enabled collectors while it is running, including when no dashboard is open.
Each series is bounded by its configured retention/sample count and a 1 MiB managed record limit. Pausing a collector
stops requests. Removing it explicitly removes its retained series. Application history APIs remain preferable when
available because Homarr cannot collect observations while it is offline.
+1 -1
View File
@@ -67,7 +67,7 @@ specific users or groups:
- Board access uses View, Modify, and Full levels.
- Integration access uses Use, Interact, and Full levels.
See [Boards](/docs/management/boards#access-control) and [Integrations](/docs/management/integrations#permissions).
See [Boards](../boards#access-control) and [Integrations](../integrations#permissions).
## Invitations
-3
View File
@@ -1,3 +0,0 @@
{
"pages": ["index", "getting-started", "management", "integrations", "widgets", "workshop", "advanced", "community"]
}
+11
View File
@@ -0,0 +1,11 @@
{
"label": "Widgets",
"position": 3,
"collapsed": true,
"link": {
"type": "generated-index",
"title": "Widgets",
"description": "Widgets display data or provide actions on a board. Choose a widget to see its configuration, supported integrations, and limitations.",
"image": "/img/pictures/widgets/widget-dark.jpg"
}
}
+2 -2
View File
@@ -9,8 +9,8 @@ import { WidgetInteractionGuide } from "@site/src/components/widgets/interaction
import { WidgetHeader } from "@site/src/components/widgets/header";
import { AddingWidget } from "@site/src/components/widgets/adding";
import { WidgetIntegrations } from "@site/src/components/widgets/integrations";
import Tabs from "@/components/mdx/legacy-tabs";
import { TabItem } from "@/components/mdx/legacy-tabs";
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import { firewallWidget } from ".";
import { opnsenseIntegration } from "../../integrations/opnsense";
Loaded 100 of 581 files, more files were not shown because too many files have changed in this diff. Show more