From ee51ac8baa022b7078bc774947fcd7fa5e24cf68 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Tue, 25 Nov 2025 22:21:17 -0800 Subject: [PATCH] feat: configure Docker deployment with Cloudflare Tunnel for Netcup hosting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrated from Cloudflare Pages to self-hosted Docker deployment on Netcup RS 8000 server. - Add optimized multi-stage Dockerfile with Next.js standalone output - Add docker-compose.yml for container orchestration (port 3003) - Add Cloudflare Tunnel configuration for mycofi.earth routing - Add .dockerignore for optimized build context - Add comprehensive DEPLOYMENT.md with setup and troubleshooting guide - Update next.config.mjs: change output from 'export' to 'standalone' Architecture: Internet → Cloudflare Tunnel → Netcup RS 8000 → Docker Container 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .dockerignore | 57 ++++++++ DEPLOYMENT.md | 312 +++++++++++++++++++++++++++++++++++++++++ Dockerfile | 49 +++++++ cloudflared-config.yml | 20 +++ docker-compose.yml | 25 ++++ next.config.mjs | 3 +- 6 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 DEPLOYMENT.md create mode 100644 Dockerfile create mode 100644 cloudflared-config.yml create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1e759ba --- /dev/null +++ b/.dockerignore @@ -0,0 +1,57 @@ +# .dockerignore - Exclude unnecessary files from Docker build context + +# Git +.git +.gitignore +.github + +# Dependencies +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# Next.js +/.next/ +/out/ +.next +out + +# Production +/build + +# Environment files +.env* +!.env.example + +# Vercel +.vercel + +# Typescript +*.tsbuildinfo +next-env.d.ts + +# IDE +.vscode +.idea +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Documentation +README.md +DEPLOYMENT.md +*.md + +# Docker files (not needed in container) +Dockerfile* +docker-compose*.yml +.dockerignore + +# Cloudflare +cloudflared-config.yml diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..2340d42 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,312 @@ +# MycoFi Earth Website - Deployment Guide + +This guide covers deploying the MycoFi Earth website to your Netcup RS 8000 server using Docker and Cloudflare Tunnel. + +## Architecture Overview + +``` +Internet → Cloudflare DNS → Cloudflare Tunnel → Netcup RS 8000 → Docker Container (Next.js) +``` + +- **Domain**: mycofi.earth, www.mycofi.earth +- **Server**: Netcup RS 8000 G12 Pro (159.195.32.209) +- **Container Port**: 3003 (internal: 3000) +- **Technology**: Next.js 15.5.4 with standalone output + +## Prerequisites + +### On Your Netcup Server + +1. **Docker & Docker Compose** installed +2. **Cloudflared** (Cloudflare Tunnel daemon) installed +3. **Cloudflare Tunnel** created and configured for mycofi.earth + +## Initial Setup + +### 1. Clone Repository to Netcup Server + +```bash +ssh netcup +cd /opt/websites # or your preferred directory +git clone https://gitea.jeffemmett.com/jeffemmett/mycofi-earth-website.git +cd mycofi-earth-website +``` + +### 2. Build and Deploy with Docker Compose + +```bash +# Build the Docker image +docker-compose build + +# Start the container +docker-compose up -d + +# Verify it's running +docker-compose ps +docker-compose logs -f +``` + +The website should now be accessible at `http://localhost:3003` on the Netcup server. + +### 3. Set Up Cloudflare Tunnel + +#### Option A: If Tunnel Already Exists + +If you already have a Cloudflare Tunnel set up, update the configuration: + +```bash +# Copy the config to cloudflared directory +sudo cp cloudflared-config.yml /etc/cloudflared/config.yml + +# Restart cloudflared service +sudo systemctl restart cloudflared +sudo systemctl status cloudflared +``` + +#### Option B: Create New Tunnel + +```bash +# Install cloudflared (if not already installed) +wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb +sudo dpkg -i cloudflared-linux-amd64.deb + +# Authenticate with Cloudflare +cloudflared tunnel login + +# Create the tunnel +cloudflared tunnel create mycofi-earth-tunnel + +# This creates a credentials file at: +# ~/.cloudflared/.json + +# Copy your credentials file to the expected location +sudo mkdir -p /root/.cloudflared +sudo cp ~/.cloudflared/.json /root/.cloudflared/mycofi-earth-tunnel.json + +# Copy the configuration +sudo cp cloudflared-config.yml /etc/cloudflared/config.yml + +# Update the config with your actual tunnel ID +sudo nano /etc/cloudflared/config.yml + +# Create DNS records (CNAME) +cloudflared tunnel route dns mycofi-earth-tunnel mycofi.earth +cloudflared tunnel route dns mycofi-earth-tunnel www.mycofi.earth + +# Run as a service +sudo cloudflared service install +sudo systemctl start cloudflared +sudo systemctl enable cloudflared +sudo systemctl status cloudflared +``` + +### 4. Configure DNS in Cloudflare Dashboard + +Ensure these DNS records exist in your Cloudflare dashboard: + +| Type | Name | Target | Proxy Status | +|-------|------|---------------------------------|--------------| +| CNAME | @ | .cfargotunnel.com | Proxied | +| CNAME | www | .cfargotunnel.com | Proxied | + +## Updating the Website + +### Method 1: Manual Update on Server + +```bash +ssh netcup +cd /opt/websites/mycofi-earth-website + +# Pull latest changes +git pull + +# Rebuild and restart +docker-compose build +docker-compose up -d + +# Check logs +docker-compose logs -f +``` + +### Method 2: Automated CI/CD (Future) + +Set up a GitHub Action or Gitea Action to automatically deploy on push to main: + +1. Trigger on push to main branch +2. SSH into Netcup server +3. Pull latest changes +4. Rebuild Docker image +5. Restart container + +## Monitoring + +### Check Container Status + +```bash +# View running containers +docker-compose ps + +# View logs +docker-compose logs -f mycofi-earth-website + +# Check resource usage +docker stats mycofi-earth-website +``` + +### Check Cloudflare Tunnel Status + +```bash +# Check service status +sudo systemctl status cloudflared + +# View tunnel logs +sudo journalctl -u cloudflared -f + +# Test tunnel connectivity +cloudflared tunnel info mycofi-earth-tunnel +``` + +### Check Website Accessibility + +```bash +# From Netcup server +curl http://localhost:3003 + +# From internet +curl https://mycofi.earth +``` + +## Troubleshooting + +### Container Won't Start + +```bash +# Check Docker logs +docker-compose logs mycofi-earth-website + +# Rebuild from scratch +docker-compose down +docker-compose build --no-cache +docker-compose up -d +``` + +### Cloudflare Tunnel Issues + +```bash +# Restart cloudflared +sudo systemctl restart cloudflared + +# Check configuration +sudo cloudflared tunnel info mycofi-earth-tunnel + +# Verify DNS records +nslookup mycofi.earth +``` + +### Port Conflicts + +If port 3003 is already in use, edit `docker-compose.yml`: + +```yaml +ports: + - "3005:3000" # Change to an available port +``` + +Then update `cloudflared-config.yml` to match: + +```yaml +service: http://localhost:3005 +``` + +## Performance Optimization + +### Enable Caching + +Next.js standalone output already includes optimizations. Additional caching can be configured in Cloudflare: + +1. Go to Cloudflare Dashboard → Caching +2. Enable caching for static assets +3. Set cache TTL appropriately + +### Resource Limits + +To limit container resources, add to `docker-compose.yml`: + +```yaml +services: + mycofi-earth-website: + deploy: + resources: + limits: + cpus: '2.0' + memory: 1G + reservations: + cpus: '0.5' + memory: 512M +``` + +## Security Considerations + +1. **Firewall**: Ensure only necessary ports are open (3003 should not be publicly accessible) +2. **HTTPS**: Cloudflare Tunnel handles SSL/TLS automatically +3. **Environment Variables**: Store sensitive data in `.env` file (not committed to git) +4. **Regular Updates**: Keep Docker images and system packages updated + +## Backup Strategy + +```bash +# Backup script (run periodically) +#!/bin/bash +DATE=$(date +%Y%m%d_%H%M%S) +BACKUP_DIR="/opt/backups/mycofi-earth" + +mkdir -p $BACKUP_DIR +cd /opt/websites/mycofi-earth-website + +# Backup the repository +tar -czf $BACKUP_DIR/mycofi-earth-$DATE.tar.gz . + +# Keep only last 7 backups +cd $BACKUP_DIR +ls -t | tail -n +8 | xargs rm -f +``` + +## Rollback Procedure + +If an update causes issues: + +```bash +# Stop current version +docker-compose down + +# Checkout previous commit +git log --oneline # Find previous commit hash +git checkout + +# Rebuild and restart +docker-compose build +docker-compose up -d +``` + +## Support & Resources + +- **Next.js Docker Docs**: https://nextjs.org/docs/deployment#docker-image +- **Cloudflare Tunnel Docs**: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/ +- **Internal Docs**: See CLAUDE.md for infrastructure details + +## Migration from Cloudflare Pages + +This deployment replaces the previous Cloudflare Pages setup. Key changes: + +1. **Static Export → Server-Side**: Changed `output: 'export'` to `output: 'standalone'` +2. **Cloudflare Pages → Docker Container**: Self-hosted on Netcup RS 8000 +3. **Direct Cloudflare → Tunnel**: Traffic now routes through Cloudflare Tunnel +4. **Benefits**: More control, lower costs, integration with other services on RS 8000 + +## Next Steps + +1. Set up automated backups +2. Configure monitoring/alerting (Prometheus + Grafana) +3. Implement CI/CD pipeline +4. Add health checks to docker-compose.yml +5. Configure log rotation for Docker logs diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8eb762a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,49 @@ +# Multi-stage Dockerfile for optimized production Next.js deployment +# Based on https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile + +# Stage 1: Dependencies +FROM node:20-alpine AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Install dependencies based on the preferred package manager +COPY package.json pnpm-lock.yaml* ./ +RUN corepack enable pnpm && pnpm i --frozen-lockfile + +# Stage 2: Builder +FROM node:20-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Disable telemetry during build +ENV NEXT_TELEMETRY_DISABLED=1 + +# Build the application +RUN corepack enable pnpm && pnpm build + +# Stage 3: Runner (production image) +FROM node:20-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +# Create non-root user for security +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Copy public assets and built application +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +# Start the Next.js server +CMD ["node", "server.js"] diff --git a/cloudflared-config.yml b/cloudflared-config.yml new file mode 100644 index 0000000..69605f6 --- /dev/null +++ b/cloudflared-config.yml @@ -0,0 +1,20 @@ +# Cloudflare Tunnel Configuration for MycoFi Earth Website +# This configuration routes traffic from mycofi.earth to the Docker container on Netcup RS 8000 + +tunnel: mycofi-earth-tunnel +credentials-file: /root/.cloudflared/mycofi-earth-tunnel.json + +ingress: + # Route mycofi.earth to the local Docker container + - hostname: mycofi.earth + service: http://localhost:3003 + + # Route www.mycofi.earth to the same container + - hostname: www.mycofi.earth + service: http://localhost:3003 + + # Catch-all rule (required by cloudflared) + - service: http_status:404 + +# Optional: Enable metrics for monitoring +metrics: 0.0.0.0:3004 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..75e7971 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3.8' + +services: + mycofi-earth-website: + build: + context: . + dockerfile: Dockerfile + image: mycofi-earth-website:latest + container_name: mycofi-earth-website + restart: unless-stopped + ports: + - "3003:3000" # Expose on port 3003 to avoid conflicts with other services + environment: + - NODE_ENV=production + - HOSTNAME=0.0.0.0 + - PORT=3000 + networks: + - mycofi-network + labels: + - "com.docker.compose.project=mycofi-earth" + - "description=MycoFi Earth Website - Next.js Application" + +networks: + mycofi-network: + driver: bridge diff --git a/next.config.mjs b/next.config.mjs index ffcb344..ee99b96 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,7 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - output: 'export', + // Changed from 'export' to 'standalone' for Docker deployment + output: 'standalone', eslint: { ignoreDuringBuilds: true, },