Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "0.0.1",
"configurations": [
{
"name": "web",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["dev"],
"port": 3001
}
]
}
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

## Project Summary
- SvelteKit app using Svelte 5 (runes syntax) with Tailwind CSS 4.
- Docs content is Markdown via MDSX and organized/validated by Velite.
- Docs content is Markdown via mdsvex and organized/validated by Velite.
- Static site build (adapter-static) with Cloudflare Workers previews/deployments.

## Key Paths
- Content source: `content/` (Markdown; MDSX renders via blueprint).
- Content source: `content/` (Markdown; mdsvex renders via layout).
- Velite config: `velite.config.js` (collections + schema).
- MDSX config: `mdsx.config.js` and `src/lib/components/mdsx/blueprint.svelte`.
- mdsvex config: `mdsvex.config.js` and `src/lib/components/markdown/layout.svelte`.
- Docs data/helpers: `src/lib/docs.ts`.
- Sidebar/nav config: `src/lib/config/docs.ts`.
- UI primitives: `src/lib/components/ui/` (shadcn-svelte style index exports).
Expand Down
16 changes: 16 additions & 0 deletions content/configuration/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ Replace each placeholder with the real value from your database.
- `<postgres_port>`: the port Postgres uses
- `<postgres_db_name>`: the database name to connect to

## Container runtime user

Official Arcane images set `ARCANE_DEFAULT_NONROOT=true`, so the process drops to the built-in non-root user (`65532:65532`) when `PUID` and `PGID` are not set.

Use `PUID` and `PGID` if mounted files should be owned by a specific host user and group. If you use a custom Unix Docker socket with `DOCKER_HOST`, Arcane uses that socket path when adding the runtime user to the socket group.

## Timezone and scheduled jobs

Arcane runs recurring background jobs — image update polling, auto-updates, vulnerability scans, scheduled pruning, GitOps sync, and environment health checks. Their cron-style schedules are evaluated in the timezone set by `TZ`.

Set `TZ` to an [IANA timezone name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) so schedules run at the local times you expect:

<Snippet text="TZ=America/New_York" class="mt-2 mb-2 w-full" />

If `TZ` is unset, Arcane uses the container's local time (`Local`), which is UTC on the official images. Individual job intervals and cron expressions are configured in the Settings UI, or via the environment when `UI_CONFIGURATION_DISABLED=true` or `AGENT_MODE=true` (see [Settings Overrides via Environment](#settings-overrides-via-environment)).

## Environment Variables

<EnvTable />
Expand Down
34 changes: 24 additions & 10 deletions content/configuration/sso.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as Code from '$lib/components/ui/code/index.js';
import OidcTable from '$lib/components/oidc-table.svelte';
import * as Alert from '$lib/components/ui/alert/index.js';
import InfoIcon from 'virtual:icons/lucide/info';
import { Link } from '$lib/components/ui/link/index.js';
</script>

## Configure OIDC in the UI
Expand All @@ -30,17 +31,32 @@ You can also configure OIDC using environment variables:

<OidcTable />

## Admin Role Assignment
## Mapping OIDC Groups to Roles

The `OIDC_ADMIN_CLAIM` and `OIDC_ADMIN_VALUE` settings let Arcane make certain users admins based on information in their login token.
Role assignment is driven from your IdP. Arcane reads the user's group claim on every login and grants role assignments based on the mappings you configure under **Settings → OIDC Mappings**.

- **OIDC_ADMIN_CLAIM**: the part of the login token to check, such as `groups` or `roles`
- **OIDC_ADMIN_VALUE**: the value or values that should grant admin access. Use commas for more than one value, such as `arcane-admins,super-users`
1. Make sure the group claim is included in `OIDC_SCOPES` — for group membership, add `groups`: `openid email profile groups`.
2. Set the **OIDC Groups Claim** under **Settings → Settings** if your IdP uses something other than `groups` (e.g. `realm_access.roles` for Keycloak, `memberOf` for Azure AD).
3. Add mappings under **Settings → OIDC Mappings**, each binding a claim value to a role and an environment scope (Global or a specific environment).

When someone signs in, Arcane checks whether their token contains the matching value. If it does, they become an admin.
See <Link href="/docs/security/rbac">Role-Based Access Control</Link> for the full role catalog and mapping details.

> [!IMPORTANT]
> The claim you want to use, such as `groups`, must be included in `OIDC_SCOPES`. For example, if you want group membership to control admin access, make sure your scopes include `groups`: `openid email profile groups`
## Declarative role mappings (IaC)

