Initial: Traefik + cloudflared + Gitea auf dama.casa

This commit is contained in:
2026-03-19 14:24:12 +00:00
commit b201d3a13e
12 changed files with 311 additions and 0 deletions

14
.env.example Normal file
View File

@@ -0,0 +1,14 @@
# Aktive Domain für Umstieg: home2.dnlm.de → home.dnlm.de ändern
# Danach: make setup && make all-up
DOMAIN=dama.casa
# Cloudflare API Token (Zone:DNS:Edit für dama.casa)
# Dashboard → My Profile → API Tokens → Create Token → "Edit zone DNS" Template
CF_DNS_API_TOKEN=
# Cloudflare Tunnel Token (Zero Trust → Networks → Tunnels → Tunnel erstellen)
CLOUDFLARE_TUNNEL_TOKEN=
# Traefik Dashboard Basic Auth
# Generieren: echo $(htpasswd -nb admin PASSWORT) | sed -e 's/\$/\$\$/g'
TRAEFIK_DASHBOARD_USER=admin:$$apr1$$...

15
.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
# Secrets
.env
*.env
# Generierte Traefik-Config (wird via `make setup` aus Template erzeugt)
services/traefik/config/traefik.yaml
# Traefik TLS-Zertifikate
**/data/acme.json
# Service-Daten und Credentials
**/data/
# Aber .env.example behalten
!.env.example

52
Makefile Normal file
View File

@@ -0,0 +1,52 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
ENV_FILE := $(ROOT_DIR)/.env
-include $(ENV_FILE)
export
# docker compose mit Root-.env für einen Service aufrufen
define compose
docker compose --env-file $(ENV_FILE) -f $(ROOT_DIR)/services/$(1)/docker-compose.yaml
endef
.PHONY: setup traefik-up traefik-down gitea-up gitea-down cloudflared-up cloudflared-down all-up all-down
## Einmalige Einrichtung (nach erstem `cp .env.example .env`)
setup:
@echo "→ Docker-Netzwerk 'proxy' anlegen..."
docker network create proxy 2>/dev/null || true
@echo "→ acme.json vorbereiten..."
mkdir -p $(ROOT_DIR)/services/traefik/data
touch $(ROOT_DIR)/services/traefik/data/acme.json
chmod 600 $(ROOT_DIR)/services/traefik/data/acme.json
@echo "→ traefik.yaml aus Template generieren (DOMAIN=$(DOMAIN))..."
envsubst < $(ROOT_DIR)/services/traefik/config/traefik.yaml.template \
> $(ROOT_DIR)/services/traefik/config/traefik.yaml
@echo "✓ Setup abgeschlossen"
## Traefik
traefik-up:
$(call compose,traefik) up -d
traefik-down:
$(call compose,traefik) down
## Gitea
gitea-up:
$(call compose,gitea) up -d
gitea-down:
$(call compose,gitea) down
## Cloudflare Tunnel
cloudflared-up:
$(call compose,cloudflared) up -d
cloudflared-down:
$(call compose,cloudflared) down
## Alle Services starten (Reihenfolge: Traefik → cloudflared → Gitea)
all-up: traefik-up cloudflared-up gitea-up
## Alle Services stoppen
all-down: gitea-down cloudflared-down traefik-down

79
README.md Normal file
View File

