mirror of
https://github.com/f/awesome-chatgpt-prompts.git
synced 2026-02-12 15:52:47 +00:00
feat(docker): Add Docker deployment guide and configuration instructions
This commit is contained in:
51
.dockerignore
Normal file
51
.dockerignore
Normal file
@@ -0,0 +1,51 @@
|
||||
# Dependencies
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
|
||||
# Build outputs
|
||||
.next
|
||||
out
|
||||
dist
|
||||
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# IDE
|
||||
.vscode
|
||||
.idea
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Environment files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# Docker
|
||||
docker-compose*.yml
|
||||
Dockerfile*
|
||||
|
||||
# Development files
|
||||
.github
|
||||
.claude
|
||||
packages
|
||||
*.md
|
||||
!README.md
|
||||
|
||||
# Test files
|
||||
coverage
|
||||
.nyc_output
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Prisma
|
||||
prisma/migrations/**/migration_lock.toml
|
||||
62
.github/workflows/docker-publish.yml
vendored
Normal file
62
.github/workflows/docker-publish.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Build and Publish Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/prompts.chat
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
platforms: linux/amd64,linux/arm64
|
||||
298
DOCKER.md
Normal file
298
DOCKER.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# Docker Deployment Guide
|
||||
|
||||
Run prompts.chat with a single command using Docker.
|
||||
|
||||
## Quick Start (All-in-One Image)
|
||||
|
||||
The easiest way to run prompts.chat - a single container with Node.js and PostgreSQL:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name prompts \
|
||||
-p 80:80 \
|
||||
-v prompts-data:/data \
|
||||
ghcr.io/f/prompts.chat
|
||||
```
|
||||
|
||||
Open http://localhost in your browser.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `AUTH_SECRET` | Secret for authentication tokens | Auto-generated |
|
||||
| `PORT` | Port to run the app on | `80` |
|
||||
| `DATABASE_URL` | PostgreSQL connection string | Internal DB |
|
||||
|
||||
### Production Setup
|
||||
|
||||
For production, always set `AUTH_SECRET`:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name prompts \
|
||||
-p 80:80 \
|
||||
-v prompts-data:/data \
|
||||
-e AUTH_SECRET="your-secret-key-min-32-chars-long" \
|
||||
ghcr.io/f/prompts.chat
|
||||
```
|
||||
|
||||
Generate a secure secret:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
### With OAuth Providers
|
||||
|
||||
Enable GitHub/Google authentication:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name prompts \
|
||||
-p 80:80 \
|
||||
-v prompts-data:/data \
|
||||
-e AUTH_SECRET="your-secret-key" \
|
||||
-e AUTH_GITHUB_ID="your-github-client-id" \
|
||||
-e AUTH_GITHUB_SECRET="your-github-client-secret" \
|
||||
-e AUTH_GOOGLE_ID="your-google-client-id" \
|
||||
-e AUTH_GOOGLE_SECRET="your-google-client-secret" \
|
||||
ghcr.io/f/prompts.chat
|
||||
```
|
||||
|
||||
### With AI Search (OpenAI)
|
||||
|
||||
Enable semantic search with OpenAI embeddings:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name prompts \
|
||||
-p 80:80 \
|
||||
-v prompts-data:/data \
|
||||
-e AUTH_SECRET="your-secret-key" \
|
||||
-e OPENAI_API_KEY="sk-..." \
|
||||
ghcr.io/f/prompts.chat
|
||||
```
|
||||
|
||||
## Docker Compose (Separate Containers)
|
||||
|
||||
For more control, use Docker Compose with separate app and database containers:
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/f/awesome-chatgpt-prompts.git
|
||||
cd awesome-chatgpt-prompts
|
||||
|
||||
# Create .env file
|
||||
echo "AUTH_SECRET=$(openssl rand -base64 32)" > .env
|
||||
|
||||
# Start services
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### docker-compose.yml
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.app
|
||||
ports:
|
||||
- "80:3000"
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://prompts:prompts@db:5432/prompts
|
||||
- AUTH_SECRET=${AUTH_SECRET}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
- POSTGRES_USER=prompts
|
||||
- POSTGRES_PASSWORD=prompts
|
||||
- POSTGRES_DB=prompts
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U prompts"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
```
|
||||
|
||||
## Data Persistence
|
||||
|
||||
### All-in-One Image
|
||||
|
||||
Data is stored in `/data` inside the container:
|
||||
- `/data/postgres` - PostgreSQL database files
|
||||
|
||||
Mount a volume to persist data:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
-v prompts-data:/data \
|
||||
ghcr.io/f/prompts.chat
|
||||
```
|
||||
|
||||
### Backup
|
||||
|
||||
```bash
|
||||
# Backup database
|
||||
docker exec prompts pg_dump -U prompts prompts > backup.sql
|
||||
|
||||
# Restore database
|
||||
docker exec -i prompts psql -U prompts prompts < backup.sql
|
||||
```
|
||||
|
||||
## Building Locally
|
||||
|
||||
Build the all-in-one image:
|
||||
|
||||
```bash
|
||||
docker build -f docker/Dockerfile -t prompts.chat .
|
||||
docker run -p 80:80 prompts.chat
|
||||
```
|
||||
|
||||
Build the app-only image (for docker-compose):
|
||||
|
||||
```bash
|
||||
docker build -f docker/Dockerfile.app -t prompts.chat-app .
|
||||
```
|
||||
|
||||
## Health Check
|
||||
|
||||
The container includes a health check endpoint:
|
||||
|
||||
```bash
|
||||
curl http://localhost/api/health
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"timestamp": "2024-01-01T00:00:00.000Z",
|
||||
"database": "connected"
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# All logs
|
||||
docker logs prompts
|
||||
|
||||
# Follow logs
|
||||
docker logs -f prompts
|
||||
|
||||
# PostgreSQL logs (inside container)
|
||||
docker exec prompts cat /var/log/supervisor/postgresql.log
|
||||
|
||||
# Next.js logs (inside container)
|
||||
docker exec prompts cat /var/log/supervisor/nextjs.log
|
||||
```
|
||||
|
||||
### Database Access
|
||||
|
||||
```bash
|
||||
# Connect to PostgreSQL
|
||||
docker exec -it prompts psql -U prompts -d prompts
|
||||
|
||||
# Run SQL query
|
||||
docker exec prompts psql -U prompts -d prompts -c "SELECT COUNT(*) FROM \"Prompt\""
|
||||
```
|
||||
|
||||
### Container Shell
|
||||
|
||||
```bash
|
||||
docker exec -it prompts bash
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Container won't start:**
|
||||
- Check logs: `docker logs prompts`
|
||||
- Ensure port 80 is available: `lsof -i :80`
|
||||
|
||||
**Database connection errors:**
|
||||
- Wait for PostgreSQL to initialize (can take 30-60 seconds on first run)
|
||||
- Check database logs: `docker exec prompts cat /var/log/supervisor/postgresql.log`
|
||||
|
||||
**Authentication issues:**
|
||||
- Ensure `AUTH_SECRET` is set for production
|
||||
- For OAuth, verify callback URLs are configured correctly
|
||||
|
||||
## Resource Requirements
|
||||
|
||||
Minimum:
|
||||
- 1 CPU core
|
||||
- 1GB RAM
|
||||
- 2GB disk space
|
||||
|
||||
Recommended:
|
||||
- 2 CPU cores
|
||||
- 2GB RAM
|
||||
- 10GB disk space
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
# Pull latest image
|
||||
docker pull ghcr.io/f/prompts.chat
|
||||
|
||||
# Stop and remove old container
|
||||
docker stop prompts && docker rm prompts
|
||||
|
||||
# Start new container (data persists in volume)
|
||||
docker run -d \
|
||||
--name prompts \
|
||||
-p 80:80 \
|
||||
-v prompts-data:/data \
|
||||
-e AUTH_SECRET="your-secret-key" \
|
||||
ghcr.io/f/prompts.chat
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **Always set AUTH_SECRET** in production
|
||||
2. **Use HTTPS** - put a reverse proxy (nginx, Caddy, Traefik) in front
|
||||
3. **Limit exposed ports** - only expose what's needed
|
||||
4. **Regular updates** - pull the latest image regularly
|
||||
5. **Backup data** - regularly backup the `/data` volume
|
||||
|
||||
## Example: Running Behind Nginx
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name prompts.example.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/prompts.example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/prompts.example.com/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:80;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
46
docker-compose.yml
Normal file
46
docker-compose.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
# Docker Compose for prompts.chat
|
||||
# Alternative to the all-in-one image - separates app and database
|
||||
#
|
||||
# Usage:
|
||||
# docker compose up -d
|
||||
# docker compose down
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.app
|
||||
ports:
|
||||
- "80:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATABASE_URL=postgresql://prompts:prompts@db:5432/prompts?schema=public
|
||||
- AUTH_SECRET=${AUTH_SECRET:-change-me-in-production}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
- POSTGRES_USER=prompts
|
||||
- POSTGRES_PASSWORD=prompts
|
||||
- POSTGRES_DB=prompts
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U prompts -d prompts"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
91
docker/Dockerfile
Normal file
91
docker/Dockerfile
Normal file
@@ -0,0 +1,91 @@
|
||||
# prompts.chat All-in-One Docker Image
|
||||
# Contains Node.js + PostgreSQL for single-container deployment
|
||||
#
|
||||
# Usage:
|
||||
# docker run -p 80:80 ghcr.io/f/prompts.chat
|
||||
# docker run -p 80:80 -e AUTH_SECRET=xxx ghcr.io/f/prompts.chat
|
||||
# docker run -p 80:80 --name my-prompts ghcr.io/f/prompts.chat
|
||||
|
||||
FROM node:24-bookworm-slim AS builder
|
||||
|
||||
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
|
||||
|
||||
# Generate Prisma client and build
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
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
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
postgresql-15 \
|
||||
postgresql-contrib-15 \
|
||||
supervisor \
|
||||
curl \
|
||||
openssl \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p /var/run/postgresql /var/log/supervisor \
|
||||
&& chown -R postgres:postgres /var/run/postgresql
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 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 docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY docker/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
# Create data directory for PostgreSQL
|
||||
RUN mkdir -p /data/postgres && chown -R postgres:postgres /data/postgres
|
||||
|
||||
# Expose port
|
||||
EXPOSE 80
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=90s --retries=3 \
|
||||
CMD curl -f http://localhost:80/api/health || exit 1
|
||||
|
||||
# Entrypoint
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD []
|
||||
68
docker/Dockerfile.app
Normal file
68
docker/Dockerfile.app
Normal file
@@ -0,0 +1,68 @@
|
||||
# prompts.chat App-Only Dockerfile
|
||||
# For use with docker-compose (separate database container)
|
||||
|
||||
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
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Remove unnecessary files
|
||||
RUN rm -rf .github .claude packages docker .git
|
||||
|
||||
# Generate Prisma client
|
||||
RUN npx prisma generate
|
||||
|
||||
# Build Next.js
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
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"]
|
||||
24
docker/entrypoint-app.sh
Normal file
24
docker/entrypoint-app.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/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 "$@"
|
||||
109
docker/entrypoint.sh
Normal file
109
docker/entrypoint.sh
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════════════╗"
|
||||
echo "║ ║"
|
||||
echo "║ 🚀 prompts.chat - AI Prompt Library ║"
|
||||
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
|
||||
PGDATA="/data/postgres"
|
||||
PGBIN="/usr/lib/postgresql/15/bin"
|
||||
|
||||
# Initialize PostgreSQL data directory if needed
|
||||
if [ ! -f "$PGDATA/PG_VERSION" ]; then
|
||||
echo "▶ Initializing PostgreSQL database..."
|
||||
|
||||
# Initialize PostgreSQL
|
||||
su postgres -c "$PGBIN/initdb -D $PGDATA"
|
||||
|
||||
# Configure PostgreSQL
|
||||
cat >> "$PGDATA/postgresql.conf" << EOF
|
||||
listen_addresses = 'localhost'
|
||||
port = 5432
|
||||
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
|
||||
|
||||
# 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
|
||||
echo "▶ Waiting for PostgreSQL..."
|
||||
for i in $(seq 1 30); do
|
||||
if $PGBIN/pg_isready -h localhost -p 5432 >/dev/null 2>&1; then
|
||||
echo "✓ PostgreSQL is ready"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq 30 ]; then
|
||||
echo "✗ PostgreSQL failed to start"
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Run database migrations
|
||||
echo "▶ Running database migrations..."
|
||||
cd /app
|
||||
./node_modules/prisma/build/index.js migrate deploy
|
||||
echo "✓ Migrations complete"
|
||||
|
||||
# Seed database if empty (check if Prompt table exists and has data)
|
||||
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"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════════════╗"
|
||||
echo "║ ║"
|
||||
echo "║ ✅ prompts.chat is running! ║"
|
||||
echo "║ ║"
|
||||
echo "║ 🌐 Open http://localhost:${PORT:-80} in your browser ║"
|
||||
echo "║ ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Keep container running and forward signals
|
||||
wait $SUPERVISOR_PID
|
||||
28
docker/supervisord.conf
Normal file
28
docker/supervisord.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
childlogdir=/var/log/supervisor
|
||||
|
||||
[program:postgresql]
|
||||
command=/usr/lib/postgresql/15/bin/postgres -D /data/postgres
|
||||
user=postgres
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=10
|
||||
stdout_logfile=/var/log/supervisor/postgresql.log
|
||||
stderr_logfile=/var/log/supervisor/postgresql-error.log
|
||||
|
||||
[program:nextjs]
|
||||
command=node /app/server.js
|
||||
directory=/app
|
||||
user=root
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=20
|
||||
startsecs=10
|
||||
startretries=3
|
||||
environment=NODE_ENV="production",PORT="%(ENV_PORT)s",HOSTNAME="0.0.0.0",DATABASE_URL="%(ENV_DATABASE_URL)s",AUTH_SECRET="%(ENV_AUTH_SECRET)s"
|
||||
stdout_logfile=/var/log/supervisor/nextjs.log
|
||||
stderr_logfile=/var/log/supervisor/nextjs-error.log
|
||||
@@ -14,7 +14,7 @@ const nextConfig: NextConfig = {
|
||||
return config;
|
||||
},
|
||||
// Enable standalone output for Docker
|
||||
// output: "standalone",
|
||||
output: "standalone",
|
||||
// Experimental features
|
||||
experimental: {
|
||||
// Enable server actions
|
||||
|
||||
30
src/app/api/health/route.ts
Normal file
30
src/app/api/health/route.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
// Check database connection
|
||||
await db.$queryRaw`SELECT 1`;
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
status: "healthy",
|
||||
timestamp: new Date().toISOString(),
|
||||
database: "connected",
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
status: "unhealthy",
|
||||
timestamp: new Date().toISOString(),
|
||||
database: "disconnected",
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
},
|
||||
{ status: 503 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user