- HTML 63.8%
- Go 34%
- JavaScript 2%
- Dockerfile 0.1%
| .forgejo/workflows | ||
| cmd/server | ||
| docs | ||
| frontend | ||
| internal | ||
| scripts | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| Makefile | ||
| README.en.md | ||
| README.md | ||
signagetools
Self-hosted digital signage — complete, with no paywall. One server (Go + PostgreSQL), one player, one browser UI. Everything included: video walls, reports, multi-user, offline players, campaigns — MIT-licensed, nothing is locked behind a "Pro" tier.
The admin UI is fully bilingual (German/English, auto-detected from the browser language, switchable under Administration). Die deutsche Fassung dieses READMEs ist README.md.
Features
- Layout editor in the browser — free-form zones, images/videos/playlists, plus widgets: clock, weather & air quality, calendar (iCal), RSS/Mastodon, tables/data feeds (CSV/JSON), KPI/progress, countdown, ticker, HLS live streams, web pages and more. Portrait and landscape up to 4K.
- Draft & publish — saving creates a draft, players only show the published state; version history with rollback.
- The shortest path to a screen: media → layout → save → "Play now on …" (one device or all) — no schedule required.
- Scheduling — priorities, scopes (global → location → group → device), time windows across midnight, holiday/exception dates, nth weekday, maintenance windows (black/pause), week/month preview through the real resolver, plain-language conflict warnings. Campaigns bundle multiple rules and switch them on/off together.
- Device fleet — pairing by code, locations & groups, live preview (screenshots), pause/blackout/mute per device, remote reload and container update, fleet diagnostics (version, uptime, memory).
- Video wall & time sync — multiple players as one surface with bezel compensation; shared server time base, clock offset visible in ms, resync at the push of a button.
- Instant messages — reachable from anywhere in the UI, any target, urgency levels, templates and auto-expiry.
- Media management — nested folders, multi-select (move/replace/delete), validity periods per asset, usage tracking ("used in N layouts").
- Reports — proof of play (what ran when and where), CSV export.
- Offline notifications — webhook and/or e-mail when a device stays offline too long, with escalation stages and a "back online" notice; status & test send under Operations → Diagnostics.
- Multi-user — roles (admin/editor/viewer), audit log, full backup & restore.
- Bilingual — German/English, automatic, switchable.
- Built-in first steps — demo content in one click, a web player to try things right in the browser.
| Design | Schedule |
|---|---|
![]() |
![]() |
| Layout gallery | Operations |
|---|---|
![]() |
![]() |
Quick start (Docker Compose)
git clone https://forgejo.thiel.tools/thiel/signagetools.git
cd signagetools
ADMIN_PASSWORD=change-me docker compose up -d --build
Then open http://<server>:8080. The bundled
docker-compose.yml starts PostgreSQL and the server;
media and database live in volumes. Instead of building locally you can use
the published image (forgejo.thiel.tools/thiel/signagetools:latest).
First steps in the UI:
- Design → "✨ Create demo content" — three ready-made layouts to explore.
- Operations → Devices → "↗ Open web player in this browser" — a test screen with zero installation; match the pairing code and approve it.
- In the editor "⬆ Publish" → "Play now on …" — done.
Real screens (Raspberry Pi, mini PC, Docker, tablets) are driven by the signagetools-player — from the zero-install web player to an offline-resilient kiosk appliance.
Configuration (environment variables)
| Variable | Meaning | Default |
|---|---|---|
PORT |
HTTP port | 8080 |
DATABASE_URL |
PostgreSQL connection | postgres://signage:signage@localhost:5432/signage |
MEDIA_DIR |
media storage path | ./data/media |
ADMIN_PASSWORD |
emergency admin password; empty = open mode (development only) | – |
REQUIRE_LOGIN |
1 = always enforce login |
– |
CORS_ORIGIN |
only needed when the builder is hosted separately | * |
ALERT_WEBHOOK_URL |
webhook for offline/back-online reports | – |
ALERT_EMAIL |
e-mail recipients (comma-separated) | – |
ALERT_OFFLINE_AFTER |
seconds until the first report | 300 |
ALERT_ESCALATION |
escalation stages in minutes, e.g. 5,30,120 |
– |
ALERT_ESCALATION_EMAILS |
extra recipients per stage (; separates stages) |
– |
SMTP_HOST SMTP_PORT SMTP_USER SMTP_PASS SMTP_FROM SMTP_TLS |
mail delivery for alerts | port 587, starttls |
For TLS put a reverse proxy in front (Caddy/Traefik/nginx).
Details: docs/DEPLOYMENT.md; offline alerts:
docs/monitoring.md. (The design docs are in German.)
Architecture
- One deployable: a Go server embedding the admin UI (
/) and the web player (/play) — same origin, no CORS. PostgreSQL for data, media on the file system, optional ffmpeg transcoding. - Pull model: players fetch a time-resolved manifest plus hash-checked media and keep running offline.
- Frontend: a single HTML file with React
(
frontend/builder.html). The repo keeps it as JSX (dev mode: the browser compiles it); the image build precompiles it and embeds React — fast startup, no internet required. - Design documents live in
docs/(architecture, scheduling rules, data model, deployment, monitoring).
Development
docker compose up -d db # PostgreSQL only
go run ./cmd/server # server on :8080, frontend in dev mode
go test ./...
Edit frontend/builder.html directly — reloading the page is enough.
License
MIT — see LICENSE. All features, all players, no restrictions.




