Setup GuideInstallation

Installation

This guide shows how to install SRExpert on your Kubernetes cluster using Helm.

Prerequisites

Before starting, make sure you have:

  • Kubernetes cluster running (v1.25+)
  • kubectl configured and connected to the cluster
  • helm installed (v3.x)
  • Namespace created for SRExpert
  • StorageClass configured for Persistent Volumes

1. Add Helm Repository

helm repo add srexpert-helm https://nexus.srexpert.io/repository/srexpert-helm/
helm repo update

2. Create Namespace

kubectl create namespace srexpert

3. Configure Values

Backend (values-backend.yaml)

Create a values-backend.yaml file with backend settings:

values-backend.yaml
# Default values for srexpert-backend (Production)
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
 
replicaCount: 1
 
image:
  repository: registry.srexpert.io/srexpert/backend
  pullPolicy: Always
  # Overrides the image tag whose default is the chart appVersion.
  tag: "latest"
 
# Nexus Registry credentials (optional - creates secret automatically)
# Set create: true and provide credentials to auto-create the imagePullSecret
imageCredentials:
  create: false
  name: nexus-registry
  registry: registry.srexpert.io
 
# imagePullSecrets - uncomment if using private registry
# imagePullSecrets:
#   - name: nexus-registry
imagePullSecrets: []
 
nameOverride: ""
fullnameOverride: ""
 
serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  name: "srexpert-backend"
 
podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 2000
  seccompProfile:
    type: RuntimeDefault
 
securityContext:
  allowPrivilegeEscalation: false
  runAsNonRoot: true
  runAsUser: 1000
  capabilities:
    drop:
    - ALL
  seccompProfile:
    type: RuntimeDefault
 
service:
  type: ClusterIP
  port: 8000
  targetPort: 8000
 
ingress:
  enabled: false
  className: "nginx"
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
    nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"
    nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
    nginx.ingress.kubernetes.io/websocket-services: "srexpert-backend"
    # Real client IP forwarding (SD-145)
    nginx.ingress.kubernetes.io/use-forwarded-headers: "true"
    nginx.ingress.kubernetes.io/compute-full-forwarded-for: "true"
    nginx.ingress.kubernetes.io/forwarded-for-header: "X-Forwarded-For"
  hosts:
    - host: srexpert-api.yourdomain.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: srexpert-backend-tls
      hosts:
        - srexpert-api.yourdomain.com
 
resources:
  limits:
    cpu: 1000m
    memory: 3Gi
  requests:
    cpu: 500m
    memory: 2Gi
 
livenessProbe:
  httpGet:
    path: /api/v1/health
    port: 8000
  initialDelaySeconds: 60
  periodSeconds: 30
  failureThreshold: 5
 
readinessProbe:
  httpGet:
    path: /api/v1/health
    port: 8000
  initialDelaySeconds: 10
  periodSeconds: 10
  failureThreshold: 3
 
volumes:
  helmCache:
    enabled: true
 
