diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index 43535d2..c5cca1d 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -80,12 +80,12 @@ WORKDIR /app/apps/api # Switch to non-root user USER nestjs -# Expose API port -EXPOSE 3001 +# Expose API port (default 3001, can be overridden via PORT env var) +EXPOSE ${PORT:-3001} -# Health check +# Health check uses PORT env var (set by docker-compose or defaults to 3001) HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ - CMD node -e "require('http').get('http://localhost:3001/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" + CMD node -e "const port = process.env.PORT || 3001; require('http').get('http://localhost:' + port + '/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" # Use dumb-init to handle signals properly ENTRYPOINT ["dumb-init", "--"] diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index 8da6c1f..03232d6 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -90,17 +90,16 @@ WORKDIR /app/apps/web # Switch to non-root user USER nextjs -# Expose web port -EXPOSE 3000 +# Expose web port (default 3000, can be overridden via PORT env var) +EXPOSE ${PORT:-3000} # Environment variables ENV NODE_ENV=production -ENV PORT=3000 ENV HOSTNAME="0.0.0.0" -# Health check +# Health check uses PORT env var (set by docker-compose or defaults to 3000) HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ - CMD node -e "require('http').get('http://localhost:3000', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" + CMD node -e "const port = process.env.PORT || 3000; require('http').get('http://localhost:' + port, (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" # Use dumb-init to handle signals properly ENTRYPOINT ["dumb-init", "--"] diff --git a/docker-compose.yml b/docker-compose.yml index c072788..10f2709 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3.9' +version: "3.9" services: # ====================== @@ -149,7 +149,15 @@ services: authentik-redis: condition: service_healthy healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9000/-/health/live/"] + test: + [ + "CMD", + "wget", + "--no-verbose", + "--tries=1", + "--spider", + "http://localhost:9000/-/health/live/", + ] interval: 30s timeout: 10s retries: 3 @@ -293,8 +301,8 @@ services: restart: unless-stopped environment: NODE_ENV: production - # API Configuration - API_PORT: ${API_PORT:-3001} + # API Configuration - PORT is what NestJS reads + PORT: ${API_PORT:-3001} API_HOST: ${API_HOST:-0.0.0.0} # Database DATABASE_URL: postgresql://${POSTGRES_USER:-mosaic}:${POSTGRES_PASSWORD:-mosaic_dev_password}@postgres:5432/${POSTGRES_DB:-mosaic} @@ -311,14 +319,20 @@ services: # Ollama (optional) OLLAMA_ENDPOINT: ${OLLAMA_ENDPOINT:-http://ollama:11434} ports: - - "${API_PORT:-3001}:3001" + - "${API_PORT:-3001}:${API_PORT:-3001}" depends_on: postgres: condition: service_healthy valkey: condition: service_healthy healthcheck: - test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] + test: + [ + "CMD", + "sh", + "-c", + 'node -e "require(''http'').get(''http://localhost:${PORT:-3001}/health'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"', + ] interval: 30s timeout: 10s retries: 3 @@ -334,7 +348,7 @@ services: - "traefik.http.routers.mosaic-api.rule=Host(`${MOSAIC_API_DOMAIN:-api.mosaic.local}`)" - "traefik.http.routers.mosaic-api.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - "traefik.http.routers.mosaic-api.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.services.mosaic-api.loadbalancer.server.port=3001" + - "traefik.http.services.mosaic-api.loadbalancer.server.port=${API_PORT:-3001}" - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-mosaic-public}" # Let's Encrypt (if enabled) - "traefik.http.routers.mosaic-api.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" @@ -352,14 +366,21 @@ services: restart: unless-stopped environment: NODE_ENV: production + PORT: ${WEB_PORT:-3000} NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001} ports: - - "${WEB_PORT:-3000}:3000" + - "${WEB_PORT:-3000}:${WEB_PORT:-3000}" depends_on: api: condition: service_healthy healthcheck: - test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] + test: + [ + "CMD", + "sh", + "-c", + 'node -e "require(''http'').get(''http://localhost:${PORT:-3000}'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"', + ] interval: 30s timeout: 10s retries: 3 @@ -374,7 +395,7 @@ services: - "traefik.http.routers.mosaic-web.rule=Host(`${MOSAIC_WEB_DOMAIN:-mosaic.local}`)" - "traefik.http.routers.mosaic-web.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - "traefik.http.routers.mosaic-web.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.services.mosaic-web.loadbalancer.server.port=3000" + - "traefik.http.services.mosaic-web.loadbalancer.server.port=${WEB_PORT:-3000}" - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-mosaic-public}" # Let's Encrypt (if enabled) - "traefik.http.routers.mosaic-web.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}"