| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| .idea | ||
| .env | ||
| .gitignore | ||
| AGENTS.md | ||
| CICD-Actions.md | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| LICENSE | ||
| Projekt.md | ||
| README.md | ||
Google Tag Manager – Server-Side Tagging Stack
Dieser Stack betreibt Google Tag Manager (GTM) als selbst gehostete Server-Side-Tagging-Lösung. Er besteht aus zwei Containern: einem Tag-Server (produktiver Endpunkt) und einem Preview-Server (Debugging & Vorschau).
Voraussetzungen
- Docker & Docker Compose
- Laufender [Traefik] Reverse Proxy mit dem externen Netzwerk
traefik_proxy_network - Zwei DNS-Einträge auf den Server (je einen für Tag-Server und Preview-Server)
- Laufender [Autoheal] Stack auf dem Server
Verzeichnisstruktur
GTM/
├── docker-compose.yml ← Haupt-Stack (Tag-Server + Preview-Server)
├── .env ← Konfiguration (Template mit Platzhaltern)
├── README.md ← Diese Datei
Einrichtung
1. Google Tag Manager Container-Konfiguration holen
- Auf tagmanager.google.com einloggen
- Einen neuen Server-Container anlegen (Typ: Server)
- In den Container-Einstellungen den Wert unter „Container-Konfiguration" kopieren — dieser Base64-kodierte String ist der Wert für
CONTAINER_CONFIG
2. .env Datei anlegen
COMPOSE_PROJECT_NAME=mein-gtm-stack
# Base64-kodierter String aus den GTM Container-Einstellungen
CONTAINER_CONFIG=aWQ9R1RNLVhYWFhYWFhYJmVudj0xJmF1dGg9XXXXXXXXXX==
# Traefik Host-Regeln
HOSTRULEGTM=Host(`gtm.domain.de`)
HOSTRULEPREVIEW=Host(`gtm-preview.domain.de`)
# URL des Preview-Servers (ohne https://)
PREVIEW_SERVER_URL=gtm-preview.domain.de
# Name des externen Traefik-Netzwerks
PROXY_NETWORK=traefik_proxy_network
TIMEZONE=Europe/Berlin
3. GTM Container-URLs eintragen
Nach dem ersten Start müssen die URLs in GTM hinterlegt werden:
- In GTM die Container-Einstellungen öffnen
- Unter „Server-Container-URLs" beide Domains eintragen:
- Tag-Server:
https://gtm.domain.de - Preview-Server:
https://gtm-preview.domain.de
- Tag-Server:
- Speichern
4. Stack starten
docker compose up -d
Healthcheck
Beide Container prüfen regelmäßig den Endpoint /healthy auf Port 8080:
| Container | Healthcheck-URL (intern) | Öffentliche URL |
|---|---|---|
| Tag-Server | http://localhost:8080/healthy |
https://gtm.domain.de/healthy |
| Preview-Server | http://localhost:8080/healthy |
https://gtm-preview.domain.de/healthy |
Gibt der Endpoint HTTP 200 zurück, ist der Container healthy. Bei einem Fehler wird der Container nach 3 fehlgeschlagenen Versuchen als unhealthy markiert und von Autoheal neugestartet.
Healthcheck-Parameter:
| Parameter | Wert | Bedeutung |
|---|---|---|
interval |
30s | Prüfintervall |
timeout |
10s | Maximale Antwortzeit pro Prüfung |
retries |
3 | Fehlversuche bis Status unhealthy |
start_period |
60s | Wartezeit nach Container-Start (GTM lädt Konfiguration von Google) |
Autoheal-Integration
Die GTM-Container sind für den zentralen Autoheal-Stack vorkonfiguriert:
labels:
- autoheal=true # Markiert den Container zur Überwachung
- autoheal.stop.timeout=10 # Wartezeit in Sekunden vor SIGKILL beim Neustart
Autoheal startet den Container automatisch neu sobald der Status unhealthy ist. Der Autoheal-Stack muss separat auf dem Server laufen (Stack docker-autoheal-neustart).
Nützliche Befehle
# Stack starten
docker compose up -d
# Stack stoppen
docker compose down
# Logs ansehen
docker compose logs -f
# Logs eines einzelnen Containers
docker compose logs -f gtm-tag-server
docker compose logs -f gtm-preview-server
# Healthcheck-Status prüfen
docker inspect --format='{{.State.Health.Status}}' <container-name>
# Alle Container-Status auf einmal
docker ps --format "table {{.Names}}\t{{.Status}}"
Troubleshooting
Container bleibt auf starting / wird nicht healthy:
- GTM braucht beim Start bis zu 60 Sekunden um die Konfiguration von Google zu laden
- Logs prüfen:
docker compose logs -f gtm-tag-server - Sicherstellen dass
CONTAINER_CONFIGin der.envkorrekt ist
/healthy gibt keinen 200 zurück:
- Prüfen ob
CONTAINER_CONFIGgültig und vollständig ist - In GTM unter Container-Einstellungen den Base64-String neu kopieren
Preview-Server nicht erreichbar:
PREVIEW_SERVER_URLin der.envdarf keinhttps://enthalten, nur die Domain- In den GTM Container-Einstellungen muss die Preview-URL korrekt eingetragen sein
Traefik routet nicht:
- Sicherstellen dass das Netzwerk
traefik_proxy_networkexistiert:docker network ls - Traefik-Dashboard prüfen ob der Router registriert ist
CI/CD & Spiegelung
Die Pipeline (.forgejo/workflows/ci.yml) läuft self-hosted auf Forgejo, ganz ohne externe Actions (Checkout per git clone):
validate(jeder Push/PR aufmain+ Tags):docker compose config -q,yamllint(relaxed) undgitleaks(nur Working-Tree). Es wird docker compose v2 genutzt (Runner-Imagecatthehacker/ubuntu:act-latest; nötig u. a. für v2-Keys wiedockerfile_inline), apt nur als Fallback – kein 64-MB-github-Download.mirror(nur Push,needs: validate): spiegeltmain+ Tags erst nach grünen Checks nach Codeberg (OrgDocker-Stacks), mit Retry gegen transiente 502/504. Forgejos eingebauten Push-Mirror dafür nicht zusätzlich aktivieren.release(nur Tagv*): baut ein schlankes Deploy-ZIP und hängt es an ein Forgejo-Release und – als Backup – an ein Codeberg-Release (die Releases-Unit am Codeberg-Repo wird dabei automatisch aktiviert).
Release auslösen:
git tag v1.1
git push origin v1.1
Details siehe CICD-Actions.md.
Lizenz
Copyright (C) 2026 Christian Säum – web-seo-consulting.eu
Dieses Projekt steht unter der GNU Affero General Public License, Version 3
oder (nach deiner Wahl) einer späteren Version (AGPL-3.0-or-later). Der
vollständige Lizenztext steht in der Datei LICENSE.
Du darfst die Software nutzen, weitergeben und – auch kommerziell – verkaufen.
Gibst du eine veränderte Fassung weiter oder betreibst du sie über ein
Netzwerk (z. B. als Dienst), muss deren vollständiger Quellcode ebenfalls
unter der AGPL-3.0-or-later verfügbar sein. Der Copyright-Hinweis und die
Nennung des ursprünglichen Autors dürfen nicht entfernt werden.
Diese Angabe betrifft nur die in diesem Repository enthaltenen eigenen Dateien (Konfiguration, Skripte, Anpassungen). Eingebundene Fremdsoftware und Container-Images unterliegen weiterhin ihren eigenen Lizenzen.