Files
onix/SETUP.md
Mayuresh A Nirhali 9d6a1a70a6 Update SETUP.md
Fixed path to build-plugins.sh.
2025-09-09 21:25:49 +05:30

43 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

For a complete Beckn network setup with all services, use our automated setup:

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

# Run the setup (includes only adapter services)
cd install
chmod +x setup.sh
./setup.sh

# Start the Beckn-ONIX server
source .env.vault && ./server --config=config/local-dev.yaml

This will automatically:

  • Run & Configure Redis and Vault
  • Build all plugins
  • Set up authentication
  • Create environment variables

Services Started:

To stop all services: docker compose down To view logs: docker compose logs -f [service-name]


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
./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
  • publisher.so - RabbitMQ publishing
  • 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: Create Required Directories

# Create schemas directory for validation
mkdir -p schemas

# Create logs directory (optional)
mkdir -p logs

Step 7: Configure for Local Development

Create or modify config/local-dev.yaml:

appName: "onix-local"
log:
  level: debug
  destinations:
    - type: stdout
  contextKeys:
    - transaction_id
    - message_id
    - subscriber_id
    - module_id
http:
  port: 8081
  timeout:
    read: 30
    write: 30
    idle: 30
pluginManager:
  root: ./plugins
modules:
  - name: bapTxnReceiver
    path: /bap/receiver/
    handler:
      type: std
      role: bap
      registryUrl: http://localhost:8080/reg
      plugins:
        keyManager:
          id: keymanager
          config:
            projectID: beckn-onix-local
            vaultAddr: http://localhost:8200
            kvVersion: v2
            mountPath: beckn
        cache:
          id: cache
          config:
            addr: localhost:6379
        schemaValidator:
          id: schemavalidator
          config:
            schemaDir: ./schemas
        signValidator:
          id: signvalidator
          config:
            publicKeyPath: beckn/keys
        router:
          id: router
          config:
            routingConfig: ./config/local-routing.yaml
        middleware:
          - id: reqpreprocessor
            config:
              uuidKeys: transaction_id,message_id
              role: bap
      steps:
        - validateSign
        - addRoute
        - validateSchema
  
  - name: bapTxnCaller
    path: /bap/caller/
    handler:
      type: std
      role: bap
      registryUrl: http://localhost:8080/reg
      plugins:
        keyManager:
          id: keymanager
          config:
            projectID: beckn-onix-local
            vaultAddr: http://localhost:8200
            kvVersion: v2
            mountPath: beckn
        cache:
          id: cache
          config:
            addr: localhost:6379
        router:
          id: router
          config:
            routingConfig: ./config/local-routing.yaml
        signer:
          id: signer
        middleware:
          - id: reqpreprocessor
            config:
              uuidKeys: transaction_id,message_id
              role: bap
      steps:
        - addRoute
        - sign
  
  - name: bppTxnReceiver
    path: /bpp/receiver/
    handler:
      type: std
      role: bpp
      registryUrl: http://localhost:8080/reg
      plugins:
        keyManager:
          id: keymanager
          config:
            projectID: beckn-onix-local
            vaultAddr: http://localhost:8200
            kvVersion: v2
            mountPath: beckn
        cache:
          id: cache
          config:
            addr: localhost:6379
        schemaValidator:
          id: schemavalidator
          config:
            schemaDir: ./schemas
        signValidator:
          id: signvalidator
          config:
            publicKeyPath: beckn/keys
        router:
          id: router
          config:
            routingConfig: ./config/local-routing.yaml
      steps:
        - validateSign
        - addRoute
        - validateSchema
  
  - name: bppTxnCaller
    path: /bpp/caller/
    handler:
      type: std
      role: bpp
      registryUrl: http://localhost:8080/reg
      plugins:
        keyManager:
          id: keymanager
          config:
            projectID: beckn-onix-local
            vaultAddr: http://localhost:8200
            kvVersion: v2
            mountPath: beckn
        cache:
          id: cache
          config:
            addr: localhost:6379
        router:
          id: router
          config:
            routingConfig: ./config/local-routing.yaml
        signer:
          id: signer
      steps:
        - addRoute
        - sign

Step 8: Create Routing Configuration

Create config/local-routing.yaml:

routingRules:
  - domain: "nic2004:60221"  # Mobility domain
    version: "0.9.4"
    targetType: "url"
    target:
      url: "http://localhost:9001/beckn"
    endpoints:
      - search
      - select
      - init
      - confirm
      - status
      - track
      - cancel
      - update
      - rating
      - support
  
  - domain: "nic2004:52110"  # Retail domain
    version: "1.0.0"
    targetType: "url"
    target:
      url: "http://localhost:9002/beckn"
    endpoints:
      - search
      - select
      - init
      - confirm
      - status
      - track
      - cancel
      - update
      - rating
      - support

Step 9: Run the Application with HashiCorp Vault

Since the configuration now includes the keyManager plugin for signing capabilities, you need to set up Vault:

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
├── local-routing.yaml          # Local routing rules
├── onix/                       # Combined BAP+BPP
│   ├── adapter.yaml
│   ├── bapTxnCaller-routing.yaml
│   ├── bapTxnReceiver-routing.yaml
│   ├── bppTxnCaller-routing.yaml
│   └── bppTxnReceiver-routing.yaml
├── onix-bap/                   # BAP-only deployment
│   ├── adapter.yaml
│   ├── bapTxnCaller-routing.yaml
│   └── bapTxnReceiver-routing.yaml
└── onix-bpp/                   # BPP-only deployment
    ├── adapter.yaml
    ├── bppTxnCaller-routing.yaml
    └── bppTxnReceiver-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
docker tag beckn-onix:latest registry.example.com/beckn-onix:v1.0.0

Docker Compose Setup

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: vault:1.15
    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:
      - "8080:8080"
    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:/app/plugins
    command: ["./server", "--config=/app/config/docker.yaml"]

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

Run with:

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
curl -X POST http://localhost:8081/bap/caller/search \
  -H "Content-Type: application/json" \
  -H "Authorization: Signature keyId=\"test.bap.com|key1|ed25519\",algorithm=\"ed25519\",created=\"$(date +%s)\",expires=\"$(date -d '+5 minutes' +%s)\",headers=\"(created) (expires) digest\",signature=\"test-signature\"" \
  -d '{
    "context": {
      "domain": "nic2004:52110",
      "country": "IND",
      "city": "std:080",
      "action": "search",
      "core_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
ab -n 1000 -c 10 -p search.json -T application/json \
  -H "Authorization: Signature keyId=\"test|key1|ed25519\",..." \
  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
./build-plugins.sh

# Check plugin files exist
ls -la plugins/

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

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",
    "core_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",
    "core_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",
    "core_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",
    "core_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

All requests must include proper authorization:

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

Example generation in bash:

#!/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! 🚀