No description
  • TypeScript 94%
  • CSS 5.7%
  • Dockerfile 0.2%
  • HTML 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
WRPHayden b57d57d917
All checks were successful
CI / verify (push) Successful in 1m27s
CI / browser-e2e (push) Successful in 1m36s
CI / container-smoke (push) Successful in 1m55s
CI / docker-discovery-smoke (push) Successful in 39s
CI / Publish and scan image (push) Successful in 55s
build: use distroless runtime image
2026-09-02 22:42:02 +01:00
.forgejo/workflows ci: scan the built image platform 2026-09-02 00:07:53 +01:00
.github test: stabilize Linux Playwright CI 2026-09-01 22:04:14 +01:00
apps test: allow slower server tests in CI 2026-09-01 22:30:01 +01:00
docs/images Initial commit 2026-08-31 22:03:12 +01:00
e2e test: stabilize Linux Playwright CI 2026-09-01 22:04:14 +01:00
packages/contracts Initial commit 2026-08-31 22:03:12 +01:00
.dockerignore Initial commit 2026-08-31 22:03:12 +01:00
.editorconfig Initial commit 2026-08-31 22:03:12 +01:00
.env.example Initial commit 2026-08-31 22:03:12 +01:00
.gitignore Initial commit 2026-08-31 22:03:12 +01:00
biome.json Initial commit 2026-08-31 22:03:12 +01:00
CHANGELOG.md Initial commit 2026-08-31 22:03:12 +01:00
compose.yaml Initial commit 2026-08-31 22:03:12 +01:00
CONTRIBUTING.md Initial commit 2026-08-31 22:03:12 +01:00
Dockerfile build: use distroless runtime image 2026-09-02 22:42:02 +01:00
package.json Initial commit 2026-08-31 22:03:12 +01:00
playwright.config.ts Initial commit 2026-08-31 22:03:12 +01:00
pnpm-lock.yaml fix: update vulnerable fast-uri dependencies 2026-09-02 21:09:39 +01:00
pnpm-workspace.yaml Initial commit 2026-08-31 22:03:12 +01:00
README.md ci: publish and scan Harbor images 2026-09-01 23:34:43 +01:00
SECURITY.md Initial commit 2026-08-31 22:03:12 +01:00
tsconfig.base.json Initial commit 2026-08-31 22:03:12 +01:00

Lablist

Lablist is a self-hosted, living inventory and map of a homelab. It discovers local Docker workloads, Proxmox VE infrastructure, TrueNAS SCALE appliances, and Kubernetes clusters, then lets you add the context discovery cannot know: physical devices, external services, notes, URLs, and relationships.

Lablist infrastructure map

Project status

Lablist is pre-release software. The current version is 0.1.0 and its data model, deployment process, and user interface may change before a stable release.

A licence and public security contact have not yet been selected. Do not publish Lablist as a stable release until those decisions have been made. See CHANGELOG.md for the current release scope.

Contents

Capabilities

Discovery

  • Independent observation-only discovery from the local Docker Engine, multiple Proxmox VE clusters, TrueNAS SCALE appliances, and Kubernetes clusters
  • Docker host, Compose project, service, container, network, and volume inventory, including host operating system and hardware details
  • Proxmox cluster, node, QEMU guest, LXC guest, storage, bridge, and attachment inventory
  • TrueNAS appliance, network, pool, dataset, disk, share, service, VM, app, and app-container inventory
  • Kubernetes cluster, node, namespace, workload, Service, Ingress, and persistent-storage inventory
  • Stable Compose service identities across container recreation
  • Missing-resource tracking without destructive deletion

Inventory and mapping

  • Persistent topology with multiple editable canvases
  • Shared hardware inventory with identity, location, lifecycle status, interfaces, and custom specifications
  • Reusable resources and semantic relationships across canvases
  • Infrastructure zones, shapes, labels, grouping, and visual connectors
  • One-click infrastructure views arranged into Internet, edge, LAN, compute, and power tiers
  • Directional graph exploration, navigation history, explicit pinning, Markdown notes, and resource metadata