# Environment variables
env:
  environment: "production"
  logLevel: "error"
  database:
    # When postgresql.enabled=true, use: srexpert-backend-postgresql (subchart service)
    # When using external DB, use: postgresql.dbs.svc.cluster.local
    host: "srexpert-backend-postgresql"
    port: "5432"
    name: "srexpert"
  redis:
    # When customRedis.enabled=true, use: srexpert-backend-redis (custom deployment)
    # When redis.enabled=true (Bitnami), use: srexpert-backend-redis-master
    url: "redis://srexpert-backend-redis:6379"
  encryptionKey: "SOME_KEY"
  nextPublicApiBaseUrl: "https://srexpert-frontend.srexpert-dev.svc.cluster.local/api/v1"
  accessTokenExpireMinutes: "480"
  backofficeApiUrl: "https://backoffice-api.srexpert.io" #Not change this endpoint
  frontendUrl: "https://srexpert.yourdomain.com"  # IMPORTANT: Must match your actual frontend domain
  # Cookie Security Settings
  # Set cookieSecure to "false" for HTTP-only environments (NodePort, local dev without TLS)
  # Set cookieSecure to "true" for HTTPS environments (Ingress with TLS)
  cookieSecure: "false"  # Default false for local/NodePort - change to "true" for production with HTTPS
  cookieSamesite: "lax"  # Options: "strict", "lax", "none"
  helm:
    cacheHome: "/tmp/.helm/cache"
    configHome: "/tmp/.helm/config"
    dataHome: "/tmp/.helm/data"
 
  # Pod Management Configuration
  podManagement:
    maxIdleTimeHours: "8"
    cleanupIntervalMinutes: "30"
    terminationGracePeriod: "120"
 
  # IA Terminal Configuration
  iaTerminal:
    namespace: "srexpert"
    image: "registry.srexpert.io/srexpert/ia-terminal:latest"
    serviceAccount: "srexpert-backend"
    backendServiceUrl: "http://srexpert-backend.srexpert.svc.cluster.local:8000"
    allowTlsInsecure: "false"
    allowedOrigins: '["https://srexpert.yourdomain.com","https://app.yourdomain.com"]'
    wsRateLimit: "20/min"
    wsIdleTimeout: "300"
    sseHeartbeatInterval: "20"
    # Pod Resource Configuration
    resources:
      requests:
        memory: "1Gi"
        cpu: "500m"
        ephemeralStorage: "2Gi"
      limits:
        memory: "4Gi"
        cpu: "2"
        ephemeralStorage: "10Gi"
 
  # Redis Advanced Configuration
  redisConfig:
    db: "0"
    sessionEnabled: "true"
    cacheEnabled: "true"
    pubsubEnabled: "true"
 
  # Cache TTL Settings (seconds)
  cacheTtl:
    short: "300"
    medium: "1800"
    long: "3600"
    metrics: "60"
    workloads: "120"
 
  # Security - API Key Encryption (should be different from encryptionKey)
  apiKeyEncryptionSecret: "CHANGE-IN-PRODUCTION-32-CHARS-MIN-KEY-HERE"
 
# Secrets configuration
secrets:
  database:
    name: srexpert-database
    postgresUser: postgres
    postgresPassword: postgres123
    redisPassword: srexpert-redis
    rabbitmqPassword: srexpert-rabbitmq
  jwt:
    name: srexpert-jwt
    secretKey: "srexpert-jwt-secret-key-change-in-production-please-32-chars-min"
  integrations:
    name: srexpert-integrations
    slackWebhookUrl: ""
    teamsWebhookUrl: ""
    emailSmtpPassword: ""
 
# RBAC configuration
rbac:
  create: true
  clusterAdmin: true
 
# Init DB Job configuration
initDb:
  enabled: true
  image:
    repository: registry.srexpert.io/srexpert/backend
    tag: "latest"
  resources:
    requests:
      memory: "512Mi"
      cpu: "500m"
    limits:
      memory: "1Gi"
      cpu: "1"
 
autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 5
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80
 
# PostgreSQL subchart configuration (Bitnami)
postgresql:
  enabled: true  # Set to true to deploy PostgreSQL with this chart
  image:
    registry: registry.srexpert.io
    repository: dependencies/postgresql
    tag: "17.0.0"
  auth:
    username: postgres
    password: postgres123
    database: srexpert
    enablePostgresUser: true
    postgresPassword: postgres123
  primary:
    persistence:
      enabled: true
      size: 8Gi
    resources:
      requests:
        memory: "256Mi"
        cpu: "250m"
      limits:
        memory: "512Mi"
        cpu: "500m"
 
# Custom Redis configuration (standalone deployment)
# Use this instead of Bitnami subchart for simpler setups
customRedis:
  enabled: true  # Set to true to deploy a simple Redis alongside the backend
  image: registry.srexpert.io/dependencies/redis:7.2-alpine
  resources:
    requests:
      memory: "128Mi"
      cpu: "100m"
    limits:
      memory: "256Mi"
      cpu: "200m"
 
# Redis subchart configuration (Bitnami) - disabled, using customRedis
redis:
  enabled: false
  auth:
    password: srexpert-redis
  master:
    persistence:
      enabled: true
      size: 2Gi
    resources:
      requests:
        memory: "128Mi"
        cpu: "100m"
      limits:
        memory: "256Mi"
        cpu: "200m"
 
nodeSelector: {}
tolerations: []
affinity: {}
!

Critical Configuration: frontendUrl

