From d1f312116ef8c522eadc51826b91359b75d94830 Mon Sep 17 00:00:00 2001 From: elpatron Date: Tue, 30 Sep 2025 14:23:14 +0200 Subject: [PATCH] feat: Add Docker support and health endpoint - Add production-ready Dockerfile with multi-stage build - Add .dockerignore for optimized builds - Add docker-compose.yml for easy deployment - Add /health endpoint for container health checks - Update README with comprehensive Docker documentation - Include security best practices (non-root user, health checks) - Support for both development and production deployments --- .dockerignore | 93 ++++++++++++++++++++++++++++ Dockerfile | 62 +++++++++++++++++++ README.md | 75 ++++++++++++++++++++++ docker-compose.yml | 18 ++++++ src/client/components/login-form.tsx | 5 -- src/server/index.ts | 5 ++ 6 files changed, 253 insertions(+), 5 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c487123 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,93 @@ +# Dependencies +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Environment files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Build outputs +dist +build +.next +out + +# Development files +.vscode +.idea +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Git +.git +.gitignore + +# Docker +Dockerfile +.dockerignore +docker-compose.yml +docker-compose.yaml + +# Documentation +README.md +docs/ +*.md + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# ESLint cache +.eslintcache + +# 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 + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# Temporary folders +tmp/ +temp/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..17710b5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,62 @@ +# Multi-stage build for production +FROM node:22-alpine AS base + +# Install pnpm +RUN npm install -g pnpm + +# Set working directory +WORKDIR /app + +# Copy package files +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ + +# Install dependencies +RUN pnpm install --frozen-lockfile + +# Copy source code +COPY . . + +# Build the application +RUN pnpm build + +# Production stage +FROM node:22-alpine AS production + +# Install pnpm +RUN npm install -g pnpm + +# Set working directory +WORKDIR /app + +# Copy package files +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ + +# Install production dependencies only +RUN pnpm install --frozen-lockfile --prod + +# Copy built application from base stage +COPY --from=base /app/dist ./dist + +# Copy necessary files for runtime +COPY --from=base /app/src/server/index.ts ./src/server/index.ts +COPY --from=base /app/src/server/routes ./src/server/routes +COPY --from=base /app/src/server/rpc ./src/server/rpc +COPY --from=base /app/src/server/lib ./src/server/lib + +# Create non-root user for security +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nextjs -u 1001 + +# Change ownership of the app directory +RUN chown -R nextjs:nodejs /app +USER nextjs + +# Expose port +EXPOSE 3000 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD node -e "require('http').get('http://localhost:3000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })" || exit 1 + +# Start the application +CMD ["node", "--loader", "ts-node/esm", "src/server/index.ts"] diff --git a/README.md b/README.md index d691402..ba82fb6 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,81 @@ pnpm install pnpm dev ``` +## Docker Deployment + +### Docker Build + +```bash +# Docker Image erstellen +docker build -t stargirlnails-booking . + +# Container starten +docker run -d \ + --name stargirlnails-app \ + -p 3000:3000 \ + --env-file .env \ + stargirlnails-booking +``` + +### Docker Compose (empfohlen) + +Erstelle eine `docker-compose.yml` Datei: + +```yaml +version: '3.8' + +services: + stargirlnails: + build: . + ports: + - "3000:3000" + env_file: + - .env + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s +``` + +Starten mit Docker Compose: + +```bash +# Container starten +docker-compose up -d + +# Logs anzeigen +docker-compose logs -f + +# Container stoppen +docker-compose down +``` + +### Produktions-Deployment + +Für den produktiven Einsatz: + +```bash +# Mit Docker Compose +docker-compose -f docker-compose.yml up -d + +# Oder direkt mit Docker +docker run -d \ + --name stargirlnails-prod \ + -p 80:3000 \ + --restart unless-stopped \ + --env-file .env.production \ + stargirlnails-booking +``` + +**Wichtige Produktions-Hinweise:** +- Verwende eine `.env.production` Datei mit Produktions-Konfiguration +- Setze `NODE_ENV=production` in der Umgebungsdatei +- Verwende einen Reverse Proxy (nginx, Traefik) für HTTPS +- Überwache Container mit Health Checks + ## Features - 📅 **Terminbuchung**: Kunden können online Termine buchen diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e2b424c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3.8' + +services: + stargirlnails: + build: . + ports: + - "3000:3000" + env_file: + - .env + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + environment: + - NODE_ENV=production diff --git a/src/client/components/login-form.tsx b/src/client/components/login-form.tsx index 477e743..0a39538 100644 --- a/src/client/components/login-form.tsx +++ b/src/client/components/login-form.tsx @@ -74,11 +74,6 @@ export function LoginForm() { -
-

Standard Login:

-

Benutzername: owner

-

Passwort: admin123

-
); diff --git a/src/server/index.ts b/src/server/index.ts index bf70709..7de8bbf 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -11,6 +11,11 @@ app.use("*", async (c, next) => { return next(); }); +// Health check endpoint +app.get("/health", (c) => { + return c.json({ status: "ok", timestamp: new Date().toISOString() }); +}); + app.route("/rpc", rpcApp); app.get("/*", clientEntry);