Administration and portability

  • One-time administrator setup and session authentication
  • Reviewed cross-platform identity matching instead of automatic merges
  • Exact Docker-to-TrueNAS NFS relationship inference from host and export-path evidence
  • JSON backup and fresh-instance restore
  • PNG canvas export
  • linux/amd64 and linux/arm64 container builds

Quick start

Requirements

  • A recent Docker Engine installation with the Docker Compose plugin
  • A Docker socket at /var/run/docker.sock for the included Compose deployment
  • OpenSSL to generate the credential-encryption key
  • A Linux or macOS shell for the commands below

The current Compose deployment builds Lablist from the checked-out source. Run these commands from the repository root.

First create a persistent local configuration file:

cp .env.example .env

Find the Docker socket group ID:

# Linux
stat -c '%g' /var/run/docker.sock

# macOS
stat -f '%g' /var/run/docker.sock

Generate a credential-encryption key:

openssl rand -base64 32

Put the resulting values in .env as DOCKER_GID and LABLIST_ENCRYPTION_KEY. Keep the encryption key stable and store a separate copy in your deployment secret manager; it is required to decrypt saved Proxmox and TrueNAS credentials.

Build and start Lablist:

docker compose up -d --build
docker compose logs lablist

Open http://localhost:8080, copy the one-time setup token from the logs, and create the administrator account. The password must contain at least 12 characters.

The token expires after 24 hours. Restart an unconfigured instance to issue a replacement:

docker compose restart lablist

Check that the service and database are ready with:

curl --fail http://localhost:8080/health/ready

The setup token is a secret. Do not share unredacted first-run logs.

How Lablist models a homelab

Lablist separates discovered facts from the map you maintain:

  1. Sources connect to Docker, Proxmox, TrueNAS, or Kubernetes.
  2. Observations record the allowlisted inventory reported by each source.
  3. Resources provide stable, canonical identities. Lablist proposes possible cross-source matches for review rather than merging them automatically.
  4. Canvases place reusable resources into editable views with relationships, notes, diagram elements, and visual connectors.

This separation allows discovery to refresh facts without overwriting manual context or deleting resources that temporarily disappear.

Docker volumes created with the local NFS driver are matched to TrueNAS NFS shares when both the NAS hostname or IP address and the normalized export path agree. Lablist then adds a read-only discovered uses_storage relationship from the Docker volume to the TrueNAS share. Names alone never create this relationship, and ambiguous endpoint matches are left unlinked.

Discovery sources

Each source is scanned independently. A failed or unavailable source leaves its previous successful inventory intact and does not block other sources.

Local Docker Engine

The Compose deployment mounts /var/run/docker.sock and adds the Lablist user to the socket's group. If discovery reports a permission error, confirm that DOCKER_GID in .env matches the current socket group, then recreate the container:

docker compose up -d --force-recreate

Lablist uses the Docker API connection to inventory the host as well as its workloads. It does not expose start, stop, restart, exec, deploy, or delete operations.

Proxmox VE

Add one source per Proxmox cluster. Lablist connects to one node's API endpoint and uses it to query the whole cluster. The chosen endpoint must remain reachable from the Lablist container on TCP port 8006; a stable internal DNS name is preferable to an address that may move between nodes.

Before adding the source, confirm that LABLIST_ENCRYPTION_KEY is set and stable. Lablist will not save a Proxmox token without it.

1. Create a least-privilege Proxmox identity

The recommended identity is a dedicated pve-realm user with no interactive password, plus a privilege-separated API token. Do not use a root@pam token or another administrator token.

In the Proxmox web interface:

  1. Open Datacenter > Permissions > Users and choose Add.
  2. Create a user such as lablist@pve. A password is not needed by Lablist; it authenticates only with the API token.
  3. Open Datacenter > Permissions, choose Add > User Permission, and grant lablist@pve the PVEAuditor role at path / with Propagate enabled.
  4. Open Datacenter > Permissions > API Tokens and choose Add.
  5. Select lablist@pve, use a token ID such as inventory, and keep Privilege Separation enabled.
  6. Copy the generated token secret immediately. Proxmox does not display it again.
  7. Return to Datacenter > Permissions, choose Add > API Token Permission, and grant lablist@pve!inventory the PVEAuditor role at path / with Propagate enabled.

