Skip to content
GitHub

Helm & Kubernetes

This guide explains how to deploy Rafiki using Helm charts on a Kubernetes cluster. Helm is a package manager for Kubernetes that allows you to define, install, and upgrade complex Kubernetes applications through Helm charts.

Rafiki uses the following key infrastructure components:

  • PostgreSQL : Used for storing application data, grants, and Open Payments resources
  • Redis : Used for caching and session management
  • TigerBeetle (recommended): High-performance accounting database for financial transaction processing and ledger management

Before you begin, ensure you have the following:

Before installing Rafiki, ensure your target Kubernetes cluster already has Redis and PostgreSQL deployed.

  • PostgreSQL must be initialized with two databases: one for the backend service and one for the auth service
  • Each service must be configured with a connection URL that points to its corresponding database

Add the official Interledger Helm repository which contains the Rafiki charts:

Terminal window
helm repo add interledger-helm https://interledger.github.io/charts/interledger
helm repo update

You can list the available Rafiki charts:

Terminal window
helm search repo interledger-helm/rafiki

This returns available chart versions, including the main interledger-helm/rafiki chart.

Create a single values.yaml file to customize your Rafiki deployment.

Configure the following required values:

  • config.auth.redisUrl.value
  • config.auth.databaseUrl.value
  • config.backend.redisUrl.value
  • config.backend.databaseUrl.value
  • config.auth.tenancy.tenantId
  • config.backend.tenancy.tenantId
  • config.auth.identityServer.serverSecret.value
  • config.backend.ilp.streamSecret.value
  • config.backend.webhookSignatureSecret.value
  • config.frontend.kratos.enabled

When using --set config.auth.shouldCreateSecrets=true and --set config.backend.shouldCreateSecrets=true, Helm creates and manages the auth and backend Kubernetes secrets as part of the chart installation.

In this mode, include the required secret values in values.yaml so the chart can populate those generated secrets during install/upgrade:

config:
auth:
identityServer:
serverSecret:
value: your-identity-server-secret
backend:
ilp:
streamSecret:
value: your-stream-secret
webhookSignatureSecret:
value: your-webhook-signature-secret

If you prefer to pre-create Kubernetes secrets manually, set both config.auth.shouldCreateSecrets and config.backend.shouldCreateSecrets to false and configure secretKeyRef values in values.yaml.

Install Rafiki using the following command:

Terminal window
helm install rafiki interledger-helm/rafiki -f values.yaml \
--set config.auth.shouldCreateSecrets=true \
--set config.backend.shouldCreateSecrets=true

If you want to install to a specific namespace:

Terminal window
kubectl create namespace rafiki
helm install rafiki interledger-helm/rafiki -f values.yaml \
--set config.auth.shouldCreateSecrets=true \
--set config.backend.shouldCreateSecrets=true \
-n rafiki

The namespace used for Rafiki must match the namespace used by your Redis and PostgreSQL services.

Check the status of your deployments:

Terminal window
# Check Helm releases
helm list
# Check running pods
kubectl get pods
# Check deployed services
kubectl get services
# Check logs for any issues
kubectl logs -l app.kubernetes.io/name=rafiki-auth
kubectl logs -l app.kubernetes.io/name=rafiki-backend
kubectl logs -l app.kubernetes.io/name=rafiki-frontend

Each Rafiki service can be configured via environment variables through Helm values. Below are the complete environment variable configurations for each service:

Auth service

The Rafiki auth service is responsible for handling Open Payments authorization and grant management. It implements the Open Payments authorization server specification and manages access tokens, grants, and interactions. The auth service connects to a PostgreSQL database to store grant-related data and uses Redis for session management.

Ports exposed:

  • 3003 (admin) - Auth Admin API for managing grants and access tokens
  • 3006 (auth) - Open Payments authorization server endpoint
  • 3007 (introspection) - Access token introspection endpoint
  • 3009 (interaction) - User interaction endpoint for grant flows
