لاڠکاو ککاندوڠن دوکومينتاسي

ترجمهن سدڠ دجالنکن

دوکومين اين دسدياکن دالم بهاس ايڠݢريس بوات سمنتارا وقتو سمنتارا ترجمهن جاوي دسياڤکن.

Docker Compose Deployment

Docker Compose offers the fastest and most reproducible method to deploy Aqiled on an individual server or cloud virtual machine.

ترسديا سکارڠ. سيمقن تراخير: 26 October 2026.

Architecture in Docker

The Docker Compose setup launches three services in an isolated bridge network:

  • db: PostgreSQL 18 container pinned to postgres:18-bookworm.
  • api: .NET API service running Kestrel internally on port 5216.
  • web: Nginx web server serving the compiled dedicated front-end and reverse-proxying /api and /hubs.
graph LR
    Browser[Web Browser] -->|HTTPS: 443| Nginx[web: Nginx Container]
    Nginx -->|Static Assets| ReactApp[dist/dedicated]
    Nginx -->|/api and /hubs| ApiService[api: .NET Container]
    ApiService -->|Port 5432| Postgres[(db: PostgreSQL 18 Volume)]

1. Directory Setup

Create a deployment directory on your server:

mkdir -p /opt/aqiled && cd /opt/aqiled

2. Docker Compose File

Create docker-compose.yml:

version: '3.8'

services:
  db:
    image: postgres:18-bookworm
    container_name: aqiled_db
    restart: always
    environment:
      POSTGRES_DB: school_db
      POSTGRES_PASSWORD: DB_ROOT_PASSWORD_CHANGE_ME
    volumes:
      - postgres_data:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d school_db"]
      interval: 5s
      timeout: 5s
      retries: 5

  api:
    image: aqiled/api:latest
    container_name: aqiled_api
    restart: always
    depends_on:
      db:
        condition: service_healthy
    env_file:
      - api.env
    ports:
      - "127.0.0.1:5216:5216"

  web:
    image: aqiled/web:latest
    container_name: aqiled_web
    restart: always
    depends_on:
      - api
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro

volumes:
  postgres_data:

3. Environment Variables (api.env)

Generate secure 32-character hexadecimal keys before launching:

openssl rand -hex 32 # For Encryption__MasterKey
openssl rand -hex 32 # For Jwt__Secret

Create api.env:

ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://+:5216

# Deployment Mode (Leave empty until provisioned)
Deployment__Mode=MultiTenant
Deployment__SchoolTenantId=

# Database Connections (target internal db container)
ConnectionStrings__DefaultConnection=Host=db;Port=5432;Database=school_db;Username=school_app;Password=APP_ROLE_PASSWORD;
ConnectionStrings__AdminConnection=Host=db;Port=5432;Database=school_db;Username=school_admin;Password=ADMIN_ROLE_PASSWORD;
ConnectionStrings__MigrationConnection=Host=db;Port=5432;Database=school_db;Username=school_migrator;Password=MIGRATOR_PASSWORD;

# Security & Secrets
Encryption__MasterKey=GENERATED_32_CHAR_MASTER_KEY
Jwt__Secret=GENERATED_32_CHAR_JWT_SECRET

4. Initialization & Provisioning

Run once to initialize the container database

  1. Start the database container:docker compose up -d db
  2. Create the database roles: Connect to the container and run the role creation SQL from the Prerequisites Guide.

  3. Run the EF database migration bundle:docker compose run --rm api dotnet School.Api.dll --migrate
  4. Provision your school:docker compose run --rm api dotnet School.Api.dll provision-school \ --name "Madrasah Al-Falah" \ --slug "alfalah" \ --country "TH" \ --school-type "kindergarten" \ --admin-email "admin@alfalah.ac.th" \ --admin-first-name "Ahmad" \ --admin-last-name "Dahlan"

    Enter your admin password when prompted. The command prints your School tenant ID.

  5. Switch to SingleSchool mode: In api.env, update:

    Deployment__Mode=SingleSchool Deployment__SchoolTenantId=PASTE_PRINTED_TENANT_ID
  6. Start all services:docker compose up -d

5. Validate Container Health

Verify that the API and database are running and healthy:

curl -i http://127.0.0.1:5216/health/ready

Response must return HTTP/1.1 200 OK.