Jede Einstellung der drei openplate-Container ist eine Umgebungsvariable. Diese Seite listet sie alle auf, für die App, den Core-Server (openplate-core) und den Inferenzdienst. Die meisten sind optional. Wenn du eine nicht setzt, gilt der Standardwert in ihrer Zeile.
Manche Einstellungen stoppen den Start mit Absicht. Ein Wert, den der Dienst nicht verwenden kann, oder eine Hälfte eines Paars führt dazu, dass der Container sich beendet. Die Beendigungsmeldung nennt die Variable. Der Container startet nicht mit einer Vermutung. Einstellungen, die den Start stoppen listet jede solche Regel auf.
So setzt du eine Variable
Docker Compose. Trage die Zeile in die Datei .env neben der Compose-Datei ein, zum Beispiel LOG_LEVEL=debug. Führe dann docker compose -f <your file> up -d erneut aus. Jede mitgelieferte Compose-Datei leitet jede Variable, die ihr Dienst liest, an den Container weiter. docker compose restart liest .env nicht erneut ein.
Quadlet. Trage die Zeile in die Datei <unit>.env neben der Unit ein, zum Beispiel app.env, core.env oder inference.env. Verwende die container-eigenen Namen von dieser Seite. Starte die Unit dann neu, zum Beispiel systemctl --user restart core.service. podman.md erklärt die Dateien. Ohne Container. Die App und der Core-Server lesen jeweils eine .env-Datei in dem Ordner, in dem sie laufen. Du kannst die Variable auch in der Shell oder in der systemd-Unit setzen. Ohne Docker zeigt die Konfiguration der App.
Die Spalte „Standard“ gibt an, was der Dienst tut, wenn die Variable nicht gesetzt ist. Eine Compose-Datei kann einen eigenen Wert übergeben, zum Beispiel MODEL_PROFILE: lite. Die Compose-Datei zeigt diesen Wert neben dem Namen an.
Namen, die die Compose-Dateien für dich ausfüllen
Die drei Topologie-Dateien, compose.core.yml, compose.inference.yml und compose.full.yml, füllen manche Container-Variablen aus gemeinsamen Namen in .env. Setze den gemeinsamen Namen dort. Die Container-Variable allein hat in diesen Dateien keine Auswirkung.
In .env | Füllt |
|---|
PUBLIC_APP_URL | das APP_URL der App und das CLIENT_BASE_URL des Core-Servers |
PUBLIC_SYNC_URL | das CORE_URL der App und das SERVER_PUBLIC_URL des Core-Servers |
PUBLIC_INFERENCE_URL | DEFAULT_INFERENCE_BASE_URL der App |
INFERENCE_API_KEY | DEFAULT_INFERENCE_API_KEY der App und API_KEYS des Inferenz-Dienstes |
POSTGRES_USER, POSTGRES_PASSWORD, SYNC_DB_NAME | die Datenbank und das DATABASE_URL des Core-Servers |
docker/compose.yml, die App allein, übernimmt APP_URL unter eigenem Namen. Die eigene Schnellstart-Datei des Core-Servers ist apps/core/docker/compose.yml. Sie übernimmt SERVER_PUBLIC_URL und CLIENT_BASE_URL unter deren eigenen Namen. Sie baut DATABASE_URL aus POSTGRES_USER, POSTGRES_PASSWORD und POSTGRES_DB zusammen.
Die App
Der App-Container, ghcr.io/lowcarbcheck/openplate. Er startet, ohne dass etwas gesetzt ist. configuration.md erklärt seine größeren Funktionen im Detail.
Server und Adressen
| Variable | Standardwert | Was es tut | Mehr |
|---|
NODE_ENV | production im Image, sonst development | production liefert die gebaute App aus, macht APP_URL erforderlich und setzt 1 als Standard für TRUST_PROXY. Das Image setzt es. | |
APP_URL | http://localhost:3000, erforderlich in der Produktion | Die öffentliche Adresse, die Nutzer aufrufen, zum Beispiel https://openplate.example.com. Die Startseite verwendet sie in ihren Freigabelinks. Der Server startet in der Produktion nicht ohne sie. | Caddy |
PORT | 3000 | Der Port, auf dem der Server lauscht. | |
HOST | nicht gesetzt, jede Schnittstelle | Die Adresse, auf der der Server lauscht. Lass sie in einem Container ungesetzt. Ohne Container beschränkt 127.0.0.1 den Server auf diese Maschine, etwa für einen Proxy auf demselben Rechner. | Ohne Docker |
TRUST_PROXY | 1 in Produktion, sonst aus | Wie viele Reverse Proxies vor der App liegen: eine Zahl, true, false oder ein Express-Preset oder Adressbereich wie loopback oder 10.0.0.0/8. Die Prüfung, die seitenübergreifende Formularübertragungen blockiert, benötigt hinter einem Proxy den passenden Wert. Verwende 0 ohne Proxy. | Die App allein |
CSP_CONNECT_EXTRA | nicht gesetzt | Zusätzliche Origins für die connect-src der Content-Security-Policy, getrennt durch Leerzeichen. Ein eigener KI-Endpunkt auf einem anderen Host benötigt dies. | Eigene KI-Endpunkte |
Sprache und Inhalt
| Variable | Standardwert | Was es tut | Mehr |
|---|
DEFAULT_UI_LANGUAGE | en | Die Sprache, die Besucher sehen, bevor sie eine auswählen: en, de, fr, it, es oder tr. Die eigene Wahl einer Person hat immer Vorrang. Jeder andere Wert stoppt den Start. | |
NUTRIENT_REFERENCE_BASIS | dge | Die Referenzwerte, die der Nährstoffbildschirm anzeigt: dge (deutsche DGE), efsa (EU) oder us (NASEM). Jeder andere Wert stoppt den Start. | |
CONTENT_DIR | nicht gesetzt, keine rechtlichen Seiten | Ein Ordner mit Markdown-Dateien für die rechtlichen Seiten, schreibgeschützt eingebunden. Ein Wert, der keinen Ordner benennt, stoppt den Start. | Inhaltsseiten |
Sync und Art der Instanz
| Variable | Standardwert | Was es tut | Mehr |
|---|
CORE_URL | nicht gesetzt, Sync aus | Die Adresse deines Core-Servers, wie ein Browser sie erreicht. Ihr Origin fließt in die Content-Security-Policy ein. Auf einer verwalteten Instanz erreicht der App-Server sie ebenfalls, um das Konto jeder Lebensmittelsuche zu prüfen. Ein fehlerhafter Wert bricht den Startvorgang ab. | Synchronisation |
SYNC_SERVER_URL | nicht gesetzt | Veraltet. Der alte Name von CORE_URL. Er funktioniert noch für eine weitere Version, und der Startvorgang protokolliert eine Warnung, wenn nur er gesetzt ist. Wenn beide auf unterschiedliche Adressen gesetzt sind, gewinnt für diese Version der alte Name, und der Startvorgang protokolliert eine Warnung, die beide nennt. Entferne die alte Zeile vor der Version, die den alten Namen entfernt. | Synchronisation |
INSTANCE_MODE | open | open oder managed. Auf einer verwalteten Instanz lädt ein Administrator Personen ein, und der Core-Server stellt die KI bereit. managed erfordert CORE_URL. Jeder andere Wert bricht den Startvorgang ab. | Managed Instances |
Von der Instanz bereitgestellte KI
| Variable | Standardwert | Was es tut | Mehr |
|---|
DEFAULT_INFERENCE_BASE_URL | nicht gesetzt | Ein zu OpenAI kompatibler Endpunkt, den diese Instanz allen Besuchern anbietet, wie ein Browser ihn erreicht. Ein fehlerhafter Wert stoppt den Start. | Von der Instanz bereitgestellte KI |
DEFAULT_INFERENCE_API_KEY | nicht gesetzt | Der Schlüssel für diesen Endpunkt. Er ist öffentlich: Der Browser jedes Besuchers empfängt ihn. | Von der Instanz bereitgestellte KI |
DEFAULT_INFERENCE_MODEL | openplate-plate-1 | Der Modellname, der an diesen Endpunkt gesendet wird. | Von der Instanz bereitgestellte KI |
Lebensmitteldatenbank
| Variable | Standardwert | Was es tut | Mehr |
|---|
FOOD_DB_API_URL | https://lowcarbcheck.org | Die LowCarbCheck-Lebensmitteldatenbank, in der der Server nach Lebensmittelnamen sucht. Ein leerer Wert schaltet die Suche ab. | Der Schlüssel für die Lebensmitteldatenbank |
FOOD_DB_API_KEY | nicht gesetzt, die anonyme Stufe | Dein LowCarbCheck-Schlüssel. Nur der Server liest ihn, und er erreicht nie einen Browser. | Der Schlüssel für die Lebensmitteldatenbank |
FOOD_DB_BACKFILL | false | true leitet Lebensmittel, die Personen aus einer KI-Antwort speichern, als Vorschläge an LowCarbCheck weiter. Dies erfordert FOOD_DB_API_KEY und bleibt ohne diesen Wert deaktiviert. Jeder Wert außer true oder false stoppt den Start. | Vorschläge an die Lebensmitteldatenbank |
FOOD_DB_DAILY_CALL_LIMIT | 3200 | Die Höchstzahl an LowCarbCheck-Aufrufen, die dieser Server an einem UTC-Tag ausführt. Wird sie überschritten, pausieren Lebensmittelsuchen bis Mitternacht UTC, und die App weist darauf hin. Der Standardwert hält die monatlichen 100.000 eines kostenlosen Schlüssels ein. Jeder andere Wert als eine positive ganze Zahl stoppt den Startvorgang. | Der Schlüssel für die Lebensmitteldatenbank |
Analytics, Newsletter und Updates
| Variable | Standardwert | Was es tut | Mehr |
|---|
MATOMO_URL | nicht gesetzt, Analytics aus | Eine Matomo-Installation, die du selbst betreibst. Setze diesen Wert zusammen mit MATOMO_SITE_ID. | Analytik |
MATOMO_SITE_ID | nicht gesetzt | Die Matomo-Site-ID, eine positive ganze Zahl. Setze diesen Wert zusammen mit MATOMO_URL. | Analytik |
MATOMO_EVENT_LEVEL | product | Wie viel die Instanz erfasst: pageviews, product oder research. Dies erfordert die beiden obigen Einstellungen. | Was eine Stufe festlegt |
NEWSLETTER_SUBSCRIBE_URL | nicht gesetzt, kein Formular | Wohin der Server das Newsletter-Formular der Startseite weiterleitet. Setze diesen Wert zusammen mit NEWSLETTER_TURNSTILE_SITE_KEY. | Newsletter-Anmeldung |
NEWSLETTER_TURNSTILE_SITE_KEY | nicht gesetzt | Der Cloudflare-Turnstile-Websiteschlüssel dieses Formulars. Das ist nicht das Registrierungs-Captcha, siehe Registrierung mit Turnstile. | Newsletter-Anmeldung |
UPDATE_CHECK | an | Wenn du dies auf off oder false setzt, ruft der Server openplate.de/latest.json nicht mehr ab, um nach neuen Versionen zu suchen. Es stoppt auch die tägliche Zählung der Abfragen durch das Projekt. | Die Release-Prüfung |
Protokollierung
| Variable | Standardwert | Was es tut | Mehr |
|---|
LOG_LEVEL | info | Wie ausführlich der Server protokolliert, als Pino-Stufe: debug, info, warn oder error. | |
Eine Instanz schließen
| Variable | Standardwert | Was es tut | Mehr |
|---|
MOVED_TO_URL | nicht gesetzt | Schließt diese Instanz und leitet Nutzer auf eine andere weiter, beispielsweise https://app.openplate.de. Jede Seitenanfrage liefert eine Seite aus, die die neue Adresse nennt, der auf Smartphones installierte Service-Worker leert seine Caches und deregistriert sich selbst, und die API gibt 410 zurück. Der Wert muss eine https://-Adresse auf einem anderen Host als APP_URL sein; alles andere bricht den Start ab. | Personen auf eine andere Instanz umziehen |
Der Core-Server (openplate-core)
Der Core-Server-Container, ghcr.io/lowcarbcheck/openplate-core. Er benötigt zwei Werte: DATABASE_URL, den die Compose-Dateien für dich ausfüllen, und SERVER_SECRET. Alles andere ist optional und deaktiviert, bis du es setzt. README von openplate-core erklärt die Funktionen.
Server und Adressen
| Variable | Standardwert | Was es tut | Mehr |
|---|
NODE_ENV | production im Image | Wenn Mail konfiguriert ist, erfordert production, dass beide unten stehenden Link-Adressen https://-Adressen auf einem anderen Host sind. | Mail benötigt die öffentlichen Adressen |
PORT | 3000 | Der Port, auf dem der Dienst lauscht. | |
HOST | nicht gesetzt, jede Schnittstelle | Die Adresse, auf der der Dienst lauscht. Im Container nicht setzen. 127.0.0.1 beschränkt eine Entwicklungsinstanz auf den eigenen Rechner. | |
TRUST_PROXY | false | Wie viele Reverse-Proxies davorstehen: eine Zahl, true oder false. Bei einem falschen Wert hinter einem Proxy scheint jede Anfrage vom Proxy zu kommen. Eine einzelne Person kann dann das Limit für alle aufbrauchen. | Drei wichtige Einstellungen |
SERVER_PUBLIC_URL | nicht gesetzt | Die eigene öffentliche Adresse dieses Dienstes. Sie wird in die Links in Einladungs- und Passwort-Reset-Mails eingefügt. Zusammen mit CLIENT_BASE_URL setzen. | Mail benötigt die öffentlichen Adressen |
CLIENT_BASE_URL | nicht gesetzt | Die Adresse der openplate-App, die andere Hälfte dieser Links. | Mail benötigt die öffentlichen Adressen |
INSTANCE_NAME | openplate | Setzt den Instanznamen für den /health-Handshake (instance.name) und das Startprotokoll. Die Mails verwenden ihn nicht. Maximal 64 Zeichen. | |
INSTANCE_LANGUAGE | en | Setzt die Sprache der Mails, wenn eine Anfrage keine angibt. Zulässige Werte sind en, de, fr, it, es oder tr. Jeder andere Wert stoppt den Startvorgang. | |
NUTRIENT_REFERENCE_BASIS | dge | Eine neue Instanz startet mit einem dieser Referenzwerte: dge, efsa oder us. Über die Admin-API kann die Administration die Einstellung später im laufenden Betrieb ändern. Jeder andere Wert stoppt den Startvorgang. | |
CONTENT_DIR | nicht gesetzt | Ein schreibgeschützt eingebundener Ordner mit dem Text der Erklärungsschreiben. Die App kann ihre rechtlichen Seiten aus diesem Ordner lesen. Der Dienst prüft ihn beim Startvorgang nie. | Erklärungsschreiben |
LEGAL_DECLARATION_RECEIPTS_PER_DAY | 200 | Die maximale Anzahl an Bestätigungen für Erklärungen, die die Instanz in beliebigen 24 Stunden versendet, an alle Adressen zusammen. Danach wird eine Erklärung zwar noch erfasst und an dich gesendet, ihre Bestätigung entfällt jedoch. | Erklärungsschreiben |
LEGAL_DECLARATION_RECEIPTS_PER_NETWORK_PER_DAY | 10 | Dasselbe Limit für ein einzelnes Absendernetzwerk, eine IPv4-Adresse oder ein IPv6-/64. Ein Neustart setzt diesen Zähler zurück. | Erklärungsschreiben |
Datenbank
| Variable | Standardwert | Was es tut | Mehr |
|---|
DATABASE_URL | keine, erforderlich | Die Postgres-Verbindungszeichenfolge. Die Compose-Dateien erstellen sie für dich. | |
DATABASE_SSL | false | Auf true setzen, wenn Postgres TLS erfordert. Akzeptiert true, false, 1 oder 0. | |
MIGRATIONS_DIR | drizzle/migrations | Legt fest, wo der Dienst beim Start seine Datenbankmigrationen findet. Das Image hält sie dort bereit, also nicht setzen. | |
Geheimnisse
| Variable | Standardwert | Was es tut | Mehr |
|---|
SERVER_SECRET | keine, erforderlich | Das Root-Geheimnis muss mindestens 32 Zeichen lang sein. Erzeuge es mit openssl rand -hex 32 und sichere es zusammen mit der Datenbank. Wenn dieses Geheimnis geändert wird, wird jedes Konto dauerhaft ausgesperrt. | Drei wichtige Einstellungen |
ADMIN_TOKEN | nicht gesetzt | Die Zugangsdaten der Betreiber-Administration müssen mindestens 24 Zeichen lang sein. Du benötigst sie, um das erste Konto zu erstellen. Ohne Token und ohne Administratorkonto liefert die Admin-API den Statuscode 404 zurück. | Das erste Konto erstellen |
Konten und Registrierung
| Variable | Standardwert | Was es tut | Mehr |
|---|
OPEN_SIGNUP | nicht gesetzt, nur Einladungen | true erlaubt es allen, mit der eigenen Adresse ein Konto anzufragen. Das erfordert Mail. Der Server akzeptiert nur true. Jeder andere Wert, einschließlich false, stoppt den Startvorgang. | Registrierung mit Turnstile |
TURNSTILE_SECRET_KEY | nicht gesetzt, kein Captcha | Der geheime Schlüssel für Cloudflare Turnstile, der das Registrierungs-Captcha prüft. Setze ihn zusammen mit TURNSTILE_SITE_KEY und nur mit OPEN_SIGNUP=true. | Registrierung mit Turnstile |
TURNSTILE_SITE_KEY | nicht gesetzt | Der öffentliche Site-Key für Turnstile. /health veröffentlicht ihn, und die App rendert das Captcha damit. | Registrierung mit Turnstile |
Einladungen und Testphasen
| Variable | Standardwert | Was es tut | Mehr |
|---|
MEMBER_INVITE_DAILY_AI_LIMIT | nicht gesetzt, Mitglieder können niemanden einladen | Die Anzahl an KI-Anfragen pro UTC-Tag, die ein Konto erhält, wenn ein Mitglied es eingeladen hat, 1 bis 10000. Setze sie zusammen mit MEMBER_INVITE_ALLOWANCE_DAYS. | Mitgliedereinladungen |
MEMBER_INVITE_ALLOWANCE_DAYS | nicht gesetzt | Die Anzahl der Tage nach der Registrierung, die dieses Kontingent gilt. | Mitgliedereinladungen |
MEMBER_INVITE_LIFETIME_CAP | 5 | Die Gesamtzahl an Einladungen, die ein Mitglied überhaupt versenden kann: 0 oder mehr. Dies erfordert das obige Paar oder MEMBER_INVITE_TRIAL=true. | Mitgliedereinladungen |
MEMBER_INVITE_TRIAL | false | true sorgt dafür, dass eine Einladung durch ein Mitglied die unten stehende Scan-Testphase statt des Tageskontingents gewährt. Es erfordert die Testphase und lässt sich nicht mit dem obigen Paar nutzen. | |
TRIAL_SCANS | nicht gesetzt, keine Testphase | Die kostenlosen KI-Scans, die ein neues Konto erhält, 1 bis 100. Setze diesen Wert zusammen mit TRIAL_DAILY_AI_LIMIT, und setze TRIAL_ADDRESS_PEPPER dazu. | |
TRIAL_DAILY_AI_LIMIT | nicht gesetzt | Die Anzahl der KI-Anfragen pro UTC-Tag während der Testphase, 1 bis 10000. | |
TRIAL_DAYS | nicht gesetzt, kein Enddatum | Die Testphase endet außerdem um Mitternacht nach so vielen Tagen, 1 bis 90, je nachdem, was zuerst eintritt. Dies erfordert das Testphasenpaar. | |
TRIAL_TIME_ZONE | UTC | Die Zeitzone dieser Mitternacht als IANA-Name wie etwa Europe/Berlin. Erfordert TRIAL_DAYS. Eine unbekannte Zeitzone bricht den Start ab. | |
TRIAL_ADDRESS_PEPPER | nicht gesetzt | Das Geheimnis, das eine Testphase pro Postfach erzwingt. Es muss mindestens 32 Zeichen lang sein. Erforderlich zusammen mit dem Testphasenpaar. Wenn du diesen Wert änderst, wird vergessen, welche Postfächer eine Testphase hatten. | |
TRIAL_HASH_RETENTION_DAYS | 365 | Die Tage, die der Postfach-Hash eines gelöschten Kontos aufbewahrt wird, 1 bis 3650, gezählt ab der Löschung. Danach löscht ihn ein stündlicher Durchlauf, und dasselbe Postfach kann erneut einen Testzeitraum nutzen. Eine Instanz ohne Scan-Testzeitraum speichert keinen Hash. | |
AI_TRIAL_INSTANCE_DAILY_LIMIT | nicht gesetzt, kein Limit | Der Gesamtbetrag, den alle Testkonten zusammen pro UTC-Tag verbrauchen können. Erfordert die Testphase. | |
AI_TRIAL_NETWORK_DAILY_LIMIT | ein Zehntel von AI_TRIAL_INSTANCE_DAILY_LIMIT, mindestens 1 | Die Menge, die die Testanfragen aus einem Netzwerk (ein IPv6-/64 oder eine IPv4-Adresse) vom Testlimit pro UTC-Tag verbrauchen können. Ohne AI_TRIAL_INSTANCE_DAILY_LIMIT ist dies deaktiviert und darf nicht darüber liegen. Personen hinter einem gemeinsamen IPv4-Carrier-NAT teilen sich diesen Wert. | |
DEFAULT_FREE_DAILY_AI_LIMIT | nicht gesetzt, aus | Die KI-Anfragen pro UTC-Tag, die jedes Konto ohne eigenes freies Limit erhält, 0 bis 10000. Es endet nie und hat keine Scan-Zählung. Ein aufgebrauchter Tag antwortet mit 429 und Retry-After. Es ersetzt den Scan-Testzeitraum; wird es zusammen mit dem Testzeitraum-Paar gesetzt, stoppt der Bootvorgang. Ein Konto, das noch einen Testzeitraum hat, fällt unter dieses Limit. | |
DEFAULT_CAPABILITIES | nicht gesetzt, keine Prüfung | Was ein Konto ohne eigene Berechtigungsliste nutzen darf: kommagetrennte Labels wie scan,recipes, oder none für nichts. Nicht gesetzt oder leer bedeutet, dass der KI-Proxy keine Funktion prüft und jede Anfrage durchlässt. Eine Anfrage für eine Funktion, die dem Konto fehlt, erhält 403 capability-required. | |
CAPABILITY_SCHEMA_MAP | nicht gesetzt, leer | Kommagetrennte schemaName:label-Paare. Eine Anfrage, die das von dir aufgeführte Schema für strukturierte Ausgaben anfordert, benötigt dieses Label, egal was ihr X-Openplate-Feature-Header angibt. | |
E-Mail
| Variable | Standardwert | Was es tut | Mehr |
|---|
SMTP_HOST | nicht gesetzt | Der Name oder die Adresse des SMTP-Servers, ohne Schema, Port oder Pfad. | SMTP |
SMTP_PORT | 587 | 465 nutzt TLS ab dem ersten Byte. Jeder andere Port muss per STARTTLS hochstufen, abgesehen von einem Mail-Catcher auf dieser Maschine. | SMTP |
SMTP_USER | nicht gesetzt | Der SMTP-Benutzername. Setze ihn zusammen mit SMTP_PASSWORD oder lasse beide ungesetzt für einen Server ohne Login. | SMTP |
SMTP_PASSWORD | nicht gesetzt | Das SMTP-Passwort. | SMTP |
SMTP_FROM | nicht gesetzt | Der Absender, formatiert als address oder Name <address>. SMTP erfordert ihn. | SMTP |
MAIL_API_URL | nicht gesetzt | Eine zu Resend kompatible HTTP-Mail-API. Setze sie zusammen mit MAIL_API_KEY, MAIL_API_FROM und MAIL_OPERATOR_EMAIL. | Eine HTTP-Mail-API |
MAIL_API_KEY | nicht gesetzt | Der Mail-API-Schlüssel, der als Bearer-Token gesendet wird. | Eine HTTP-Mail-API |
MAIL_API_FROM | nicht gesetzt | Die Absenderadresse für die Mail-API. | Eine HTTP-Mail-API |
MAIL_OPERATOR_EMAIL | nicht gesetzt | Deine eigene Adresse. Sie empfängt deine Kopie einer Kündigung oder eines Widerrufs. Beide Transporte erfordern sie. | SMTP |
NODE_EXTRA_CA_CERTS | nicht gesetzt | Der Pfad innerhalb des Containers zu einer PEM-Datei mit zusätzlichen Zertifizierungsstellen. Node.js liest sie beim Start ein. Mounte die Datei für ein Mail-Relay, dessen Zertifikat eine private Zertifizierungsstelle signiert hat. | Ein Relay mit einer privaten Zertifizierungsstelle |
KI-Proxy und Limits
| Variable | Standardwert | Was es tut | Mehr |
|---|
UPSTREAM_BASE_URL | nicht gesetzt, keine KI | Die OpenAI-kompatible Adresse des Anbieters, zum Beispiel https://openrouter.ai/api/v1. Setze sie zusammen mit UPSTREAM_API_KEY. | Managed Instances |
UPSTREAM_API_KEY | nicht gesetzt | Der Anbieterschlüssel. Er gelangt nie in einen Browser. | Managed Instances |
UPSTREAM_ZDR | nicht gesetzt | Nur OpenRouter. Setze es auf true, und der Proxy weist OpenRouter an, eine Anfrage nur an Endpunkte ohne Datenaufbewahrung weiterzuleiten. Jeder andere Host ignoriert dies. Ein anderer Wert als true, false oder leer stoppt den Bootvorgang. | Der KI-Proxy |
UPSTREAM_PROVIDER_ONLY | nicht gesetzt | Nur OpenRouter. Eine kommagetrennte Liste von Provider-Slugs, zum Beispiel google-vertex. Eine Anfrage geht an einen von ihnen oder schlägt fehl, und weicht niemals auf einen anderen Provider aus. Jeder andere Host ignoriert dies. | Der KI-Proxy |
UPSTREAM_TIMEOUT_MS | 120000 | Die Zeit in Millisekunden, die der Proxy auf die erste Antwort des Anbieters und anschließend zwischen deren Teilen wartet. | |
AI_TIERS_FILE | nicht gesetzt | Woher das Modell für jede Art von Anfrage stammt. Wenn nicht gesetzt, ist das Modell AI_ADVERTISED_MODEL, mit dem Routing aus UPSTREAM_ZDR und UPSTREAM_PROVIDER_ONLY, genau wie vor der Existenz der Datei. bundled nutzt die Datei im Core-Image, ai-tiers.json, die das Modell, sein Routing und seinen Preis enthält. Ein absoluter Pfad nutzt eine von dir eingebundene Datei. Ein ungültiger Wert oder eine fehlerhafte Datei stoppt den Systemstart. | Der KI-Proxy |
AI_ADVERTISED_MODEL | nicht gesetzt | Das Modell, das jeder Scan nutzt, wenn keine Tier-Datei vorhanden ist. /health benennt es, und der Proxy schreibt es in jede Anfrage. Ohne Modell scannt die App nicht. Mit einer Tier-Datei überschreibt es lediglich das Modell des Standard-Tiers als Notfallmaßnahme, und der Core gibt bei jedem Start eine Warnung aus. | Managed Instances |
AI_MAX_OUTPUT_TOKENS | 8192 | Die maximale Anzahl an Ausgabe-Tokens, die eine Anfrage anfordern kann. | |
AI_RATE_LIMIT_PER_MINUTE | 20 | Die maximale Anzahl an Anfragen, die ein Konto innerhalb von jeweils 60 Sekunden stellen kann. | |
AI_INSTANCE_DAILY_LIMIT | nicht gesetzt, kein Limit | Das tägliche Instanzlimit in KI-Einheiten pro UTC-Tag. Ein Tellerfoto-Scan kostet eine Einheit. | Der KI-Proxy |
AI_BUDGET_ALERT_FRACTION | 0.2 | Bei einem OpenRouter-Schlüssel sende einmal pro Rücksetzzeitraum eine E-Mail an MAIL_OPERATOR_EMAIL, wenn weniger als dieser Anteil des Schlüssellimits übrig ist. Größer als 0 und kleiner als 1. | Der KI-Proxy |
AI_MAX_REQUEST_BYTES | 8000000 | Die größte Anfrage, die der Proxy akzeptiert, in Bytes. | |
AI_MAX_IMAGE_PARTS | 1 | Maximale Bildanzahl pro Anfrage. Anfragen, die dieses Limit überschreiten, geben 400 ai-request-too-large zurück, bevor die Zählung beginnt. | |
AI_MAX_TEXT_BYTES | 49152 | Maximale Text-Bytes pro Anfrage, zusammengezählt aus Nachrichtentext und response_format. Anfragen mit mehr Bytes geben das gleiche 400 zurück. | |
AI_MAX_MESSAGES | 4 | Maximale Nachrichtenanzahl pro Anfrage. Anfragen, die dieses Limit überschreiten, geben das gleiche 400 zurück. | |
AI_UNIT_INPUT_TOKENS | 8192 | Geschätzte Eingabe-Tokens pro KI-Einheit. Jede Anfrage kostet eine Einheit, plus eine pro zusätzlichem AI_UNIT_INPUT_TOKENS. Tägliche Limits zählen diese Einheiten. | Der KI-Proxy |
AI_IMAGE_INPUT_TOKENS | 1500 | Geschätzte Eingabe-Tokens für ein Bild. Text zählt als seine Gesamtanzahl an Bytes geteilt durch 4. | |
Einwilligung
| Variable | Standardwert | Was es tut | Mehr |
|---|
HEALTH_CONSENT_VERSION | nicht gesetzt, keine Einwilligung erfragt | Die Version der Einwilligung für Gesundheitsdaten, die jedes Konto akzeptieren muss, wie etwa 2026-09-28. Verwende 1 bis 32 Buchstaben, Ziffern, ., _ oder -. Eine geänderte Version fragt alle Nutzer erneut. | Ausdrückliche Einwilligung |
Push
| Variable | Standardwert | Was es tut | Mehr |
|---|
VAPID_PUBLIC_KEY | nicht gesetzt, keine Benachrichtigungen | Der öffentliche Schlüssel für Web-Push. Setze alle drei oder keinen. Erzeuge ein Paar mit pnpm core-api push keygen. | |
VAPID_PRIVATE_KEY | nicht gesetzt | Der private Schlüssel für Web-Push. | |
VAPID_SUBJECT | nicht gesetzt | Wie ein Push-Dienst dich erreicht: eine mailto:-Adresse oder eine https://-Adresse. | |
PUSH_ENDPOINT_HOSTS | nicht gesetzt | Zusätzliche kommagetrennte Push-Hosts, die ein Gerät registrieren kann. *.example.org deckt jeden Host unter example.org ab. Standard-Browser-Push-Dienste sind immer zulässig. Setze dies nur für eigene Hosts. Ein fehlerhafter Eintrag stoppt den Startvorgang. | |
Tarife
| Variable | Standardwert | Was es tut | Mehr |
|---|
PLANS_UPSTREAM_URL | nicht gesetzt, keine Tarife | Die interne Adresse des Abrechnungsdienstes, der /v1/plans/* empfängt. Setze sie zusammen mit PLANS_UPSTREAM_SECRET. | Kostenpflichtige Tarife |
PLANS_UPSTREAM_SECRET | nicht gesetzt | Das gemeinsame Geheimnis, das der Abrechnungsdienst prüft. | Kostenpflichtige Tarife |
BILLING_TOKEN | nicht gesetzt | Die eigene Anmeldeinformation des Abrechnungsdienstes, mindestens 24 Zeichen lang. Sie erreicht drei Admin-Routen und sonst nichts. | Kostenpflichtige Tarife |
BILLING_MAX_DAILY_AI_LIMIT | 1000 | Maximales tägliches KI-Limit, das BILLING_TOKEN für ein Konto eintragen kann. Halte dies bei oder über deinem höchsten Tarif. ADMIN_TOKEN ist nicht daran gebunden. | Kostenpflichtige Tarife |
Feedback, Freigabe und Forschung
| Variable | Standardwert | Was es tut | Mehr |
|---|
SYNC_FEEDBACK | false | true nimmt gemeldete Schätzungen samt ihren Fotos an und speichert sie 30 Tage lang. Du kannst diese Fotos ansehen. | Gemeldete Schätzungen |
FEEDBACK_DAILY_LIMIT | 5 | Die Meldungen, die ein Konto pro UTC-Tag senden kann. | |
FEEDBACK_MAX_REQUEST_BYTES | 8000000 | Die größte Meldung, die der Dienst akzeptiert, in Bytes. | |
SYNC_SHARING | false | true schaltet die Freigabe eines Tagebuchs für eine medizinische Fachkraft ein. | |
SYNC_RESEARCH | false | true schaltet Forschungsbeiträge und die Studienkonsole ein. | Synchronisation |
Protokollierung und Sonstiges
| Variable | Standardwert | Was es tut | Mehr |
|---|
LOG_LEVEL | info | debug, info, warn oder error. Jeder andere Wert bricht den Start ab. | |
SYNC_NOTICE | nicht gesetzt | Eine kurze Nachricht, die jede App beim Verbinden anzeigt, höchstens 280 Zeichen. | |
SYNC_NOTICE_URL | nicht gesetzt | Ein Link neben dem Hinweis, https:// oder http://. Er erfordert SYNC_NOTICE. | |
SERVICE_VERSION | nicht gesetzt, die Version des Images | Ersetzt die Version, die /health meldet. Lass diesen Wert ungesetzt. | |
Der Inferenz-Dienst (openplate-inference)
Der Inferenz-Container, ghcr.io/lowcarbcheck/openplate-inference. Er führt die Modell-Runtime und den Dienst in einem einzigen Container aus. Konfigurationsanleitung für openplate-inference beschreibt die Optionen im Detail.
Dienst und Zugriff
| Variable | Standardwert | Was es tut | Mehr |
|---|
PORT | 8300 | Der Port, auf dem der Dienst lauscht. Er ist der einzige Port, den der Container freigibt. | |
API_KEYS | nicht gesetzt, ein temporärer Schlüssel | Die Schlüssel, die ein Aufrufer übermitteln muss, getrennt durch Kommas. Wenn nicht gesetzt, erzeugt der Dienst beim Start einen Schlüssel, gibt ihn einmalig aus und verwirft ihn beim nächsten Neustart. | Schlüssel abrufen |
LOG_LEVEL | info | debug, info, warn oder error. Jeder andere Wert bricht den Start ab. | |
PROFILE | aus MODEL_PROFILE gesetzt | Der Profilname, den das Startprotokoll ausgibt: lite, quality oder custom. Der Container setzt ihn aus MODEL_PROFILE, sonst ändert er nichts. | |
Modell und Gewichte
| Variable | Standardwert | Was es tut | Mehr |
|---|
MODEL_PROFILE | lite | Die Gewichte, die der Container herunterlädt und ausführt: lite, lite-apache oder quality. external lädt nichts herunter und nutzt deine eigene Runtime unter MODEL_RUNTIME_URL. | Hardware |
MODELS_DIR | /models | Der Speicherort der Gewichte im Container, auf einem Volume. Ändere ihn nur, wenn du die Gewichte an anderer Stelle einbindest. | |
WEIGHTS_MIRROR_BASE | nicht gesetzt | Ein Mirror für den Download der Gewichte, mit Hugging Face als Fallback. Der Dienst prüft Prüfsummen in beiden Fällen. | |
MODEL_RUNTIME_URL | http://127.0.0.1:8080, die mitgelieferte Runtime | Die Adresse deiner eigenen Runtime, ohne /v1. MODEL_PROFILE=external erfordert sie. Bei jedem anderen Profil bricht eine abweichende Adresse den Container ab. | Variablen für den externen Modus |
MODEL_RUNTIME_API_KEY | nicht gesetzt | Ein Schlüssel, den der Dienst an deine Runtime übermittelt, falls die Runtime oder ein Proxy einen erfordert. | Variablen für den externen Modus |
MODEL_ID | openplate-plate-1 | Der Modellname, den der Dienst an die Runtime sendet. vLLM benötigt die exakte Bezeichnung des bereitgestellten Modells. | Variablen für den externen Modus |
RUNTIME_PORT | 8080 | Der Port des mitgelieferten llama-server, ausschließlich auf der Loopback-Adresse des Containers. | |
CONTEXT_SIZE | 8192 | Der Kontext für jeden laufenden Scan. Der Container multipliziert ihn für llama.cpp mit CONCURRENCY. | |
LLAMA_THREADS | die Anzahl der Kerne minus zwei, mindestens 1 | Die CPU-Threads für llama.cpp. | |
LLAMA_EXTRA_ARGS | nicht gesetzt | Zusätzliche Flags für das Ende des Befehls llama-server, getrennt an Leerzeichen. Nur mitgelieferte Runtime. | |
GPU_LAYERS | erkannt: 99 mit einer GPU, sonst 0 | Wie viele Modellschichten auf die GPU ausgelagert werden. 0 erzwingt die CPU. | |
NVIDIA_VISIBLE_DEVICES | wird von der NVIDIA-Container-Runtime gesetzt | --gpus all setzt diese Variable. Jeder Wert außer void oder none sorgt dafür, dass der Container die GPU nutzt. Du setzt sie nicht selbst. | |
Grenzwerte
| Variable | Standardwert | Was es tut | Mehr |
|---|
CONCURRENCY | 2 | Die gleichzeitig laufenden Scans. Dieser Wert legt auch die Slots von llama.cpp fest. | |
MAX_QUEUE_DEPTH | 8 | Die Scans, die in der Warteschlange stehen können. Danach erhält ein Aufrufer 429. | |
RATE_LIMIT_RPM | 60 | Die Anfragen pro Minute für jeden Schlüssel. | |
LATENCY_CEILING_MS | 0, aus | Der Dienst lehnt einen Scan ab, den er nicht innerhalb dieser Anzahl an Millisekunden abschließen kann. | Hardware |
RUNTIME_COMPLETION_TIMEOUT_MS | 600000 | Die maximale Dauer eines Aufrufs an die Runtime in Millisekunden. 0 schaltet das Limit ab. | |
MAX_IMAGE_BYTES | 8388608 | Das größte Foto, das der Dienst nach dem Dekodieren akzeptiert, in Byte (8 MiB). | |
IMAGE_MAX_LONG_EDGE | 896 | Die lange Kante, auf die der Dienst jedes Foto herunterskaliert, in Pixeln, mindestens 112. | |
Lebensmitteldaten
| Variable | Standardwert | Was es tut | Mehr |
|---|
FOOD_SOURCE | fdc | Woher die Makronährstoffe stammen: fdc (der USDA-Auszug im Image, kein Netzwerk), off (Open Food Facts), lcc (LowCarbCheck) oder none. | Lebensmitteldaten |
FDC_DATASET_PATH | ./data/fdc-foods.json | Der USDA-Auszug, relativ zum Arbeitsverzeichnis. | |
OFF_API_URL | https://world.openfoodfacts.org | Die Adresse von Open Food Facts, gelesen mit FOOD_SOURCE=off. | |
LCC_API_URL | https://lowcarbcheck.org | Die Adresse von LowCarbCheck, gelesen mit FOOD_SOURCE=lcc. | |
LCC_API_KEY | nicht gesetzt, die anonyme Stufe | Dein LowCarbCheck-Schlüssel, gelesen mit FOOD_SOURCE=lcc. | |
EMBEDDING_RUNTIME_URL | nicht gesetzt | Eine OpenAI-kompatible Runtime, die /v1/embeddings bereitstellt, für einen besseren Lebensmittelabgleich. | |
EMBEDDING_RUNTIME_API_KEY | nicht gesetzt | Der Schlüssel für diese Runtime. | |
Einstellungen, die den Start stoppen
Ein Container, der nicht startet, fällt schnell auf und kostet nur einen Neustart. Eine Einstellung, die stillschweigend ignoriert wird, täuscht vor, dass etwas funktioniert, obwohl das nicht stimmt. Jede der folgenden Regeln bricht den Start daher ab, und das Log nennt die Variable.
Nicht mehr zulässige Namen
Diese Namen waren früher Einstellungen. Jetzt verweigert der Dienst den Start, solange einer davon gesetzt ist, und nennt den stattdessen zu verwendenden Namen. Der Core-Server verweigert sie selbst mit leerem Wert, lösche die Zeile also. Die App verweigert GATEWAY_URL nur, wenn es einen Wert hat.
| Variable | Abgelehnt von | Stattdessen nutzen |
|---|
GATEWAY_URL | die App | INSTANCE_MODE=managed. Der Core-Server hat den KI-Proxy übernommen. |
SIGNUP_MODE | der Core-Server | Nichts. Konten basieren auf Einladungen, und OPEN_SIGNUP=true lässt Nutzer darum bitten. |
SIGNUPS_OPEN | der Core-Server | Nichts, aus demselben Grund. |
REQUIRE_EMAIL_VERIFICATION | der Core-Server | Nichts. Die Einladung dient als Adressprüfung. |
EMAIL_FROM | der Core-Server | MAIL_API_FROM oder SMTP_FROM. |
SMTP_SECURE | der Core-Server | Nichts. SMTP_PORT bestimmt die Verschlüsselung. |
PIGEON_API_KEY | der Core-Server | MAIL_API_KEY, oder SMTP_USER und SMTP_PASSWORD. |
PIGEON_BASE_URL | der Core-Server | MAIL_API_URL oder SMTP_HOST. |
Regeln zwischen Variablen
Die App.
MATOMO_URL und MATOMO_SITE_ID: Setze beide oder keine davon. MATOMO_EVENT_LEVEL erfordert beide.
NEWSLETTER_SUBSCRIBE_URL und NEWSLETTER_TURNSTILE_SITE_KEY: Setze beide oder keine davon.
INSTANCE_MODE=managed erfordert CORE_URL.
CORE_URL und das veraltete SYNC_SERVER_URL: Setze eines davon. Wenn beide auf unterschiedliche Adressen gesetzt sind, gewinnt für diese Version SYNC_SERVER_URL, und der Startvorgang protokolliert eine Warnung.
APP_URL ist erforderlich, wenn NODE_ENV=production.
MOVED_TO_URL muss eine https://-Adresse auf einem anderen Host als APP_URL sein, ohne Benutzername oder Passwort.
Ein Wert außerhalb seiner Liste stoppt den Startvorgang: DEFAULT_UI_LANGUAGE, NUTRIENT_REFERENCE_BASIS, INSTANCE_MODE, MATOMO_EVENT_LEVEL und FOOD_DB_BACKFILL. Ebenso ein FOOD_DB_DAILY_CALL_LIMIT, das keine positive ganze Zahl ist. Fehlerhafte Adressen in CORE_URL, DEFAULT_INFERENCE_BASE_URL, MATOMO_URL oder NEWSLETTER_SUBSCRIBE_URL stoppen den Startvorgang ebenfalls. Der Startvorgang stoppt auch, wenn MATOMO_SITE_ID keine positive ganze Zahl ist oder wenn CONTENT_DIR kein Verzeichnis ist.
Der Core-Server.
DATABASE_URL und SERVER_SECRET sind erforderlich.
Mindestlängen: 32 Zeichen für SERVER_SECRET und TRIAL_ADDRESS_PEPPER, 24 Zeichen für ADMIN_TOKEN und BILLING_TOKEN.
E-Mail nutzt genau einen Transportweg. Die HTTP-Mail-API erfordert MAIL_API_URL, MAIL_API_KEY, MAIL_API_FROM und MAIL_OPERATOR_EMAIL, alle vier. SMTP erfordert SMTP_HOST, SMTP_FROM und MAIL_OPERATOR_EMAIL, wobei SMTP_USER und SMTP_PASSWORD zusammengehören. Variablen beider Transportwege gleichzeitig brechen den Start ab, ebenso wie MAIL_OPERATOR_EMAIL ohne Transportweg.
E-Mail erfordert SERVER_PUBLIC_URL und CLIENT_BASE_URL. Mit NODE_ENV=production müssen beide https://-Adressen auf einem anderen Host sein, nicht localhost.
Setze beide oder keine davon: UPSTREAM_BASE_URL und UPSTREAM_API_KEY; PLANS_UPSTREAM_URL und PLANS_UPSTREAM_SECRET; TURNSTILE_SECRET_KEY und TURNSTILE_SITE_KEY; MEMBER_INVITE_DAILY_AI_LIMIT und MEMBER_INVITE_ALLOWANCE_DAYS; TRIAL_SCANS und TRIAL_DAILY_AI_LIMIT.
Setze alle drei oder keine davon: VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY und VAPID_SUBJECT.
X erfordert Y: OPEN_SIGNUP=true erfordert Mail. Das Turnstile-Paar erfordert OPEN_SIGNUP=true. MEMBER_INVITE_LIFETIME_CAP erfordert das Mitglieder-Einladungs-Paar oder MEMBER_INVITE_TRIAL=true. MEMBER_INVITE_TRIAL=true erfordert das Test-Paar und lehnt das Mitglieder-Einladungs-Paar ab. Das Test-Paar erfordert TRIAL_ADDRESS_PEPPER. TRIAL_DAYS und AI_TRIAL_INSTANCE_DAILY_LIMIT erfordern das Test-Paar. AI_TRIAL_NETWORK_DAILY_LIMIT erfordert AI_TRIAL_INSTANCE_DAILY_LIMIT. TRIAL_TIME_ZONE erfordert TRIAL_DAYS. SYNC_NOTICE_URL erfordert SYNC_NOTICE.
Null wird abgelehnt, wo es als „aus“ gelesen würde und das Gegenteil bedeuten würde: AI_INSTANCE_DAILY_LIMIT, AI_TRIAL_INSTANCE_DAILY_LIMIT, AI_TRIAL_NETWORK_DAILY_LIMIT, TRIAL_SCANS, TRIAL_DAILY_AI_LIMIT, TRIAL_DAYS, MEMBER_INVITE_DAILY_AI_LIMIT und MEMBER_INVITE_ALLOWANCE_DAYS. Jede andere Zahl muss ebenfalls positiv sein, außer zwei Werten, die 0 akzeptieren: TRUST_PROXY und MEMBER_INVITE_LIFETIME_CAP, wo 0 Mitgliedern nichts zum Senden übrig lässt.
Obergrenzen: TRIAL_SCANS 100, TRIAL_DAYS 90, TRIAL_DAILY_AI_LIMIT und MEMBER_INVITE_DAILY_AI_LIMIT 10000, SYNC_NOTICE 280 Zeichen, INSTANCE_NAME 64 Zeichen.
SYNC_SHARING, SYNC_RESEARCH, SYNC_FEEDBACK, DATABASE_SSL und MEMBER_INVITE_TRIAL akzeptieren true, false, 1 oder 0. OPEN_SIGNUP akzeptiert nur true.
Ein Wert außerhalb der jeweiligen Liste bricht den Start ab: INSTANCE_LANGUAGE, NUTRIENT_REFERENCE_BASIS, LOG_LEVEL, TRIAL_TIME_ZONE und HEALTH_CONSENT_VERSION. Ein Wert für VAPID_SUBJECT, der nicht mailto: oder https: ist, bricht den Start ab. Ebenso ein Wert für SMTP_HOST mit Schema, Port oder Pfad. Ungültige Adressen in SERVER_PUBLIC_URL, CLIENT_BASE_URL, UPSTREAM_BASE_URL, PLANS_UPSTREAM_URL oder SYNC_NOTICE_URL brechen den Start ebenfalls ab.
Der Inferenz-Dienst.
MODEL_PROFILE=external erfordert MODEL_RUNTIME_URL. Bei jedem anderen Profil bricht ein Wert für MODEL_RUNTIME_URL, der von der mitgelieferten Adresse abweicht, den Container ab.
Ein Wert für MODEL_PROFILE, FOOD_SOURCE, PROFILE oder LOG_LEVEL außerhalb der jeweiligen Liste bricht den Start ab. Ein Wert für MODEL_RUNTIME_URL oder EMBEDDING_RUNTIME_URL, der keine http://- oder https://-Adresse ist, bricht den Start ebenfalls ab.
Anzahlen und Größen müssen positive ganze Zahlen sein. LATENCY_CEILING_MS und RUNTIME_COMPLETION_TIMEOUT_MS akzeptieren auch 0. IMAGE_MAX_LONG_EDGE muss mindestens 112 sein und PORT höchstens 65535.
Registrierung mit Turnstile
Standardmäßig entsteht ein Konto nur durch eine Einladung. Setze OPEN_SIGNUP=true auf dem Core-Server, und jede Person kann mit ihrer eigenen Adresse ein Konto anfordern. Der Dienst sendet dann eine Einladung per Mail an diese Adresse, und die Nachricht belegt, dass die Adresse funktioniert. Eine offene Registrierung erfordert also Mail, und der Dienst startet ohne Mail nicht. Die App zeigt das Registrierungsformular nur an, wenn der Core-Server meldet, dass seine Tür offen ist.
Ein Captcha hindert Skripte daran, den Dienst mit Anfragen zu überfluten. Der Core-Server prüft ein Cloudflare-Turnstile-Captcha, wenn du zwei Schlüssel konfigurierst:
- 01
Melde dich im Cloudflare-Dashboard an, öffne Turnstile und wähle Widget hinzufügen. Ein kostenloses Konto reicht aus. Deine Domain muss Cloudflare nicht nutzen.
- 02
Gib dem Widget einen Namen, trage den Hostnamen deiner App ein, etwa openplate.example.com, und belasse den Modus auf Verwaltet. Wähle Erstellen.
- 03
Trage den Site-Key in TURNSTILE_SITE_KEY und den Secret-Key in TURNSTILE_SECRET_KEY auf dem Core-Server ein. Setze entweder beide Schlüssel oder keinen von beiden.
- 04
Erstelle den Core-Server neu, zum Beispiel mit docker compose -f <your file> up -d.
/health veröffentlicht daraufhin den Site-Key. Die Registrierungsseite der App zeigt das Captcha an. Ihre Schaltfläche zum Absenden bleibt inaktiv, bis der Nutzer es löst. Der Secret-Key verlässt den Core-Server nie. Der Dienst übermittelt die Captcha-Antwort und den Secret-Key an Cloudflare, nicht die Adresse des Besuchers.
Der Dienst prüft nur die Registrierungsanfrage, POST /v1/auth/signup-request. Die Anmeldung, das Öffnen einer Einladung und alle anderen Routen nutzen kein Captcha. Kann der Dienst Cloudflare nicht erreichen, gibt er 503 zurück, und die Person kann es später erneut versuchen. Die Prüfung schlägt restriktiv fehl, sodass eine unbeantwortete Anfrage niemals durchgeht.
Die Content-Security-Policy der App erlaubt das Captcha von Cloudflare nur auf einer verwalteten Instanz (INSTANCE_MODE=managed) oder wenn das Newsletter-Formular aktiviert ist. Auf anderen Instanzen blockiert der Browser das Captcha, und niemand kann das Formular absenden. Setze die App auf verwaltet, bevor du das Captcha aktivierst.
Ohne die beiden Schlüssel funktioniert die offene Registrierung weiterhin. Ihre übrigen Limits gelten nach wie vor. Der Dienst erlaubt fünf Anfragen pro Stunde von einer Adresse und eine Nachricht pro Tag für ein Postfach. Er blockiert Adressen bekannter Wegwerf-E-Mail-Dienste. Beim Start protokolliert der Dienst eine Warnung.
NEWSLETTER_TURNSTILE_SITE_KEY ist eine separate Einstellung. Sie gehört zur App und schützt das Newsletter-Formular auf der Landingpage. Ihr Secret-Key verbleibt bei dem Dienst, der dieses Formular empfängt, nicht bei openplate. Newsletter-Anmeldung erklärt die Details.
Ein Image selbst erstellen
Die Dockerfiles akzeptieren mehrere Build-Argumente. Sie sind keine Einstellungen für einen laufenden Container. OPENPLATE_BUILD_SHA stempelt den Commit in das Bundle der App ein. Das Inferenz-Image übernimmt BASE_IMAGE, das llama.cpp-Server-Image als Build-Grundlage. Es übernimmt außerdem NODE_IMAGE, das Node.js-Image für den Build. VITE_ALLOWED_HOSTS gilt nur für den Entwicklungsserver der App und hat standardmäßig keine Hosts.