chore(docker): Update Docker deployment guide and workflow configurations
This commit is contained in:
+19
-117
@@ -1,107 +1,22 @@
|
||||
# prompts.chat All-in-One Docker Image
|
||||
# Contains Node.js + PostgreSQL for single-container deployment
|
||||
# prompts.chat Bootstrap Docker Image
|
||||
# Lightweight image that clones and builds on first run
|
||||
#
|
||||
# Usage:
|
||||
# docker build -t my-prompts .
|
||||
# docker build --build-arg BRAND_NAME="My App" --build-arg BRAND_COLOR="#ff0000" -t my-prompts .
|
||||
# docker run -p 80:80 my-prompts
|
||||
#
|
||||
# Build Arguments (all optional):
|
||||
# BRAND_NAME, BRAND_DESCRIPTION, BRAND_LOGO, BRAND_COLOR
|
||||
# AUTH_PROVIDERS (comma-separated: github,google,credentials)
|
||||
# LOCALES (comma-separated: en,es,fr)
|
||||
# docker run -p 80:80 -v prompts-data:/data ghcr.io/f/prompts.chat
|
||||
# docker run -p 80:80 -v prompts-data:/data -e PCHAT_NAME="My App" ghcr.io/f/prompts.chat
|
||||
|
||||
FROM node:24-bookworm-slim AS builder
|
||||
|
||||
# Build arguments for whitelabel branding
|
||||
ARG BRAND_NAME="My Prompt Library"
|
||||
ARG BRAND_DESCRIPTION="Collect, organize, and share AI prompts"
|
||||
ARG BRAND_LOGO="/logo.svg"
|
||||
ARG BRAND_LOGO_DARK=""
|
||||
ARG BRAND_FAVICON="/logo.svg"
|
||||
ARG BRAND_COLOR="#6366f1"
|
||||
ARG THEME_RADIUS="sm"
|
||||
ARG THEME_VARIANT="default"
|
||||
ARG THEME_DENSITY="default"
|
||||
ARG AUTH_PROVIDERS="credentials"
|
||||
ARG ALLOW_REGISTRATION="true"
|
||||
ARG LOCALES="en"
|
||||
ARG DEFAULT_LOCALE="en"
|
||||
ARG FEATURE_PRIVATE_PROMPTS="true"
|
||||
ARG FEATURE_CHANGE_REQUESTS="true"
|
||||
ARG FEATURE_CATEGORIES="true"
|
||||
ARG FEATURE_TAGS="true"
|
||||
ARG FEATURE_COMMENTS="true"
|
||||
ARG FEATURE_AI_SEARCH="false"
|
||||
ARG FEATURE_AI_GENERATION="false"
|
||||
ARG FEATURE_MCP="false"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files first for better caching
|
||||
COPY package.json package-lock.json ./
|
||||
COPY prisma ./prisma/
|
||||
|
||||
# Install all dependencies (including dev for build)
|
||||
RUN npm ci
|
||||
|
||||
# Copy application files
|
||||
COPY . .
|
||||
|
||||
# Remove unnecessary files
|
||||
RUN rm -rf .github .claude packages .git
|
||||
|
||||
# Run docker-setup.js to generate prompts.config.ts with branding
|
||||
ENV BRAND_NAME=${BRAND_NAME}
|
||||
ENV BRAND_DESCRIPTION=${BRAND_DESCRIPTION}
|
||||
ENV BRAND_LOGO=${BRAND_LOGO}
|
||||
ENV BRAND_LOGO_DARK=${BRAND_LOGO_DARK}
|
||||
ENV BRAND_FAVICON=${BRAND_FAVICON}
|
||||
ENV BRAND_COLOR=${BRAND_COLOR}
|
||||
ENV THEME_RADIUS=${THEME_RADIUS}
|
||||
ENV THEME_VARIANT=${THEME_VARIANT}
|
||||
ENV THEME_DENSITY=${THEME_DENSITY}
|
||||
ENV AUTH_PROVIDERS=${AUTH_PROVIDERS}
|
||||
ENV ALLOW_REGISTRATION=${ALLOW_REGISTRATION}
|
||||
ENV LOCALES=${LOCALES}
|
||||
ENV DEFAULT_LOCALE=${DEFAULT_LOCALE}
|
||||
ENV FEATURE_PRIVATE_PROMPTS=${FEATURE_PRIVATE_PROMPTS}
|
||||
ENV FEATURE_CHANGE_REQUESTS=${FEATURE_CHANGE_REQUESTS}
|
||||
ENV FEATURE_CATEGORIES=${FEATURE_CATEGORIES}
|
||||
ENV FEATURE_TAGS=${FEATURE_TAGS}
|
||||
ENV FEATURE_COMMENTS=${FEATURE_COMMENTS}
|
||||
ENV FEATURE_AI_SEARCH=${FEATURE_AI_SEARCH}
|
||||
ENV FEATURE_AI_GENERATION=${FEATURE_AI_GENERATION}
|
||||
ENV FEATURE_MCP=${FEATURE_MCP}
|
||||
|
||||
RUN node scripts/docker-setup.js
|
||||
|
||||
# Generate Prisma client and build
|
||||
# DATABASE_URL is needed at build time for Prisma, but not used
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy"
|
||||
RUN npx prisma generate && npm run build
|
||||
|
||||
# Production image
|
||||
FROM node:24-bookworm-slim
|
||||
|
||||
# Labels for GitHub Container Registry
|
||||
LABEL org.opencontainers.image.source="https://github.com/f/awesome-chatgpt-prompts"
|
||||
LABEL org.opencontainers.image.description="prompts.chat - Self-hosted AI prompt library"
|
||||
LABEL org.opencontainers.image.licenses="MIT"
|
||||
|
||||
# Environment variables
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=80
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
ENV DATABASE_URL="postgresql://prompts:prompts@localhost:5432/prompts?schema=public"
|
||||
|
||||
# Install PostgreSQL, supervisor, and utilities
|
||||
# Install PostgreSQL, git, and utilities
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
postgresql-15 \
|
||||
postgresql-contrib-15 \
|
||||
supervisor \
|
||||
git \
|
||||
curl \
|
||||
openssl \
|
||||
ca-certificates \
|
||||
@@ -109,38 +24,25 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
&& mkdir -p /var/run/postgresql /var/log/supervisor \
|
||||
&& chown -R postgres:postgres /var/run/postgresql
|
||||
|
||||
# Create directories
|
||||
WORKDIR /app
|
||||
RUN mkdir -p /data/postgres /data/app && chown -R postgres:postgres /data/postgres
|
||||
|
||||
# Copy built application from builder
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder /app/prisma ./prisma
|
||||
COPY --from=builder /app/prompts.csv ./prompts.csv
|
||||
COPY --from=builder /app/messages ./messages
|
||||
COPY --from=builder /app/prompts.config.ts ./prompts.config.ts
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
COPY --from=builder /app/.next/standalone ./
|
||||
COPY --from=builder /app/.next/static ./.next/static
|
||||
|
||||
# Copy node_modules for prisma CLI (needed for migrations)
|
||||
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
|
||||
COPY --from=builder /app/node_modules/@prisma ./node_modules/@prisma
|
||||
COPY --from=builder /app/node_modules/prisma ./node_modules/prisma
|
||||
|
||||
# Copy Docker configuration files
|
||||
# Copy bootstrap scripts
|
||||
COPY docker/bootstrap.sh /bootstrap.sh
|
||||
COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY docker/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
RUN chmod +x /bootstrap.sh
|
||||
|
||||
# Create data directory for PostgreSQL
|
||||
RUN mkdir -p /data/postgres && chown -R postgres:postgres /data/postgres
|
||||
# Environment defaults
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=80
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
ENV DATABASE_URL="postgresql://prompts:prompts@localhost:5432/prompts?schema=public"
|
||||
ENV REPO_URL="https://github.com/f/awesome-chatgpt-prompts.git"
|
||||
|
||||
# Expose port
|
||||
EXPOSE 80
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=90s --retries=3 \
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=180s --retries=3 \
|
||||
CMD curl -f http://localhost:80/api/health || exit 1
|
||||
|
||||
# Entrypoint
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD []
|
||||
ENTRYPOINT ["/bootstrap.sh"]
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
# prompts.chat App-Only Dockerfile
|
||||
# For use with docker-compose (separate database container)
|
||||
#
|
||||
# Build with branding:
|
||||
# docker build --build-arg BRAND_NAME="My App" -f docker/Dockerfile.app -t my-prompts .
|
||||
|
||||
FROM node:24-alpine AS base
|
||||
|
||||
# Install dependencies only when needed
|
||||
FROM base AS deps
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package.json package-lock.json ./
|
||||
COPY prisma ./prisma/
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM base AS builder
|
||||
|
||||
# Build arguments for whitelabel branding
|
||||
ARG BRAND_NAME="My Prompt Library"
|
||||
ARG BRAND_DESCRIPTION="Collect, organize, and share AI prompts"
|
||||
ARG BRAND_LOGO="/logo.svg"
|
||||
ARG BRAND_LOGO_DARK=""
|
||||
ARG BRAND_FAVICON="/logo.svg"
|
||||
ARG BRAND_COLOR="#6366f1"
|
||||
ARG THEME_RADIUS="sm"
|
||||
ARG THEME_VARIANT="default"
|
||||
ARG AUTH_PROVIDERS="credentials"
|
||||
ARG LOCALES="en"
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Remove unnecessary files
|
||||
RUN rm -rf .github .claude packages docker .git
|
||||
|
||||
# Run docker-setup.js to generate prompts.config.ts with branding
|
||||
ENV BRAND_NAME=${BRAND_NAME} \
|
||||
BRAND_DESCRIPTION=${BRAND_DESCRIPTION} \
|
||||
BRAND_LOGO=${BRAND_LOGO} \
|
||||
BRAND_LOGO_DARK=${BRAND_LOGO_DARK} \
|
||||
BRAND_FAVICON=${BRAND_FAVICON} \
|
||||
BRAND_COLOR=${BRAND_COLOR} \
|
||||
THEME_RADIUS=${THEME_RADIUS} \
|
||||
THEME_VARIANT=${THEME_VARIANT} \
|
||||
AUTH_PROVIDERS=${AUTH_PROVIDERS} \
|
||||
LOCALES=${LOCALES}
|
||||
|
||||
RUN node scripts/docker-setup.js
|
||||
|
||||
# DATABASE_URL is needed at build time for Prisma, but not used
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy"
|
||||
|
||||
# Generate Prisma client
|
||||
RUN npx prisma generate
|
||||
|
||||
# Build Next.js
|
||||
RUN npm run build
|
||||
|
||||
# Production image
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Install netcat for health checks
|
||||
RUN apk add --no-cache netcat-openbsd curl
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
# Copy built files
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder /app/prisma ./prisma
|
||||
COPY --from=builder /app/prompts.csv ./prompts.csv
|
||||
|
||||
# Copy standalone build
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
# Copy entrypoint
|
||||
COPY docker/entrypoint-app.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["node", "server.js"]
|
||||
@@ -9,25 +9,28 @@ echo "║ ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Generate AUTH_SECRET if not provided
|
||||
if [ -z "$AUTH_SECRET" ]; then
|
||||
export AUTH_SECRET=$(openssl rand -base64 32)
|
||||
echo "⚠ AUTH_SECRET not provided, generated random secret"
|
||||
echo " For production, set AUTH_SECRET environment variable"
|
||||
fi
|
||||
|
||||
# PostgreSQL paths
|
||||
# Paths
|
||||
APP_DIR="/data/app"
|
||||
PGDATA="/data/postgres"
|
||||
PGBIN="/usr/lib/postgresql/15/bin"
|
||||
BUILD_MARKER="/data/.built"
|
||||
|
||||
# Initialize PostgreSQL data directory if needed
|
||||
# Generate AUTH_SECRET if not provided
|
||||
if [ -z "$AUTH_SECRET" ]; then
|
||||
if [ -f "/data/.auth_secret" ]; then
|
||||
export AUTH_SECRET=$(cat /data/.auth_secret)
|
||||
else
|
||||
export AUTH_SECRET=$(openssl rand -base64 32)
|
||||
echo "$AUTH_SECRET" > /data/.auth_secret
|
||||
echo "⚠ AUTH_SECRET generated and saved"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Initialize PostgreSQL if needed
|
||||
if [ ! -f "$PGDATA/PG_VERSION" ]; then
|
||||
echo "▶ Initializing PostgreSQL database..."
|
||||
|
||||
# Initialize PostgreSQL
|
||||
echo "▶ Initializing PostgreSQL..."
|
||||
su postgres -c "$PGBIN/initdb -D $PGDATA"
|
||||
|
||||
# Configure PostgreSQL
|
||||
cat >> "$PGDATA/postgresql.conf" << EOF
|
||||
listen_addresses = 'localhost'
|
||||
port = 5432
|
||||
@@ -35,34 +38,77 @@ max_connections = 100
|
||||
shared_buffers = 128MB
|
||||
EOF
|
||||
|
||||
# Configure authentication
|
||||
cat > "$PGDATA/pg_hba.conf" << EOF
|
||||
local all all trust
|
||||
host all all 127.0.0.1/32 trust
|
||||
host all all ::1/128 trust
|
||||
EOF
|
||||
|
||||
# Start PostgreSQL temporarily to create database
|
||||
su postgres -c "$PGBIN/pg_ctl -D $PGDATA -l /tmp/pg.log start"
|
||||
sleep 3
|
||||
|
||||
# Create database and user
|
||||
su postgres -c "$PGBIN/createuser -s prompts 2>/dev/null" || true
|
||||
su postgres -c "$PGBIN/createdb -O prompts prompts 2>/dev/null" || true
|
||||
|
||||
# Stop PostgreSQL (supervisor will start it)
|
||||
su postgres -c "$PGBIN/pg_ctl -D $PGDATA stop"
|
||||
sleep 2
|
||||
|
||||
echo "✓ PostgreSQL initialized"
|
||||
fi
|
||||
|
||||
# Clone and build on first run
|
||||
if [ ! -f "$BUILD_MARKER" ]; then
|
||||
echo ""
|
||||
echo "▶ First run detected - building prompts.chat..."
|
||||
echo ""
|
||||
|
||||
# Clone repository
|
||||
if [ ! -d "$APP_DIR/.git" ]; then
|
||||
echo "▶ Cloning repository..."
|
||||
rm -rf "$APP_DIR"
|
||||
git clone --depth 1 "$REPO_URL" "$APP_DIR"
|
||||
echo "✓ Repository cloned"
|
||||
fi
|
||||
|
||||
cd "$APP_DIR"
|
||||
|
||||
# Clean up unnecessary files
|
||||
rm -rf .github .claude packages .git
|
||||
|
||||
# Install dependencies
|
||||
echo "▶ Installing dependencies..."
|
||||
npm ci
|
||||
echo "✓ Dependencies installed"
|
||||
|
||||
# Run docker-setup.js to generate config with branding
|
||||
echo "▶ Generating configuration..."
|
||||
node scripts/docker-setup.js
|
||||
echo "✓ Configuration generated"
|
||||
|
||||
# Generate Prisma client
|
||||
echo "▶ Generating Prisma client..."
|
||||
npx prisma generate
|
||||
echo "✓ Prisma client generated"
|
||||
|
||||
# Build Next.js
|
||||
echo "▶ Building Next.js application (this may take a few minutes)..."
|
||||
npm run build
|
||||
echo "✓ Build complete"
|
||||
|
||||
# Mark as built
|
||||
touch "$BUILD_MARKER"
|
||||
|
||||
echo ""
|
||||
echo "✅ Build complete! Starting application..."
|
||||
echo ""
|
||||
else
|
||||
echo "✓ Using existing build"
|
||||
cd "$APP_DIR"
|
||||
fi
|
||||
|
||||
# Start supervisor (manages PostgreSQL and Next.js)
|
||||
echo "▶ Starting services..."
|
||||
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf &
|
||||
SUPERVISOR_PID=$!
|
||||
|
||||
# Wait for PostgreSQL to be ready
|
||||
# Wait for PostgreSQL
|
||||
echo "▶ Waiting for PostgreSQL..."
|
||||
for i in $(seq 1 30); do
|
||||
if $PGBIN/pg_isready -h localhost -p 5432 >/dev/null 2>&1; then
|
||||
@@ -76,23 +122,17 @@ for i in $(seq 1 30); do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Run database migrations
|
||||
# Run migrations
|
||||
echo "▶ Running database migrations..."
|
||||
cd /app
|
||||
./node_modules/prisma/build/index.js migrate deploy
|
||||
npx prisma migrate deploy
|
||||
echo "✓ Migrations complete"
|
||||
|
||||
# Seed database if empty (check if Prompt table exists and has data)
|
||||
# Seed if empty
|
||||
PROMPT_COUNT=$(su postgres -c "$PGBIN/psql -h localhost -U prompts -d prompts -t -c \"SELECT COUNT(*) FROM \\\"Prompt\\\"\"" 2>/dev/null | tr -d ' ' || echo "0")
|
||||
if [ "$PROMPT_COUNT" = "0" ] || [ -z "$PROMPT_COUNT" ]; then
|
||||
echo "▶ Seeding database with prompts..."
|
||||
# Run seed script if available
|
||||
if [ -f "/app/prisma/seed.ts" ]; then
|
||||
npx tsx /app/prisma/seed.ts || echo "⚠ Seeding skipped or failed"
|
||||
fi
|
||||
echo "✓ Database seeded"
|
||||
else
|
||||
echo "✓ Database already has $PROMPT_COUNT prompts"
|
||||
echo "▶ Seeding database..."
|
||||
npx tsx prisma/seed.ts 2>/dev/null || echo "⚠ Seeding skipped"
|
||||
echo "✓ Database ready"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
@@ -105,5 +145,4 @@ echo "║ ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Keep container running and forward signals
|
||||
wait $SUPERVISOR_PID
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "🚀 Starting prompts.chat..."
|
||||
|
||||
# Wait for database to be ready
|
||||
echo "⏳ Waiting for database..."
|
||||
until nc -z ${DATABASE_HOST:-db} ${DATABASE_PORT:-5432}; do
|
||||
sleep 1
|
||||
done
|
||||
echo "✅ Database is ready"
|
||||
|
||||
# Run migrations
|
||||
echo "📦 Running database migrations..."
|
||||
npx prisma migrate deploy
|
||||
|
||||
# Check if database needs seeding
|
||||
echo "🌱 Checking database..."
|
||||
# Skip seed check in entrypoint, let the app handle it
|
||||
|
||||
echo "✨ prompts.chat is starting on port ${PORT:-3000}"
|
||||
|
||||
# Execute the main command
|
||||
exec "$@"
|
||||
@@ -15,8 +15,8 @@ stdout_logfile=/var/log/supervisor/postgresql.log
|
||||
stderr_logfile=/var/log/supervisor/postgresql-error.log
|
||||
|
||||
[program:nextjs]
|
||||
command=node /app/server.js
|
||||
directory=/app
|
||||
command=node /data/app/.next/standalone/server.js
|
||||
directory=/data/app
|
||||
user=root
|
||||
autostart=true
|
||||
autorestart=true
|
||||
|
||||
Reference in New Issue
Block a user