Files
mypage/ENV_CONFIG_GUIDE.md
RJ 3d79cab89a
Some checks failed
Build and Deploy Next.js Blog to Production / 🔍 Code Quality Checks (push) Failing after 18s
Build and Deploy Next.js Blog to Production / 🏗️ Build and Push Docker Image (push) Has been skipped
Build and Deploy Next.js Blog to Production / 🚀 Deploy to Production (push) Has been skipped
📄 production optimizations
2025-12-02 12:39:11 +02:00

7.6 KiB

Build-time Environment Variables Configuration Guide

Overview

This guide documents the configuration for build-time environment variables in the Next.js CI/CD pipeline.

Problem Solved: Next.js 16 requires NEXT_PUBLIC_* variables available during npm run build for:

  • SEO metadata (metadataBase)
  • Sitemap generation
  • OpenGraph URLs
  • RSS feed URLs

Solution: Create .env file in CI/CD from Gitea secrets, copy to Docker build context, embed variables in JavaScript bundle.


Files Modified

1. .gitea/workflows/main.yml

Changes:

  • Added step to create .env from Gitea secrets (after checkout)
  • Added cleanup step to remove .env after Docker push

New Steps:

- name: 📝 Create .env file from Gitea secrets
  run: |
    echo "Creating .env file for Docker build..."
    cat > .env << EOF
    # Build-time environment variables
    NEXT_PUBLIC_SITE_URL=${{ secrets.NEXT_PUBLIC_SITE_URL }}
    NODE_ENV=production
    NEXT_TELEMETRY_DISABLED=1
    EOF
    
    echo "✅ .env file created successfully"
    echo "Preview (secrets masked):"
    cat .env | sed 's/=.*/=***MASKED***/g'
- name: 🚀 Push Docker image to registry
  run: |
    docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
    
    # Clean up sensitive files
    rm -f .env
    echo "✅ Cleaned up .env file"

2. Dockerfile.nextjs

Changes:

  • Added COPY .env* ./ in builder stage (after copying node_modules, before copying source code)

Added Section:

# Copy .env file for build-time variables
# This file is created by CI/CD workflow from Gitea secrets
# NEXT_PUBLIC_* variables are embedded in client-side bundle during build
COPY .env* ./

Position: Between COPY --from=deps /app/node_modules ./node_modules and COPY . .


3. .dockerignore

Changes:

  • Modified to allow .env file (created by CI/CD) while excluding other .env* files

Updated Section:

# Environment files
.env*           # Exclude all .env files
!.env           # EXCEPT .env (needed for build from CI/CD)
!.env.example   # Keep example

Explanation:

  • .env* excludes all environment files
  • !.env creates exception for main .env (from CI/CD)
  • .env.local, .env.development, .env.production.local remain excluded

Gitea Repository Configuration

Required Secrets

Navigate to: Repository Settings → Secrets

Add the following secret:

Secret Name Value Type Description
NEXT_PUBLIC_SITE_URL https://yourdomain.com Secret or Variable Production site URL

Notes:

  • Can be configured as Secret (masked in logs) or Variable (visible in logs)
  • Recommended: Use Variable since it's a public URL
  • For sensitive values (API keys), always use Secret

Adding Additional Variables

To add more build-time variables:

  1. Add to Gitea Secrets/Variables:

    NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
    NEXT_PUBLIC_API_URL=https://api.example.com
    
  2. Update workflow .env creation step:

    cat > .env << EOF
    NEXT_PUBLIC_SITE_URL=${{ secrets.NEXT_PUBLIC_SITE_URL }}
    NEXT_PUBLIC_GA_ID=${{ secrets.NEXT_PUBLIC_GA_ID }}
    NEXT_PUBLIC_API_URL=${{ secrets.NEXT_PUBLIC_API_URL }}
    NODE_ENV=production
    NEXT_TELEMETRY_DISABLED=1
    EOF
    
  3. No changes needed to Dockerfile or .dockerignore


