From 3a7c7b09082fa449e340b30ea3a2623822a4f889 Mon Sep 17 00:00:00 2001 From: MMD Date: Sun, 6 Sep 2026 20:49:17 +0330 Subject: [PATCH] =?UTF-8?q?=D8=B2=DB=8C=D8=B1=D8=B3=D8=A7=D8=AE=D8=AA:=20T?= =?UTF-8?q?raefik=20=D8=A8=D9=87=E2=80=8C=D8=AC=D8=A7=DB=8C=20nginx=20?= =?UTF-8?q?=D8=A8=D9=87=E2=80=8C=D8=B9=D9=86=D9=88=D8=A7=D9=86=20=D9=86?= =?UTF-8?q?=D9=82=D8=B7=D9=87=20=D9=88=D8=B1=D9=88=D8=AF=20=D9=88=D8=A7?= =?UTF-8?q?=D8=AD=D8=AF=20+=20=D8=B3=D8=B1=D9=88=20MinIO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - سرویس traefik:v3 روی پورت ۵۱۷۳ (پورت هاست) — تنها نقطه ورود استک: / → frontend (فایل‌های استاتیک SPA) /api → backend:8000 /media → MinIO:9000 با rewrite به باکت aramesh-media مسیریابی با Docker labels در docker-compose.yml - حذف کامل nginx: Caddy فقط فایل‌های استاتیک را سرو می‌کند (fallback به index.html برای SPA، کش یک‌ساله immutable برای assets/) - سرویس minio + minio-setup (ساخت خودکار باکت و دسترسی عمومی خواندن — یک‌بار در اولین اجرا)؛ کنسول MinIO روی پورت ۹۰۰۱ - وابستگی backend به سلامت db و minio - vite dev: پروکسی /api و /media به Traefik برای هم‌مبدأ بودن در توسعه --- docker-compose.yml | 84 +++++++++++++++++++++++++++++++++++++++-- frontend/Caddyfile | 12 ++++++ frontend/Dockerfile | 9 +++-- frontend/nginx.conf | 28 -------------- frontend/vite.config.ts | 7 ++++ 5 files changed, 104 insertions(+), 36 deletions(-) create mode 100644 frontend/Caddyfile delete mode 100644 frontend/nginx.conf diff --git a/docker-compose.yml b/docker-compose.yml index c6468be..ccec156 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,17 @@ services: + # نقطه ورود واحد — مسیریابی / (سایت استاتیک)، /api (بک‌اند) و /media (MinIO) + traefik: + image: traefik:v3 + restart: unless-stopped + command: + - --providers.docker=true + - --providers.docker.exposedbydefault=false + - --entrypoints.web.address=:80 + ports: + - "5173:80" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + db: image: postgres:17-alpine restart: unless-stopped @@ -14,6 +27,51 @@ services: timeout: 5s retries: 12 + minio: + image: minio/minio:latest + restart: unless-stopped + command: server /data --console-address ":9001" + environment: + MINIO_ROOT_USER: aramesh + MINIO_ROOT_PASSWORD: aramesh-minio-secret + volumes: + - minio_data:/data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 5s + timeout: 5s + retries: 12 + ports: + - "9001:9001" # کنسول MinIO + labels: + - traefik.enable=true + - traefik.http.routers.media.rule=PathPrefix(`/media`) + - traefik.http.routers.media.entrypoints=web + - traefik.http.routers.media.priority=100 + - traefik.http.routers.media.middlewares=media-rewrite + - traefik.http.middlewares.media-rewrite.replacepathregex.regex=^/media/(.*) + - traefik.http.middlewares.media-rewrite.replacepathregex.replacement=/aramesh-media/$$1 + - traefik.http.services.media.loadbalancer.server.port=9000 + + # یک‌بار اجرا می‌شود: ساخت باکت و بازگذاشتن خواندن عمومی برای سرو تصاویر + minio-setup: + image: minio/mc:latest + depends_on: + minio: + condition: service_healthy + environment: + MINIO_ROOT_USER: aramesh + MINIO_ROOT_PASSWORD: aramesh-minio-secret + MINIO_BUCKET: aramesh-media + restart: "no" + entrypoint: > + /bin/sh -c " + mc alias set local http://minio:9000 $$MINIO_ROOT_USER $$MINIO_ROOT_PASSWORD && + mc mb --ignore-existing local/$$MINIO_BUCKET && + mc anonymous set download local/$$MINIO_BUCKET && + echo 'minio-setup: bucket ready' + " + backend: build: ./backend restart: unless-stopped @@ -23,12 +81,24 @@ services: CORS_ORIGINS: '["http://localhost:5173","http://127.0.0.1:5173"]' ADMIN_USERNAME: admin ADMIN_PASSWORD: aramesh123 + S3_ENDPOINT: http://minio:9000 + S3_ACCESS_KEY: aramesh + S3_SECRET_KEY: aramesh-minio-secret + S3_BUCKET: aramesh-media + MEDIA_PUBLIC_BASE: /media depends_on: db: condition: service_healthy - ports: - - "8000:8000" + minio: + condition: service_healthy + labels: + - traefik.enable=true + - traefik.http.routers.api.rule=PathPrefix(`/api`) + - traefik.http.routers.api.entrypoints=web + - traefik.http.routers.api.priority=100 + - traefik.http.services.api.loadbalancer.server.port=8000 + # فقط سرو فایل‌های استاتیک SPA — همه مسیریابی‌ها روی Traefik است frontend: build: context: ./frontend @@ -37,8 +107,14 @@ services: restart: unless-stopped depends_on: - backend - ports: - - "5173:80" + - minio + labels: + - traefik.enable=true + - traefik.http.routers.web.rule=PathPrefix(`/`) + - traefik.http.routers.web.entrypoints=web + - traefik.http.routers.web.priority=1 + - traefik.http.services.web.loadbalancer.server.port=80 volumes: db_data: + minio_data: diff --git a/frontend/Caddyfile b/frontend/Caddyfile new file mode 100644 index 0000000..71db35c --- /dev/null +++ b/frontend/Caddyfile @@ -0,0 +1,12 @@ +:80 { + root * /srv + encode gzip + + # مسیریابی SPA — مسیرهای ناشناخته به index.html برمی‌گردند + try_files {path} /index.html + file_server + + # کش بلندمدت برای فایل‌های هش‌دار بیلد + @assets path /assets/* + header @assets Cache-Control "public, immutable, max-age=31536000" +} diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 846d933..38973e8 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -8,16 +8,17 @@ RUN npm ci COPY . . -# آدرس API در زمان بیلد؛ پیش‌فرض خالی یعنی درخواست‌های نسبی (/api) که nginx آن‌ها را به بک‌اند پروکسی می‌کند +# آدرس API در زمان بیلد؛ پیش‌فرض خالی یعنی درخواست‌های نسبی (/api) که Traefik مسیریابی می‌کند ARG VITE_API_URL="" ENV VITE_API_URL=$VITE_API_URL RUN npm run build # ---------- مرحله سرو ---------- -FROM nginx:alpine +# Caddy فقط فایل‌های استاتیک SPA را سرو می‌کند؛ مسیریابی /api و /media روی Traefik است +FROM caddy:2-alpine -COPY --from=build /app/dist /usr/share/nginx/html -COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY Caddyfile /etc/caddy/Caddyfile +COPY --from=build /app/dist /srv EXPOSE 80 diff --git a/frontend/nginx.conf b/frontend/nginx.conf deleted file mode 100644 index 6064268..0000000 --- a/frontend/nginx.conf +++ /dev/null @@ -1,28 +0,0 @@ -server { - listen 80; - server_name _; - - root /usr/share/nginx/html; - index index.html; - - # مسیریابی SPA — همه مسیرها به index.html برمی‌گردند - location / { - try_files $uri $uri/ /index.html; - } - - # پروکسی درخواست‌های API به سرویس بک‌اند - location /api/ { - proxy_pass http://backend:8000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - # کش استاتیک - location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff2?)$ { - expires 30d; - add_header Cache-Control "public, immutable"; - try_files $uri =404; - } -} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 5a33944..b995e05 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -4,4 +4,11 @@ import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], + server: { + // در حالت توسعه، /api و /media به Traefik پروکسی می‌شوند (پورت ۵۱۷۳ روی هاست) + proxy: { + '/api': 'http://localhost:5173', + '/media': 'http://localhost:5173', + }, + }, })