Instead of the UI, you can declare OIDC group → role mappings with the `OIDC_ROLE_MAPPINGS` environment variable. It takes a JSON array, where each entry binds a claim value to a role and (optionally) an environment:

```json
[
{ "claimValue": "arcane-admins", "roleId": "role_admin" },
{ "claimValue": "arcane-devops", "roleId": "role_editor", "environmentId": "env-prod" }
]
```

- `claimValue` — the value to match in the user's groups claim.
- `roleId` — the role to grant (see <Link href="/docs/security/rbac">Role-Based Access Control</Link> for the role catalog).
- `environmentId` — optional; scope the assignment to one environment. Omit for a global assignment.

Arcane reconciles these mappings on every startup, so they are read-only in the UI (shown as environment-managed); update them by changing `OIDC_ROLE_MAPPINGS`. The variable also supports the `_FILE` suffix for Docker secrets.

## Example Compose Configuration

Expand All @@ -55,7 +71,5 @@ services:
- OIDC_CLIENT_SECRET="your_super_secret_client_secret_from_provider"
- OIDC_ISSUER_URL="https://auth.example.com"
- OIDC_SCOPES=openid email profile groups
- OIDC_ADMIN_CLAIM=groups
- OIDC_ADMIN_VALUE=_arcane_admins
- OIDC_MERGE_ACCOUNTS=true
- OIDC_GROUPS_CLAIM=groups
```
5 changes: 4 additions & 1 deletion content/configuration/websockets-reverse-proxies.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Traefik proxies WebSocket connections automatically, so no extra middleware is n
```yaml
services:
arcane:
image: ghcr.io/getarcaneapp/arcane:latest
image: ghcr.io/getarcaneapp/manager:latest
container_name: arcane
environment:
- APP_URL=https://arcane.example.com
Expand Down Expand Up @@ -134,6 +134,9 @@ docker network inspect <network> --format '{{range .IPAM.Config}}{{.Subnet}}{{en

`TRUSTED_PROXIES` accepts a comma-separated list of IPs or CIDR ranges. Only requests whose direct peer is in this list have their forwarded headers trusted, so an untrusted client cannot spoof its IP via `X-Forwarded-For`. See the <Link href="/docs/configuration/environment">Environment Variables</Link> reference for all configuration options.

> [!NOTE]
> When you bind Arcane to a loopback address with `LISTEN` (for example `LISTEN=127.0.0.1`, the usual same-host proxy setup), Arcane automatically trusts loopback proxies (`127.0.0.0/8`, `::1/128`), so you do not need to set `TRUSTED_PROXIES`. Auto-trust applies only to literal loopback IPs, not hostnames such as `localhost`.

## Additional Resources

