راهنمای نصب و راهاندازی سامانه دارانو
نسخه: استقرار بر بستر Ubuntu 22.04 VPS
1. نیازمندیها
1.1 مشخصات سختافزاری پیشنهادی
| مورد | مقدار پیشنهادی |
|---|---|
| RAM | حداقل ۸GB (پیشنهاد: ۱۶GB) |
| CPU | حداقل ۴ vCPU |
| Storage | حداقل ۱۰۰GB SSD |
| Network | Static Public IP |
1.2 پیشنیازهای نرمافزاری
- Ubuntu 22.04 LTS
- Docker
- Docker Compose Plugin
- Git
- دسترسی SSH
2. نصب Docker و Docker Compose
2.1 نصب یکخطی Docker (پیشنهادی)
curl -fsSL https://get.docker.com | sh
2.2 تست عملکرد Docker
docker --version
docker compose version
2.3 اجرای Docker بدون sudo (اختیاری)
sudo usermod -aG docker $USER
# Logout / Login
3. ایجاد Docker Networks
docker network create dev-mq
docker network create dev-db
docker network create dev-backend
docker network create gateway
اگر شبکه از قبل موجود باشد، پیام خطا قابل چشمپوشی است.
4. ساختار فایلها در VPS
/opt/darano
|-- backend
| |-- backend-docker-compose.yaml
| |-- cfg
| | |-- auth.toml
| | |-- jwt
| | |-- jwt.key
| | |-- jwt.pub
| |-- data
| |-- auth
| | |-- log
| |-- wallet
| | |-- log
| |-- market
| | |-- log
| |-- gateway
| |-- log
| |-- assets
|
|-- ui
|-- ui-docker-compose.yml
5. تولید JWT Keys
در مسیر /opt/darano/backend/cfg/jwt:
openssl genpkey -algorithm RSA -out jwt.key -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in jwt.key -out jwt.pub
chmod 600 jwt.key
chmod 644 jwt.pub
6. دریافت کد / ایمیج سرویسها
6.1 Pull از رجیستری (در محیط Dev/Staging)
cd /opt/darano/backend
docker compose -f backend-docker-compose.yaml pull
cd /opt/darano/ui
docker compose -f ui-docker-compose.yml pull
6.2 Build محلی (فقط در صورت نیاز)
git clone https://git.darano.ir/kahroba/backend.git
cd backend
docker build -t git.darano.ir/kahroba/api:dev .
در حالت معمول CI/CD مسئول Build و Push ایمیج است.
در این راهنمای تصب پیشفرض این است که سورس کد در git.darano.ir موجود است.
7. اجرای Backend
cd /opt/darano/backend
docker compose -f backend-docker-compose.yaml up -d
سرویسهای فعال Backend
| سرویس | نقش |
|---|---|
| auth | Authentication / Authorization |
| wallet | Wallet Service |
| wallet-streamer | Wallet Streamer / Listener |
| market | Market Service |
| api | API Gateway / Aggregator |
| AdminPanel | پنل مدیریت بر پایه Django 5.2 |
8. اجرای UI
cd /opt/darano/ui
docker compose -f ui-docker-compose.yml up -d
سرویس UI
| سرویس | آدرس |
|---|---|
| ui | https://dev.darano.ir |
9. پیکربندی Traefik + Cloudflare
Traefik:
- Routing
- TLS Certificates (DNS Challenge with Cloudflare)
- مدیریت CORS و Middlewareها
Cloudflare:
- DNS
- Proxy
- Firewall / WAF
دامنههای فعال در این استقرار
| سرویس | دامنه |
|---|---|
| UI | https://dev.darano.ir |
| API | https://dev.api.darano.ir |
| Admin Panel | https://dev.admin.darano.ir |
در پنل Cloudflare:
- رکوردهای A را به IP سرورVPS اشاره دهید.
- Proxy بر حسب سیاست امنیتی میتواند فعال باشد.
10. Health Check
10.1 از طریق Curl
curl -k https://dev.api.darano.ir/
10.2 پاسخ نمونه
{ "data": "Server is up and running" }
11. مانیتورینگ
در صورت استفاده از استک مانیتورینگ (Prometheus, Grafana, Portainer, Alertmanager):
cd /opt/darano/monitoring
docker compose up -d
12. چکلیست نهایی
| مورد | وضعیت |
|---|---|
| Docker / Compose نصب و تست شد | ☐ |
| شبکههای Docker ایجاد شدند | ☐ |
| Database / Redis / RabbitMQ فعال هستند | ☐ |
| Backend بدون خطا اجرا شد | ☐ |
| UI بدون خطا اجرا شد | ☐ |
| Traefik روی پورتهای 80 و 443 فعال است | ☐ |
| DNSها روی Cloudflare به VPS اشاره دارد | ☐ |
| Health Check موفق | ☐ |
| مانیتورینگ فعال است | ☐ |
13. نمونه فایلهای docker-compose
13.1 فایل backend-docker-compose.yaml
version: "3.9"
networks:
mq:
name: dev-mq
external: true
db:
name: dev-db
external: true
backend:
name: dev-backend
gateway:
name: gateway
external: true
services:
auth:
image: git.darano.ir/kahroba/auth:dev
hostname: auth
restart: always
networks:
- backend
- db
- mq
expose:
- 3000
ports:
- 9100:4000
volumes:
- ./cfg/auth.toml:/app/config.cfg:ro
- ./cfg/jwt/jwt.key:/var/jwt/jwt.key:ro
- ./cfg/jwt/jwt.pub:/var/jwt/jwt.pub:ro
- ./data/auth/log/:/log/
wallet-streamer:
image: git.darano.ir/kahroba/wallet:dev
command:
- /app/main
- stream
- --conf
- /app/config.cfg
hostname: wallet-streamer
restart: always
networks:
- backend
- db
- mq
expose:
- 3000
ports:
- 9200:4000
volumes:
- ./cfg/auth.toml:/app/config.cfg:ro
- ./data/wallet/log/:/log/
market:
image: git.darano.ir/kahroba/wallet:dev
hostname: market
restart: always
command:
- /app/main
- serve
- market
- --conf
- /app/config.cfg
networks:
- backend
- db
- mq
expose:
- 3000
ports:
- 9302:4000
volumes:
- ./cfg/auth.toml:/app/config.cfg:ro
- ./data/market/log/:/log/
wallet:
image: git.darano.ir/kahroba/wallet:dev
hostname: wallet
restart: always
command:
- /app/main
- serve
- wallet
- --conf
- /app/config.cfg
networks:
- backend
- db
- mq
expose:
- 3000
ports:
- 9301:4000
volumes:
- ./cfg/auth.toml:/app/config.cfg:ro
- ./data/wallet/log/:/log/
api:
image: git.darano.ir/kahroba/api:dev
hostname: dev-api
restart: always
networks:
- backend
- db
- mq
- gateway
expose:
- 3000
ports:
- 9500:4000
environment:
- CFG_DIR=/app/config.cfg
depends_on:
- auth
- wallet
volumes:
- ./cfg/auth.toml:/app/config.cfg:ro
- ./data/gateway/assets/:/app/static/
- ./data/gateway/log/:/log/
labels:
- "traefik.enable=true"
- "traefik.http.routers.dev-ktgateway.rule=Host(`dev.api.darano.ir`)"
- "traefik.http.routers.dev-ktgateway.entrypoints=websecure"
- "traefik.http.routers.dev-ktgateway.tls.certresolver=myresolver"
- "traefik.http.services.dev-ktgateway.loadbalancer.server.port=3000"
- "traefik.http.middlewares.cors.headers.accesscontrolallowmethods=*"
- "traefik.http.middlewares.cors.headers.accessControlAllowHeaders=*"
- "traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist=*"
- "traefik.http.middlewares.cors.headers.accesscontrolmaxage=100"
- "traefik.http.middlewares.cors.headers.addvaryheader=true"
- "traefik.http.routers.dev-ktgateway.middlewares=cors"
AdminPanel:
image: git.darano.ir/kahroba/adminpanel:dev
expose:
- 8000
restart: always
networks:
- db
- gateway
environment:
- DEBUG=True
- CSRF_TRUSTED_ORIGINS=https://dev.admin.darano.ir
- DJANGO_ALLOWED_HOSTS=https://dev.admin.darano.ir
- REDIS_URL=redis://redis:6379/2
- DATABASE_URL=postgresql://gitea:gitea@dev-db:5432/djdev
- CORE_DATABASE_URL=postgresql://gitea:gitea@dev-db:5432/backend
labels:
- "traefik.enable=true"
- "traefik.http.routers.dev-adminpanel.rule=Host(`dev.admin.darano.ir`)"
- "traefik.http.routers.dev-adminpanel.entrypoints=websecure"
- "traefik.http.routers.dev-adminpanel.tls.certresolver=myresolver"
- "traefik.http.services.dev-adminpanel.loadbalancer.server.port=8000"
- "traefik.http.middlewares.cors.headers.accesscontrolallowmethods=*"
- "traefik.http.middlewares.cors.headers.accessControlAllowHeaders=*"
- "traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist=*"
- "traefik.http.middlewares.cors.headers.accesscontrolmaxage=100"
- "traefik.http.middlewares.cors.headers.addvaryheader=true"
- "traefik.http.middlewares.testHeader.headers.customrequestheaders.Accept-Language=fa"
- "traefik.http.routers.dev-adminpanel.middlewares=cors,testHeader"
13.2 فایل ui-docker-compose.yml
version: "3.9"
networks:
gateway:
external: true
name: gateway
backend:
external: true
name: dev-backend
services:
ui:
image: git.darano.ir/kahroba/ui:dev
restart: always
networks:
- gateway
- backend
environment:
- NODE_ENV=production
- NEXT_PUBLIC_API_URL=https://dev.api.darano.ir/
- NEXT_PUBLIC_PLATFORM_VERSION=andishe
- NEXTAUTH_SECRET=5qVmtoPxW85R7q695qsNrOe0SQ1E6w8eszUFypGoPHg
- NEXTAUTH_URL=https://dev.darano.ir/
- NEXT_PUBLIC_TEST_ALERT=true
expose:
- 3000
labels:
- "traefik.enable=true"
- "traefik.http.services.ktui-dev.loadbalancer.server.port=3000"
- "traefik.http.routers.ktui-dev.rule=Host(`dev.darano.ir`)"
- "traefik.http.routers.ktui-dev.entrypoints=websecure"
- "traefik.http.routers.ktui-dev.tls.certresolver=myresolver"
13.3 فایل infra-docker-compose.yml (Postgres, RabbitMQ, Redis)
version: "3.9"
networks:
db:
external: true
name: dev-db
mq:
external: true
name: dev-mq
services:
postgres:
image: postgres:15
restart: always
networks:
- db
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=gitea
- POSTGRES_DB=backend
volumes:
- ./data/postgres:/var/lib/postgresql/data
ports:
- "5432:5432"
rabbitmq:
image: rabbitmq:3-management
restart: always
networks:
- mq
ports:
- "5672:5672"
- "15672:15672"
redis:
image: redis:7
restart: always
networks:
- mq
ports:
- "6379:6379"
13.4 فایل traefik-docker-compose.yml
version: "3.9"
services:
traefik:
image: traefik:v2.11
restart: always
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.dnschallenge=true"
- "--certificatesresolvers.myresolver.acme.dnschallenge.provider=cloudflare"
- "--certificatesresolvers.myresolver.acme.email=you@example.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
networks:
- gateway
ports:
- "80:80"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./letsencrypt:/letsencrypt"
environment:
- CF_DNS_API_TOKEN=YOUR_CLOUDFLARE_DNS_API_TOKEN
networks:
gateway:
external: true
name: gateway
13.5 فایل monitoring-docker-compose.yml (Prometheus, Grafana, Portainer, Alertmanager)
version: "3.9"
networks:
gateway:
external: true
name: gateway
services:
prometheus:
image: prom/prometheus:latest
restart: always
networks:
- gateway
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
ports:
- "9090:9090"
grafana:
image: grafana/grafana:latest
restart: always
networks:
- gateway
ports:
- "3001:3000"
volumes:
- ./grafana:/var/lib/grafana
alertmanager:
image: prom/alertmanager:latest
restart: always
networks:
- gateway
volumes:
- ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
ports:
- "9093:9093"
portainer:
image: portainer/portainer-ce:latest
restart: always
networks:
- gateway
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./portainer:/data
ports:
- "9443:9443"
13.6 فایل cfg/auth.toml
version= "v1.0.5"
production= true
public_serve= true
no_shahkar= true
no_otp = true
no_ipg = true
no_iban_check = true
shahkar_provider= "Zohal"
environment = "development"
receipt-url = "https://dev.darano.ir/dashboard/assets/deposit?symbol=IRT"
[cors]
allowed-headers = [
"Content-Type",
"Content-Length",
"Accept-Encoding",
"X-CSRF-Token",
"Authorization",
"accept",
"origin",
"Cache-Control",
"X-Requested-With",
"Platform-Version",
"Refresh-Token",
"Baggage",
"Sentry-Trace",
"elastic-apm-traceparent",
]
[dumb-shit]
irt-asset-id = 3
null-buy-and-sell-asset-price = 400_000_000
bnpl-id-used-in-redeem = 1
market-order-counter-asset = 3
[system_encryption]
public = "<ENCRYPTION_PUBLIC_KEY>" # "GBR345DS2MC2IVSNPTKVW2XQFXMQAVQB32CMQMRRSXGHGKKBB3G72A7R"
private = "<ENCRYPTION_PRIVATE_KEY>" # "SA5HCBIYRFKL3WQZDGIN4TDOMNHREPCVRGDNBXEGUP34345T6LSOZEUBQ"
[peers]
Wallet = "wallet:3000"
Marketplace = "market:3000"
Authorization = "auth:3000"
Notification = "auth:3000"
InternalAuthorization = "auth:3000"
[log]
level= "info"
error-path= "/log/"
info-path= "/log/"
debug-path= "/log/"
[rest]
port= 3000
host= "0.0.0.0"
[grpc]
port= 3000
host= "0.0.0.0"
timeout = "1m"
[db]
host= "dev-db"
port= 5432
name= "backend"
user= "gitea"
password= "gitea"
[redis]
host= "redis"
port= 6379
user= ""
password= ""
db= 2
[rabbitmq]
host= "rabbitmq"
port= 5672
name= ""
user= "guest"
password= "guest"
[kavenegar]
# Hossein's account
base-url= "https://api.kavenegar.com"
api-key= "<API_KEY>"
sender= "1000689696"
template= "Verify"
[mellat-ipg]
base-url = "https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl"
terminal-id = 11111111
username = "<USERNAME>"
password = "<PASSWORD>"
callback-url = "https://dev.api.darano.ir/v1/public/wallet/confirm-sale"
[jwt]
private-key-path= "/var/jwt/jwt.key"
public-key-path= "/var/jwt/jwt.pub"
audience= "dev-darano"
issuer= "dev-darano"
access-token-expiry = "1h" # One day
refresh-token-expiry = "168h" # One week
[ehraz]
base-url= "https://ehraz.io/api/"
version= 1
api-key= "<API_KEY>"
[zohal]
base-url = "https://service.zohal.io/api/v0/services/"
version = 0
api-key= "<API_KEY>"
[wallet]
master-key = "<MASTER_KEY>"
source-secret-key = "<SOURCE_SECRET_KEY>"
distributor-secret-key = "<DISTRIBUTOR_SECRET_KEY>"
system-wallet-address = ""
redeem-wallet-address = ""
[network]
horizon-url = "http://n2.mellatbam.com"
network-passphrase = "Kuknos Foundation, Feb 2019"
min-balance = 2
min-reserved-gas = 0.6
gas-asset-id = 2
trx-base-fee = 500_000
[profilling]
enabled = true
host = "0.0.0.0"
port = 4000