From 1311d564cc3d4e111a72de473fbacac069826289 Mon Sep 17 00:00:00 2001 From: Logan Ford <110533855+Logannford@users.noreply.github.com> Date: Sun, 16 Mar 2025 22:02:17 +0000 Subject: [PATCH 1/6] chore: init docker commit (adds docker ignore and start of Dockerfile) --- .dockerignore | 7 +++++++ .env.example | 24 +++++++++++++++--------- Dockerfile | 13 +++++++++++++ 3 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..72e9aa425 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +Dockerfile +.dockerignore +node_modules +npm-debug.log +README.md +.next +.git \ No newline at end of file diff --git a/.env.example b/.env.example index 07a74e21e..a76245713 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,8 @@ ##### REQUIRED FOR DEV ##### # Supabase keys, learn more here: https://supabase.com/docs/guides/getting-started/quickstarts/nextjs -NEXT_PUBLIC_SUPABASE_URL= -NEXT_PUBLIC_SUPABASE_ANON_KEY= +NEXT_PUBLIC_SUPABASE_URL=your_supabase_url +NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key NEXT_PRIVATE_SUPABASE_SERVICE_ROLE_KEY= # needed for sending auth emails, learn more here: https://supabase.com/docs/guides/auth/auth-hooks?queryGroups=language&language=http @@ -12,8 +12,8 @@ SEND_EMAIL_HOOK_SECRET= RESEND_API_KEY= # Keys used to connect to PostHog, learn more here: https://posthog.com/docs/libraries/next-js?tab=App+router -NEXT_PUBLIC_POSTHOG_KEY= -NEXT_PUBLIC_POSTHOG_HOST= +NEXT_PUBLIC_POSTHOG_KEY=your_posthog_key +NEXT_PUBLIC_POSTHOG_HOST=your_posthog_host # This was inserted by `prisma init`: # Environment variables declared in this file are automatically made available to Prisma. @@ -23,7 +23,7 @@ NEXT_PUBLIC_POSTHOG_HOST= # See the documentation for all the connection string options: https://pris.ly/d/connection-strings # Connect to Supabase via connection pooling with Supavisor. -DATABASE_URL= +DATABASE_URL="postgresql://postgres:postgres@db:5432/techblitz" # Direct connection to the database. Used for migrations. DIRECT_URL= @@ -40,17 +40,17 @@ EXECUTE_CODE_URL= ##### OPTIONAL KEYS NOT REQUIRED FOR DEV ##### # Keys used to connect to Stripe (only needed for stripe development) -NEXT_PUBLIC_STRIPE_KEY= -NEXT_PRIVATE_STRIPE_SECRET_KEY= +NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=your_stripe_publishable_key +NEXT_PRIVATE_STRIPE_SECRET_KEY=your_stripe_secret_key # webhook secret used for updating user details from stripe events, learn more here: https://docs.stripe.com/development/dashboard/webhooks?locale=en-GB NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET= # Keys used to connect to OpenAI (only needed for ai development) -OPENAI_API_KEY= +NEXT_PUBLIC_OPENAI_API_KEY=your_openai_api_key NEXT_PRIVATE_OPEN_AI_ORG= # Keys used to connect to Claude (only needed for ai development) -ANTHROPIC_API_KEY= +NEXT_PUBLIC_ANTHROPIC_API_KEY=your_anthropic_api_key # already preset. NEXT_PUBLIC_ENV=development @@ -63,3 +63,9 @@ REFERRAL_CODE= # the stripe product id for the premium product (used to create custom signup coupons) STRIPE_PREMIUM_PRODUCT_ID= + +# OAuth +NEXT_PUBLIC_GITHUB_OAUTH_CLIENT_ID=your_github_client_id +NEXT_PUBLIC_GITHUB_OAUTH_CLIENT_SECRET=your_github_client_secret +NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_ID=your_google_client_id +NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_SECRET=your_google_client_secret diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..620e8fd9c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +# syntax=docker.io/docker/dockerfile:1 + +FROM node:20-alpine as base + +# install system dependencies +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 yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ \ No newline at end of file From 2a5dd07dc1dd24dd48602e248b5a90533862528c Mon Sep 17 00:00:00 2001 From: Logan Ford <110533855+Logannford@users.noreply.github.com> Date: Sun, 16 Mar 2025 22:13:29 +0000 Subject: [PATCH 2/6] hotfix --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 620e8fd9c..8c13f2f85 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,4 @@ RUN apk add --no-cache libc6-compat WORKDIR /app # Install dependencies based on the preferred package manager -COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ \ No newline at end of file +COPY package.json pnpm-lock.yaml* .npmrc* ./ \ No newline at end of file From a051206d9763f19f97619cf6dd95f2ef549dc434 Mon Sep 17 00:00:00 2001 From: Logan Ford <110533855+Logannford@users.noreply.github.com> Date: Mon, 17 Mar 2025 15:38:40 +0000 Subject: [PATCH 3/6] (ssh key issues, testing github can still be pushed up to) --- .env.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.env.example b/.env.example index a76245713..e87506571 100644 --- a/.env.example +++ b/.env.example @@ -69,3 +69,6 @@ NEXT_PUBLIC_GITHUB_OAUTH_CLIENT_ID=your_github_client_id NEXT_PUBLIC_GITHUB_OAUTH_CLIENT_SECRET=your_github_client_secret NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_ID=your_google_client_id NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_SECRET=your_google_client_secret + +# Docker for self hosting +DOCKER=false \ No newline at end of file From 6b73709399e5a87094b3133d60a4fff2af7f93ee Mon Sep 17 00:00:00 2001 From: Logan Ford <110533855+Logannford@users.noreply.github.com> Date: Mon, 17 Mar 2025 20:03:08 +0000 Subject: [PATCH 4/6] chore(docker): more work implementing docker for easier self hosting --- Dockerfile | 76 +++++++++++++++++++++++++++++++++++++---- app/api/health/route.ts | 25 ++++++++++++++ docker-compose.yml | 64 ++++++++++++++++++++++++++++++++++ next.config.js | 2 ++ package.json | 3 ++ 5 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 app/api/health/route.ts create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile index 8c13f2f85..cc4dc36e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,77 @@ # syntax=docker.io/docker/dockerfile:1 -FROM node:20-alpine as base +FROM node:18-alpine AS base -# install system dependencies -FROM base as deps - -# check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +# 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 pnpm +RUN npm install -g pnpm + # Install dependencies based on the preferred package manager -COPY package.json pnpm-lock.yaml* .npmrc* ./ \ No newline at end of file +COPY package.json pnpm-lock.yaml ./ +# Use --no-frozen-lockfile to avoid issues with lockfile changes +RUN pnpm install --no-frozen-lockfile + +# Rebuild the source code only when needed +FROM base AS builder +# set working directory +WORKDIR /app + +# Install pnpm +RUN npm install -g pnpm + +# copy the dependencies from the deps stage +COPY --from=deps /app/node_modules ./node_modules + +# copy the rest of the application code +COPY . . + +# Skip Prisma's postinstall script for the build phase to avoid schema errors +ENV PRISMA_SKIP_POSTINSTALL=1 +ENV NEXT_TELEMETRY_DISABLED=1 + +# Generate Prisma client - make sure to use the correct schema path +RUN if [ -f "prisma/schema/schema.prisma" ]; then \ + # log the schema path + echo "Generating Prisma client for schema at prisma/schema/schema.prisma"; \ + npx prisma generate --schema=prisma/schema/schema.prisma; \ + elif [ -f "prisma/schema.prisma" ]; then \ + echo "Generating Prisma client for schema at prisma/schema.prisma"; \ + npx prisma generate --schema=prisma/schema.prisma; \ + fi + +# Build the application +RUN pnpm build + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +RUN mkdir .next +RUN chown -R nextjs:nodejs .next + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +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" + +CMD ["node", "server.js"] \ No newline at end of file diff --git a/app/api/health/route.ts b/app/api/health/route.ts new file mode 100644 index 000000000..7e7f17f28 --- /dev/null +++ b/app/api/health/route.ts @@ -0,0 +1,25 @@ +import { NextResponse } from 'next/server'; + +export async function GET() { + try { + return NextResponse.json( + { + status: 'ok', + timestamp: new Date().toISOString(), + environment: process.env.NODE_ENV, + }, + { status: 200 } + ); + } catch (error) { + console.error('Health check failed:', error); + + return NextResponse.json( + { + status: 'error', + message: 'Health check failed', + timestamp: new Date().toISOString(), + }, + { status: 500 } + ); + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..0233cf103 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,64 @@ +# Docker Compose file for TechBlitz application + +services: + app: + build: + context: . + dockerfile: Dockerfile + restart: unless-stopped + ports: + - '3000:3000' + environment: + - DATABASE_URL=postgresql://postgres:postgres@db:5432/techblitz + - NEXT_PUBLIC_URL=http://localhost:3000 + - NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL:-} + - NEXT_PUBLIC_SUPABASE_ANON_KEY=${NEXT_PUBLIC_SUPABASE_ANON_KEY:-} + - NEXT_PRIVATE_SUPABASE_SERVICE_ROLE_KEY=${NEXT_PRIVATE_SUPABASE_SERVICE_ROLE_KEY:-} + - NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY:-} + - NEXT_PUBLIC_POSTHOG_HOST=${NEXT_PUBLIC_POSTHOG_HOST:-} + - NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY:-} + - NEXT_PRIVATE_STRIPE_SECRET_KEY=${NEXT_PRIVATE_STRIPE_SECRET_KEY:-} + - NEXT_PUBLIC_OPENAI_API_KEY=${NEXT_PUBLIC_OPENAI_API_KEY:-} + - NEXT_PUBLIC_ANTHROPIC_API_KEY=${NEXT_PUBLIC_ANTHROPIC_API_KEY:-} + - DOCKER=true + - PRISMA_SKIP_POSTINSTALL=1 + - PRISMA_SCHEMA_PATH=prisma/schema/schema.prisma + depends_on: + - db + # Add healthcheck to ensure the application is running properly + healthcheck: + test: ['CMD', 'wget', '--no-verbose', '--spider', 'http://localhost:3000'] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + volumes: + # Use volume for node_modules to avoid rebuilding + - node_modules:/app/node_modules + # Mount prisma directory for schema access + - ./prisma:/app/prisma + + db: + image: postgres:16-alpine + restart: unless-stopped + environment: + - POSTGRES_PASSWORD=postgres + - POSTGRES_USER=postgres + - POSTGRES_DB=techblitz + ports: + - '5432:5432' + volumes: + - postgres-data:/var/lib/postgresql/data + # Add healthcheck to ensure the database is running properly + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U postgres'] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + +volumes: + postgres-data: + driver: local + node_modules: + driver: local diff --git a/next.config.js b/next.config.js index 4082ceec0..9df094a0f 100644 --- a/next.config.js +++ b/next.config.js @@ -3,6 +3,8 @@ const createMDX = require('@next/mdx'); /** @type {import('next').NextConfig} */ const nextConfig = { + // output: 'standalone' if the flag is set + output: 'standalone', pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'], images: { remotePatterns: [ diff --git a/package.json b/package.json index 6ab8eebe4..fcd5d60a4 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,9 @@ "knip": "knip", "format": "prettier --write \"**/*.{ts,tsx,md}\"" }, + "prisma": { + "schema": "prisma/schema/schema.prisma" + }, "dependencies": { "@ai-sdk/anthropic": "1.1.13", "@ai-sdk/openai": "1.1.15", From d08de79393fe5a40c72b6424b76feb5049074f8d Mon Sep 17 00:00:00 2001 From: Logan Ford <110533855+Logannford@users.noreply.github.com> Date: Mon, 17 Mar 2025 20:14:21 +0000 Subject: [PATCH 5/6] more docker work. --- Dockerfile | 19 +++++++++---------- docker-compose.yml | 2 +- next.config.js | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index cc4dc36e5..c0045016c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ WORKDIR /app # Install pnpm RUN npm install -g pnpm -# Install dependencies based on the preferred package manager +# Install dependencies COPY package.json pnpm-lock.yaml ./ # Use --no-frozen-lockfile to avoid issues with lockfile changes RUN pnpm install --no-frozen-lockfile @@ -27,6 +27,9 @@ RUN npm install -g pnpm # copy the dependencies from the deps stage COPY --from=deps /app/node_modules ./node_modules +# copy the prisma schema from the deps stage +COPY --from=deps /app/prisma/schema/schema.prisma ./prisma/schema/schema.prisma + # copy the rest of the application code COPY . . @@ -34,15 +37,11 @@ COPY . . ENV PRISMA_SKIP_POSTINSTALL=1 ENV NEXT_TELEMETRY_DISABLED=1 -# Generate Prisma client - make sure to use the correct schema path -RUN if [ -f "prisma/schema/schema.prisma" ]; then \ - # log the schema path - echo "Generating Prisma client for schema at prisma/schema/schema.prisma"; \ - npx prisma generate --schema=prisma/schema/schema.prisma; \ - elif [ -f "prisma/schema.prisma" ]; then \ - echo "Generating Prisma client for schema at prisma/schema.prisma"; \ - npx prisma generate --schema=prisma/schema.prisma; \ - fi +# Enables Hot Reloading Check https://github.com/vercel/next.js/issues/36774 for more information +ENV CHOKIDAR_USEPOLLING=true +ENV WATCHPACK_POLLING=true + +RUN pnpm exec prisma generate # Build the application RUN pnpm build diff --git a/docker-compose.yml b/docker-compose.yml index 0233cf103..fce879c91 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,7 +36,7 @@ services: # Use volume for node_modules to avoid rebuilding - node_modules:/app/node_modules # Mount prisma directory for schema access - - ./prisma:/app/prisma + - ./prisma:/app/prisma/schema db: image: postgres:16-alpine diff --git a/next.config.js b/next.config.js index 9df094a0f..cc61fed7f 100644 --- a/next.config.js +++ b/next.config.js @@ -4,7 +4,7 @@ const createMDX = require('@next/mdx'); /** @type {import('next').NextConfig} */ const nextConfig = { // output: 'standalone' if the flag is set - output: 'standalone', + output: process.env.DOCKER ? 'standalone' : undefined, pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'], images: { remotePatterns: [ From afdb266ff5cbd0965c0712c1dbbb7283763754d9 Mon Sep 17 00:00:00 2001 From: Logan Ford <110533855+Logannford@users.noreply.github.com> Date: Thu, 3 Apr 2025 12:46:47 +0100 Subject: [PATCH 6/6] changes to Dockerfile to try and get a build working --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index c0045016c..e8b9a040d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,8 +27,8 @@ RUN npm install -g pnpm # copy the dependencies from the deps stage COPY --from=deps /app/node_modules ./node_modules -# copy the prisma schema from the deps stage -COPY --from=deps /app/prisma/schema/schema.prisma ./prisma/schema/schema.prisma +# Copy the prisma directory containing schema files +COPY prisma ./prisma # copy the rest of the application code COPY . . @@ -41,6 +41,7 @@ ENV NEXT_TELEMETRY_DISABLED=1 ENV CHOKIDAR_USEPOLLING=true ENV WATCHPACK_POLLING=true +# Generate Prisma client RUN pnpm exec prisma generate # Build the application