Full documentation for common reverse proxies is available from [websocket.org](https://websocket.org/):
Expand Down
4 changes: 2 additions & 2 deletions content/features/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Example Compose:
```yaml
services:
arcane-agent:
image: ghcr.io/getarcaneapp/arcane-headless:latest
image: ghcr.io/getarcaneapp/agent:latest
container_name: arcane-agent
ports:
- '3553:3553'
Expand Down Expand Up @@ -101,7 +101,7 @@ Example Compose:
```yaml
services:
arcane-edge-agent:
image: ghcr.io/getarcaneapp/arcane-headless:latest
image: ghcr.io/getarcaneapp/agent:latest
container_name: arcane-edge-agent
environment:
- EDGE_AGENT=true
Expand Down
4 changes: 2 additions & 2 deletions content/guides/buildables.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
-o /out/arcane \
./cmd/main.go

FROM ghcr.io/getarcaneapp/arcane:latest
# For headless builds, use: ghcr.io/getarcaneapp/arcane-headless:latest
FROM ghcr.io/getarcaneapp/manager:latest
# For headless builds, use: ghcr.io/getarcaneapp/agent:latest
COPY --from=builder /out/arcane /app/arcane
```

Expand Down
53 changes: 45 additions & 8 deletions content/guides/custom-metadata.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
---
title: 'Custom Metadata'
description: 'Add icons and external links to projects and services.'
description: 'Add theme-aware icons and external links to projects and services.'
---

You can give projects and services a custom icon and a list of external links — for example a docs URL, a homepage, or a repo. Project-level metadata goes in the compose file's `x-arcane` block; service-level icons go on the service via a label.
You can give projects and services theme-aware icons and a list of external links — for example a docs URL, a homepage, or a repo. Project-level metadata goes in the compose file's `x-arcane` block; service-level icons go on the service via labels.

Icon values can be either absolute `http://` or `https://` URLs, or catalog slugs from the selected icon catalog. Data URIs and embedded base64 icons are not supported.

## Project-level metadata

Add an `x-arcane` block at the top level of your `compose.yaml`:

```yaml
x-arcane:
icon: https://example.com/project-icon.png
icon-light: nginx
icon-dark: nginx
urls:
- https://docs.example.com
- https://github.com/example/repo
Expand All @@ -20,16 +23,19 @@ services:
# ...
```

- `icon` (or `icons`) — image URL for the project.
- `icon-light` — light icon used in dark theme.
- `icon-dark` — dark icon used in light theme.
- `icon` — fallback icon used only when neither `icon-light` nor `icon-dark` is provided.
- `urls` — extra links shown next to the project (docs, homepage, etc.).

## Service-level icons

Set an icon for an individual service via a label:
Set icons for an individual service via labels:

```yaml
x-arcane:
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/nginx.png
icon-light: nginx
icon-dark: nginx
urls:
- https://google.com

Expand All @@ -39,7 +45,38 @@ services:
container_name: nginx_service
# ...
labels:
- com.getarcaneapp.arcane.icon=https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/nginx.png
- com.getarcaneapp.arcane.icon-light=nginx
- com.getarcaneapp.arcane.icon-dark=nginx
```

The labels only change the container's icons. The top-level `x-arcane` block only changes the project's icons. They're independent.

If a service only needs one icon for both themes, use `com.getarcaneapp.arcane.icon`. Arcane uses this fallback only when neither `com.getarcaneapp.arcane.icon-light` nor `com.getarcaneapp.arcane.icon-dark` is set for the service.

Short label aliases are also supported:

```yaml
labels:
- arcane.icon=nginx
- arcane.icon-light=nginx
- arcane.icon-dark=nginx
```

The label only changes the container's icon. The top-level `x-arcane` block only changes the project's icon. They're independent.
## Icon catalogs

The icon catalog setting controls how slugs are resolved:

- `selfhst` resolves `nginx` to `https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/nginx.svg`.
- `dashboard-icons` resolves `nginx` to `https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/nginx.svg`.

Theme variants append `-light` or `-dark` before `.svg`. For example, `icon-light: nginx` resolves to `nginx-light.svg`.

Fallback `icon` slugs use the base catalog file without a theme suffix.

Absolute URLs pass through unchanged:

```yaml
x-arcane:
icon-light: https://example.com/nginx-light.svg
icon-dark: https://example.com/nginx-dark.svg
```
8 changes: 5 additions & 3 deletions content/guides/gpu-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ order: 3
---

> [!IMPORTANT]
> This guide assumes GPU drivers are already installed and configured on your host system. Refer to the respective vendor documentation for driver installation.
> This guide assumes GPU drivers are already installed and configured on your host system. Refer to the respective vendor documentation for driver installation.
>
> Official Arcane images use a minimal hardened runtime base and do not bundle vendor GPU utilities. NVIDIA monitoring relies on `nvidia-smi` being injected by the NVIDIA container runtime. AMD monitoring reads `/sys/class/drm` directly. Intel monitoring requires an image/runtime that provides `intel_gpu_top`.

## NVIDIA GPU Setup

Expand All @@ -14,7 +16,7 @@ Configure Arcane with NVIDIA GPU support in your `compose.yaml`:
```yaml
services:
arcane:
image: ghcr.io/getarcaneapp/arcane:latest
image: ghcr.io/getarcaneapp/manager:latest
container_name: arcane
ports:
- '3552:3552'
Expand Down Expand Up @@ -50,7 +52,7 @@ Configure Arcane with AMD GPU support in your `compose.yaml`:
```yaml
services:
arcane:
image: ghcr.io/getarcaneapp/arcane:latest
image: ghcr.io/getarcaneapp/manager:latest
container_name: arcane
ports:
- '3552:3552'
Expand Down
4 changes: 2 additions & 2 deletions content/guides/lxc-container.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Configure your `compose.yaml` with the required volume mounts:
```yaml
services:
arcane:
image: ghcr.io/getarcaneapp/arcane:latest
image: ghcr.io/getarcaneapp/manager:latest
container_name: arcane
ports:
- '3552:3552'
Expand Down Expand Up @@ -67,7 +67,7 @@ Configure your agent's `compose.yaml` with host PID namespace and proc mount:
```yaml
services:
arcane-agent:
image: ghcr.io/getarcaneapp/arcane-agent:latest
image: ghcr.io/getarcaneapp/agent:latest
container_name: arcane-agent
# Use host PID namespace for process visibility
pid: host
Expand Down
Loading