diff --git a/.env.production.example b/.env.production.example index 54eccda..07a2dd8 100644 --- a/.env.production.example +++ b/.env.production.example @@ -1,18 +1,17 @@ -# کپی به env سرویس API در Dokploy (یا فایل .env کنار compose) +# Env برای Dokploy / compose # دامنه‌ها: -# wheel.montzar.ir → سرویس client -# api.wheel.montzar.ir → سرویس api -# adm.wheel.montzar.ir → سرویس admin +# wheel.montzar.ir → سرویس client (port 80) +# api.wheel.montzar.ir → سرویس api (port 3000) +# adm.wheel.montzar.ir → سرویس admin (port 80) POSTGRES_DB=lucky_wheel POSTGRES_USER=postgres POSTGRES_PASSWORD=CHANGE_ME_STRONG_PASSWORD -# پورت خارجی فقط برای DB (مثلاً DBeaver) — داخل شبکه همچنان 5432 است -# اگر 5432 روی سرور اشغال است مثلاً بگذارید 15432 + +# پورت خارجی فقط برای DB از بیرون (DBeaver). داخل شبکه همیشه 5432 روی سرویس postgres است. EXPORT_DB_PORT=15432 -# داخل شبکه compose هاست postgres است (نه localhost و نه IP عمومی) -DATABASE_URL=postgresql://postgres:CHANGE_ME_STRONG_PASSWORD@postgres:5432/lucky_wheel?schema=public +# نکته: DATABASE_URL را جدا ست نکنید — در docker-compose از POSTGRES_* و هاست "postgres" ساخته می‌شود. REDIS_PASSWORD= diff --git a/apps/api/docker-entrypoint.sh b/apps/api/docker-entrypoint.sh index ae32060..6106dcb 100644 --- a/apps/api/docker-entrypoint.sh +++ b/apps/api/docker-entrypoint.sh @@ -16,10 +16,51 @@ if [ ! -f node_modules/prisma/build/index.js ]; then exit 1 fi +if [ -z "${DATABASE_URL:-}" ]; then + echo "[api] FATAL: DATABASE_URL is empty" >&2 + exit 1 +fi + +# پسورد را در لاگ نشان نده — فقط host/port/db +echo "[api] DATABASE_URL (redacted)=$(node -e "try{const u=new URL(process.env.DATABASE_URL);u.password='***';console.log(u.toString())}catch(e){console.log('INVALID:'+e.message)}")" echo "[api] REDIS_HOST=${REDIS_HOST:-unset} REDIS_PORT=${REDIS_PORT:-unset}" -echo "[api] running prisma migrate deploy..." -node node_modules/prisma/build/index.js migrate deploy --schema=./prisma/schema.prisma +echo "[api] probing postgres TCP (10s timeout)..." +node <<'NODE' +const net = require('net'); +let u; +try { + u = new URL(process.env.DATABASE_URL); +} catch (e) { + console.error('[api] FATAL: invalid DATABASE_URL', e.message); + process.exit(1); +} +const host = u.hostname; +const port = Number(u.port || 5432); +const socket = net.connect({ host, port }); +const timer = setTimeout(() => { + console.error(`[api] FATAL: TCP timeout to ${host}:${port} — سرویس postgres در شبکه compose در دسترس نیست`); + socket.destroy(); + process.exit(1); +}, 10000); +socket.on('connect', () => { + clearTimeout(timer); + console.log(`[api] TCP OK ${host}:${port}`); + socket.end(); + process.exit(0); +}); +socket.on('error', (err) => { + clearTimeout(timer); + console.error(`[api] FATAL: TCP error ${host}:${port} → ${err.message}`); + process.exit(1); +}); +NODE + +echo "[api] running prisma migrate deploy (60s timeout)..." +if ! timeout 60 node node_modules/prisma/build/index.js migrate deploy --schema=./prisma/schema.prisma; then + echo "[api] FATAL: prisma migrate failed or timed out" >&2 + exit 1 +fi echo "[api] migrate done" echo "[api] launching app.js on 0.0.0.0:${PORT:-3000}" diff --git a/apps/api/release/docker-entrypoint.sh b/apps/api/release/docker-entrypoint.sh index ae32060..6106dcb 100644 --- a/apps/api/release/docker-entrypoint.sh +++ b/apps/api/release/docker-entrypoint.sh @@ -16,10 +16,51 @@ if [ ! -f node_modules/prisma/build/index.js ]; then exit 1 fi +if [ -z "${DATABASE_URL:-}" ]; then + echo "[api] FATAL: DATABASE_URL is empty" >&2 + exit 1 +fi + +# پسورد را در لاگ نشان نده — فقط host/port/db +echo "[api] DATABASE_URL (redacted)=$(node -e "try{const u=new URL(process.env.DATABASE_URL);u.password='***';console.log(u.toString())}catch(e){console.log('INVALID:'+e.message)}")" echo "[api] REDIS_HOST=${REDIS_HOST:-unset} REDIS_PORT=${REDIS_PORT:-unset}" -echo "[api] running prisma migrate deploy..." -node node_modules/prisma/build/index.js migrate deploy --schema=./prisma/schema.prisma +echo "[api] probing postgres TCP (10s timeout)..." +node <<'NODE' +const net = require('net'); +let u; +try { + u = new URL(process.env.DATABASE_URL); +} catch (e) { + console.error('[api] FATAL: invalid DATABASE_URL', e.message); + process.exit(1); +} +const host = u.hostname; +const port = Number(u.port || 5432); +const socket = net.connect({ host, port }); +const timer = setTimeout(() => { + console.error(`[api] FATAL: TCP timeout to ${host}:${port} — سرویس postgres در شبکه compose در دسترس نیست`); + socket.destroy(); + process.exit(1); +}, 10000); +socket.on('connect', () => { + clearTimeout(timer); + console.log(`[api] TCP OK ${host}:${port}`); + socket.end(); + process.exit(0); +}); +socket.on('error', (err) => { + clearTimeout(timer); + console.error(`[api] FATAL: TCP error ${host}:${port} → ${err.message}`); + process.exit(1); +}); +NODE + +echo "[api] running prisma migrate deploy (60s timeout)..." +if ! timeout 60 node node_modules/prisma/build/index.js migrate deploy --schema=./prisma/schema.prisma; then + echo "[api] FATAL: prisma migrate failed or timed out" >&2 + exit 1 +fi echo "[api] migrate done" echo "[api] launching app.js on 0.0.0.0:${PORT:-3000}" diff --git a/docker-compose.yml b/docker-compose.yml index 2c4cf5d..225b9b4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,7 +50,8 @@ services: environment: NODE_ENV: production PORT: 3000 - DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgrespassword@postgres:5432/lucky_wheel?schema=public} + # همیشه هاست داخلی compose — اگر در Dokploy مقدار DATABASE_URL=localhost بگذارید اپ گیر می‌کند + DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgrespassword}@postgres:5432/${POSTGRES_DB:-lucky_wheel}?schema=public REDIS_HOST: redis REDIS_PORT: '6379' REDIS_PASSWORD: ${REDIS_PASSWORD:-}