Selbst bauen · Schritt 5
Server installieren
Voraussetzung ist Docker mit Compose. Zum Ausprobieren reicht ein Rechner, für den Betrieb ein kleiner Server im Heimnetz.
Auf dieser Seite
Zum Ausprobieren
Die Entwicklungsumgebung bringt den Simulator und einen Mail-Fänger mit. Nichts verlässt den Rechner.
-
Unter Windows
dev.batdoppelklicken und „1 Starten“ wählen. Sonst:pnpm install pnpm dev:up -
Warten. Der erste Start dauert, weil beim Bauen die Firmware für Hub und Module mitgebaut wird. Spätere Builds nutzen den Zwischenspeicher.
-
Die Oberfläche öffnen:
http://localhost:8080, von einem anderen Gerät im Netzhttps://<rechner>:8443.
Auch in der Entwicklung geht nichts im Klartext über ein Netz. Ohne TLS gibt es nur Ports auf
127.0.0.1. Was vom Handy oder einem zweiten Rechner aus erreichbar ist, spricht HTTPS mit dem
Zertifikat der eigenen CA. Damit der Browser nicht warnt, das CA-Zertifikat einmal importieren
(System → Status → „CA-Zertifikat herunterladen“).
dev.bat hat ein Menü: starten, stoppen, neu starten, aktualisieren, Status, Protokoll,
Sicherung anlegen und zurückspielen, alles zurücksetzen, Prüfungen. Jeder Punkt geht auch
direkt, zum Beispiel dev.bat logs.
Im Homelab
Zwei Wege führen zum laufenden Server. Option A ist die einfache Installation auf einem
Rechner, auf dem Docker schon läuft. Option B ist die vollständige Anleitung für einen eigenen
Server, etwa einen LXC-Container unter Debian 13: SmartBeet läuft unter einem eigenen Benutzer
deploy ohne root-Rechte, und auf Wunsch spielt ein GitHub-Runner jeden Push auf main von
selbst ein.
Option A: einfache Installation
-
Repository auf den Server kopieren.
-
.env.examplenach.envkopieren und anpassen. -
Starten, ohne die Ergänzung für die Entwicklung:
docker compose up --build -d -
Die Oberfläche öffnen. Der Einrichtungsassistent erscheint von selbst.
Fehlt Docker, steht die Installation unter Option B im ersten Schritt.
Option B: Debian 13 mit Benutzer deploy
Das System richtest du als root ein (Pakete, Docker). Alles, was SmartBeet selbst betrifft
(klonen, einstellen, bauen, starten), läuft unter dem Benutzer deploy, der später auch das
automatische Aktualisieren ausführt. Die Schritte sind mit [root] und [deploy]
markiert. Wechsel mit su - deploy, zurück mit exit. deploy hat kein Passwort, keinen
SSH-Zugang und ruft nie sudo auf.
In einem LXC-Container (etwa unter Proxmox) braucht Docker die Optionen nesting=1 und
keyctl=1. Richtwert für die Größe: 2 Kerne, 4 GB RAM (oder 2 GB mit Swap), 40 GB Platte.
Das erste Bauen ist der anspruchsvollste Teil.
-
Voraussetzungen — [root]. System aktualisieren und Docker aus dem offiziellen Repository installieren:
apt update && apt upgrade -y apt install -y git curl ca-certificates gnupg curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null apt update apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin -
Benutzer deploy anlegen — [root]. Mit Docker-Rechten und dem Verzeichnis unter
/opt:useradd -m -s /bin/bash deploy usermod -aG docker deploy mkdir -p /opt/smartbeet chown deploy:deploy /opt/smartbeetWer in der Gruppe
dockerist, kann den Docker-Dienst steuern und damit faktisch alles auf dem Server. Deshalb hatdeploykein Passwort und keinen SSH-Zugang. -
Repository klonen — [deploy]. Solange das Repository privat ist, fragt
git clonenach dem GitHub-Benutzernamen und einem Personal Access Token als Passwort (fine-grained mit „Contents: Read“).su - deploy git clone https://github.com/smartbeet/smartbeet.git /opt/smartbeet cd /opt/smartbeetDer Server braucht nur Docker, kein Node und kein pnpm: Jedes Image baut seine Abhängigkeiten selbst, auch die Firmware.
-
Einstellungen — [deploy].
cp .env.example .env nano .env chmod 600 .envMindestens
APP_URLundNTFY_PUBLIC_URLanpassen,SERVER_HOSTnur bei Hubs an einem anderen Ort, siehe „Die drei Adressen“ unten. Passwörter, Schlüssel, die eigene CA und das Serverzertifikat stehen nicht in der.env, sie entstehen beim ersten Start von selbst. -
Erster Start — [deploy]. Der erste Lauf dauert, weil die Firmware mitgebaut wird.
docker compose up -d --build docker compose ps docker compose logs -f backendDanach die Oberfläche unter
APP_URLöffnen. Der Einrichtungsassistent legt Admin-Konto, Standort und Mailserver an.
HTTPS und Reverse-Proxy
SmartBeet ist immer verschlüsselt erreichbar, auch ohne eigenen Proxy. Der Container frontend
ist zugleich der TLS-Endpunkt.
| Port (Standard) | Was | Für wen |
|---|---|---|
8443 |
HTTPS: Oberfläche, API, Live, Firmware für die Hubs, CA | Browser, Hubs, Proxy auf einem anderen Rechner |
8883 |
MQTT über TLS | Hubs |
8091 |
Push (ntfy) über HTTPS | ntfy-App, Proxy auf einem anderen Rechner |
127.0.0.1:8080, 127.0.0.1:8090 |
Oberfläche und Push ohne TLS | nur ein Proxy auf demselben Rechner |
Das Zertifikat stammt von der eigenen CA der Installation. Der Dienst certs legt sie beim
ersten Start an und erneuert das Serverzertifikat 30 Tage vor dem Ablauf selbst. Browser warnen,
bis das CA-Zertifikat importiert ist (System → Status → „CA-Zertifikat herunterladen“). Hubs
brauchen das nicht: Sie erkennen die CA am Server-Schlüssel im Einrichtungscode.
Die Hubs gehen nie über einen eigenen Proxy, sondern immer direkt an Port 8443 und 8883 des Stacks. Der Proxy ist nur dafür da, dass Menschen die Oberfläche von außen erreichen.
Mit eigenem Proxy. Er nimmt HTTPS entgegen und leitet an SmartBeet weiter.
| Deine Adresse (Beispiel) | Proxy auf anderem Rechner | Proxy auf demselben Rechner | Wofür |
|---|---|---|---|
https://beet.example.org |
https://<server>:8443 |
http://127.0.0.1:8080 |
Oberfläche, API, Live |
https://push.beet.example.org |
https://<server>:8091 |
http://127.0.0.1:8090 |
Push-Nachrichten (ntfy) |
Dabei beachten:
-
Auch zwischen Proxy und Stack liegt ein Netz. Steht der Proxy auf einem anderen Rechner, leitet er an die HTTPS-Ports weiter und prüft das Zertifikat mit dem CA-Zertifikat des Stacks. Bei nginx:
proxy_pass https://192.168.1.10:8443; proxy_ssl_trusted_certificate /etc/nginx/smartbeet-ca.crt; proxy_ssl_verify on; proxy_ssl_name smartbeet-server;http://zum Stack nur, wenn Proxy und SmartBeet auf demselben Rechner laufen. -
WebSocket durchreichen (
Upgrade,Connection) und lange Verbindungen erlauben, sonst aktualisiert sich die Übersicht nicht live. Für Push ebenso. -
Uploads bis 32 MB erlauben (Firmware), bei nginx
client_max_body_size 32m. -
Die Kopfzeilen
Host,X-Forwarded-ForundX-Forwarded-Protosetzen. -
In der
.envdie Adressen so eintragen, wie man sie von außen sieht, und SmartBeet neu starten (./deploy.sh→ „Neu starten“):APP_URL=https://beet.example.org NTFY_PUBLIC_URL=https://push.beet.example.orgMit
https://inAPP_URLmarkiert SmartBeet seine Cookies als „secure“.
Ohne eigenen Proxy, mit eigener Domain. Der mitgelieferte HTTPS-Vorbau, Caddy mit Let’s
Encrypt. In der .env:
COMPOSE_PROFILES=caddy
PUBLIC_DOMAIN=beet.example.org
PUSH_DOMAIN=push.beet.example.org
APP_URL=https://beet.example.org
NTFY_PUBLIC_URL=https://push.beet.example.org
Port 80 und 443 müssen aus dem Internet auf den Server zeigen. Caddy holt und erneuert das
Zertifikat selbst. Danach docker compose up -d --build.
Ohne Proxy und ohne Domain. https://<server>:8443 öffnen (eigene CA, siehe oben) und
APP_URL so eintragen.
Bedienen und aktualisieren
deploy.sh im Verzeichnis von SmartBeet hat ein Menü für alles, was auf dem Server anfällt:
cd /opt/smartbeet
./deploy.sh
| Menü | Direkt | Was passiert |
|---|---|---|
| 1 Aktualisieren | ./deploy.sh update |
git pull, Images bauen, starten, warten bis es antwortet |
| 2 Neu bauen | ./deploy.sh rebuild |
dasselbe ohne git pull |
| 3 Status | ./deploy.sh status |
Dienste, Stand, Antwort des Backends |
| 4 Protokoll | ./deploy.sh logs |
läuft mit; ein Dienst: ./deploy.sh logs backend |
| 5 bis 7 | restart stop start |
neu starten, stoppen, starten; die Daten bleiben erhalten |
| 8 Sicherung anlegen | ./deploy.sh backup |
legt backups/smartbeet-<Zeit>.tar.gz an |
| 9 Sicherung zurückspielen | ./deploy.sh restore |
Auswahl aus backups/, fragt nach |
| X Alles zurücksetzen | ./deploy.sh reset |
löscht alle Daten; zwei Rückfragen und das Wort RESET |
Gebaut wird vor dem Neustart: Schlägt das Bauen fehl, läuft die bisherige Anlage weiter.
Automatisch aktualisieren
Push auf main, und der Server aktualisiert sich selbst. Dafür läuft auf dem Server ein
selbst gehosteter GitHub-Actions-Runner unter dem Benutzer deploy. Bei jedem Push führt er
git reset --hard origin/main und ./deploy.sh rebuild aus. Der Ablauf liegt im Repository
als .github/workflows/deploy.yml und startet nur bei einem Push auf main, nie bei Pull
Requests: Fremder Code läuft so nie auf deinem Server.
-
Verzeichnis für den Runner — [root].
mkdir -p /opt/actions-runner chown deploy:deploy /opt/actions-runner -
Runner einrichten. Token und Version stehen unter Repository → Settings → Actions → Runners → „New self-hosted runner“. Der Runner gehört zu diesem Repository, nicht zur Organisation.
# [deploy] herunterladen cd /opt/actions-runner RUNNER_VER=2.323.0 # die Version von der Runner-Seite curl -o runner.tar.gz -L https://github.com/actions/runner/releases/download/v${RUNNER_VER}/actions-runner-linux-x64-${RUNNER_VER}.tar.gz tar xzf runner.tar.gz # [root] Abhängigkeiten, einmal cd /opt/actions-runner ./bin/installdependencies.sh apt-get install -y libicu76 # Debian 13: ICU nachinstallieren # [deploy] anmelden cd /opt/actions-runner ./config.sh --url https://github.com/smartbeet/smartbeet \ --token <TOKEN> --name "$(hostname)" --labels deploy --unattended # [root] als Dienst einrichten, läuft als deploy cd /opt/actions-runner ./svc.sh install deploy ./svc.sh start ./svc.sh status # active (running)RUNNER_ALLOW_RUNASROOTist nicht nötig, der Runner läuft nicht als root. -
Einschalten. Der Ablauf ist aus, bis du ihn einschaltest. Dafür setzt du im Repository die Variable
DEPLOY_ENABLEDauftrue(Settings → Secrets and variables → Actions → Variables). Sonst würde jeder Push aufmaineinen Lauf starten, der ohne Runner ewig wartet; bei Open Source träfe das auch jeden Fork. Liegt SmartBeet nicht in/opt/smartbeet, zusätzlichDEPLOY_DIRmit dem Pfad. -
Testen.
devnachmainmergen, unter Repository → Actions erscheint der Lauf „Deploy“. Auf dem Server:./deploy.sh status.
Alle Daten liegen in Docker-Volumes und überstehen jedes Aktualisieren. Die .env steht in
.gitignore, git reset --hard lässt sie in Ruhe. Dateien aus dem Repository auf dem
Server nicht von Hand ändern, sie werden beim nächsten Lauf überschrieben. Ein Push kann
keine Daten löschen; Zurücksetzen geht nur von Hand mit ./deploy.sh reset.
Die drei Adressen
| Einstellung | Bedeutung | Beispiel |
|---|---|---|
APP_URL |
Adresse, unter der du die Oberfläche öffnest. Sie steht in allen Mails. | https://server.lan:8443 |
NTFY_PUBLIC_URL |
Adresse des Push-Servers, wie sie die ntfy-App auf dem Handy sieht | https://server.lan:8091 |
SERVER_HOST |
Nur für Hubs an einem anderen Ort: Name oder IP, unter der sie den Server erreichen. Steht im Zertifikat und beim Einrichtungscode. | beet.example.org |
Die Einträge unter „Nur Entwicklung“ braucht der Betrieb nicht. INTERNAL_URL und MQTT_PORT
sind entfallen: Hubs laden ihre Firmware über HTTPS, und einen Broker ohne TLS gibt es nach außen
nicht mehr. Stehen sie noch in einer älteren .env, nennt das Backend sie beim Start und
ignoriert sie.
Geheimnisse
Passwörter für Datenbank und Broker und der Sitzungsschlüssel entstehen beim ersten Start von selbst und liegen in einem eigenen Volume, die eigene CA und das Serverzertifikat in einem zweiten. Es gibt keine Standardpasswörter.
Einrichtungsassistent
- Admin-Konto anlegen. Der erste Benutzer ist Hauptadmin.
- Standort eintragen. Hier lässt sich auch das Wetter abschalten.
- Mailserver eintragen und testen: der eigene oder der des Anbieters, nur mit STARTTLS oder TLS. In der Entwicklungsumgebung ist der Mail-Fänger voreingestellt.
Offene Ports
| Port | Dienst | Hinweis |
|---|---|---|
| 8443 | HTTPS | Oberfläche, API, Firmware, CA |
| 8883 | MQTT über TLS | für die Hubs |
| 8091 | Push über HTTPS (ntfy) | für die App auf dem Handy |
Mit Caddy kommen 80 und 443 dazu. Oberfläche (8080) und ntfy (8090) ohne TLS hören nur auf
127.0.0.1. Datenbank, Broker (1883) und Backend sind nur innerhalb von Docker erreichbar.
Jeder Hub hat eigene Zugangsdaten und darf nur seine eigenen Topics lesen und schreiben. Sonst
geht nichts im Klartext über ein Netz, auch nicht im Heimnetz. Die Ausnahmen nennt die README des
Projekts: Container untereinander im Docker-Netz, Ports auf 127.0.0.1, der CAN-Bus und die
offenen Einrichtungs-WLANs von Hub und Anzeige (WLAN).
Server an einem anderen Ort. Im Router dort Port 8443 und 8883 (TCP) auf den Server
weiterleiten, SERVER_HOST auf den öffentlichen Namen oder die IP setzen und beim Hub diese
Server-Adresse eintragen.
Damit der Hub den Server findet
Unter Linux kündigt ein kleiner Dienst den Server per mDNS im Heimnetz an, mit dem HTTPS-Port. Dafür braucht er Host-Netzwerk.
Unter Docker Desktop auf Windows und macOS erreicht mDNS das Heimnetz nicht. Der Hub sucht dann selbst das eigene Netz nach einem offenen Port 8443 oder 443 ab. Jeden Kandidaten prüft er über HTTPS: Er nimmt das CA-Zertifikat nur, wenn es zum Server-Schlüssel im Einrichtungscode passt. Das klappt überall, wo der Hub den Server erreicht, dauert aber bis etwa drei Minuten.
Liegt der Server in einem anderen Netz, wird seine Adresse im Einrichtungs-WLAN des Hubs
eingetragen. Hat der Server mehrere Netze, legt ANNOUNCE_IP fest, welche Adresse angekündigt
wird.
Ohne root
Kein Dienst läuft als root. Jeder Container hat einen festen, unprivilegierten Benutzer.
Wer von einem älteren Stand kommt, setzt einmal die Besitzer der Volumes, bei gestoppter Anlage:
docker compose stop
sh infra/scripts/fix-permissions.sh
docker compose up --build -d
Aktualisieren und sichern
./deploy.sh update # oder: git pull && docker compose up --build -d
./deploy.sh backup # legt backups/smartbeet-<Zeit>.tar.gz an
Die Datenbank migriert beim Start von selbst. Sicherung und Wiederherstellung stehen unter Updates und Sicherung.