selfhost.directory

The index of self-hostable projects — ranked, categorized and served with live updates.
Own your data and stop giving it to big tech.

tesserae logo

Self-host tesserae

v0.480.0

Composable dashboards for your e-ink wall panels

BetaOpen SourceAGPL-3.0
curl -fsSL https://raw.githubusercontent.com/dmellok/tesserae/main/install.sh | bash
Updated9 hours ago
LanguagePython
Setup difficultyModerate
Stars
973
Ports
8765 (Web UI + API), 1883 (Built-in MQTT broker (optional, enabled in Settings))
Docker
ghcr.io/dmellok/tesserae
tesserae screenshot 1tesserae screenshot 2tesserae screenshot 3tesserae screenshot 4tesserae screenshot 5

What is tesserae?

Should you self-host tesserae?

tesserae scores 51/100 on selfhost.directory (how scoring works) and ranks #14 of 44 in Dashboard. It has 973 GitHub stars.

It shipped 78 stable releases in the past year. The latest, v0.480.0, came out on 26 October 2026.

Setup is moderate: expect some configuration beyond a single command. An official Docker image is available. It is AGPL-3.0-licensed and written mostly in Python.

Its closest alternative on selfhost.directory is Homepage by gethomepage (84/100, 33 412 stars). It scores higher overall, so compare the two before you pick. See tesserae vs Homepage by gethomepage side by side.

Features

  • Backup and data export/import
  • Broad e-ink hardware support
  • Browser dashboard composer
  • Built-in MQTT Broker
  • Bundled widget gallery
  • Colour-palette dithering and calibration
  • Community widget catalog
  • Drop-a-folder plugin system
  • Home Assistant Integration
  • MCP API for AI agents
  • MQTT and REST frame delivery
  • Per-panel scheduling and rotation
  • Server-side headless rendering
  • Theme System
  • Webhook-triggered re-render

tesserae README

How to install tesserae

Install tesserae with Docker

Environment variables
TESSERAE_SECRET_KEY, TESSERAE_IN_DOCKER, TESSERAE_BIND_PORT, TESSERAE_HOST_IP
mkdir ~/tesserae && cd ~/tesserae
curl -fsSLO https://raw.githubusercontent.com/dmellok/tesserae/main/docker-compose.yml
docker compose up -d

Host networking by default (Linux); bridge variant for Docker Desktop. Image is ~970 MB to pull, ~2.5 GB on disk uncompressed.

