mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
feat: add multi-arch Docker builds and Mac Mini deployment
- CI: Build Docker images for linux/amd64 + linux/arm64 - CI: Add manacore-web to build matrix - Add docker-compose.macmini.yml for Mac Mini deployment - Add cloudflared-config.yml for Cloudflare Tunnel routing - Add Mac Mini deployment scripts and documentation - Configure Cloudflared as launchd service for auto-start Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e02a94a29c
commit
4ebe3ec574
8 changed files with 823 additions and 0 deletions
33
.env.macmini.example
Normal file
33
.env.macmini.example
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Mac Mini Production Environment
|
||||||
|
# Copy to .env.macmini and fill in the values
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Database (PostgreSQL)
|
||||||
|
# ============================================
|
||||||
|
POSTGRES_PASSWORD=your-secure-password-here
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Redis
|
||||||
|
# ============================================
|
||||||
|
REDIS_PASSWORD=your-redis-password-here
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# JWT Keys (generate with: openssl rand -base64 32)
|
||||||
|
# For EdDSA keys, use mana-core-auth key generation
|
||||||
|
# ============================================
|
||||||
|
JWT_SECRET=your-jwt-secret-here
|
||||||
|
# Leave empty to use auto-generated keys
|
||||||
|
JWT_PUBLIC_KEY=
|
||||||
|
JWT_PRIVATE_KEY=
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Supabase (optional, for legacy features)
|
||||||
|
# ============================================
|
||||||
|
SUPABASE_URL=
|
||||||
|
SUPABASE_SERVICE_ROLE_KEY=
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Azure OpenAI (for Chat AI features)
|
||||||
|
# ============================================
|
||||||
|
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
|
||||||
|
AZURE_OPENAI_API_KEY=your-api-key-here
|
||||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
|
@ -61,6 +61,7 @@ jobs:
|
||||||
run: pnpm run lint || echo "Lint warnings found"
|
run: pnpm run lint || echo "Lint warnings found"
|
||||||
|
|
||||||
# Build Docker images - only on push to dev/main (not PRs)
|
# Build Docker images - only on push to dev/main (not PRs)
|
||||||
|
# Multi-arch build: linux/amd64 (Hetzner) + linux/arm64 (Mac Mini)
|
||||||
build-docker-images:
|
build-docker-images:
|
||||||
name: Build ${{ matrix.service.name }}
|
name: Build ${{ matrix.service.name }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
@ -69,6 +70,7 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
service:
|
service:
|
||||||
- { name: 'mana-core-auth', path: 'services/mana-core-auth', port: '3001' }
|
- { name: 'mana-core-auth', path: 'services/mana-core-auth', port: '3001' }
|
||||||
|
- { name: 'manacore-web', path: 'apps/manacore/apps/web', port: '5173' }
|
||||||
- { name: 'chat-backend', path: 'apps/chat/apps/backend', port: '3002' }
|
- { name: 'chat-backend', path: 'apps/chat/apps/backend', port: '3002' }
|
||||||
- { name: 'chat-web', path: 'apps/chat/apps/web', port: '3000' }
|
- { name: 'chat-web', path: 'apps/chat/apps/web', port: '3000' }
|
||||||
- { name: 'todo-backend', path: 'apps/todo/apps/backend', port: '3018' }
|
- { name: 'todo-backend', path: 'apps/todo/apps/backend', port: '3018' }
|
||||||
|
|
@ -82,6 +84,9 @@ jobs:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
|
@ -118,6 +123,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ${{ matrix.service.path }}/Dockerfile
|
file: ${{ matrix.service.path }}/Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -96,3 +96,7 @@ yarn.lock
|
||||||
# Claude Flow metrics
|
# Claude Flow metrics
|
||||||
.claude-flow/
|
.claude-flow/
|
||||||
.claude-flow/metrics/
|
.claude-flow/metrics/
|
||||||
|
|
||||||
|
# Mac Mini deployment
|
||||||
|
.env.macmini
|
||||||
|
ssh-key-command.txt
|
||||||
|
|
|
||||||
25
cloudflared-config.yml
Normal file
25
cloudflared-config.yml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
tunnel: bb0ea86d-8253-4a54-838b-107bb7945be9
|
||||||
|
credentials-file: /Users/mana/.cloudflared/bb0ea86d-8253-4a54-838b-107bb7945be9.json
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
- hostname: auth.mana.how
|
||||||
|
service: http://localhost:3001
|
||||||
|
- hostname: mana.how
|
||||||
|
service: http://localhost:5173
|
||||||
|
- hostname: chat.mana.how
|
||||||
|
service: http://localhost:3000
|
||||||
|
- hostname: chat-api.mana.how
|
||||||
|
service: http://localhost:3002
|
||||||
|
- hostname: todo.mana.how
|
||||||
|
service: http://localhost:5188
|
||||||
|
- hostname: todo-api.mana.how
|
||||||
|
service: http://localhost:3018
|
||||||
|
- hostname: calendar.mana.how
|
||||||
|
service: http://localhost:5186
|
||||||
|
- hostname: calendar-api.mana.how
|
||||||
|
service: http://localhost:3016
|
||||||
|
- hostname: clock.mana.how
|
||||||
|
service: http://localhost:5187
|
||||||
|
- hostname: clock-api.mana.how
|
||||||
|
service: http://localhost:3017
|
||||||
|
- service: http_status:404
|
||||||
329
docker-compose.macmini.yml
Normal file
329
docker-compose.macmini.yml
Normal file
|
|
@ -0,0 +1,329 @@
|
||||||
|
# ManaCore Mac Mini Configuration
|
||||||
|
# Domain: mana.how (via Cloudflare Tunnel)
|
||||||
|
|
||||||
|
services:
|
||||||
|
# ============================================
|
||||||
|
# Infrastructure Services
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: manacore-postgres
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: manacore
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-manacore123}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: manacore-redis
|
||||||
|
restart: always
|
||||||
|
command: redis-server --requirepass ${REDIS_PASSWORD:-redis123}
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Auth Service
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
mana-core-auth:
|
||||||
|
image: ghcr.io/memo-2023/mana-core-auth:latest
|
||||||
|
container_name: mana-core-auth
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 3001
|
||||||
|
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/manacore_auth
|
||||||
|
REDIS_HOST: redis
|
||||||
|
REDIS_PORT: 6379
|
||||||
|
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
|
||||||
|
JWT_SECRET: ${JWT_SECRET:-your-jwt-secret-change-me}
|
||||||
|
JWT_PUBLIC_KEY: ${JWT_PUBLIC_KEY:-}
|
||||||
|
JWT_PRIVATE_KEY: ${JWT_PRIVATE_KEY:-}
|
||||||
|
CORS_ORIGINS: https://mana.how,https://chat.mana.how,https://todo.mana.how,https://calendar.mana.how,https://clock.mana.how
|
||||||
|
ports:
|
||||||
|
- "3001:3001"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/api/v1/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ManaCore Dashboard
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
manacore-web:
|
||||||
|
image: ghcr.io/memo-2023/manacore-web:latest
|
||||||
|
container_name: manacore-web
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
mana-core-auth:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 5173
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
|
||||||
|
PUBLIC_TODO_API_URL: http://todo-backend:3018
|
||||||
|
PUBLIC_TODO_API_URL_CLIENT: https://todo-api.mana.how
|
||||||
|
PUBLIC_CALENDAR_API_URL: http://calendar-backend:3016
|
||||||
|
PUBLIC_CALENDAR_API_URL_CLIENT: https://calendar-api.mana.how
|
||||||
|
PUBLIC_CLOCK_API_URL: http://clock-backend:3017
|
||||||
|
PUBLIC_CLOCK_API_URL_CLIENT: https://clock-api.mana.how
|
||||||
|
ports:
|
||||||
|
- "5173:5173"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5173/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Chat App
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
chat-backend:
|
||||||
|
image: ghcr.io/memo-2023/chat-backend:latest
|
||||||
|
container_name: chat-backend
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
mana-core-auth:
|
||||||
|
condition: service_healthy
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 3002
|
||||||
|
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/chat
|
||||||
|
MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||||
|
SUPABASE_URL: ${SUPABASE_URL:-}
|
||||||
|
SUPABASE_SERVICE_KEY: ${SUPABASE_SERVICE_ROLE_KEY:-}
|
||||||
|
AZURE_OPENAI_ENDPOINT: ${AZURE_OPENAI_ENDPOINT:-}
|
||||||
|
AZURE_OPENAI_API_KEY: ${AZURE_OPENAI_API_KEY:-}
|
||||||
|
AZURE_OPENAI_API_VERSION: 2024-12-01-preview
|
||||||
|
CORS_ORIGINS: https://chat.mana.how,https://mana.how
|
||||||
|
ports:
|
||||||
|
- "3002:3002"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3002/api/v1/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
chat-web:
|
||||||
|
image: ghcr.io/memo-2023/chat-web:latest
|
||||||
|
container_name: chat-web
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
chat-backend:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 3000
|
||||||
|
PUBLIC_BACKEND_URL: http://chat-backend:3002
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||||
|
PUBLIC_BACKEND_URL_CLIENT: https://chat-api.mana.how
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Todo App
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
todo-backend:
|
||||||
|
image: ghcr.io/memo-2023/todo-backend:latest
|
||||||
|
container_name: todo-backend
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
mana-core-auth:
|
||||||
|
condition: service_healthy
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 3018
|
||||||
|
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/todo
|
||||||
|
MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||||
|
CORS_ORIGINS: https://todo.mana.how,https://mana.how
|
||||||
|
ports:
|
||||||
|
- "3018:3018"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3018/api/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
todo-web:
|
||||||
|
image: ghcr.io/memo-2023/todo-web:latest
|
||||||
|
container_name: todo-web
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
todo-backend:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 5188
|
||||||
|
PUBLIC_BACKEND_URL: http://todo-backend:3018
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||||
|
PUBLIC_BACKEND_URL_CLIENT: https://todo-api.mana.how
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
|
||||||
|
ports:
|
||||||
|
- "5188:5188"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5188/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Calendar App
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
calendar-backend:
|
||||||
|
image: ghcr.io/memo-2023/calendar-backend:latest
|
||||||
|
container_name: calendar-backend
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
mana-core-auth:
|
||||||
|
condition: service_healthy
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 3016
|
||||||
|
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/calendar
|
||||||
|
DB_HOST: postgres
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_USER: postgres
|
||||||
|
MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||||
|
CORS_ORIGINS: https://calendar.mana.how,https://mana.how
|
||||||
|
ports:
|
||||||
|
- "3016:3016"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3016/api/v1/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
calendar-web:
|
||||||
|
image: ghcr.io/memo-2023/calendar-web:latest
|
||||||
|
container_name: calendar-web
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
calendar-backend:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 5186
|
||||||
|
PUBLIC_BACKEND_URL: http://calendar-backend:3016
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||||
|
PUBLIC_BACKEND_URL_CLIENT: https://calendar-api.mana.how
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
|
||||||
|
ports:
|
||||||
|
- "5186:5186"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5186/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Clock App
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
clock-backend:
|
||||||
|
image: ghcr.io/memo-2023/clock-backend:latest
|
||||||
|
container_name: clock-backend
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
mana-core-auth:
|
||||||
|
condition: service_healthy
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 3017
|
||||||
|
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/clock
|
||||||
|
DB_HOST: postgres
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_USER: postgres
|
||||||
|
MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||||
|
CORS_ORIGINS: https://clock.mana.how,https://mana.how
|
||||||
|
ports:
|
||||||
|
- "3017:3017"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3017/api/v1/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
clock-web:
|
||||||
|
image: ghcr.io/memo-2023/clock-web:latest
|
||||||
|
container_name: clock-web
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
clock-backend:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 5187
|
||||||
|
PUBLIC_BACKEND_URL: http://clock-backend:3017
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||||
|
PUBLIC_BACKEND_URL_CLIENT: https://clock-api.mana.how
|
||||||
|
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
|
||||||
|
ports:
|
||||||
|
- "5187:5187"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5187/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Volumes
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
name: manacore-postgres
|
||||||
|
redis_data:
|
||||||
|
name: manacore-redis
|
||||||
234
docs/MAC_MINI_DEPLOYMENT.md
Normal file
234
docs/MAC_MINI_DEPLOYMENT.md
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
# Mac Mini Deployment Guide
|
||||||
|
|
||||||
|
Production deployment auf Mac Mini M2 via Cloudflare Tunnel.
|
||||||
|
|
||||||
|
**Domain:** mana.how
|
||||||
|
**Tunnel ID:** bb0ea86d-8253-4a54-838b-107bb7945be9
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architektur
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet → Cloudflare Tunnel → Mac Mini (Docker) → Apps
|
||||||
|
↓
|
||||||
|
mana.how → localhost:5173 (Dashboard)
|
||||||
|
auth.mana.how → localhost:3001 (Auth API)
|
||||||
|
chat.mana.how → localhost:3000 (Chat Web)
|
||||||
|
chat-api.mana.how → localhost:3002 (Chat API)
|
||||||
|
todo.mana.how → localhost:5188 (Todo Web)
|
||||||
|
todo-api.mana.how → localhost:3018 (Todo API)
|
||||||
|
calendar.mana.how → localhost:5186 (Calendar Web)
|
||||||
|
calendar-api.mana.how → localhost:3016 (Calendar API)
|
||||||
|
clock.mana.how → localhost:5187 (Clock Web)
|
||||||
|
clock-api.mana.how → localhost:3017 (Clock API)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
- Mac Mini mit Apple Silicon (ARM64)
|
||||||
|
- Docker Desktop for Mac
|
||||||
|
- Homebrew
|
||||||
|
- Cloudflared
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Erstmaliges Setup
|
||||||
|
|
||||||
|
### 1. Repository klonen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/projects
|
||||||
|
cd ~/projects
|
||||||
|
git clone https://github.com/Memo-2023/manacore-monorepo.git
|
||||||
|
cd manacore-monorepo
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Cloudflared installieren & konfigurieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install cloudflared
|
||||||
|
|
||||||
|
# Bereits erledigt: Tunnel ist erstellt und konfiguriert
|
||||||
|
# Die Config liegt in: cloudflared-config.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Cloudflared als Service einrichten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x scripts/mac-mini/setup-cloudflared-service.sh
|
||||||
|
./scripts/mac-mini/setup-cloudflared-service.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Script erstellt einen launchd-Service, der:
|
||||||
|
- Automatisch beim Login startet
|
||||||
|
- Bei Abstürzen neu startet
|
||||||
|
- Logs nach `/tmp/cloudflared.log` schreibt
|
||||||
|
|
||||||
|
### 4. Environment konfigurieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Template kopieren
|
||||||
|
cp .env.macmini.example .env.macmini
|
||||||
|
|
||||||
|
# Werte eintragen
|
||||||
|
nano .env.macmini
|
||||||
|
```
|
||||||
|
|
||||||
|
**Wichtige Werte:**
|
||||||
|
- `POSTGRES_PASSWORD` - Sicheres Passwort für PostgreSQL
|
||||||
|
- `REDIS_PASSWORD` - Sicheres Passwort für Redis
|
||||||
|
- `JWT_SECRET` - Für JWT-Token Generierung
|
||||||
|
- `AZURE_OPENAI_*` - Für Chat AI Features (optional)
|
||||||
|
|
||||||
|
### 5. Container starten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x scripts/mac-mini/deploy.sh
|
||||||
|
./scripts/mac-mini/deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tägliche Operationen
|
||||||
|
|
||||||
|
### Container Status prüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.macmini.yml ps
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logs anschauen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Alle Services
|
||||||
|
docker compose -f docker-compose.macmini.yml logs -f
|
||||||
|
|
||||||
|
# Einzelner Service
|
||||||
|
docker compose -f docker-compose.macmini.yml logs -f mana-core-auth
|
||||||
|
```
|
||||||
|
|
||||||
|
### Neustart aller Services
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.macmini.yml restart
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update auf neue Images
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Neuste Images pullen
|
||||||
|
docker compose -f docker-compose.macmini.yml pull
|
||||||
|
|
||||||
|
# Container mit neuen Images starten
|
||||||
|
docker compose -f docker-compose.macmini.yml up -d
|
||||||
|
|
||||||
|
# Alte Images aufräumen
|
||||||
|
docker image prune -f
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cloudflared Service verwalten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Status prüfen
|
||||||
|
launchctl list | grep cloudflared
|
||||||
|
|
||||||
|
# Logs anschauen
|
||||||
|
tail -f /tmp/cloudflared.log
|
||||||
|
|
||||||
|
# Service stoppen
|
||||||
|
launchctl unload ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist
|
||||||
|
|
||||||
|
# Service starten
|
||||||
|
launchctl load ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Container startet nicht
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Logs des Services anschauen
|
||||||
|
docker compose -f docker-compose.macmini.yml logs <service-name>
|
||||||
|
|
||||||
|
# Beispiel
|
||||||
|
docker compose -f docker-compose.macmini.yml logs mana-core-auth
|
||||||
|
```
|
||||||
|
|
||||||
|
### Datenbank-Probleme
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In PostgreSQL einloggen
|
||||||
|
docker compose -f docker-compose.macmini.yml exec postgres psql -U postgres
|
||||||
|
|
||||||
|
# Datenbanken auflisten
|
||||||
|
\l
|
||||||
|
|
||||||
|
# Zu Datenbank wechseln
|
||||||
|
\c manacore_auth
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cloudflare Tunnel nicht erreichbar
|
||||||
|
|
||||||
|
1. Prüfen ob der Service läuft:
|
||||||
|
```bash
|
||||||
|
launchctl list | grep cloudflared
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Logs prüfen:
|
||||||
|
```bash
|
||||||
|
cat /tmp/cloudflared.error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Manuell testen:
|
||||||
|
```bash
|
||||||
|
cloudflared tunnel --config cloudflared-config.yml run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3001/api/v1/health # Auth
|
||||||
|
curl http://localhost:5173/health # Dashboard
|
||||||
|
curl http://localhost:3000/health # Chat Web
|
||||||
|
curl http://localhost:3002/api/v1/health # Chat API
|
||||||
|
curl http://localhost:5188/health # Todo Web
|
||||||
|
curl http://localhost:3018/api/health # Todo API
|
||||||
|
curl http://localhost:5186/health # Calendar Web
|
||||||
|
curl http://localhost:3016/api/v1/health # Calendar API
|
||||||
|
curl http://localhost:5187/health # Clock Web
|
||||||
|
curl http://localhost:3017/api/v1/health # Clock API
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CI/CD
|
||||||
|
|
||||||
|
Docker Images werden automatisch bei Push zu `main` gebaut:
|
||||||
|
- Multi-Arch: `linux/amd64` (Hetzner) + `linux/arm64` (Mac Mini)
|
||||||
|
- Registry: `ghcr.io/memo-2023/<service>:latest`
|
||||||
|
|
||||||
|
Nach einem neuen Build:
|
||||||
|
```bash
|
||||||
|
cd ~/projects/manacore-monorepo
|
||||||
|
git pull
|
||||||
|
./scripts/mac-mini/deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wichtige Dateien
|
||||||
|
|
||||||
|
| Datei | Beschreibung |
|
||||||
|
|-------|--------------|
|
||||||
|
| `docker-compose.macmini.yml` | Docker Compose für Mac Mini |
|
||||||
|
| `cloudflared-config.yml` | Cloudflare Tunnel Routing |
|
||||||
|
| `.env.macmini` | Environment Variables |
|
||||||
|
| `scripts/mac-mini/deploy.sh` | Deployment Script |
|
||||||
|
| `scripts/mac-mini/setup-cloudflared-service.sh` | Cloudflared Service Setup |
|
||||||
113
scripts/mac-mini/deploy.sh
Executable file
113
scripts/mac-mini/deploy.sh
Executable file
|
|
@ -0,0 +1,113 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Mac Mini Deployment Script
|
||||||
|
# Pulls latest images and starts all containers
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
COMPOSE_FILE="$PROJECT_ROOT/docker-compose.macmini.yml"
|
||||||
|
ENV_FILE="$PROJECT_ROOT/.env.macmini"
|
||||||
|
|
||||||
|
echo "=== ManaCore Mac Mini Deployment ==="
|
||||||
|
echo ""
|
||||||
|
echo "Project root: $PROJECT_ROOT"
|
||||||
|
echo "Compose file: $COMPOSE_FILE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if env file exists
|
||||||
|
if [ ! -f "$ENV_FILE" ]; then
|
||||||
|
echo "Warning: $ENV_FILE not found"
|
||||||
|
echo "Creating from template..."
|
||||||
|
cat > "$ENV_FILE" << 'EOF'
|
||||||
|
# Mac Mini Production Environment
|
||||||
|
# Copy this to .env.macmini and fill in the values
|
||||||
|
|
||||||
|
# Database
|
||||||
|
POSTGRES_PASSWORD=your-secure-password
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
REDIS_PASSWORD=your-redis-password
|
||||||
|
|
||||||
|
# JWT Keys (from mana-core-auth)
|
||||||
|
JWT_SECRET=your-jwt-secret
|
||||||
|
JWT_PUBLIC_KEY=
|
||||||
|
JWT_PRIVATE_KEY=
|
||||||
|
|
||||||
|
# Supabase (if needed)
|
||||||
|
SUPABASE_URL=
|
||||||
|
SUPABASE_SERVICE_ROLE_KEY=
|
||||||
|
|
||||||
|
# Azure OpenAI (for chat)
|
||||||
|
AZURE_OPENAI_ENDPOINT=
|
||||||
|
AZURE_OPENAI_API_KEY=
|
||||||
|
EOF
|
||||||
|
echo ""
|
||||||
|
echo "Please edit $ENV_FILE with your values and run this script again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Login to GitHub Container Registry
|
||||||
|
echo "=== Logging into GitHub Container Registry ==="
|
||||||
|
echo "Please enter your GitHub Personal Access Token (with read:packages scope):"
|
||||||
|
read -s GITHUB_TOKEN
|
||||||
|
echo "$GITHUB_TOKEN" | docker login ghcr.io -u memo-2023 --password-stdin
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Pulling latest images ==="
|
||||||
|
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" pull
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Starting containers ==="
|
||||||
|
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Waiting for services to start (30s) ==="
|
||||||
|
sleep 30
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Container Status ==="
|
||||||
|
docker compose -f "$COMPOSE_FILE" ps
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Creating databases ==="
|
||||||
|
docker compose -f "$COMPOSE_FILE" exec -T postgres psql -U postgres -c "CREATE DATABASE manacore_auth;" 2>/dev/null || echo "manacore_auth exists"
|
||||||
|
docker compose -f "$COMPOSE_FILE" exec -T postgres psql -U postgres -c "CREATE DATABASE chat;" 2>/dev/null || echo "chat exists"
|
||||||
|
docker compose -f "$COMPOSE_FILE" exec -T postgres psql -U postgres -c "CREATE DATABASE todo;" 2>/dev/null || echo "todo exists"
|
||||||
|
docker compose -f "$COMPOSE_FILE" exec -T postgres psql -U postgres -c "CREATE DATABASE calendar;" 2>/dev/null || echo "calendar exists"
|
||||||
|
docker compose -f "$COMPOSE_FILE" exec -T postgres psql -U postgres -c "CREATE DATABASE clock;" 2>/dev/null || echo "clock exists"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Health Checks ==="
|
||||||
|
check_health() {
|
||||||
|
local name=$1
|
||||||
|
local url=$2
|
||||||
|
if curl -s -o /dev/null -w "%{http_code}" "$url" | grep -q "200"; then
|
||||||
|
echo " $name: OK"
|
||||||
|
else
|
||||||
|
echo " $name: FAILED"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_health "Auth API" "http://localhost:3001/api/v1/health"
|
||||||
|
check_health "ManaCore Web" "http://localhost:5173/health"
|
||||||
|
check_health "Chat Backend" "http://localhost:3002/api/v1/health"
|
||||||
|
check_health "Chat Web" "http://localhost:3000/health"
|
||||||
|
check_health "Todo Backend" "http://localhost:3018/api/health"
|
||||||
|
check_health "Todo Web" "http://localhost:5188/health"
|
||||||
|
check_health "Calendar Backend" "http://localhost:3016/api/v1/health"
|
||||||
|
check_health "Calendar Web" "http://localhost:5186/health"
|
||||||
|
check_health "Clock Backend" "http://localhost:3017/api/v1/health"
|
||||||
|
check_health "Clock Web" "http://localhost:5187/health"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Deployment Complete ==="
|
||||||
|
echo ""
|
||||||
|
echo "URLs via Cloudflare Tunnel:"
|
||||||
|
echo " https://mana.how - Dashboard"
|
||||||
|
echo " https://auth.mana.how - Auth API"
|
||||||
|
echo " https://chat.mana.how - Chat"
|
||||||
|
echo " https://todo.mana.how - Todo"
|
||||||
|
echo " https://calendar.mana.how - Calendar"
|
||||||
|
echo " https://clock.mana.how - Clock"
|
||||||
|
echo ""
|
||||||
79
scripts/mac-mini/setup-cloudflared-service.sh
Executable file
79
scripts/mac-mini/setup-cloudflared-service.sh
Executable file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Setup Cloudflared as a launchd service on macOS
|
||||||
|
# Run this script once on the Mac Mini to enable auto-start
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TUNNEL_ID="bb0ea86d-8253-4a54-838b-107bb7945be9"
|
||||||
|
CONFIG_FILE="$HOME/projects/manacore-monorepo/cloudflared-config.yml"
|
||||||
|
CREDENTIALS_FILE="$HOME/.cloudflared/${TUNNEL_ID}.json"
|
||||||
|
PLIST_FILE="$HOME/Library/LaunchAgents/com.cloudflare.cloudflared.plist"
|
||||||
|
|
||||||
|
echo "=== Cloudflared Service Setup ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if credentials exist
|
||||||
|
if [ ! -f "$CREDENTIALS_FILE" ]; then
|
||||||
|
echo "Error: Credentials file not found: $CREDENTIALS_FILE"
|
||||||
|
echo "Run 'cloudflared tunnel login' first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if config exists
|
||||||
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
|
echo "Error: Config file not found: $CONFIG_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create LaunchAgents directory if needed
|
||||||
|
mkdir -p ~/Library/LaunchAgents
|
||||||
|
|
||||||
|
# Create the plist file
|
||||||
|
cat > "$PLIST_FILE" << EOF
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>com.cloudflare.cloudflared</string>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>/opt/homebrew/bin/cloudflared</string>
|
||||||
|
<string>tunnel</string>
|
||||||
|
<string>--config</string>
|
||||||
|
<string>${CONFIG_FILE}</string>
|
||||||
|
<string>run</string>
|
||||||
|
</array>
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
<key>KeepAlive</key>
|
||||||
|
<true/>
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string>/tmp/cloudflared.log</string>
|
||||||
|
<key>StandardErrorPath</key>
|
||||||
|
<string>/tmp/cloudflared.error.log</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Created plist: $PLIST_FILE"
|
||||||
|
|
||||||
|
# Unload if already loaded
|
||||||
|
launchctl unload "$PLIST_FILE" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Load the service
|
||||||
|
launchctl load "$PLIST_FILE"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Service Status ==="
|
||||||
|
launchctl list | grep cloudflared || echo "Service loaded"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Cloudflared is now running as a service."
|
||||||
|
echo ""
|
||||||
|
echo "Useful commands:"
|
||||||
|
echo " Check status: launchctl list | grep cloudflared"
|
||||||
|
echo " View logs: tail -f /tmp/cloudflared.log"
|
||||||
|
echo " Stop service: launchctl unload $PLIST_FILE"
|
||||||
|
echo " Start service: launchctl load $PLIST_FILE"
|
||||||
|
echo ""
|
||||||
Loading…
Add table
Add a link
Reference in a new issue