With privilege separation enabled, the token's effective permissions are the intersection of its own ACLs and the backing user's ACLs. Both therefore need PVEAuditor at / for Lablist to inventory cluster status, nodes, guests, storage, and networking.

The equivalent commands, run as root on any cluster node, are:

pveum user add lablist@pve --comment "Lablist observation-only discovery"
pveum acl modify / -user lablist@pve -role PVEAuditor
pveum user token add lablist@pve inventory -privsep 1
pveum acl modify / -token 'lablist@pve!inventory' -role PVEAuditor

pveum user permissions lablist@pve
pveum user token permissions lablist@pve inventory

Save the secret printed by pveum user token add; it cannot be recovered later. See the Proxmox VE Administration Guide, particularly User Management and Limited API Token for Monitoring, for the upstream permission model.

2. Add the Proxmox source to Lablist

  1. Sign in to Lablist and open Sources in the header.
  2. Choose Add Proxmox.
  3. Complete the form:
    • Name: a descriptive cluster name, such as Home cluster.
    • Endpoint: the HTTPS origin of any reachable cluster node, normally https://pve1.example.net:8006. Do not append /api2/json.
    • API token ID: the complete identifier, for example lablist@pve!inventory.
    • API token secret: the generated secret only. Do not include PVEAPIToken=, the token ID, or an extra =.
    • TLS verification: choose one of the modes described below.
  4. Choose Test. A successful result reports the Proxmox VE version and confirms the endpoint, TLS choice, token syntax, and access to the version API.
  5. Choose Add source, then select Rescan on the saved source.
  6. Wait for the source to show online with a non-zero resource count. Check that the expected cluster, nodes, guests, storage, and bridges appear in the resource list.
  7. Review any Suggested identity matches before combining Proxmox resources with resources observed by Docker or another source.

The connection test is intentionally small; it does not prove that every inventory endpoint is readable. A successful full rescan is the final permission check. Proxmox discovery is polling-only and uses GET requests.

Proxmox-specific problems

  • HTTP 401 or 403: verify the full token ID, recopy or regenerate the secret, and confirm that both the user and privilege-separated token have PVEAuditor at / with propagation.
  • Test succeeds but the rescan fails: the token can read the version endpoint but lacks one or more cluster-wide audit permissions. Recheck both ACL entries and their path.
  • Redirect rejected: enter the final Proxmox HTTPS endpoint directly. Lablist does not follow redirects because they could move the authorization header to another origin.
  • One node works but another does not appear: the selected endpoint must be able to proxy API requests for every cluster node, and the token's ACL must propagate from /.

TrueNAS SCALE

Add one source per TrueNAS SCALE appliance. Lablist requires TrueNAS SCALE 25.10 or newer and the current JSON-RPC WebSocket API. The appliance must be reachable from the Lablist container over HTTPS; if a reverse proxy is in the path, it must support WebSocket upgrades.

Before adding the source, confirm that LABLIST_ENCRYPTION_KEY is set and stable. Lablist will not save a TrueNAS API key without it.

1. Create a read-only TrueNAS service account

In the TrueNAS web interface:

  1. Open Credentials > Users and choose Add.
  2. Create a dedicated local user such as lablist. Usernames are case-sensitive.
  3. Under access options, select TrueNAS Access, then choose Readonly Admin. This is the READONLY_ADMIN role used by the API.
  4. Do not grant SMB, WebShare, Shell, SSH, or sudo access unless the account separately requires it. Lablist needs none of them.
  5. Give the account a strong, unique password if TrueNAS requires one during creation. Lablist never asks for or stores this password.
  6. Keep the default non-interactive home-directory settings and save the user.

TrueNAS also supports assigning the built-in Read-Only Administrator privilege to the user's group. If your interface presents group privileges instead of a user-level Readonly Admin choice, assign that built-in privilege to a dedicated group and make lablist a member. Do not build a custom role unless you are prepared to maintain every read permission needed by the inventory queries.