Helm variable nameDefaultDescription
config.auth.databaseUrl.value''The URL of the PostgreSQL database storing your Open Payments grant data.
config.auth.redisUrl.value''The connection URL of Redis used for session/cache operations.
config.auth.authServerUrlhttp://rafiki-auth:3006The public endpoint for your Rafiki instance’s public Open Payments auth routes.
config.auth.cookieKey.value"changeme"The koa KeyGrip key that’s used to sign cookies for an interaction session.
config.auth.identityServer.domainhttp://rafiki-backend/idpThe URL of your identity provider (IdP) server, used by the authorization server to tell an Open Payments client where to redirect the end-user to start interactions.
config.auth.identityServer.serverSecret.value''A shared secret between the authorization server and the identity provider (IdP); the authorization server uses the secret to secure its IdP-related endpoints.
When the IdP sends requests to the authorization server, it must provide the secret via an x-idp-secret header.
Helm value nameDefaultDescription
config.auth.trustProxytrueMust be set to true when running Rafiki behind a proxy. When true, the X-Forwarded-Proto header is used to determine if connections are secure.
config.auth.tenancy.tenantIdsome-guidThe tenant identifier for the operator tenant. Should match config.backend.tenancy.tenantId.
Helm value nameDefaultDescription
config.auth.shouldCreateSecretsfalseIf true, chart-managed auth secrets are created from secretsMaps.auth.
config.auth.accessToken.deletionDays30The days until expired and/or revoked access tokens are deleted.
config.auth.accessToken.expirySeconds600 (10 minutes)The expiry time, in seconds, for access tokens.
config.auth.admin.signatureVersion1The version of the request signing algorithm used to validate signatures.
config.auth.admin.signatureTtlSeconds30The TTL, in seconds, for which a request signature is valid.
config.auth.port.admin3003The port of your Rafiki Auth Admin API server.
config.auth.port.auth3006The port of your Open Payments authorization server.
config.auth.port.interaction3009The port number of your Open Payments interaction-related APIs.
config.auth.port.introspection3007The port of your Open Payments access token introspection server.
config.auth.workers.cleanup1The number of workers processing expired or revoked access tokens.
config.auth.interaction.incomingPayment"false"When "true", incoming Open Payments grant requests are interactive.
config.auth.interaction.expirySeconds600 (10 minutes)The time, in seconds, for which a user can interact with a grant request before the request expires.
config.auth.interaction.quote"false"When "true", quote grants are interactive.
config.auth.logLevelinfoPino log level.
config.auth.nodeEnvproductionThe type of node environment: development, test, or production.
config.auth.grant.waitSeconds5The wait time, in seconds, included in a grant request response (grant.continue).
Backend service

The Rafiki backend service handles the core Open Payments capabilities and business logic. It exposes the Open Payments resource server APIs for wallet addresses, incoming payments, outgoing payments, and quotes. The backend also includes an ILP connector for sending and receiving Interledger packets. It connects to PostgreSQL for storing Open Payments resources, Redis for caching, and optionally TigerBeetle for high-performance accounting.

Ports exposed:

  • 3000 (openPayments) - Open Payments resource server API
  • 3001 (admin) - Backend Admin API and GraphQL endpoint
  • 3002 (connector) - ILP connector for sending and receiving packets
  • 3005 (autoPeering) - Autopeering service (when enabled)