@@ -0,0 +1,79 @@
# dell01
Docker-Infrastruktur für Dell01 (OptiPlex 3060 Micro, Ubuntu 24.04).
## Architektur
```
Internet
└── Cloudflare Edge
└── Cloudflare Tunnel (cloudflared)
└── Traefik (Wildcard-Cert via Cloudflare DNS-Challenge)
└── Alle Docker-Container
```
## Ersteinrichtung
```bash
cp .env.example .env
# .env befüllen (alle Variablen, siehe Kommentare)
make setup
make all-up
```
### .env vorbereiten
| Variable | Beschreibung |
|---|---|
| `DOMAIN` | Aktive Domain, z.B. `home2.dnlm.de` |
| `INWX_USERNAME` | INWX Login-Name |
| `INWX_PASSWORD` | INWX Passwort |
| `CLOUDFLARE_TUNNEL_TOKEN` | Zero Trust → Networks → Tunnels → Tunnel erstellen |
| `TRAEFIK_DASHBOARD_USER` | `echo $(htpasswd -nb admin PW) \| sed -e 's/\$/\$\$/g'` |
### Cloudflare Tunnel konfigurieren
Tunnel anlegen: Zero Trust → Networks → Tunnels → Token kopieren.
Public Hostname im Dashboard: `*.${DOMAIN}``https://traefik:443`
Alternativ (ohne Cloudflare-Zone): Tunnel-UUID aus dem Dashboard nehmen und
bei INWX manuell setzen:
```
*.home2 CNAME <tunnel-uuid>.cfargotunnel.com
```
Dann ingress in `services/cloudflared/config.yaml` konfigurieren (statt Dashboard).
## Domain-Umstieg (home2 → home)
```bash
# In .env ändern:
DOMAIN=home.dnlm.de
make setup # traefik.yaml neu generieren
make all-down
make all-up
```
## Services
| Service | URL | Compose |
|-------------|------------------------------|----------------------------------|
| Traefik | traefik.home2.dnlm.de | services/traefik/ |
| Gitea | gitea.home2.dnlm.de | services/gitea/ |
| cloudflared | | services/cloudflared/ |
## Neuen Service hinzufügen
Nur Traefik-Labels in die `docker-compose.yaml`:
```yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.SERVICENAME.rule=Host(`SERVICENAME.home2.dnlm.de`)"
- "traefik.http.routers.SERVICENAME.entrypoints=websecure"
- "traefik.http.routers.SERVICENAME.tls=true"
- "traefik.http.services.SERVICENAME.loadbalancer.server.port=PORT"
```
Netzwerk `proxy` als external einbinden fertig.

View File

@@ -0,0 +1 @@
# Alle Variablen liegen in /.env.example (Root des Repos)

View File

@@ -0,0 +1,9 @@
tunnel: fbfb9bdc-f049-4c42-9e2a-622adb05f2c8
credentials-file: /etc/cloudflared/credentials.json
ingress:
- hostname: "*.dama.casa"
service: https://traefik:443
originRequest:
noTLSVerify: true
- service: http_status:404

View File

@@ -0,0 +1,15 @@
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel --no-autoupdate --config /etc/cloudflared/config.yaml run
volumes:
- ./config/config.yaml:/etc/cloudflared/config.yaml:ro
- ./data/credentials.json:/etc/cloudflared/credentials.json:ro
networks:
- proxy
networks:
proxy:
external: true

View File

@@ -0,0 +1,31 @@
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=sqlite3
- GITEA__server__ROOT_URL=https://gitea.${DOMAIN}
- GITEA__server__DOMAIN=gitea.${DOMAIN}
- GITEA__server__HTTP_PORT=3000
- GITEA__server__SSH_DOMAIN=gitea.${DOMAIN}
- GITEA__server__SSH_PORT=2222
volumes:
- ./data:/data
ports:
- "2222:22"
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.gitea.rule=Host(`gitea.${DOMAIN}`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls=true"
- "traefik.http.routers.gitea.tls.certresolver=cloudflare"
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
networks:
proxy:
external: true

View File

@@ -0,0 +1 @@
# Alle Variablen liegen in /.env.example (Root des Repos)

View File

@@ -0,0 +1,20 @@
http:
middlewares:
# Basic Auth für Traefik Dashboard
# Generieren: echo $(htpasswd -nb user password) | sed -e 's/\$/\$\$/g'
traefik-auth:
basicAuth:
usersFile: /auth/traefik-users
# Sicherheits-Header für alle Services
secure-headers:
headers:
sslRedirect: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
contentTypeNosniff: true
browserXssFilter: true
referrerPolicy: "strict-origin-when-cross-origin"
customFrameOptionsValue: "SAMEORIGIN"

View File

@@ -0,0 +1,43 @@
api:
dashboard: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
http:
tls:
certResolver: cloudflare
domains:
- main: "${DOMAIN}"
sans:
- "*.${DOMAIN}"
certificatesResolvers:
cloudflare:
acme:
email: "mail@dnlm.de"
storage: /acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: proxy
file:
directory: /dynamic
watch: true
log:
level: INFO

View File

@@ -0,0 +1,31 @@
services:
traefik:
image: traefik:v3.2
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
- DOCKER_API_VERSION=1.41
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config/traefik.yaml:/traefik.yaml:ro
- ./config/dynamic:/dynamic:ro
- ./data/acme.json:/acme.json
- ./data/traefik-users:/auth/traefik-users:ro
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
- "traefik.http.routers.traefik-dashboard.tls=true"
- "traefik.http.routers.traefik-dashboard.tls.certresolver=cloudflare"
- "traefik.http.routers.traefik-dashboard.service=api@internal"
- "traefik.http.routers.traefik-dashboard.middlewares=traefik-auth@file"
networks:
proxy:
external: true