See the official TrueNAS 25.10 user-management guide for the current account and privilege screens.

2. Create the TrueNAS API key

  1. In Credentials > Users, select the lablist user.
  2. In its Access panel, choose Add API Key or View API Keys. You can also open My API Keys from the top-right settings menu.
  3. Choose Add API Key, give it a descriptive name such as Lablist inventory, and associate it with the lablist user.
  4. Decide whether the key should expire. If it does, arrange rotation before that date; an expired key stops discovery.
  5. Choose Save, then copy the generated key immediately. TrueNAS displays the key value only once.
  6. Store a recovery copy in your secret manager. JSON backups intentionally exclude it.

API keys are password-equivalent and are not protected by the user's interactive 2FA requirement. Keep the account read-only, restrict network access to the API, and revoke the key if it is exposed. The official TrueNAS 25.10 API-key guide describes creation, expiration, reset, and revocation.

3. Add the TrueNAS source to Lablist

  1. Sign in to Lablist and open Sources in the header.
  2. Choose Add TrueNAS.
  3. Complete the form:
    • Name: a descriptive appliance name, such as Backup NAS.
    • Endpoint: the HTTPS origin only, for example https://truenas.example.net or https://truenas.example.net:8443. Do not append /api/current, another path, credentials, a query string, or a fragment.
    • Username: the exact case-sensitive username associated with the API key, for example lablist.
    • API key: the complete generated key.
    • TLS verification: choose one of the modes described below.
  4. Choose Test. A successful result reports the TrueNAS hostname and version and confirms WebSocket connectivity, TLS verification, API-key authentication, and access to system.info.
  5. Choose Add source, then select Rescan on the saved source.
  6. Wait for the source to show online with a non-zero resource count. Check the expected pools, datasets, disks, shares, services, VMs, and apps.
  7. Review any Suggested identity matches before combining TrueNAS resources with resources observed by Docker, Proxmox, or another source.

Lablist derives wss://<appliance>/api/current from the HTTPS origin, performs a complete scan, and closes the WebSocket afterward. It calls only system.info and an allowlist of *.query methods. HTTP and unencrypted WebSocket endpoints are rejected.

Disk-password, app-schema, app-config, and iSCSI authentication retrieval are disabled. Lablist does not retain VM display passwords, application configuration, environment values, share authentication material, or raw API responses.

TrueNAS-specific problems

  • Unsupported-version error: upgrade the appliance to TrueNAS SCALE 25.10 or newer. Lablist does not support TrueNAS CORE or the older REST API.
  • API-key authentication failed: check the case-sensitive username, confirm the key belongs to that user, and verify that it has not expired, been revoked, or been reset.
  • Test succeeds but the rescan fails: confirm that the API-key owner has the built-in Readonly Admin role. The test reads only system.info; the full scan calls the inventory query methods.
  • WebSocket connection fails through a proxy: connect directly to the appliance or configure the proxy to pass WebSocket upgrades without redirecting or rewriting /api/current.
  • A rotated key no longer works: edit the saved source and enter both the replacement username and replacement API key. Lablist requires credential names and secrets to be rotated together.

Kubernetes

Add one source per Kubernetes cluster. Lablist connects directly to the HTTPS API server and polls only stable core/v1, apps/v1, and networking.k8s.io/v1 collection endpoints. It inventories Nodes, Namespaces, Deployments, StatefulSets, DaemonSets, Services, Ingresses, PersistentVolumes, and PersistentVolumeClaims. Pods and ReplicaSets are read only to derive workload placement and routing relationships; they are not persisted as resources.

Before adding a source, confirm that LABLIST_ENCRYPTION_KEY is set and stable. Lablist encrypts the ServiceAccount token at rest and excludes it from responses and backups.

1. Create a least-privilege ServiceAccount

Apply the following manifest with an administrator context. It grants only collection-list access to the objects Lablist inventories and access to the /version probe endpoint. It grants no create, update, patch, delete, Secret, or ConfigMap permission.

