The MinIO S3 API is accessed internally via the Docker network. The admin console is not needed externally and was causing port 9001 conflicts with other services on the host. Co-authored-by: Cursor <cursoragent@cursor.com>
225 lines
7.8 KiB
YAML
225 lines
7.8 KiB
YAML
# ═══════════════════════════════════════════════════════════════
|
|
# IndeeHub — Production Stack for Portainer
|
|
# ═══════════════════════════════════════════════════════════════
|
|
#
|
|
# All ${VARIABLES} are resolved by Portainer at deploy time.
|
|
# Configure them in Portainer → Stacks → Environment variables
|
|
# before deploying.
|
|
#
|
|
# See env.portainer for the full list of required variables.
|
|
#
|
|
# For local development, use: docker compose -f docker-compose.dev.yml up
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
version: '3.8'
|
|
|
|
services:
|
|
# ── Frontend (nginx serving built Vue app) ──────────────────
|
|
app:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
args:
|
|
VITE_USE_MOCK_DATA: "false"
|
|
VITE_CONTENT_ORIGIN: ${FRONTEND_URL}
|
|
VITE_INDEEHUB_API_URL: /api
|
|
VITE_INDEEHUB_CDN_URL: /storage
|
|
VITE_NOSTR_RELAYS: ""
|
|
restart: unless-stopped
|
|
ports:
|
|
- "${APP_PORT:-7777}:7777"
|
|
depends_on:
|
|
- relay
|
|
- api
|
|
networks:
|
|
- indeedhub-network
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:7777/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
|
|
# ── Backend API (NestJS) ────────────────────────────────────
|
|
api:
|
|
build:
|
|
context: ./backend
|
|
dockerfile: Dockerfile
|
|
restart: unless-stopped
|
|
environment:
|
|
# ── Core ─────────────────────────────────────────────
|
|
ENVIRONMENT: production
|
|
PORT: 4000
|
|
DOMAIN: ${DOMAIN}
|
|
FRONTEND_URL: ${FRONTEND_URL}
|
|
|
|
# ── Database ─────────────────────────────────────────
|
|
DATABASE_HOST: postgres
|
|
DATABASE_PORT: 5432
|
|
DATABASE_USER: ${POSTGRES_USER}
|
|
DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
|
|
DATABASE_NAME: ${POSTGRES_DB}
|
|
|
|
# ── Redis / BullMQ ───────────────────────────────────
|
|
QUEUE_HOST: redis
|
|
QUEUE_PORT: 6379
|
|
QUEUE_PASSWORD: ${REDIS_PASSWORD:-}
|
|
|
|
# ── S3 / MinIO ──────────────────────────────────────
|
|
S3_ENDPOINT: http://minio:9000
|
|
AWS_REGION: us-east-1
|
|
AWS_ACCESS_KEY: ${S3_ACCESS_KEY}
|
|
AWS_SECRET_KEY: ${S3_SECRET_KEY}
|
|
S3_PRIVATE_BUCKET_NAME: indeedhub-private
|
|
S3_PUBLIC_BUCKET_NAME: indeedhub-public
|
|
S3_PUBLIC_BUCKET_URL: ${S3_PUBLIC_BUCKET_URL}
|
|
|
|
# ── BTCPay Server ───────────────────────────────────
|
|
BTCPAY_URL: ${BTCPAY_URL}
|
|
BTCPAY_API_KEY: ${BTCPAY_API_KEY}
|
|
BTCPAY_STORE_ID: ${BTCPAY_STORE_ID}
|
|
BTCPAY_WEBHOOK_SECRET: ${BTCPAY_WEBHOOK_SECRET}
|
|
|
|
# ── Nostr Auth / JWT ─────────────────────────────────
|
|
NOSTR_JWT_SECRET: ${NOSTR_JWT_SECRET}
|
|
NOSTR_JWT_EXPIRES_IN: ${NOSTR_JWT_EXPIRES_IN:-7d}
|
|
|
|
# ── AES-128 Content Encryption ──────────────────────
|
|
AES_MASTER_SECRET: ${AES_MASTER_SECRET}
|
|
|
|
# ── Admin API ────────────────────────────────────────
|
|
ADMIN_API_KEY: ${ADMIN_API_KEY:-}
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
minio:
|
|
condition: service_started
|
|
networks:
|
|
- indeedhub-network
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:4000/nostr-auth/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 60s
|
|
|
|
# ── PostgreSQL Database ─────────────────────────────────────
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: ${POSTGRES_USER}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
POSTGRES_DB: ${POSTGRES_DB}
|
|
volumes:
|
|
- postgres-data:/var/lib/postgresql/data
|
|
networks:
|
|
- indeedhub-network
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 30s
|
|
|
|
# ── Redis (BullMQ job queue) ────────────────────────────────
|
|
redis:
|
|
image: redis:7-alpine
|
|
restart: unless-stopped
|
|
command: >
|
|
sh -c "if [ -n '${REDIS_PASSWORD:-}' ]; then
|
|
redis-server --requirepass '${REDIS_PASSWORD}' --appendonly yes;
|
|
else
|
|
redis-server --appendonly yes;
|
|
fi"
|
|
volumes:
|
|
- redis-data:/data
|
|
networks:
|
|
- indeedhub-network
|
|
|
|
# ── MinIO (S3-compatible object storage) ────────────────────
|
|
minio:
|
|
image: minio/minio:latest
|
|
restart: unless-stopped
|
|
command: server /data --console-address ":9001"
|
|
environment:
|
|
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
|
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
|
volumes:
|
|
- minio-data:/data
|
|
networks:
|
|
- indeedhub-network
|
|
|
|
# ── MinIO bucket init (one-shot: creates required buckets) ──
|
|
minio-init:
|
|
image: minio/mc:latest
|
|
depends_on:
|
|
- minio
|
|
entrypoint: >
|
|
/bin/sh -c "
|
|
sleep 5;
|
|
mc alias set local http://minio:9000 ${MINIO_ROOT_USER} ${MINIO_ROOT_PASSWORD};
|
|
mc mb local/indeedhub-private --ignore-existing;
|
|
mc mb local/indeedhub-public --ignore-existing;
|
|
mc anonymous set download local/indeedhub-public;
|
|
echo 'MinIO buckets initialized';
|
|
"
|
|
networks:
|
|
- indeedhub-network
|
|
restart: "no"
|
|
|
|
# ── FFmpeg Transcoding Worker ───────────────────────────────
|
|
ffmpeg-worker:
|
|
build:
|
|
context: ./backend
|
|
dockerfile: Dockerfile.ffmpeg
|
|
restart: unless-stopped
|
|
environment:
|
|
ENVIRONMENT: production
|
|
DATABASE_HOST: postgres
|
|
DATABASE_PORT: 5432
|
|
DATABASE_USER: ${POSTGRES_USER}
|
|
DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
|
|
DATABASE_NAME: ${POSTGRES_DB}
|
|
QUEUE_HOST: redis
|
|
QUEUE_PORT: 6379
|
|
QUEUE_PASSWORD: ${REDIS_PASSWORD:-}
|
|
S3_ENDPOINT: http://minio:9000
|
|
AWS_REGION: us-east-1
|
|
AWS_ACCESS_KEY: ${S3_ACCESS_KEY}
|
|
AWS_SECRET_KEY: ${S3_SECRET_KEY}
|
|
S3_PRIVATE_BUCKET_NAME: indeedhub-private
|
|
S3_PUBLIC_BUCKET_NAME: indeedhub-public
|
|
S3_PUBLIC_BUCKET_URL: ${S3_PUBLIC_BUCKET_URL}
|
|
AES_MASTER_SECRET: ${AES_MASTER_SECRET}
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
minio:
|
|
condition: service_started
|
|
networks:
|
|
- indeedhub-network
|
|
|
|
# ── Nostr Relay ─────────────────────────────────────────────
|
|
relay:
|
|
image: scsibug/nostr-rs-relay:latest
|
|
restart: unless-stopped
|
|
volumes:
|
|
- relay-data:/usr/src/app/db
|
|
networks:
|
|
- indeedhub-network
|
|
|
|
networks:
|
|
indeedhub-network:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
postgres-data:
|
|
redis-data:
|
|
minio-data:
|
|
relay-data:
|