Helm value nameDefaultDescription
config.backend.auth.grantUrlhttp://rafiki-auth.rafiki-auth:3006The endpoint on your Open Payments authorization server to grant a request.
config.backend.auth.introspectionUrlhttp://rafiki-auth.rafiki-auth:3007The endpoint on your Open Payments authorization server to introspect an access token.
config.backend.databaseUrl.value''The PostgreSQL database URL of the database storing your resource data.
config.backend.redisUrl.value''The Redis URL used for queue, cache, and connector state.
config.backend.ilp.hosthttp://rafiki-backend:3000The public endpoint of your Open Payments resource server.
config.backend.ilp.addresstest.rafiki-backendThe ILP address of your Rafiki instance.
config.backend.ilp.connectorhttp://rafiki-backend:3002The ILP connector address where ILP packets are received.
config.backend.key.idrafiki-override-this-valueYour Rafiki instance’s client key ID.
config.backend.webhook.urlhttp://wallet/webhooks/rafikiYour endpoint that consumes webhook events.
config.backend.ilp.streamSecret.value''The seed secret to generate shared STREAM secrets.
config.backend.webhookSignatureSecret.value''The secret used to generate webhook request signatures.
Helm value nameDefaultDescription
config.backend.instanceNamerafiki-backend-changemeYour Rafiki instance name used for automatic peering and/or telemetry. Required when either feature is enabled.
config.backend.trustProxy"true"Must be set to true when running Rafiki behind a proxy. When true, the X-Forwarded-Proto header is used to determine if connections are secure.
config.backend.tenancy.tenantIdsome-guidThe tenant identifier for the operator tenant. Should match config.auth.tenancy.tenantId.
Helm value nameDefaultDescription
config.backend.shouldCreateSecretsfalseIf true, chart-managed backend secrets are created from secretsMaps.backend.
config.backend.port.admin3001The port of your Backend Admin API server.
config.backend.port.connector3002The port of the ILP connector for sending packets via ILP over HTTP.
config.backend.port.openPayments3000The port of your Open Payments resource server.
config.backend.port.autoPeering3005If automatic peering is enabled, the server uses this port.
config.backend.autoPeering.enabled"false"When "true", automatic peering is enabled.
config.backend.telemetry.enabled"false"When "true", telemetry is enabled.
config.backend.useTigerbeetlefalseWhen true, TigerBeetle is used for accounting.
config.backend.rates.url''The endpoint your Rafiki instance uses to request exchange rates.
config.backend.webhook.timeout200The time, in milliseconds, for wallet-address worker webhook polling timeout behavior.
config.backend.ilp.slippage0.01The accepted ILP rate fluctuation.
config.backend.key.mount/mnt/keys/pvk.pemThe mounted path to your Rafiki instance private key file.
config.backend.idempotency.keyTTL86400000The TTL, in milliseconds, for idempotency keys on Backend Admin API mutations.
config.backend.idempotency.keyLock2000The TTL, in milliseconds, for idempotency key lock concurrency control.
config.backend.workerIdle200The time, in milliseconds, workers wait before polling an empty queue again.
config.backend.workers.incomingPayment1The number of workers processing incoming payment requests.
config.backend.workers.outgoingPayment1The number of workers processing outgoing payment requests.
config.backend.workers.walletAddress1The number of workers processing wallet address requests.
config.backend.workers.webhook1The number of workers processing webhook events.
config.backend.lifetime.exchangeRate15000The time, in milliseconds, that exchange rates from config.backend.rates.url are considered valid.
config.backend.lifetime.quote300000The time, in milliseconds, an Open Payments quote is valid for.
config.backend.lifetime.webhook200The time, in milliseconds, to wait for a 200 response from your webhook endpoint before retry.
config.backend.withdrawalThrottleDelay''The delay in liquidity withdrawal processing.
config.backend.logLevelinfoPino log level.
config.backend.nodeEnvproductionThe type of node environment: development, test, or production.
Frontend service

The Rafiki frontend service provides an administrative web interface for managing your Rafiki instance. It offers a user-friendly dashboard for monitoring and managing wallet addresses, payments, peers, and other Open Payments resources. The frontend communicates with the Backend Admin API to perform administrative operations.

Ports exposed:

  • 3010 (http) - Rafiki Admin web interface
Helm value nameDefaultDescription
config.frontend.serviceUrls.GRAPHQL_URLhttp://rafiki-backend-service.rafiki:3001/graphqlURL of Rafiki’s GraphQL Admin API
config.frontend.serviceUrls.OPEN_PAYMENTS_URLhttps://rafiki-backend-service/Your Open Payments API endpoint
config.frontend.port3010Port from which to host the Rafiki Remix app

The following values are required only when config.frontend.kratos.enabled is set to true.