apiVersion: v1
kind: Namespace
metadata:
  name: lablist-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: lablist
  namespace: lablist-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: lablist-inventory
rules:
  - nonResourceURLs: ["/version"]
    verbs: ["get"]
  - apiGroups: [""]
    resources:
      - namespaces
      - nodes
      - pods
      - services
      - persistentvolumes
      - persistentvolumeclaims
    verbs: ["list"]
  - apiGroups: ["apps"]
    resources:
      - deployments
      - statefulsets
      - daemonsets
      - replicasets
    verbs: ["list"]
  - apiGroups: ["networking.k8s.io"]
    resources: ["ingresses"]
    verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: lablist-inventory
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: lablist-inventory
subjects:
  - kind: ServiceAccount
    name: lablist
    namespace: lablist-system
---
apiVersion: v1
kind: Secret
metadata:
  name: lablist-token
  namespace: lablist-system
  annotations:
    kubernetes.io/service-account.name: lablist
type: kubernetes.io/service-account-token

Save it as lablist-kubernetes.yaml, then run:

kubectl apply -f lablist-kubernetes.yaml
kubectl -n lablist-system get secret lablist-token -o jsonpath='{.data.token}' | base64 --decode
kubectl -n lablist-system get secret lablist-token -o jsonpath='{.data.ca\.crt}' | base64 --decode > lablist-kubernetes-ca.crt
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'

The manually managed token is long-lived because Lablist must continue polling unattended. Protect it like a password, restrict API-server network access, and rotate it by replacing the Secret and then entering the replacement token in Lablist. Delete the Secret or ServiceAccount to revoke it.

2. Add the Kubernetes source to Lablist

  1. Sign in to Lablist and open Sources in the header.
  2. Choose Add Kubernetes.
  3. Enter a descriptive name and the API-server HTTPS origin, normally https://HOST:6443. Paths, embedded credentials, query strings, fragments, HTTP, and redirects are rejected.
  4. Paste the complete decoded ServiceAccount token.
  5. Select Custom CA certificate and paste lablist-kubernetes-ca.crt unless the API server uses a certificate already trusted by the Lablist container. Certificate fingerprint pinning is also supported.
  6. Review Excluded namespaces. New sources exclude kube-system, kube-public, and kube-node-lease; add distribution-specific system namespaces or remove entries you want inventoried.
  7. Choose Test, then Add source and Rescan. The test checks /version and Namespace-list permission; the complete rescan verifies every required RBAC rule.

Excluded namespace names are exact and case-sensitive. Cluster-scoped Nodes and PersistentVolumes remain visible. Lablist never requests Secrets or ConfigMaps and does not persist annotations, commands, arguments, environment values, secret references, raw Pod specifications, or CSI volume attributes.

Kubernetes-specific problems

  • HTTP 401: recopy the decoded token and confirm that the lablist-token Secret and lablist ServiceAccount still exist.
  • HTTP 403 or test/rescan permission failure: reapply the ClusterRole and ClusterRoleBinding and confirm the binding names the ServiceAccount in lablist-system.
  • TLS verification failure: paste the cluster CA from the token Secret, install the CA in the container trust store, or verify and pin the API server's leaf-certificate fingerprint.
  • Test succeeds but rescan fails: the test reads only /version and Namespaces; the full scan requires every collection in the documented ClusterRole.
  • Expected workloads are absent: remove their namespace from the exclusion list. Jobs, CronJobs, controllerless Pods, CRDs, and Gateway API objects are intentionally outside the current inventory scope.

TLS verification for credentialed sources

Choose the strictest mode that works with the certificate deployed on the source:

  • System trust store: use this for a publicly trusted certificate or a private CA already installed in the Lablist container. Normal chain, expiry, and hostname verification apply.
  • Custom CA certificate: paste the PEM-encoded root or issuing CA certificate, including the BEGIN CERTIFICATE and END CERTIFICATE lines. Normal hostname verification still applies. Prefer this mode for an internal CA whose root is not in the container trust store.
  • Pinned SHA-256 fingerprint: enter the exact colon-separated SHA-256 fingerprint of the leaf certificate, such as AA:BB:... with 32 byte pairs. Obtain and verify it through an authenticated administration session or another trusted channel. This mode trusts that exact certificate rather than its CA or hostname, so certificate renewal requires the pin to be updated.