How to configure tesserae

  • --devoffFlask dev server with auto-reload + debugger instead of waitress.

    Flask dev server with auto-reload + debugger instead of waitress.

  • --host0.0.0.0Bind address; set :: for IPv6 dual-stack where the OS supports it.

    Bind address; set :: for IPv6 dual-stack where the OS supports it.

  • --log-levelinfoRoot log level; wins over TESSERAE_LOG_LEVEL.

    Root log level; wins over TESSERAE_LOG_LEVEL.

    values: trace/debug/info/warning/error

  • --port8765Bind port for the web UI + API; an explicit flag beats TESSERAE_BIND_PORT.

    Bind port for the web UI + API; an explicit flag beats TESSERAE_BIND_PORT.

  • --reset-passwordClears the stored admin password and exits; next request goes to /setup.

    Clears the stored admin password and exits; next request goes to /setup.

  • TESSERAE_API_BASEhttps://api.tesserae.inkBase URL for online features (template marketplace, community catalog). Only useful for development or a self-hosted API.

    Base URL for online features (template marketplace, community catalog). Only useful for development or a self-hosted API.

  • TESSERAE_BIND_HOST0.0.0.0The address the server binds. Feeds the --host default (image 0.381.0+); an explicit --host flag wins. Set :: for IPv6. Also used internally so loopback renders target [::1] instead of 127.0.0.1 under an IPv6 bind.

    The address the server binds. Feeds the --host default (image 0.381.0+); an explicit --host flag wins. Set :: for IPv6. Also used internally so loopback renders target [::1] instead of 127.0.0.1 under an IPv6 bind.

  • TESSERAE_BIND_PORT8765The port the server actually listens on. Feeds the --port default (image 0.378.0+), so a compose environment: entry is enough to move the web port; an explicit --port flag wins if both are given. Also used internally so loopback renders target the real bind port behind a reverse proxy or Docker port map.

    The port the server actually listens on. Feeds the --port default (image 0.378.0+), so a compose environment: entry is enough to move the web port; an explicit --port flag wins if both are given. Also used internally so loopback renders target the real bind port behind a reverse proxy or Docker port map.

  • TESSERAE_CHROMIUM_PATHbundledPath to a Chromium executable for the renderer, when the Playwright-bundled one can't be used.

    Path to a Chromium executable for the renderer, when the Playwright-bundled one can't be used.

  • TESSERAE_DATA_ROOT<repo>/dataData directory: settings, pages, schedules, event log, render cache, backups. The Docker image keeps the default and expects a volume at /app/data.

    Data directory: settings, pages, schedules, event log, render cache, backups. The Docker image keeps the default and expects a volume at /app/data.

  • TESSERAE_EXPERIMENT_unsetForce one of the optional features in Settings → System → Features on (1/true) or off (0/false) at deployment level. Names: COMPOSER (canvas editor), MCP (agent API), TEMPLATES (template marketplace). All are on by default, so this is mostly for switching one off, e.g. TESSERAE_EXPERIMENT_MCP=0. Overrides and locks the Settings toggle.

    Force one of the optional features in Settings → System → Features on (1/true) or off (0/false) at deployment level. Names: COMPOSER (canvas editor), MCP (agent API), TEMPLATES (template marketplace). All are on by default, so this is mostly for switching one off, e.g. TESSERAE_EXPERIMENT_MCP=0. Overrides and locks the Settings toggle.

  • TESSERAE_FIRMWARE_APIhttps://api.tesserae.inkBase URL the firmware-update check queries. Development override.

    Base URL the firmware-update check queries. Development override.

  • TESSERAE_FORWARDED_HOPS1Trusted X-Forwarded-* proxy hops (Flask ProxyFix). Set 2 behind a double proxy, 0 to trust none.

    Trusted X-Forwarded-* proxy hops (Flask ProxyFix). Set 2 behind a double proxy, 0 to trust none.

  • TESSERAE_HA_INGRESS
  • TESSERAE_HOST_IPauto-detectedThe LAN IP baked into frame URLs and the broker URL shown to panels. Required under Docker bridge networking, where auto-detection finds the container's unreachable 172.x address. May be an IPv6 address (0.381.0+); URLs bracket it automatically.

    The LAN IP baked into frame URLs and the broker URL shown to panels. Required under Docker bridge networking, where auto-detection finds the container's unreachable 172.x address. May be an IPv6 address (0.381.0+); URLs bracket it automatically.

  • TESSERAE_HTTP_PORT8765The advertised port, what panels and generated URLs should use when it differs from the bind port (reverse proxy, ports: ["8766:8765"] remap). Only the fallback before the first request captures the real external port.

    The advertised port, what panels and generated URLs should use when it differs from the bind port (reverse proxy, ports: ["8766:8765"] remap). Only the fallback before the first request captures the real external port.

  • TESSERAE_IN_DOCKERunsetSet to 1 by the Docker image. Hides the in-app self-update card and shows a docker compose pull hint instead.

    Set to 1 by the Docker image. Hides the in-app self-update card and shows a docker compose pull hint instead.

  • TESSERAE_LOG_LEVELinfoRoot log level. --log-level wins; the HA App's own Log level option wins there.

    Root log level. --log-level wins; the HA App's own Log level option wins there.

  • TESSERAE_PARENT_PID
  • TESSERAE_SECRET_KEYderived64 hex chars (32 bytes) used to encrypt stored secrets (API keys, broker passwords) at rest. Unset, the key is derived from the persisted session secret. That survives restarts, but if the session secret is ever regenerated (a data folder restored without settings.json, a container recreated without its data volume) every stored secret reads back empty while the rest of the settings stay intact. P

    64 hex chars (32 bytes) used to encrypt stored secrets (API keys, broker passwords) at rest. Unset, the key is derived from the persisted session secret. That survives restarts, but if the session secret is ever regenerated (a data folder restored without settings.json, a container recreated without its data volume) every stored secret reads back empty while the rest of the settings stay intact. P

  • TESSERAE_THREADS24Waitress worker threads (minimum 4). Raise if many open editors + SSE streams starve renders.

    Waitress worker threads (minimum 4). Raise if many open editors + SSE streams starve renders.

  • TESSERAE_TRUSTED_NETWORKSunsetComma-separated CIDRs the auth gate treats as local on top of the fixed private ranges, e.g. 2001:db8:abcd::/48 for a LAN on an ISP-delegated IPv6 prefix. Clients in these networks fetch /renders/ without a session and, with the password disabled, reach the admin UI. Merged with the list under Settings → System → Authentication → Trusted networks.

    Comma-separated CIDRs the auth gate treats as local on top of the fixed private ranges, e.g. 2001:db8:abcd::/48 for a LAN on an ISP-delegated IPv6 prefix. Clients in these networks fetch /renders/ without a session and, with the password disabled, reach the admin UI. Merged with the list under Settings → System → Authentication → Trusted networks.

tesserae releases & version history

More in Dashboard

Rate this project

Click to rate — no account needed.

0 comments

Posting as guest
Loading comments…