feat: configure Docker deployment with Cloudflare Tunnel for Netcup hosting

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 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2025-11-25 22:21:17 -08:00
parent 7da4937556
commit ee51ac8baa
6 changed files with 465 additions and 1 deletions

57
.dockerignore Normal file
View File

@ -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

312
DEPLOYMENT.md Normal file
View File

@ -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/<TUNNEL-ID>.json
# Copy your credentials file to the expected location
sudo mkdir -p /root/.cloudflared
sudo cp ~/.cloudflared/<TUNNEL-ID>.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 | @ | <TUNNEL-ID>.cfargotunnel.com | Proxied |
| CNAME | www | <TUNNEL-ID>.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 <previous-commit-hash>
# 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

49
Dockerfile Normal file
View File

@ -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"]

20
cloudflared-config.yml Normal file
View File

@ -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

25
docker-compose.yml Normal file
View File

@ -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

View File

@ -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,
},