پرش به محتویات

راهنمای نصب و راه‌اندازی سامانه دارانو

نسخه: استقرار بر بستر 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