diff --git a/.gitignore b/.gitignore index a547bf3..d84340b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,113 @@ -# Logs -logs -*.log +# Dependencies +node_modules/ npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* -node_modules +# Build outputs +dist/ +build/ +.vite/ + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDE and editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt dist -dist-ssr -*.local + +# Gatsby files +.cache/ +public + +# Storybook build outputs +.out +.storybook-out + +# Temporary folders +tmp/ +temp/ # Editor directories and files .vscode/* !.vscode/extensions.json .idea -.DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? + +# Docker +.dockerignore + +# SSL certificates +*.pem +*.key +*.crt +ssl/ + +# Backup files +*.bak +*.backup \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0117850 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,46 @@ +# Use Node.js 18 Alpine as base image +FROM node:18-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Install dependencies based on the preferred package manager +COPY package.json package-lock.json* ./ +RUN npm ci --only=production + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Build the application +RUN npm run build + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Copy the built application +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/public ./public + +# Change ownership to nextjs user +RUN chown -R nextjs:nodejs /app +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 +ENV HOSTNAME "0.0.0.0" + +# Start the application +CMD ["npx", "serve", "-s", "dist", "-l", "3000"] diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..6bfbae1 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,17 @@ +# Development Dockerfile +FROM node:18-alpine + +WORKDIR /app + +# Install dependencies +COPY package.json package-lock.json* ./ +RUN npm ci + +# Copy source code +COPY . . + +# Expose port +EXPOSE 8080 + +# Start development server +CMD ["npm", "run", "dev"] diff --git a/README-Docker.md b/README-Docker.md new file mode 100644 index 0000000..3162d7a --- /dev/null +++ b/README-Docker.md @@ -0,0 +1,118 @@ +# Docker Setup für IIT Welders + +Dieses Projekt kann mit Docker und Docker Compose ausgeführt werden. + +## Voraussetzungen + +- Docker +- Docker Compose + +## Entwicklung + +### Mit Docker Compose (empfohlen) + +```bash +# Entwicklungsumgebung starten +docker-compose -f docker-compose.dev.yml up + +# Im Hintergrund ausführen +docker-compose -f docker-compose.dev.yml up -d + +# Logs anzeigen +docker-compose -f docker-compose.dev.yml logs -f + +# Stoppen +docker-compose -f docker-compose.dev.yml down +``` + +Die Anwendung ist dann unter `http://localhost:8080` erreichbar. + +### Manuell mit Docker + +```bash +# Development Image bauen +docker build -f Dockerfile.dev -t iitwelders-dev . + +# Container starten +docker run -p 8080:8080 -v $(pwd):/app -v /app/node_modules iitwelders-dev +``` + +## Produktion + +### Mit Docker Compose + +```bash +# Produktionsumgebung starten +docker-compose up -d + +# Logs anzeigen +docker-compose logs -f + +# Stoppen +docker-compose down +``` + +Die Anwendung ist dann unter `http://localhost:3000` erreichbar. + +### Mit Nginx (optional) + +```bash +# Mit Nginx Reverse Proxy +docker-compose up -d + +# Anwendung ist dann unter http://localhost erreichbar +``` + +### Manuell mit Docker + +```bash +# Produktions Image bauen +docker build -t iitwelders-prod . + +# Container starten +docker run -p 3000:3000 iitwelders-prod +``` + +## Nützliche Befehle + +```bash +# Container neu bauen +docker-compose build --no-cache + +# Alle Container und Volumes entfernen +docker-compose down -v + +# In laufenden Container einsteigen +docker exec -it iitwelders-web sh + +# Images aufräumen +docker system prune -a +``` + +## Umgebungsvariablen + +Kopieren Sie `.env.example` zu `.env` und passen Sie die Werte an: + +```bash +cp .env.example .env +``` + +## Troubleshooting + +### Port bereits belegt +Falls Port 3000 oder 8080 bereits belegt ist, ändern Sie die Ports in der entsprechenden docker-compose.yml Datei. + +### Node Modules Probleme +```bash +# Container und Volumes entfernen +docker-compose down -v + +# Neu starten +docker-compose up --build +``` + +### Permission Probleme (Linux/Mac) +```bash +# Ownership korrigieren +sudo chown -R $USER:$USER . +``` diff --git a/README-Server.md b/README-Server.md new file mode 100644 index 0000000..8161615 --- /dev/null +++ b/README-Server.md @@ -0,0 +1,255 @@ +# Server Deployment Guide - IIT Welders + +## Voraussetzungen für Server-Deployment + +### Server-Anforderungen +- **Betriebssystem**: Ubuntu 20.04+ / CentOS 7+ / Debian 10+ +- **RAM**: Mindestens 2GB (4GB empfohlen) +- **CPU**: 1 Core (2 Cores empfohlen) +- **Speicher**: Mindestens 10GB freier Speicher +- **Docker**: Version 20.10+ +- **Docker Compose**: Version 2.0+ + +### Domain & SSL (optional) +- Domain-Name für die Website +- SSL-Zertifikat (Let's Encrypt empfohlen) + +## Schnellstart + +### 1. Server vorbereiten +```bash +# Docker installieren (Ubuntu/Debian) +curl -fsSL https://get.docker.com -o get-docker.sh +sudo sh get-docker.sh +sudo usermod -aG docker $USER + +# Docker Compose installieren +sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose +sudo chmod +x /usr/local/bin/docker-compose + +# Neustart erforderlich +sudo reboot +``` + +### 2. Projekt auf Server übertragen +```bash +# Mit Git (empfohlen) +git clone +cd iitwelders + +# Oder mit SCP +scp -r ./iitwelders user@server:/home/user/ +``` + +### 3. Deployment ausführen +```bash +# Produktions-Deployment +./deploy.sh + +# Oder manuell +docker-compose up -d +``` + +## Detaillierte Anleitung + +### Option 1: Einfaches Deployment (nur App) +```bash +# 1. Projekt klonen/übertragen +git clone +cd iitwelders + +# 2. Dependencies installieren +npm install + +# 3. Build erstellen +npm run build + +# 4. Mit Docker starten +docker-compose up -d + +# 5. Status prüfen +./deploy.sh status +``` + +### Option 2: Vollständiges Deployment (mit Nginx) +```bash +# 1. Alle Schritte aus Option 1 +# 2. Nginx-Konfiguration anpassen (falls nötig) +# 3. SSL-Zertifikate hinzufügen (optional) +mkdir ssl +# SSL-Zertifikate in ssl/ Ordner kopieren + +# 4. Mit Nginx starten +docker-compose up -d + +# 5. Nginx-Konfiguration testen +docker exec iitwelders-nginx nginx -t +``` + +### Option 3: Mit Reverse Proxy (Traefik/Nginx) +```bash +# Für Produktionsumgebung mit automatischem SSL +# docker-compose.prod.yml erstellen (siehe unten) +``` + +## Konfiguration + +### Umgebungsvariablen +```bash +# .env Datei erstellen +cp .env.example .env + +# Anpassen nach Bedarf +nano .env +``` + +### Nginx-Konfiguration anpassen +```bash +# nginx.conf bearbeiten +nano nginx.conf + +# Neustart nach Änderungen +docker-compose restart nginx +``` + +### SSL-Zertifikate (Let's Encrypt) +```bash +# Certbot installieren +sudo apt install certbot + +# Zertifikat erstellen +sudo certbot certonly --standalone -d yourdomain.com + +# Zertifikate in Docker-Container kopieren +sudo cp /etc/letsencrypt/live/yourdomain.com/*.pem ./ssl/ +``` + +## Monitoring & Wartung + +### Logs anzeigen +```bash +# Alle Logs +./deploy.sh logs + +# Nur App-Logs +docker logs iitwelders-web + +# Nur Nginx-Logs +docker logs iitwelders-nginx +``` + +### Health Check +```bash +# Automatischer Health Check +./deploy.sh health + +# Manueller Check +curl http://localhost:3000 +``` + +### Updates +```bash +# Code aktualisieren +git pull origin main + +# Neues Deployment +./deploy.sh + +# Oder nur App neu starten +docker-compose restart iitwelders-app +``` + +### Backup +```bash +# Container stoppen +./deploy.sh stop + +# Backup erstellen +tar -czf backup-$(date +%Y%m%d).tar.gz . + +# Container starten +./deploy.sh +``` + +## Troubleshooting + +### Häufige Probleme + +#### Port bereits belegt +```bash +# Ports prüfen +netstat -tulpn | grep :3000 + +# Prozess beenden +sudo kill -9 +``` + +#### Docker-Probleme +```bash +# Docker neu starten +sudo systemctl restart docker + +# Container bereinigen +docker system prune -a +``` + +#### Speicherplatz +```bash +# Speicherplatz prüfen +df -h + +# Docker-Images bereinigen +docker image prune -a +``` + +#### Logs prüfen +```bash +# System-Logs +journalctl -u docker + +# Container-Logs +docker logs iitwelders-web --tail 100 +``` + +## Sicherheit + +### Firewall konfigurieren +```bash +# UFW aktivieren +sudo ufw enable + +# Nur notwendige Ports öffnen +sudo ufw allow 22 # SSH +sudo ufw allow 80 # HTTP +sudo ufw allow 443 # HTTPS +``` + +### SSL/TLS +- Let's Encrypt für kostenlose SSL-Zertifikate +- Automatische Erneuerung einrichten +- HSTS-Header aktivieren + +### Updates +- Regelmäßige System-Updates +- Docker-Images aktualisieren +- Sicherheits-Patches installieren + +## Performance-Optimierung + +### Nginx-Optimierung +- Gzip-Kompression aktiviert +- Browser-Caching konfiguriert +- Rate Limiting aktiviert + +### Docker-Optimierung +- Multi-stage Builds +- Alpine Linux Images +- Volume-Optimierung + +## Support + +Bei Problemen: +1. Logs prüfen: `./deploy.sh logs` +2. Health Check: `./deploy.sh health` +3. Status prüfen: `./deploy.sh status` +4. Container neu starten: `./deploy.sh stop && ./deploy.sh` diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..754fe3b --- /dev/null +++ b/deploy.sh @@ -0,0 +1,171 @@ +#!/bin/bash + +# Deployment script for IIT Welders +# This script handles the deployment process + +set -e + +# Configuration +APP_NAME="iitwelders" +DOCKER_COMPOSE_FILE="docker-compose.yml" +DOCKER_COMPOSE_DEV_FILE="docker-compose.dev.yml" + +# 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" +} + +# Function to check if Docker is running +check_docker() { + if ! docker info > /dev/null 2>&1; then + print_error "Docker is not running. Please start Docker and try again." + exit 1 + fi + print_success "Docker is running" +} + +# Function to build and deploy +deploy() { + local environment=${1:-production} + + print_status "Starting deployment for $environment environment..." + + # Check Docker + check_docker + + # Stop existing containers + print_status "Stopping existing containers..." + if [ "$environment" = "development" ]; then + docker-compose -f $DOCKER_COMPOSE_DEV_FILE down || true + else + docker-compose -f $DOCKER_COMPOSE_FILE down || true + fi + + # Remove old images + print_status "Cleaning up old images..." + docker image prune -f + + # Build and start containers + print_status "Building and starting containers..." + if [ "$environment" = "development" ]; then + docker-compose -f $DOCKER_COMPOSE_DEV_FILE up --build -d + else + docker-compose -f $DOCKER_COMPOSE_FILE up --build -d + fi + + # Wait for application to start + print_status "Waiting for application to start..." + sleep 10 + + # Run health check + if [ -f "./healthcheck.sh" ]; then + print_status "Running health check..." + chmod +x ./healthcheck.sh + ./healthcheck.sh + fi + + print_success "Deployment completed successfully!" + + if [ "$environment" = "development" ]; then + print_status "Application is available at: http://localhost:8080" + else + print_status "Application is available at: http://localhost:3000" + print_status "With Nginx at: http://localhost" + fi +} + +# Function to show logs +show_logs() { + local environment=${1:-production} + + if [ "$environment" = "development" ]; then + docker-compose -f $DOCKER_COMPOSE_DEV_FILE logs -f + else + docker-compose -f $DOCKER_COMPOSE_FILE logs -f + fi +} + +# Function to stop application +stop() { + local environment=${1:-production} + + print_status "Stopping $environment environment..." + + if [ "$environment" = "development" ]; then + docker-compose -f $DOCKER_COMPOSE_DEV_FILE down + else + docker-compose -f $DOCKER_COMPOSE_FILE down + fi + + print_success "Application stopped" +} + +# Function to show status +status() { + print_status "Container status:" + docker ps --filter "name=$APP_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" +} + +# Main script logic +case "${1:-deploy}" in + "deploy") + deploy "${2:-production}" + ;; + "dev") + deploy "development" + ;; + "logs") + show_logs "${2:-production}" + ;; + "stop") + stop "${2:-production}" + ;; + "status") + status + ;; + "help"|"-h"|"--help") + echo "Usage: $0 [command] [environment]" + echo "" + echo "Commands:" + echo " deploy Deploy to production (default)" + echo " dev Deploy to development" + echo " logs Show application logs" + echo " stop Stop application" + echo " status Show container status" + echo " help Show this help message" + echo "" + echo "Environments:" + echo " production Production environment (default)" + echo " development Development environment" + echo "" + echo "Examples:" + echo " $0 deploy production" + echo " $0 dev" + echo " $0 logs development" + echo " $0 stop" + ;; + *) + print_error "Unknown command: $1" + echo "Use '$0 help' for usage information" + exit 1 + ;; +esac diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..2edcf39 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,21 @@ +version: '3.8' + +services: + iitwelders-dev: + build: + context: . + dockerfile: Dockerfile.dev + ports: + - "8080:8080" + volumes: + - .:/app + - /app/node_modules + environment: + - NODE_ENV=development + - CHOKIDAR_USEPOLLING=true + restart: unless-stopped + container_name: iitwelders-dev + command: npm run dev + +volumes: + node_modules: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..dbbc518 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,30 @@ +version: '3.8' + +services: + iitwelders-app: + build: + context: . + dockerfile: Dockerfile + ports: + - "3000:3000" + environment: + - NODE_ENV=production + restart: unless-stopped + container_name: iitwelders-web + + # Optional: Add nginx reverse proxy for production + nginx: + image: nginx:alpine + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + - ./ssl:/etc/nginx/ssl:ro + depends_on: + - iitwelders-app + restart: unless-stopped + container_name: iitwelders-nginx + +volumes: + node_modules: diff --git a/healthcheck.sh b/healthcheck.sh new file mode 100644 index 0000000..1172ab7 --- /dev/null +++ b/healthcheck.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Health check script for IIT Welders application +# This script checks if the application is running and responding + +set -e + +# Configuration +HEALTH_URL="http://localhost:3000" +TIMEOUT=10 +MAX_RETRIES=3 + +# Function to check health +check_health() { + local url=$1 + local timeout=$2 + + if curl -f -s --max-time $timeout "$url" > /dev/null 2>&1; then + echo "✅ Health check passed: $url" + return 0 + else + echo "❌ Health check failed: $url" + return 1 + fi +} + +# Function to check if port is listening +check_port() { + local port=$1 + + if netstat -tuln | grep -q ":$port "; then + echo "✅ Port $port is listening" + return 0 + else + echo "❌ Port $port is not listening" + return 1 + fi +} + +# Main health check +echo "🔍 Starting health check for IIT Welders..." + +# Check if port is listening +if ! check_port 3000; then + echo "❌ Application is not running on port 3000" + exit 1 +fi + +# Check application health +retry_count=0 +while [ $retry_count -lt $MAX_RETRIES ]; do + if check_health "$HEALTH_URL" $TIMEOUT; then + echo "✅ Application is healthy and responding" + exit 0 + fi + + retry_count=$((retry_count + 1)) + echo "⏳ Retry $retry_count/$MAX_RETRIES in 5 seconds..." + sleep 5 +done + +echo "❌ Health check failed after $MAX_RETRIES retries" +exit 1 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..14776d4 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,76 @@ +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Logging + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + error_log /var/log/nginx/error.log; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_proxied expired no-cache no-store private must-revalidate auth; + gzip_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/xml+rss + application/json; + + # Rate limiting + limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; + + upstream app { + server iitwelders-app:3000; + } + + server { + listen 80; + server_name localhost; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "no-referrer-when-downgrade" always; + add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; + + # Static files caching + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + proxy_pass http://app; + } + + # Main application + location / { + proxy_pass http://app; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } + + # Health check + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } + } +} diff --git a/package.json b/package.json index f0b63a8..0948545 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,11 @@ "build": "vite build", "build:dev": "vite build --mode development", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "start": "serve -s dist -l 3000", + "deploy": "./deploy.sh", + "deploy:dev": "./deploy.sh dev", + "health": "./healthcheck.sh" }, "dependencies": { "@hookform/resolvers": "^3.10.0", @@ -59,7 +63,8 @@ "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "vaul": "^0.9.9", - "zod": "^3.25.76" + "zod": "^3.25.76", + "serve": "^14.2.1" }, "devDependencies": { "@eslint/js": "^9.32.0", diff --git a/public/favicon.ico b/public/favicon.ico index 9bc7cff..896e6cf 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 1c09bd5..46f84b5 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -16,7 +16,7 @@ const Footer = () => { }; return ( -