diff --git a/.gitea/workflows/ci-cd-old.yml b/.gitea/workflows/ci-cd-old.yml deleted file mode 100644 index ed99bd3..0000000 --- a/.gitea/workflows/ci-cd-old.yml +++ /dev/null @@ -1,169 +0,0 @@ -name: CI/CD Pipeline - -on: - push: - branches: [ main, production ] - pull_request: - branches: [ main, production ] - -env: - NODE_VERSION: '20' - DOCKER_IMAGE: portfolio-app - CONTAINER_NAME: portfolio-app - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Run linting - run: npm run lint - - - name: Run tests - run: npm run test - - - name: Build application - run: npm run build - - security: - runs-on: ubuntu-latest - needs: test - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@0.30.0 - with: - scan-type: 'fs' - scan-ref: '.' - format: 'table' - output: 'trivy-results.txt' - timeout: '10m' - ignore-unfixed: true - severity: 'CRITICAL,HIGH' - continue-on-error: true - - - name: Run npm audit as fallback - if: failure() - run: | - echo "Trivy failed, running npm audit as fallback..." - npm audit --audit-level=high || true - echo "Security scan completed with fallback method" - - - name: Upload Trivy scan results - uses: actions/upload-artifact@v3 - if: always() - with: - name: trivy-results - path: trivy-results.txt - retention-days: 7 - - build: - runs-on: ubuntu-latest - needs: test - if: github.ref == 'refs/heads/production' - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Build Docker image - run: | - docker build -t ${{ env.DOCKER_IMAGE }}:latest . - docker tag ${{ env.DOCKER_IMAGE }}:latest ${{ env.DOCKER_IMAGE }}:$(date +%Y%m%d-%H%M%S) - - - name: Save Docker image - run: | - docker save ${{ env.DOCKER_IMAGE }}:latest | gzip > ${{ env.DOCKER_IMAGE }}.tar.gz - - - name: Upload Docker image artifact - uses: actions/upload-artifact@v3 - with: - name: docker-image - path: ${{ env.DOCKER_IMAGE }}.tar.gz - retention-days: 7 - - deploy: - runs-on: ubuntu-latest - needs: build - if: github.ref == 'refs/heads/production' - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Download Docker image artifact - uses: actions/download-artifact@v3 - with: - name: docker-image - path: ./ - - - name: Load Docker image - run: | - gunzip -c ${{ env.DOCKER_IMAGE }}.tar.gz | docker load - - - name: Stop existing services - run: | - docker-compose -f docker-compose.workflow.yml down || true - - - name: Verify secrets before deployment - run: | - echo "🔍 Verifying secrets..." - if [ -z "${{ secrets.NEXT_PUBLIC_BASE_URL }}" ]; then - echo "❌ NEXT_PUBLIC_BASE_URL secret is missing!" - exit 1 - fi - if [ -z "${{ secrets.MY_EMAIL }}" ]; then - echo "❌ MY_EMAIL secret is missing!" - exit 1 - fi - if [ -z "${{ secrets.ADMIN_BASIC_AUTH }}" ]; then - echo "❌ ADMIN_BASIC_AUTH secret is missing!" - exit 1 - fi - echo "✅ All required secrets are present" - - - name: Start services with Docker Compose - run: | - docker-compose -f docker-compose.workflow.yml up -d - env: - NEXT_PUBLIC_BASE_URL: ${{ secrets.NEXT_PUBLIC_BASE_URL }} - MY_EMAIL: ${{ secrets.MY_EMAIL }} - MY_INFO_EMAIL: ${{ secrets.MY_INFO_EMAIL }} - MY_PASSWORD: ${{ secrets.MY_PASSWORD }} - MY_INFO_PASSWORD: ${{ secrets.MY_INFO_PASSWORD }} - ADMIN_BASIC_AUTH: ${{ secrets.ADMIN_BASIC_AUTH }} - - - name: Verify container environment - run: | - echo "🔍 Checking container environment variables..." - sleep 10 - docker exec portfolio-app sh -c 'echo "NODE_ENV: $NODE_ENV" && echo "DATABASE_URL: $DATABASE_URL" && echo "REDIS_URL: $REDIS_URL" && echo "NEXT_PUBLIC_BASE_URL: $NEXT_PUBLIC_BASE_URL" && echo "MY_EMAIL: $MY_EMAIL" && echo "ADMIN_BASIC_AUTH: [HIDDEN]"' - - - name: Wait for container to be ready - run: | - sleep 10 - timeout 60 bash -c 'until curl -f http://localhost:3000/api/health; do sleep 2; done' - - - name: Health check - run: | - curl -f http://localhost:3000/api/health - echo "✅ Deployment successful!" - - - name: Cleanup old images - run: | - docker image prune -f - docker system prune -f diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 6a48a9f..12a29e6 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -81,7 +81,7 @@ jobs: - name: Stop existing services run: | - docker-compose -f docker-compose.workflow.yml down || true + docker-compose down || true - name: Verify secrets before deployment run: | @@ -102,7 +102,7 @@ jobs: - name: Start services with Docker Compose run: | - docker-compose -f docker-compose.workflow.yml up -d + docker-compose up -d env: NEXT_PUBLIC_BASE_URL: ${{ secrets.NEXT_PUBLIC_BASE_URL }} MY_EMAIL: ${{ secrets.MY_EMAIL }} diff --git a/.gitea/workflows/quick-deploy.yml b/.gitea/workflows/quick-deploy.yml deleted file mode 100644 index bfba90f..0000000 --- a/.gitea/workflows/quick-deploy.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Quick Deploy - -on: - push: - branches: [ main ] - workflow_dispatch: - -env: - NODE_VERSION: '20' - DOCKER_IMAGE: portfolio-app - CONTAINER_NAME: portfolio-app - -jobs: - quick-deploy: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Build application - run: npm run build - - - name: Build Docker image - run: | - docker build -t ${{ env.DOCKER_IMAGE }}:latest . - - - name: Stop existing services - run: | - docker-compose -f docker-compose.workflow.yml down || true - - - name: Verify secrets before deployment - run: | - echo "🔍 Verifying secrets..." - if [ -z "${{ secrets.NEXT_PUBLIC_BASE_URL }}" ]; then - echo "❌ NEXT_PUBLIC_BASE_URL secret is missing!" - exit 1 - fi - if [ -z "${{ secrets.MY_EMAIL }}" ]; then - echo "❌ MY_EMAIL secret is missing!" - exit 1 - fi - if [ -z "${{ secrets.ADMIN_BASIC_AUTH }}" ]; then - echo "❌ ADMIN_BASIC_AUTH secret is missing!" - exit 1 - fi - echo "✅ All required secrets are present" - - - name: Start services with Docker Compose - run: | - docker-compose -f docker-compose.workflow.yml up -d - env: - NEXT_PUBLIC_BASE_URL: ${{ secrets.NEXT_PUBLIC_BASE_URL }} - MY_EMAIL: ${{ secrets.MY_EMAIL }} - MY_INFO_EMAIL: ${{ secrets.MY_INFO_EMAIL }} - MY_PASSWORD: ${{ secrets.MY_PASSWORD }} - MY_INFO_PASSWORD: ${{ secrets.MY_INFO_PASSWORD }} - ADMIN_BASIC_AUTH: ${{ secrets.ADMIN_BASIC_AUTH }} - - - name: Verify container environment - run: | - echo "🔍 Checking container environment variables..." - sleep 10 - docker exec portfolio-app sh -c 'echo "NODE_ENV: $NODE_ENV" && echo "DATABASE_URL: $DATABASE_URL" && echo "REDIS_URL: $REDIS_URL" && echo "NEXT_PUBLIC_BASE_URL: $NEXT_PUBLIC_BASE_URL" && echo "MY_EMAIL: $MY_EMAIL" && echo "ADMIN_BASIC_AUTH: [HIDDEN]"' - - - name: Health check - run: | - sleep 10 - curl -f http://localhost:3000/api/health - echo "✅ Quick deployment successful!" diff --git a/.gitea/workflows/security-scan.yml b/.gitea/workflows/security-scan.yml deleted file mode 100644 index a96a525..0000000 --- a/.gitea/workflows/security-scan.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Security Scan - -on: - push: - branches: [ main, production ] - pull_request: - branches: [ main, production ] - schedule: - - cron: '0 2 * * 1' # Weekly on Monday at 2 AM - -jobs: - security: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '20' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Run npm audit - run: | - echo "🔍 Running npm audit for dependency vulnerabilities..." - npm audit --audit-level=high --json > npm-audit-results.json || true - npm audit --audit-level=high || echo "⚠️ Some vulnerabilities found, but continuing..." - - - name: Run Trivy (with fallback) - run: | - echo "🔍 Attempting Trivy scan..." - # Try to install and run Trivy directly - wget -qO- https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin - trivy fs --scanners vuln,secret --format table . > trivy-results.txt 2>&1 || { - echo "⚠️ Trivy scan failed, but continuing with other checks..." - echo "Trivy scan failed due to network issues" > trivy-results.txt - } - - - name: Check for secrets - run: | - echo "🔍 Checking for potential secrets..." - chmod +x scripts/check-secrets.sh - if ./scripts/check-secrets.sh; then - echo "✅ No secrets found in code" - else - echo "❌ Secrets detected - please review" - exit 1 - fi - - - name: Upload security scan results - uses: actions/upload-artifact@v3 - if: always() - with: - name: security-scan-results - path: | - npm-audit-results.json - trivy-results.txt - retention-days: 30 - - - name: Security scan summary - run: | - echo "## Security Scan Summary" - echo "### NPM Audit Results" - if [ -f npm-audit-results.json ]; then - echo "✅ NPM audit completed" - else - echo "❌ NPM audit failed" - fi - echo "### Trivy Results" - if [ -f trivy-results.txt ]; then - echo "✅ Trivy scan completed" - else - echo "❌ Trivy scan failed" - fi diff --git a/.githooks/README.md b/.githooks/README.md new file mode 100644 index 0000000..646e875 --- /dev/null +++ b/.githooks/README.md @@ -0,0 +1,78 @@ +# Git Hooks + +This directory contains Git hooks for the Portfolio project. + +## Pre-Push Hook + +The pre-push hook runs automatically before every `git push` and performs the following checks: + +### Checks Performed: +1. **Node.js Version Check** - Ensures Node.js 20+ is installed +2. **Dependency Installation** - Installs npm dependencies if needed +3. **Linting** - Runs ESLint to check code quality +4. **Tests** - Runs Jest test suite +5. **Build** - Builds the Next.js application +6. **Security Audit** - Runs npm audit for vulnerabilities +7. **Secret Detection** - Checks for accidentally committed secrets +8. **Docker Configuration** - Validates Dockerfile and docker-compose.yml +9. **Production Checks** - Additional checks when pushing to production branch + +### Production Branch Special Checks: +- Environment file validation +- Docker build test +- Deployment readiness check + +### Usage: + +The hook runs automatically on every push. To manually test it: + +```bash +# Test the hook manually +.githooks/pre-push + +# Or push to trigger it +git push origin main +``` + +### Bypassing the Hook: + +If you need to bypass the hook in an emergency: + +```bash +git push --no-verify origin main +``` + +**Note**: Only bypass in emergencies. The hook prevents broken code from being pushed. + +### Troubleshooting: + +If the hook fails: + +1. **Fix the reported issues** (linting errors, test failures, etc.) +2. **Run the checks manually** to debug: + ```bash + npm run lint + npm run test + npm run build + npm audit + ``` +3. **Check Node.js version**: `node --version` (should be 20+) +4. **Reinstall dependencies**: `rm -rf node_modules && npm ci` + +### Configuration: + +The hook is configured in `.git/config`: +``` +[core] + hooksPath = .githooks +``` + +To disable hooks temporarily: +```bash +git config core.hooksPath "" +``` + +To re-enable: +```bash +git config core.hooksPath .githooks +``` \ No newline at end of file diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 0000000..f7f9333 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,163 @@ +#!/bin/bash + +# Pre-push hook for Portfolio +# Runs CI/CD checks before allowing push + +set -e + +echo "🚀 Running pre-push checks..." + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if we're in the right directory +if [ ! -f "package.json" ]; then + print_error "Not in project root directory!" + exit 1 +fi + +# Check if Node.js is available +if ! command -v node &> /dev/null; then + print_error "Node.js is not installed!" + exit 1 +fi + +# Check Node.js version +NODE_VERSION=$(node --version | cut -d'v' -f2 | cut -d'.' -f1) +if [ "$NODE_VERSION" -lt 20 ]; then + print_error "Node.js version 20+ required, found: $(node --version)" + exit 1 +fi + +print_success "Node.js version: $(node --version)" + +# Install dependencies if node_modules doesn't exist +if [ ! -d "node_modules" ]; then + print_status "Installing dependencies..." + npm ci +else + print_status "Dependencies already installed" +fi + +# Run linting +print_status "Running ESLint..." +if npm run lint; then + print_success "Linting passed" +else + print_error "Linting failed! Please fix the issues before pushing." + exit 1 +fi + +# Run tests +print_status "Running tests..." +if npm run test; then + print_success "Tests passed" +else + print_error "Tests failed! Please fix the issues before pushing." + exit 1 +fi + +# Build application +print_status "Building application..." +if npm run build; then + print_success "Build successful" +else + print_error "Build failed! Please fix the issues before pushing." + exit 1 +fi + +# Security audit +print_status "Running security audit..." +if npm audit --audit-level=high; then + print_success "Security audit passed" +else + print_warning "Security audit found issues. Consider running 'npm audit fix'" + # Don't fail the push for security warnings, just warn +fi + +# Check for secrets in code +print_status "Checking for secrets in code..." +if [ -f "scripts/check-secrets.sh" ]; then + if ./scripts/check-secrets.sh; then + print_success "No secrets found in code" + else + print_error "Secrets detected in code! Please remove them before pushing." + exit 1 + fi +else + print_warning "Secret check script not found, skipping..." +fi + +# Check Docker configuration +print_status "Checking Docker configuration..." +if [ -f "Dockerfile" ]; then + print_success "Dockerfile found" +else + print_error "Dockerfile not found!" + exit 1 +fi + +if [ -f "docker-compose.yml" ]; then + print_success "Docker Compose configuration found" +else + print_error "Docker Compose configuration not found!" + exit 1 +fi + +# Check if we're pushing to production branch +CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) +if [ "$CURRENT_BRANCH" = "production" ]; then + print_warning "Pushing to production branch - this will trigger deployment!" + + # Additional production checks + print_status "Running production-specific checks..." + + # Check if environment file exists + if [ ! -f ".env" ]; then + print_warning "No .env file found. Make sure secrets are configured in Gitea." + fi + + # Check Docker image can be built + print_status "Testing Docker build..." + if docker build -t portfolio-app:test . > /dev/null 2>&1; then + print_success "Docker build test passed" + docker rmi portfolio-app:test > /dev/null 2>&1 + else + print_error "Docker build test failed!" + exit 1 + fi +fi + +# Final success message +echo "" +print_success "All pre-push checks passed! ✅" +print_status "Ready to push to: $CURRENT_BRANCH" + +# Show what will be pushed +echo "" +print_status "Files to be pushed:" +git diff --name-only HEAD~1 2>/dev/null || git diff --cached --name-only + +echo "" +print_success "🚀 Push will proceed..." \ No newline at end of file diff --git a/AUTO-DEPLOYMENT.md b/AUTO-DEPLOYMENT.md deleted file mode 100644 index af592eb..0000000 --- a/AUTO-DEPLOYMENT.md +++ /dev/null @@ -1,226 +0,0 @@ -# Automatisches Deployment System - -## Übersicht - -Dieses Portfolio verwendet ein **automatisches Deployment-System**, das bei jedem Git Push die Codebase prüft, den Container erstellt und startet. - -## 🚀 Deployment-Skripte - -### **1. Auto-Deploy (Vollständig)** -```bash -# Vollständiges automatisches Deployment -./scripts/auto-deploy.sh - -# Oder mit npm -npm run auto-deploy -``` - -**Was passiert:** -- ✅ Git Status prüfen und uncommitted Changes committen -- ✅ Latest Changes pullen -- ✅ ESLint Linting -- ✅ Tests ausführen -- ✅ Next.js Build -- ✅ Docker Image erstellen -- ✅ Container stoppen/starten -- ✅ Health Check -- ✅ Cleanup alter Images - -### **2. Quick-Deploy (Schnell)** -```bash -# Schnelles Deployment ohne Tests -./scripts/quick-deploy.sh - -# Oder mit npm -npm run quick-deploy -``` - -**Was passiert:** -- ✅ Docker Image erstellen -- ✅ Container stoppen/starten -- ✅ Health Check - -### **3. Manuelles Deployment** -```bash -# Manuelles Deployment mit Docker Compose -./scripts/deploy.sh - -# Oder mit npm -npm run deploy -``` - -## 🔄 Automatisches Deployment - -### **Git Hook Setup** -Das System verwendet einen Git Post-Receive Hook, der automatisch bei jedem Push ausgeführt wird: - -```bash -# Hook ist bereits konfiguriert in: -.git/hooks/post-receive -``` - -### **Wie es funktioniert:** -1. **Git Push** → Hook wird ausgelöst -2. **Auto-Deploy Script** wird ausgeführt -3. **Vollständige Pipeline** läuft automatisch -4. **Deployment** wird durchgeführt -5. **Health Check** bestätigt Erfolg - -## 📋 Deployment-Schritte - -### **Automatisches Deployment:** -```bash -# 1. Code Quality Checks -git status --porcelain -git pull origin main -npm run lint -npm run test - -# 2. Build Application -npm run build - -# 3. Docker Operations -docker build -t portfolio-app:latest . -docker tag portfolio-app:latest portfolio-app:$(date +%Y%m%d-%H%M%S) - -# 4. Deployment -docker stop portfolio-app || true -docker rm portfolio-app || true -docker run -d --name portfolio-app -p 3000:3000 portfolio-app:latest - -# 5. Health Check -curl -f http://localhost:3000/api/health - -# 6. Cleanup -docker system prune -f -``` - -## 🎯 Verwendung - -### **Für Entwicklung:** -```bash -# Schnelles Deployment während der Entwicklung -npm run quick-deploy -``` - -### **Für Production:** -```bash -# Vollständiges Deployment mit Tests -npm run auto-deploy -``` - -### **Automatisch bei Push:** -```bash -# Einfach committen und pushen -git add . -git commit -m "Update feature" -git push origin main -# → Automatisches Deployment läuft -``` - -## 📊 Monitoring - -### **Container Status:** -```bash -# Status prüfen -npm run monitor status - -# Health Check -npm run monitor health - -# Logs anzeigen -npm run monitor logs -``` - -### **Deployment Logs:** -```bash -# Deployment-Logs anzeigen -tail -f /var/log/portfolio-deploy.log - -# Git-Deployment-Logs -tail -f /var/log/git-deploy.log -``` - -## 🔧 Konfiguration - -### **Ports:** -- **Standard Port:** 3000 -- **Backup Port:** 3001 (falls 3000 belegt) - -### **Container:** -- **Name:** portfolio-app -- **Image:** portfolio-app:latest -- **Restart Policy:** unless-stopped - -### **Logs:** -- **Deployment Logs:** `/var/log/portfolio-deploy.log` -- **Git Logs:** `/var/log/git-deploy.log` - -## 🚨 Troubleshooting - -### **Deployment schlägt fehl:** -```bash -# Logs prüfen -docker logs portfolio-app - -# Container-Status prüfen -docker ps -a - -# Manuell neu starten -npm run quick-deploy -``` - -### **Port bereits belegt:** -```bash -# Ports prüfen -lsof -i :3000 - -# Anderen Port verwenden -docker run -d --name portfolio-app -p 3001:3000 portfolio-app:latest -``` - -### **Tests schlagen fehl:** -```bash -# Tests lokal ausführen -npm run test - -# Linting prüfen -npm run lint - -# Build testen -npm run build -``` - -## 📈 Features - -### **Automatische Features:** -- ✅ **Git Integration** - Automatisch bei Push -- ✅ **Code Quality** - Linting und Tests -- ✅ **Health Checks** - Automatische Verifikation -- ✅ **Rollback** - Alte Container werden gestoppt -- ✅ **Cleanup** - Alte Images werden entfernt -- ✅ **Logging** - Vollständige Deployment-Logs - -### **Sicherheits-Features:** -- ✅ **Non-root Container** -- ✅ **Resource Limits** -- ✅ **Health Monitoring** -- ✅ **Error Handling** -- ✅ **Rollback bei Fehlern** - -## 🎉 Vorteile - -1. **Automatisierung** - Keine manuellen Schritte nötig -2. **Konsistenz** - Immer gleiche Deployment-Prozesse -3. **Sicherheit** - Tests vor jedem Deployment -4. **Monitoring** - Vollständige Logs und Health Checks -5. **Schnell** - Quick-Deploy für Entwicklung -6. **Zuverlässig** - Automatische Rollbacks bei Fehlern - -## 📞 Support - -Bei Problemen: -1. **Logs prüfen:** `tail -f /var/log/portfolio-deploy.log` -2. **Container-Status:** `npm run monitor status` -3. **Health Check:** `npm run monitor health` -4. **Manueller Neustart:** `npm run quick-deploy` diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 92ec034..aec7786 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -1,272 +1,229 @@ # Portfolio Deployment Guide -## Übersicht +## Overview -Dieses Portfolio verwendet ein **optimiertes CI/CD-System** mit Docker für Production-Deployment. Das System ist darauf ausgelegt, hohen Traffic zu bewältigen und automatische Tests vor dem Deployment durchzuführen. +This document covers all aspects of deploying the Portfolio application, including local development, CI/CD, and production deployment. -## 🚀 Features +## Prerequisites -### ✅ **CI/CD Pipeline** -- **Automatische Tests** vor jedem Deployment -- **Security Scanning** mit Trivy -- **Multi-Architecture Docker Builds** (AMD64 + ARM64) -- **Health Checks** und Deployment-Verifikation -- **Automatische Cleanup** alter Images +- Docker and Docker Compose installed +- Node.js 20+ for local development +- Access to Gitea repository with Actions enabled -### ⚡ **Performance-Optimierungen** -- **Multi-Stage Docker Build** für kleinere Images -- **Nginx Load Balancer** mit Caching -- **Gzip Compression** und optimierte Headers -- **Rate Limiting** für API-Endpoints -- **Resource Limits** für Container +## Environment Setup -### 🔒 **Sicherheit** -- **Non-root User** im Container -- **Security Headers** (HSTS, CSP, etc.) -- **SSL/TLS Termination** mit Nginx -- **Vulnerability Scanning** in CI/CD +### Required Secrets in Gitea -## 📁 Dateistruktur +Configure these secrets in your Gitea repository (Settings → Secrets): -``` -├── .github/workflows/ -│ └── ci-cd.yml # CI/CD Pipeline -├── scripts/ -│ ├── deploy.sh # Deployment-Skript -│ └── monitor.sh # Monitoring-Skript -├── docker-compose.prod.yml # Production Docker Compose -├── nginx.conf # Nginx Konfiguration -├── Dockerfile # Optimiertes Dockerfile -└── env.example # Environment Template -``` +| Secret Name | Description | Example | +|-------------|-------------|---------| +| `NEXT_PUBLIC_BASE_URL` | Public URL of your website | `https://dk0.dev` | +| `MY_EMAIL` | Main email for contact form | `contact@dk0.dev` | +| `MY_INFO_EMAIL` | Info email address | `info@dk0.dev` | +| `MY_PASSWORD` | Password for main email | `your_email_password` | +| `MY_INFO_PASSWORD` | Password for info email | `your_info_email_password` | +| `ADMIN_BASIC_AUTH` | Admin basic auth for protected areas | `admin:your_secure_password` | -## 🛠️ Setup +### Local Environment -### 1. **Environment Variables** -```bash -# Kopiere die Beispiel-Datei -cp env.example .env +1. Copy environment template: + ```bash + cp env.example .env + ``` -# Bearbeite die .env Datei mit deinen Werten -nano .env -``` +2. Update `.env` with your values: + ```bash + NEXT_PUBLIC_BASE_URL=https://dk0.dev + MY_EMAIL=contact@dk0.dev + MY_INFO_EMAIL=info@dk0.dev + MY_PASSWORD=your_email_password + MY_INFO_PASSWORD=your_info_email_password + ADMIN_BASIC_AUTH=admin:your_secure_password + ``` -### 2. **GitHub Secrets & Variables** -Konfiguriere in deinem GitHub Repository: +## Deployment Methods -**Secrets:** -- `GITHUB_TOKEN` (automatisch verfügbar) -- `GHOST_API_KEY` -- `MY_PASSWORD` -- `MY_INFO_PASSWORD` - -**Variables:** -- `NEXT_PUBLIC_BASE_URL` -- `GHOST_API_URL` -- `MY_EMAIL` -- `MY_INFO_EMAIL` - -### 3. **SSL-Zertifikate** -```bash -# Erstelle SSL-Verzeichnis -mkdir -p ssl - -# Kopiere deine SSL-Zertifikate -cp your-cert.pem ssl/cert.pem -cp your-key.pem ssl/key.pem -``` - -## 🚀 Deployment - -### **Automatisches Deployment** -Das System deployt automatisch bei Push auf den `production` Branch: +### 1. Local Development ```bash -# Code auf production Branch pushen -git push origin production +# Start all services +docker-compose up -d + +# View logs +docker-compose logs -f portfolio + +# Stop services +docker-compose down ``` -### **Manuelles Deployment** +### 2. CI/CD Pipeline (Automatic) + +The CI/CD pipeline runs automatically on: +- **Push to `main`**: Runs tests, linting, build, and security checks +- **Push to `production`**: Full deployment including Docker build and deployment + +#### Pipeline Steps: +1. **Install dependencies** (`npm ci`) +2. **Run linting** (`npm run lint`) +3. **Run tests** (`npm run test`) +4. **Build application** (`npm run build`) +5. **Security scan** (`npm audit`) +6. **Build Docker image** (production only) +7. **Deploy with Docker Compose** (production only) + +### 3. Manual Deployment + ```bash -# Lokales Deployment -./scripts/deploy.sh production +# Build and start services +docker-compose up -d --build -# Oder mit npm -npm run deploy +# Check service status +docker-compose ps + +# View logs +docker-compose logs -f ``` -### **Docker Commands** +## Service Configuration + +### Portfolio App +- **Port**: 3000 (configurable via `PORT` environment variable) +- **Health Check**: `http://localhost:3000/api/health` +- **Environment**: Production +- **Resources**: 512M memory limit, 0.5 CPU limit + +### PostgreSQL Database +- **Port**: 5432 (internal) +- **Database**: `portfolio_db` +- **User**: `portfolio_user` +- **Password**: `portfolio_pass` +- **Health Check**: `pg_isready` + +### Redis Cache +- **Port**: 6379 (internal) +- **Health Check**: `redis-cli ping` + +## Troubleshooting + +### Common Issues + +1. **Secrets not loading**: + - Run the debug workflow: Actions → Debug Secrets + - Verify all secrets are set in Gitea + - Check secret names match exactly + +2. **Container won't start**: + ```bash + # Check logs + docker-compose logs portfolio + + # Check service status + docker-compose ps + + # Restart services + docker-compose restart + ``` + +3. **Database connection issues**: + ```bash + # Check PostgreSQL status + docker-compose exec postgres pg_isready -U portfolio_user -d portfolio_db + + # Check database logs + docker-compose logs postgres + ``` + +4. **Redis connection issues**: + ```bash + # Test Redis connection + docker-compose exec redis redis-cli ping + + # Check Redis logs + docker-compose logs redis + ``` + +### Debug Commands + ```bash -# Container starten -npm run docker:compose +# Check environment variables in container +docker exec portfolio-app env | grep -E "(DATABASE_URL|REDIS_URL|NEXT_PUBLIC_BASE_URL)" -# Container stoppen -npm run docker:down +# Test health endpoints +curl -f http://localhost:3000/api/health -# Health Check -npm run health +# View all service logs +docker-compose logs --tail=50 + +# Check resource usage +docker stats ``` -## 📊 Monitoring +## Monitoring -### **Container Status** +### Health Checks +- **Portfolio App**: `http://localhost:3000/api/health` +- **PostgreSQL**: `pg_isready` command +- **Redis**: `redis-cli ping` command + +### Logs ```bash -# Status anzeigen -./scripts/monitor.sh status +# Follow all logs +docker-compose logs -f -# Oder mit npm -npm run monitor status +# Follow specific service logs +docker-compose logs -f portfolio +docker-compose logs -f postgres +docker-compose logs -f redis ``` -### **Health Check** +## Security + +### Security Scans +- **NPM Audit**: Runs automatically in CI/CD +- **Dependency Check**: Checks for known vulnerabilities +- **Secret Detection**: Prevents accidental secret commits + +### Best Practices +- Never commit secrets to repository +- Use environment variables for sensitive data +- Regularly update dependencies +- Monitor security advisories + +## Backup and Recovery + +### Database Backup ```bash -# Application Health -./scripts/monitor.sh health +# Create backup +docker-compose exec postgres pg_dump -U portfolio_user portfolio_db > backup.sql -# Oder direkt -curl http://localhost:3000/api/health +# Restore backup +docker-compose exec -T postgres psql -U portfolio_user portfolio_db < backup.sql ``` -### **Logs anzeigen** +### Volume Backup ```bash -# Letzte 50 Zeilen -./scripts/monitor.sh logs 50 - -# Live-Logs folgen -./scripts/monitor.sh logs 100 +# Backup volumes +docker run --rm -v portfolio_postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres_backup.tar.gz /data +docker run --rm -v portfolio_redis_data:/data -v $(pwd):/backup alpine tar czf /backup/redis_backup.tar.gz /data ``` -### **Metriken** -```bash -# Detaillierte Metriken -./scripts/monitor.sh metrics -``` +## Performance Optimization -## 🔧 Wartung +### Resource Limits +- **Portfolio App**: 512M memory, 0.5 CPU +- **PostgreSQL**: 256M memory, 0.25 CPU +- **Redis**: Default limits -### **Container neustarten** -```bash -./scripts/monitor.sh restart -``` +### Caching +- **Next.js**: Built-in caching +- **Redis**: Session and analytics caching +- **Static Assets**: Served from CDN -### **Cleanup** -```bash -# Docker-Ressourcen bereinigen -./scripts/monitor.sh cleanup -``` +## Support -### **Updates** -```bash -# Neues Image pullen und deployen -./scripts/deploy.sh production -``` - -## 📈 Performance-Tuning - -### **Nginx Optimierungen** -- **Gzip Compression** aktiviert -- **Static Asset Caching** (1 Jahr) -- **API Rate Limiting** (10 req/s) -- **Load Balancing** bereit für Skalierung - -### **Docker Optimierungen** -- **Multi-Stage Build** für kleinere Images -- **Non-root User** für Sicherheit -- **Health Checks** für automatische Recovery -- **Resource Limits** (512MB RAM, 0.5 CPU) - -### **Next.js Optimierungen** -- **Standalone Output** für Docker -- **Image Optimization** (WebP, AVIF) -- **CSS Optimization** aktiviert -- **Package Import Optimization** - -## 🚨 Troubleshooting - -### **Container startet nicht** -```bash -# Logs prüfen -./scripts/monitor.sh logs - -# Status prüfen -./scripts/monitor.sh status - -# Neustarten -./scripts/monitor.sh restart -``` - -### **Health Check schlägt fehl** -```bash -# Manueller Health Check -curl -v http://localhost:3000/api/health - -# Container-Logs prüfen -docker compose -f docker-compose.prod.yml logs portfolio -``` - -### **Performance-Probleme** -```bash -# Resource-Usage prüfen -./scripts/monitor.sh metrics - -# Nginx-Logs prüfen -docker compose -f docker-compose.prod.yml logs nginx -``` - -### **SSL-Probleme** -```bash -# SSL-Zertifikate prüfen -openssl x509 -in ssl/cert.pem -text -noout - -# Nginx-Konfiguration testen -docker compose -f docker-compose.prod.yml exec nginx nginx -t -``` - -## 📋 CI/CD Pipeline - -### **Workflow-Schritte** -1. **Test** - Linting, Tests, Build -2. **Security** - Trivy Vulnerability Scan -3. **Build** - Multi-Arch Docker Image -4. **Deploy** - Automatisches Deployment - -### **Trigger** -- **Push auf `main`** - Build nur -- **Push auf `production`** - Build + Deploy -- **Pull Request** - Test + Security - -### **Monitoring** -- **GitHub Actions** - Pipeline-Status -- **Container Health** - Automatische Checks -- **Resource Usage** - Monitoring-Skript - -## 🔄 Skalierung - -### **Horizontal Scaling** -```yaml -# In nginx.conf - weitere Backend-Server hinzufügen -upstream portfolio_backend { - least_conn; - server portfolio:3000 max_fails=3 fail_timeout=30s; - server portfolio-2:3000 max_fails=3 fail_timeout=30s; - server portfolio-3:3000 max_fails=3 fail_timeout=30s; -} -``` - -### **Vertical Scaling** -```yaml -# In docker-compose.prod.yml - Resource-Limits erhöhen -deploy: - resources: - limits: - memory: 1G - cpus: '1.0' -``` - -## 📞 Support - -Bei Problemen: -1. **Logs prüfen**: `./scripts/monitor.sh logs` -2. **Status prüfen**: `./scripts/monitor.sh status` -3. **Health Check**: `./scripts/monitor.sh health` -4. **Container neustarten**: `./scripts/monitor.sh restart` +For issues or questions: +1. Check the troubleshooting section above +2. Review CI/CD pipeline logs +3. Run the debug workflow +4. Check service health endpoints \ No newline at end of file diff --git a/GITEA-SECRETS-SETUP.md b/GITEA-SECRETS-SETUP.md deleted file mode 100644 index ee69dfb..0000000 --- a/GITEA-SECRETS-SETUP.md +++ /dev/null @@ -1,56 +0,0 @@ -# Gitea Secrets Setup - -Um die GitHub Actions Workflows korrekt zu verwenden, müssen die folgenden Secrets in deinem Gitea Repository konfiguriert werden: - -## Secrets konfigurieren - -1. Gehe zu deinem Repository in Gitea -2. Klicke auf **Settings** → **Secrets** -3. Füge die folgenden Secrets hinzu: - -### Erforderliche Secrets: - -| Secret Name | Beschreibung | Beispiel | -|-------------|--------------|----------| -| `NEXT_PUBLIC_BASE_URL` | Die öffentliche URL deiner Website | `https://dk0.dev` | -| `MY_EMAIL` | Haupt-Email-Adresse für Kontaktformular | `contact@dk0.dev` | -| `MY_INFO_EMAIL` | Info-Email-Adresse | `info@dk0.dev` | -| `MY_PASSWORD` | Passwort für Haupt-Email | `dein_email_passwort` | -| `MY_INFO_PASSWORD` | Passwort für Info-Email | `dein_info_email_passwort` | -| `ADMIN_BASIC_AUTH` | Admin-Basic-Auth für geschützte Bereiche | `admin:dein_sicheres_passwort` | - -## Docker Compose Setup - -Die Workflows verwenden jetzt `docker-compose.workflow.yml` für eine vollständige Service-Konfiguration: - -- **PostgreSQL**: Datenbank für die Anwendung -- **Redis**: Caching und Session-Management -- **Portfolio App**: Die Hauptanwendung - -## Netzwerk-Konfiguration - -Die Services sind im `portfolio_net` Netzwerk konfiguriert, damit sie miteinander kommunizieren können. - -## Health Checks - -Alle Services haben Health Checks konfiguriert: -- PostgreSQL: `pg_isready` -- Redis: `redis-cli ping` -- Portfolio App: HTTP Health Check auf `/api/health` - -## Troubleshooting - -Falls die Workflows fehlschlagen: - -1. **Secrets prüfen**: Stelle sicher, dass alle Secrets korrekt konfiguriert sind -2. **Netzwerk prüfen**: Überprüfe, ob das `portfolio_net` Netzwerk existiert -3. **Ports prüfen**: Stelle sicher, dass Port 3000 frei ist -4. **Logs prüfen**: Schaue in die Container-Logs für Fehlermeldungen - -```bash -# Container-Logs anzeigen -docker-compose -f docker-compose.workflow.yml logs - -# Services-Status prüfen -docker-compose -f docker-compose.workflow.yml ps -``` \ No newline at end of file diff --git a/SECRETS-VERIFICATION.md b/SECRETS-VERIFICATION.md deleted file mode 100644 index a022613..0000000 --- a/SECRETS-VERIFICATION.md +++ /dev/null @@ -1,105 +0,0 @@ -# Secrets Verification Guide - -## Wie du überprüfst, ob Secrets korrekt geladen werden - -### 1. **Debug-Workflow ausführen** - -Ich habe einen speziellen Debug-Workflow erstellt (`.gitea/workflows/debug-secrets.yml`): - -1. Gehe zu deinem Repository in Gitea -2. Klicke auf **Actions** → **Debug Secrets** -3. Klicke auf **Run workflow** → **Run workflow** -4. Der Workflow wird dir zeigen: - - ✅ Welche Secrets gesetzt sind - - ❌ Welche Secrets fehlen - - 🔐 Ob die Formate korrekt sind - -### 2. **Secrets in Gitea überprüfen** - -**Manuell in Gitea:** -1. Gehe zu **Settings** → **Secrets** -2. Überprüfe, ob alle Secrets vorhanden sind: - - `NEXT_PUBLIC_BASE_URL` - - `MY_EMAIL` - - `MY_INFO_EMAIL` - - `MY_PASSWORD` - - `MY_INFO_PASSWORD` - - `ADMIN_BASIC_AUTH` - -### 3. **Workflow-Logs überprüfen** - -Nach dem Ausführen eines Workflows: - -1. Gehe zu **Actions** → **Workflow runs** -2. Klicke auf den neuesten Run -3. Schaue dir die Logs an, besonders: - - "Verify secrets before deployment" - - "Verify container environment" - -### 4. **Container direkt überprüfen** - -Falls der Container läuft, kannst du ihn direkt überprüfen: - -```bash -# Container-Environment anzeigen -docker exec portfolio-app env | grep -E "(NEXT_PUBLIC_BASE_URL|MY_EMAIL|ADMIN_BASIC_AUTH)" - -# Container-Logs anzeigen -docker logs portfolio-app - -# Services-Status prüfen -docker-compose -f docker-compose.workflow.yml ps -``` - -### 5. **Häufige Probleme** - -**❌ Secret nicht gesetzt:** -- Gehe zu Gitea → Settings → Secrets -- Füge das fehlende Secret hinzu - -**❌ Falsches Format:** -- `NEXT_PUBLIC_BASE_URL`: Muss mit `http://` oder `https://` beginnen -- `MY_EMAIL`: Muss eine gültige Email-Adresse sein -- `ADMIN_BASIC_AUTH`: Muss Format `username:password` haben - -**❌ Container kann nicht starten:** -- Überprüfe die Docker-Logs -- Stelle sicher, dass alle Services (PostgreSQL, Redis) laufen - -### 6. **Test-Schritte** - -1. **Führe den Debug-Workflow aus** -2. **Überprüfe die Ausgabe** -3. **Korrigiere fehlende/falsche Secrets** -4. **Führe einen normalen Workflow aus** -5. **Überprüfe die Container-Environment** - -### 7. **Erwartete Ausgabe** - -**Bei korrekten Secrets:** -``` -✅ NEXT_PUBLIC_BASE_URL: Set (length: 15) -✅ MY_EMAIL: Set (length: 20) -✅ MY_INFO_EMAIL: Set (length: 18) -✅ MY_PASSWORD: Set (length: 12) -✅ MY_INFO_PASSWORD: Set (length: 12) -✅ ADMIN_BASIC_AUTH: Set (length: 15) -``` - -**Bei fehlenden Secrets:** -``` -❌ NEXT_PUBLIC_BASE_URL: Not set -❌ MY_EMAIL: Not set -``` - -### 8. **Schnelltest** - -Führe diesen Befehl aus, um schnell zu testen: - -```bash -# Debug-Workflow manuell ausführen -curl -X POST "https://your-gitea-instance.com/api/v1/repos/your-username/portfolio/actions/workflows/debug-secrets.yml/dispatches" \ - -H "Authorization: token YOUR_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"ref":"main"}' -``` \ No newline at end of file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml deleted file mode 100644 index 4459e7a..0000000 --- a/docker-compose.prod.yml +++ /dev/null @@ -1,80 +0,0 @@ -services: - portfolio: - image: portfolio-app:latest - container_name: portfolio-app - restart: unless-stopped - ports: - - "4000:3000" - environment: - - NODE_ENV=production - - DATABASE_URL=postgresql://portfolio_user:portfolio_pass@postgres:5432/portfolio_db?schema=public - - REDIS_URL=redis://redis-redis-shared-1:6379 - - NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL} - - MY_EMAIL=${MY_EMAIL} - - MY_INFO_EMAIL=${MY_INFO_EMAIL} - - MY_PASSWORD=${MY_PASSWORD} - - MY_INFO_PASSWORD=${MY_INFO_PASSWORD} - - ADMIN_BASIC_AUTH=${ADMIN_BASIC_AUTH} - volumes: - - portfolio_data:/app/.next/cache - networks: - - portfolio_net - - proxy - depends_on: - postgres: - condition: service_healthy - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - deploy: - resources: - limits: - memory: 512M - cpus: '0.5' - reservations: - memory: 256M - cpus: '0.25' - - postgres: - image: postgres:16-alpine - container_name: portfolio-postgres - restart: unless-stopped - environment: - - POSTGRES_DB=portfolio_db - - POSTGRES_USER=portfolio_user - - POSTGRES_PASSWORD=portfolio_pass - volumes: - - postgres_data:/var/lib/postgresql/data - networks: - - portfolio_net - healthcheck: - test: ["CMD-SHELL", "pg_isready -U portfolio_user -d portfolio_db"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - deploy: - resources: - limits: - memory: 256M - cpus: '0.25' - reservations: - memory: 128M - cpus: '0.1' - -volumes: - portfolio_data: - driver: local - postgres_data: - driver: local - redis_data: - driver: local - -networks: - portfolio_net: - external: true - proxy: - external: true diff --git a/docker-compose.workflow.yml b/docker-compose.yml similarity index 75% rename from docker-compose.workflow.yml rename to docker-compose.yml index 57e3ddf..4586a48 100644 --- a/docker-compose.workflow.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ -# Docker Compose configuration for GitHub Actions workflows -# This ensures all required services are running before deployment +# Unified Docker Compose configuration for Portfolio +# Supports both local development and production deployment services: portfolio: @@ -7,9 +7,9 @@ services: container_name: portfolio-app restart: unless-stopped ports: - - "3000:3000" + - "${PORT:-3000}:3000" # Configurable port, defaults to 3000 environment: - - NODE_ENV=production + - NODE_ENV=${NODE_ENV:-production} - DATABASE_URL=postgresql://portfolio_user:portfolio_pass@postgres:5432/portfolio_db?schema=public - REDIS_URL=redis://redis:6379 - NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL} @@ -22,6 +22,7 @@ services: - portfolio_data:/app/.next/cache networks: - portfolio_net + - proxy depends_on: postgres: condition: service_healthy @@ -33,6 +34,14 @@ services: timeout: 10s retries: 3 start_period: 40s + deploy: + resources: + limits: + memory: 512M + cpus: '0.5' + reservations: + memory: 256M + cpus: '0.25' postgres: image: postgres:16-alpine @@ -52,6 +61,14 @@ services: timeout: 5s retries: 5 start_period: 30s + deploy: + resources: + limits: + memory: 256M + cpus: '0.25' + reservations: + memory: 128M + cpus: '0.1' redis: image: redis:7-alpine @@ -78,4 +95,6 @@ volumes: networks: portfolio_net: - driver: bridge \ No newline at end of file + driver: bridge + proxy: + external: true \ No newline at end of file