🎉 Initial Commit
This commit is contained in:
commit
8f23ba583d
20 changed files with 1153 additions and 0 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.env
|
||||
.env.local
|
||||
*.env
|
||||
30
dyndns/docker-compose.yml
Normal file
30
dyndns/docker-compose.yml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
name: dyndns
|
||||
services:
|
||||
ddns-updater:
|
||||
container_name: ddns-updater
|
||||
environment:
|
||||
- PERIOD=${DDNS_PERIOD}
|
||||
- UPDATE_COOLDOWN=${DDNS_COOLDOWN}
|
||||
- TZ=${TZ}
|
||||
image: qmcgaw/ddns-updater:latest
|
||||
restart: ${RESTART_POLICY}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DDNS_DATA_PATH}
|
||||
target: /updater/data
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
ports:
|
||||
- "8000:8000"
|
||||
network_mode: host
|
||||
hostname: ddns-updater
|
||||
cpu_shares: 90
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 15841M
|
||||
38
excalidraw/docker-compose.yml
Normal file
38
excalidraw/docker-compose.yml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
name: ${CONTAINER_NAME}
|
||||
services:
|
||||
excalidraw:
|
||||
cpu_shares: 90
|
||||
command: []
|
||||
container_name: ${CONTAINER_NAME}
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 15841M
|
||||
hostname: ${CONTAINER_NAME}
|
||||
image: excalidraw/excalidraw:latest
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
restart: ${RESTART_POLICY}
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
ports: []
|
||||
volumes: []
|
||||
devices: []
|
||||
cap_add: []
|
||||
environment: []
|
||||
networks:
|
||||
- traefik
|
||||
privileged: false
|
||||
networks:
|
||||
traefik:
|
||||
name: traefik
|
||||
external: true
|
||||
45
forgejo/docker-compose.yml
Normal file
45
forgejo/docker-compose.yml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
name: ${CONTAINER_NAME}
|
||||
|
||||
networks:
|
||||
forgejo:
|
||||
external: false
|
||||
traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
server:
|
||||
image: codeberg.org/forgejo/forgejo:9.0
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: ${RESTART_POLICY}
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
networks:
|
||||
- forgejo
|
||||
- traefik
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DATA_PATH}
|
||||
target: /data
|
||||
bind:
|
||||
create_host_path: true
|
||||
|
||||
- type: bind
|
||||
source: /etc/localtime
|
||||
target: /etc/localtime
|
||||
read_only: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
ports:
|
||||
- '222:22'
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
36
gantt_dockerfolder/docker-compose.yml
Normal file
36
gantt_dockerfolder/docker-compose.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
name: gantt
|
||||
services:
|
||||
gantt-app:
|
||||
image: nginx:stable-alpine
|
||||
container_name: ${CONTAINER_NAME}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DIST_PATH}
|
||||
target: /usr/share/nginx/html:ro
|
||||
bind:
|
||||
create_host_path: true
|
||||
- type: bind
|
||||
source: ${CONFIG_PATH}
|
||||
target: /etc/nginx/conf.d/default.conf:ro
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
restart: ${RESTART_POLICY}
|
||||
networks:
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
41
jellyfin/docker-compose.yml
Normal file
41
jellyfin/docker-compose.yml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: ${RESTART_POLICY}
|
||||
networks:
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
environment:
|
||||
- JELLYFIN_PublishedServerUrl=https://${SUBDOMAIN}.${DOMAIN}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${CACHE_PATH}
|
||||
target: /cache
|
||||
bind:
|
||||
create_host_path: true
|
||||
- type: bind
|
||||
source: ${CONFIG_PATH}
|
||||
target: /config
|
||||
bind:
|
||||
create_host_path: true
|
||||
- type: bind
|
||||
source: ${MEDIA_PATH}
|
||||
target: /media
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
59
kitchenowl/docker-compose.yml
Normal file
59
kitchenowl/docker-compose.yml
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
services:
|
||||
kitchenowl:
|
||||
image: tombursch/kitchenowl:latest
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: ${RESTART_POLICY}
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
environment:
|
||||
- DATABASE_URL=${DB_PROVIDER}://${DB_USER}:${DB_PASSWORD}@db:${DB_PORT}/${DB_DATABASE}
|
||||
- BACKEND_PROVIDER=${DB_BACKEND_PROVIDER}
|
||||
networks:
|
||||
- traefik
|
||||
- internal_net
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
- "traefik.http.middlewares.${ROUTER_NAME}-stripprefix.headers.customrequestheaders.X-Forwarded-Proto=http"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.middlewares=kitchenowl-compress"
|
||||
- "traefik.http.middlewares.${ROUTER_NAME}-compress.compress=true"
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
db:
|
||||
image: postgres:15-alpine
|
||||
container_name: ${CONTAINER_NAME}_db
|
||||
restart: ${RESTART_POLICY}
|
||||
environment:
|
||||
- POSTGRES_USER=${DB_USER}
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
- POSTGRES_DB=${DB_DATABASE}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DB_PATH}
|
||||
target: /var/lib/postgresql/data
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- internal_net
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
internal_net:
|
||||
driver: bridge
|
||||
|
||||
60
matrix/docker-compose.yml
Executable file
60
matrix/docker-compose.yml
Executable file
|
|
@ -0,0 +1,60 @@
|
|||
name: matrix
|
||||
services:
|
||||
synapse:
|
||||
container_name: ${CONTAINER_NAME}
|
||||
hostname: ${CONTAINER_NAME}
|
||||
image: matrixdotorg/synapse:latest
|
||||
restart: ${RESTART_POLICY}
|
||||
cpu_shares: 90
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 15841M
|
||||
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- >
|
||||
set -e
|
||||
if [ ! -f /data/homeserver.yaml ]; then
|
||||
echo "Generating initial configuration..."
|
||||
/start.py generate
|
||||
echo "" >> /data/homeserver.yaml
|
||||
echo "enable_registration: true" >> /data/homeserver.yaml
|
||||
echo "enable_registration_without_verification: true" >> /data/homeserver.yaml
|
||||
fi
|
||||
|
||||
echo "Starting Synapse..."
|
||||
exec /start.py
|
||||
|
||||
environment:
|
||||
- SYNAPSE_REPORT_STATS=${SYNAPSE_REPORT_STATS}
|
||||
- SYNAPSE_SERVER_NAME=${SUBDOMAIN}.${DOMAIN}
|
||||
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DATA_PATH}
|
||||
target: /data
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
name: traefik
|
||||
external: true
|
||||
49
n8n/docker-compose.yml
Normal file
49
n8n/docker-compose.yml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
name: n8n
|
||||
services:
|
||||
n8n:
|
||||
image: docker.n8n.io/n8nio/n8n:latest
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: ${RESTART_POLICY}
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- N8N_PORT=${CONTAINER_PORT}
|
||||
- N8N_PROTOCOL=https
|
||||
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
|
||||
- N8N_HOST=${SUBDOMAIN}.${DOMAIN}
|
||||
- WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN}/
|
||||
- GENERIC_TIMEZONE=${TZ}
|
||||
- TZ=${TZ}
|
||||
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DATA_PATH}
|
||||
target: /home/node/.n8n
|
||||
bind:
|
||||
create_host_path: true
|
||||
|
||||
- type: bind
|
||||
source: ${FILES_PATH}
|
||||
target: /files
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
name: traefik
|
||||
external: true
|
||||
44
openProject/docker-compose.yml
Normal file
44
openProject/docker-compose.yml
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
name: op-xwiki-stack
|
||||
networks:
|
||||
frontend:
|
||||
name: op_xwiki_frontend
|
||||
backend:
|
||||
name: op_xwiki_backend
|
||||
traefik:
|
||||
name: traefik
|
||||
external: true
|
||||
|
||||
services:
|
||||
openproject_web:
|
||||
image: openproject/openproject:17
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: ${RESTART_POLICY}
|
||||
|
||||
environment:
|
||||
- OPENPROJECT_SECRET_KEY_BASE=${OP_SECRET_KEY_BASE}
|
||||
- SECRET_KEY_BASE=${SECRET_KEY_BASE}
|
||||
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DATA_PATH}
|
||||
target: /var/openproject
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
- traefik
|
||||
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
72
passbolt/docker-compose.yml
Normal file
72
passbolt/docker-compose.yml
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
name: passbolt
|
||||
services:
|
||||
passbolt-db:
|
||||
image: mariadb:10.11
|
||||
container_name: ${CONTAINER_NAME}-db
|
||||
restart: ${RESTART_POLICY}
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${DB_MYSQL_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=${DB_DATABASE}
|
||||
- MYSQL_USER=${DB_USER}
|
||||
- MYSQL_PASSWORD=${DB_PASSWORD}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DB_PATH}
|
||||
target: /var/lib/mysql
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- internal_net
|
||||
|
||||
passbolt:
|
||||
image: passbolt/passbolt:latest-ce
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: ${RESTART_POLICY}
|
||||
depends_on:
|
||||
- passbolt-db
|
||||
environment:
|
||||
- APP_FULL_BASE_URL=https://${SUBDOMAIN}.${DOMAIN}
|
||||
- DB_HOST=passbolt-db
|
||||
- DB_USER=${DB_USER}
|
||||
- DB_PASSWORD=${DB_PASSWORD}
|
||||
- DB_DATABASE=${DB_DATABASE}
|
||||
- EMAIL_DEFAULT_TRANSPORT=${EMAIL_TRANSPORT}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${PGP_PATH}
|
||||
target: /etc/passbolt/gpg
|
||||
bind:
|
||||
create_host_path: true
|
||||
- type: bind
|
||||
source: ${JWT_PATH}
|
||||
target: /etc/passbolt/jwt
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- traefik
|
||||
- internal_net
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
name: traefik
|
||||
external: true
|
||||
internal_net:
|
||||
driver: bridge
|
||||
192
readme.md
Normal file
192
readme.md
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
# 🏠 Homeserver Setup
|
||||
|
||||
Zentrale Dokumentation der Infrastruktur, Docker-Container und persistenten Daten meines Debian-basierten Homeservers.
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Projektstruktur
|
||||
|
||||
Das Setup trennt strikt zwischen persistenten Anwendungsdaten (`data/`) und den Docker-Konfigurationsdateien (`homeserver/`).
|
||||
|
||||
```text
|
||||
|
||||
## Tree
|
||||
├── data
|
||||
│ ├── backup_emmc
|
||||
│ │ └── sys_ssh
|
||||
│ ├── dyndns
|
||||
│ │ └── ddns-data
|
||||
│ ├── excalidraw
|
||||
│ ├── forgejo
|
||||
│ │ └── forgejo
|
||||
│ ├── gantt
|
||||
│ │ ├── dist
|
||||
│ │ ├── env.d.ts
|
||||
│ │ ├── gantt_dockerfolder
|
||||
│ │ ├── index.html
|
||||
│ │ ├── node_modules
|
||||
│ │ ├── package.json
|
||||
│ │ ├── package-lock.json
|
||||
│ │ ├── public
|
||||
│ │ ├── README.md
|
||||
│ │ ├── src
|
||||
│ │ ├── tsconfig.app.json
|
||||
│ │ ├── tsconfig.json
|
||||
│ │ ├── tsconfig.node.json
|
||||
│ │ └── vite.config.ts
|
||||
│ ├── jellyfin
|
||||
│ │ ├── cache
|
||||
│ │ ├── config
|
||||
│ │ └── media
|
||||
│ ├── kitchenowl
|
||||
│ │ └── db_data
|
||||
│ ├── letsencrypt
|
||||
│ ├── matrix
|
||||
│ │ └── data
|
||||
│ ├── n8n
|
||||
│ │ └── local-files
|
||||
│ ├── openProject
|
||||
│ ├── passbolt
|
||||
│ │ ├── db-data
|
||||
│ │ ├── gpg-keys
|
||||
│ │ └── jwt-keys
|
||||
│ ├── sure
|
||||
│ │ ├── db
|
||||
│ │ ├── enable_banking.pem
|
||||
│ │ └── storage
|
||||
│ ├── test
|
||||
│ │ └── dns-check.sh
|
||||
│ ├── traefik
|
||||
│ │ ├── acme.json
|
||||
│ │ └── letsencrypt
|
||||
│ ├── wartungsskripte
|
||||
│ │ ├── update_befehl.sh
|
||||
│ │ └── update_docker.sh
|
||||
│ └── xWiki
|
||||
│ ├── postgres_data
|
||||
│ └── xwiki_data
|
||||
└── homeserver
|
||||
│ └── docker-compose.yml
|
||||
├── excalidraw
|
||||
│ └── docker-compose.yml
|
||||
├── forgejo
|
||||
│ └── docker-compose.yml
|
||||
├── gantt_dockerfolder
|
||||
│ └── docker-compose.yml
|
||||
├── jellyfin
|
||||
│ └── docker-compose.yml
|
||||
├── kitchenowl
|
||||
│ └── docker-compose.yml
|
||||
├── letsencrypt
|
||||
├── matrix
|
||||
│ └── docker-compose.yml
|
||||
├── n8n
|
||||
│ └── docker-compose.yml
|
||||
├── openProject
|
||||
│ └── docker-compose.yml
|
||||
├── passbolt
|
||||
│ └── docker-compose.yml
|
||||
├── readme.md
|
||||
├── sure
|
||||
│ └── docker-compose.yml
|
||||
├── test
|
||||
│ └── dns-check.sh
|
||||
├── traefik
|
||||
│ └── docker-compose.yml
|
||||
├── wartungsskripte
|
||||
│ ├── update_befehl.sh
|
||||
│ └── update_docker.sh
|
||||
└── xWiki
|
||||
└── docker-compose.yml
|
||||
```
|
||||
## 🚀 Infrastruktur & Netzwerk
|
||||
Als zentraler Reverse Proxy wird Traefik eingesetzt. Er fängt alle Anfragen auf Port 80/443 ab, verteilt sie an die jeweiligen Docker-Container und erstellt automatisch SSL-Zertifikate via Let's Encrypt.
|
||||
|
||||
## Wichtige URLs im Netzwerk:
|
||||
🌐 Git-Server (Forgejo): `https://git.bybenji.de` (SSH-Port: 222)
|
||||
🌐 Passwortmanager: `https://passbolt.bybenji.de`
|
||||
🌐 Streaming: `https://jellyfin.bybenji.de`
|
||||
|
||||
## 🛠️ Betrieb & Wartung
|
||||
Container starten / stoppen
|
||||
Um einen bestimmten Dienst zu starten, in den entsprechenden Ordner unter homeserver/ wechseln und ausführen:
|
||||
```Bash
|
||||
cd homeserver/jellyfin
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Updates
|
||||
Unter `homeserver/wartungsskripte/` befinden sich Skripte zur Serverpflege.
|
||||
`update_docker.sh`: Aktualisiert alle laufenden Docker-Container auf das neueste Image und räumt alte Images auf (docker system prune).
|
||||
Aktuell ist ein Manuelles Wartungsfenster jeden Samstag um 21 Uhr gesetzt.
|
||||
> [!NOTE] Automatisierung
|
||||
Einrichtung als Cronjob für automatische Updates jeden Sonntag um 03:00 Uhr:
|
||||
>```Bash
|
||||
>0 3 * * 0 /bin/bash /mnt/PB960/data/gantt/homeserver/wartungsskripte/update_docker.>sh
|
||||
>```
|
||||
## 📦 Backup-Strategie
|
||||
|
||||
Um maximale Datensicherheit zu gewährleisten, werden alle Produktivdaten (`data/`) nach dem 3-2-1-Prinzip gesichert.
|
||||
|
||||
### 1. Datenbasis & Lokales Backup (Kopie 1 & 2 - Medium 1)
|
||||
* **Produktivdaten:** Befinden sich live auf dem Produktivsystem.
|
||||
* **Lokales Backup:** Täglich inkrementelle und monatlich vollständige Backups werden auf einem dedizierten **NAS** gesichert, das sich physisch im selben Serverrack befindet.
|
||||
|
||||
### 2. Offsite & Standby-Server (Kopie 3 - Standort extern)
|
||||
* **Backup-Server:** Eine vollständige Kopie wird an einen geografisch getrennten Standort gesichert.
|
||||
* **Hot-Standby:** Da dieser Server denselben Techstack besitzt, kann er bei Wartungsarbeiten oder Ausfällen des Hauptservers direkt als temporäres Produktivsystem zugeschaltet werden.
|
||||
|
||||
|
||||
|
||||
> [!NOTE]
|
||||
> **Offene Baustelle: Das 2. Speichermedium**
|
||||
> Für die vollständige Erfüllung des 3-2-1-Prinzips fehlt noch das zweite, alternative Speichermedium (z. B. eine rotierende externe USB-Festplatte (Air-Gapped) oder ein verschlüsselter S3-Cloud-Speicher wie Hetzner Storage Box).
|
||||
|
||||
### 🖥️ System-Backup
|
||||
* Unabhängig von den Anwendungsdaten werden Abbilder des eMMC-Speichers sowie die systemrelevanten SSH-Schlüssel unter `data/backup_emmc/sys_ssh/` vorgehalten.
|
||||
|
||||
|
||||
### 💾 Speicher-Architektur & NAS
|
||||
|
||||
Sowohl das lokale Produktiv-NAS als auch das Offsite-NAS sind speicherseitig identisch aufgebaut, um maximale Redundanz und volle Kompatibilität im Failover-Fall zu gewährleisten.
|
||||
|
||||
### 📍 Phase 1: Start-Setup (Aktueller Stand)
|
||||
* **Main-Server:** 1x 14 TB Seagate Exos (Single Drive – 14 TB Netto-Nutzdaten)
|
||||
* **Offsite-Server:** 1x 14 TB Seagate Exos (Single Drive – 14 TB Backup-Ziel)
|
||||
* **Sicherheit:** Die Datenkomponente wird per täglichem Skript/Replikation auf den Offsite-Server gesichert. Es besteht in dieser Phase noch keine lokale Festplatten-Redundanz (RAID) beim Ausfall einer Platte vor Ort.
|
||||
|
||||
### 🚀 Phase 2: RAID 5 Erweiterung (Zukunft)
|
||||
Sobald zusätzlicher Speicher oder lokale Ausfallsicherheit benötigt wird, wird jedes System um 2 weitere 14 TB Platten ergänzt:
|
||||
* **Konfiguration:** Migration auf ein **3-Platten-RAID-5** pro Server.
|
||||
* **Neuer Speicher:** **28 TB Netto-Nutzdaten** pro Server bei einer Fehlertoleranz von 1 ausfallenden Festplatte pro System.
|
||||
|
||||
## 🖥️ Offsite-Server & Techstack
|
||||
|
||||
Der Offsite-Server dient primär als geografisch getrenntes Backup-Ziel, ist jedoch hardware- und softwareseitig als **Hot-Standby** konzipiert. Bei einem Totalausfall oder Wartungsarbeiten am Hauptstandort kann er die primären Dienste temporär übernehmen.
|
||||
|
||||
### 🌐 Virtualisierungs-Plattform (Proxmox VE)
|
||||
Als Betriebssystem-Unterbau wird **Proxmox VE (Virtual Environment)** eingesetzt. Dies ermöglicht eine strikte Kapselung und einfache Verwaltung der Ressourcen:
|
||||
|
||||
* **Hypervisor:** Typ-1-Bare-Metal-Hypervisor auf Debian-Basis.
|
||||
* **LXC (Linux Containers):** Für ressourcensparende Anwendungen (wie den Docker-Host).
|
||||
* **VMs (Virtuelle Maschinen):** Für isolierte Systeme, die einen eigenen Kernel oder ein anderes OS benötigen.
|
||||
|
||||
### 📦 Container-Architektur (Der "Bauchtanz")
|
||||
Um den exakt gleichen Techstack wie auf dem Main-Server zu spiegeln, läuft innerhalb von Proxmox ein dedizierter LXC-Container (oder eine VM), der als **Docker-Host** fungiert.
|
||||
|
||||
* **Docker & Compose:** Innerhalb dieser Instanz wird die identische `homeserver/`-Struktur per Git synchronisiert gehalten.
|
||||
* **Dienste-Status:** Die Docker-Container (Nextcloud, Immich, Jellyfin etc.) sind im Normalbetrieb gestoppt oder laufen im reinen Standby-Modus, um Ressourcen zu schonen, stehen aber für ein sofortiges Failover bereit.
|
||||
|
||||
### 🔄 Replikation & Backup-Infrastruktur (Phase 1)
|
||||
In der aktuellen Phase (Single-Drive) sieht das Zusammenspiel wie folgt aus:
|
||||
|
||||
1. **ZFS / Local Storage:** Proxmox verwaltet die einzelne 14 TB Seagate Exos Festplatte als lokalen Speicherpool.
|
||||
2. **Pull-/Push-Backups:** Der Hauptserver schiebt seine Daten (z. B. via `rsync`, `rclone` oder BorgBackup) verschlüsselt über das Netzwerk auf den Offsite-Proxmox-Speicher.
|
||||
|
||||
|
||||
---
|
||||
|
||||
# Visualisierung
|
||||
├── für einen Ordner oder eine Datei, wenn danach noch weitere Elemente auf derselben Ebene folgen.
|
||||
└── für das letzte Element auf einer Ebene (das „Eckstück“).
|
||||
│ für Linien, die an Unterordnern vorbeiführen (wichtig für die richtige Einrückung).
|
||||
110
sparkyFitness/docker-compose.yml
Normal file
110
sparkyFitness/docker-compose.yml
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
services:
|
||||
sparkyfitness-db:
|
||||
image: postgres:18.3-alpine
|
||||
container_name: ${CONTAINER_NAME}-db
|
||||
restart: ${RESTART_POLICY}
|
||||
environment:
|
||||
POSTGRES_DB: ${SPARKY_FITNESS_DB_NAME}
|
||||
POSTGRES_USER: ${SPARKY_FITNESS_DB_USER}
|
||||
POSTGRES_PASSWORD: ${SPARKY_FITNESS_DB_PASSWORD}
|
||||
PUID: 1000
|
||||
GUID: 1000
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DB_PATH:-./postgresql}
|
||||
target: /var/lib/postgresql
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- sparkyfitness-network
|
||||
|
||||
sparkyfitness-server:
|
||||
image: codewithcj/sparkyfitness_server:latest
|
||||
environment:
|
||||
SPARKY_FITNESS_LOG_LEVEL: ${SPARKY_FITNESS_LOG_LEVEL}
|
||||
ALLOW_PRIVATE_NETWORK_CORS: ${ALLOW_PRIVATE_NETWORK_CORS:-false}
|
||||
SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS: ${SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS}
|
||||
SPARKY_FITNESS_PUBLIC_API_DOCS: ${SPARKY_FITNESS_PUBLIC_API_DOCS:-false}
|
||||
SPARKY_FITNESS_DB_USER: ${SPARKY_FITNESS_DB_USER:-sparky}
|
||||
SPARKY_FITNESS_DB_HOST: ${SPARKY_FITNESS_DB_HOST:-sparkyfitness-db}
|
||||
SPARKY_FITNESS_DB_NAME: ${SPARKY_FITNESS_DB_NAME}
|
||||
SPARKY_FITNESS_DB_PASSWORD: ${SPARKY_FITNESS_DB_PASSWORD}
|
||||
SPARKY_FITNESS_APP_DB_USER: ${SPARKY_FITNESS_APP_DB_USER:-sparkyapp}
|
||||
SPARKY_FITNESS_APP_DB_PASSWORD: ${SPARKY_FITNESS_APP_DB_PASSWORD}
|
||||
SPARKY_FITNESS_DB_PORT: 5432
|
||||
SPARKY_FITNESS_API_ENCRYPTION_KEY: ${SPARKY_FITNESS_API_ENCRYPTION_KEY}
|
||||
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
|
||||
SPARKY_FITNESS_FRONTEND_URL: ${SPARKY_FITNESS_FRONTEND_URL:-http://0.0.0.0}
|
||||
SPARKY_FITNESS_DISABLE_SIGNUP: ${SPARKY_FITNESS_DISABLE_SIGNUP}
|
||||
SPARKY_FITNESS_ADMIN_EMAIL: ${SPARKY_FITNESS_ADMIN_EMAIL}
|
||||
SPARKY_FITNESS_EMAIL_HOST: ${SPARKY_FITNESS_EMAIL_HOST}
|
||||
SPARKY_FITNESS_EMAIL_PORT: ${SPARKY_FITNESS_EMAIL_PORT}
|
||||
SPARKY_FITNESS_EMAIL_SECURE: ${SPARKY_FITNESS_EMAIL_SECURE}
|
||||
SPARKY_FITNESS_EMAIL_USER: ${SPARKY_FITNESS_EMAIL_USER}
|
||||
SPARKY_FITNESS_EMAIL_PASS: ${SPARKY_FITNESS_EMAIL_PASS}
|
||||
SPARKY_FITNESS_EMAIL_FROM: ${SPARKY_FITNESS_EMAIL_FROM}
|
||||
GARMIN_MICROSERVICE_URL: http://sparkyfitness-garmin:8000
|
||||
HTTP_PROXY: ${HTTP_PROXY:-}
|
||||
HTTPS_PROXY: ${HTTPS_PROXY:-}
|
||||
NO_PROXY: ${NO_PROXY:-}
|
||||
PUID: 1000
|
||||
GUID: 1000
|
||||
networks:
|
||||
- sparkyfitness-network
|
||||
restart: always
|
||||
depends_on:
|
||||
- sparkyfitness-db
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${SERVER_BACKUP_PATH:-./backup}
|
||||
target: /app/SparkyFitnessServer/backup
|
||||
bind:
|
||||
create_host_path: true
|
||||
- type: bind
|
||||
source: ${SERVER_UPLOADS_PATH:-./uploads}
|
||||
target: /app/SparkyFitnessServer/uploads
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
sparkyfitness-frontend:
|
||||
image: codewithcj/sparkyfitness:latest
|
||||
environment:
|
||||
SPARKY_FITNESS_FRONTEND_URL: ${SPARKY_FITNESS_FRONTEND_URL}
|
||||
SPARKY_FITNESS_SERVER_HOST: ${CONTAINER_NAME}-server
|
||||
SPARKY_FITNESS_SERVER_PORT: 3010
|
||||
PUID: 1000
|
||||
GUID: 1000
|
||||
networks:
|
||||
- sparkyfitness-network
|
||||
- traefik
|
||||
restart: ${RESTART_POLICY}
|
||||
depends_on:
|
||||
- sparkyfitness-server
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
- "traefik.http.routers.${ROUTER_NAME}.middlewares=sparkyfitness-headers"
|
||||
- "traefik.http.middlewares.${ROUTER_NAME}-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||
- "traefik.http.middlewares.${ROUTER_NAME}-headers.headers.customrequestheaders.X-Forwarded-Host=fitness.bybenji.de"
|
||||
|
||||
networks:
|
||||
sparkyfitness-network:
|
||||
driver: bridge
|
||||
traefik:
|
||||
external: true
|
||||
149
sure/docker-compose.yml
Normal file
149
sure/docker-compose.yml
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
name: sure
|
||||
networks:
|
||||
traefik:
|
||||
name: traefik
|
||||
external: true
|
||||
internal_net:
|
||||
name: sure_internal_net
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
sure-db:
|
||||
image: postgres:16-alpine
|
||||
container_name: ${CONTAINER_NAME}-db
|
||||
restart: ${RESTART_POLICY}
|
||||
environment:
|
||||
- POSTGRES_DB=${DB_DATABASE}
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
- POSTGRES_USER=${DB_USER}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DB_PATH}
|
||||
target: /var/lib/postgresql/data
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- internal_net
|
||||
cpu_shares: 90
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 15841M
|
||||
|
||||
sure-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: ${CONTAINER_NAME}-redis
|
||||
restart: ${RESTART_POLICY}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${REDIS_PATH}
|
||||
target: /data
|
||||
bind:
|
||||
create_host_path: true
|
||||
networks:
|
||||
- internal_net
|
||||
cpu_shares: 90
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 15841M
|
||||
|
||||
web:
|
||||
image: ghcr.io/we-promise/sure:stable
|
||||
container_name: ${CONTAINER_NAME}-web
|
||||
restart: ${RESTART_POLICY}
|
||||
depends_on:
|
||||
sure-db:
|
||||
condition: service_started
|
||||
sure-redis:
|
||||
condition: service_started
|
||||
environment:
|
||||
- SELF_HOSTED=${SELF_HOSTED}
|
||||
- ALLOW_REGISTRATION=${ALLOW_REGISTRATION}
|
||||
- SECRET_KEY_BASE=${SECRET_KEY_BASE}
|
||||
- RAILS_ASSUME_SSL=${RAILS_ASSUME_SSL}
|
||||
- RAILS_FORCE_SSL=${RAILS_FORCE_SSL}
|
||||
- DB_HOST=sure-db
|
||||
- POSTGRES_DB=${DB_DATABASE}
|
||||
- POSTGRES_USER=${DB_USER}
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
- REDIS_URL=${REDIS_URL}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${STORAGE_PATH}
|
||||
target: /rails/storage
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- traefik
|
||||
- internal_net
|
||||
cpu_shares: 90
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 15841M
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
worker:
|
||||
image: ghcr.io/we-promise/sure:stable
|
||||
container_name: ${CONTAINER_NAME}-worker
|
||||
restart: ${RESTART_POLICY}
|
||||
command:
|
||||
- /rails/bin/docker-entrypoint
|
||||
- ./bin/bundle
|
||||
- exec
|
||||
- sidekiq
|
||||
depends_on:
|
||||
sure-db:
|
||||
condition: service_started
|
||||
sure-redis:
|
||||
condition: service_started
|
||||
environment:
|
||||
- APP_URL=https://${SUBDOMAIN}.${DOMAIN}
|
||||
- DB_HOST=sure-db
|
||||
- POSTGRES_DB=${DB_DATABASE}
|
||||
- POSTGRES_USER=${DB_USER}
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
- REDIS_URL=${REDIS_URL}
|
||||
- SECRET_KEY_BASE=${SECRET_KEY_BASE}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${STORAGE_PATH}
|
||||
target: /rails/storage
|
||||
bind:
|
||||
create_host_path: true
|
||||
- type: bind
|
||||
source: ${BANKING_PATH}
|
||||
target: /rails/config/enable_banking.pem
|
||||
read_only: true
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- internal_net
|
||||
cpu_shares: 90
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 15841M
|
||||
19
test/dns-check.sh
Executable file
19
test/dns-check.sh
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
while true; do
|
||||
clear
|
||||
echo "=== Nameserver-Überwachung für bybenji.de ==="
|
||||
echo "Letzte Prüfung: $(date +%H:%M:%S)"
|
||||
echo "----------------------------------------"
|
||||
|
||||
NS_INFO=$(nslookup -type=ns budget.bybenji.de 8.8.8.8 2>&1)
|
||||
echo "$NS_INFO"
|
||||
|
||||
if echo "$NS_INFO" | grep -q "desec.io"; then
|
||||
echo -e "\n\a🚀🚀🚀 ERFOLG! Die Nameserver wurden auf deSEC umgestellt! 🚀🚀🚀"
|
||||
break
|
||||
fi
|
||||
|
||||
echo -e "\n[Warten auf deSEC...] Nächste Prüfung in 30 Sekunden. (Abbrechen mit STRG+C)"
|
||||
sleep 30
|
||||
done
|
||||
63
traefik/docker-compose.yml
Normal file
63
traefik/docker-compose.yml
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
name: traefik
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
name: traefik
|
||||
# external: true -> Entfernt, damit dieser Stack das Netzwerk global auf dem Server erstellt!
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:latest
|
||||
container_name: ${CONTAINER_NAME}
|
||||
hostname: traefik
|
||||
restart: ${RESTART_POLICY}
|
||||
cpu_shares: 90
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 15841M
|
||||
|
||||
command:
|
||||
- --api.insecure=true
|
||||
- --providers.docker=true
|
||||
- --providers.docker.exposedbydefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.web.http.redirections.entryPoint.to=websecure
|
||||
- --entrypoints.web.http.redirections.entryPoint.scheme=https
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --certificatesresolvers.myresolver.acme.dnschallenge=true
|
||||
- --certificatesresolvers.myresolver.acme.dnschallenge.provider=desec
|
||||
- --certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=10
|
||||
- --certificatesresolvers.myresolver.acme.email=${CERT_RESOLVER_EMAIL}
|
||||
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
|
||||
- --certificatesresolvers.myresolver.acme.dnschallenge.resolvers=${DNS_RESOLVERS}
|
||||
|
||||
environment:
|
||||
- DESEC_TOKEN=${DESEC_TOKEN}
|
||||
- DESEC_TTL=${DESEC_TTL}
|
||||
- DESEC_POLLING_INTERVAL=${DESEC_POLLING_INTERVAL}
|
||||
- DESEC_PROPAGATION_TIMEOUT=${DESEC_PROPAGATION_TIMEOUT}
|
||||
|
||||
ports:
|
||||
- "${HTTP_PORT}:80"
|
||||
- "${HTTPS_PORT}:443"
|
||||
- "${DASHBOARD_PORT}:8080"
|
||||
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /var/run/docker.sock
|
||||
target: /var/run/docker.sock
|
||||
read_only: true
|
||||
- type: bind
|
||||
source: ${LETSENCRYPT_PATH}
|
||||
target: /letsencrypt
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
- traefik
|
||||
1
wartungsskripte/update_befehl.sh
Normal file
1
wartungsskripte/update_befehl.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
sudo ./update_docker.sh
|
||||
72
wartungsskripte/update_docker.sh
Executable file
72
wartungsskripte/update_docker.sh
Executable file
|
|
@ -0,0 +1,72 @@
|
|||
#!/bin/bash
|
||||
|
||||
PROJECTS=(
|
||||
"/mnt/PB960/homeserver/dyndns"
|
||||
"/mnt/PB960/homeserver/excalidraw"
|
||||
"/mnt/PB960/homeserver/forgejo"
|
||||
"/mnt/PB960/homeserver/gantt_dockerfolder"
|
||||
"/mnt/PB960/homeserver/jellyfin"
|
||||
"/mnt/PB960/homeserver/kitchenowl"
|
||||
"/mnt/PB960/homeserver/matrix"
|
||||
"/mnt/PB960/homeserver/n8n"
|
||||
"/mnt/PB960/homeserver/openProject"
|
||||
"/mnt/PB960/homeserver/passbolt"
|
||||
"/mnt/PB960/homeserver/sparkyFitness"
|
||||
"/mnt/PB960/homeserver/sure"
|
||||
"/mnt/PB960/homeserver/traefik"
|
||||
"/mnt/PB960/homeserver/xWiki"
|
||||
)
|
||||
|
||||
echo "=========================================="
|
||||
echo " STARRTE AUTOMATISCHES DOCKER-UPDATE "
|
||||
echo " Datum: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "=========================================="
|
||||
|
||||
# Prüfen, ob das Skript als Root ausgeführt wird
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "[FEHLER] Bitte starte das Skript mit 'sudo'!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Aktuellste Version des Repos holen
|
||||
echo "[1/2] Aktualisiere Git-Repository (Homeserver)..."
|
||||
cd /mnt/PB960/homeserver && git pull
|
||||
|
||||
echo "[2/2] Aktualisiere Git-Repository (Gantt)..."
|
||||
cd /mnt/PB960/data/gantt && git pull
|
||||
|
||||
for TARGET_DIR in "${PROJECTS[@]}"; do
|
||||
if [ -d "$TARGET_DIR" ]; then
|
||||
echo ""
|
||||
echo "------------------------------------------"
|
||||
echo "[INFO] Verarbeite Projekt in: $TARGET_DIR"
|
||||
echo "------------------------------------------"
|
||||
|
||||
cd "$TARGET_DIR" || continue
|
||||
|
||||
# 1. Container sauber stoppen
|
||||
echo "[1/4] Stoppe laufende Container..."
|
||||
docker compose down
|
||||
|
||||
# 2. Neueste Versionen/Images aus dem Netz ziehen
|
||||
echo "[2/4] Ziehe neueste Docker-Images (Pull)..."
|
||||
docker compose pull
|
||||
|
||||
# 3. Container im Hintergrund neu starten (erzwingt das Update)
|
||||
echo "[3/4] Starte Container neu (erzwinge Update)..."
|
||||
docker compose up -d --build --force-recreate
|
||||
|
||||
# 4. Alte, ungenutzte Image-Reste löschen (spart Speicherplatz)
|
||||
echo "[4/4] Bereinige alte Image-Leichen..."
|
||||
docker image prune -f
|
||||
|
||||
echo "[ERFOLG] Projekt $TARGET_DIR wurde aktualisiert!"
|
||||
else
|
||||
echo "[WARNUNG] Verzeichnis $TARGET_DIR existiert nicht. Überspringe..."
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " ALLE UPDATES ERFOLGREICH DURCHGEFÜHRT! "
|
||||
echo "=========================================="
|
||||
70
xWiki/docker-compose.yml
Normal file
70
xWiki/docker-compose.yml
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
name: xwiki
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
name: op_xwiki_frontend
|
||||
backend:
|
||||
name: op_xwiki_backend
|
||||
traefik:
|
||||
name: traefik
|
||||
external: true
|
||||
|
||||
services:
|
||||
xwiki_db:
|
||||
image: postgres:15-alpine
|
||||
container_name: ${CONTAINER_NAME}_postgres
|
||||
restart: ${RESTART_POLICY}
|
||||
environment:
|
||||
- POSTGRES_USER=${DB_USER}
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
- POSTGRES_DB=${DB_DATABASE}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DB_PATH}
|
||||
target: /var/lib/postgresql/data
|
||||
bind:
|
||||
create_host_path: true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- backend
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
xwiki_web:
|
||||
image: xwiki:lts-postgres-tomcat
|
||||
container_name: ${CONTAINER_NAME}_web
|
||||
restart: ${RESTART_POLICY}
|
||||
environment:
|
||||
- POSTGRES_USER=${DB_USER}
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
- POSTGRES_DB=${DB_DATABASE}
|
||||
- DB_HOST=xwiki_db
|
||||
- JAVA_OPTS=-Xmx1024m
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${DATA_PATH}
|
||||
target: /usr/local/xwiki
|
||||
bind:
|
||||
create_host_path: true
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
- traefik
|
||||
depends_on:
|
||||
xwiki_db:
|
||||
condition: service_healthy
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${SUBDOMAIN}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
|
||||
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=${CERTIFICATE_RESOLVER}"
|
||||
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${CONTAINER_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
Loading…
Reference in a new issue