---
title: "HitKeep mit Docker Compose selbst hosten | HitKeep"
description: "Hoste HitKeep mit Docker Compose, persistentem Speicher, vorkonfiguriertem Netzwerk und Reverse-Proxy-Beispielen für Caddy, nginx und Traefik selbst."
canonical: "https://hitkeep.com/de/guides/installation/docker-compose/"
---

# 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](https://hitkeep.com/guides/contributing/).

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

| Registry | Image |
| --- | --- |
| Docker Hub | pascalebeier/hitkeep |
| GitHub Container Registry | ghcr.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.

Geheimnisse aus Compose-Dateien heraushalten

Übergib sensible Werte (`HITKEEP_JWT_SECRET`, SMTP-Passwörter) über Umgebungsvariablen, eine `.env`-Datei oder Docker Secrets – nicht fest codiert in `compose.yml` oder als Kommandozeilen-Flags. Nimm `.env` nicht in die Versionsverwaltung auf. Für strengere Geheimnisverwaltung verwende Docker Secrets.

## Schnellstart

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`.

### 1. compose.yml erstellen

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`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/compose.yml) gepflegt, zusammen mit [`examples/.env.example`](https://github.com/PascaleBeier/hitkeep/blob/main/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: {}
```

### 2. .env erstellen

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

```
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
```

.env ist kein Shell-Skript

`.env` enthält einfache `KEY=value`-Zeilen – kein `echo`, keine geschweiften Klammern und keine `$(command)`-Ersetzung. Docker Compose liest die Datei wörtlich; hineinkopierte Befehle würden daher als Text ankommen. Anführungszeichen um Werte sind unnötig. Halte die Datei aus der Versionsverwaltung heraus und ergänze sie in `.gitignore`.

Die beiden Dateien verwenden bewusst unterschiedliche Syntax: `compose.yml` ist YAML, deshalb stehen Umgebungswerte dort als `KEY: value`; `.env` nutzt das dotenv-Format `KEY=value`.

### 3. HitKeep starten

```
docker compose up -d
docker compose logs -f hitkeep
```

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

### 4. Anmelden

Ö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](https://hitkeep.com/guides/analytics/opportunities/) und in der [Anleitung zur KI-Modellkonfiguration](https://hitkeep.com/guides/admin/ai-model-configuration/).

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](https://hitkeep.com/guides/security/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`.

## Installation prüfen

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

```
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.

## Upgrade

Lies die [aktuellen Release Notes](https://github.com/PascaleBeier/hitkeep/releases/latest) und stelle sicher, dass ein aktuelles Backup vorhanden ist. Lade anschließend das aktuelle stabile Image und erstelle ausschließlich den HitKeep-Dienst neu:

```
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.

## Reverse-Proxy-Konfigurationen

Betreibe HitKeep für produktives HTTPS hinter einem Reverse Proxy. Konfiguriere [vertrauenswürdige Proxys](https://hitkeep.com/guides/installation/trusted-proxies/), 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
- nginx
- Traefik

`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:

```
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:

```
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
}
```

Bei einem bestehenden nginx auf dem Host, der seine Zertifikate etwa mit certbot selbst verwaltet, behältst du die `compose.yml` aus dem Schnellstart und leitest nginx an den veröffentlichten Port weiter.

Passe die Schnellstartdateien an zwei Stellen an:

1. Binde den Port in `compose.yml` an Loopback, damit nur der lokale nginx den Container erreichen kann:

```
    ports:
    - "127.0.0.1:8080:8080"
```

1. Setze in `.env` die öffentliche URL auf die von nginx bereitgestellte Domain und vertraue dem Docker-Netzwerk. Host-Datenverkehr erreicht den Container über das Docker-Netzwerk-Gateway im Bereich `172.16.0.0/12`:

```
HITKEEP_PUBLIC_URL=https://analytics.example.com
HITKEEP_TRUSTED_PROXIES=172.16.0.0/12
```

Füge nginx anschließend einen Server-Block hinzu:

```
server {
  listen 443 ssl;
  http2 on;
  server_name analytics.example.com;

  # ssl_certificate / ssl_certificate_key as issued by certbot or your CA.

  location / {
      proxy_pass http://127.0.0.1:8080;
      proxy_http_version 1.1;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-Host $host;
      # Live dashboard updates stream over server-sent events.
      proxy_set_header Connection "";
      proxy_buffering off;
      proxy_read_timeout 300s;
  }
}
```

Lade nginx neu (`nginx -t && systemctl reload nginx`) und öffne `https://analytics.example.com`. Wenn alle Besucher von derselben privaten IP zu kommen scheinen, prüfe erneut die [vertrauenswürdigen Proxys](https://hitkeep.com/guides/installation/trusted-proxies/).

Veröffentliche HitKeep in bestehenden Traefik-Stacks über Labels:

```
services:
hitkeep:
  image: pascalebeier/hitkeep:latest
  restart: unless-stopped
  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 HTTPS origin served by Traefik, 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 Traefik 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 traefik 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:
    - "traefik.enable=true"
    - "traefik.http.routers.hitkeep.rule=Host(`analytics.example.com`)"
    - "traefik.http.routers.hitkeep.entrypoints=websecure"
    - "traefik.http.routers.hitkeep.tls.certresolver=myresolver"
    - "traefik.http.services.hitkeep.loadbalancer.server.port=8080"

volumes:
hitkeep_data: {}
hitkeep_archive: {}
hitkeep_backups: {}
```

## Eigene Tracking-Domains

Selbst gehostete Teams können [eigene Tracking-Domains](https://hitkeep.com/guides/tracking/custom-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.

### Externes TLS mit nginx oder Traefik

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:

- [`examples/nginx.custom-tracking.conf`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/nginx.custom-tracking.conf)
- [`examples/compose.nginx-custom-tracking.yml`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/compose.nginx-custom-tracking.yml)
- [`examples/traefik.custom-tracking.yml`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/traefik.custom-tracking.yml)
- [`examples/compose.traefik-custom-tracking.yml`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/compose.traefik-custom-tracking.yml)

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.

### Caddy On-Demand-TLS

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:

- [`examples/Caddyfile.custom-tracking`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/Caddyfile.custom-tracking)
- [`examples/compose.caddy-on-demand.yml`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/compose.caddy-on-demand.yml)

## Backup

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](https://hitkeep.com/guides/data/backups-and-restore/) beschreibt den vollständigen Datensatz und Ablauf.

### S3-kompatible Backups oder Archive nutzen

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`:

```
# 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](https://hitkeep.com/guides/data/s3-backups/) findest du providerspezifische Beispiele.

## Fehlerbehebung

**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.

## Verwandte Themen

- [Vertrauenswürdige Proxys](https://hitkeep.com/guides/installation/trusted-proxies/)
- [Social Sign-in](https://hitkeep.com/guides/security/social-sign-in/)
- [Eigene Tracking-Domains](https://hitkeep.com/guides/tracking/custom-tracking-domains/)
- [Konfigurationsreferenz](https://hitkeep.com/reference/configuration/)
- [Datenaufbewahrung](https://hitkeep.com/guides/data/retention/)
- [S3-Backups](https://hitkeep.com/guides/data/s3-backups/)
- [Installation als Binärdatei](https://hitkeep.com/de/guides/installation/binary/)

Du möchtest verwaltetes Hosting mit ausdrücklicher Regionswahl? [HitKeep Cloud vergleichen](https://hitkeep.com/de/pricing/).

[Vorherige Seite Linux-Binärdatei](https://hitkeep.com/de/guides/installation/binary/)[Nächste Seite Kubernetes und Helm](https://hitkeep.com/de/guides/installation/kubernetes/)
