Zum Inhalt springen
Kostenlos in Cloud starten

HitKeep mit Docker Compose selbst hosten

Docker Compose bietet dir eine reproduzierbare, versionierbare Bereitstellung mit persistenten Speicher-Volumes. Deine Analysedaten verbleiben in einem benannten Docker-Volume auf deinem Server, einschließlich der gemeinsamen hitkeep.db und aller mandantenlokalen Datenbanken unter tenants/*/hitkeep.db.

Diese Seite beschreibt HitKeep als selbst gehosteten Dienst. Für die Hot-Reload-Entwicklungsumgebung mit Go, Air, Angular, Mailpit und vorbereiteten Demo-Daten in Docker nutze die Anleitung zum Mitwirken.

HitKeep-Images werden mit jedem Release in zwei Registries veröffentlicht:

RegistryImage
Docker Hubpascalebeier/hitkeep
GitHub Container Registryghcr.io/pascalebeier/hitkeep

Beide Registries enthalten identische plattformübergreifende Images (linux/amd64, linux/arm64) mit signierten Provenienz-Attestierungen. Wähle die Registry passend zu deinen Netzwerk- oder Pull-Rate-Anforderungen.

Eine Bereitstellung besteht aus zwei Dateien in einem Verzeichnis: compose.yml (unverändert kopieren) und .env (hier stehen deine Werte). Compose ersetzt beim Start jedes ${VARIABLE} in compose.yml durch die entsprechende Zeile aus .env.

Erstelle ein Verzeichnis und füge diese compose.yml hinzu. Diese Basiskonfiguration speichert Live-Daten, Aufbewahrungsarchive und automatische Backup-Snapshots in getrennten benannten Volumes. Dieselbe Datei wird im Repository als examples/compose.yml gepflegt, zusammen mit examples/.env.example, falls du lieber die Quelldateien kopierst.

services:
hitkeep:
image: pascalebeier/hitkeep:latest
container_name: hitkeep
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- hitkeep_data:/var/lib/hitkeep/data
- hitkeep_archive:/var/lib/hitkeep/archive
- hitkeep_backups:/var/lib/hitkeep/backups
environment:
# Public URL must match the browser-visible origin, including any path prefix.
HITKEEP_PUBLIC_URL: ${HITKEEP_PUBLIC_URL:-http://localhost:8080}
# Required for stable sessions. Generate with: openssl rand -hex 32
HITKEEP_JWT_SECRET: ${HITKEEP_JWT_SECRET:?set HITKEEP_JWT_SECRET in .env}
# Behind a reverse proxy, set to the proxy network CIDR so real client IPs are used.
HITKEEP_TRUSTED_PROXIES: ${HITKEEP_TRUSTED_PROXIES:-} # config-default-override: require an explicit trusted proxy network
# Keep live data, retention archives, and backup snapshots on persistent volumes.
HITKEEP_DB_PATH: /var/lib/hitkeep/data/hitkeep.db
HITKEEP_DATA_PATH: /var/lib/hitkeep/data
HITKEEP_ARCHIVE_PATH: /var/lib/hitkeep/archive
HITKEEP_BACKUP_PATH: /var/lib/hitkeep/backups
HITKEEP_BACKUP_INTERVAL: ${HITKEEP_BACKUP_INTERVAL:-60}
HITKEEP_BACKUP_RETENTION: ${HITKEEP_BACKUP_RETENTION:-24}
# Optional OSS spam-list refresh. Disable for fully offline/air-gapped installs.
HITKEEP_SPAM_FILTER_AUTO_UPDATE: "true"
HITKEEP_SPAM_FILTER_UPDATE_INTERVAL: ${HITKEEP_SPAM_FILTER_UPDATE_INTERVAL:-1440}
HITKEEP_SPAM_FILTER_PATH: /var/lib/hitkeep/data/spam-filter.json
# Optional read-only MCP endpoint for governed assistant/reporting access.
HITKEEP_MCP_ENABLED: "true"
HITKEEP_MCP_PATH: /mcp
HITKEEP_MCP_MAX_RANGE_DAYS: ${HITKEEP_MCP_MAX_RANGE_DAYS:-366}
# Optional AI model route for Opportunity enrichment. Provider credentials
# use the selected goAI provider's own env vars, such as OPENAI_API_KEY.
HITKEEP_AI_ENABLED: ${HITKEEP_AI_ENABLED:-false}
HITKEEP_AI_PROVIDER: ${HITKEEP_AI_PROVIDER:-}
HITKEEP_AI_MODEL: ${HITKEEP_AI_MODEL:-}
HITKEEP_AI_BASE_URL: ${HITKEEP_AI_BASE_URL:-}
HITKEEP_AI_REGION: ${HITKEEP_AI_REGION:-}
HITKEEP_AI_API_KEY: ${HITKEEP_AI_API_KEY:-}
HITKEEP_AI_REQUEST_LIMIT: ${HITKEEP_AI_REQUEST_LIMIT:-100}
HITKEEP_AI_TOKEN_LIMIT: ${HITKEEP_AI_TOKEN_LIMIT:-100000}
HITKEEP_AI_BUDGET_WINDOW: ${HITKEEP_AI_BUDGET_WINDOW:-1440}
# Optional Google Search Console OAuth integration.
HITKEEP_GOOGLE_SEARCH_CONSOLE_CLIENT_ID: ${HITKEEP_GOOGLE_SEARCH_CONSOLE_CLIENT_ID:-}
HITKEEP_GOOGLE_SEARCH_CONSOLE_CLIENT_SECRET: ${HITKEEP_GOOGLE_SEARCH_CONSOLE_CLIENT_SECRET:-}
HITKEEP_GOOGLE_SEARCH_CONSOLE_REDIRECT_URL: ${HITKEEP_GOOGLE_SEARCH_CONSOLE_REDIRECT_URL:-}
# Optional Google, GitHub, and Microsoft social sign-in.
HITKEEP_SOCIAL_GOOGLE_CLIENT_ID: ${HITKEEP_SOCIAL_GOOGLE_CLIENT_ID:-}
HITKEEP_SOCIAL_GOOGLE_CLIENT_SECRET: ${HITKEEP_SOCIAL_GOOGLE_CLIENT_SECRET:-}
HITKEEP_SOCIAL_GITHUB_CLIENT_ID: ${HITKEEP_SOCIAL_GITHUB_CLIENT_ID:-}
HITKEEP_SOCIAL_GITHUB_CLIENT_SECRET: ${HITKEEP_SOCIAL_GITHUB_CLIENT_SECRET:-}
HITKEEP_SOCIAL_MICROSOFT_CLIENT_ID: ${HITKEEP_SOCIAL_MICROSOFT_CLIENT_ID:-}
HITKEEP_SOCIAL_MICROSOFT_CLIENT_SECRET: ${HITKEEP_SOCIAL_MICROSOFT_CLIENT_SECRET:-}
HITKEEP_SOCIAL_MICROSOFT_TENANT: ${HITKEEP_SOCIAL_MICROSOFT_TENANT:-common}
# SMTP powers invites, password reset, email reports, and security mail.
HITKEEP_MAIL_HOST: ${HITKEEP_MAIL_HOST:-}
HITKEEP_MAIL_PORT: ${HITKEEP_MAIL_PORT:-587}
HITKEEP_MAIL_USERNAME: ${HITKEEP_MAIL_USERNAME:-}
HITKEEP_MAIL_PASSWORD: ${HITKEEP_MAIL_PASSWORD:-}
HITKEEP_MAIL_ENCRYPTION: ${HITKEEP_MAIL_ENCRYPTION:-tls}
HITKEEP_MAIL_FROM_ADDRESS: ${HITKEEP_MAIL_FROM_ADDRESS:-hitkeep@localhost}
HITKEEP_MAIL_FROM_NAME: ${HITKEEP_MAIL_FROM_NAME:-HitKeep}
volumes:
hitkeep_data: {}
hitkeep_archive: {}
hitkeep_backups: {}

Erzeuge zuerst den Signaturschlüssel für Sitzungen. Führe diesen Befehl in deinem Terminal aus und kopiere die Ausgabe:

Terminal-Fenster
openssl rand -hex 32

Falls openssl nicht installiert ist, erzeugt head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n'; echo auf jedem Linux-System einen gleichwertigen Wert.

Erstelle anschließend neben compose.yml mit deinem Editor eine Datei namens .env und trage deine Werte ein:

# Required. Paste the generated 64-character hex string here.
HITKEEP_JWT_SECRET=paste-the-generated-value-here
# Required. The exact URL you open in the browser. Behind a reverse proxy
# this is your public domain, e.g. https://analytics.example.com
HITKEEP_PUBLIC_URL=http://localhost:8080
# Optional social sign-in. Set both values for each provider you enable.
HITKEEP_SOCIAL_GOOGLE_CLIENT_ID=
HITKEEP_SOCIAL_GOOGLE_CLIENT_SECRET=
HITKEEP_SOCIAL_GITHUB_CLIENT_ID=
HITKEEP_SOCIAL_GITHUB_CLIENT_SECRET=
HITKEEP_SOCIAL_MICROSOFT_CLIENT_ID=
HITKEEP_SOCIAL_MICROSOFT_CLIENT_SECRET=
HITKEEP_SOCIAL_MICROSOFT_TENANT=common
# Optional SMTP. Powers invites, password resets, and email reports.
# Leave the values empty to run without outbound mail.
HITKEEP_MAIL_HOST=
HITKEEP_MAIL_PORT=587
HITKEEP_MAIL_USERNAME=
HITKEEP_MAIL_PASSWORD=
HITKEEP_MAIL_FROM_ADDRESS=hitkeep@localhost
HITKEEP_MAIL_FROM_NAME=HitKeep
Terminal-Fenster
docker compose up -d
docker compose logs -f hitkeep

Die Logzeilen Starting HitKeep und HTTP server starting zeigen, dass der Dienst läuft.

Öffne HITKEEP_PUBLIC_URL im Browser. Der Einrichtungsassistent erstellt das erste Konto, macht es automatisch zum Instanzbesitzer und führt dich durch das Hinzufügen deiner ersten Website.

Die Datenbankdatei liegt im Volume hitkeep_data. Damit bleibt auch das Standardverzeichnis für automatische Wiederherstellung, /var/lib/hitkeep/data/recovery, persistent. Aufbewahrungsarchive liegen in hitkeep_archive, automatische Datenbank-Snapshots in hitkeep_backups. Wiederherstellungspakete enthalten Datenbankmaterial, werden nicht über die Backup-Aufbewahrung rotiert und müssen separat geschützt und gelöscht werden. MCP ist unter /mcp erreichbar, Clients benötigen dennoch bereichsgebundene API-Client-Bearer-Token.

MCP ist im Produkt optional und in diesem Compose-Beispiel für Teams aktiviert, die schreibgeschützten Assistenten- oder Reporting-Zugriff wünschen. Entferne HITKEEP_MCP_ENABLED, HITKEEP_MCP_PATH und HITKEEP_MCP_MAX_RANGE_DAYS, wenn du keinen MCP-Endpunkt veröffentlichen möchtest.

KI-Provider-Anreicherung ist optional und standardmäßig deaktiviert. Belasse HITKEEP_AI_ENABLED=false, bis du Provider und Modell gewählt, Zugangsdaten konfiguriert und lokale Budgetgrenzen gesetzt hast. Die genauen Felder stehen unter Opportunity-Empfehlungen und in der Anleitung zur KI-Modellkonfiguration.

Social Sign-in ist optional. Setze Client-ID und Client-Secret für jeden gewünschten Provider und registriere anschließend die exakte Callback-URL, die sich aus HITKEEP_PUBLIC_URL ergibt. Die Anleitung zu Social Sign-in behandelt Provider-Registrierung, Callback-Pfade, E-Mail-Verifizierung, Einladungen, MFA und Kontoverknüpfung. HITKEEP_SOCIAL_SIGNUP_ENABLED öffnet keine öffentliche Registrierung auf einer selbst gehosteten Instanz.

Daten für Stadt-, Provider- und ASN-Erkennung sind in Release-Images eingebettet. Laufende Compose-Bereitstellungen benötigen kein IP2LOCATION_DOWNLOAD_TOKEN.

Prüfe, ob Compose einen laufenden Dienst sieht und beide Laufzeitprüfungen erfolgreich sind:

Terminal-Fenster
docker compose ps
curl --fail http://localhost:8080/healthz
curl --fail http://localhost:8080/readyz
docker compose logs --since=5m hitkeep

/healthz bestätigt, dass der Prozess läuft. /readyz bestätigt, dass die gemeinsame Datenbank und jede geöffnete Mandantendatenbank bereit sind. Falls HitKeep nur über deinen Reverse Proxy erreichbar ist, prüfe stattdessen dessen im Browser sichtbare URL.

Lies die aktuellen Release Notes und stelle sicher, dass ein aktuelles Backup vorhanden ist. Lade anschließend das aktuelle stabile Image und erstelle ausschließlich den HitKeep-Dienst neu:

Terminal-Fenster
docker compose pull hitkeep
docker compose up -d hitkeep
docker compose ps
curl --fail http://localhost:8080/readyz

Compose behält die benannten Daten-, Archiv- und Backup-Volumes, wenn der Container ersetzt wird. Führe während eines Upgrades niemals docker compose down -v aus; -v löscht diese Volumes.

Betreibe HitKeep für produktives HTTPS hinter einem Reverse Proxy. Konfiguriere vertrauenswürdige Proxys, damit echte Client-IPs für Webanalyse und Ratenbegrenzung genutzt werden.

HITKEEP_PUBLIC_URL darf ein Pfadpräfix enthalten. Setze beispielsweise HITKEEP_PUBLIC_URL=https://www.example.net/hitkeep/, wenn HitKeep unterhalb einer bestehenden Website eingebunden wird. Der Proxy muss dasselbe Präfix wie /hitkeep/* veröffentlichen und an den HitKeep-Container weiterleiten. HitKeep stellt dann Dashboard-Basis-Href, API-Anfragen, hk.js, hk-vitals.js und Ingest-Endpunkte unter diesem Präfix bereit.

caddy-docker-proxy übernimmt automatisches HTTPS mit Let’s Encrypt und erzeugt die Caddy-Konfiguration direkt aus Docker-Labels. Als bewährte Praxis solltest du ein eigenes Ingress-Netzwerk verwenden und in HitKeep ausschließlich dessen CIDR vertrauen.

services:
caddy:
image: lucaslorentz/caddy-docker-proxy:2.9-alpine
container_name: caddy-proxy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
environment:
CADDY_INGRESS_NETWORKS: caddy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- caddy_data:/data
- caddy_config:/config
networks:
- caddy
labels:
caddy.email: ${CADDY_EMAIL:?set in .env}
hitkeep:
image: pascalebeier/hitkeep:latest
container_name: hitkeep
restart: unless-stopped
networks:
- caddy
volumes:
- hitkeep_data:/var/lib/hitkeep/data
- hitkeep_archive:/var/lib/hitkeep/archive
- hitkeep_backups:/var/lib/hitkeep/backups
environment:
HITKEEP_NODE_NAME: leader
# Public URL must match the HTTPS origin served by Caddy, including any path prefix.
HITKEEP_PUBLIC_URL: ${HITKEEP_PUBLIC_URL:?set in .env}
# Required for stable sessions. Generate with: openssl rand -hex 32
HITKEEP_JWT_SECRET: ${HITKEEP_JWT_SECRET:?set in .env}
# Must be the Caddy network CIDR. This controls real visitor IP, geo/network metadata,
# country exclusions, rate limiting, and spam checks.
HITKEEP_TRUSTED_PROXIES: ${HITKEEP_TRUSTED_PROXIES:?set to your caddy network CIDR}
# Keep live data, retention archives, and backup snapshots on persistent volumes.
HITKEEP_DB_PATH: /var/lib/hitkeep/data/hitkeep.db
HITKEEP_DATA_PATH: /var/lib/hitkeep/data
HITKEEP_ARCHIVE_PATH: /var/lib/hitkeep/archive
HITKEEP_BACKUP_PATH: /var/lib/hitkeep/backups
HITKEEP_BACKUP_INTERVAL: ${HITKEEP_BACKUP_INTERVAL:-60}
HITKEEP_BACKUP_RETENTION: ${HITKEEP_BACKUP_RETENTION:-24}
# Optional OSS spam-list refresh. Disable for fully offline/air-gapped installs.
HITKEEP_SPAM_FILTER_AUTO_UPDATE: "true"
HITKEEP_SPAM_FILTER_UPDATE_INTERVAL: ${HITKEEP_SPAM_FILTER_UPDATE_INTERVAL:-1440}
HITKEEP_SPAM_FILTER_PATH: /var/lib/hitkeep/data/spam-filter.json
# Optional read-only MCP endpoint for governed assistant/reporting access.
HITKEEP_MCP_ENABLED: "true"
HITKEEP_MCP_PATH: /mcp
HITKEEP_MCP_MAX_RANGE_DAYS: ${HITKEEP_MCP_MAX_RANGE_DAYS:-366}
# Optional AI model route for Opportunity enrichment. Leave disabled until a provider is configured.
HITKEEP_AI_ENABLED: ${HITKEEP_AI_ENABLED:-false}
HITKEEP_AI_PROVIDER: ${HITKEEP_AI_PROVIDER:-}
HITKEEP_AI_MODEL: ${HITKEEP_AI_MODEL:-}
HITKEEP_AI_BASE_URL: ${HITKEEP_AI_BASE_URL:-}
HITKEEP_AI_REGION: ${HITKEEP_AI_REGION:-}
HITKEEP_AI_API_KEY: ${HITKEEP_AI_API_KEY:-}
HITKEEP_AI_REQUEST_LIMIT: ${HITKEEP_AI_REQUEST_LIMIT:-100}
HITKEEP_AI_TOKEN_LIMIT: ${HITKEEP_AI_TOKEN_LIMIT:-100000}
HITKEEP_AI_BUDGET_WINDOW: ${HITKEEP_AI_BUDGET_WINDOW:-1440}
# Optional Google Search Console OAuth integration.
HITKEEP_GOOGLE_SEARCH_CONSOLE_CLIENT_ID: ${HITKEEP_GOOGLE_SEARCH_CONSOLE_CLIENT_ID:-}
HITKEEP_GOOGLE_SEARCH_CONSOLE_CLIENT_SECRET: ${HITKEEP_GOOGLE_SEARCH_CONSOLE_CLIENT_SECRET:-}
HITKEEP_GOOGLE_SEARCH_CONSOLE_REDIRECT_URL: ${HITKEEP_GOOGLE_SEARCH_CONSOLE_REDIRECT_URL:-}
# Optional Google, GitHub, and Microsoft social sign-in.
HITKEEP_SOCIAL_GOOGLE_CLIENT_ID: ${HITKEEP_SOCIAL_GOOGLE_CLIENT_ID:-}
HITKEEP_SOCIAL_GOOGLE_CLIENT_SECRET: ${HITKEEP_SOCIAL_GOOGLE_CLIENT_SECRET:-}
HITKEEP_SOCIAL_GITHUB_CLIENT_ID: ${HITKEEP_SOCIAL_GITHUB_CLIENT_ID:-}
HITKEEP_SOCIAL_GITHUB_CLIENT_SECRET: ${HITKEEP_SOCIAL_GITHUB_CLIENT_SECRET:-}
HITKEEP_SOCIAL_MICROSOFT_CLIENT_ID: ${HITKEEP_SOCIAL_MICROSOFT_CLIENT_ID:-}
HITKEEP_SOCIAL_MICROSOFT_CLIENT_SECRET: ${HITKEEP_SOCIAL_MICROSOFT_CLIENT_SECRET:-}
HITKEEP_SOCIAL_MICROSOFT_TENANT: ${HITKEEP_SOCIAL_MICROSOFT_TENANT:-common}
# SMTP powers invites, password reset, email reports, and security mail.
HITKEEP_MAIL_HOST: ${HITKEEP_MAIL_HOST:-}
HITKEEP_MAIL_PORT: ${HITKEEP_MAIL_PORT:-587}
HITKEEP_MAIL_USERNAME: ${HITKEEP_MAIL_USERNAME:-}
HITKEEP_MAIL_PASSWORD: ${HITKEEP_MAIL_PASSWORD:-}
HITKEEP_MAIL_ENCRYPTION: ${HITKEEP_MAIL_ENCRYPTION:-tls}
HITKEEP_MAIL_FROM_ADDRESS: ${HITKEEP_MAIL_FROM_ADDRESS:-hitkeep@localhost}
HITKEEP_MAIL_FROM_NAME: ${HITKEEP_MAIL_FROM_NAME:-HitKeep}
labels:
caddy: ${HITKEEP_HOSTNAME:?set in .env}
caddy.reverse_proxy: "{{upstreams 8080}}"
caddy.encode: "zstd gzip"
volumes:
caddy_data: {}
caddy_config: {}
hitkeep_data: {}
hitkeep_archive: {}
hitkeep_backups: {}
networks:
caddy:
external: true

Zwei Werte kommen aus deinem Terminal: das Sitzungsgeheimnis und die CIDR des Caddy-Netzwerks:

Terminal-Fenster
openssl rand -hex 32
docker network inspect caddy --format '{{(index .IPAM.Config 0).Subnet}}'

Erstelle anschließend die .env-Datei mit deinem Editor:

# Required. Paste the generated 64-character hex string here.
HITKEEP_JWT_SECRET=paste-the-generated-value-here
HITKEEP_PUBLIC_URL=https://analytics.example.com
HITKEEP_HOSTNAME=analytics.example.com
CADDY_EMAIL=ops@example.com
# Paste the Caddy network subnet from the docker network inspect command.
HITKEEP_TRUSTED_PROXIES=paste-the-caddy-subnet-here
# Optional social sign-in. Set both values for each provider you enable.
HITKEEP_SOCIAL_GOOGLE_CLIENT_ID=
HITKEEP_SOCIAL_GOOGLE_CLIENT_SECRET=
HITKEEP_SOCIAL_GITHUB_CLIENT_ID=
HITKEEP_SOCIAL_GITHUB_CLIENT_SECRET=
HITKEEP_SOCIAL_MICROSOFT_CLIENT_ID=
HITKEEP_SOCIAL_MICROSOFT_CLIENT_SECRET=
HITKEEP_SOCIAL_MICROSOFT_TENANT=common
HITKEEP_MAIL_HOST=smtp.example.com
HITKEEP_MAIL_PORT=587
HITKEEP_MAIL_USERNAME=postmaster@example.com
HITKEEP_MAIL_PASSWORD=change-me
HITKEEP_MAIL_FROM_ADDRESS=analytics@example.com
HITKEEP_MAIL_FROM_NAME=HitKeep

HITKEEP_TRUSTED_PROXIES muss der CIDR deines Reverse-Proxy-Netzwerks entsprechen, nicht 0.0.0.0/0.

Halte bei einer Einbindung unter einem Unterverzeichnis HITKEEP_PUBLIC_URL und das Routenpräfix des Reverse Proxys synchron. Die entsprechende Caddy-Route lautet:

Terminal-Fenster
HITKEEP_PUBLIC_URL=https://www.example.net/hitkeep/
HITKEEP_HOSTNAME=www.example.net
www.example.net {
handle /hitkeep* {
reverse_proxy hitkeep:8080
}
encode zstd gzip
}

Selbst gehostete Teams können eigene Tracking-Domains mit jedem Reverse Proxy nutzen, der TLS terminiert und den ursprünglichen Host-Header erhält. Nutze den externen TLS-Modus, wenn Zertifikate von nginx, Traefik, einem Load Balancer oder einem anderen ACME-Prozess verwaltet werden. Nutze das Caddy-Profil nur, wenn du über das Dashboard geführtes Domain-Onboarding mit On-Demand-Zertifikaten wünschst.

Ergänze diese HitKeep-Einstellung, wenn der Reverse Proxy bereits Zertifikate verwaltet:

HITKEEP_CUSTOM_TRACKING_TLS_MODE: external

Füge im externen Modus jeden Tracking-Hostnamen zum Proxy hinzu, bevor das Team in HitKeep auf Verify klickt. Die Verifizierungsprüfung verlangt, dass https://<hostname>/hk.js den Tracker mit einem gültigen Zertifikat ausliefert.

Das HitKeep-Repository enthält Beispiele ohne Caddy:

Das nginx-Beispiel beschränkt eigene Tracking-Hosts bereits am Proxy auf Tracker-Assets und Ingest-Routen. Das Traefik-Beispiel verwendet exakte Host(...)-Einträge für jeden Tracking-Hostnamen. Ersetze sie nur dann durch eine Catch-all-Regel, wenn der Proxy bewusst beliebige Hostnamen akzeptieren soll.

Ergänze diese HitKeep-Einstellungen im Dienst hitkeep:

HITKEEP_CUSTOM_TRACKING_TLS_MODE: caddy-on-demand
HITKEEP_CADDY_TLS_ASK_TOKEN: ${HITKEEP_CADDY_TLS_ASK_TOKEN:?set in .env}
# Optional. Use only when tracker hostnames point somewhere other than
# the host in HITKEEP_PUBLIC_URL.
HITKEEP_CUSTOM_TRACKING_DNS_TARGET: ${HITKEEP_CUSTOM_TRACKING_DNS_TARGET:-}

Erzeuge das Ask-Token im Terminal (openssl rand -hex 32) und füge es als neue Zeile in .env ein:

HITKEEP_CADDY_TLS_ASK_TOKEN=paste-the-generated-value-here

Nutze ein Caddyfile mit persistentem Speicher und einem eingeschränkten On-Demand-TLS-Ask-Endpunkt:

{
email ops@example.com
storage file_system {
root /data
}
on_demand_tls {
ask http://hitkeep:8080/internal/caddy/on-demand-tls/{$HITKEEP_CADDY_TLS_ASK_TOKEN}
}
}
{$HITKEEP_HOSTNAME} {
reverse_proxy hitkeep:8080
encode zstd gzip
}
https:// {
tls {
on_demand
}
reverse_proxy hitkeep:8080 {
header_up Host {host}
header_up X-Forwarded-Host {host}
header_up X-Forwarded-Proto {scheme}
}
encode zstd gzip
}

Caddy sendet ?domain= an die Ask-URL, bevor es ein Zertifikat ausstellt. HitKeep antwortet nur dann mit 204, wenn das Token stimmt und der angefragte Hostname eine aktivierte, per DNS verifizierte eigene Tracking-Domain ist. Betreibe Caddy On-Demand-TLS niemals ohne ask; andernfalls kann jeder Hostname, der den Caddy-Listener erreicht, eine Zertifikatsausstellung versuchen.

Das HitKeep-Repository enthält ein vollständiges optionales Profil:

Der Schnellstart aktiviert HitKeeps Worker für konsistente Checkpoint-Backups und speichert Snapshots im persistenten Volume hitkeep_backups. Teste eine Wiederherstellung, bevor du dich darauf verlässt, und kopiere Backups vom Docker-Host weg, damit ein Hostausfall nicht Live- und Wiederherstellungsdaten zugleich entfernt. Backups und Wiederherstellung beschreibt den vollständigen Datensatz und Ablauf.

Die Beispiele oben verwenden lokale Docker-Volumes. Um Backup-Snapshots oder Aufbewahrungsarchive in Objektspeicher zu schreiben, ersetze die lokalen Pfade durch s3://-URLs und ergänze die S3-Einstellungen in .env:

Terminal-Fenster
# Local or S3 backup snapshots. Empty HITKEEP_BACKUP_PATH disables automatic backups.
HITKEEP_BACKUP_PATH=s3://my-analytics-bucket/hitkeep/backups
# Retention archives can use local paths or S3-compatible URLs.
HITKEEP_ARCHIVE_PATH=s3://my-analytics-bucket/hitkeep/archive
HITKEEP_S3_REGION=eu-central-1
# Static credentials are optional when your container runtime provides an AWS credential chain.
HITKEEP_S3_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
HITKEEP_S3_SECRET_ACCESS_KEY=change-me

Setze für MinIO, Cloudflare R2, Backblaze B2 oder einen anderen S3-kompatiblen Endpunkt zusätzlich HITKEEP_S3_ENDPOINT und bei Bedarf HITKEEP_S3_URL_STYLE=path. Unter S3-Backups findest du providerspezifische Beispiele.

Das Dashboard zeigt während Einrichtung oder Anmeldung „An unexpected error occurred“ an. Prüfe nacheinander:

  1. Zuerst Container-Logs lesen: docker compose logs hitkeep. HitKeep protokolliert jeden serverseitigen Fehler auf Error-Level. Zeigt der Browser einen Fehler, während die Logs leer bleiben, hat die Anfrage den Container nie erreicht. Ursache ist dann der Reverse Proxy oder eine falsche HITKEEP_PUBLIC_URL, nicht HitKeep.
  2. HITKEEP_PUBLIC_URL muss exakt der Adressleiste entsprechen – Schema, Host und Port. Bei einer öffentlichen https://-URL erhalten Sitzungscookies das Secure-Attribut; eine Anmeldung über reines HTTP schlägt dann still fehl. Führe nach einer Änderung an .env erneut docker compose up -d aus, weil Compose Umgebungsänderungen erst beim Neuerstellen des Containers übernimmt.
  3. Setup has already been completed. bedeutet, dass bereits ein Benutzer in der Datenbank existiert – meist in einem hitkeep_data-Volume aus einem früheren Versuch. docker compose down -v entfernt die benannten Volumes und ermöglicht einen sauberen Neustart. Dabei werden alle Analysedaten gelöscht.
  4. E-Mail-Einstellungen sind bei der Einrichtung nicht die Ursache. Beim Erstellen des ersten Kontos wird keine E-Mail gesendet; leere HITKEEP_MAIL_*-Werte blockieren den Vorgang nie. SMTP wird erst für Einladungen, Passwortzurücksetzungen und E-Mail-Berichte benötigt.
  5. Mehr Details benötigt? Ergänze HITKEEP_LOG_LEVEL: debug unter environment: in compose.yml und führe erneut docker compose up -d aus.

Du möchtest verwaltetes Hosting mit ausdrücklicher Regionswahl? HitKeep Cloud vergleichen.