The frontendUrl field in values-backend.yaml must match the exact domain where your SRExpert frontend is accessible (e.g., https://srexpert.yourdomain.com).

This URL is used by the backend to generate links in emails (password recovery, invitations, notifications) and in the payment flow (Stripe redirect URLs). If misconfigured:

  • Password recovery emails will contain broken links
  • Payment checkout will fail to redirect back to your application
  • Team invitation links will not work

Make sure it uses https:// and does not include a trailing slash.

Frontend (values-frontend.yaml)

Create a values-frontend.yaml file:

values-frontend.yaml
# Default values for srexpert-frontend
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
 
replicaCount: 1
 
image:
  repository: registry.srexpert.io/srexpert/frontend
  pullPolicy: Always
  tag: "latest"
 
# Docker registry credentials for pulling images
imageCredentials:
  create: false
 
nameOverride: ""
fullnameOverride: ""
 
serviceAccount:
  create: true
  annotations: {}
  name: "srexpert-frontend"
 
podAnnotations:
  kubectl.kubernetes.io/restartedAt: "2025-09-22T19:30:00Z"
 
podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 2000
  seccompProfile:
    type: RuntimeDefault
 
securityContext:
  allowPrivilegeEscalation: false
  runAsNonRoot: true
  runAsUser: 1001
  capabilities:
    drop:
    - ALL
  seccompProfile:
    type: RuntimeDefault
 
service:
  type: ClusterIP
  port: 3000
  targetPort: 3000
 
ingress:
  enabled: true
  className: "nginx"
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
  hosts:
    - host: srexpert.yourdomain.com
      paths:
        - path: /api/v1/
          pathType: Prefix
          backend: srexpert-backend
          backendPort: 8000
        - path: /
          pathType: Prefix
  tls:
    - secretName: srexpert-frontend-tls
      hosts:
        - srexpert.yourdomain.com
 
resources:
  limits:
    cpu: 1000m
    memory: 3Gi
  requests:
    cpu: 500m
    memory: 2Gi
 
livenessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 60
  periodSeconds: 30
  timeoutSeconds: 10
  failureThreshold: 5
 
readinessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 30
  periodSeconds: 10
  timeoutSeconds: 5
  failureThreshold: 5
 
startupProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 0
  periodSeconds: 10
  timeoutSeconds: 5
  failureThreshold: 30
 
# Environment variables
env:
  nodeEnv: "production"
  backendUrl: "http://srexpert-backend:8000"
  nextPublicApiBaseUrl: "/api/v1"
  nextPublicBackendUrl: ""
  nextTelemetryDisabled: "1"
  # Backoffice API URL for registration/payment flow (runtime configurable)
  backofficeApiUrl: "https://backoffice-api.srexpert.io"
  # Cookie security (secure flag) is auto-detected based on request protocol (HTTP vs HTTPS)
  # No manual configuration needed - works automatically in any environment
 
autoscaling:
  enabled: false
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80
 
nodeSelector: {}
 
tolerations: []
 
affinity: {}

4. Install Backend

helm upgrade --install srexpert-backend srexpert-helm/srexpert-backend \
  --namespace srexpert \
  -f values-backend.yaml

Wait for PostgreSQL and Backend to be ready:

kubectl get pods -n srexpert -w

5. Install Frontend

helm upgrade --install srexpert-frontend srexpert-helm/srexpert-frontend \
  --namespace srexpert \
  -f values-frontend.yaml

6. Verify Installation

# Check pods
kubectl get pods -n srexpert
 
# Check services
kubectl get svc -n srexpert
 
# Check ingress
kubectl get ingress -n srexpert
 
# View backend logs
kubectl logs -n srexpert -l app.kubernetes.io/name=srexpert-backend --tail=100

Persistent Volumes

SRExpert uses Persistent Volumes for:

ComponentUsageRecommended Size
PostgreSQLDatabase data10Gi+
RedisCache (optional)2Gi
Helm CacheChart cache5Gi

Check PVCs

kubectl get pvc -n srexpert

Manual PVC Example (if needed)

pvc-postgresql.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-srexpert-backend-postgresql-0
  namespace: srexpert
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: default

Troubleshooting

Pod not starting

# View events
kubectl describe pod -n srexpert <pod-name>
 
# View logs
kubectl logs -n srexpert <pod-name> --previous

ImagePull Error

Check if registry secret was created:

kubectl get secret nexus-registry -n srexpert

Database not connecting

Check if PostgreSQL is running:

kubectl get pods -n srexpert -l app.kubernetes.io/name=postgresql

Next Steps

After installation, continue to: