From d81565ca711cc9ff0976f08cb8fdae2b2e0a38ae Mon Sep 17 00:00:00 2001 From: root Date: Sun, 17 May 2026 15:36:17 -0400 Subject: [PATCH] fix prod --- DOCKER.md | 10 ++-- docker-compose.production.yml | 99 +++++++++++++++++++++++------------ 2 files changed, 69 insertions(+), 40 deletions(-) diff --git a/DOCKER.md b/DOCKER.md index dba8b1b..26ed2f5 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -112,11 +112,8 @@ Add an A record for every subdomain to your server's public IP before deploying | Subdomain | Service | |---|---| -| `rentaldrivego.ma` | public site | -| `app.rentaldrivego.ma` | marketplace | +| `rentaldrivego.ma` | marketplace and public site | | `api.rentaldrivego.ma` | API | -| `dashboard.rentaldrivego.ma` | dashboard | -| `admin.rentaldrivego.ma` | admin panel | | `pgmanage.rentaldrivego.ma` | pgManage (DB admin) | #### 2. Install Docker and clone the repo @@ -154,7 +151,7 @@ Open `.env.docker.production` and fill in every value. The minimum required secr Production now derives `DATABASE_URL` inside the app container from `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` when `DATABASE_URL_FROM_POSTGRES=true`. That avoids Prisma auth failures when the database password contains reserved URL characters such as `@`, `:`, or `/`. -The example file uses `rentaldrivego.ma` for the public site and `app.rentaldrivego.ma` for the marketplace. Adjust them only if you use different hostnames. +The example file uses `rentaldrivego.ma` for the marketplace and public site. The dashboard and admin panel are routed under that same host at `/dashboard` and `/admin`. #### 5. Start Traefik @@ -172,8 +169,7 @@ npm run docker:prod:up Docker will: 1. Build the monorepo image -2. Run database migrations (`migrate` service) -3. Start all app services (api, marketplace, dashboard, admin, public-site, pgmanage) +2. Start all app services (`api`, `marketplace`, `dashboard`, `admin`, `pgmanage`) Traefik automatically picks up the containers and provisions TLS certificates. Services are live at their `https://` URLs within ~30 seconds. diff --git a/docker-compose.production.yml b/docker-compose.production.yml index e162ff1..0963970 100644 --- a/docker-compose.production.yml +++ b/docker-compose.production.yml @@ -55,13 +55,13 @@ services: restart: unless-stopped labels: - traefik.enable=true - - traefik.http.routers.api.rule=Host(`api.rentaldrivego.ma`) + - traefik.http.routers.api.rule=Host(`${API_DOMAIN}`) - traefik.http.routers.api.entrypoints=websecure - traefik.http.routers.api.tls=true - traefik.http.routers.api.tls.certresolver=letsencrypt - traefik.http.services.api.loadbalancer.server.port=4000 - frontend: + marketplace: build: context: . dockerfile: Dockerfile.production @@ -70,14 +70,7 @@ services: NEXT_PUBLIC_MARKETPLACE_URL: ${NEXT_PUBLIC_MARKETPLACE_URL} NEXT_PUBLIC_DASHBOARD_URL: ${NEXT_PUBLIC_DASHBOARD_URL} NEXT_PUBLIC_ADMIN_URL: ${NEXT_PUBLIC_ADMIN_URL} - command: - - bash - - -c - - | - npm run start --workspace @rentaldrivego/marketplace & - npm run start --workspace @rentaldrivego/dashboard & - npm run start --workspace @rentaldrivego/admin & - wait -n + command: ["npm", "run", "start", "--workspace", "@rentaldrivego/marketplace"] networks: - internal - traefik-proxy @@ -88,29 +81,69 @@ services: restart: unless-stopped labels: - traefik.enable=true - # /dashboard and /admin route to their respective ports (higher priority) - - traefik.http.routers.frontend-dashboard.rule=(Host(`${PUBLIC_SITE_DOMAIN}`) || Host(`www.${PUBLIC_SITE_DOMAIN}`)) && PathPrefix(`/dashboard`) - - traefik.http.routers.frontend-dashboard.entrypoints=websecure - - traefik.http.routers.frontend-dashboard.tls=true - - traefik.http.routers.frontend-dashboard.tls.certresolver=letsencrypt - - traefik.http.routers.frontend-dashboard.service=frontend-dashboard-svc - - traefik.http.routers.frontend-dashboard.priority=20 - - traefik.http.services.frontend-dashboard-svc.loadbalancer.server.port=3001 - - traefik.http.routers.frontend-admin.rule=(Host(`${PUBLIC_SITE_DOMAIN}`) || Host(`www.${PUBLIC_SITE_DOMAIN}`)) && PathPrefix(`/admin`) - - traefik.http.routers.frontend-admin.entrypoints=websecure - - traefik.http.routers.frontend-admin.tls=true - - traefik.http.routers.frontend-admin.tls.certresolver=letsencrypt - - traefik.http.routers.frontend-admin.service=frontend-admin-svc - - traefik.http.routers.frontend-admin.priority=20 - - traefik.http.services.frontend-admin-svc.loadbalancer.server.port=3002 - # marketplace catches everything else (root and all other paths) - - traefik.http.routers.frontend-marketplace.rule=Host(`${PUBLIC_SITE_DOMAIN}`) || Host(`www.${PUBLIC_SITE_DOMAIN}`) - - traefik.http.routers.frontend-marketplace.entrypoints=websecure - - traefik.http.routers.frontend-marketplace.tls=true - - traefik.http.routers.frontend-marketplace.tls.certresolver=letsencrypt - - traefik.http.routers.frontend-marketplace.service=frontend-marketplace-svc - - traefik.http.routers.frontend-marketplace.priority=10 - - traefik.http.services.frontend-marketplace-svc.loadbalancer.server.port=3000 + - traefik.http.routers.marketplace.rule=Host(`${PUBLIC_SITE_DOMAIN}`) || Host(`www.${PUBLIC_SITE_DOMAIN}`) + - traefik.http.routers.marketplace.entrypoints=websecure + - traefik.http.routers.marketplace.tls=true + - traefik.http.routers.marketplace.tls.certresolver=letsencrypt + - traefik.http.routers.marketplace.service=marketplace-svc + - traefik.http.routers.marketplace.priority=10 + - traefik.http.services.marketplace-svc.loadbalancer.server.port=3000 + + dashboard: + build: + context: . + dockerfile: Dockerfile.production + args: + NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL} + NEXT_PUBLIC_MARKETPLACE_URL: ${NEXT_PUBLIC_MARKETPLACE_URL} + NEXT_PUBLIC_DASHBOARD_URL: ${NEXT_PUBLIC_DASHBOARD_URL} + NEXT_PUBLIC_ADMIN_URL: ${NEXT_PUBLIC_ADMIN_URL} + command: ["npm", "run", "start", "--workspace", "@rentaldrivego/dashboard"] + networks: + - internal + - traefik-proxy + depends_on: + - api + env_file: + - .env.docker.production + restart: unless-stopped + labels: + - traefik.enable=true + - traefik.http.routers.dashboard.rule=(Host(`${PUBLIC_SITE_DOMAIN}`) || Host(`www.${PUBLIC_SITE_DOMAIN}`)) && PathPrefix(`/dashboard`) + - traefik.http.routers.dashboard.entrypoints=websecure + - traefik.http.routers.dashboard.tls=true + - traefik.http.routers.dashboard.tls.certresolver=letsencrypt + - traefik.http.routers.dashboard.service=dashboard-svc + - traefik.http.routers.dashboard.priority=20 + - traefik.http.services.dashboard-svc.loadbalancer.server.port=3001 + + admin: + build: + context: . + dockerfile: Dockerfile.production + args: + NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL} + NEXT_PUBLIC_MARKETPLACE_URL: ${NEXT_PUBLIC_MARKETPLACE_URL} + NEXT_PUBLIC_DASHBOARD_URL: ${NEXT_PUBLIC_DASHBOARD_URL} + NEXT_PUBLIC_ADMIN_URL: ${NEXT_PUBLIC_ADMIN_URL} + command: ["npm", "run", "start", "--workspace", "@rentaldrivego/admin"] + networks: + - internal + - traefik-proxy + depends_on: + - api + env_file: + - .env.docker.production + restart: unless-stopped + labels: + - traefik.enable=true + - traefik.http.routers.admin.rule=(Host(`${PUBLIC_SITE_DOMAIN}`) || Host(`www.${PUBLIC_SITE_DOMAIN}`)) && PathPrefix(`/admin`) + - traefik.http.routers.admin.entrypoints=websecure + - traefik.http.routers.admin.tls=true + - traefik.http.routers.admin.tls.certresolver=letsencrypt + - traefik.http.routers.admin.service=admin-svc + - traefik.http.routers.admin.priority=20 + - traefik.http.services.admin-svc.loadbalancer.server.port=3002 pgmanage: image: cmdpromptinc/pgmanage-enterprise:latest