feat: docker compose

This commit is contained in:
Arda Kilicdagi
2026-03-31 15:08:05 +03:00
parent fc08dbdefe
commit b05b5dd788
8 changed files with 397 additions and 378 deletions
+5 -1
View File
@@ -10,6 +10,7 @@ dist
# Git
.git
.gitignore
.gitattributes
# IDE
.vscode
@@ -23,10 +24,11 @@ dist
.env.development.local
.env.test.local
.env.production.local
.env.sentry-build-plugin
# Docker
compose.yml
docker-compose*.yml
Dockerfile*
# Development files
.github
@@ -38,6 +40,8 @@ packages
# Test files
coverage
.nyc_output
vitest.config.ts
vitest.setup.ts
# OS files
.DS_Store
+179 -130
View File
@@ -1,45 +1,68 @@
# Docker Deployment Guide
Run your own prompts.chat instance with a single command.
Run your own prompts.chat instance using Docker Compose.
## Quick Start
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
ghcr.io/f/prompts.chat
git clone https://github.com/f/prompts.chat.git
cd prompts.chat
docker compose up -d
```
**First run:** The container will clone the repository and build the app (~3-5 minutes).
**Subsequent runs:** Starts immediately using the cached build.
Open http://localhost:4444 in your browser.
## Custom Branding
## Using a Pre-built Image
Customize your instance with environment variables:
Edit `compose.yml` and replace the `build` block with the published image:
```bash
docker run -d \
--name my-prompts \
-p 4444:3000 \
-v prompts-data:/data \
-e PCHAT_NAME="Acme Prompts" \
-e PCHAT_DESCRIPTION="Our team's AI prompt library" \
-e PCHAT_COLOR="#ff6600" \
-e PCHAT_AUTH_PROVIDERS="github,google" \
-e PCHAT_LOCALES="en,es,fr" \
ghcr.io/f/prompts.chat
```yaml
services:
app:
# build:
# context: .
# dockerfile: docker/Dockerfile
image: ghcr.io/f/prompts.chat:latest
```
> **Note:** Branding is applied during the first build. To change branding later, delete the volume and re-run:
> ```bash
> docker rm -f my-prompts
> docker volume rm prompts-data
> docker run ... # with new env vars
> ```
Then run:
```bash
docker compose up -d
```
## Standalone (Bring Your Own Database)
If you already have a PostgreSQL instance, you can run just the app container:
```bash
docker build -f docker/Dockerfile -t prompts.chat .
docker run -d \
--name prompts \
-p 4444:3000 \
-e DATABASE_URL="postgresql://user:pass@your-db-host:5432/prompts?schema=public" \
-e AUTH_SECRET="$(openssl rand -base64 32)" \
prompts.chat
```
## Custom Branding
All branding is configured via `PCHAT_*` environment variables at runtime -- no rebuild needed.
```yaml
# compose.yml
services:
app:
environment:
# ... existing vars ...
PCHAT_NAME: "Acme Prompts"
PCHAT_DESCRIPTION: "Our team's AI prompt library"
PCHAT_COLOR: "#ff6600"
PCHAT_AUTH_PROVIDERS: "github,google"
PCHAT_LOCALES: "en,es,fr"
```
Then restart: `docker compose up -d`
## Configuration Variables
@@ -95,103 +118,102 @@ All variables are prefixed with `PCHAT_` to avoid conflicts.
| Variable | Description | Default |
|----------|-------------|---------|
| `AUTH_SECRET` | Secret for authentication tokens | Auto-generated |
| `PORT` | Internal container port | `3000` |
| `DATABASE_URL` | PostgreSQL connection string | Internal DB |
| `AUTH_SECRET` | Secret for authentication tokens | Auto-generated (set explicitly for production) |
| `DATABASE_URL` | PostgreSQL connection string | Set in compose.yml |
| `DIRECT_URL` | Direct PostgreSQL URL (bypasses poolers) | Same as DATABASE_URL |
| `PORT` | Host port mapping | `4444` |
## Production Setup
For production, set `AUTH_SECRET` explicitly:
For production, always set `AUTH_SECRET` explicitly:
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
-e AUTH_SECRET="$(openssl rand -base64 32)" \
-e PCHAT_NAME="My Company Prompts" \
ghcr.io/f/prompts.chat
# Generate a secret
export AUTH_SECRET=$(openssl rand -base64 32)
# Start with explicit secret
docker compose up -d
```
Or add it to a `.env` file next to `compose.yml`:
```env
AUTH_SECRET=your-secret-key-here
```
### With OAuth Providers
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
-e AUTH_SECRET="your-secret-key" \
-e PCHAT_AUTH_PROVIDERS="github,google" \
-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
```yaml
# compose.yml
services:
app:
environment:
# ... existing vars ...
PCHAT_AUTH_PROVIDERS: "github,google"
AUTH_GITHUB_ID: "your-github-client-id"
AUTH_GITHUB_SECRET: "your-github-client-secret"
AUTH_GOOGLE_ID: "your-google-client-id"
AUTH_GOOGLE_SECRET: "your-google-client-secret"
```
### With AI Features (OpenAI)
```yaml
# compose.yml
services:
app:
environment:
# ... existing vars ...
PCHAT_FEATURE_AI_SEARCH: "true"
OPENAI_API_KEY: "sk-..."
```
## Database Seeding
Seed the database with example prompts:
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
-e PCHAT_FEATURE_AI_SEARCH="true" \
-e OPENAI_API_KEY="sk-..." \
ghcr.io/f/prompts.chat
docker compose exec app npx prisma db seed
```
## Custom Logo
Mount your logo file:
Mount your logo file into the app container:
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
-v ./my-logo.svg:/data/app/public/logo.svg \
-e PCHAT_NAME="My App" \
ghcr.io/f/prompts.chat
```yaml
# compose.yml
services:
app:
volumes:
- ./my-logo.svg:/app/public/logo.svg
environment:
PCHAT_LOGO: "/logo.svg"
```
## 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
```
PostgreSQL data is stored in the `postgres_data` named volume and persists across container restarts, rebuilds, and image updates.
### Backup
```bash
# Backup database
docker exec prompts pg_dump -U prompts prompts > backup.sql
docker compose exec db pg_dump -U prompts prompts > backup.sql
# Restore database
docker exec -i prompts psql -U prompts prompts < backup.sql
docker compose exec -T db psql -U prompts prompts < backup.sql
```
## Building Locally
Build and run locally:
```bash
docker build -f docker/Dockerfile -t prompts.chat .
docker run -p 4444:3000 -v prompts-data:/data prompts.chat
docker compose build
docker compose up -d
```
## Health Check
The container includes a health check endpoint:
The app container includes a health check endpoint:
```bash
curl http://localhost:4444/api/health
@@ -211,48 +233,82 @@ Response:
### View Logs
```bash
# All logs
docker logs prompts
# All services
docker compose logs
# Follow logs
docker logs -f prompts
docker compose logs -f
# PostgreSQL logs (inside container)
docker exec prompts cat /var/log/supervisor/postgresql.log
# App logs only
docker compose logs app
# Next.js logs (inside container)
docker exec prompts cat /var/log/supervisor/nextjs.log
# Database logs only
docker compose logs db
```
### Database Access
```bash
# Connect to PostgreSQL
docker exec -it prompts psql -U prompts -d prompts
docker compose exec db psql -U prompts -d prompts
# Run SQL query
docker exec prompts psql -U prompts -d prompts -c "SELECT COUNT(*) FROM \"Prompt\""
# Run a query
docker compose exec db psql -U prompts -d prompts -c "SELECT COUNT(*) FROM \"Prompt\""
```
### Container Shell
```bash
docker exec -it prompts bash
docker compose exec app sh
docker compose exec db bash
```
### Common Issues
**Container won't start:**
- Check logs: `docker logs prompts`
- Ensure port 4444 is available: `lsof -i :4444`
**App container keeps restarting:**
- Check logs: `docker compose logs app`
- Database may not be ready yet -- the entrypoint retries for up to 60 seconds
**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`
- Verify the `db` service is healthy: `docker compose ps`
- Check database logs: `docker compose logs db`
**Authentication issues:**
- Ensure `AUTH_SECRET` is set for production
- For OAuth, verify callback URLs are configured correctly
- Set `AUTH_SECRET` explicitly for production
- For OAuth, verify callback URLs match your domain
## Updating
```bash
# If using pre-built images
docker compose pull
docker compose up -d
# If building locally
git pull
docker compose build
docker compose up -d
```
Data persists in the `postgres_data` volume across updates.
## Migrating from the Old Single-Image Setup
If you were using the previous all-in-one Docker image:
```bash
# 1. Export your database from the old container
docker exec prompts pg_dump -U prompts prompts > backup.sql
# 2. Stop and remove the old container
docker stop prompts && docker rm prompts
# 3. Start the new compose setup
docker compose up -d
# 4. Import your data
docker compose exec -T db psql -U prompts prompts < backup.sql
```
## Resource Requirements
@@ -266,33 +322,9 @@ Recommended:
- 2GB RAM
- 10GB disk space
## Updating
## Running Behind a Reverse Proxy
```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 4444:3000 \
-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
```nginx
server {
@@ -316,6 +348,23 @@ server {
}
```
### Caddy
```
prompts.example.com {
reverse_proxy localhost:4444
}
```
## Security Considerations
1. **Always set AUTH_SECRET** in production
2. **Use HTTPS** -- put a reverse proxy (Nginx, Caddy, Traefik) in front
3. **Change default database password** -- update `POSTGRES_PASSWORD` in compose.yml and the connection strings
4. **Limit exposed ports** -- only expose what's needed
5. **Regular updates** -- pull the latest image regularly
6. **Backup data** -- regularly backup the database
## License
MIT
+57
View File
@@ -0,0 +1,57 @@
# Fix Docker setup: proper multi-container architecture with Docker Compose
## Summary
The previous Docker setup bundled PostgreSQL and the Next.js app into a single image managed by `supervisord`. This is an anti-pattern — it violates the "one container, one process" principle, clones the repo and runs the full build at runtime (3–5 min cold start), and makes scaling, updating, and debugging significantly harder.
This PR replaces it with a proper Docker Compose setup following the "Docker way":
- **`app`** — Next.js application container (multi-stage build, standalone output)
- **`db`** — Official `postgres:17-bookworm` container
Database data is persisted via a named Docker volume and survives container restarts, rebuilds, and image updates.
## Changes
### New files
- **`compose.yml`** — Docker Compose configuration with `app` and `db` services, healthchecks, and a named volume for PostgreSQL data
- **`docker/entrypoint.sh`** — Lightweight entrypoint: waits for the database, runs `prisma migrate deploy`, then starts the app
### Modified files
- **`docker/Dockerfile`** — Replaced the single-stage bootstrap image with a proper 4-stage multi-stage build:
- `base` — Shared `node:24-bookworm-slim` with system dependencies
- `deps` — Runs `npm ci` (and `prisma generate` via postinstall)
- `builder` — Runs `npm run build`, produces `.next/standalone/`
- `runner` — Minimal production image; copies standalone output, installs only Prisma CLI for migrations
- **`.dockerignore`** — Added `compose.yml`, test config files
- **`DOCKER.md`** — Complete rewrite covering the new compose-based workflow, standalone single-container usage, migration guide from the old setup, backup/restore, and production deployment tips
### Deleted files
- `docker/bootstrap.sh` — Replaced by `docker/entrypoint.sh`
- `docker/supervisord.conf` — No longer needed (one process per container)
## Key design decisions
- **PCHAT_* env vars work at runtime** — `src/lib/config/index.ts` already applies overrides via `applyEnvOverrides()`. No rebuild is needed to change branding or feature flags; just update environment variables and restart.
- **Migrations run at startup** — `prisma migrate deploy` runs in the entrypoint before the app starts, keeping deployments simple without init containers.
- **Seeding is manual** — `docker compose exec app npx prisma db seed`
- **All images are Debian-based** — `node:24-bookworm-slim` (bookworm) and `postgres:17-bookworm`
- **`.github/workflows/docker-publish.yml` needs no changes** — it already builds `./docker/Dockerfile` with context `.`
## Quick start after this PR
```bash
git clone https://github.com/f/prompts.chat.git
cd prompts.chat
docker compose up -d
```
Open http://localhost:4444
## Testing
- `docker compose build` — builds successfully
- `docker compose up -d` — both services start, DB healthcheck passes before app starts
- `curl http://localhost:4444/api/health` — returns `{"status":"healthy","database":"connected"}`
- `curl http://localhost:4444/` — homepage returns 200
- Data persists across `docker compose down && docker compose up -d`
+44
View File
@@ -0,0 +1,44 @@
services:
db:
image: postgres:17-bookworm
restart: unless-stopped
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 -d prompts"]
interval: 5s
timeout: 5s
retries: 10
start_period: 10s
app:
build:
context: .
dockerfile: docker/Dockerfile
# To use a pre-built image instead of building locally, comment out
# the 'build' block above and uncomment the line below:
# image: ghcr.io/f/prompts.chat:latest
restart: unless-stopped
ports:
- "${PORT:-4444}:3000"
environment:
DATABASE_URL: "postgresql://prompts:prompts@db:5432/prompts?schema=public"
DIRECT_URL: "postgresql://prompts:prompts@db:5432/prompts?schema=public"
AUTH_SECRET: "${AUTH_SECRET:-}"
NODE_ENV: production
# Branding (all optional — set any PCHAT_* variable to customize at runtime)
# PCHAT_NAME: "My Prompt Library"
# PCHAT_DESCRIPTION: "Our team's AI prompt collection"
# PCHAT_COLOR: "#6366f1"
# PCHAT_AUTH_PROVIDERS: "credentials"
# PCHAT_LOCALES: "en"
depends_on:
db:
condition: service_healthy
volumes:
postgres_data:
+73 -28
View File
@@ -1,49 +1,94 @@
# prompts.chat Bootstrap Docker Image
# Lightweight image that clones and builds on first run
# prompts.chat Docker Image
# Multi-stage build for a production-ready Next.js application
#
# Usage:
# docker run -p 4444:3000 -v prompts-data:/data ghcr.io/f/prompts.chat
# docker run -p 4444:3000 -v prompts-data:/data -e PCHAT_NAME="My App" ghcr.io/f/prompts.chat
# Usage with Docker Compose:
# docker compose up -d
#
# Usage standalone (bring your own PostgreSQL):
# docker build -f docker/Dockerfile -t prompts.chat .
# docker run -p 4444:3000 -e DATABASE_URL="postgresql://..." prompts.chat
FROM node:24-bookworm-slim
# ---- Stage 1: Base ----
FROM node:24-bookworm-slim AS base
RUN apt-get update && apt-get install -y --no-install-recommends \
openssl \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# ---- Stage 2: Dependencies ----
FROM base AS deps
# Copy dependency manifests and Prisma schema (postinstall runs prisma generate)
COPY package.json package-lock.json ./
COPY prisma/schema.prisma prisma/schema.prisma
COPY prisma.config.ts tsconfig.json ./
# Dummy DATABASE_URL for prisma generate (no actual connection is made)
ENV DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy"
RUN npm ci
# ---- Stage 3: Builder ----
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
ENV DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy"
RUN npm run build
# ---- Stage 4: Runner ----
FROM node:24-bookworm-slim AS runner
LABEL org.opencontainers.image.source="https://github.com/f/prompts.chat"
LABEL org.opencontainers.image.description="prompts.chat - Self-hosted AI prompt library"
LABEL org.opencontainers.image.licenses="MIT"
# 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 \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /var/run/postgresql /var/log/supervisor \
&& chown -R postgres:postgres /var/run/postgresql
&& rm -rf /var/lib/apt/lists/*
# Create directories
WORKDIR /app
RUN mkdir -p /data/postgres /data/app && chown -R postgres:postgres /data/postgres
# Copy bootstrap scripts
COPY docker/bootstrap.sh /bootstrap.sh
COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
RUN chmod +x /bootstrap.sh
RUN groupadd --system --gid 1001 nodejs && \
useradd --system --uid 1001 --gid nodejs nextjs
# Copy standalone build output
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
# Copy Prisma schema, migrations, and config for runtime migrations
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
COPY --from=builder --chown=nextjs:nodejs /app/prisma.config.ts ./prisma.config.ts
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json
COPY --from=builder --chown=nextjs:nodejs /app/tsconfig.json ./tsconfig.json
# Install only Prisma CLI and its dependencies for runtime migrations
RUN npm install --no-save prisma@6.19 dotenv
# Copy entrypoint script
COPY --chown=nextjs:nodejs docker/entrypoint.sh ./entrypoint.sh
RUN chmod +x ./entrypoint.sh
# Environment defaults
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
ENV DATABASE_URL="postgresql://prompts:prompts@localhost:5432/prompts?schema=public"
ENV DIRECT_URL="postgresql://prompts:prompts@localhost:5432/prompts?schema=public"
ENV REPO_URL="https://github.com/f/prompts.chat.git"
ENV HOSTNAME=0.0.0.0
ENV NEXT_TELEMETRY_DISABLED=1
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --start-period=180s --retries=3 \
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
ENTRYPOINT ["/bootstrap.sh"]
USER nextjs
ENTRYPOINT ["./entrypoint.sh"]
-181
View File
@@ -1,181 +0,0 @@
#!/bin/bash
set -e
echo ""
echo "╔═══════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ 🚀 prompts.chat - AI Prompt Library ║"
echo "║ ║"
echo "╚═══════════════════════════════════════════════════════════════╝"
echo ""
# Paths
APP_DIR="/data/app"
PGDATA="/data/postgres"
PGBIN="/usr/lib/postgresql/15/bin"
BUILD_MARKER="/data/.built"
# 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..."
su postgres -c "$PGBIN/initdb -D $PGDATA"
cat >> "$PGDATA/postgresql.conf" << EOF
listen_addresses = 'localhost'
port = 5432
max_connections = 100
shared_buffers = 128MB
EOF
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
su postgres -c "$PGBIN/pg_ctl -D $PGDATA -l /tmp/pg.log start"
sleep 3
su postgres -c "$PGBIN/createuser -s prompts 2>/dev/null" || true
su postgres -c "$PGBIN/createdb -O prompts prompts 2>/dev/null" || true
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 (including devDependencies needed for build)
echo "▶ Installing dependencies..."
NODE_ENV=development 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"
# Copy static files for standalone mode
echo "▶ Copying static assets..."
cp -r .next/static .next/standalone/.next/
cp -r public .next/standalone/
echo "✓ Static assets copied"
# Mark as built
touch "$BUILD_MARKER"
echo ""
echo "✅ Build complete! Starting application..."
echo ""
else
echo "✓ Using existing build"
cd "$APP_DIR"
fi
# Start supervisord (manages PostgreSQL and Next.js)
echo "▶ Starting services..."
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf &
SUPERVISOR_PID=$!
# 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
echo "✓ PostgreSQL is ready"
break
fi
if [ $i -eq 30 ]; then
echo "✗ PostgreSQL failed to start"
exit 1
fi
sleep 1
done
# Run migrations
echo "▶ Running database migrations..."
cd "$APP_DIR"
npx prisma migrate deploy
echo "✓ Migrations complete"
# Seed on first run only
SEED_MARKER="/data/.seeded"
if [ ! -f "$SEED_MARKER" ]; then
echo "▶ Seeding database..."
if npx tsx prisma/seed.ts 2>/dev/null; then
touch "$SEED_MARKER"
echo "✓ Database seeded"
else
echo "⚠ Seeding skipped"
fi
fi
# Wait for supervisord to be ready
echo "▶ Waiting for supervisord..."
for i in $(seq 1 30); do
if kill -0 $SUPERVISOR_PID 2>/dev/null && [ -S /var/run/supervisor.sock ]; then
echo "✓ Supervisord is ready"
break
fi
if ! kill -0 $SUPERVISOR_PID 2>/dev/null; then
echo "✗ Supervisord process died"
exit 1
fi
if [ $i -eq 30 ]; then
echo "✗ Supervisord socket not available after 30s"
exit 1
fi
sleep 1
done
# Start Next.js via supervisorctl
echo "▶ Starting Next.js..."
supervisorctl start nextjs
echo ""
echo "╔═══════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ ✅ prompts.chat is running! ║"
echo "║ ║"
echo "║ 🌐 Open http://localhost:${PORT:-80} in your browser ║"
echo "║ ║"
echo "╚═══════════════════════════════════════════════════════════════╝"
echo ""
wait $SUPERVISOR_PID
+39
View File
@@ -0,0 +1,39 @@
#!/bin/sh
set -e
# Generate AUTH_SECRET if not provided
if [ -z "$AUTH_SECRET" ]; then
AUTH_SECRET=$(openssl rand -base64 32)
export AUTH_SECRET
echo "[prompts.chat] AUTH_SECRET not set -- generated a random value."
echo "[prompts.chat] Set AUTH_SECRET explicitly for production to persist sessions across restarts."
fi
# Wait for PostgreSQL to be ready
echo "[prompts.chat] Waiting for database..."
MAX_RETRIES=30
RETRY_COUNT=0
until node -e "
const net = require('net');
const url = new URL(process.env.DATABASE_URL);
const sock = net.createConnection({ host: url.hostname, port: url.port || 5432 });
sock.on('connect', () => { sock.destroy(); process.exit(0); });
sock.on('error', () => process.exit(1));
" 2>/dev/null; do
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ "$RETRY_COUNT" -ge "$MAX_RETRIES" ]; then
echo "[prompts.chat] ERROR: Database not reachable after ${MAX_RETRIES} attempts."
exit 1
fi
echo "[prompts.chat] Database not ready (attempt ${RETRY_COUNT}/${MAX_RETRIES}), retrying in 2s..."
sleep 2
done
# Run database migrations
echo "[prompts.chat] Running database migrations..."
npx prisma migrate deploy
echo "[prompts.chat] Migrations applied successfully."
# Start the application
echo "[prompts.chat] Starting application on port ${PORT:-3000}..."
exec node server.js
-38
View File
@@ -1,38 +0,0 @@
[unix_http_server]
file=/var/run/supervisor.sock
chmod=0700
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[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 /data/app/.next/standalone/server.js
directory=/data/app
user=root
autostart=false
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