Compare commits
35 Commits
c45823ee91
...
feature/ve
| Author | SHA1 | Date | |
|---|---|---|---|
| 9650bd8b3c | |||
| 33112f6142 | |||
| fc00c3f627 | |||
| 436a81e2a8 | |||
| fa6780d032 | |||
| 19d41f3041 | |||
| a32e2da6c3 | |||
| 062b30e379 | |||
| b186c22bf2 | |||
| 61853ac2cd | |||
| 56e6a53f0a | |||
| 62a96dc243 | |||
| d4f202f204 | |||
| 49badb74a7 | |||
| 71d080a87e | |||
| 138525835d | |||
| f6e3793193 | |||
| c9b55aa0ed | |||
| b8a6abe100 | |||
| 2930854814 | |||
| d4abe64b0b | |||
| 1d04638be8 | |||
| 02f20a277c | |||
| 0f08168947 | |||
| c976fea1c3 | |||
| e981a365cc | |||
| 42b71394df | |||
| a9143ae8f8 | |||
| dff86e0486 | |||
| f14186deca | |||
| 9afa8808db | |||
| 69323be965 | |||
| 76e3b3938f | |||
| 97b28e9540 | |||
| b886adf877 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -3,3 +3,8 @@ apps/proxy
|
||||
.DS_Store
|
||||
apps/administration/*
|
||||
apps/tools/app/*
|
||||
env/secrets.env
|
||||
infra/core/traefik/data/acme.json
|
||||
infra/**/.env
|
||||
infra/**/*.env.local
|
||||
infra/secrets/*
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -4,3 +4,9 @@
|
||||
[submodule "apps/frontend/src"]
|
||||
path = apps/frontend/src
|
||||
url = https://gitea.mindboost.team/Mindboost/mindboost-webapp.git
|
||||
[submodule "apps/tools/invoiceninja/dockerfiles"]
|
||||
path = apps/tools/invoiceninja/dockerfiles
|
||||
url = https://github.com/invoiceninja/dockerfiles.git
|
||||
[submodule "apps/security/Eduroam Analyzer/asn-updater"]
|
||||
path = apps/security/Eduroam Analyzer/asn-updater
|
||||
url = https://gitea.mindboost.team/mindboost/education-flagger.git
|
||||
|
||||
34
Jenkinsfile
vendored
Normal file
34
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
stages {
|
||||
stage('Checkout Code & Submodules') {
|
||||
steps {
|
||||
git branch: 'main', url: 'git@github.com:your-org/my-main-repo.git', credentialsId: 'git-credentials'
|
||||
sh 'git submodule update --init --recursive'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Run Backend Pipeline') {
|
||||
steps {
|
||||
build job: 'backend-pipeline', wait: true
|
||||
}
|
||||
}
|
||||
|
||||
stage('Run Frontend Pipeline') {
|
||||
steps {
|
||||
build job: 'frontend-pipeline', wait: true
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy Infrastructure') {
|
||||
steps {
|
||||
sshagent(['jenkins-ssh-key']) {
|
||||
sh "ssh user@server 'cd /opt/myapp && git pull origin main && docker compose up -d'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Makefile
Normal file
42
Makefile
Normal file
@@ -0,0 +1,42 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
# Environment selection
|
||||
ENV ?= development
|
||||
COMMON_ENV := infra/env/$(ENV)/common.env
|
||||
|
||||
# Helper to pass env files if present
|
||||
define with_env
|
||||
$(foreach f,$(1),$(if $(wildcard $(f)),--env-file $(f),))
|
||||
endef
|
||||
|
||||
.PHONY: bootstrap proxy-up proxy-down proxy-logs app-up app-down app-logs ps
|
||||
|
||||
bootstrap:
|
||||
@bash scripts/infra/bootstrap.sh
|
||||
|
||||
proxy-up:
|
||||
@docker compose -f infra/core/traefik/docker-compose.yml $(call with_env,$(COMMON_ENV) infra/apps/traefik/.env) up -d
|
||||
|
||||
proxy-down:
|
||||
@docker compose -f infra/core/traefik/docker-compose.yml $(call with_env,$(COMMON_ENV) infra/apps/traefik/.env) down
|
||||
|
||||
proxy-logs:
|
||||
@docker compose -f infra/core/traefik/docker-compose.yml $(call with_env,$(COMMON_ENV) infra/apps/traefik/.env) logs -f
|
||||
|
||||
# Usage: make app-up APP=nextcloud
|
||||
APP ?=
|
||||
app-up:
|
||||
@test -n "$(APP)" || (echo "APP not set. Example: make app-up APP=nextcloud" && exit 1)
|
||||
@docker compose -f infra/apps/$(APP)/docker-compose.yml $(call with_env,$(COMMON_ENV) infra/apps/$(APP)/.env) up -d
|
||||
|
||||
app-down:
|
||||
@test -n "$(APP)" || (echo "APP not set. Example: make app-down APP=nextcloud" && exit 1)
|
||||
@docker compose -f infra/apps/$(APP)/docker-compose.yml $(call with_env,$(COMMON_ENV) infra/apps/$(APP)/.env) down
|
||||
|
||||
app-logs:
|
||||
@test -n "$(APP)" || (echo "APP not set. Example: make app-logs APP=nextcloud" && exit 1)
|
||||
@docker compose -f infra/apps/$(APP)/docker-compose.yml $(call with_env,$(COMMON_ENV) infra/apps/$(APP)/.env) logs -f
|
||||
|
||||
ps:
|
||||
@docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Networks}}'
|
||||
|
||||
34
README.md
34
README.md
@@ -2,6 +2,30 @@
|
||||
|
||||
All the software used and hosted by mindboost organized in containers.
|
||||
|
||||
## New Infra (v2) Overview
|
||||
|
||||
This repo now includes a modular, best‑practice infrastructure under `infra/` to make replication and selective deployment easy. It is centered on Traefik as the reverse proxy with automatic TLS via Let's Encrypt, environment layering, and pick‑what‑you‑need application stacks.
|
||||
|
||||
- Core: `infra/core/traefik` — Traefik with HTTPS (ACME), dashboard, and sane defaults
|
||||
- Apps: `infra/apps/<service>` — self‑contained stacks (e.g., `nextcloud`)
|
||||
- Env: `infra/env/<environment>/common.env` — environment defaults (dev/prod)
|
||||
- Secrets: `infra/secrets/` — local secret storage (ignored by git)
|
||||
- Make targets: top‑level `Makefile` to bootstrap, start proxy, and start apps
|
||||
|
||||
Quickstart
|
||||
|
||||
- Copy `infra/env/development/common.env` and adjust domains and ACME email.
|
||||
- Create the shared proxy network and ACME storage: `make bootstrap`
|
||||
- Start Traefik: `make proxy-up`
|
||||
- Start a service, e.g. Nextcloud: `make app-up APP=nextcloud`
|
||||
|
||||
Notes
|
||||
|
||||
- Traefik dashboard is exposed at `TRAEFIK_DASHBOARD_DOMAIN` with optional basic auth.
|
||||
- Services connect to an external `proxy` network for routing, plus their own internal network.
|
||||
- Each app has its own `.env.example`; copy to `.env` and adjust.
|
||||
- The legacy `apps/` structure remains as-is; new infra is additive and can coexist.
|
||||
|
||||
## Project Structure
|
||||
|
||||
./apps/
|
||||
@@ -111,7 +135,7 @@ Each service's `docker-compose.yml` file references the appropriate `.env` file
|
||||
services:
|
||||
backend:
|
||||
env_file:
|
||||
- ../../env/${ENVIRONMENT}/backend.env
|
||||
- ../../env/${ENVIRONMENT:-development}/backend.env
|
||||
```
|
||||
|
||||
## Networking
|
||||
@@ -128,12 +152,6 @@ Our infrastructure uses a two-tier network model to enhance security and isolate
|
||||
- These networks are not directly accessible from the internet and provide secure communication between public and internal services.
|
||||
- Examples: backend_network, database_network, etc.
|
||||
|
||||
Service Network Configuration:
|
||||
- Frontend: Connected to proxy_network and backend_network
|
||||
- Backend API: Connected to backend_network and database_network
|
||||
- Database: Connected only to database_network
|
||||
- Traefik: Connected only to proxy_network
|
||||
|
||||
This structure ensures that:
|
||||
- The proxy (Traefik) can route traffic to public-facing services.
|
||||
- Internal services (like databases) are not directly accessible from the proxy network.
|
||||
@@ -163,7 +181,7 @@ The `volumes/` folder contains subdirectories for different volumes used by vari
|
||||
|
||||
Each subdirectory corresponds to a specific service or group of services, containing the persistent data that needs to be preserved across container restarts or redeployments.
|
||||
|
||||
When configuring Docker Compose files, reference these volume paths to ensure data persistence. For example:
|
||||
When configuring Docker Compose files, reference these volume paths to ensure data persistence.
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
|
||||
36
apps/backend/database/docker-compose.yml
Normal file
36
apps/backend/database/docker-compose.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
### Database (./apps/database/docker-compose.yml)
|
||||
# - [ ] Create a MariaDB service
|
||||
# - [ ] Configure volumes for persistent storage of database data
|
||||
secrets:
|
||||
mariadb_root:
|
||||
file: ${ROOT_DIR:-../../..}/env/secrets.env
|
||||
services:
|
||||
database:
|
||||
secrets:
|
||||
- mariadb_root
|
||||
profiles: ["all", "database", "backend", "app"]
|
||||
image: mariadb:latest
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-mariadb-${ENVIRONMENT:-development}
|
||||
command: --bind-address=0.0.0.0
|
||||
env_file:
|
||||
- ${ROOT_DIR:-../../..}/env/${ENVIRONMENT:-development}/.env.database
|
||||
volumes:
|
||||
- backend_mariadb_data:/var/lib/mysql
|
||||
- ./healthcheck.sh:/usr/local/bin/healthcheck.sh
|
||||
networks:
|
||||
- backend
|
||||
- database
|
||||
healthcheck:
|
||||
test: ["CMD", "bash", "/usr/local/bin/healthcheck.sh"]
|
||||
interval: 1s
|
||||
retries: 3
|
||||
# TODO: ADMINER IS NOT PREPARED FOR TRAEFIK
|
||||
networks:
|
||||
backend:
|
||||
name: ${INFRASTRUCTURE_LABEL:-default}-backend-${ENVIRONMENT:-development}
|
||||
database:
|
||||
name: ${INFRASTRUCTURE_LABEL:-default}-database-${ENVIRONMENT:-development}
|
||||
volumes:
|
||||
backend_mariadb_data:
|
||||
driver: local
|
||||
name: ${INFRASTRUCTURE_LABEL:-default}_mariadb_${ENVIRONMENT:-development}
|
||||
33
apps/backend/database/healthcheck.sh
Executable file
33
apps/backend/database/healthcheck.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Credentials from environment variables
|
||||
MYSQL_USER="${MARIADB_USER:-default}"
|
||||
MYSQL_PASSWORD="${MARIADB_PASSWORD:-default}"
|
||||
MYSQL_HOST="127.0.0.1"
|
||||
|
||||
ROOT_PASSWORD=$(cat /run/secrets/mariadb_root)
|
||||
|
||||
echo "🔑 READ ROOT PASSWORD FROM SECRETS"
|
||||
|
||||
# Check if MariaDB is running
|
||||
if ! mariadb -h "$MYSQL_HOST" -u root -p"$ROOT_PASSWORD" -e "SELECT 1;" &>/dev/null; then
|
||||
echo "❌ MariaDB is not responding"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if a specific user exists
|
||||
USER_EXISTS=$(mariadb -h "$MYSQL_HOST" -u root -p"$ROOT_PASSWORD" -e "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '${MYSQL_USER}');" | tail -n 1)
|
||||
|
||||
if [ "$USER_EXISTS" -ne 1 ]; then
|
||||
echo "❌ User '${MYSQL_USER}' does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if the user can log in with the provided password
|
||||
if ! mariadb -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SELECT 1;" &>/dev/null; then
|
||||
echo "❌ User '${MYSQL_USER}' exists, but authentication failed with the provided password."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ MariaDB is healthy"
|
||||
exit 0
|
||||
74
apps/backend/database/init-user.sh
Normal file
74
apps/backend/database/init-user.sh
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
echo "🔄 Running MariaDB initialization script..."
|
||||
|
||||
# Wait until MariaDB is ready
|
||||
until mysqladmin ping -h localhost --silent; do
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "✅ MariaDB is ready. Checking root credentials..."
|
||||
|
||||
# Try logging in with the root password
|
||||
if ! mysql -u root -p"$MARIADB_ROOT_PASSWORD" -e "SELECT 1;" &>/dev/null; then
|
||||
echo "❌ ERROR: Root password in .env does not match the database!"
|
||||
echo "🔄 Attempting to reset the root password..."
|
||||
|
||||
# Stop MariaDB safely
|
||||
echo "⚠️ Stopping MariaDB..."
|
||||
service mysql stop || pkill mysqld
|
||||
sleep 5
|
||||
|
||||
# Start MariaDB in recovery mode
|
||||
echo "🚀 Starting MariaDB in recovery mode..."
|
||||
mysqld_safe --skip-grant-tables --skip-networking &
|
||||
sleep 5
|
||||
|
||||
# Reset root password
|
||||
echo "🔐 Resetting root password..."
|
||||
mysql -u root <<EOSQL
|
||||
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}';
|
||||
ALTER USER 'root'@'%' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}';
|
||||
FLUSH PRIVILEGES;
|
||||
EOSQL
|
||||
|
||||
echo "✅ Root password reset successfully!"
|
||||
|
||||
# Restart MariaDB in normal mode
|
||||
echo "🔄 Restarting MariaDB in production mode..."
|
||||
service mysql stop || pkill mysqld
|
||||
sleep 3
|
||||
mysqld_safe &
|
||||
sleep 5
|
||||
else
|
||||
echo "✅ Root password is correct."
|
||||
fi
|
||||
|
||||
# Check if the database exists
|
||||
DB_EXISTS=$(mysql -u root -p"$MARIADB_ROOT_PASSWORD" -e "SHOW DATABASES LIKE '${MARIADB_DATABASE}';" | grep "${MARIADB_DATABASE}" > /dev/null; echo "$?")
|
||||
|
||||
if [ "$DB_EXISTS" -ne 0 ]; then
|
||||
echo "⚠️ Database '${MARIADB_DATABASE}' does not exist. Creating it now..."
|
||||
mysql -u root -p"$MARIADB_ROOT_PASSWORD" -e "CREATE DATABASE ${MARIADB_DATABASE};"
|
||||
echo "✅ Database '${MARIADB_DATABASE}' created!"
|
||||
else
|
||||
echo "✅ Database '${MARIADB_DATABASE}' already exists."
|
||||
fi
|
||||
|
||||
# Ensure the database user exists and has the correct password
|
||||
USER_EXISTS=$(mysql -u root -p"$MARIADB_ROOT_PASSWORD" -e "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '${MARIADB_USER}');" | tail -n 1)
|
||||
|
||||
if [ "$USER_EXISTS" -eq 0 ]; then
|
||||
echo "⚠️ User '${MARIADB_USER}' does not exist. Creating it now..."
|
||||
mysql -u root -p"$MARIADB_ROOT_PASSWORD" <<EOSQL
|
||||
CREATE USER '${MARIADB_USER}'@'%' IDENTIFIED BY '${MARIADB_PASSWORD}';
|
||||
GRANT ALL PRIVILEGES ON ${MARIADB_DATABASE}.* TO '${MARIADB_USER}'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
EOSQL
|
||||
echo "✅ User '${MARIADB_USER}' created and granted access to '${MARIADB_DATABASE}'!"
|
||||
else
|
||||
echo "✅ User '${MARIADB_USER}' already exists. Ensuring correct password."
|
||||
mysql -u root -p"$MARIADB_ROOT_PASSWORD" -e "ALTER USER '${MARIADB_USER}'@'%' IDENTIFIED BY '${MARIADB_PASSWORD}'; FLUSH PRIVILEGES;"
|
||||
echo "✅ Password for '${MARIADB_USER}' updated!"
|
||||
fi
|
||||
|
||||
echo "🎉 MariaDB initialization complete!"
|
||||
48
apps/backend/docker-compose.overwrite.yml
Normal file
48
apps/backend/docker-compose.overwrite.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
### Backend (./apps/backend/docker-compose.yml)
|
||||
include:
|
||||
- ./database/docker-compose.yml
|
||||
services:
|
||||
backend:
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-backend-laravel-${ENVIRONMENT:-development}
|
||||
profiles: ["laravel", "backend", "all", "app"]
|
||||
ports:
|
||||
- "${LARAVEL_PORT:-8000}:8000"
|
||||
- "${LARAVEL_VITE_PORT:-5173}:5173"
|
||||
env_file:
|
||||
- ../../env/${ENVIRONMENT:-development}/.env.backend
|
||||
volumes:
|
||||
- ./src/entrypoint.sh:/usr/local/bin/entrypoint.sh
|
||||
depends_on:
|
||||
- database
|
||||
build:
|
||||
context: ./src
|
||||
dockerfile: Dockerfile
|
||||
networks:
|
||||
- backend
|
||||
labels:
|
||||
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
||||
- "traefik.http.routers.backend.entrypoints=${TRAEFIK_ENTRYPOINT}"
|
||||
- "traefik.http.routers.backend.rule=Host(`${BACKEND_DOMAIN}`)"
|
||||
- "traefik.http.routers.backend.tls=true"
|
||||
- "traefik.http.routers.backend.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
|
||||
- "traefik.http.routers.backend.tls.domains[0].main=`${BACKEND_DOMAIN}`"
|
||||
- "traefik.http.services.backend.loadbalancer.server.port=${BACKEND_PORT:-8000}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
backend-redis:
|
||||
image: redis:alpine
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-backend-redis-${ENVIRONMENT:-development}
|
||||
profiles: ["redis", "backend", "all"]
|
||||
env_file:
|
||||
- ../../env/${ENVIRONMENT:-development}/.env.backend
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-laravel-redis-passwort} # Redis Passwort eingeben
|
||||
volumes:
|
||||
- backend_redis_data:/data
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
backend_redis_data:
|
||||
driver: local
|
||||
name: "${INFRASTRUCTURE_LABEL:-default}_backend_redis_data"
|
||||
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
### Backend (./apps/backend/docker-compose.yml)
|
||||
|
||||
include:
|
||||
- ./database/docker-compose.yml
|
||||
services:
|
||||
backend:
|
||||
container_name: ${INFRASTRUCTURE_LABEL}-laravel-${ENVIRONMENT}
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-backend-laravel-${ENVIRONMENT:-development}
|
||||
profiles: ["laravel", "backend", "all", "app"]
|
||||
env_file:
|
||||
- ../../env/.env.all
|
||||
- ../../env/${ENVIRONMENT}/.env.proxy
|
||||
- ../../env/${ENVIRONMENT}/.env.database
|
||||
- ../../env/${ENVIRONMENT}/.env.backend
|
||||
- ../../env/${ENVIRONMENT:-development}/.env.backend
|
||||
volumes:
|
||||
- ./src/entrypoint.sh:/usr/local/bin/entrypoint.sh
|
||||
depends_on:
|
||||
- database
|
||||
build:
|
||||
context: ./src
|
||||
dockerfile: Dockerfile
|
||||
networks:
|
||||
- backend
|
||||
labels:
|
||||
- "traefik.enable=${TRAEFIK_ENABLE}"
|
||||
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
||||
- "traefik.http.routers.backend.entrypoints=${TRAEFIK_ENTRYPOINT}"
|
||||
- "traefik.http.routers.backend.rule=Host(`${BACKEND_DOMAIN}`)"
|
||||
- "traefik.http.routers.backend.tls=true"
|
||||
@@ -23,14 +25,21 @@ services:
|
||||
- "traefik.http.routers.backend.tls.domains[0].main=`${BACKEND_DOMAIN}`"
|
||||
- "traefik.http.services.backend.loadbalancer.server.port=${BACKEND_PORT:-8000}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
# Traefik-Crowdsec Stack
|
||||
backend-redis:
|
||||
image: redis:alpine
|
||||
container_name: ${INFRASTRUCTURE_LABEL}-laravelredis-${ENVIRONMENT}
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-backend-redis-${ENVIRONMENT:-development}
|
||||
profiles: ["redis", "backend", "all"]
|
||||
env_file:
|
||||
- ../../env/${ENVIRONMENT:-development}/.env.backend
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes --requirepass laravel-redis-passwort # Redis Passwort eingeben
|
||||
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-laravel-redis-passwort} # Redis Passwort eingeben
|
||||
volumes:
|
||||
- ../../volumes/backend/redis:/data
|
||||
networks:
|
||||
backend:
|
||||
- backend_redis_data:/data
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
backend_redis_data:
|
||||
driver: local
|
||||
name: "${INFRASTRUCTURE_LABEL}_backend_redis_data"
|
||||
|
||||
|
||||
|
||||
Submodule apps/backend/src updated: 0e3ecbb0a7...8dcadaec5c
@@ -1,40 +0,0 @@
|
||||
### Database (./apps/database/docker-compose.yml)
|
||||
# - [ ] Create a MariaDB service
|
||||
# - [ ] Configure volumes for persistent storage of database data
|
||||
# - [ ] Set up environment variables using the new structure (../../env/${ENVIRONMENT}/database.env)
|
||||
# - [ ] Configure networking to allow connections from the backend service
|
||||
# - [ ] Set up regular backup jobs for the database
|
||||
# - [ ] Configure appropriate resource limits and restart policies
|
||||
services:
|
||||
database:
|
||||
profiles: ["all", "mariadb", "backend", "app"]
|
||||
image: mariadb:latest
|
||||
container_name: ${INFRASTRUCTURE_LABEL}-mariadb-${ENVIRONMENT}
|
||||
command: --bind-address=0.0.0.0
|
||||
hostname: ${MARIADB_HOST}
|
||||
env_file:
|
||||
- ../../env/.env.all
|
||||
- ../../env/${ENVIRONMENT:-development}/.env.database
|
||||
- ../../env/${ENVIRONMENT:-development}/.env.proxy
|
||||
environment:
|
||||
- MARIADB_USER=${MARIADB_USER}
|
||||
- MARIADB_DATABASE=${MARIADB_DATABASE}
|
||||
- MARIADB_PASSWORD=${MARIADB_PASSWORD}
|
||||
- MARIADB_ROOT_PASSWORD=root-mindboost
|
||||
volumes:
|
||||
- ../../volumes/database/mariadb:/var/lib/mysql
|
||||
networks:
|
||||
- backend
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
interval: 10s
|
||||
retries: 3
|
||||
adminer:
|
||||
profiles: ["all", "mariadb", "backend", "app"]
|
||||
image: adminer
|
||||
container_name: local_adminer
|
||||
restart: always
|
||||
ports:
|
||||
- 8082:8080
|
||||
networks:
|
||||
- backend
|
||||
8
apps/develop/adminer/docker-compose.overwrite.yml
Normal file
8
apps/develop/adminer/docker-compose.overwrite.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
services:
|
||||
adminer:
|
||||
profiles: ["all", "database", "backend", "adminer", "app"]
|
||||
image: adminer
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-adminer-${ENVIRONMENT:-development}
|
||||
restart: always
|
||||
ports:
|
||||
- ${ADMINER_PORT:-0}:8080
|
||||
20
apps/develop/adminer/docker-compose.yml
Normal file
20
apps/develop/adminer/docker-compose.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
services:
|
||||
adminer:
|
||||
profiles: ["all", "database", "backend", "adminer", "app"]
|
||||
image: adminer
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-adminer-${ENVIRONMENT:-development}
|
||||
restart: always
|
||||
ports:
|
||||
- ${ADMINER_PORT:-0}:8080
|
||||
networks:
|
||||
- database
|
||||
- proxy
|
||||
labels:
|
||||
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_adminer.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_adminer.rule=Host(`${ADMINER_DOMAIN:-adminer.local}`)"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_adminer.tls=true"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_adminer.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-http_resolver}"
|
||||
- 'traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_adminer.service=adminer'
|
||||
- "traefik.http.adminer.cloud.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK:-default}"
|
||||
@@ -1,7 +1,7 @@
|
||||
### Develop (./apps/develop/docker-compose.yml)
|
||||
# - [ ] Create services for Gitea, Jenkins, and Adminer
|
||||
# - [ ] Configure volumes for persistent storage of Git repositories, Jenkins data, and Adminer settings
|
||||
# - [ ] Set up environment variables using the new structure (../../env/${ENVIRONMENT}/develop.env)
|
||||
# - [ ] Set up environment variables using the new structure (../../env/${ENVIRONMENT:-development}/develop.env)
|
||||
# - [ ] Configure networking to allow these services to communicate with each other and the necessary application services
|
||||
# - [ ] Set up access controls and security measures for development tools
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ services:
|
||||
depends_on:
|
||||
- gitea_db
|
||||
labels:
|
||||
- "traefik.enable=${TRAEFIK_ENABLE}"
|
||||
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
||||
- "traefik.http.routers.gitea.entrypoints=${TRAEFIK_ENTRYPOINT}"
|
||||
- "traefik.http.routers.gitea.rule=(Host(`${GITEA_DOMAIN})`)"
|
||||
- "traefik.http.routers.gitea.tls=true"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
version: '3.8'
|
||||
|
||||
### Jenkins (./apps/frontend/docker-compose.yml)
|
||||
services:
|
||||
jenkins:
|
||||
image: jenkins/jenkins:lts
|
||||
@@ -7,7 +6,10 @@ services:
|
||||
ports:
|
||||
- "50000:50000" # Jenkins Agent Port
|
||||
volumes:
|
||||
- jenkins_home:/var/jenkins_home
|
||||
- ../../../volumes/develop/jenkins:/var/jenkins_home
|
||||
- ./plugins.yml:/usr/share/jenkins/ref/plugins.yml
|
||||
depends_on:
|
||||
- jenkins-plugins
|
||||
environment:
|
||||
- JAVA_OPTS=-Djenkins.install.runSetupWizard=false
|
||||
networks:
|
||||
@@ -21,6 +23,14 @@ services:
|
||||
- "traefik.http.services.jenkins.loadbalancer.server.port=8080" # interner Port von Jenkins
|
||||
- "traefik.docker.network=proxy"
|
||||
|
||||
jenkins-plugins:
|
||||
image: jenkins/jenkins:lts-jdk17
|
||||
command: >
|
||||
jenkins-plugin-cli -f /usr/share/jenkins/ref/plugins.yml --available-updates --output txt > /usr/share/jenkins/ref/plugins.yml
|
||||
volumes:
|
||||
- ./plugins.yml:/usr/share/jenkins/ref/plugins.yml
|
||||
restart: "no"
|
||||
|
||||
volumes:
|
||||
jenkins_home:
|
||||
driver: local
|
||||
|
||||
0
apps/develop/jenkins/plugins.yml
Normal file
0
apps/develop/jenkins/plugins.yml
Normal file
@@ -14,6 +14,9 @@
|
||||
## Stellen Sie sicher, dass die .env.all Datei im angegebenen Verzeichnis existiert und den ENVIRONMENT Wert enthält.
|
||||
##
|
||||
|
||||
configs:
|
||||
all:
|
||||
file: ../env/.env.all
|
||||
include:
|
||||
- path: ./proxy/docker-compose.yml
|
||||
env_file:
|
||||
@@ -23,7 +26,6 @@ include:
|
||||
env_file:
|
||||
- ../env/.env.all
|
||||
- ../env/${ENVIRONMENT:-development}/.env.frontend
|
||||
- ../env/${ENVIRONMENT:-development}/.env.proxy
|
||||
- path: ./backend/docker-compose.yml
|
||||
- path: ./database/docker-compose.yml
|
||||
- path: ./website/docker-compose.yml
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
##
|
||||
## DIESES COMPOSE FILE IST FÜR DIE LOKALE ENTWICKLUNG MITTELS DOCKER
|
||||
##
|
||||
## Der Inhalt von frontend und von backend wird über ein volume eingebunden, dass
|
||||
## bedeutet Änderungen innerhalb der Projektordner ./frontend/src und ./backend/src
|
||||
## Ändern direkt die Werte innerhalb des Containers wie z.B. das Austauschen einer Grafik.
|
||||
##
|
||||
## Datenbank ebenfalls lokal und KEIN reverse-Proxy (traefik)
|
||||
## Image der DB ist auf ARM Archtektur (Apple Silicon) ausgelegt
|
||||
##
|
||||
services:
|
||||
mariadb:
|
||||
image: mariadb:latest
|
||||
container_name: local_mariadb
|
||||
command: --bind-address=0.0.0.0
|
||||
environment:
|
||||
- ALLOW_EMPTY_PASSWORD
|
||||
- MARIADB_USER=mindboost
|
||||
- MARIADB_DATABASE=mindboost
|
||||
- MARIADB_PASSWORD=mindboost
|
||||
- MARIADB_ROOT_PASSWORD=root-mindboost
|
||||
volumes:
|
||||
- ../volumes/daten/mariadb:/var/lib/mysql
|
||||
networks:
|
||||
- backend
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend/src
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: local_frontend
|
||||
volumes:
|
||||
- ./frontend/src:/app
|
||||
- /app/node_modules
|
||||
ports:
|
||||
- "3000:3000"
|
||||
networks:
|
||||
- backend
|
||||
environment:
|
||||
NODE_ENV: development
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ./backend/src
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: local_backend
|
||||
ports:
|
||||
- "8000:8000"
|
||||
- "5173:5173"
|
||||
volumes:
|
||||
- ./backend/src:/var/www
|
||||
networks:
|
||||
- backend
|
||||
depends_on:
|
||||
- mariadb
|
||||
adminer:
|
||||
image: adminer
|
||||
container_name: local_adminer
|
||||
restart: always
|
||||
ports:
|
||||
- 8080:8080
|
||||
networks:
|
||||
- backend
|
||||
networks:
|
||||
backend:
|
||||
external: false
|
||||
@@ -1,107 +0,0 @@
|
||||
##
|
||||
## DIESES COMPOSE FILE IST FÜR DIE LOKALE ENTWICKLUNG MITTELS DOCKER
|
||||
##
|
||||
## Der Inhalt von frontend und von backend wird über ein volume eingebunden, dass
|
||||
## bedeutet Änderungen innerhalb der Projektordner ./frontend/src und ./backend/src
|
||||
## Ändern direkt die Werte innerhalb des Containers wie z.B. das Austauschen einer Grafik.
|
||||
##
|
||||
## Datenbank ebenfalls lokal und KEIN reverse-Proxy (traefik)
|
||||
## Image der DB ist auf ARM Archtektur (Apple Silicon) ausgelegt
|
||||
##
|
||||
|
||||
services:
|
||||
prod-mariadb:
|
||||
image: mariadb:latest
|
||||
container_name: prod-mariadb
|
||||
hostname: mariadb
|
||||
command: --bind-address=0.0.0.0
|
||||
env_file:
|
||||
- ../config/.env.db
|
||||
networks:
|
||||
- ${BACKEND_NETWORK}
|
||||
volumes:
|
||||
- ../volumes/daten/mariadb:/var/lib/mysql
|
||||
prod-redis:
|
||||
image: redis:alpine
|
||||
container_name: prod-redis
|
||||
hostname: redis
|
||||
networks:
|
||||
- ${BACKEND_NETWORK}
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes --requirepass laravel-redis-passwort # Redis Passwort eingeben
|
||||
volumes:
|
||||
- ../volumes/daten/redis:/data
|
||||
prod-frontend:
|
||||
build:
|
||||
context: ./frontend/src
|
||||
dockerfile: Dockerfile
|
||||
container_name: prod-frontend
|
||||
networks:
|
||||
- ${BACKEND_NETWORK}
|
||||
- ${TRAEFIK_NETWORK}
|
||||
env_file:
|
||||
- ../config/.env.frontend
|
||||
- ../config/.env.traefik
|
||||
labels:
|
||||
- "traefik.enable=${TRAEFIK_ENABLE}"
|
||||
- "traefik.http.routers.prod-frontend.entrypoints=${TRAEFIK_ROUTER_FRONTEND_ENTRYPOINT}"
|
||||
- "traefik.http.routers.prod-frontend.rule=${TRAEFIK_ROUTER_FRONTEND_RULE}"
|
||||
- "traefik.http.routers.prod-frontend.tls=${TRAEFIK_ROUTER_FRONTEND_TLS}"
|
||||
- "traefik.http.routers.prod-frontend.tls.certresolver=${TRAEFIK_ROUTER_FRONTEND_CERTRESOLVER}"
|
||||
- "traefik.http.routers.prod-frontend.tls.domains[0].main=${TRAEFIK_ROUTER_FRONTEND_TLS_DOMAIN_MAIN}"
|
||||
- "traefik.http.routers.prod-frontend.tls.domains[0].sans=${TRAEFIK_ROUTER_FRONTEND_TLS_DOMAIN_SANS}"
|
||||
- "traefik.http.services.prod-frontend.loadbalancer.server.port=${TRAEFIK_SERVICE_FRONTEND_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
prod-backend:
|
||||
build:
|
||||
context: ./backend/src
|
||||
dockerfile: Dockerfile
|
||||
env_file:
|
||||
- ../config/.env.backend
|
||||
- ../config/.env.traefik
|
||||
labels:
|
||||
- "traefik.enable=${TRAEFIK_ENABLE}"
|
||||
- "traefik.http.routers.prod-backend.entrypoints=${TRAEFIK_ROUTER_BACKEND_ENTRYPOINT}"
|
||||
- "traefik.http.routers.prod-backend.rule=${TRAEFIK_ROUTER_BACKEND_RULE}"
|
||||
- "traefik.http.routers.prod-backend.tls=${TRAEFIK_ROUTER_BACKEND_TLS}"
|
||||
- "traefik.http.routers.prod-backend.tls.certresolver=${TRAEFIK_ROUTER_BACKEND_CERTRESOLVER}"
|
||||
- "traefik.http.routers.prod-backend.tls.domains[0].main=${TRAEFIK_ROUTER_BACKEND_TLS_DOMAIN_MAIN}"
|
||||
- "traefik.http.services.prod-backend.loadbalancer.server.port=${TRAEFIK_SERVICE_BACKEND_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
networks:
|
||||
- ${BACKEND_NETWORK}
|
||||
- ${TRAEFIK_NETWORK}
|
||||
depends_on:
|
||||
- prod-mariadb
|
||||
# Traefik-Crowdsec Stack
|
||||
crowdsec:
|
||||
extends:
|
||||
file: ./proxy/docker-compose.yml
|
||||
service: crowdsec
|
||||
networks:
|
||||
- ${TRAEFIK_NETWORK}
|
||||
|
||||
traefik:
|
||||
extends:
|
||||
file: ./proxy/docker-compose.yml
|
||||
service: traefik
|
||||
networks:
|
||||
- ${TRAEFIK_NETWORK}
|
||||
depends_on:
|
||||
- crowdsec
|
||||
|
||||
traefik_crowdsec_bouncer:
|
||||
extends:
|
||||
file: ./proxy/docker-compose.yml
|
||||
service: traefik_crowdsec_bouncer
|
||||
networks:
|
||||
- ${TRAEFIK_NETWORK}
|
||||
depends_on:
|
||||
- crowdsec
|
||||
- traefik
|
||||
|
||||
networks:
|
||||
prod-backend:
|
||||
external: false
|
||||
proxy:
|
||||
external: true
|
||||
19
apps/frontend/docker-compose.overwrite.yml
Normal file
19
apps/frontend/docker-compose.overwrite.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
services:
|
||||
webapp:
|
||||
build:
|
||||
context: ./src
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
BACKEND_URL: ${BACKEND_URL:-http://localhost:8000} # this argument is important on build to set the server url!
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-frontend-${ENVIRONMENT:-development}
|
||||
profiles: ["webapp", "frontend", "all", "app"]
|
||||
ports:
|
||||
- 3000:3000
|
||||
labels:
|
||||
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
||||
- "traefik.http.routers.webapp.service=webapp"
|
||||
- "traefik.http.routers.webapp.entrypoints=${TRAEFIK_ENTRYPOINT}"
|
||||
- 'traefik.http.routers.webapp.rule=Host(`${FRONTEND_DOMAIN}`) || Host(`${FRONTEND_DOMAIN_2}`)'
|
||||
- "traefik.http.services.webapp.loadbalancer.server.port=3000"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
@@ -1,27 +1,17 @@
|
||||
### Frontend (./apps/frontend/docker-compose.yml)
|
||||
# - [ ] Create a Vue.js frontend service
|
||||
# - [ ] Set up a Node.js environment for the frontend
|
||||
# - [ ] Configure volumes for persistent storage of frontend assets
|
||||
# - [ ] Set up environment variables using the new structure (../../env/${ENVIRONMENT}/frontend.env)
|
||||
# - [ ] Configure networking to communicate with the backend service
|
||||
# - [ ] Set up healthchecks for the frontend service
|
||||
services:
|
||||
webapp:
|
||||
build:
|
||||
context: ./src
|
||||
dockerfile: Dockerfile
|
||||
container_name: ${INFRASTRUCTURE_LABEL}-frontend-${ENVIRONMENT}
|
||||
args:
|
||||
BACKEND_URL: ${BACKEND_URL:-http://localhost:8000} # this argument is important on build to set the backend server url!
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-frontend-${ENVIRONMENT:-development}
|
||||
profiles: ["webapp", "frontend", "all", "app"]
|
||||
depends_on:
|
||||
- database
|
||||
- backend
|
||||
labels:
|
||||
- "traefik.enable=${TRAEFIK_ENABLE}"
|
||||
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
||||
- "traefik.http.routers.webapp.service=webapp"
|
||||
- "traefik.http.routers.webapp.entrypoints=${TRAEFIK_ENTRYPOINT}"
|
||||
- 'traefik.http.routers.webapp.rule=Host(`${FRONTEND_DOMAIN}`) || Host(`${FRONTEND_DOMAIN_2}`)'
|
||||
- "traefik.http.routers.webapp.tls=true"
|
||||
- "traefik.http.routers.webapp.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
|
||||
- "traefik.http.routers.webapp.tls.domains[0].main=${FRONTEND_DOMAIN}"
|
||||
- "traefik.http.routers.webapp.tls.domains[0].sans=${FRONTEND_DOMAIN_2}"
|
||||
- "traefik.http.services.webapp.loadbalancer.server.port=3000"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
Submodule apps/frontend/src updated: 2d8bcb6067...078571bc57
11
apps/security/Eduroam Analyzer/.env.example
Normal file
11
apps/security/Eduroam Analyzer/.env.example
Normal file
@@ -0,0 +1,11 @@
|
||||
# MaxMind (create a free GeoLite2 license key in your MaxMind account)
|
||||
MAXMIND_LICENSE_KEY=your_maxmind_license_key
|
||||
|
||||
# PeeringDB (optional; reduces rate limits)
|
||||
PDB_API_KEY=your_peeringdb_api_key
|
||||
|
||||
# existing Traefik/proxy network name (must already exist)
|
||||
PROXY_NETWORK=proxy
|
||||
|
||||
# update interval in seconds (30 days)
|
||||
UPDATE_INTERVAL_SECONDS=2592000
|
||||
1
apps/security/Eduroam Analyzer/.gitignore
vendored
Normal file
1
apps/security/Eduroam Analyzer/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.env
|
||||
16
apps/security/Eduroam Analyzer/Dockerfile
Normal file
16
apps/security/Eduroam Analyzer/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM golang:1.22-alpine AS build
|
||||
WORKDIR /src
|
||||
COPY go.mod ./
|
||||
RUN go mod download
|
||||
COPY main.go ./
|
||||
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/asn-header-service
|
||||
|
||||
FROM alpine:3.20
|
||||
RUN adduser -D -H -u 10001 app
|
||||
USER 10001
|
||||
WORKDIR /app
|
||||
COPY --from=build /out/asn-header-service /app/asn-header-service
|
||||
EXPOSE 8080
|
||||
ENV ADDR=:8080
|
||||
ENTRYPOINT ["/app/asn-header-service"]
|
||||
|
||||
89
apps/security/Eduroam Analyzer/README.md
Normal file
89
apps/security/Eduroam Analyzer/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# NREN / ASN Detection Service
|
||||
|
||||
Dieses Projekt stellt einen **minimalen Microservice** bereit, um **Hochschul- und Forschungsnetzwerke (NRENs)** anhand der **Autonomous System Number (ASN)** zu erkennen.
|
||||
|
||||
Der Zweck ist es, **Anfragen aus Hochschulnetzen (z. B. eduroam)** zu identifizieren, um **Research-bezogene Services kostenlos oder bevorzugt bereitzustellen**.
|
||||
|
||||
Das System dient ausschließlich der **Netzwerk-Klassifikation** und **ersetzt keine Authentifizierung**.
|
||||
|
||||
---
|
||||
|
||||
## Ziel
|
||||
|
||||
- Erkennen, ob eine Anfrage aus einem **Hochschul- oder Forschungsnetz** stammt
|
||||
- Bereitstellung eines **Header-Hinweises** für nachgelagerte Services
|
||||
- Grundlage für Entscheidungen wie:
|
||||
- kostenfreie Research-Features
|
||||
- angepasste UI-Hinweise
|
||||
- alternative Rate-Limits
|
||||
|
||||
---
|
||||
|
||||
## Funktionsweise (Kurzfassung)
|
||||
|
||||
```
|
||||
Client
|
||||
→ Traefik
|
||||
→ ForwardAuth
|
||||
→ ASN Detection Service
|
||||
→ Header wird ergänzt
|
||||
```
|
||||
|
||||
1. Die Client-IP wird ermittelt
|
||||
2. Die zugehörige ASN wird lokal nachgeschlagen
|
||||
3. Die ASN wird mit einer NREN-ASN-Liste verglichen
|
||||
4. Das Ergebnis wird als HTTP-Header zurückgegeben
|
||||
|
||||
---
|
||||
|
||||
## Datenquellen
|
||||
|
||||
- **GeoLite2 ASN (MaxMind)**
|
||||
- kostenlos
|
||||
- lokal
|
||||
- monatliche Aktualisierung
|
||||
|
||||
- **NREN-ASN-Liste**
|
||||
- abgeleitet aus PeeringDB
|
||||
- Kategorie: `Research and Education`
|
||||
- monatliche Aktualisierung
|
||||
|
||||
---
|
||||
|
||||
## Bereitgestellte Header
|
||||
|
||||
| Header | Beschreibung |
|
||||
|------|-------------|
|
||||
| `X-ASN` | ASN der Client-IP |
|
||||
| `X-ASN-ORG` | Organisation (optional) |
|
||||
| `X-NREN` | `1` wenn ASN zu einem Hochschul-/Forschungsnetz gehört, sonst `0` |
|
||||
|
||||
---
|
||||
|
||||
## Integration
|
||||
|
||||
Der Service wird als **Traefik ForwardAuth Middleware** eingebunden.
|
||||
Die Header werden über `authResponseHeaders` an die eigentliche Anwendung weitergereicht.
|
||||
|
||||
Der Service ist **nicht öffentlich exponiert** und kommuniziert ausschließlich über das interne Docker-Netzwerk.
|
||||
|
||||
---
|
||||
|
||||
## Update-Strategie
|
||||
|
||||
- monatliche Aktualisierung der ASN-Daten
|
||||
- keine externen Requests während der Anfrageverarbeitung
|
||||
|
||||
---
|
||||
|
||||
## Einschränkungen
|
||||
|
||||
- Die Erkennung ist **heuristisch**
|
||||
- Es gibt **keine Garantie**, dass jede Anfrage aus einem Hochschulnetz erkannt wird
|
||||
- Die Information darf **nicht als Authentifizierungsmerkmal** verwendet werden
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
Dieses Projekt ermöglicht eine **performante, datenschutzfreundliche Erkennung von Hochschulnetzen**, um **Research-Angebote kontextabhängig bereitzustellen**, ohne Nutzer zu identifizieren oder externe Dienste zur Laufzeit zu kontaktieren.
|
||||
89
apps/security/Eduroam Analyzer/README_technical.md
Normal file
89
apps/security/Eduroam Analyzer/README_technical.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# NREN / ASN Detection Service
|
||||
|
||||
Dieses Projekt stellt einen **minimalen Microservice** bereit, um **Hochschul- und Forschungsnetzwerke (NRENs)** anhand der **Autonomous System Number (ASN)** zu erkennen.
|
||||
|
||||
Der Zweck ist es, **Anfragen aus Hochschulnetzen (z. B. eduroam)** zu identifizieren, um **Research-bezogene Services kostenlos oder bevorzugt bereitzustellen**.
|
||||
|
||||
Das System dient ausschließlich der **Netzwerk-Klassifikation** und **ersetzt keine Authentifizierung**.
|
||||
|
||||
---
|
||||
|
||||
## Ziel
|
||||
|
||||
- Erkennen, ob eine Anfrage aus einem **Hochschul- oder Forschungsnetz** stammt
|
||||
- Bereitstellung eines **Header-Hinweises** für nachgelagerte Services
|
||||
- Grundlage für Entscheidungen wie:
|
||||
- kostenfreie Research-Features
|
||||
- angepasste UI-Hinweise
|
||||
- alternative Rate-Limits
|
||||
|
||||
---
|
||||
|
||||
## Funktionsweise (Kurzfassung)
|
||||
|
||||
```
|
||||
Client
|
||||
→ Traefik
|
||||
→ ForwardAuth
|
||||
→ ASN Detection Service
|
||||
→ Header wird ergänzt
|
||||
```
|
||||
|
||||
1. Die Client-IP wird ermittelt
|
||||
2. Die zugehörige ASN wird lokal nachgeschlagen
|
||||
3. Die ASN wird mit einer NREN-ASN-Liste verglichen
|
||||
4. Das Ergebnis wird als HTTP-Header zurückgegeben
|
||||
|
||||
---
|
||||
|
||||
## Datenquellen
|
||||
|
||||
- **GeoLite2 ASN (MaxMind)**
|
||||
- kostenlos
|
||||
- lokal
|
||||
- monatliche Aktualisierung
|
||||
|
||||
- **NREN-ASN-Liste**
|
||||
- abgeleitet aus PeeringDB
|
||||
- Kategorie: `Research and Education`
|
||||
- monatliche Aktualisierung
|
||||
|
||||
---
|
||||
|
||||
## Bereitgestellte Header
|
||||
|
||||
| Header | Beschreibung |
|
||||
|------|-------------|
|
||||
| `X-ASN` | ASN der Client-IP |
|
||||
| `X-ASN-ORG` | Organisation (optional) |
|
||||
| `X-NREN` | `1` wenn ASN zu einem Hochschul-/Forschungsnetz gehört, sonst `0` |
|
||||
|
||||
---
|
||||
|
||||
## Integration
|
||||
|
||||
Der Service wird als **Traefik ForwardAuth Middleware** eingebunden.
|
||||
Die Header werden über `authResponseHeaders` an die eigentliche Anwendung weitergereicht.
|
||||
|
||||
Der Service ist **nicht öffentlich exponiert** und kommuniziert ausschließlich über das interne Docker-Netzwerk.
|
||||
|
||||
---
|
||||
|
||||
## Update-Strategie
|
||||
|
||||
- monatliche Aktualisierung der ASN-Daten
|
||||
- keine externen Requests während der Anfrageverarbeitung
|
||||
|
||||
---
|
||||
|
||||
## Einschränkungen
|
||||
|
||||
- Die Erkennung ist **heuristisch**
|
||||
- Es gibt **keine Garantie**, dass jede Anfrage aus einem Hochschulnetz erkannt wird
|
||||
- Die Information darf **nicht als Authentifizierungsmerkmal** verwendet werden
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
Dieses Projekt ermöglicht eine **performante, datenschutzfreundliche Erkennung von Hochschulnetzen**, um **Research-Angebote kontextabhängig bereitzustellen**, ohne Nutzer zu identifizieren oder externe Dienste zur Laufzeit zu kontaktieren.
|
||||
1
apps/security/Eduroam Analyzer/asn-updater
Submodule
1
apps/security/Eduroam Analyzer/asn-updater
Submodule
Submodule apps/security/Eduroam Analyzer/asn-updater added at d36a1e7655
36
apps/security/Eduroam Analyzer/docker-compose.yml
Normal file
36
apps/security/Eduroam Analyzer/docker-compose.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
services:
|
||||
asn-header:
|
||||
build: .
|
||||
container_name: asn-header
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
environment:
|
||||
MMDB_PATH: /data/GeoLite2-ASN.mmdb
|
||||
ASN_LIST_PATH: /data/nren_asns.txt
|
||||
ADDR: ":8080"
|
||||
volumes:
|
||||
- asn_data:/data:ro
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
asn-updater:
|
||||
build: ./asn-updater
|
||||
container_name: asn-updater
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
environment:
|
||||
OUT_DIR: /data
|
||||
PDB_INFO_TYPE: "Research and Education"
|
||||
INTERVAL_SECONDS: "${UPDATE_INTERVAL_SECONDS}"
|
||||
volumes:
|
||||
- asn_data:/data
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
name: ${PROXY_NETWORK}
|
||||
|
||||
volumes:
|
||||
asn_data:
|
||||
6
apps/security/Eduroam Analyzer/go.mod
Normal file
6
apps/security/Eduroam Analyzer/go.mod
Normal file
@@ -0,0 +1,6 @@
|
||||
module asn-header-service
|
||||
|
||||
go 1.22
|
||||
|
||||
require github.com/oschwald/maxminddb-golang v1.13.1
|
||||
|
||||
158
apps/security/Eduroam Analyzer/main.go
Normal file
158
apps/security/Eduroam Analyzer/main.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/oschwald/maxminddb-golang"
|
||||
)
|
||||
|
||||
type asnRecord struct {
|
||||
ASN uint `maxminddb:"autonomous_system_number"`
|
||||
Org string `maxminddb:"autonomous_system_organization"`
|
||||
}
|
||||
|
||||
type server struct {
|
||||
db *maxminddb.Reader
|
||||
nrenASNs map[uint]struct{}
|
||||
ready atomic.Bool
|
||||
versionTag string
|
||||
}
|
||||
|
||||
func loadASNSet(path string) (map[uint]struct{}, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
set := make(map[uint]struct{}, 4096)
|
||||
sc := bufio.NewScanner(f)
|
||||
for sc.Scan() {
|
||||
line := strings.TrimSpace(sc.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
v, err := strconv.ParseUint(line, 10, 32)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
set[uint(v)] = struct{}{}
|
||||
}
|
||||
return set, sc.Err()
|
||||
}
|
||||
|
||||
func firstForwardedFor(r *http.Request) string {
|
||||
xff := r.Header.Get("X-Forwarded-For")
|
||||
if xff == "" {
|
||||
return ""
|
||||
}
|
||||
parts := strings.Split(xff, ",")
|
||||
if len(parts) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(parts[0])
|
||||
}
|
||||
|
||||
func remoteIP(r *http.Request) string {
|
||||
// Prefer XFF (because Traefik is proxy)
|
||||
ip := firstForwardedFor(r)
|
||||
if ip != "" {
|
||||
return ip
|
||||
}
|
||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err == nil {
|
||||
return host
|
||||
}
|
||||
return r.RemoteAddr
|
||||
}
|
||||
|
||||
func (s *server) authHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.ready.Load() {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
ipStr := remoteIP(r)
|
||||
parsed := net.ParseIP(ipStr)
|
||||
if parsed == nil {
|
||||
// Always 200: we enrich, not block
|
||||
w.Header().Set("X-NREN", "0")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
var rec asnRecord
|
||||
if err := s.db.Lookup(parsed, &rec); err != nil || rec.ASN == 0 {
|
||||
w.Header().Set("X-NREN", "0")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("X-ASN", strconv.FormatUint(uint64(rec.ASN), 10))
|
||||
if rec.Org != "" {
|
||||
// optional: keep it short; some org strings can be long
|
||||
w.Header().Set("X-ASN-ORG", rec.Org)
|
||||
}
|
||||
|
||||
_, ok := s.nrenASNs[rec.ASN]
|
||||
if ok {
|
||||
w.Header().Set("X-NREN", "1")
|
||||
} else {
|
||||
w.Header().Set("X-NREN", "0")
|
||||
}
|
||||
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
w.Header().Set("X-Service", s.versionTag)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func main() {
|
||||
mmdbPath := getenv("MMDB_PATH", "/data/GeoLite2-ASN.mmdb")
|
||||
asnListPath := getenv("ASN_LIST_PATH", "/data/nren_asns.txt")
|
||||
addr := getenv("ADDR", ":8080")
|
||||
version := getenv("VERSION_TAG", "asn-header-service")
|
||||
|
||||
db, err := maxminddb.Open(mmdbPath)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open mmdb: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
set, err := loadASNSet(asnListPath)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load asn list: %v", err)
|
||||
}
|
||||
|
||||
s := &server{db: db, nrenASNs: set, versionTag: version}
|
||||
s.ready.Store(true)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/auth", s.authHandler)
|
||||
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: mux,
|
||||
ReadHeaderTimeout: 2 * time.Second,
|
||||
}
|
||||
|
||||
log.Printf("listening on %s (asn_count=%d)", addr, len(set))
|
||||
log.Fatal(srv.ListenAndServe())
|
||||
}
|
||||
|
||||
func getenv(k, def string) string {
|
||||
v := strings.TrimSpace(os.Getenv(k))
|
||||
if v == "" {
|
||||
return def
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -6,17 +6,17 @@ services:
|
||||
environment:
|
||||
# Change Language:
|
||||
# (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th, hi, ja, si)
|
||||
- LANG=de
|
||||
- LANG=${WG_LANG:-de}
|
||||
# ⚠️ Required:
|
||||
# Change this to your host's public address
|
||||
- WG_HOST=${SERVER_IP}
|
||||
- WG_HOST=${SERVER_IP:-localhost}
|
||||
|
||||
# Optional:
|
||||
# - PASSWORD_HASH=$$2y$$10$$hBCoykrB95WSzuV4fafBzOHWKu9sbyVa34GJr8VV5R/pIelfEMYyG # (needs double $$, hash of 'foobar123'; see "How_to_generate_an_bcrypt_hash.md" for generate the hash)
|
||||
# - PORT=51821
|
||||
# - WG_PORT=51820
|
||||
# - WG_CONFIG_PORT=92820
|
||||
- WG_DEFAULT_ADDRESS=22.22.22.0
|
||||
- WG_DEFAULT_ADDRESS=${WG_DEFAULT_ADDRESS:-22.22.22.0}
|
||||
# - WG_DEFAULT_DNS=1.1.1.1
|
||||
# - WG_MTU=1420
|
||||
# - WG_ALLOWED_IPS=192.168.15.0/24, 10.0.1.0/24
|
||||
|
||||
@@ -1,67 +1,11 @@
|
||||
### Tools (./apps/tools/docker-compose.yml)
|
||||
# - [ ] Create services for Nextcloud, LimeSurvey, and LinkStack
|
||||
# - [ ] Configure volumes for persistent storage of files, survey data, and link management data
|
||||
# - [ ] Set up environment variables using the new structure (../../env/${ENVIRONMENT}/tools.env)
|
||||
# - [ ] Set up environment variables using the new structure (../../env/${ENVIRONMENT:-development}/tools.env)
|
||||
# - [ ] Configure networking to expose these services to the internet via the proxy
|
||||
# - [ ] Set up regular backup jobs for critical data in these services
|
||||
|
||||
services:
|
||||
nextcloud-db:
|
||||
image: mariadb:10.6
|
||||
container_name: ${INFRASTRUCTURE_LABEL}-nextcloud-db-${ENVIRONMENT}
|
||||
profiles: ["all", "tools", "nextcloud"]
|
||||
command: --transaction-isolation=READ-COMMITTED --innodb_read_only_compressed=OFF
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- ../../volumes/tools/${INFRASTRUCTURE_LABEL}_cloud/database:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=headpiece-constant1-denim-mindboost #SQL root Passwort eingeben
|
||||
- MYSQL_PASSWORD=idealist9-frayed-murkiness-mindboost #SQL Benutzer Passwort eingeben
|
||||
- MYSQL_DATABASE=nextcloud-mindboost #Datenbank Name
|
||||
- MYSQL_USER=mindboostcloud #SQL Nutzername
|
||||
- MYSQL_INITDB_SKIP_TZINFO=1
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
nextcloud-redis:
|
||||
image: redis:alpine
|
||||
container_name: ${INFRASTRUCTURE_LABEL}-nextcloud-redis-${ENVIRONMENT}
|
||||
profiles: ["all", "tools", "nextcloud"]
|
||||
hostname: nextcloud-redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --requirepass redis-mindboost-passwort # Redis Passwort eingeben
|
||||
cloud:
|
||||
image: nextcloud
|
||||
container_name: ${INFRASTRUCTURE_LABEL}-nextcloud-app-${ENVIRONMENT}
|
||||
profiles: ["all", "tools", "nextcloud"]
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- nextcloud-db
|
||||
- nextcloud-redis
|
||||
environment:
|
||||
TRUSTED_PROXIES: 172.16.255.254/16
|
||||
OVERWRITEPROTOCOL: https
|
||||
OVERWRITECLIURL: https://${CLOUD_DOMAIN}
|
||||
OVERWRITEHOST: ${CLOUD_DOMAIN}
|
||||
REDIS_HOST: nextcloud-redis
|
||||
REDIS_HOST_PASSWORD: redis-mindboost-passwort # Redis Passwort von oben wieder eingeben
|
||||
volumes:
|
||||
- ./app:/var/www/html
|
||||
- ../../volumes/tools/${INFRASTRUCTURE_LABEL}_cloudapp/:/var/www/html/data
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL}_cloud.entrypoints=websecure"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL}_cloud.rule=Host(`${CLOUD_DOMAIN}`)"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL}_cloud.tls=true"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL}_cloud.tls.certresolver=http_resolver"
|
||||
- 'traefik.http.routers.${INFRASTRUCTURE_LABEL}_cloud.service=cloud'
|
||||
- "traefik.http.services.cloud.loadbalancer.server.port=80"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL}_cloud.middlewares=nextcloud-dav,default@file"
|
||||
- "traefik.http.middlewares.nextcloud-dav.replacepathregex.regex=^/.well-known/ca(l|rd)dav"
|
||||
- "traefik.http.middlewares.nextcloud-dav.replacepathregex.replacement=/remote.php/dav/"
|
||||
networks:
|
||||
- ${TRAEFIK_NETWORK}
|
||||
networks:
|
||||
nextcloud:
|
||||
name: ${INFRASTRUCTURE_LABEL}_nextcloud
|
||||
include:
|
||||
- path: ./nextcloud/docker-compose.yml
|
||||
- path: ./limesurvey/docker-compose.yml
|
||||
- path: ./invoiceninja/dockerfiles/debian/docker-compose.yml
|
||||
|
||||
0
apps/tools/limesurvey/docker-compose.yml
Normal file
0
apps/tools/limesurvey/docker-compose.yml
Normal file
59
apps/tools/nextcloud/docker-compose.yml
Normal file
59
apps/tools/nextcloud/docker-compose.yml
Normal file
@@ -0,0 +1,59 @@
|
||||
services:
|
||||
nextcloud-db:
|
||||
image: mariadb:10.6
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-nextcloud-db-${ENVIRONMENT:-development}
|
||||
profiles: ["all", "tools", "nextcloud"]
|
||||
command: --transaction-isolation=READ-COMMITTED --innodb_read_only_compressed=OFF
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- ../../volumes/tools/${INFRASTRUCTURE_LABEL:-default}_cloud/database:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=headpiece-constant1-denim-mindboost #SQL root Passwort eingeben
|
||||
- MYSQL_PASSWORD=idealist9-frayed-murkiness-mindboost #SQL Benutzer Passwort eingeben
|
||||
- MYSQL_DATABASE=nextcloud-mindboost #Datenbank Name
|
||||
- MYSQL_USER=mindboostcloud #SQL Nutzername
|
||||
- MYSQL_INITDB_SKIP_TZINFO=1
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
nextcloud-redis:
|
||||
image: redis:alpine
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-nextcloud-redis-${ENVIRONMENT:-development}
|
||||
profiles: ["all", "tools", "nextcloud"]
|
||||
hostname: nextcloud-redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --requirepass redis-mindboost-passwort # Redis Passwort eingeben
|
||||
cloud:
|
||||
image: nextcloud
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-nextcloud-app-${ENVIRONMENT:-development}
|
||||
profiles: ["all", "tools", "nextcloud"]
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- nextcloud-db
|
||||
- nextcloud-redis
|
||||
environment:
|
||||
TRUSTED_PROXIES: 172.16.255.254/16
|
||||
OVERWRITEPROTOCOL: https
|
||||
OVERWRITECLIURL: https://${CLOUD_DOMAIN:-cloud}
|
||||
OVERWRITEHOST: ${CLOUD_DOMAIN:-cloud}
|
||||
REDIS_HOST: nextcloud-redis
|
||||
REDIS_HOST_PASSWORD: redis-mindboost-passwort # Redis Passwort von oben wieder eingeben
|
||||
volumes:
|
||||
- ../../volumes/tools/${INFRASTRUCTURE_LABEL:-default}_cloudapp/:/var/www/html/data
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_cloud.entrypoints=websecure"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_cloud.rule=Host(`${CLOUD_DOMAIN}`)"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_cloud.tls=true"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_cloud.tls.certresolver=http_resolver"
|
||||
- 'traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_cloud.service=cloud'
|
||||
- "traefik.http.services.cloud.loadbalancer.server.port=80"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK:-default}"
|
||||
- "traefik.http.routers.${INFRASTRUCTURE_LABEL:-default}_cloud.middlewares=nextcloud-dav,default@file"
|
||||
- "traefik.http.middlewares.nextcloud-dav.replacepathregex.regex=^/.well-known/ca(l|rd)dav"
|
||||
- "traefik.http.middlewares.nextcloud-dav.replacepathregex.replacement=/remote.php/dav/"
|
||||
networks:
|
||||
- ${TRAEFIK_NETWORK}
|
||||
networks:
|
||||
nextcloud:
|
||||
name: ${INFRASTRUCTURE_LABEL:-default}_nextcloud
|
||||
@@ -4,20 +4,26 @@ services:
|
||||
context: ./kirby
|
||||
dockerfile: Dockerfile
|
||||
image: kirbycms
|
||||
container_name: ${INFRASTRUCTURE_LABEL}-kirbycms-${ENVIRONMENT}
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-default}-kirbycms-${ENVIRONMENT:-development}
|
||||
profiles: ["website","kirbycms","all"]
|
||||
volumes:
|
||||
- ../../volumes/website/kirbycms:/var/www/html:rw # Persistente Daten
|
||||
- kirbycms_data:/var/www/html:rw # Persistente Daten
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 0:80
|
||||
networks:
|
||||
- ${TRAEFIK_NETWORK}
|
||||
- ${TRAEFIK_NETWORK:-default}
|
||||
labels:
|
||||
- "traefik.enable=${TRAEFIK_ENABLE}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK:-default}"
|
||||
- "traefik.http.routers.kirbycms.service=kirbycms"
|
||||
- "traefik.http.routers.kirbycms.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
|
||||
- "traefik.http.routers.kirbycms.tls.domains[0].main=`${WEBSITE_DOMAIN}`"
|
||||
- "traefik.http.routers.kirbycms.rule=Host(`${WEBSITE_DOMAIN}`)"
|
||||
- "traefik.http.routers.kirbycms.entrypoints=${TRAEFIK_ENTRYPOINT}"
|
||||
- "traefik.http.routers.kirbycms.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-default}"
|
||||
- "traefik.http.routers.kirbycms.tls.domains[0].main=`${WEBSITE_DOMAIN:-kirby.local}`"
|
||||
- "traefik.http.routers.kirbycms.rule=Host(`${WEBSITE_DOMAIN:-kirby.local}`)"
|
||||
- "traefik.http.routers.kirbycms.entrypoints=${TRAEFIK_ENTRYPOINT:-default}"
|
||||
- "traefik.http.routers.kirbycms.tls=true"
|
||||
- "traefik.http.services.kirbycms.loadbalancer.server.port=80"
|
||||
volumes:
|
||||
kirbycms_data:
|
||||
driver: local
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
USERID=0
|
||||
USERID=${USERID:-0}
|
||||
|
||||
114
dev-fpm.docker-compose.yml
Normal file
114
dev-fpm.docker-compose.yml
Normal file
@@ -0,0 +1,114 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
mariadb_webapp_dev:
|
||||
image: docker.io/bitnami/mariadb:11.1
|
||||
container_name: ${DEV_COMPOSE_PREFIX:-dev}-mariadb
|
||||
hostname: ${DEV_DB_HOST:-mariadb-webapp-dev}
|
||||
environment:
|
||||
MARIADB_USER: ${MARIADB_USER}
|
||||
MARIADB_DATABASE: ${MARIADB_DATABASE}
|
||||
MARIADB_PASSWORD: ${MARIADB_PASSWORD}
|
||||
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
|
||||
networks:
|
||||
- dev_backend
|
||||
volumes:
|
||||
- mindboost_mariadb_data_dev:/var/lib/mysql
|
||||
|
||||
laravel-redis-dev:
|
||||
image: redis:alpine
|
||||
container_name: ${DEV_COMPOSE_PREFIX:-dev}-redis
|
||||
hostname: ${DEV_REDIS_HOST:-laravel-redis-dev}
|
||||
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
|
||||
networks:
|
||||
- dev_backend
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./data/redis-dev:/data
|
||||
|
||||
laravel_backend_dev:
|
||||
image: ${BACKEND_IMAGE}
|
||||
container_name: ${DEV_COMPOSE_PREFIX:-dev}-backend
|
||||
environment:
|
||||
APP_ENV: ${APP_ENV:-production}
|
||||
APP_NAME: ${APP_NAME:-Mindboost Backend Dev}
|
||||
APP_URL: https://${DEV_BACKEND_DOMAIN}
|
||||
FRONTEND_URL: https://${DEV_FRONTEND_DOMAIN}
|
||||
DB_CONNECTION: mysql
|
||||
DB_HOST: ${DEV_DB_HOST:-mariadb-webapp-dev}
|
||||
DB_PORT: ${DB_PORT:-3306}
|
||||
DB_DATABASE: ${MARIADB_DATABASE}
|
||||
DB_USERNAME: ${MARIADB_USER}
|
||||
DB_PASSWORD: ${MARIADB_PASSWORD}
|
||||
REDIS_HOST: ${DEV_REDIS_HOST:-laravel-redis-dev}
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
CACHE_DRIVER: redis
|
||||
QUEUE_CONNECTION: redis
|
||||
SESSION_DRIVER: redis
|
||||
volumes:
|
||||
- ${BACKEND_CODE_PATH:-./apps/backend/src}:/app
|
||||
- ${BACKEND_PUBLIC_PATH:-./apps/backend/src/public}:/var/www/public
|
||||
- ${BACKEND_ENV_FILE:-./env/development/.env.backend}:/var/www/.env
|
||||
- ./logs/backend-dev:/var/www/storage/logs
|
||||
depends_on:
|
||||
- mariadb_webapp_dev
|
||||
- laravel-redis-dev
|
||||
networks:
|
||||
- dev_backend
|
||||
|
||||
laravel-nginx-dev:
|
||||
image: nginx:alpine
|
||||
container_name: ${DEV_COMPOSE_PREFIX:-dev}-nginx
|
||||
volumes:
|
||||
- ./nginx:/etc/nginx/conf.d:ro
|
||||
- ${BACKEND_PUBLIC_PATH:-./apps/backend/src/public}:/var/www/public:ro
|
||||
depends_on:
|
||||
- laravel_backend_dev
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dev_backend_http.entrypoints=web"
|
||||
- "traefik.http.routers.dev_backend_http.rule=Host(`${DEV_BACKEND_DOMAIN}`)"
|
||||
- "traefik.http.routers.dev_backend_http.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.routers.dev_backend_https.entrypoints=websecure"
|
||||
- "traefik.http.routers.dev_backend_https.rule=Host(`${DEV_BACKEND_DOMAIN}`)"
|
||||
- "traefik.http.routers.dev_backend_https.tls=true"
|
||||
- "traefik.http.routers.dev_backend_https.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
|
||||
- "traefik.http.routers.dev_backend_https.service=dev_backend_service"
|
||||
- "traefik.http.services.dev_backend_service.loadbalancer.server.port=80"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
networks:
|
||||
- dev_backend
|
||||
- proxy
|
||||
|
||||
nuxt_frontend_dev:
|
||||
image: ${NUXT_IMAGE}
|
||||
container_name: ${DEV_COMPOSE_PREFIX:-dev}-frontend
|
||||
environment:
|
||||
VUE_APP_BACKEND_HOST_ADDRESS: https://${DEV_BACKEND_DOMAIN}
|
||||
NUXT_PUBLIC_BACKEND_URL: https://${DEV_BACKEND_DOMAIN}
|
||||
networks:
|
||||
- dev_backend
|
||||
- proxy
|
||||
depends_on:
|
||||
- laravel_backend_dev
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dev_frontend_http.entrypoints=web"
|
||||
- "traefik.http.routers.dev_frontend_http.rule=Host(`${DEV_FRONTEND_DOMAIN}`)"
|
||||
- "traefik.http.routers.dev_frontend_http.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.routers.dev_frontend_https.entrypoints=websecure"
|
||||
- "traefik.http.routers.dev_frontend_https.rule=Host(`${DEV_FRONTEND_DOMAIN}`)"
|
||||
- "traefik.http.routers.dev_frontend_https.tls=true"
|
||||
- "traefik.http.routers.dev_frontend_https.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
|
||||
- "traefik.http.services.dev_frontend_https.loadbalancer.server.port=${VUE_INTERNAL_PORT}"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK}"
|
||||
|
||||
networks:
|
||||
dev_backend:
|
||||
driver: bridge
|
||||
proxy:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
mindboost_mariadb_data_dev:
|
||||
29
docs/infra.md
Normal file
29
docs/infra.md
Normal file
@@ -0,0 +1,29 @@
|
||||
Infrastructure v2
|
||||
|
||||
Goals
|
||||
|
||||
- Modular stacks you can pick individually (Nextcloud, etc.)
|
||||
- Unified reverse proxy (Traefik) with automatic TLS
|
||||
- Clear env layering and git‑ignored secrets
|
||||
- Simple Make targets for a smooth DX
|
||||
|
||||
Layout
|
||||
|
||||
- infra/core/traefik: Traefik compose + static/dynamic config
|
||||
- infra/apps/<service>: Self‑contained compose stacks and .env.example
|
||||
- infra/env/<env>/common.env: Shared environment defaults per environment
|
||||
- infra/secrets: Local secret files (ignored)
|
||||
- scripts/infra/bootstrap.sh: Creates proxy network and ACME storage
|
||||
|
||||
Usage
|
||||
|
||||
1. cp infra/env/development/common.env infra/env/development/common.env (adjust values)
|
||||
2. make bootstrap
|
||||
3. make proxy-up
|
||||
4. make app-up APP=nextcloud
|
||||
|
||||
Security
|
||||
|
||||
- Do not commit real secrets. Place them in local `.env` files or secret managers.
|
||||
- Optionally protect Traefik dashboard with basic auth via `TRAEFIK_BASIC_AUTH_USERS`.
|
||||
|
||||
33
env/.env.all
vendored
33
env/.env.all
vendored
@@ -2,9 +2,38 @@
|
||||
## Einstellung die für das gesamte Projekt gelten. Also der Name und der Admin
|
||||
## Das Environment muss "production","staging" oder "development" heißen
|
||||
|
||||
INFRASTRUCTURE_LABEL=mindboost_dev
|
||||
INFRASTRUCTURE_LABEL=mindboost
|
||||
ENVIRONMENT=development
|
||||
|
||||
ADMIN_USER=${INFRASTRUCTURE_LABEL}_${ENVIRONMENT}
|
||||
ADMIN_USER=${INFRASTRUCTURE_LABEL:-default}_${ENVIRONMENT:-development}
|
||||
ADMIN_PASSWORD_HASH='$2y$05$U7noO29Ru/4VB5x8TpZo3.b4VjH6AAnhufJJUG2Vs7qHCM2Cd8yIK' # for development = admin
|
||||
|
||||
SERVER_IP=127.0.0.1
|
||||
|
||||
|
||||
#################################################################################################
|
||||
# 🔧 ENVIRONMENT VARIABLES 🔧 #
|
||||
#################################################################################################
|
||||
#
|
||||
# This file contains **default (fallback) values** for environment variables.
|
||||
# These values ensure that services run with sane defaults if no other configuration is provided.
|
||||
#
|
||||
# 📌 **ENVIRONMENT VARIABLE PRIORITY ORDER (Lowest to Highest)**
|
||||
# 1️⃣ **Fallback Values in the File** (Used only if no other source provides a value)
|
||||
# 2️⃣ **Global Defaults in `.env.all`** (Shared settings across all services)
|
||||
# 3️⃣ **Service-Specific `.env` Files** (Overrides per service group, e.g., `.env.backend`, `.env.proxy`)
|
||||
# 4️⃣ **Preloaded Shell Environment** (`export VAR=value` before running `docker compose`)
|
||||
# 5️⃣ **CLI Overrides** (`docker compose --env-file` or `-e VAR=value` → Highest Priority)
|
||||
#
|
||||
# 🔄 **Overwriting Behavior**
|
||||
# - Variables defined in **`.env.all`** override values in this file.
|
||||
# - Variables defined in **`.env.<service>`** (e.g., `.env.backend`) override `.env.all`.
|
||||
# - Variables explicitly **exported in the shell** take priority over all `.env` files.
|
||||
# - Variables passed via **CLI (`--env-file` or `-e VAR=value`)** have the **highest priority**.
|
||||
#
|
||||
# 🚀 **Key Takeaways**
|
||||
# ✅ Use `.env.all` for common values across environments.
|
||||
# ✅ Use `.env.<service>` for service-specific configurations.
|
||||
# ✅ If needed, manually override variables in the shell or CLI.
|
||||
#
|
||||
#################################################################################################
|
||||
|
||||
49
env/.env.backend
vendored
49
env/.env.backend
vendored
@@ -1,49 +0,0 @@
|
||||
# ----------------------------------
|
||||
# Datenbank (MariaDB)
|
||||
# ----------------------------------
|
||||
MARIADB_USER=mindboost
|
||||
MARIADB_DATABASE=mindboost
|
||||
MARIADB_PASSWORD=1stronges-mindboostdb-passwort
|
||||
MARIADB_ROOT_PASSWORD=1stronges-passwort-fuer-diedb
|
||||
|
||||
# ----------------------------------
|
||||
# Redis
|
||||
# ----------------------------------
|
||||
REDIS_PASSWORD=laravel-redis-passwort
|
||||
REDIS_PORT=6379
|
||||
|
||||
# ----------------------------------
|
||||
# Vue Frontend (Nuxt.js)
|
||||
# ----------------------------------
|
||||
VUE_APP_BACKEND_HOST_ADDRESS=https://dev.b.mindboost.team
|
||||
VUE_FRONTEND_PORT=3001
|
||||
VUE_INTERNAL_PORT=3000
|
||||
VUE_FRONTEND_DOMAIN_1=app.mindboost.team
|
||||
VUE_FRONTEND_DOMAIN_2=mindboost.app
|
||||
|
||||
# ----------------------------------
|
||||
# Laravel Backend
|
||||
# ----------------------------------
|
||||
BACKEND_NETWORK=backend
|
||||
APP_NAME="mindboost backend - Compose Deployment"
|
||||
APP_URL=https://b.mindboost.team
|
||||
LARAVEL_PORT=8000
|
||||
LARAVEL_VITE_PORT=5173
|
||||
DB_HOST=mariadb
|
||||
DB_PORT=3306
|
||||
DB_PASSWORD=1stronges-mindboostdb-passwort
|
||||
DB_USERNAME=mindboost
|
||||
DB_DATABASE=mindboost
|
||||
LARAVEL_DOMAIN=b.mindboost.team
|
||||
JWT_SECRET=zMtO8sgsnc4UixWSsYWE1pK9EdpNLzxNSoIPlUpTe6dDlarM3bu4cwM80tH3jA0F
|
||||
# ----------------------------------
|
||||
# Traefik
|
||||
# ----------------------------------
|
||||
TRAEFIK_CERT_RESOLVER=http_resolver
|
||||
TRAEFIK_ENTRYPOINT=websecure
|
||||
TRAEFIK_NETWORK=proxy
|
||||
|
||||
# ----------------------------------
|
||||
# Adminer
|
||||
# ----------------------------------
|
||||
ADMINER_PORT=8080
|
||||
8
env/.env.db
vendored
8
env/.env.db
vendored
@@ -1,8 +0,0 @@
|
||||
# ----------------------------------
|
||||
# Datenbank (MariaDB)
|
||||
# ----------------------------------
|
||||
MARIADB_USER=mindboost
|
||||
MARIADB_DATABASE=mindboost
|
||||
MARIADB_PASSWORD=1stronges-mindboostdb-passwort
|
||||
MARIADB_ROOT_PASSWORD=1stronges-passwort-fuer-diedb
|
||||
ADMINER_PORT=8000
|
||||
1
env/.env.frontend
vendored
1
env/.env.frontend
vendored
@@ -1 +0,0 @@
|
||||
DB_HOST= BLALBLAB
|
||||
1
env/.env.shared
vendored
1
env/.env.shared
vendored
@@ -1 +0,0 @@
|
||||
DB_HOST= BLALBLAB
|
||||
24
env/.env.traefik
vendored
24
env/.env.traefik
vendored
@@ -1,24 +0,0 @@
|
||||
# ----------------------------------
|
||||
# Traefik
|
||||
# ----------------------------------
|
||||
|
||||
# Allgemein
|
||||
TRAEFIK_ENABLE=true
|
||||
TRAEFIK_NETWORK=proxy
|
||||
|
||||
# Backend
|
||||
TRAEFIK_ROUTER_BACKEND_ENTRYPOINT=websecure
|
||||
TRAEFIK_ROUTER_BACKEND_RULE=Host(`b.mindboost.team`)
|
||||
TRAEFIK_ROUTER_BACKEND_TLS=true
|
||||
TRAEFIK_ROUTER_BACKEND_CERTRESOLVER=http_resolver
|
||||
TRAEFIK_ROUTER_BACKEND_TLS_DOMAIN_MAIN=b.mindboost.team
|
||||
TRAEFIK_SERVICE_BACKEND_PORT=8000
|
||||
|
||||
# Frontend
|
||||
TRAEFIK_ROUTER_FRONTEND_ENTRYPOINT=websecure
|
||||
TRAEFIK_ROUTER_FRONTEND_RULE=Host(`app.mindboost.team`)
|
||||
TRAEFIK_ROUTER_FRONTEND_TLS=true
|
||||
TRAEFIK_ROUTER_FRONTEND_CERTRESOLVER=http_resolver
|
||||
TRAEFIK_ROUTER_FRONTEND_TLS_DOMAIN_MAIN=app.mindboost.team
|
||||
TRAEFIK_ROUTER_FRONTEND_TLS_DOMAIN_SANS=mindboost.app
|
||||
TRAEFIK_SERVICE_FRONTEND_PORT=3000
|
||||
50
env/README.md
vendored
Normal file
50
env/README.md
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
# 🔧 Environment Configuration Guide
|
||||
|
||||
## 🌍 Overview
|
||||
This project uses **environment variables** to manage configuration across different environments (development, staging, production, etc.). These variables are loaded from `.env` files and can be overridden at multiple levels.
|
||||
|
||||
---
|
||||
|
||||
## 📌 **Environment Variable Priority (Lowest to Highest)**
|
||||
|
||||
| 🔢 Priority | 📄 Source | 🔍 Description |
|
||||
|------------|-----------------------------|------------------------------------------------|
|
||||
| 1️⃣ **Fallback Values** | hardcoded defaults | Used only if no other configuration is provided |
|
||||
| 2️⃣ **Global Defaults** | `.env.all` | Shared settings for all services |
|
||||
| 3️⃣ **Service-Specific Overrides** | `.env.backend`, `.env.proxy`, etc. | Overrides `.env.all` with service-specific values |
|
||||
| 4️⃣ **Shell Environment Variables** | `export VAR=value` before running | Takes precedence over `.env` files |
|
||||
| 5️⃣ **CLI Overrides** | `docker compose --env-file` or `-e VAR=value` | **Highest priority** (for temporary overrides) |
|
||||
|
||||
---
|
||||
|
||||
## 🔄 **Overwriting Behavior**
|
||||
- 🏗 **Variables defined in `.env.all`** override fallback values.
|
||||
- 🏗 **Variables defined in `.env.<service>`** (e.g., `.env.backend`) override `.env.all`.
|
||||
- 🔧 **Manually exported environment variables** in the shell take priority over `.env` files.
|
||||
- 🚀 **Variables passed via CLI (`--env-file` or `-e VAR=value`)** override everything.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **Best Practices**
|
||||
✔️ **Use `.env.all` for global configurations** (e.g., `ENVIRONMENT=development`, `INFRASTRUCTURE_LABEL=myinfra`).
|
||||
✔️ **Use `.env.<service>` for service-specific configurations** (e.g., `.env.backend` for Laravel, `.env.database` for MariaDB).
|
||||
✔️ **If needed, manually override variables in the shell** using `export VAR=value`.
|
||||
✔️ **Use CLI `--env-file` for temporary overrides** in testing/debugging scenarios.
|
||||
|
||||
---
|
||||
|
||||
## 🏗 **Example File Structure**
|
||||
```sh
|
||||
/env/
|
||||
├── .env.all # Global default variables
|
||||
├── development/
|
||||
│ ├── .env.backend # Backend service config for development
|
||||
│ ├── .env.database # Database config for development
|
||||
│ ├── .env.proxy # Proxy config for development
|
||||
├── staging/
|
||||
│ ├── .env.backend # Backend service config for staging
|
||||
│ ├── .env.database # Database config for staging
|
||||
├── production/
|
||||
│ ├── .env.backend # Backend service config for production
|
||||
│ ├── .env.database # Database config for production
|
||||
|
||||
5
env/development/.env.administration
vendored
5
env/development/.env.administration
vendored
@@ -1,2 +1,7 @@
|
||||
# ----------------------------------
|
||||
# Portainer
|
||||
# ----------------------------------
|
||||
|
||||
PORTAINER_IMAGE=portainer/portainer-ce:latest
|
||||
PORTAINER_DATA_PATH=../../../volumes/administration/portainer/data
|
||||
|
||||
|
||||
19
env/development/.env.backend
vendored
19
env/development/.env.backend
vendored
@@ -5,24 +5,27 @@
|
||||
# ----------------------------------
|
||||
REDIS_PASSWORD=laravel-redis-passwort
|
||||
REDIS_PORT=6379
|
||||
SERVER_IP=${SERVER_IP:-localhost}
|
||||
|
||||
# ----------------------------------
|
||||
# Laravel Backend
|
||||
# ----------------------------------
|
||||
BACKEND_NETWORK=backend
|
||||
APP_ENV=${ENVIRONMENT-local}
|
||||
APP_NAME="mindboost backend - Compose Deployment"
|
||||
APP_URL=https://backend.local
|
||||
LARAVEL_PORT=8000
|
||||
LARAVEL_VITE_PORT=5173
|
||||
DB_HOST=${MARIADB_HOST}
|
||||
DB_PORT=${MARIADB_PORT}
|
||||
DB_PASSWORD=${MARIADB_PASSWORD}
|
||||
DB_USERNAME=${MARIADB_USER}
|
||||
DB_DATABASE=${MARIADB_DATABASE}
|
||||
|
||||
JWT_SECRET=zMtO8sgsnc4UixWSsYWE1pK9EdpNLzxNSoIPlUpTe6dDlarM3bu4cwM80tH3jA0F
|
||||
|
||||
# ----------------------------------
|
||||
# Adminer
|
||||
# Datenbank Zugriff - ! MUSS MIT .env.database übereinstimmen
|
||||
# ----------------------------------
|
||||
ADMINER_PORT=8080
|
||||
DB_HOST=database
|
||||
DB_PORT=3306
|
||||
DB_PASSWORD=1stronges-mindboostdb-passwort
|
||||
DB_USERNAME=${INFRASTRUCTURE_LABEL:-default}_${ENVIRONMENT:-development}
|
||||
DB_DATABASE=${INFRASTRUCTURE_LABEL:-default}_${ENVIRONMENT:-development}
|
||||
|
||||
|
||||
|
||||
|
||||
9
env/development/.env.database
vendored
9
env/development/.env.database
vendored
@@ -1,10 +1,9 @@
|
||||
# ----------------------------------
|
||||
# Datenbank (MariaDB)
|
||||
# ----------------------------------
|
||||
MARIADB_USER=${INFRASTRUCTURE_LABEL}_${ENVIRONMENT}
|
||||
MARIADB_DATABASE=${INFRASTRUCTURE_LABEL}_${ENVIRONMENT}
|
||||
MARIADB_USER=${INFRASTRUCTURE_LABEL:-default}_${ENVIRONMENT:-development}
|
||||
MARIADB_DATABASE=${INFRASTRUCTURE_LABEL:-default}_${ENVIRONMENT:-development}
|
||||
MARIADB_ROOT_PASSWORD_FILE=/run/secrets/mariadb_root
|
||||
MARIADB_PASSWORD=1stronges-mindboostdb-passwort
|
||||
MARIADB_ROOT_PASSWORD=1stronges-passwort-fuer-diedb
|
||||
|
||||
MARIADB_PORT=3306
|
||||
MARIADB_HOST=${INFRASTRUCTURE_LABEL}_database_${ENVIRONMENT}
|
||||
MARIADB_HOST=database
|
||||
|
||||
7
env/development/.env.develop
vendored
7
env/development/.env.develop
vendored
@@ -1,3 +1,7 @@
|
||||
# ----------------------------------
|
||||
# GITEA
|
||||
# ----------------------------------
|
||||
|
||||
USER_UID=1000
|
||||
USER_GID=1000
|
||||
|
||||
@@ -10,6 +14,9 @@ GITEA_MYSQL_PASSWORD=very-difficult-gitea
|
||||
GITEA_MYSQL_DATABASE=gitea
|
||||
GITEA_MYSQL_ALLOW_EMPTY_PASSWORD=true
|
||||
|
||||
# ----------------------------------
|
||||
# GITEA DB
|
||||
# ----------------------------------
|
||||
|
||||
DB_HOST=gitea_db:3306
|
||||
DB_NAME=gitea
|
||||
|
||||
5
env/development/.env.frontend
vendored
5
env/development/.env.frontend
vendored
@@ -1 +1,4 @@
|
||||
# Frontend
|
||||
# ----------------------------------
|
||||
# VUE APP
|
||||
# ----------------------------------
|
||||
BACKEND_URL="backend.local"
|
||||
|
||||
27
env/development/.env.proxy
vendored
27
env/development/.env.proxy
vendored
@@ -1,26 +1,29 @@
|
||||
##
|
||||
## GENERAL
|
||||
##
|
||||
# ----------------------------------
|
||||
# TRAEFIK
|
||||
# ----------------------------------
|
||||
|
||||
TRAEFIK_ENABLE=true
|
||||
TRAEFIK_NETWORK=proxy
|
||||
TRAEFIK_BASIC_AUTH_USERS=${ADMIN_USER}:${ADMIN_PASSWORD_HASH}
|
||||
TRAEFIK_CERT_RESOLVER=
|
||||
|
||||
##
|
||||
## Domains when TRAEFIK is ENABLED
|
||||
##
|
||||
|
||||
PORTAINER_DOMAIN=portainer.local
|
||||
FRONTEND_DOMAIN=frontend.local
|
||||
FRONTEND_DOMAIN_2=app.frontend.local
|
||||
BACKEND_DOMAIN=backend.local
|
||||
WEBSITE_DOMAIN=web.local
|
||||
ADMINER_DOMAIN=adminer.local
|
||||
GITEA_DOMAIN=gitea.local
|
||||
LIMESURVEY_DOMAIN=survey.local
|
||||
LINKSTACK_DOMAIN=linkstack.local
|
||||
TRAEFIK_DOMAIN=traefik.local
|
||||
CLOUD_DOMAIN=cloud.local
|
||||
KILLBILL_DOMAIN=killbill.local
|
||||
|
||||
### TLS for Domains
|
||||
|
||||
### TLS for Domains
|
||||
PORTAINER_TLS_DOMAIN_MAIN=${PORTAINER_DOMAIN}
|
||||
FRONTEND_TLS_DOMAIN_MAIN=${FRONTEND_DOMAIN}
|
||||
FRONTEND_TLS_DOMAIN_SANS=${FRONTEND_DOMAIN_2}
|
||||
@@ -31,16 +34,16 @@ LIMESURVEY_TLS_DOMAIN_MAIN=${LIMESURVEY_DOMAIN}
|
||||
LINKSTACK_TLS_DOMAIN_MAIN=${LINKSTACK_DOMAIN}
|
||||
TRAEFIK_TLS_DOMAIN_MAIN=${TRAEFIK_DOMAIN}
|
||||
CLOUD_TLS_DOMAIN_MAIN=${CLOUD_DOMAIN}
|
||||
KILLBILL_TLS_DOMAIN_MAIN=${KILLBILL_DOMAIN}
|
||||
|
||||
|
||||
##
|
||||
## MIDDLEWARES
|
||||
##
|
||||
TRAEFIK_HTTPS_REDIRECT_MIDDLEWARE=${INFRASTRUCTURE_LABEL}-https-redirect
|
||||
TRAEFIK_BASIC_AUTH_MIDDLEWARE=${INFRASTRUCTURE_LABEL}-basic-auth
|
||||
|
||||
##
|
||||
TRAEFIK_HTTPS_REDIRECT_MIDDLEWARE=${INFRASTRUCTURE_LABEL:-default}-https-redirect
|
||||
TRAEFIK_BASIC_AUTH_MIDDLEWARE=${INFRASTRUCTURE_LABEL:-default}-basic-auth
|
||||
|
||||
|
||||
## ENTRYPOINTS
|
||||
##
|
||||
|
||||
TRAEFIK_ENTRYPOINT=websecure
|
||||
TRAEFIK_ENTRYPOINT_HTTP=web
|
||||
|
||||
29
env/development/.env.tools
vendored
29
env/development/.env.tools
vendored
@@ -0,0 +1,29 @@
|
||||
# ----------------------------------
|
||||
# NEXTCLOUD DB
|
||||
# ----------------------------------
|
||||
|
||||
MYSQL_ROOT_PASSWORD=headpiece-constant1-denim-mindboost #SQL root Passwort eingeben
|
||||
MYSQL_PASSWORD=idealist9-frayed-murkiness-mindboost #SQL Benutzer Passwort eingeben
|
||||
MYSQL_DATABASE=nextcloud-mindboost #Datenbank Name
|
||||
MYSQL_USER=mindboostcloud #SQL Nutzername
|
||||
MYSQL_INITDB_SKIP_TZINFO=1
|
||||
MARIADB_AUTO_UPGRADE=1
|
||||
|
||||
# ----------------------------------
|
||||
# NEXTCLOUD CLOUD
|
||||
# ----------------------------------
|
||||
|
||||
TRUSTED_PROXIES=172.16.255.254/16
|
||||
OVERWRITEPROTOCOL=https
|
||||
OVERWRITECLIURL=https://${CLOUD_DOMAIN:-cloud}
|
||||
OVERWRITEHOST=${CLOUD_DOMAIN:-cloud}
|
||||
REDIS_HOST=nextcloud-redis
|
||||
REDIS_HOST_PASSWORD=redis-mindboost-passwort
|
||||
|
||||
# ----------------------------------
|
||||
# KILLBILL PAYMENT
|
||||
# ----------------------------------
|
||||
|
||||
KILLBILL_DAO_URL=jdbc:mysql://db:3306/killbill
|
||||
KILLBILL_DAO_USER=${ADMIN_USER:-root}
|
||||
KILLBILL_DAO_PASSWORD=${ADMIN_PASSWORD_HASH}
|
||||
|
||||
5
env/development/.env.website
vendored
5
env/development/.env.website
vendored
@@ -0,0 +1,5 @@
|
||||
# ----------------------------------
|
||||
# KIRBY CMS
|
||||
# ----------------------------------
|
||||
|
||||
USER_ID=0
|
||||
31
env/development/portainer/backend.env
vendored
Normal file
31
env/development/portainer/backend.env
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
|
||||
# ----------------------------------
|
||||
# Redis
|
||||
# ----------------------------------
|
||||
REDIS_PASSWORD=laravel-redis-passwort
|
||||
REDIS_PORT=6379
|
||||
SERVER_IP=${SERVER_IP:-localhost}
|
||||
|
||||
# ----------------------------------
|
||||
# Laravel Backend
|
||||
# ----------------------------------
|
||||
BACKEND_NETWORK=backend
|
||||
APP_ENV=${ENVIRONMENT-local}
|
||||
APP_NAME="mindboost backend - Compose Deployment"
|
||||
APP_URL=https://backend.local
|
||||
LARAVEL_PORT=8000
|
||||
LARAVEL_VITE_PORT=5173
|
||||
JWT_SECRET=zMtO8sgsnc4UixWSsYWE1pK9EdpNLzxNSoIPlUpTe6dDlarM3bu4cwM80tH3jA0F
|
||||
|
||||
# ----------------------------------
|
||||
# Datenbank Zugriff - ! MUSS MIT .env.database übereinstimmen
|
||||
# ----------------------------------
|
||||
DB_HOST=database
|
||||
DB_PORT=3306
|
||||
DB_PASSWORD=1stronges-mindboostdb-passwort
|
||||
DB_USERNAME=${INFRASTRUCTURE_LABEL:-default}_${ENVIRONMENT:-development}
|
||||
DB_DATABASE=${INFRASTRUCTURE_LABEL:-default}_${ENVIRONMENT:-development}
|
||||
|
||||
|
||||
|
||||
4
env/production/.env.database
vendored
4
env/production/.env.database
vendored
@@ -1,7 +1,7 @@
|
||||
# ----------------------------------
|
||||
# Datenbank (MariaDB)
|
||||
# ----------------------------------
|
||||
MARIADB_USER=${INFRASTRUCTURE_LABEL}_${ENVIRONMENT}
|
||||
MARIADB_DATABASE=${INFRASTRUCTURE_LABEL}_${ENVIRONMENT}
|
||||
MARIADB_USER=${INFRASTRUCTURE_LABEL:-default}_${ENVIRONMENT:-development}
|
||||
MARIADB_DATABASE=${INFRASTRUCTURE_LABEL:-default}_${ENVIRONMENT:-development}
|
||||
MARIADB_PASSWORD=1stronges-mindboostdb-passwort
|
||||
MARIADB_ROOT_PASSWORD=1stronges-passwort-fuer-diedb
|
||||
|
||||
8
env/production/.env.proxy
vendored
8
env/production/.env.proxy
vendored
@@ -1,5 +1,5 @@
|
||||
TRAEFIK_HTTPS_REDIRECT_MIDDLEWARE=${INFRASTRUCTURE_LABEL}-https-redirect
|
||||
TRAEFIK_BASIC_AUTH_MIDDLEWARE=${INFRASTRUCTURE_LABEL}-basic-auth
|
||||
TRAEFIK_HTTPS_REDIRECT_MIDDLEWARE=${INFRASTRUCTURE_LABEL:-default}-https-redirect
|
||||
TRAEFIK_BASIC_AUTH_MIDDLEWARE=${INFRASTRUCTURE_LABEL:-default}-basic-auth
|
||||
TRAEFIK_BASIC_AUTH_USERS=${ADMIN_USER}:${ADMIN_PASSWORD_HASH}
|
||||
|
||||
# Service Crowdsec
|
||||
@@ -10,8 +10,8 @@ SERVICES_CROWDSEC_IMAGE_VERSION=latest
|
||||
SERVICES_CROWDSEC_NETWORKS_CROWDSEC_IPV4=172.31.254.254
|
||||
|
||||
# Service Traefik
|
||||
SERVICES_TRAEFIK_CONTAINER_NAME=${INFRASTRUCTURE_LABEL}-traefik
|
||||
SERVICES_TRAEFIK_HOSTNAME=${INFRASTRUCTURE_LABEL}-traefik
|
||||
SERVICES_TRAEFIK_CONTAINER_NAME=${INFRASTRUCTURE_LABEL:-default}-traefik
|
||||
SERVICES_TRAEFIK_HOSTNAME=${INFRASTRUCTURE_LABEL:-default}-traefik
|
||||
SERVICES_TRAEFIK_IMAGE=traefik
|
||||
SERVICES_TRAEFIK_IMAGE_VERSION=2.11
|
||||
SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST=`traefik.haslach2025.de`
|
||||
|
||||
6
env/staging/.env.administration
vendored
Normal file
6
env/staging/.env.administration
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
# ----------------------------------
|
||||
# Portainer
|
||||
# ----------------------------------
|
||||
|
||||
15
env/staging/.env.backend
vendored
Normal file
15
env/staging/.env.backend
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
|
||||
# ----------------------------------
|
||||
# Redis
|
||||
# ----------------------------------
|
||||
|
||||
|
||||
# ----------------------------------
|
||||
# Laravel Backend
|
||||
# ----------------------------------
|
||||
|
||||
|
||||
# ----------------------------------
|
||||
# Adminer
|
||||
# ----------------------------------
|
||||
3
env/staging/.env.database
vendored
Normal file
3
env/staging/.env.database
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# ----------------------------------
|
||||
# Datenbank (MariaDB)
|
||||
# ----------------------------------
|
||||
9
env/staging/.env.develop
vendored
Normal file
9
env/staging/.env.develop
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# ----------------------------------
|
||||
# GITEA
|
||||
# ----------------------------------
|
||||
|
||||
|
||||
|
||||
# ----------------------------------
|
||||
# GITEA DB
|
||||
# ----------------------------------
|
||||
3
env/staging/.env.frontend
vendored
Normal file
3
env/staging/.env.frontend
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# ----------------------------------
|
||||
# VUE APP
|
||||
# ----------------------------------
|
||||
4
env/staging/.env.proxy
vendored
Normal file
4
env/staging/.env.proxy
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# ----------------------------------
|
||||
# TRAEFIK
|
||||
# ----------------------------------
|
||||
|
||||
9
env/staging/.env.tools
vendored
Normal file
9
env/staging/.env.tools
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# ----------------------------------
|
||||
# NEXTCLOUD DB
|
||||
# ----------------------------------
|
||||
|
||||
|
||||
|
||||
# ----------------------------------
|
||||
# NEXTCLOUD CLOUD
|
||||
# ----------------------------------
|
||||
4
env/staging/.env.website
vendored
Normal file
4
env/staging/.env.website
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# ----------------------------------
|
||||
# KIRBY CMS
|
||||
# ----------------------------------
|
||||
|
||||
14
infra/apps/nextcloud/.env.example
Normal file
14
infra/apps/nextcloud/.env.example
Normal file
@@ -0,0 +1,14 @@
|
||||
# Nextcloud stack configuration
|
||||
|
||||
NEXTCLOUD_DOMAIN=cloud.example.com
|
||||
|
||||
# Database
|
||||
NEXTCLOUD_DB_NAME=nextcloud
|
||||
NEXTCLOUD_DB_USER=nextcloud
|
||||
NEXTCLOUD_DB_PASSWORD=changeMe
|
||||
NEXTCLOUD_DB_ROOT_PASSWORD=changeMeRoot
|
||||
|
||||
# PHP tuning
|
||||
NEXTCLOUD_PHP_MEMORY_LIMIT=512M
|
||||
NEXTCLOUD_PHP_UPLOAD_LIMIT=1024M
|
||||
|
||||
13
infra/apps/nextcloud/README.md
Normal file
13
infra/apps/nextcloud/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
Nextcloud Stack
|
||||
|
||||
Env vars required (copy .env.example to .env and adjust):
|
||||
|
||||
- NEXTCLOUD_DOMAIN: public domain for Nextcloud
|
||||
- NEXTCLOUD_DB_NAME, NEXTCLOUD_DB_USER, NEXTCLOUD_DB_PASSWORD, NEXTCLOUD_DB_ROOT_PASSWORD
|
||||
- Optional: NEXTCLOUD_PHP_MEMORY_LIMIT, NEXTCLOUD_PHP_UPLOAD_LIMIT
|
||||
|
||||
Usage
|
||||
|
||||
- Ensure the Traefik proxy stack is up and the external `${TRAEFIK_NETWORK}` network exists.
|
||||
- Run: `docker compose --env-file ../../env/${ENV}/common.env --env-file ./.env -f docker-compose.yml up -d`
|
||||
|
||||
70
infra/apps/nextcloud/docker-compose.yml
Normal file
70
infra/apps/nextcloud/docker-compose.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
services:
|
||||
nextcloud:
|
||||
image: nextcloud:28-apache
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-stack}-nextcloud
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
environment:
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_DOMAIN}
|
||||
- OVERWRITEHOST=${NEXTCLOUD_DOMAIN}
|
||||
- OVERWRITEPROTOCOL=https
|
||||
- OVERWRITECLIURL=https://${NEXTCLOUD_DOMAIN}
|
||||
- REDIS_HOST=redis
|
||||
- MYSQL_HOST=db
|
||||
- MYSQL_DATABASE=${NEXTCLOUD_DB_NAME:-nextcloud}
|
||||
- MYSQL_USER=${NEXTCLOUD_DB_USER:-nextcloud}
|
||||
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
|
||||
- PHP_MEMORY_LIMIT=${NEXTCLOUD_PHP_MEMORY_LIMIT:-512M}
|
||||
- PHP_UPLOAD_LIMIT=${NEXTCLOUD_PHP_UPLOAD_LIMIT:-1024M}
|
||||
volumes:
|
||||
- nextcloud_data:/var/www/html
|
||||
networks:
|
||||
- nextcloud
|
||||
- proxy
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.nextcloud.rule=Host(`${NEXTCLOUD_DOMAIN}`)
|
||||
- traefik.http.routers.nextcloud.entrypoints=websecure
|
||||
- traefik.http.routers.nextcloud.tls=true
|
||||
- traefik.http.routers.nextcloud.tls.certresolver=letsencrypt
|
||||
- traefik.http.services.nextcloud.loadbalancer.server.port=80
|
||||
- traefik.http.routers.nextcloud.middlewares=security-headers@file
|
||||
- traefik.docker.network=${TRAEFIK_NETWORK:-proxy}
|
||||
|
||||
db:
|
||||
image: mariadb:11
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-stack}-nextcloud-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${NEXTCLOUD_DB_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=${NEXTCLOUD_DB_NAME:-nextcloud}
|
||||
- MYSQL_USER=${NEXTCLOUD_DB_USER:-nextcloud}
|
||||
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- nextcloud
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-stack}-nextcloud-redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- nextcloud
|
||||
|
||||
volumes:
|
||||
nextcloud_data:
|
||||
db_data:
|
||||
redis_data:
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
nextcloud:
|
||||
name: ${INFRASTRUCTURE_LABEL:-stack}-nextcloud
|
||||
|
||||
47
infra/core/traefik/docker-compose.yml
Normal file
47
infra/core/traefik/docker-compose.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v2.11
|
||||
container_name: ${INFRASTRUCTURE_LABEL:-stack}-traefik
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- --providers.file.directory=/etc/traefik/dynamic
|
||||
- --providers.file.watch=true
|
||||
- --providers.docker=true
|
||||
- --providers.docker.exposedbydefault=false
|
||||
- --providers.docker.network=${TRAEFIK_NETWORK:-proxy}
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}
|
||||
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
|
||||
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
|
||||
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
|
||||
- --api.dashboard=true
|
||||
- --log.level=${TRAEFIK_LOG_LEVEL:-INFO}
|
||||
- --accesslog=true
|
||||
ports:
|
||||
- ${TRAEFIK_HTTP_PORT:-80}:80
|
||||
- ${TRAEFIK_HTTPS_PORT:-443}:443
|
||||
environment:
|
||||
- TZ=${TZ:-UTC}
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./traefik.yml:/etc/traefik/traefik.yml:ro
|
||||
- ./dynamic:/etc/traefik/dynamic:ro
|
||||
- ./data:/letsencrypt
|
||||
networks:
|
||||
- proxy
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DASHBOARD_DOMAIN}`)
|
||||
- traefik.http.routers.traefik.entrypoints=websecure
|
||||
- traefik.http.routers.traefik.tls=true
|
||||
- traefik.http.routers.traefik.tls.certresolver=letsencrypt
|
||||
- traefik.http.routers.traefik.service=api@internal
|
||||
- traefik.docker.network=${TRAEFIK_NETWORK:-proxy}
|
||||
# Optional: protect dashboard with basic auth if TRAEFIK_BASIC_AUTH_USERS is set
|
||||
- traefik.http.routers.traefik.middlewares=dashboard-basicauth@file
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
|
||||
25
infra/core/traefik/dynamic/middlewares.yml
Normal file
25
infra/core/traefik/dynamic/middlewares.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
http:
|
||||
middlewares:
|
||||
redirect-to-https:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
permanent: true
|
||||
|
||||
security-headers:
|
||||
headers:
|
||||
frameDeny: true
|
||||
contentTypeNosniff: true
|
||||
browserXssFilter: true
|
||||
referrerPolicy: no-referrer-when-downgrade
|
||||
stsSeconds: 31536000
|
||||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
|
||||
dashboard-basicauth:
|
||||
basicAuth:
|
||||
users:
|
||||
# Provide users via env TRAEFIK_BASIC_AUTH_USERS, format: user:hashedpassword
|
||||
# Example to generate: htpasswd -nbB admin 'yourpassword'
|
||||
# If env is empty, you can comment this middleware out from labels
|
||||
- ${TRAEFIK_BASIC_AUTH_USERS:-}
|
||||
|
||||
6
infra/core/traefik/dynamic/tls.yml
Normal file
6
infra/core/traefik/dynamic/tls.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
minVersion: VersionTLS12
|
||||
sniStrict: true
|
||||
|
||||
30
infra/core/traefik/traefik.yml
Normal file
30
infra/core/traefik/traefik.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
api:
|
||||
dashboard: true
|
||||
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false
|
||||
network: ${TRAEFIK_NETWORK:-proxy}
|
||||
file:
|
||||
directory: /etc/traefik/dynamic
|
||||
watch: true
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
websecure:
|
||||
address: ":443"
|
||||
|
||||
log:
|
||||
level: ${TRAEFIK_LOG_LEVEL:-INFO}
|
||||
|
||||
accessLog: {}
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: ${ACME_EMAIL}
|
||||
storage: /letsencrypt/acme.json
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
|
||||
14
infra/env/common.env.example
vendored
Normal file
14
infra/env/common.env.example
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Global/defaults
|
||||
INFRASTRUCTURE_LABEL=mindboost
|
||||
TZ=UTC
|
||||
|
||||
# Traefik / proxy
|
||||
TRAEFIK_NETWORK=proxy
|
||||
TRAEFIK_HTTP_PORT=80
|
||||
TRAEFIK_HTTPS_PORT=443
|
||||
TRAEFIK_LOG_LEVEL=INFO
|
||||
ACME_EMAIL=you@example.com
|
||||
TRAEFIK_DASHBOARD_DOMAIN=traefik.example.com
|
||||
# Optional basic auth users for dashboard (format: user:hashed)
|
||||
#TRAEFIK_BASIC_AUTH_USERS=admin:$2y$05$...
|
||||
|
||||
11
infra/env/development/common.env
vendored
Normal file
11
infra/env/development/common.env
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# Development defaults (copy to production and adjust as needed)
|
||||
INFRASTRUCTURE_LABEL=dev
|
||||
TZ=UTC
|
||||
|
||||
TRAEFIK_NETWORK=proxy
|
||||
TRAEFIK_HTTP_PORT=80
|
||||
TRAEFIK_HTTPS_PORT=443
|
||||
TRAEFIK_LOG_LEVEL=INFO
|
||||
ACME_EMAIL=dev@example.com
|
||||
TRAEFIK_DASHBOARD_DOMAIN=traefik.local
|
||||
|
||||
27
nginx/dev-backend.conf
Normal file
27
nginx/dev-backend.conf
Normal file
@@ -0,0 +1,27 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /var/www/public;
|
||||
index index.php index.html;
|
||||
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-Frame-Options SAMEORIGIN;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_pass laravel_backend_dev:9000;
|
||||
fastcgi_index index.php;
|
||||
}
|
||||
|
||||
location ~ /\.(?!well-known).* {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
3
scripts/debug/deploy-backend.sh
Executable file
3
scripts/debug/deploy-backend.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
source ./../setup/set-global-env.sh
|
||||
chmod +x ./../../apps/backend/src/entrypoint.sh
|
||||
docker compose -f ./../../apps/backend/docker-compose.overwrite.yml --env-file ./../../env/${ENVIRONMENT}/.env.database --env-file ./../../env/${ENVIRONMENT}/.env.backend --profile backend up
|
||||
3
scripts/debug/deploy-frontend.sh
Executable file
3
scripts/debug/deploy-frontend.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
source ./../setup/set-global-env.sh
|
||||
source ./../setup/set-frontend-env.sh
|
||||
docker compose -f ./../../apps/frontend/docker-compose.overwrite.yml --env-file ./../../env/${ENVIRONMENT}/.env.frontend --profile frontend up
|
||||
24
scripts/infra/bootstrap.sh
Normal file
24
scripts/infra/bootstrap.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Create external proxy network if it doesn't exist and prepare Traefik state
|
||||
|
||||
NETWORK_NAME=${TRAEFIK_NETWORK:-proxy}
|
||||
ACME_FILE="infra/core/traefik/data/acme.json"
|
||||
|
||||
echo "[bootstrap] Ensuring external network '${NETWORK_NAME}' exists..."
|
||||
if ! docker network ls --format '{{.Name}}' | grep -qx "${NETWORK_NAME}"; then
|
||||
docker network create "${NETWORK_NAME}"
|
||||
echo "[bootstrap] Created network '${NETWORK_NAME}'."
|
||||
else
|
||||
echo "[bootstrap] Network '${NETWORK_NAME}' already exists."
|
||||
fi
|
||||
|
||||
echo "[bootstrap] Ensuring ACME storage exists with correct permissions..."
|
||||
mkdir -p "$(dirname "${ACME_FILE}")"
|
||||
touch "${ACME_FILE}"
|
||||
chmod 600 "${ACME_FILE}"
|
||||
echo "[bootstrap] ACME storage ready at ${ACME_FILE}."
|
||||
|
||||
echo "[bootstrap] Done."
|
||||
|
||||
87
scripts/setup/generate-secrets.sh
Executable file
87
scripts/setup/generate-secrets.sh
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 🚀 Script to Generate Secure Secrets for Deployment
|
||||
|
||||
# Define root directory relative to the script location
|
||||
|
||||
# Stelle sicher, dass ROOT_DIR gesetzt ist
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
echo "❌ WARN: ROOT_DIR ist nicht gesetzt! Setze ROOT_DIR..."
|
||||
source ./set-project-root.sh
|
||||
fi
|
||||
|
||||
SECRET_FILE="$ROOT_DIR/env/secrets.env"
|
||||
GITIGNORE_FILE="$ROOT_DIR/.gitignore"
|
||||
|
||||
# ✅ Function to check if a command is installed
|
||||
check_dependency() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# 🔍 Check for OpenSSL, and prompt user to install if missing
|
||||
if ! check_dependency "openssl"; then
|
||||
echo "⚠️ OpenSSL is not installed. It is required to generate secure secrets."
|
||||
echo "Would you like to install OpenSSL now? (yes/no)"
|
||||
read -r install_choice
|
||||
if [[ "$install_choice" == "yes" ]]; then
|
||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
sudo apt update && sudo apt install -y openssl
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
brew install openssl
|
||||
else
|
||||
echo "❌ Unsupported OS. Please install OpenSSL manually."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "❌ OpenSSL is required but was not installed. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ✅ Securely generate random values
|
||||
generate_secret() {
|
||||
openssl rand -base64 32
|
||||
}
|
||||
|
||||
# 🔄 Check if the secret file already exists
|
||||
if [ -f "$SECRET_FILE" ]; then
|
||||
echo "⚠️ $SECRET_FILE already exists. Overwrite? (yes/no)"
|
||||
read -r response
|
||||
if [[ "$response" != "yes" ]]; then
|
||||
echo "❌ Secret file creation canceled."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ✏️ Write secrets to file
|
||||
echo "🔐 Generating $SECRET_FILE ..."
|
||||
mkdir -p "$(dirname "$SECRET_FILE")" # Ensure the env directory exists
|
||||
> "$SECRET_FILE" # Clear file if it exists
|
||||
|
||||
# 🔑 Define and write secrets
|
||||
echo "ADMIN_PASSWORD_HASH=$(openssl passwd -6 admin)" >> "$SECRET_FILE"
|
||||
echo "JWT_SECRET=$(generate_secret)" >> "$SECRET_FILE"
|
||||
echo "MARIADB_PASSWORD=$(generate_secret)" >> "$SECRET_FILE"
|
||||
echo "MARIADB_ROOT_PASSWORD=$(generate_secret)" >> "$SECRET_FILE"
|
||||
echo "REDIS_HOST_PASSWORD=$(generate_secret)" >> "$SECRET_FILE"
|
||||
echo "TRAEFIK_BASIC_AUTH_USERS=admin:$(openssl passwd -6 traefikpass)" >> "$SECRET_FILE"
|
||||
echo "GITEA_MYSQL_PASSWORD=$(generate_secret)" >> "$SECRET_FILE"
|
||||
echo "NEXTCLOUD_ADMIN_PASSWORD=$(generate_secret)" >> "$SECRET_FILE"
|
||||
echo "MAIL_PASSWORD=$(generate_secret)" >> "$SECRET_FILE"
|
||||
|
||||
# 🛑 Ensure secrets.env is ignored by Git **without overwriting last line**
|
||||
if [ -f "$SECRET_FILE" ]; then
|
||||
# Check if the last line is missing a newline and fix it
|
||||
if [ -s "$GITIGNORE_FILE" ] && [ "$(tail -c1 "$GITIGNORE_FILE")" != "" ]; then
|
||||
echo "" >> "$GITIGNORE_FILE"
|
||||
fi
|
||||
|
||||
# Append 'env/secrets.env' only if it's not already in .gitignore
|
||||
if ! grep -q "^env/secrets.env$" "$GITIGNORE_FILE"; then
|
||||
echo "env/secrets.env" >> "$GITIGNORE_FILE"
|
||||
echo "✅ Added 'env/secrets.env' to .gitignore"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ Secrets have been generated and stored in $SECRET_FILE."
|
||||
echo "⚠️ Keep this file secure and do NOT commit it to Git!"
|
||||
59
scripts/setup/set-frontend-env.sh
Normal file
59
scripts/setup/set-frontend-env.sh
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
# Stelle sicher, dass ROOT_DIR gesetzt ist
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
echo "❌ WARN: ROOT_DIR ist nicht gesetzt! Setze ROOT_DIR..."
|
||||
# Bestimme das Root-Verzeichnis des Git-Repos
|
||||
ROOT_DIR=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
|
||||
# Falls das Repository nicht gefunden wurde, abbrechen
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
echo "❌ Fehler: Kein Git-Repository gefunden!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Setze die Variable für die aktuelle Shell-Sitzung
|
||||
export ROOT_DIR
|
||||
echo "✅ ROOT_DIR gesetzt auf: $ROOT_DIR"
|
||||
fi
|
||||
|
||||
# Setze den Pfad zur .env.all Datei relativ zum Projekt-Root
|
||||
ENV_FILE="$ROOT_DIR/env/development/.env.frontend"
|
||||
|
||||
# Prüfen, ob die Datei existiert
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "❌ Fehler: Die Datei $ENV_FILE existiert nicht!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ ENV-Datei vorhanden: $ENV_FILE"
|
||||
|
||||
# Funktion: Alle Variablen exportieren
|
||||
export_env_vars() {
|
||||
while IFS='=' read -r key value; do
|
||||
# Entferne führende und nachfolgende Leerzeichen
|
||||
key=$(echo "$key" | xargs)
|
||||
value=$(echo "$value" | xargs)
|
||||
|
||||
# Falls die Zeile ein Kommentar oder leer ist, überspringen
|
||||
if [[ -z "$key" || "$key" =~ ^# || -z "$value" ]]; then
|
||||
continue
|
||||
fi
|
||||
# Exportiere die Variable
|
||||
export "$key=$value"
|
||||
done < "$ENV_FILE"
|
||||
}
|
||||
|
||||
# Alle Variablen exportieren
|
||||
export_env_vars
|
||||
|
||||
echo "🔹 Geladene Variablen:"
|
||||
grep -o '^[^#]*' "$ENV_FILE" | cut -d '=' -f1 | while read -r var; do
|
||||
echo "$var=${!var}" # Gibt die gesetzten Variablen mit ihrem Wert aus
|
||||
done
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
65
scripts/setup/set-global-env.sh
Executable file
65
scripts/setup/set-global-env.sh
Executable file
@@ -0,0 +1,65 @@
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
# Stelle sicher, dass ROOT_DIR gesetzt ist
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
echo "❌ WARN: ROOT_DIR ist nicht gesetzt! Setze ROOT_DIR..."
|
||||
# Bestimme das Root-Verzeichnis des Git-Repos
|
||||
ROOT_DIR=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
|
||||
# Falls das Repository nicht gefunden wurde, abbrechen
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
echo "❌ Fehler: Kein Git-Repository gefunden!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Setze die Variable für die aktuelle Shell-Sitzung
|
||||
export ROOT_DIR
|
||||
echo "✅ ROOT_DIR gesetzt auf: $ROOT_DIR"
|
||||
fi
|
||||
|
||||
# Setze den Pfad zur .env.all Datei relativ zum Projekt-Root
|
||||
ENV_FILE="$ROOT_DIR/env/.env.all"
|
||||
|
||||
# Prüfen, ob die Datei existiert
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "❌ Fehler: Die Datei $ENV_FILE existiert nicht!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ ENV-Datei vorhanden: $ENV_FILE"
|
||||
|
||||
# Funktion: Alle Variablen exportieren
|
||||
export_env_vars() {
|
||||
while IFS='=' read -r key value; do
|
||||
# Entferne führende und nachfolgende Leerzeichen
|
||||
key=$(echo "$key" | xargs)
|
||||
value=$(echo "$value" | xargs)
|
||||
|
||||
# Falls die Zeile ein Kommentar oder leer ist, überspringen
|
||||
if [[ -z "$key" || "$key" =~ ^# || -z "$value" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Entferne umschließende Anführungszeichen, falls vorhanden
|
||||
value=$(echo "$value" | sed -E 's/^"(.*)"$/\1/')
|
||||
|
||||
# Exportiere die Variable
|
||||
export "$key=$value"
|
||||
done < "$ENV_FILE"
|
||||
}
|
||||
|
||||
# Alle Variablen exportieren
|
||||
export_env_vars
|
||||
|
||||
export SERVER_IP=$(curl -s https://api.ipify.org)
|
||||
|
||||
echo "🔹 Geladene Variablen:"
|
||||
grep -o '^[^#]*' "$ENV_FILE" | cut -d '=' -f1 | while read -r var; do
|
||||
echo "$var=${!var}" # Gibt die gesetzten Variablen mit ihrem Wert aus
|
||||
done
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
14
scripts/setup/set-project-root.sh
Executable file
14
scripts/setup/set-project-root.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Bestimme das Root-Verzeichnis des Git-Repos
|
||||
ROOT_DIR=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
|
||||
# Falls das Repository nicht gefunden wurde, abbrechen
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
echo "❌ Fehler: Kein Git-Repository gefunden!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Setze die Variable für die aktuelle Shell-Sitzung
|
||||
export ROOT_DIR
|
||||
echo "✅ ROOT_DIR gesetzt auf: $ROOT_DIR"
|
||||
60
scripts/setup/set-proxy-env.sh
Normal file
60
scripts/setup/set-proxy-env.sh
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
# Stelle sicher, dass ROOT_DIR gesetzt ist
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
echo "❌ WARN: ROOT_DIR ist nicht gesetzt! Setze ROOT_DIR..."
|
||||
source ./set-project-root.sh
|
||||
fi
|
||||
|
||||
# Stelle sicher, dass ENVIRONMENT gesetzt ist
|
||||
if [ -z "$ENVIRONMENT" ]; then
|
||||
echo "❌ WARN: ENVIRONMENT ist nicht gesetzt! Setze ENVIRONMENT..."
|
||||
source ./set-global-env.sh
|
||||
fi
|
||||
|
||||
# Setze den Pfad zur .env.all Datei relativ zum Projekt-Root
|
||||
ENV_FILE="$ROOT_DIR/env/${ENVIRONMENT}/.env.proxy"
|
||||
|
||||
# Prüfen, ob die Datei existiert
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "❌ Fehler: Die Datei $ENV_FILE existiert nicht!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ ENV-Datei vorhanden: $ENV_FILE"
|
||||
|
||||
# Funktion: Alle Variablen exportieren
|
||||
export_env_vars() {
|
||||
while IFS='=' read -r key value; do
|
||||
# Entferne führende und nachfolgende Leerzeichen
|
||||
key=$(echo "$key" | xargs)
|
||||
value=$(echo "$value" | xargs)
|
||||
|
||||
# Falls die Zeile ein Kommentar oder leer ist, überspringen
|
||||
if [[ -z "$key" || "$key" =~ ^# || -z "$value" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Entferne umschließende Anführungszeichen, falls vorhanden
|
||||
value=$(echo "$value" | sed -E 's/^"(.*)"$/\1/')
|
||||
|
||||
# Exportiere die Variable
|
||||
export "$key=$value"
|
||||
done < "$ENV_FILE"
|
||||
}
|
||||
|
||||
# Alle Variablen exportieren
|
||||
export_env_vars
|
||||
|
||||
export SERVER_IP=$(curl -s https://api.ipify.org)
|
||||
|
||||
echo "🔹 Geladene Variablen:"
|
||||
grep -o '^[^#]*' "$ENV_FILE" | cut -d '=' -f1 | while read -r var; do
|
||||
echo "$var=${!var}" # Gibt die gesetzten Variablen mit ihrem Wert aus
|
||||
done
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Pfad zur .env.all Datei
|
||||
ENV_FILE="../env/.env.all"
|
||||
ENV_FILE="../../env/.env.all"
|
||||
|
||||
# Funktion zum Überprüfen der Existenz einer Datei
|
||||
check_file_exists() {
|
||||
@@ -12,7 +12,7 @@ check_file_exists() {
|
||||
}
|
||||
|
||||
# Überprüfe die Existenz von .env.all
|
||||
check_file_exists "../env/.env.all"
|
||||
check_file_exists "../../env/.env.all"
|
||||
|
||||
# Funktion zum Auslesen von Variablen aus der .env.all Datei
|
||||
get_env_var() {
|
||||
@@ -25,8 +25,8 @@ ENVIRONMENT=$(get_env_var "ENVIRONMENT")
|
||||
|
||||
# Load environment variables from the .env files
|
||||
set -o allexport
|
||||
source ../env/.env.all
|
||||
source ../env/${ENVIRONMENT}/.env.administration
|
||||
source ../../env/.env.all
|
||||
source ../../env/${ENVIRONMENT:-development}/.env.administration
|
||||
set +o allexport
|
||||
|
||||
# Liste Stacks
|
||||
@@ -39,14 +39,14 @@ ENVIRONMENTS=("development" "staging" "production")
|
||||
# Überprüfe die Existenz aller Stack-spezifischen .env Dateien
|
||||
missing_files=0
|
||||
for stack in "${STACKS[@]}"; do
|
||||
env_file="../env/${ENVIRONMENT}/.env.${stack}"
|
||||
env_file="../../env/${ENVIRONMENT:-development}/.env.${stack}"
|
||||
if ! check_file_exists "$env_file"; then
|
||||
missing_files=$((missing_files + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $missing_files -eq 0 ]; then
|
||||
echo "Alle erforderlichen .env Dateien für das ${ENVIRONMENT}-Environment sind vorhanden."
|
||||
echo "Alle erforderlichen .env Dateien für das ${ENVIRONMENT:-development}-Environment sind vorhanden."
|
||||
else
|
||||
echo "Warnung: $missing_files .env Datei(en) fehlen. Einige Stacks könnten nicht korrekt funktionieren."
|
||||
fi
|
||||
@@ -55,7 +55,7 @@ fi
|
||||
for env in "${ENVIRONMENTS[@]}"; do
|
||||
if [ "$env" != "$ENVIRONMENT" ]; then
|
||||
for stack in "${STACKS[@]}"; do
|
||||
env_file="../env/${env}/.env.${stack}"
|
||||
env_file="../../env/${env}/.env.${stack}"
|
||||
if ! check_file_exists "$env_file"; then
|
||||
echo "Warnung: Die Datei $env_file fehlt für das Environment $env."
|
||||
fi
|
||||
@@ -72,4 +72,4 @@ echo "ENVIRONMENT: ${ENVIRONMENT:-Not set}"
|
||||
echo "-----------------------------------"
|
||||
|
||||
# Ausführen des Docker Compose Befehls
|
||||
docker compose -f ../apps/docker-compose.all.yml --env-file ../env/.env.all --env-file ../env/${ENVIRONMENT}/.env.proxy --profile administration up --remove-orphans
|
||||
docker compose -f ../apps/docker-compose.all.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile administration up --remove-orphans
|
||||
@@ -1,7 +1,12 @@
|
||||
#!/bin/bash
|
||||
source ../setup/set-project-root.sh
|
||||
source ../setup/set-global-env.sh
|
||||
source ../setup/set-proxy-env.sh
|
||||
source ../setup/generate-secrets.sh
|
||||
|
||||
|
||||
# Pfad zur .env.all Datei
|
||||
ENV_FILE="../env/.env.all"
|
||||
ENV_FILE="../../env/.env.all"
|
||||
# Funktion zum Auslesen von Variablen aus der .env.all Datei
|
||||
get_env_var() {
|
||||
grep "^$1=" "$ENV_FILE" | cut -d '=' -f2
|
||||
@@ -25,7 +30,6 @@ check_file_exists() {
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
#!/bin/bash
|
||||
|
||||
# Prüfe, ob das Skript nur in der Entwicklungsumgebung ausgeführt wird
|
||||
if [ "$ENVIRONMENT" == "development" ]; then
|
||||
@@ -43,7 +47,7 @@ if [ "$ENVIRONMENT" == "development" ]; then
|
||||
echo "🔹 ENVIRONMENT ist 'development' – Hosts aus .env.proxy werden hinzugefügt und Container gestartet."
|
||||
|
||||
# Pfad zur Proxy-Env-Datei
|
||||
ENV_PROXY_FILE="../env/development/.env.proxy"
|
||||
ENV_PROXY_FILE="../../env/development/.env.proxy"
|
||||
|
||||
# Hosts-Datei Pfad (Linux/macOS)
|
||||
HOSTS_FILE="/etc/hosts"
|
||||
@@ -72,12 +76,12 @@ else
|
||||
fi
|
||||
|
||||
# Überprüfe die Existenz von .env.all
|
||||
check_file_exists "../env/.env.all"
|
||||
check_file_exists "../../env/.env.all"
|
||||
|
||||
# Überprüfe die Existenz aller Stack-spezifischen .env Dateien
|
||||
missing_files=0
|
||||
for stack in "${STACKS[@]}"; do
|
||||
env_file="../env/${ENVIRONMENT}/.env.${stack}"
|
||||
env_file="../../env/${ENVIRONMENT:-development}/.env.${stack}"
|
||||
if ! check_file_exists "$env_file"; then
|
||||
missing_files=$((missing_files + 1))
|
||||
fi
|
||||
@@ -102,4 +106,4 @@ if [[ "$1" == "--build" ]]; then
|
||||
fi
|
||||
|
||||
# Ausführen des Docker Compose Befehls
|
||||
docker compose -f ../apps/docker-compose.all.yml -p ${INFRASTRUCTURE:-my} --env-file ../env/.env.all --env-file ../env/${ENVIRONMENT}/.env.proxy --profile backend up --remove-orphans $BUILD_OPTION
|
||||
docker compose -f ../../apps/docker-compose.all.yml -p ${INFRASTRUCTURE:-my} --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile backend up --remove-orphans $BUILD_OPTION
|
||||
@@ -1,7 +1,11 @@
|
||||
#!/bin/bash
|
||||
source ../setup/set-project-root.sh
|
||||
source ../setup/set-global-env.sh
|
||||
source ../setup/set-proxy-env.sh
|
||||
source ../setup/generate-secrets.sh
|
||||
|
||||
# Pfad zur .env.all Datei
|
||||
ENV_FILE="../env/.env.all"
|
||||
ENV_FILE="../../env/.env.all"
|
||||
# Funktion zum Auslesen von Variablen aus der .env.all Datei
|
||||
get_env_var() {
|
||||
grep "^$1=" "$ENV_FILE" | cut -d '=' -f2
|
||||
@@ -13,7 +17,7 @@ ENVIRONMENT=$(get_env_var "ENVIRONMENT")
|
||||
SERVER_IP=$(curl -s https://api.ipify.org)
|
||||
|
||||
# Liste aller Stacks
|
||||
STACKS=("administration" "frontend" "develop" "database" "proxy" "tools" "website" "backend")
|
||||
STACKS=("proxy" "frontend" "database" "backend")
|
||||
|
||||
# Liste aller Environments
|
||||
ENVIRONMENTS=("development" "staging" "production")
|
||||
@@ -26,12 +30,12 @@ check_file_exists() {
|
||||
fi
|
||||
}
|
||||
# Überprüfe die Existenz von .env.all
|
||||
check_file_exists "../env/.env.all"
|
||||
check_file_exists "../../env/.env.all"
|
||||
|
||||
# Überprüfe die Existenz aller Stack-spezifischen .env Dateien
|
||||
missing_files=0
|
||||
for stack in "${STACKS[@]}"; do
|
||||
env_file="../env/${ENVIRONMENT}/.env.${stack}"
|
||||
env_file="../../env/${ENVIRONMENT:-development}/.env.${stack}"
|
||||
if ! check_file_exists "$env_file"; then
|
||||
missing_files=$((missing_files + 1))
|
||||
fi
|
||||
@@ -44,7 +48,7 @@ else
|
||||
fi
|
||||
|
||||
# Ausgabe der Variablen
|
||||
echo "Deploying to:"
|
||||
echo "Deploying to"
|
||||
echo "INFRASTRUCTURE: ${INFRASTRUCTURE:-Not set}"
|
||||
echo "ENVIRONMENT: ${ENVIRONMENT:-Not set}"
|
||||
echo "-----------------------------------"
|
||||
@@ -55,5 +59,7 @@ if [[ "$1" == "--build" ]]; then
|
||||
BUILD_OPTION="--build"
|
||||
fi
|
||||
|
||||
|
||||
# Ausführen des Docker Compose Befehls
|
||||
docker compose -f ../apps/docker-compose.all.yml -p ${INFRASTRUCTURE:-my} --env-file ../env/.env.all --env-file ../env/${ENVIRONMENT}/.env.proxy --profile app up --remove-orphans $BUILD_OPTION
|
||||
docker compose -f ../../apps/docker-compose.all.yml -p ${INFRASTRUCTURE:-my} --profile app up --remove-orphans $BUILD_OPTION
|
||||
|
||||
3
scripts/start/deploy-backend.sh
Executable file
3
scripts/start/deploy-backend.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
source ./../setup/set-global-env.sh
|
||||
chmod +x ./../../apps/backend/src/entrypoint.sh
|
||||
docker compose -f ./../../apps/backend/docker-compose.yml --env-file ./../../env/${ENVIRONMENT}/.env.database --env-file ./../../env/${ENVIRONMENT}/.env.backend --profile backend up
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Pfad zur .env.all Datei
|
||||
ENV_FILE="../env/.env.all"
|
||||
ENV_FILE="../../env/.env.all"
|
||||
|
||||
# Funktion zum Auslesen von Variablen aus der .env.all Datei
|
||||
get_env_var() {
|
||||
@@ -27,12 +27,12 @@ check_file_exists() {
|
||||
}
|
||||
|
||||
# Überprüfe die Existenz von .env.all
|
||||
check_file_exists "../env/.env.all"
|
||||
check_file_exists "../../env/.env.all"
|
||||
|
||||
# Überprüfe die Existenz aller Stack-spezifischen .env Dateien
|
||||
missing_files=0
|
||||
for stack in "${STACKS[@]}"; do
|
||||
env_file="../env/${ENVIRONMENT}/.env.${stack}"
|
||||
env_file="../../env/${ENVIRONMENT:-development}/.env.${stack}"
|
||||
if ! check_file_exists "$env_file"; then
|
||||
missing_files=$((missing_files + 1))
|
||||
fi
|
||||
@@ -51,4 +51,4 @@ echo "ENVIRONMENT: ${ENVIRONMENT:-Not set}"
|
||||
echo "-----------------------------------"
|
||||
|
||||
# Ausführen des Docker Compose Befehls
|
||||
docker compose -f ../apps/docker-compose.all.yml --env-file ../env/.env.all --env-file ../env/${ENVIRONMENT}/.env.proxy --profile proxy up --remove-orphans
|
||||
docker compose -f ../../apps/docker-compose.all.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans
|
||||
@@ -3,7 +3,7 @@ set -e
|
||||
|
||||
# Funktion zur Überprüfung der Produktivumgebung
|
||||
is_production() {
|
||||
local prod_ip="85.215.56.185" # IP-Adresse deines Produktivservers
|
||||
local prod_ip=${SERVER_IP:-127.0.0.1} # IP-Adresse deines Produktivservers
|
||||
local current_ip
|
||||
|
||||
# Überprüfe das Betriebssystem
|
||||
@@ -69,30 +69,27 @@ if ! docker ps --format '{{.Names}}' | grep -q 'traefik'; then
|
||||
echo "Wir befinden uns in der Produktivumgebung."
|
||||
echo "Starte Traefik und CrowdSec Bouncer mit docker-compose.traefik.prod.yml..."
|
||||
env | grep DOMAIN # Debug: Zeige die gesetzten Umgebungsvariablen an
|
||||
docker compose -f ../apps/proxy/docker-compose.traefik.prod.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
else
|
||||
echo "Wir befinden uns in der lokalen Entwicklungsumgebung."
|
||||
echo "Starte Traefik und CrowdSec Bouncer mit docker-compose.traefik.local.yml..."
|
||||
env | grep DOMAIN # Debug: Zeige die gesetzten Umgebungsvariablen an
|
||||
docker compose -f ../apps/docker-compose.traefik.local.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.overwrite.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
fi
|
||||
else
|
||||
echo "Traefik läuft bereits. Aktualisiere die Konfiguration..."
|
||||
|
||||
if is_production; then
|
||||
echo "Aktualisiere Traefik und CrowdSec Bouncer in der Produktivumgebung..."
|
||||
docker compose -f ../apps/docker-compose.traefik.prod.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
else
|
||||
echo "Aktualisiere Traefik und CrowdSec Bouncer in der lokalen Umgebung..."
|
||||
docker compose -f ../apps/docker-compose.traefik.local.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.overwrite.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Traefik und CrowdSec Bouncer Deployment abgeschlossen."
|
||||
|
||||
=================
|
||||
|
||||
|
||||
echo "Prüfe, ob Traefik läuft..."
|
||||
|
||||
set_environment_variables
|
||||
@@ -106,14 +103,14 @@ fi
|
||||
|
||||
if is_production; then
|
||||
echo "Wir befinden uns in der Produktivumgebung."
|
||||
echo "Starte/Aktualisiere Deployment mit docker-compose.prod.yml..."
|
||||
echo "Starte/Aktualisiere Deployment mit docker-compose.yml..."
|
||||
env | grep DOMAIN # Debug: Zeige die gesetzten Umgebungsvariablen an
|
||||
docker compose -f ../apps/docker-compose.prod.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
else
|
||||
echo "Wir befinden uns in der lokalen Entwicklungsumgebung."
|
||||
echo "Starte/Aktualisiere lokale Version mit docker-compose.overwrite.yml..."
|
||||
env | grep DOMAIN # Debug: Zeige die gesetzten Umgebungsvariablen an
|
||||
docker compose -f ../apps/docker-compose.overwrite.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.overwrite.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
fi
|
||||
|
||||
|
||||
@@ -123,9 +120,9 @@ if ! docker ps --format '{{.Names}}' | grep -q 'traefik'; then
|
||||
if is_production; then
|
||||
echo "Wir befinden uns in der Produktivumgebung."
|
||||
set_environment_variables
|
||||
echo "Starte Deployment mit docker-compose.prod.yml..."
|
||||
echo "Starte Deployment mit docker-compose.yml..."
|
||||
env | grep DOMAIN # Debug: Zeige die gesetzten Umgebungsvariablen an
|
||||
docker compose -f ../apps/docker-compose.prod.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
else
|
||||
echo "Wir befinden uns in der lokalen Entwicklungsumgebung."
|
||||
read -p "Möchtest du die lokale Version zum Debuggen (docker-compose.overwrite.yml) starten? (y/n): " answer
|
||||
@@ -133,7 +130,7 @@ if ! docker ps --format '{{.Names}}' | grep -q 'traefik'; then
|
||||
echo "Starte lokale Version..."
|
||||
set_environment_variables
|
||||
env | grep DOMAIN # Debug: Zeige die gesetzten Umgebungsvariablen an
|
||||
docker compose -f ../apps/docker-compose.overwrite.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.overwrite.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
else
|
||||
echo "Deployment abgebrochen."
|
||||
exit 1
|
||||
@@ -145,15 +142,15 @@ else
|
||||
if is_production; then
|
||||
echo "Wir befinden uns in der Produktivumgebung."
|
||||
set_environment_variables
|
||||
echo "Aktualisiere Deployment mit docker-compose.prod.yml..."
|
||||
echo "Aktualisiere Deployment mit docker-compose.yml..."
|
||||
env | grep DOMAIN # Debug: Zeige die gesetzten Umgebungsvariablen an
|
||||
docker compose -f ../apps/docker-compose.prod.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
else
|
||||
echo "Wir befinden uns in der lokalen Entwicklungsumgebung."
|
||||
set_environment_variables
|
||||
echo "Aktualisiere lokale Version mit docker-compose.overwrite.yml..."
|
||||
env | grep DOMAIN # Debug: Zeige die gesetzten Umgebungsvariablen an
|
||||
docker compose -f ../apps/docker-compose.overwrite.yml up -d
|
||||
docker compose -f ../../apps/proxy/docker-compose.overwrite.yml --env-file ../../env/.env.all --env-file ../../env/${ENVIRONMENT:-development}/.env.proxy --profile proxy up --remove-orphans -d
|
||||
fi
|
||||
fi
|
||||
|
||||
37
scripts/start/deploy.sh
Executable file
37
scripts/start/deploy.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
#!/bin/bash
|
||||
|
||||
# Bestimme das Root-Verzeichnis des Git-Repos
|
||||
ROOT_DIR=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
|
||||
# Falls das Repository nicht gefunden wurde, abbrechen
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
echo "❌ Fehler: Kein Git-Repository gefunden!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Setze die Variable für die aktuelle Shell-Sitzung
|
||||
echo "✅ ROOT_DIR gesetzt auf: $ROOT_DIR"
|
||||
|
||||
# Pfad zur .env.all Datei
|
||||
ENV_FILE="${ROOT_DIR}/env/.env.all"
|
||||
echo $ENV_FILE
|
||||
# Funktion zum Auslesen von Variablen aus der .env.all Datei
|
||||
get_env_var() {
|
||||
grep "^$1=" "$ENV_FILE" | cut -d '=' -f2
|
||||
}
|
||||
|
||||
# Auslesen der INFRASTRUCTURE und ENVIRONMENT Variablen
|
||||
INFRASTRUCTURE=$(get_env_var "INFRASTRUCTURE_LABEL")
|
||||
ENVIRONMENT=$(get_env_var "ENVIRONMENT")
|
||||
SERVER_IP=$(curl -s https://api.ipify.org)
|
||||
|
||||
|
||||
# Ausgabe der Variablen
|
||||
echo "Deploying to:"
|
||||
echo "INFRASTRUCTURE: ${INFRASTRUCTURE:-Not set}"
|
||||
echo "ENVIRONMENT: ${ENVIRONMENT:-Not set}"
|
||||
echo "-----------------------------------"
|
||||
|
||||
# Ausführen des Docker Compose Befehls
|
||||
docker compose -f ../../apps/docker-compose.all.yml -p ${INFRASTRUCTURE:-my} --env-file ${ENV_FILE} --env-file ${ROOT_DIR}/env/${ENVIRONMENT:-development}/.env.proxy --profile app up --remove-orphans
|
||||
Reference in New Issue
Block a user