You can inspect the certificate presented by an endpoint with OpenSSL:

openssl s_client -connect HOST:PORT -servername HOST </dev/null 2>/dev/null \
  | openssl x509 -noout -fingerprint -sha256

Do not trust this command's result by itself on an untrusted network; compare it with the fingerprint shown by the source or supplied by its administrator. If a previously working pin changes unexpectedly, investigate before accepting the new certificate.

Configuration and HTTPS

Docker Compose reads these values from .env:

Variable Default Purpose
DOCKER_GID 0 Supplemental group used to access the Docker socket. Set this to the socket's actual group ID.
LABLIST_PORT 8080 Host port mapped to the Lablist web server.
LABLIST_ENCRYPTION_KEY empty Base64-encoded 32-byte key used to encrypt credentialed discovery sources.
LABLIST_SECURE_COOKIES false Sends the session cookie only over HTTPS when enabled.
LABLIST_TRUST_PROXY false Trusts forwarded proxy information for request and origin handling.
LABLIST_LOG_LEVEL info Fastify log level, such as debug, info, warn, or error.

The encryption key is optional only while using local Docker discovery. Once a credentialed source is saved, losing or changing the key locks that source. It does not prevent Lablist or local Docker discovery from starting.

When a reverse proxy terminates HTTPS, set both of these values in .env:

LABLIST_SECURE_COOKIES=true
LABLIST_TRUST_PROXY=true

Configure the proxy to preserve the original host and send standard forwarded headers. Verify login through the public HTTPS origin before closing any direct administrative access. Enabling secure cookies while accessing Lablist over plain HTTP prevents the browser from sending the session cookie.

Backup and restore

Use Export JSON in the header to back up resources, hardware profiles, safe observations, sanitized source definitions, identity decisions, notes, relationships, canvases, positions, diagram elements, grouping, and visual connectors.

JSON backups never include:

  • Administrator accounts, passwords, or sessions
  • Proxmox token secrets, TrueNAS API keys, or Kubernetes ServiceAccount tokens
  • Unsafe or raw discovery responses

Restore is available only before first-run setup:

  1. Start Lablist with a fresh /data volume.
  2. Enter the new instance's setup token.
  3. Choose Restore JSON first on the setup screen.
  4. Create a new administrator account.
  5. Re-enter credentials for restored discovery sources and enable them.

Restored sources are disabled and contain no credentials. Legacy Docker resources remain unknown until discovery confirms them. Schema version 3 is current; version 1 and 2 backups remain accepted.

For complete disaster recovery, also back up the lablist-data Docker volume while the container is stopped. The volume contains the SQLite database, including authentication data and encrypted credentials. Protect it accordingly and retain the matching LABLIST_ENCRYPTION_KEY separately.

Updating Lablist

Before updating:

  1. Export a JSON backup from the UI.
  2. Stop Lablist and take a backup or snapshot of the lablist-data volume.
  3. Preserve the current .env, especially LABLIST_ENCRYPTION_KEY.

After obtaining the newer source, rebuild and recreate the service:

docker compose build --pull
docker compose up -d
docker compose logs lablist
curl --fail http://localhost:8080/health/ready

Database migrations run automatically at startup. For rollback, restore the pre-update data-volume snapshot as well as the older application version; a migrated database may not be compatible with an older build.

Publishing images from Forgejo Actions

The Forgejo Actions workflow can publish successful branch builds to a Harbor repository. Configure these values under the repository's Settings > Actions pages:

  • Variable HARBOR_IMAGE: the complete image repository without a scheme, tag, or digest, for example harbor.example.com/lablist/lablist
  • Secret HARBOR_USERNAME: preferably a Harbor project robot account with pull and push access
  • Secret HARBOR_PASSWORD: the corresponding robot-account secret