Testing

Local Testing

  1. Create test .env file:

    cat > .env << EOF
    NEXT_PUBLIC_SITE_URL=http://localhost:3030
    NODE_ENV=production
    NEXT_TELEMETRY_DISABLED=1
    EOF
    
  2. Build Docker image:

    docker build -t mypage:test -f Dockerfile.nextjs .
    
  3. Verify variable is embedded (should show "NOT FOUND" - correct behavior):

    docker run --rm mypage:test node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL || 'NOT FOUND')"
    

    Expected Output: NOT FOUND

    Why? NEXT_PUBLIC_* variables are embedded in JavaScript bundle during build, NOT available as runtime environment variables.

  4. Test application starts:

    docker run --rm -p 3030:3030 mypage:test
    

    Visit http://localhost:3030 to verify.

  5. Cleanup:

    rm .env
    docker rmi mypage:test
    

CI/CD Pipeline Flow

Build Process

  1. Checkout code (actions/checkout@v4)
  2. Create .env file from Gitea secrets
  3. Build Docker image:
    • Stage 1: Install dependencies
    • Stage 2: Copy .env → Build Next.js (variables embedded in bundle)
    • Stage 3: Production runtime (no .env needed)
  4. Push image to registry
  5. Cleanup .env file from runner

Deployment Process

  • Production server pulls pre-built image
  • No .env file needed on production server
  • Variables already embedded in JavaScript bundle

Security Best Practices

Implemented

  • .env file created only in CI/CD runner (not committed to git)
  • .env cleaned up after Docker push
  • .gitignore excludes .env files
  • .dockerignore only allows .env created by CI/CD

⚠️ Important Notes

  • DO NOT commit .env files to git repository
  • DO NOT store secrets in NEXT_PUBLIC_* variables (they are exposed to client-side)
  • USE Gitea Secrets for sensitive values (API keys, passwords)
  • USE Gitea Variables for non-sensitive config (URLs, feature flags)

🔒 Sensitive Data Guidelines

Type Use For Access
NEXT_PUBLIC_* Client-side config (URLs, feature flags) Public (embedded in JS bundle)
SECRET_* Server-side secrets (API keys, DB passwords) Private (runtime only)

Troubleshooting

Issue: Variables not available during build

Symptoms:

  • Next.js build errors about missing NEXT_PUBLIC_SITE_URL
  • Metadata/sitemap generation fails

Solution:

  • Verify NEXT_PUBLIC_SITE_URL secret exists in Gitea
  • Check workflow logs for .env creation step
  • Ensure .env file is created BEFORE Docker build

Issue: Variables not working in application

Symptoms:

  • URLs show as undefined or null in production

Diagnosis:

# Check if variable is in bundle (should work):
curl https://yourdomain.com | grep -o 'NEXT_PUBLIC_SITE_URL'

# Check runtime env (should be empty - correct):
docker exec mypage-prod node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL)"

Solution:

  • Verify .env was copied during Docker build
  • Check Dockerfile logs for COPY .env* ./ step
  • Rebuild with --no-cache if needed

Issue: .env file not found during Docker build

Symptoms:

  • Docker build warning: COPY .env* ./ - no files matched

Solution:

  • Check .dockerignore allows .env file
  • Verify workflow creates .env BEFORE Docker build
  • Check file exists: ls -la .env in workflow

Verification Checklist

After deploying changes:

  • Workflow creates .env file (check logs)
  • Docker build copies .env (check build logs)
  • Build succeeds without errors
  • Application starts in production
  • URLs/metadata display correctly
  • .env cleaned up after push (security)

Additional Resources


Support

For issues or questions:

  1. Check workflow logs in Gitea Actions
  2. Review Docker build logs
  3. Verify Gitea secrets configuration
  4. Test locally with sample .env

Last Updated: 2025-11-24