Helm value nameDefaultDescription
config.frontend.kratos.enabledtrueEnables Kratos-backed authentication for the frontend.
config.frontend.kratos.adminUrlundefinedThe admin endpoint/container address for Kratos.
config.frontend.kratos.containerPublicUrlundefinedThe URL for internal backend calls to the Kratos container from within the cluster network.
config.frontend.kratos.browserPublicUrlundefinedThe browser-facing URL for Kratos, used by the Rafiki Admin UI to complete auth flows.
Helm value nameDefaultDescription
config.frontend.signatureVersion1The signature version number used for outgoing HTTP signatures to the Backend Admin API.
config.frontend.nodeEnvproductionThe type of node environment: development, test, or production.
config.frontend.logLevelinfoPino log level.

To expose Rafiki services outside the cluster, you’ll need to configure ingress. Here’s an example using NGINX Ingress Controller:

If you don’t already have an ingress controller installed:

Terminal window
# Add the ingress-nginx repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# Install the ingress controller
helm install nginx-ingress ingress-nginx/ingress-nginx \
--set controller.publishService.enabled=true

Add ingress configuration to your values.yaml file:

# In values.yaml
ingress:
backend:
enabled: true
className: nginx
hosts:
- host: rafiki-backend.your-domain.com
paths:
- path: /
pathType: Prefix
service:
name: rafiki-backend-service
port: 3000
tls:
- secretName: rafiki-backend-tls
hosts:
- rafiki-backend.your-domain.com
auth:
enabled: true
className: nginx
hosts:
- host: rafiki-auth.your-domain.com
paths:
- path: /
pathType: Prefix
service:
name: rafiki-auth-service
port: 3006
tls:
- secretName: rafiki-auth-tls
hosts:
- rafiki-auth.your-domain.com

Create DNS records pointing to your ingress controller’s external IP:

  • rafiki-backend.your-domain.com
  • rafiki-auth.your-domain.com
  • rafiki-frontend.your-domain.com

You can use an external PostgreSQL instance or deploy one using Helm:

Terminal window
# Add Bitnami repository
helm repo add bitnami https://charts.bitnami.com/bitnami
# Install PostgreSQL for the backend database
helm install rafiki-postgres bitnami/postgresql \
--set auth.postgresPassword=your-secure-password \
--set auth.database=rafiki_backend \
--set primary.persistence.size=20Gi

Then create the auth database:

Terminal window
kubectl exec -it rafiki-postgres-postgresql-0 -- psql -U postgres -d postgres -c "CREATE DATABASE rafiki_auth;"

Deploy Redis for caching and session management:

Terminal window
# Install Redis
helm install rafiki-redis bitnami/redis \
--set auth.enabled=false \
--set master.persistence.size=8Gi

For high-performance accounting, deploy TigerBeetle:

Terminal window
# Add TigerBeetle repository
helm repo add tigerbeetle https://tigerbeetle.github.io/helm-charts
# Install TigerBeetle
helm install rafiki-tigerbeetle tigerbeetle/tigerbeetle \
--set replicaCount=3 \
--set persistence.size=20Gi

To upgrade your Rafiki services to newer versions:

Terminal window
helm repo update
helm upgrade rafiki interledger-helm/rafiki -f values.yaml

To uninstall Rafiki services:

Terminal window
helm uninstall rafiki
# Optionally uninstall dependencies
helm uninstall rafiki-postgres
helm uninstall rafiki-redis

Verify that all services are running correctly:

