Initial: Traefik + cloudflared + Gitea auf dama.casa
This commit is contained in:
14
.env.example
Normal file
14
.env.example
Normal 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
15
.gitignore
vendored
Normal 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
52
Makefile
Normal 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
79
README.md
Normal 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.
|
||||||
1
services/cloudflared/.env.example
Normal file
1
services/cloudflared/.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Alle Variablen liegen in /.env.example (Root des Repos)
|
||||||
9
services/cloudflared/config/config.yaml
Normal file
9
services/cloudflared/config/config.yaml
Normal 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
|
||||||
15
services/cloudflared/docker-compose.yaml
Normal file
15
services/cloudflared/docker-compose.yaml
Normal 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
|
||||||
31
services/gitea/docker-compose.yaml
Normal file
31
services/gitea/docker-compose.yaml
Normal 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
|
||||||
1
services/traefik/.env.example
Normal file
1
services/traefik/.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Alle Variablen liegen in /.env.example (Root des Repos)
|
||||||
20
services/traefik/config/dynamic/middlewares.yaml
Normal file
20
services/traefik/config/dynamic/middlewares.yaml
Normal 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"
|
||||||
43
services/traefik/config/traefik.yaml.template
Normal file
43
services/traefik/config/traefik.yaml.template
Normal 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
|
||||||
31
services/traefik/docker-compose.yaml
Normal file
31
services/traefik/docker-compose.yaml
Normal 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
|
||||||
Reference in New Issue
Block a user