The publish job is skipped until HARBOR_IMAGE is configured. On a push to main or master, it waits for every verification job, pushes an immutable tag containing the commit SHA, and scans that pushed artifact with Trivy. Fixable high or critical vulnerabilities fail the job. The mutable latest tag is pushed only after the scan passes.

The Harbor endpoint must use a TLS certificate trusted by the runner's Docker-in-Docker daemon and the scanner container. Create the Harbor project before the first run.

Administrator recovery

Generate a one-time reset token and invalidate current sessions:

docker exec lablist node dist/cli.js reset-admin

The reset token is valid for 24 hours. There is not yet a recovery form in the web interface, so submit the token, a username, and a new password of at least 12 characters to the reset API:

curl --fail-with-body \
  --header 'Content-Type: application/json' \
  --data '{
    "token": "PASTE_RESET_TOKEN",
    "username": "admin",
    "password": "REPLACE_WITH_A_NEW_PASSWORD"
  }' \
  http://localhost:8080/api/v1/auth/reset

Avoid entering real credentials into a shared terminal or retained shell history. A successful reset signs in the requesting client and invalidates all earlier sessions.

Security model

Lablist extracts an allowlist of inventory fields and does not store environment-variable values, cloud-init secrets, guest commands, raw guest configuration, Kubernetes Secret or ConfigMap contents, secret contents, container commands, or arbitrary inspect payloads. Proxmox token secrets, TrueNAS API keys, and Kubernetes ServiceAccount tokens are encrypted with AES-256-GCM and are never returned by the API, published in events, or included in JSON backups.

However, Docker socket access is effectively host-administrator access. A read-only bind mount does not make Docker API operations read-only. Keep Lablist private, use HTTPS through a maintained reverse proxy when leaving the local machine, and read SECURITY.md before exposing it to a wider network.

Lablist intentionally provides no infrastructure control operations. Discovery adapters must remain observation-only.

Troubleshooting

Docker discovery reports a permission error

Compare the socket group ID with DOCKER_GID in .env, then run docker compose up -d --force-recreate. The supplemental group is assigned when the container is created, not while it is already running.

A Proxmox, TrueNAS, or Kubernetes source is locked

Restore the exact LABLIST_ENCRYPTION_KEY that was used when the credential was saved, or configure a valid deployment key and re-enter the source credentials. Restart Lablist after changing the key.

Port 8080 is already in use

Set another host port in .env, for example LABLIST_PORT=8181, then recreate the service and open that port instead.

The setup token expired

If the instance is still unconfigured, run docker compose restart lablist and inspect the new logs. Restarting an already configured instance does not issue a new setup token.

Health and logs

curl http://localhost:8080/health/live
curl http://localhost:8080/health/ready
docker compose ps
docker compose logs --tail=200 lablist

Redact setup tokens, hostnames, addresses, and other sensitive inventory before sharing logs.

Local development

Requirements: Node.js 24+, pnpm 11+, and optionally Docker for live local discovery and Docker integration tests.

pnpm install --frozen-lockfile
pnpm dev

The frontend runs on port 5173 and proxies API calls to the Fastify server on port 8080. SQLite migrations are applied automatically when the server starts. Run pnpm --filter @lablist/server db:generate only when intentionally creating a migration after a schema change.

Run linting, type checks, unit tests, and production builds with:

pnpm check

Browser tests and the production dependency audit are separate:

pnpm exec playwright install chromium
pnpm test:e2e
pnpm run audit

On Linux, Playwright may require pnpm exec playwright install --with-deps chromium with permission to install system packages.

Project structure

  • apps/server: Fastify API, SQLite persistence, authentication, discovery, and reconciliation
  • apps/web: React and React Flow interface
  • packages/contracts: shared Zod contracts and TypeScript types
  • e2e: Playwright browser tests and visual snapshots

See CONTRIBUTING.md before submitting changes. The project uses strict TypeScript, Biome, Vitest, Playwright, Drizzle migrations, and conventional pull requests.

Non-goals for the current release

Generic remote collectors, OIDC, multi-user roles, attachments, a full wiki, metrics, and infrastructure control operations are intentionally deferred.