Terminal window
# Check pod status
kubectl get pods -l app.kubernetes.io/name=rafiki-auth
kubectl get pods -l app.kubernetes.io/name=rafiki-backend
kubectl get pods -l app.kubernetes.io/name=rafiki-frontend
# Check service endpoints
kubectl get endpoints
# Check for events
kubectl get events --sort-by=.metadata.creationTimestamp
  1. Verify database connectivity:

    Terminal window
    kubectl logs -l app.kubernetes.io/name=rafiki-backend | grep -i database
  2. Check PostgreSQL status:

    Terminal window
    kubectl get pods -l app.kubernetes.io/name=postgresql
    kubectl logs -l app.kubernetes.io/name=postgresql
  3. Test database connection:

    Terminal window
    kubectl run -it --rm debug --image=postgres:14 -- psql postgresql://username:password@rafiki-postgres-postgresql:5432/rafiki_backend
  1. Check Redis status:

    Terminal window
    kubectl get pods -l app.kubernetes.io/name=redis
    kubectl logs -l app.kubernetes.io/name=redis
  2. Test Redis connectivity:

    Terminal window
    kubectl run -it --rm debug --image=redis:7 -- redis-cli -h rafiki-redis ping
  1. Verify service names and ports:

    Terminal window
    kubectl get services
    kubectl describe service rafiki-backend-service
  2. Check DNS resolution:

    Terminal window
    kubectl run -it --rm debug --image=busybox -- nslookup rafiki-backend-service
  1. Check auth service logs:

    Terminal window
    kubectl logs -l app.kubernetes.io/name=rafiki-auth
  2. Verify secrets are correctly mounted:

    Terminal window
    kubectl describe pod -l app.kubernetes.io/name=rafiki-auth
  3. Test auth endpoints:

    Terminal window
    kubectl port-forward svc/rafiki-auth-service 3007:3007
    curl http://localhost:3007/healthz
  1. Check ingress controller status:

    Terminal window
    kubectl get pods -n ingress-nginx
    kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller
  2. Verify ingress resources:

    Terminal window
    kubectl get ingress
    kubectl describe ingress rafiki-backend-ingress
  3. Check TLS certificates:

    Terminal window
    kubectl get secrets
    kubectl describe secret rafiki-backend-tls
  1. Check resource usage:

    Terminal window
    kubectl top pods
    kubectl top nodes
  2. Monitor pod metrics:

    Terminal window
    kubectl describe pod -l app.kubernetes.io/name=rafiki-backend
  3. Scale services if needed:

    Terminal window
    # Update replicaCount in values.yaml and upgrade
    helm upgrade rafiki interledger-helm/rafiki -f values.yaml
  • Use strong passwords: Replace all default passwords with cryptographically secure values
  • Enable TLS: Configure HTTPS for all external communications
  • Network policies: Implement Kubernetes network policies to restrict pod-to-pod communication
  • RBAC: Use Kubernetes Role-Based Access Control to limit cluster access
  • Secrets management: Consider using external secret management solutions like HashiCorp Vault
  • Image security: Use specific image tags and scan images for vulnerabilities
  • Pod security: Configure pod security standards and security contexts
  • Multi-replica deployments: Run multiple replicas of critical services
  • Pod disruption budgets: Configure disruption budgets to maintain availability during updates
  • Resource limits: Set appropriate CPU and memory limits
  • Health checks: Configure proper readiness and liveness probes
  • Load balancing: Use multiple ingress controller replicas
  • Prometheus: Deploy Prometheus for metrics collection
  • Grafana: Set up Grafana dashboards for visualization
  • Logging: Implement centralized logging with ELK stack or similar
  • Alerting: Configure alerting rules for critical issues
  • Distributed tracing: Consider implementing distributed tracing for request flow analysis

PostgreSQL backup:

Terminal window
# Create a backup job
kubectl create job --from=cronjob/postgres-backup manual-backup-$(date +%Y%m%d-%H%M%S)
# Manual backup
kubectl exec -it rafiki-postgres-postgresql-0 -- pg_dump -U postgres rafiki_backend > backup.sql

TigerBeetle backup:

Terminal window
# Create volume snapshots
kubectl create -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: tigerbeetle-snapshot-$(date +%Y%m%d-%H%M%S)
spec:
source:
persistentVolumeClaimName: tigerbeetle-data-0
volumeSnapshotClassName: your-snapshot-class
EOF
  • Resource allocation: Right-size CPU and memory requests/limits based on actual usage
  • Connection pooling: Configure appropriate database connection pool sizes
  • Caching: Optimize Redis configuration for your workload
  • TigerBeetle tuning: Configure TigerBeetle cluster size based on expected transaction volume
  • Rolling updates: Use rolling update strategies to maintain availability
  • Blue-green deployments: Consider blue-green deployments for zero-downtime upgrades
  • Database migrations: Plan for database schema migrations
  • Backup before upgrade: Always backup data before major upgrades
  • Testing: Test upgrades in staging environments first