fix error preprod
All checks were successful
Dev CI / Backend — Lint (push) Successful in 10m21s
Dev CI / Frontend — Lint & Type-check (push) Successful in 11m6s
Dev CI / Backend — Unit Tests (push) Successful in 10m8s
Dev CI / Frontend — Unit Tests (push) Successful in 10m36s
Dev CI / Notify Failure (push) Has been skipped
All checks were successful
Dev CI / Backend — Lint (push) Successful in 10m21s
Dev CI / Frontend — Lint & Type-check (push) Successful in 11m6s
Dev CI / Backend — Unit Tests (push) Successful in 10m8s
Dev CI / Frontend — Unit Tests (push) Successful in 10m36s
Dev CI / Notify Failure (push) Has been skipped
This commit is contained in:
parent
8f1afb0098
commit
65abbff7ed
@ -95,11 +95,38 @@ export const rateLimitConfig = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed CORS origins.
|
||||||
|
*
|
||||||
|
* Reads CORS_ORIGIN (comma-separated list — supports several frontend hosts such
|
||||||
|
* as app.* and www.*), falling back to FRONTEND_URL, then to localhost in dev.
|
||||||
|
* With `credentials: true` the browser requires an exact origin echo (no `*`),
|
||||||
|
* so we resolve the request origin against this allow-list per request.
|
||||||
|
*/
|
||||||
|
const allowedOrigins: string[] = (
|
||||||
|
process.env.CORS_ORIGIN ||
|
||||||
|
process.env.FRONTEND_URL ||
|
||||||
|
'http://localhost:3000,http://localhost:3001'
|
||||||
|
)
|
||||||
|
.split(',')
|
||||||
|
.map(origin => origin.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CORS Configuration
|
* CORS Configuration
|
||||||
*/
|
*/
|
||||||
export const corsConfig = {
|
export const corsConfig = {
|
||||||
origin: process.env.FRONTEND_URL || ['http://localhost:3000', 'http://localhost:3001'],
|
origin: (
|
||||||
|
requestOrigin: string | undefined,
|
||||||
|
callback: (err: Error | null, allow?: boolean) => void
|
||||||
|
): void => {
|
||||||
|
// Allow non-browser clients (no Origin header: server-to-server, curl, health checks).
|
||||||
|
if (!requestOrigin || allowedOrigins.includes(requestOrigin)) {
|
||||||
|
callback(null, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback(null, false);
|
||||||
|
},
|
||||||
credentials: true,
|
credentials: true,
|
||||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||||
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'X-CSRF-Token'],
|
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'X-CSRF-Token'],
|
||||||
@ -156,15 +183,22 @@ export const AUTH_COOKIE_NAMES = {
|
|||||||
export function authCookieOptions(options?: { maxAgeMs?: number; httpOnly?: boolean }): {
|
export function authCookieOptions(options?: { maxAgeMs?: number; httpOnly?: boolean }): {
|
||||||
httpOnly: boolean;
|
httpOnly: boolean;
|
||||||
secure: boolean;
|
secure: boolean;
|
||||||
sameSite: 'lax';
|
sameSite: 'lax' | 'strict' | 'none';
|
||||||
path: string;
|
path: string;
|
||||||
domain?: string;
|
domain?: string;
|
||||||
maxAge?: number;
|
maxAge?: number;
|
||||||
} {
|
} {
|
||||||
|
// SameSite must be 'none' when the frontend and the API live on different
|
||||||
|
// sites (cross-origin), otherwise the browser drops the auth cookies set in
|
||||||
|
// the cross-site login XHR response. 'none' REQUIRES Secure (HTTPS).
|
||||||
|
// Configurable via COOKIE_SAMESITE; defaults to 'lax' for same-site setups.
|
||||||
|
const sameSite = (process.env.COOKIE_SAMESITE?.toLowerCase() as 'lax' | 'strict' | 'none') || 'lax';
|
||||||
|
const secure = process.env.NODE_ENV === 'production' || sameSite === 'none';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
httpOnly: options?.httpOnly ?? true,
|
httpOnly: options?.httpOnly ?? true,
|
||||||
secure: process.env.NODE_ENV === 'production',
|
secure,
|
||||||
sameSite: 'lax',
|
sameSite,
|
||||||
path: '/',
|
path: '/',
|
||||||
...(process.env.COOKIE_DOMAIN ? { domain: process.env.COOKIE_DOMAIN } : {}),
|
...(process.env.COOKIE_DOMAIN ? { domain: process.env.COOKIE_DOMAIN } : {}),
|
||||||
...(options?.maxAgeMs ? { maxAge: options.maxAgeMs } : {}),
|
...(options?.maxAgeMs ? { maxAge: options.maxAgeMs } : {}),
|
||||||
|
|||||||
402
infra/preprod/docker-stack.preprod.yml
Normal file
402
infra/preprod/docker-stack.preprod.yml
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# PostgreSQL Database
|
||||||
|
xpeditis-db:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
volumes:
|
||||||
|
- xpeditis_db_data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: xpeditis_preprod
|
||||||
|
POSTGRES_USER: xpeditis
|
||||||
|
POSTGRES_PASSWORD: 9Lc3M9qoPBeHLKHDXGUf1
|
||||||
|
PGDATA: /var/lib/postgresql/data/pgdata
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U xpeditis"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- xpeditis_internal
|
||||||
|
|
||||||
|
# Redis Cache
|
||||||
|
xpeditis-redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
command: redis-server --requirepass hXiy5GMPswMtxMZujjS2O --appendonly yes
|
||||||
|
volumes:
|
||||||
|
- xpeditis_redis_data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "-a", "hXiy5GMPswMtxMZujjS2O", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- xpeditis_internal
|
||||||
|
|
||||||
|
# MinIO S3 Storage
|
||||||
|
xpeditis-minio:
|
||||||
|
image: minio/minio:latest
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
volumes:
|
||||||
|
- xpeditis_minio_data:/data
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: minioadmin_preprod_CHANGE_ME
|
||||||
|
MINIO_ROOT_PASSWORD: RBJfD0QVXC5JDfAHCwdUW
|
||||||
|
networks:
|
||||||
|
- xpeditis_internal
|
||||||
|
- traefik_network
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=traefik_network"
|
||||||
|
|
||||||
|
# MinIO API (S3) - HTTPS
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api.rule=Host(`s3.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api.tls=true"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api.service=xpeditis-minio-api"
|
||||||
|
- "traefik.http.services.xpeditis-minio-api.loadbalancer.server.port=9000"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api.middlewares=xpeditis-minio-api-headers"
|
||||||
|
|
||||||
|
# MinIO API Headers
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-api-headers.headers.customRequestHeaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-api-headers.headers.customRequestHeaders.X-Forwarded-For="
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-api-headers.headers.customRequestHeaders.X-Real-IP="
|
||||||
|
|
||||||
|
# MinIO API - HTTP → HTTPS Redirect
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api-http.rule=Host(`s3.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api-http.entrypoints=web"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api-http.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api-http.middlewares=xpeditis-minio-api-redirect"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-api-http.service=xpeditis-minio-api"
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-api-redirect.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-api-redirect.redirectscheme.permanent=true"
|
||||||
|
|
||||||
|
# MinIO Console - HTTPS
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console.rule=Host(`minio.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console.tls=true"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console.service=xpeditis-minio-console"
|
||||||
|
- "traefik.http.services.xpeditis-minio-console.loadbalancer.server.port=9001"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console.middlewares=xpeditis-minio-console-headers"
|
||||||
|
|
||||||
|
# MinIO Console Headers
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-console-headers.headers.customRequestHeaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-console-headers.headers.customRequestHeaders.X-Forwarded-For="
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-console-headers.headers.customRequestHeaders.X-Real-IP="
|
||||||
|
|
||||||
|
# MinIO Console - HTTP → HTTPS Redirect
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console-http.rule=Host(`minio.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console-http.entrypoints=web"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console-http.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console-http.middlewares=xpeditis-minio-console-redirect"
|
||||||
|
- "traefik.http.routers.xpeditis-minio-console-http.service=xpeditis-minio-console"
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-console-redirect.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-minio-console-redirect.redirectscheme.permanent=true"
|
||||||
|
|
||||||
|
# Backend API (NestJS)
|
||||||
|
xpeditis-backend:
|
||||||
|
image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod
|
||||||
|
healthcheck:
|
||||||
|
disable: true
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
depends_on:
|
||||||
|
- xpeditis-db
|
||||||
|
- xpeditis-redis
|
||||||
|
labels:
|
||||||
|
- "logging=promtail"
|
||||||
|
- "logging.service=backend"
|
||||||
|
- "traefik.enable=true"
|
||||||
|
|
||||||
|
# Backend API - HTTPS
|
||||||
|
- "traefik.http.routers.xpeditis-api.rule=Host(`api.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-api.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.xpeditis-api.tls=true"
|
||||||
|
- "traefik.http.routers.xpeditis-api.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.xpeditis-api.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-api.service=xpeditis-api"
|
||||||
|
- "traefik.http.services.xpeditis-api.loadbalancer.server.port=4000"
|
||||||
|
- "traefik.http.routers.xpeditis-api.middlewares=xpeditis-api-headers"
|
||||||
|
|
||||||
|
# Backend API Headers
|
||||||
|
- "traefik.http.middlewares.xpeditis-api-headers.headers.customRequestHeaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-api-headers.headers.customRequestHeaders.X-Forwarded-For="
|
||||||
|
- "traefik.http.middlewares.xpeditis-api-headers.headers.customRequestHeaders.X-Real-IP="
|
||||||
|
|
||||||
|
# Backend API - HTTP → HTTPS Redirect
|
||||||
|
- "traefik.http.routers.xpeditis-api-http.rule=Host(`api.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-api-http.entrypoints=web"
|
||||||
|
- "traefik.http.routers.xpeditis-api-http.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-api-http.middlewares=xpeditis-api-redirect"
|
||||||
|
- "traefik.http.routers.xpeditis-api-http.service=xpeditis-api"
|
||||||
|
- "traefik.http.middlewares.xpeditis-api-redirect.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-api-redirect.redirectscheme.permanent=true"
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: "4000"
|
||||||
|
API_PREFIX: api/v1
|
||||||
|
LOG_FORMAT: json
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DATABASE_HOST: xpeditis-db
|
||||||
|
DATABASE_PORT: "5432"
|
||||||
|
DATABASE_USER: xpeditis
|
||||||
|
DATABASE_PASSWORD: 9Lc3M9qoPBeHLKHDXGUf1
|
||||||
|
DATABASE_NAME: xpeditis_preprod
|
||||||
|
DATABASE_SYNC: "false"
|
||||||
|
DATABASE_LOGGING: "false"
|
||||||
|
|
||||||
|
# Email (SMTP)
|
||||||
|
# SMTP (Brevo)
|
||||||
|
SMTP_HOST: smtp-relay.brevo.com
|
||||||
|
SMTP_PORT: 587
|
||||||
|
SMTP_USER: 9637ef001@smtp-brevo.com
|
||||||
|
SMTP_PASS: xsmtpsib-8d965bda028cd63bed868a119f9e0330485204bf9f4e1f92a3a11c8e61000722-xUYUSrGGxhMqlUcu
|
||||||
|
SMTP_SECURE: "false"
|
||||||
|
SMTP_FROM: noreply@xpeditis.com
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
REDIS_HOST: xpeditis-redis
|
||||||
|
REDIS_PORT: "6379"
|
||||||
|
REDIS_PASSWORD: hXiy5GMPswMtxMZujjS2O
|
||||||
|
REDIS_DB: "0"
|
||||||
|
|
||||||
|
# JWT
|
||||||
|
JWT_SECRET: 4C4tQC8qym/evv4zI5DaUE1yy3kilEnm6lApOGD0GgNBLA0BLm2tVyUr1Lr0mTnV
|
||||||
|
JWT_ACCESS_EXPIRATION: 15m
|
||||||
|
JWT_REFRESH_EXPIRATION: 7d
|
||||||
|
|
||||||
|
# S3/MinIO
|
||||||
|
AWS_S3_ENDPOINT: http://xpeditis-minio:9000
|
||||||
|
AWS_REGION: us-east-1
|
||||||
|
AWS_ACCESS_KEY_ID: minioadmin_preprod_CHANGE_ME
|
||||||
|
AWS_SECRET_ACCESS_KEY: RBJfD0QVXC5JDfAHCwdUW
|
||||||
|
AWS_S3_BUCKET: xpeditis-csv-rates
|
||||||
|
|
||||||
|
# CORS
|
||||||
|
CORS_ORIGIN: https://app.preprod.xpeditis.com,https://www.preprod.xpeditis.com,https://api.preprod.xpeditis.com
|
||||||
|
|
||||||
|
# App URLs
|
||||||
|
APP_URL: https://app.preprod.xpeditis.com
|
||||||
|
FRONTEND_URL: https://app.preprod.xpeditis.com
|
||||||
|
API_URL: https://api.preprod.xpeditis.com
|
||||||
|
|
||||||
|
# ─── Auth cookies (FIX login redirect) ──────────────────────────────────
|
||||||
|
# The httpOnly auth cookies (accessToken / refreshToken / xpeditis_session)
|
||||||
|
# MUST be shared across the parent domain so that:
|
||||||
|
# 1. the API (api.preprod.xpeditis.com) can set them, AND
|
||||||
|
# 2. the Next.js middleware running on the FRONTEND
|
||||||
|
# (app.preprod.xpeditis.com) can read `accessToken` to authorize routes.
|
||||||
|
# Without this, login succeeds but the middleware never sees the cookie and
|
||||||
|
# bounces the user back to /login instead of /dashboard.
|
||||||
|
# Leading dot => valid for every *.preprod.xpeditis.com subdomain.
|
||||||
|
COOKIE_DOMAIN: .preprod.xpeditis.com
|
||||||
|
# app & api are same-site (same xpeditis.com), so 'lax' is correct & safest.
|
||||||
|
# Only switch to 'none' (forces Secure) if front/back ever become cross-site.
|
||||||
|
COOKIE_SAMESITE: lax
|
||||||
|
|
||||||
|
# Security
|
||||||
|
BCRYPT_ROUNDS: "10"
|
||||||
|
SESSION_TIMEOUT_MS: "7200000"
|
||||||
|
|
||||||
|
# Rate Limiting
|
||||||
|
RATE_LIMIT_TTL: "60"
|
||||||
|
RATE_LIMIT_MAX: "100"
|
||||||
|
|
||||||
|
# Stripe (Subscriptions & Payments)
|
||||||
|
STRIPE_SECRET_KEY: "sk_test_51R8p8R4atifoBlu1U9sMJh3rkQbO1G1xeguwFMQYMIMeaLNrTX7YFO5Ovu3P1VfbwcOoEmiy6I0UWi4DThNNzHG100YF75TnJr"
|
||||||
|
STRIPE_WEBHOOK_SECRET: "whsec_0BLJx3J2LXITCq1cgp9ArzBuMG1W3QMj"
|
||||||
|
|
||||||
|
# Stripe Price IDs (from Stripe Dashboard)
|
||||||
|
STRIPE_STARTER_MONTHLY_PRICE_ID: "price_1SrIrR4atifoBlu1ZplPEdkD"
|
||||||
|
STRIPE_STARTER_YEARLY_PRICE_ID: "price_1SrIsm4atifoBlu1ycMAXVGj"
|
||||||
|
STRIPE_PRO_MONTHLY_PRICE_ID: "price_1SrIs14atifoBlu1BDTlsbK7"
|
||||||
|
STRIPE_PRO_YEARLY_PRICE_ID: "price_1SrItG4atifoBlu1CiSKold0"
|
||||||
|
STRIPE_ENTERPRISE_MONTHLY_PRICE_ID: "price_1SrNj94atifoBlu1F6axOXrR"
|
||||||
|
STRIPE_ENTERPRISE_YEARLY_PRICE_ID: "price_1SrNiA4atifoBlu11RJD0ocG"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- xpeditis_internal
|
||||||
|
- traefik_network
|
||||||
|
|
||||||
|
# Frontend (Next.js)
|
||||||
|
xpeditis-frontend:
|
||||||
|
image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod
|
||||||
|
healthcheck:
|
||||||
|
disable: true
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
labels:
|
||||||
|
- "logging=promtail"
|
||||||
|
- "logging.service=frontend"
|
||||||
|
- "traefik.enable=true"
|
||||||
|
|
||||||
|
# Frontend - HTTPS
|
||||||
|
- "traefik.http.routers.xpeditis-app.rule=Host(`app.preprod.xpeditis.com`) || Host(`www.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-app.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.xpeditis-app.tls=true"
|
||||||
|
- "traefik.http.routers.xpeditis-app.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.xpeditis-app.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-app.service=xpeditis-app"
|
||||||
|
- "traefik.http.services.xpeditis-app.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.http.routers.xpeditis-app.middlewares=xpeditis-app-headers"
|
||||||
|
|
||||||
|
# Frontend Headers
|
||||||
|
- "traefik.http.middlewares.xpeditis-app-headers.headers.customRequestHeaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-app-headers.headers.customRequestHeaders.X-Forwarded-For="
|
||||||
|
- "traefik.http.middlewares.xpeditis-app-headers.headers.customRequestHeaders.X-Real-IP="
|
||||||
|
|
||||||
|
# Frontend - HTTP → HTTPS Redirect
|
||||||
|
- "traefik.http.routers.xpeditis-app-http.rule=Host(`app.preprod.xpeditis.com`) || Host(`www.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-app-http.entrypoints=web"
|
||||||
|
- "traefik.http.routers.xpeditis-app-http.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-app-http.middlewares=xpeditis-app-redirect"
|
||||||
|
- "traefik.http.routers.xpeditis-app-http.service=xpeditis-app"
|
||||||
|
- "traefik.http.middlewares.xpeditis-app-redirect.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-app-redirect.redirectscheme.permanent=true"
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
NEXT_PUBLIC_API_URL: https://api.preprod.xpeditis.com
|
||||||
|
NEXT_PUBLIC_WS_URL: wss://api.preprod.xpeditis.com
|
||||||
|
networks:
|
||||||
|
- traefik_network
|
||||||
|
|
||||||
|
# ─── Logging Stack ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Loki - Log aggregation
|
||||||
|
xpeditis-loki:
|
||||||
|
image: grafana/loki:3.0.0
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
volumes:
|
||||||
|
- xpeditis_loki_data:/loki
|
||||||
|
configs:
|
||||||
|
- source: loki_config
|
||||||
|
target: /etc/loki/local-config.yaml
|
||||||
|
command: -config.file=/etc/loki/local-config.yaml
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD-SHELL', 'wget --quiet --tries=1 --spider http://localhost:3100/ready || exit 1']
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- xpeditis_internal
|
||||||
|
|
||||||
|
# Promtail - Log collector (scrapes Docker container logs)
|
||||||
|
xpeditis-promtail:
|
||||||
|
image: grafana/promtail:3.0.0
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
configs:
|
||||||
|
- source: promtail_config
|
||||||
|
target: /etc/promtail/config.yml
|
||||||
|
command: -config.file=/etc/promtail/config.yml
|
||||||
|
depends_on:
|
||||||
|
- xpeditis-loki
|
||||||
|
networks:
|
||||||
|
- xpeditis_internal
|
||||||
|
|
||||||
|
# Grafana - Log & metrics dashboards
|
||||||
|
xpeditis-grafana:
|
||||||
|
image: grafana/grafana:11.0.0
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
environment:
|
||||||
|
GF_SECURITY_ADMIN_USER: "David"
|
||||||
|
GF_SECURITY_ADMIN_PASSWORD: "G9N]71dT80l"
|
||||||
|
GF_USERS_ALLOW_SIGN_UP: 'false'
|
||||||
|
GF_AUTH_ANONYMOUS_ENABLED: 'false'
|
||||||
|
GF_SERVER_ROOT_URL: https://grafana.preprod.xpeditis.com
|
||||||
|
GF_ANALYTICS_REPORTING_ENABLED: 'false'
|
||||||
|
GF_ANALYTICS_CHECK_FOR_UPDATES: 'false'
|
||||||
|
volumes:
|
||||||
|
- xpeditis_grafana_data:/var/lib/grafana
|
||||||
|
depends_on:
|
||||||
|
- xpeditis-loki
|
||||||
|
networks:
|
||||||
|
- xpeditis_internal
|
||||||
|
- traefik_network
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=traefik_network"
|
||||||
|
|
||||||
|
# Grafana - HTTPS
|
||||||
|
- "traefik.http.routers.xpeditis-grafana.rule=Host(`grafana.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana.tls=true"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana.service=xpeditis-grafana"
|
||||||
|
- "traefik.http.services.xpeditis-grafana.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana.middlewares=xpeditis-grafana-headers"
|
||||||
|
|
||||||
|
# Grafana Headers
|
||||||
|
- "traefik.http.middlewares.xpeditis-grafana-headers.headers.customRequestHeaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-grafana-headers.headers.customRequestHeaders.X-Forwarded-For="
|
||||||
|
- "traefik.http.middlewares.xpeditis-grafana-headers.headers.customRequestHeaders.X-Real-IP="
|
||||||
|
|
||||||
|
# Grafana - HTTP → HTTPS Redirect
|
||||||
|
- "traefik.http.routers.xpeditis-grafana-http.rule=Host(`grafana.preprod.xpeditis.com`)"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana-http.entrypoints=web"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana-http.priority=50"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana-http.middlewares=xpeditis-grafana-redirect"
|
||||||
|
- "traefik.http.routers.xpeditis-grafana-http.service=xpeditis-grafana"
|
||||||
|
- "traefik.http.middlewares.xpeditis-grafana-redirect.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.middlewares.xpeditis-grafana-redirect.redirectscheme.permanent=true"
|
||||||
|
|
||||||
|
# Log Exporter - HTTP API to push structured logs to Loki (internal only)
|
||||||
|
xpeditis-log-exporter:
|
||||||
|
image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-log-exporter:preprod
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
environment:
|
||||||
|
PORT: "3200"
|
||||||
|
LOKI_URL: http://xpeditis-loki:3100
|
||||||
|
# LOG_EXPORTER_API_KEY: your-secret-key-here
|
||||||
|
depends_on:
|
||||||
|
- xpeditis-loki
|
||||||
|
networks:
|
||||||
|
- xpeditis_internal
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
xpeditis_db_data:
|
||||||
|
xpeditis_redis_data:
|
||||||
|
xpeditis_minio_data:
|
||||||
|
xpeditis_loki_data:
|
||||||
|
driver: local
|
||||||
|
xpeditis_grafana_data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
traefik_network:
|
||||||
|
external: true
|
||||||
|
xpeditis_internal:
|
||||||
|
driver: overlay
|
||||||
|
internal: true
|
||||||
|
|
||||||
|
configs:
|
||||||
|
loki_config:
|
||||||
|
external: true
|
||||||
|
promtail_config:
|
||||||
|
external: true
|
||||||
Loading…
Reference in New Issue
Block a user