زیرساخت: رمزهای اجباری از .env + لایه تولید با TLS + healthcheck و مسیر سئوی Traefik + پشتیبان‌گیری

- docker-compose.yml همه مقادیر محرمانه را با ${VAR:?} از .env می‌خواند — بدون .env استک بالا نمی‌آید
- docker-compose.prod.yml: ورودی 443 + ریدایرکت HTTP به HTTPS + گواهی Let's Encrypt و قواعد Host برای همه روترها
- healthcheck بک‌اند (api/health) و فرانت (wget) + سوار کردن frontend/dist در بک‌اند برای تزریق متا + روتر سئو (robots/sitemap/blog/projects) با اولویت 50
- سرویس mc با پروفایل tools + scripts/backup.sh (pg_dump + آینه MinIO با نگهداری ۱۴ روزه)
- .env.example ریشه + بروزرسانی READMEها
This commit is contained in:
MMD
2026-09-07 04:26:18 +03:30
parent b31124e1e4
commit 2ad3ad7367
6 changed files with 237 additions and 22 deletions
+51 -14
View File
@@ -1,3 +1,7 @@
# مقادیر محرمانه از فایل .env ریشه خوانده می‌شوند — از .env.example کپی کنید:
# cp .env.example .env
# برای انتشار با TLS، روی این فایل docker-compose.prod.yml را هم سوار کنید (README).
services:
# نقطه ورود واحد — مسیریابی / (سایت استاتیک)، /api (بک‌اند) و /media (MinIO)
traefik:
@@ -8,7 +12,7 @@ services:
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
ports:
- "5173:80"
- "${TRAEFIK_HTTP_PORT:-5173}:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
@@ -17,7 +21,7 @@ services:
restart: unless-stopped
environment:
POSTGRES_USER: aramesh
POSTGRES_PASSWORD: aramesh
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD را در .env تنظیم کنید}
POSTGRES_DB: arameshplaza
volumes:
- db_data:/var/lib/postgresql/data
@@ -32,8 +36,8 @@ services:
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: aramesh
MINIO_ROOT_PASSWORD: aramesh-minio-secret
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-aramesh}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD را در .env تنظیم کنید}
volumes:
- minio_data:/data
healthcheck:
@@ -42,7 +46,7 @@ services:
timeout: 5s
retries: 12
ports:
- "9001:9001" # کنسول MinIO
- "9001:9001" # کنسول MinIO — در محیط واقعی با فایروال ببندید
labels:
- traefik.enable=true
- traefik.http.routers.media.rule=PathPrefix(`/media`)
@@ -60,8 +64,8 @@ services:
minio:
condition: service_healthy
environment:
MINIO_ROOT_USER: aramesh
MINIO_ROOT_PASSWORD: aramesh-minio-secret
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-aramesh}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD را در .env تنظیم کنید}
MINIO_BUCKET: aramesh-media
restart: "no"
entrypoint: >
@@ -76,27 +80,44 @@ services:
build: ./backend
restart: unless-stopped
environment:
DATABASE_URL: postgresql+psycopg://aramesh:aramesh@db:5432/arameshplaza
SECRET_KEY: change-me-to-a-long-random-string
CORS_ORIGINS: '["http://localhost:5173","http://127.0.0.1:5173"]'
ADMIN_USERNAME: admin
ADMIN_PASSWORD: aramesh123
DATABASE_URL: postgresql+psycopg://aramesh:${POSTGRES_PASSWORD}@db:5432/arameshplaza
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY را در .env تنظیم کنید}
CORS_ORIGINS: ${CORS_ORIGINS:-'["http://localhost:5173","http://127.0.0.1:5173"]'}
ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}
ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD را در .env تنظیم کنید}
S3_ENDPOINT: http://minio:9000
S3_ACCESS_KEY: aramesh
S3_SECRET_KEY: aramesh-minio-secret
S3_ACCESS_KEY: ${MINIO_ROOT_USER:-aramesh}
S3_SECRET_KEY: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD را در .env تنظیم کنید}
S3_BUCKET: aramesh-media
MEDIA_PUBLIC_BASE: /media
# نشانی عمومی سایت — برای sitemap و آدرس مطلق OG (مثل https://aramesh.example)
SITE_URL: ${SITE_URL:-}
# بیلد فرانت‌اند برای تزریق متای سئو در صفحات /blog و /projects
FRONTEND_DIST: /srv/frontend
volumes:
- ./frontend/dist:/srv/frontend:ro
depends_on:
db:
condition: service_healthy
minio:
condition: service_healthy
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"]
interval: 15s
timeout: 5s
retries: 5
start_period: 20s
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
# robots.txt و sitemap.xml و صفحات وبلاگ/پروژه با متای سئو — اولویت بالاتر از SPA
- traefik.http.routers.seo.rule=PathPrefix(`/blog/`) || Path(`/blog`) || PathPrefix(`/projects/`) || Path(`/projects`) || PathPrefix(`/robots.txt`) || PathPrefix(`/sitemap.xml`)
- traefik.http.routers.seo.entrypoints=web
- traefik.http.routers.seo.priority=50
- traefik.http.routers.seo.service=api
# فقط سرو فایل‌های استاتیک SPA — بیلد روی هاست (npm run build) انجام شده است
frontend:
@@ -105,6 +126,11 @@ services:
depends_on:
- backend
- minio
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost/"]
interval: 15s
timeout: 5s
retries: 5
labels:
- traefik.enable=true
- traefik.http.routers.web.rule=PathPrefix(`/`)
@@ -112,6 +138,17 @@ services:
- traefik.http.routers.web.priority=1
- traefik.http.services.web.loadbalancer.server.port=80
# ابزار پشتیبان‌گیری — فقط با پروفایل tools اجرا می‌شود (scripts/backup.sh این کار را می‌کند)
mc:
image: minio/mc:latest
profiles: ["tools"]
depends_on:
minio:
condition: service_healthy
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-aramesh}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD را در .env تنظیم کنید}
volumes:
db_data:
minio_data: