Files
onix/SETUP.md
2025-10-15 18:14:31 +05:30

45 KiB

Beckn-ONIX Setup Guide

This comprehensive guide walks you through setting up Beckn-ONIX from development to production deployment.

Table of Contents

  1. Prerequisites
  2. Development Setup
  3. Production Setup
  4. Configuration Guide
  5. External Services Setup
  6. GUI Component Setup
  7. Docker Deployment
  8. Kubernetes Deployment
  9. Testing Your Setup
  10. Troubleshooting
  11. Sample Payloads

Prerequisites

System Requirements

  • Operating System: Linux, macOS, or Windows (with WSL2)
  • CPU: 2+ cores recommended
  • RAM: 4GB minimum, 8GB recommended
  • Disk Space: 2GB free space

Software Requirements

Required

Optional (for production)

  • Docker 20.10+: For containerized deployment
  • HashiCorp Vault 1.12+: For secrets management
  • RabbitMQ 3.10+: For async messaging
  • Kubernetes 1.25+: For orchestrated deployment

Verify Installation

# Check Go version
go version
# Expected: go version go1.23.x

# Check Git
git --version

# Check Docker (optional)
docker --version

# Check Redis
redis-cli --version

Option 1: ONIX Adapter Only (Fastest)

For just the ONIX adapter with Redis (no Vault required):

# Clone the repository
git clone https://github.com/beckn/beckn-onix.git
cd beckn-onix/install

# Run the automated setup
chmod +x setup.sh
./setup.sh

This will automatically:

  • Start Redis container
  • Build all plugins
  • Build adapter server
  • Start ONIX adapter in Docker using local-simple.yaml (with simplekeymanager)
  • Create .env file

Services Started:

Key Management: Uses simplekeymanager with embedded keys - no Vault setup required!

Note: Extract schemas before running: unzip schemas.zip (required for schema validation) and before running the automated setup, build the adapter image ,update docker-compose-adapter.yaml to use the correct image (optional)

# from the repository root
docker build -f Dockerfile.adapter-with-plugins -t beckn-onix:latest .

Option 2: Complete Beckn Network

For a full local Beckn network with all components:

cd beckn-onix/install
chmod +x beckn-onix.sh
./beckn-onix.sh

# Choose option 3: "Set up a network on your local machine"

This will automatically:

  • Install and configure Registry service
  • Install and configure Gateway service
  • Create BAP Protocol Server registry entries
  • Create BPP Protocol Server registry entries
  • Build ONIX adapter plugins
  • Detect config file from docker-compose-adapter.yml
  • Extract keys from protocol server configs (bap-client.yml, bpp-client.yml)
  • Auto-update simplekeymanager in the detected config file with extracted keys
  • Start ONIX Adapter with Redis

Services Started:

Note: Extract schemas before running: unzip schemas.zip (required for schema validation) and before running the automated full-network setup, build the adapter image , update docker-compose-adapter.yaml to use the correct image(optional)

# from the repository root
docker build -f Dockerfile.adapter-with-plugins -t beckn-onix:latest .

Intelligent Key Management: The script reads docker-compose-adapter.yml to detect which config file is being used (default: local-simple.yaml), extracts keys from protocol server configs, and automatically updates the simplekeymanager section in that config file - no manual configuration needed!

Note: Update docker-compose-adapter.yml to use the correct config file and correct image (optional):

  • For combined setup (simplekeymanager): CONFIG_FILE: "/app/config/local-simple.yaml"
  • For combined setup (keymanager with Vault): CONFIG_FILE: "/app/config/local-dev.yaml"
  • For combined setup (production): CONFIG_FILE: "/app/config/onix/adapter.yaml"
  • For BAP only: CONFIG_FILE: "/app/config/onix-bap/adapter.yaml"
  • For BPP only: CONFIG_FILE: "/app/config/onix-bpp/adapter.yaml"

The script will automatically detect and configure whichever file you specify.


Development Setup (Manual)

Step 1: Clone the Repository

git clone https://github.com/beckn/beckn-onix.git
cd beckn-onix

Step 2: Install Dependencies

# Download Go dependencies
go mod download

# Verify dependencies
go mod verify

Step 3: Build the Application

# Build the main server binary
go build -o server cmd/adapter/main.go

# Make it executable
chmod +x server

Step 4: Build Plugins

The application uses a plugin architecture. Build all plugins:

# Make the build script executable
chmod +x install/build-plugins.sh

# Build all plugins (run from project root)
./install/build-plugins.sh

This creates .so files in the plugins/ directory:

  • cache.so - Redis caching
  • router.so - Request routing
  • signer.so - Message signing
  • signvalidator.so - Signature validation
  • schemavalidator.so - JSON schema validation
  • keymanager.so - Vault integration
  • simplekeymanager.so - Simple key management (no Vault)
  • publisher.so - RabbitMQ publishing
  • registry.so - Registry lookup
  • dediregistry.so - registry type plugin for public key lookup
  • encrypter.so / decrypter.so - Encryption/decryption
  • reqpreprocessor.so - Request preprocessing

Step 5: Setup Redis (Local)

Option A: Using Docker

docker run -d \
  --name redis-onix \
  -p 6379:6379 \
  redis:alpine

Option B: Native Installation

macOS:

brew install redis
brew services start redis

Ubuntu/Debian:

sudo apt update
sudo apt install redis-server
sudo systemctl start redis-server
sudo systemctl enable redis-server

Verify Redis:

redis-cli ping
# Expected: PONG

Step 6: Setup Schemas

# Create schemas directory
mkdir -p schemas

# Extract schemas from the provided schemas.zip
unzip schemas.zip

# Create logs directory (optional)
mkdir -p logs

Note: The schemas.zip file is included in the repository. You must extract it before running the adapter for schema validation to work.

Step 7: Configure for Local Development

For local development, use the existing config/local-simple.yaml which includes:

  • All 4 modules (BAP + BPP)
  • Simple key management (no Vault required)
  • Redis caching
  • Basic routing configuration

The file is pre-configured with embedded sample keys and ready to use for standalone testing.

Note: When using beckn-onix.sh (Option 2 in Quick Start), the script automatically extracts keys from protocol server configs and updates the simplekeymanager section in this file - no manual configuration needed!

Step 8: Configuration Files Overview

The config/ directory contains deployment configurations:

config/
├── local-dev.yaml                      # Local development with Vault
├── local-simple.yaml                   # Local development (no Vault)
├── local-routing.yaml                  # Local routing rules
├── local-simple-routing.yaml           # Simple routing rules
├── local-simple-routing-BAPCaller.yaml # BAP caller routing
├── local-simple-routing-BPPReceiver.yaml # BPP receiver routing
├── onix/                               # Combined BAP+BPP deployment
│   ├── adapter.yaml
│   ├── plugin.yaml
│   ├── bapTxnCaller-routing.yaml
│   ├── bapTxnReciever-routing.yaml
│   ├── bppTxnCaller-routing.yaml
│   └── bppTxnReciever-routing.yaml
├── onix-bap/                           # BAP-only deployment
│   ├── adapter.yaml
│   ├── plugin.yaml
│   ├── bapTxnCaller-routing.yaml
│   └── bapTxnReciever-routing.yaml
└── onix-bpp/                           # BPP-only deployment
    ├── adapter.yaml
    ├── plugin.yaml
    ├── bppTxnCaller-routing.yaml
    └── bppTxnReciever-routing.yaml

Routing configuration files for local-simple are already provided and referenced in local-simple.yaml.

Step 9: Run the Application

Choose your key management approach:

No Vault setup required! Use this for quick local testing.

# Run with local-simple.yaml (uses simplekeymanager plugin)
./server --config=config/local-simple.yaml

# Or run with go
go run cmd/adapter/main.go --config=config/local-simple.yaml

The local-simple.yaml config uses simplekeymanager plugin with embedded keys - no external dependencies needed.

With Docker:

cd install
docker compose -f docker-compose-adapter.yml up -d onix-adapter

The server will start on http://localhost:8081


Option B: HashiCorp Vault (Production-like Setup)

Only use this if your config has keymanager plugin (not simplekeymanager).

Configs that require Vault:

  • config/local-dev.yaml - uses keymanager plugin
  • config/onix/adapter.yaml - uses secretskeymanager plugin

Note: Make sure Redis is already running from Step 5.

# Make the script executable
chmod +x start-vault.sh

# Run the automated setup script
./start-vault.sh

# This creates a .env.vault file with your credentials
# Source it and run the server
source .env.vault && ./server --config=config/local-dev.yaml

That's it! The script handles everything automatically.

Manual Setup (Advanced)

If you prefer to set up Vault manually or need custom configuration:

# 1. Start Vault container
docker run -d \
  --name vault-dev \
  --cap-add=IPC_LOCK \
  -p 8200:8200 \
  -e 'VAULT_DEV_ROOT_TOKEN_ID=root' \
  hashicorp/vault:latest

# 2. Configure Vault (run the setup script)
chmod +x config/setup-vault.sh
./config/setup-vault.sh

# 3. Export the displayed credentials
export VAULT_ROLE_ID=<displayed-role-id>
export VAULT_SECRET_ID=<displayed-secret-id>

# 4. Run the server
./server --config=config/local-dev.yaml

What the Setup Does

  • Starts Vault in development mode on port 8200
  • Enables AppRole authentication
  • Creates necessary policies and roles
  • Sets up the KV secrets engine at path beckn
  • Stores sample keys for both BAP and BPP
  • Generates and saves credentials to .env.vault

Accessing Vault UI

Troubleshooting

If you get "invalid role or secret ID" error, the SECRET_ID has expired. Simply run:

./start-vault.sh
source .env.vault

Alternative: Simple Docker Run Command

# Start Vault in dev mode with initial setup
docker run -d \
  --name vault-dev \
  --cap-add=IPC_LOCK \
  -p 8200:8200 \
  -e 'VAULT_DEV_ROOT_TOKEN_ID=root' \
  -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200' \
  hashicorp/vault:latest

# Wait for Vault to be ready
sleep 3

# Setup Vault using a single command
docker exec vault-dev sh -c "
  export VAULT_ADDR='http://127.0.0.1:8200' &&
  export VAULT_TOKEN='root' &&
  vault secrets enable -path=beckn kv-v2 &&
  vault kv put beckn/keys/bap private_key='sample_bap_private_key' public_key='sample_bap_public_key' &&
  vault kv put beckn/keys/bpp private_key='sample_bpp_private_key' public_key='sample_bpp_public_key'
"

Step 9b: Set Environment Variables and Run

# Get the AppRole credentials from Vault container logs
docker logs vault-dev | grep "VAULT_ROLE_ID\|VAULT_SECRET_ID"

# Copy the displayed credentials and export them
# They will look something like this:
export VAULT_ROLE_ID='<role-id-from-logs>'
export VAULT_SECRET_ID='<secret-id-from-logs>'

# Run the server
./server --config=config/local-dev.yaml

# Or using go run
go run cmd/adapter/main.go --config=config/local-dev.yaml

Note: The Vault address is already configured in config/local-dev.yaml as http://localhost:8200. The docker-compose automatically sets up AppRole authentication and displays the credentials in the logs.

Alternative: Create a startup script

Create run-with-vault.sh:

#!/bin/bash
# Set Vault environment variables
export VAULT_ADDR=${VAULT_ADDR:-"http://localhost:8200"}
export VAULT_TOKEN=${VAULT_TOKEN:-"root"}  # For dev mode

# Or use AppRole auth for production-like setup
# export VAULT_ROLE_ID=${VAULT_ROLE_ID:-"beckn-role-id"}
# export VAULT_SECRET_ID=${VAULT_SECRET_ID:-"beckn-secret-id"}

echo "Starting Beckn-ONIX with Vault key management..."
echo "Vault Address: $VAULT_ADDR"

# Check if Vault is accessible
if ! curl -s "$VAULT_ADDR/v1/sys/health" > /dev/null 2>&1; then
    echo "Error: Cannot reach Vault at $VAULT_ADDR"
    echo "Please start Vault first with: vault server -dev -dev-root-token-id='root'"
    exit 1
fi

# Run the server
./server --config=config/local-dev.yaml

Make it executable and run:

chmod +x run-with-vault.sh
./run-with-vault.sh

The server will start on http://localhost:8081

Step 10: Verify Setup

# Check health endpoint
curl http://localhost:8081/health

# Check if modules are loaded
curl http://localhost:8081/bap/receiver/
# Expected: 404 with proper error (means module is loaded)

Production Setup

Additional Requirements for Production

  1. HashiCorp Vault for key management
  2. RabbitMQ for message queuing
  3. TLS certificates for secure communication
  4. Load balancer for high availability

Step 1: Setup HashiCorp Vault

Install Vault

# Download and install
wget https://releases.hashicorp.com/vault/1.15.0/vault_1.15.0_linux_amd64.zip
unzip vault_1.15.0_linux_amd64.zip
sudo mv vault /usr/local/bin/

Configure Vault

# Start Vault in dev mode (for testing only)
vault server -dev -dev-root-token-id="root"

# In production, use proper configuration
cat > vault-config.hcl <<EOF
storage "file" {
  path = "/opt/vault/data"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = 0
  tls_cert_file = "/opt/vault/tls/cert.pem"
  tls_key_file  = "/opt/vault/tls/key.pem"
}

api_addr = "https://vault.example.com:8200"
cluster_addr = "https://vault.example.com:8201"
ui = true
EOF

vault server -config=vault-config.hcl

Setup Keys in Vault

# Login to Vault
export VAULT_ADDR='http://localhost:8200'
vault login token=root

# Enable KV secrets engine
vault secrets enable -path=beckn kv-v2

# Store signing keys
vault kv put beckn/keys/bap \
  private_key="$(cat bap_private_key.pem)" \
  public_key="$(cat bap_public_key.pem)"

vault kv put beckn/keys/bpp \
  private_key="$(cat bpp_private_key.pem)" \
  public_key="$(cat bpp_public_key.pem)"

Step 2: Setup RabbitMQ

Using Docker

docker run -d \
  --name rabbitmq-onix \
  -p 5672:5672 \
  -p 15672:15672 \
  -e RABBITMQ_DEFAULT_USER=admin \
  -e RABBITMQ_DEFAULT_PASS=admin123 \
  rabbitmq:3-management

Configure Exchange and Queues

# Access RabbitMQ management UI
# http://localhost:15672 (admin/admin123)

# Or use CLI
docker exec rabbitmq-onix rabbitmqctl add_exchange beckn_exchange topic
docker exec rabbitmq-onix rabbitmqctl add_queue search_queue
docker exec rabbitmq-onix rabbitmqctl bind_queue search_queue beckn_exchange "*.search"

Step 3: Production Configuration

Create config/production.yaml:

appName: "beckn-onix-prod"
log:
  level: info
  destinations:
    - type: file
      config:
        filename: /var/log/beckn-onix/app.log
        maxSize: 100  # MB
        maxBackups: 10
        maxAge: 30    # days
    - type: stdout
  contextKeys:
    - transaction_id
    - message_id
    - subscriber_id
    - module_id
    - domain
    - action
http:
  port: 8080
  timeout:
    read: 60
    write: 60
    idle: 120
  tls:
    enabled: true
    certFile: /etc/ssl/certs/server.crt
    keyFile: /etc/ssl/private/server.key
pluginManager:
  root: ./plugins
modules:
  - name: bapTxnReceiver
    path: /bap/receiver/
    handler:
      type: std
      role: bap
      registryUrl: https://registry.ondc.org/lookup
      plugins:
        keyManager:
          id: keymanager
          config:
            projectID: ${PROJECT_ID}
            vaultAddr: ${VAULT_ADDR}
            kvVersion: v2
        cache:
          id: cache
          config:
            addr: ${REDIS_ADDR}
            password: ${REDIS_PASSWORD}
            db: 0
            poolSize: 100
        schemaValidator:
          id: schemavalidator
          config:
            schemaDir: ./schemas
            strictMode: true
        signValidator:
          id: signvalidator
          config:
            publicKeyPath: beckn/keys
        router:
          id: router
          config:
            routingConfig: ./config/routing-prod.yaml
        publisher:
          id: publisher
          config:
            addr: ${RABBITMQ_ADDR}
            username: ${RABBITMQ_USER}
            password: ${RABBITMQ_PASS}
            exchange: beckn_exchange
            durable: true
            useTLS: true
        middleware:
          - id: reqpreprocessor
            config:
              uuidKeys: transaction_id,message_id
              role: bap
      steps:
        - validateSign
        - addRoute
        - validateSchema
        - cache
        - publish
  
  # Add similar configuration for other modules...

Step 4: Environment Variables

Create .env.production:

# Vault Configuration
VAULT_ADDR=https://vault.example.com:8200
VAULT_ROLE_ID=your-role-id
VAULT_SECRET_ID=your-secret-id
PROJECT_ID=beckn-onix-prod

# Redis Configuration
REDIS_ADDR=redis.example.com:6379
REDIS_PASSWORD=strong-redis-password

# RabbitMQ Configuration
RABBITMQ_ADDR=rabbitmq.example.com:5671
RABBITMQ_USER=beckn_user
RABBITMQ_PASS=strong-rabbitmq-password

# Application Configuration
LOG_LEVEL=info
CONFIG_FILE=/app/config/production.yaml

Step 5: Systemd Service (Linux)

Create /etc/systemd/system/beckn-onix.service:

[Unit]
Description=Beckn ONIX Adapter
After=network.target redis.service

[Service]
Type=simple
User=beckn
Group=beckn
WorkingDirectory=/opt/beckn-onix
EnvironmentFile=/opt/beckn-onix/.env.production
ExecStart=/opt/beckn-onix/server --config=${CONFIG_FILE}
Restart=always
RestartSec=10
StandardOutput=append:/var/log/beckn-onix/stdout.log
StandardError=append:/var/log/beckn-onix/stderr.log

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable beckn-onix
sudo systemctl start beckn-onix
sudo systemctl status beckn-onix

Configuration Guide

Configuration Hierarchy

config/
├── local-dev.yaml                      # Local development with Vault
├── local-simple.yaml                   # Local development (no Vault)
├── local-routing.yaml                  # Local routing rules
├── local-simple-routing.yaml           # Simple routing rules
├── local-simple-routing-BAPCaller.yaml # BAP caller routing
├── local-simple-routing-BPPReceiver.yaml # BPP receiver routing
├── onix/                               # Combined BAP+BPP deployment
│   ├── adapter.yaml
│   ├── plugin.yaml
│   ├── bapTxnCaller-routing.yaml
│   ├── bapTxnReciever-routing.yaml
│   ├── bppTxnCaller-routing.yaml
│   └── bppTxnReciever-routing.yaml
├── onix-bap/                           # BAP-only deployment
│   ├── adapter.yaml
│   ├── plugin.yaml
│   ├── bapTxnCaller-routing.yaml
│   └── bapTxnReciever-routing.yaml
└── onix-bpp/                           # BPP-only deployment
    ├── adapter.yaml
    ├── plugin.yaml
    ├── bppTxnCaller-routing.yaml
    └── bppTxnReciever-routing.yaml

Module Configuration

Each module needs:

  • name: Unique identifier
  • path: HTTP endpoint path
  • handler: Processing configuration
    • type: Handler type (usually "std")
    • role: "bap" or "bpp"
    • plugins: Plugin configurations
    • steps: Processing pipeline steps

Plugin Configuration

Cache Plugin (Redis)

cache:
  id: cache
  config:
    addr: localhost:6379
    password: ""  # Optional
    db: 0
    poolSize: 50
    minIdleConns: 10
    maxRetries: 3

KeyManager Plugin (Vault)

keyManager:
  id: keymanager
  config:
    projectID: beckn-project
    vaultAddr: http://localhost:8200
    kvVersion: v2
    mountPath: beckn
    namespace: ""  # Optional for Vault Enterprise

Publisher Plugin (RabbitMQ)

publisher:
  id: publisher
  config:
    addr: localhost:5672
    username: guest
    password: guest
    exchange: beckn_exchange
    exchangeType: topic
    durable: true
    autoDelete: false
    useTLS: false
    tlsConfig:
      certFile: ""
      keyFile: ""
      caFile: ""

SchemaValidator Plugin

schemaValidator:
  id: schemavalidator
  config:
    schemaDir: ./schemas
    strictMode: false
    downloadSchemas: true
    schemaURL: https://schemas.beckn.org

Router Plugin

router:
  id: router
  config:
    routingConfig: ./config/routing.yaml
    defaultTimeout: 30
    retryCount: 3
    retryDelay: 1000  # milliseconds

Routing Rules Configuration

routingRules:
  - domain: "ONDC:RET10"
    version: "1.0.0"
    targetType: "url"  # or "publisher"
    target:
      url: "https://seller.example.com/beckn"
      # OR for async
      # queueName: "retail_queue"
      # routingKey: "retail.*"
    endpoints:
      - search
      - select
      - init
      - confirm
    headers:  # Optional additional headers
      X-Custom-Header: "value"
    timeout: 60  # seconds
    retryPolicy:
      maxRetries: 3
      backoff: exponential

Processing Steps

Available steps for configuration:

  • validateSign: Validate incoming signatures
  • addRoute: Determine routing based on rules
  • validateSchema: Validate against JSON schemas
  • sign: Sign outgoing requests
  • cache: Cache requests/responses
  • publish: Publish to message queue
  • encrypt: Encrypt sensitive data
  • decrypt: Decrypt encrypted data

External Services Setup

Redis Cluster (Production)

# Redis cluster configuration
cache:
  id: cache
  config:
    clusterAddrs:
      - redis-node1:6379
      - redis-node2:6379
      - redis-node3:6379
    password: ${REDIS_PASSWORD}
    poolSize: 100
    readTimeout: 3s
    writeTimeout: 3s

Vault High Availability

# Vault HA configuration
keyManager:
  id: keymanager
  config:
    vaultAddrs:
      - https://vault1.example.com:8200
      - https://vault2.example.com:8200
      - https://vault3.example.com:8200
    roleID: ${VAULT_ROLE_ID}
    secretID: ${VAULT_SECRET_ID}
    renewToken: true
    tokenTTL: 3600

RabbitMQ Cluster

# RabbitMQ cluster configuration
publisher:
  id: publisher
  config:
    clusterAddrs:
      - amqp://user:pass@rabbitmq1:5672
      - amqp://user:pass@rabbitmq2:5672
      - amqp://user:pass@rabbitmq3:5672
    haPolicy: all  # all, exactly, nodes
    connectionTimeout: 10s
    channelMax: 2047

GUI Component Setup

The GUI component provides a web interface for monitoring and management.

Prerequisites

  • Node.js 18+ and npm

Installation

cd onix-gui/GUI

# Install dependencies
npm install

# Development mode
npm run dev

# Production build
npm run build
npm start

Features

  • Dashboard: Real-time metrics and status
  • Configuration Editor: Visual YAML editor
  • Request Monitor: Live request/response tracking
  • Plugin Manager: Enable/disable plugins
  • Routing Rules: Visual routing configuration
  • Logs Viewer: Centralized log viewing

Configuration

Create onix-gui/GUI/.env.local:

NEXT_PUBLIC_API_URL=http://localhost:8081
NEXT_PUBLIC_REFRESH_INTERVAL=5000

Access

Open http://localhost:3000 in your browser.


Docker Deployment

Build Docker Image

# Build the image
docker build -f Dockerfile.adapter -t beckn-onix:latest .

# Tag for registry (optional)
docker tag beckn-onix:latest registry.example.com/beckn-onix:v1.0.0

Docker Compose Setup

Important: Create docker.yaml config and plugins bundle first

# Create symlink to existing config
cd config
ln -s onix/adapter.yaml docker.yaml
cd ..

# Build plugins first
./install/build-plugins.sh

# Create plugins bundle for Docker
cd plugins
zip -r plugins_bundle.zip *.so
cd ..

Create docker-compose.yml:

version: '3.8'

services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    command: redis-server --appendonly yes

  vault:
    image: hashicorp/vault:latest
    ports:
      - "8200:8200"
    environment:
      VAULT_DEV_ROOT_TOKEN_ID: root
      VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200
    cap_add:
      - IPC_LOCK
    volumes:
      - vault-data:/vault/file

  rabbitmq:
    image: rabbitmq:3-management
    ports:
      - "5672:5672"
      - "15672:15672"
    environment:
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: admin123
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq

  beckn-onix:
    image: beckn-onix:latest
    ports:
      - "8081:8081"
    depends_on:
      - redis
      - vault
      - rabbitmq
    environment:
      VAULT_ADDR: http://vault:8200
      VAULT_TOKEN: root
      REDIS_ADDR: redis:6379
      RABBITMQ_ADDR: rabbitmq:5672
      RABBITMQ_USER: admin
      RABBITMQ_PASS: admin123
    volumes:
      - ./config:/app/config
      - ./schemas:/app/schemas
      - ./plugins:/mnt/gcs/plugins
    command: ["./server", "--config=/app/config/docker.yaml"]

volumes:
  redis-data:
  vault-data:
  rabbitmq-data:

Important: Build the image first

# Build the beckn-onix image before running docker-compose
docker build -f Dockerfile.adapter -t beckn-onix:latest .

# Then run docker-compose
docker-compose up -d

Kubernetes Deployment

Kubernetes Manifests

Create namespace:

apiVersion: v1
kind: Namespace
metadata:
  name: beckn-onix

ConfigMap for configuration:

apiVersion: v1
kind: ConfigMap
metadata:
  name: beckn-onix-config
  namespace: beckn-onix
data:
  adapter.yaml: |
    # Your configuration here

Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: beckn-onix
  namespace: beckn-onix
spec:
  replicas: 3
  selector:
    matchLabels:
      app: beckn-onix
  template:
    metadata:
      labels:
        app: beckn-onix
    spec:
      containers:
      - name: beckn-onix
        image: registry.example.com/beckn-onix:v1.0.0
        ports:
        - containerPort: 8080
        env:
        - name: VAULT_ADDR
          valueFrom:
            secretKeyRef:
              name: beckn-secrets
              key: vault-addr
        - name: REDIS_ADDR
          value: redis-service:6379
        volumeMounts:
        - name: config
          mountPath: /app/config
        - name: plugins
          mountPath: /app/plugins
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
      volumes:
      - name: config
        configMap:
          name: beckn-onix-config
      - name: plugins
        persistentVolumeClaim:
          claimName: plugins-pvc

Service:

apiVersion: v1
kind: Service
metadata:
  name: beckn-onix-service
  namespace: beckn-onix
spec:
  selector:
    app: beckn-onix
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer

Helm Chart

For easier deployment, use the Helm chart:

# Add repo
helm repo add beckn https://charts.beckn.org

# Install
helm install beckn-onix beckn/onix \
  --namespace beckn-onix \
  --create-namespace \
  --values values.yaml

Example values.yaml:

replicaCount: 3

image:
  repository: registry.example.com/beckn-onix
  tag: v1.0.0
  pullPolicy: IfNotPresent

service:
  type: LoadBalancer
  port: 80

ingress:
  enabled: true
  hostname: beckn-onix.example.com
  tls: true

redis:
  enabled: true
  auth:
    enabled: true
    password: secretpassword

vault:
  enabled: true
  server:
    dev:
      enabled: false
    ha:
      enabled: true
      replicas: 3

rabbitmq:
  enabled: true
  auth:
    username: beckn
    password: secretpassword

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

Testing Your Setup

Health Check

# Basic health check
curl http://localhost:8081/health

# Expected response
{
  "status": "healthy",
  "timestamp": "2024-01-15T10:30:00Z",
  "version": "1.0.0"
}

Test Search Request

# Create a test search request (no Authorization header needed - ONIX auto-generates it)
curl -X POST http://localhost:8081/bap/caller/search \
  -H "Content-Type: application/json" \
  -d '{
    "context": {
      "domain": "nic2004:52110",
      "country": "IND",
      "city": "std:080",
      "action": "search",
      "version": "1.0.0",
      "bap_id": "test.bap.com",
      "bap_uri": "https://test.bap.com/beckn",
      "transaction_id": "'$(uuidgen)'",
      "message_id": "'$(uuidgen)'",
      "timestamp": "'$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")'",
      "ttl": "PT30S"
    },
    "message": {
      "intent": {
        "item": {
          "descriptor": {
            "name": "coffee"
          }
        },
        "fulfillment": {
          "end": {
            "location": {
              "gps": "12.9715987,77.5945627",
              "area_code": "560001"
            }
          }
        },
        "payment": {
          "buyer_app_finder_fee_type": "percent",
          "buyer_app_finder_fee_amount": "3"
        }
      }
    }
  }'

Load Testing

Use Apache Bench or similar tools:

# Install ab
sudo apt-get install apache2-utils

# Simple load test (no Authorization header needed - ONIX auto-generates it)
ab -n 1000 -c 10 -p search.json -T application/json \
  http://localhost:8081/bap/caller/search

Integration Testing

Create test script test_integration.sh:

#!/bin/bash

# Test BAP endpoints
endpoints=(
  "search"
  "select"
  "init"
  "confirm"
  "status"
  "track"
  "cancel"
  "update"
  "rating"
  "support"
)

for endpoint in "${endpoints[@]}"; do
  echo "Testing /bap/caller/$endpoint..."
  response=$(curl -s -o /dev/null -w "%{http_code}" \
    -X POST "http://localhost:8081/bap/caller/$endpoint" \
    -H "Content-Type: application/json" \
    -d @"test_payloads/${endpoint}.json")
  
  if [ "$response" -eq 200 ] || [ "$response" -eq 202 ]; then
    echo "✅ $endpoint: SUCCESS"
  else
    echo "❌ $endpoint: FAILED (HTTP $response)"
  fi
done

Troubleshooting

Common Issues and Solutions

1. Plugin Loading Failures

Error: failed to load plugin: plugin.Open: plugin.so: cannot open shared object file

Solution:

# Rebuild plugins from project root
./install/build-plugins.sh

# Check plugin files exist
ls -la plugins/

# Verify plugin compatibility
go version
file plugins/cache.so

Error: plugin was built with a different version of package internal/godebugs

Solution: Plugin version mismatch - rebuild with same Go version:

# Clean and rebuild plugins
rm -rf plugins/*.so
./install/build-plugins.sh

# Ensure same Go version for server and plugins
go version

2. Redis Connection Issues

Error: dial tcp 127.0.0.1:6379: connect: connection refused

Solution:

# Check Redis is running
redis-cli ping

# Start Redis if not running
sudo systemctl start redis

# Check Redis configuration
redis-cli CONFIG GET bind
redis-cli CONFIG GET protected-mode

3. Signature Validation Failures

Error: signature validation failed: invalid signature

Solution:

  • Verify correct key pair is being used
  • Check timestamp synchronization between systems
  • Ensure signature includes all required headers
  • Validate Base64 encoding of signature
# Generate test keys
openssl genpkey -algorithm ed25519 -out private_key.pem
openssl pkey -in private_key.pem -pubout -out public_key.pem

4. Schema Validation Errors

Error: schema validation failed: required property 'context' not found

Solution:

  • Verify schema files are in correct directory
  • Check schema version matches protocol version
  • Validate JSON structure
# Download latest schemas
wget https://schemas.beckn.org/core/v1.0.0.zip
unzip v1.0.0.zip -d schemas/

5. Port Already in Use

Error: listen tcp :8081: bind: address already in use

Solution:

# Find process using port
lsof -i :8081

# Kill process
kill -9 <PID>

# Or use different port in config

6. Vault Authentication Issues

Error: vault: authentication failed

Solution:

# Check Vault status
vault status

# Verify authentication
vault login -method=approle \
  role_id=${VAULT_ROLE_ID} \
  secret_id=${VAULT_SECRET_ID}

# Check policy permissions
vault policy read beckn-policy

Debug Mode

Enable debug logging:

log:
  level: debug
  destinations:
    - type: stdout
      config:
        pretty: true
        includeCalller: true

Or via environment variable:

LOG_LEVEL=debug ./server --config=config/adapter.yaml

Performance Tuning

System Limits

# Increase file descriptors
ulimit -n 65536

# Add to /etc/security/limits.conf
beckn soft nofile 65536
beckn hard nofile 65536

Go Runtime

# Set GOMAXPROCS
export GOMAXPROCS=8

# Enable profiling
./server --config=config/adapter.yaml --profile

Redis Optimization

# Redis configuration
redis-cli CONFIG SET maxclients 10000
redis-cli CONFIG SET tcp-keepalive 60
redis-cli CONFIG SET timeout 300

Sample Payloads

Search Request (Retail)

{
  "context": {
    "domain": "nic2004:52110",
    "country": "IND",
    "city": "std:080",
    "action": "search",
    "version": "1.0.0",
    "bap_id": "buyerapp.com",
    "bap_uri": "https://buyerapp.com/beckn",
    "transaction_id": "6d5f4c3b-2a1e-4b8c-9f7d-3e2a1b5c8d9f",
    "message_id": "a9f8e7d6-c5b4-3a2e-1f0d-9e8c7b6a5d4f",
    "timestamp": "2024-01-15T10:30:00.000Z",
    "ttl": "PT30S"
  },
  "message": {
    "intent": {
      "item": {
        "descriptor": {
          "name": "Laptop"
        }
      },
      "fulfillment": {
        "type": "Delivery",
        "end": {
          "location": {
            "gps": "12.9715987,77.5945627",
            "area_code": "560001"
          }
        }
      },
      "payment": {
        "buyer_app_finder_fee_type": "percent",
        "buyer_app_finder_fee_amount": "3"
      }
    }
  }
}

Select Request

{
  "context": {
    "domain": "nic2004:52110",
    "country": "IND",
    "city": "std:080",
    "action": "select",
    "version": "1.0.0",
    "bap_id": "buyerapp.com",
    "bap_uri": "https://buyerapp.com/beckn",
    "bpp_id": "sellerapp.com",
    "bpp_uri": "https://sellerapp.com/beckn",
    "transaction_id": "6d5f4c3b-2a1e-4b8c-9f7d-3e2a1b5c8d9f",
    "message_id": "b8e7f6d5-c4a3-2b1e-0f9d-8e7c6b5a4d3f",
    "timestamp": "2024-01-15T10:31:00.000Z",
    "ttl": "PT30S"
  },
  "message": {
    "order": {
      "provider": {
        "id": "P1",
        "locations": [
          {
            "id": "L1"
          }
        ]
      },
      "items": [
        {
          "id": "I1",
          "quantity": {
            "count": 2
          }
        }
      ],
      "fulfillment": {
        "end": {
          "location": {
            "gps": "12.9715987,77.5945627",
            "address": {
              "door": "21A",
              "name": "ABC Apartments",
              "building": "Tower 1",
              "street": "100 Feet Road",
              "locality": "Indiranagar",
              "city": "Bengaluru",
              "state": "Karnataka",
              "country": "India",
              "area_code": "560001"
            }
          },
          "contact": {
            "phone": "9876543210",
            "email": "customer@example.com"
          }
        }
      }
    }
  }
}

Init Request

{
  "context": {
    "domain": "nic2004:52110",
    "country": "IND",
    "city": "std:080",
    "action": "init",
    "version": "1.0.0",
    "bap_id": "buyerapp.com",
    "bap_uri": "https://buyerapp.com/beckn",
    "bpp_id": "sellerapp.com",
    "bpp_uri": "https://sellerapp.com/beckn",
    "transaction_id": "6d5f4c3b-2a1e-4b8c-9f7d-3e2a1b5c8d9f",
    "message_id": "c7f6e5d4-b3a2-1e0f-9d8e-7c6b5a4d3e2f",
    "timestamp": "2024-01-15T10:32:00.000Z",
    "ttl": "PT30S"
  },
  "message": {
    "order": {
      "provider": {
        "id": "P1",
        "locations": [
          {
            "id": "L1"
          }
        ]
      },
      "items": [
        {
          "id": "I1",
          "quantity": {
            "count": 2
          },
          "fulfillment_id": "F1"
        }
      ],
      "billing": {
        "name": "John Doe",
        "address": {
          "door": "21A",
          "name": "ABC Apartments",
          "building": "Tower 1",
          "street": "100 Feet Road",
          "locality": "Indiranagar",
          "city": "Bengaluru",
          "state": "Karnataka",
          "country": "India",
          "area_code": "560001"
        },
        "email": "john.doe@example.com",
        "phone": "9876543210",
        "created_at": "2024-01-15T10:32:00.000Z",
        "updated_at": "2024-01-15T10:32:00.000Z"
      },
      "fulfillment": {
        "id": "F1",
        "type": "Delivery",
        "tracking": false,
        "end": {
          "location": {
            "gps": "12.9715987,77.5945627",
            "address": {
              "door": "21A",
              "name": "ABC Apartments",
              "building": "Tower 1",
              "street": "100 Feet Road",
              "locality": "Indiranagar",
              "city": "Bengaluru",
              "state": "Karnataka",
              "country": "India",
              "area_code": "560001"
            }
          },
          "contact": {
            "phone": "9876543210",
            "email": "customer@example.com"
          }
        }
      },
      "payment": {
        "type": "ON-ORDER",
        "collected_by": "BAP",
        "buyer_app_finder_fee_type": "percent",
        "buyer_app_finder_fee_amount": "3",
        "settlement_details": [
          {
            "settlement_counterparty": "seller-app",
            "settlement_phase": "sale-amount",
            "settlement_type": "neft",
            "settlement_bank_account_no": "1234567890",
            "settlement_ifsc_code": "SBIN0001234",
            "beneficiary_name": "Seller Name",
            "bank_name": "State Bank of India",
            "branch_name": "Koramangala"
          }
        ]
      }
    }
  }
}

Confirm Request

{
  "context": {
    "domain": "nic2004:52110",
    "country": "IND",
    "city": "std:080",
    "action": "confirm",
    "version": "1.0.0",
    "bap_id": "buyerapp.com",
    "bap_uri": "https://buyerapp.com/beckn",
    "bpp_id": "sellerapp.com",
    "bpp_uri": "https://sellerapp.com/beckn",
    "transaction_id": "6d5f4c3b-2a1e-4b8c-9f7d-3e2a1b5c8d9f",
    "message_id": "d8f7e6d5-c4b3-2a1e-0f9d-8e7c6b5a4d3f",
    "timestamp": "2024-01-15T10:33:00.000Z",
    "ttl": "PT30S"
  },
  "message": {
    "order": {
      "id": "ORDER123",
      "state": "Created",
      "provider": {
        "id": "P1",
        "locations": [
          {
            "id": "L1"
          }
        ]
      },
      "items": [
        {
          "id": "I1",
          "fulfillment_id": "F1",
          "quantity": {
            "count": 2
          }
        }
      ],
      "quote": {
        "price": {
          "currency": "INR",
          "value": "4000"
        },
        "breakup": [
          {
            "item_id": "I1",
            "item_quantity": {
              "count": 2
            },
            "title_type": "item",
            "title": "Laptop",
            "price": {
              "currency": "INR",
              "value": "3800"
            }
          },
          {
            "item_id": "F1",
            "title_type": "delivery",
            "title": "Delivery charges",
            "price": {
              "currency": "INR",
              "value": "100"
            }
          },
          {
            "item_id": "F1",
            "title_type": "packing",
            "title": "Packing charges",
            "price": {
              "currency": "INR",
              "value": "50"
            }
          },
          {
            "item_id": "I1",
            "title_type": "tax",
            "title": "Tax",
            "price": {
              "currency": "INR",
              "value": "50"
            }
          }
        ],
        "ttl": "P1D"
      },
      "payment": {
        "uri": "https://ondc.transaction.com/payment",
        "tl_method": "http/get",
        "params": {
          "transaction_id": "TXN123456",
          "amount": "4000",
          "currency": "INR"
        },
        "type": "ON-ORDER",
        "status": "PAID",
        "collected_by": "BAP",
        "buyer_app_finder_fee_type": "percent",
        "buyer_app_finder_fee_amount": "3",
        "settlement_details": [
          {
            "settlement_counterparty": "seller-app",
            "settlement_phase": "sale-amount",
            "settlement_type": "neft",
            "settlement_bank_account_no": "1234567890",
            "settlement_ifsc_code": "SBIN0001234",
            "beneficiary_name": "Seller Name",
            "bank_name": "State Bank of India",
            "branch_name": "Koramangala"
          }
        ]
      },
      "fulfillment": {
        "id": "F1",
        "type": "Delivery",
        "tracking": true,
        "start": {
          "location": {
            "id": "L1",
            "descriptor": {
              "name": "Seller Store"
            },
            "gps": "12.9715987,77.5945627",
            "address": {
              "locality": "Koramangala",
              "city": "Bengaluru",
              "area_code": "560034",
              "state": "Karnataka"
            }
          },
          "time": {
            "range": {
              "start": "2024-01-15T11:00:00.000Z",
              "end": "2024-01-15T12:00:00.000Z"
            }
          },
          "contact": {
            "phone": "9988776655",
            "email": "seller@example.com"
          }
        },
        "end": {
          "location": {
            "gps": "12.9715987,77.5945627",
            "address": {
              "door": "21A",
              "name": "ABC Apartments",
              "building": "Tower 1",
              "street": "100 Feet Road",
              "locality": "Indiranagar",
              "city": "Bengaluru",
              "state": "Karnataka",
              "country": "India",
              "area_code": "560001"
            }
          },
          "time": {
            "range": {
              "start": "2024-01-15T14:00:00.000Z",
              "end": "2024-01-15T18:00:00.000Z"
            }
          },
          "person": {
            "name": "John Doe"
          },
          "contact": {
            "phone": "9876543210",
            "email": "customer@example.com"
          }
        }
      },
      "created_at": "2024-01-15T10:33:00.000Z",
      "updated_at": "2024-01-15T10:33:00.000Z"
    }
  }
}

Authorization Header Structure

Note: ONIX adapter automatically generates and adds the Authorization signature header to outgoing requests. You don't need to manually create it when calling ONIX endpoints.

For reference, the Authorization header format is:

Authorization: Signature keyId="{subscriber_id}|{key_id}|{algorithm}",algorithm="{algorithm}",created="{created}",expires="{expires}",headers="(created) (expires) digest",signature="{base64_signature}"

Example of how ONIX generates it internally:

#!/bin/bash

# Variables
SUBSCRIBER_ID="buyerapp.com"
KEY_ID="key1"
ALGORITHM="ed25519"
CREATED=$(date +%s)
EXPIRES=$((CREATED + 300))
PRIVATE_KEY="path/to/private_key.pem"

# Create string to sign
STRING_TO_SIGN="(created): ${CREATED}
(expires): ${EXPIRES}
digest: SHA-256=${DIGEST}"

# Sign with Ed25519
SIGNATURE=$(echo -n "$STRING_TO_SIGN" | \
  openssl pkeyutl -sign -inkey $PRIVATE_KEY -rawin | \
  base64 -w 0)

# Create header
AUTH_HEADER="Signature keyId=\"${SUBSCRIBER_ID}|${KEY_ID}|${ALGORITHM}\",algorithm=\"${ALGORITHM}\",created=\"${CREATED}\",expires=\"${EXPIRES}\",headers=\"(created) (expires) digest\",signature=\"${SIGNATURE}\""

echo $AUTH_HEADER

Conclusion

This setup guide covers all aspects of deploying Beckn-ONIX from local development to production. Key points:

  1. Start Simple: Begin with local development setup
  2. Test Thoroughly: Use provided test scripts and payloads
  3. Scale Gradually: Move from single instance to clustered deployment
  4. Monitor Continuously: Use logs and metrics for observability
  5. Secure Always: Implement proper authentication and encryption

For additional help:

Happy deploying! 🚀