A Helm chart for deploying OpenPanel analytics platform on Kubernetes.
- Kubernetes 1.19+
- Helm 3.0+
- kubectl configured to access your cluster
helm repo add openpanel https://yashGoyal40.github.io/openpanel
helm repo updatevalues.yaml. The chart includes placeholder values (marked with <>) that will cause the installation to fail if not properly configured.
Create a custom values file or download the default values:
helm show values openpanel/openpanel > my-values.yamlThen edit my-values.yaml with your configuration (see Required Configuration below).
helm install my-openpanel openpanel/openpanel --version 0.6.0 --namespace openpanel --create-namespace -f my-values.yamlOr if you want to override specific values directly:
helm install my-openpanel openpanel/openpanel --version 0.6.0 --namespace openpanel --create-namespace \
--set ingress.fqdn=your-domain.com \
--set config.apiUrl=https://your-domain.com/api \
--set secrets.cookieSecret=$(openssl rand -base64 32)Here's a minimal example configuration file (my-values.yaml) with all required values:
# Ingress Configuration
ingress:
enabled: true
type: standard # or "httpproxy" for Contour
fqdn: analytics.example.com
standard:
className: nginx
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod" # For Let's Encrypt
# tlsSecretName: openpanel-tls # Optional: Only needed for manual TLS certs
# Application URLs
config:
apiUrl: "https://analytics.example.com/api"
dashboardUrl: "https://analytics.example.com"
googleRedirectUri: "https://analytics.example.com/api/oauth/google/callback"
# Cookie Secret (generate with: openssl rand -base64 32)
secrets:
cookieSecret: "YOUR_GENERATED_SECRET_HERE"
# PostgreSQL - Using External Database
postgresql:
enabled: false
externalPostgresql:
host: "postgres.example.com"
port: 5432
user: "openpanel"
password: "your-secure-password"
database: "openpanel"
schema: publicThen install with:
helm install my-openpanel openpanel/openpanel --version 0.6.0 --namespace openpanel --create-namespace -f my-values.yamlThe following values MUST be configured before installation. These are marked with <> placeholders in the default values.yaml and will prevent the chart from working correctly if left unchanged.
Configure your fully qualified domain name (FQDN) and TLS settings:
ingress:
enabled: true
type: httpproxy # or "standard" for nginx/traefik
fqdn: your-domain.com # Replace <fqdn> with your actual domain
# For HTTPProxy (Contour)
httpproxy:
tlsSecretName: openpanel-tls # Optional: Only needed for manual TLS certs
# For standard Ingress
standard:
className: nginx
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod" # For Let's Encrypt via cert-manager
# tlsSecretName: openpanel-tls # Optional: Leave empty/unset when using cert-manager/Let's EncryptTLS Configuration Options:
-
Using cert-manager/Let's Encrypt (Recommended):
- Leave
tlsSecretNameempty or unset - Add the
cert-manager.io/cluster-issuerannotation (as shown above) - cert-manager will automatically create and manage the TLS certificate
- Leave
-
Using Manual TLS Certificate:
- Set
tlsSecretNameto your existing Kubernetes secret name - Ensure the secret exists in the same namespace before installation
- Set
Examples:
fqdn: analytics.example.com- For cert-manager: Leave
tlsSecretNameunset (or commented out) - For manual certs:
tlsSecretName: openpanel-tls
Configure the API and Dashboard URLs to match your ingress FQDN:
config:
apiUrl: "https://your-domain.com/api" # Replace <fqdn> with your domain
dashboardUrl: "https://your-domain.com" # Replace <fqdn> with your domain
googleRedirectUri: "https://your-domain.com/api/oauth/google/callback" # Replace <fqdn>Example:
config:
apiUrl: "https://analytics.example.com/api"
dashboardUrl: "https://analytics.example.com"
googleRedirectUri: "https://analytics.example.com/api/oauth/google/callback"Generate a secure random string for session management:
openssl rand -base64 32Then set it in values.yaml:
secrets:
cookieSecret: "YOUR_GENERATED_SECRET_HERE" # Replace CHANGE_ME_GENERATE_A_RANDOM_32_CHAR_STRINGIf you have an existing PostgreSQL database:
postgresql:
enabled: false
externalPostgresql:
host: "postgres.example.com" # Replace <postgres_host>
port: 5432
user: "openpanel" # Replace <postgres_user>
password: "your-secure-password" # Replace <postgres_password>
database: "openpanel" # Replace <database_name>
schema: publicTo deploy PostgreSQL within Kubernetes:
postgresql:
enabled: true
user: postgres
password: "your-secure-password" # Change from default!
database: postgres
persistence:
size: 20GiexternalPostgresql section.
If you want to enable email functionality (password resets, invitations, etc.):
secrets:
resendApiKey: "re_xxxxxxxxxxxxx" # Replace <resend_api_key> with your Resend API key
emailSender: "noreply@your-domain.com" # Replace <email_sender> with your verified sender emailGetting a Resend API Key:
- Sign up at resend.com
- Create an API key in the dashboard
- Verify your sender email domain
- Add the API key and sender email to your values
If you want to enable AI-powered features:
config:
aiModel: "gpt-4o-mini" # Options: gpt-4o, gpt-4o-mini, claude-3-5
secrets:
openaiApiKey: "sk-xxxxxxxxxxxxx" # Replace <openai_api_key> for OpenAI models
anthropicApiKey: "" # Leave empty if not using Anthropic/Claude models
geminiApiKey: "" # Leave empty if not using Gemini modelsImportant Notes:
- You only need to configure the API key for the model you choose:
- For
gpt-4oorgpt-4o-mini: ConfigureopenaiApiKey - For
claude-3-5: ConfigureanthropicApiKey
- For
- You can leave
anthropicApiKeyandgeminiApiKeyempty (as empty strings"") if you don't want to use those features - Only configure the API keys for the AI providers you plan to use
If you want to enable Google OAuth login:
secrets:
googleClientId: "xxxxx.apps.googleusercontent.com" # Replace <google_client_id>
googleClientSecret: "GOCSPX-xxxxxxxxxxxxx" # Replace <google_client_secret>Setting up Google OAuth:
- Go to Google Cloud Console
- Create a new OAuth 2.0 Client ID
- Add authorized redirect URI:
https://your-domain.com/api/oauth/google/callback - Copy the Client ID and Client Secret to your values
| Configuration | Required | Placeholder | Description |
|---|---|---|---|
ingress.fqdn |
✅ Yes | <fqdn> |
Your domain name |
ingress.*.tlsSecretName |
<tls_secret_name> |
TLS certificate secret name (optional when using cert-manager/Let's Encrypt) | |
config.apiUrl |
✅ Yes | <fqdn> |
Full API URL |
config.dashboardUrl |
✅ Yes | <fqdn> |
Full Dashboard URL |
config.googleRedirectUri |
✅ Yes | <fqdn> |
OAuth callback URL |
secrets.cookieSecret |
✅ Yes | CHANGE_ME_... |
Session encryption key |
externalPostgresql.host |
<postgres_host> |
PostgreSQL hostname | |
externalPostgresql.user |
<postgres_user> |
PostgreSQL username | |
externalPostgresql.password |
<postgres_password> |
PostgreSQL password | |
externalPostgresql.database |
<database_name> |
PostgreSQL database name | |
secrets.resendApiKey |
❌ Optional | <resend_api_key> |
Resend API key for emails (leave empty "" if not using) |
secrets.emailSender |
❌ Optional | <email_sender> |
Verified sender email (leave empty "" if not using) |
secrets.openaiApiKey |
❌ Optional | <openai_api_key> |
OpenAI API key (leave empty "" if not using OpenAI) |
secrets.anthropicApiKey |
❌ Optional | <anthropic_api_key> |
Anthropic API key (leave empty "" if not using Anthropic/Claude) |
secrets.geminiApiKey |
❌ Optional | <gemini_api_key> |
Gemini API key (leave empty "" if not using Gemini) |
secrets.googleClientId |
❌ Optional | <google_client_id> |
Google OAuth Client ID (leave empty "" if not using) |
secrets.googleClientSecret |
❌ Optional | <google_client_secret> |
Google OAuth Client Secret (leave empty "" if not using) |
Redis is enabled by default and will be deployed within Kubernetes. To use an external Redis instance:
redis:
enabled: false
externalRedis:
host: "redis.example.com" # Replace with your Redis host
port: 6379ClickHouse is enabled by default and will be deployed within Kubernetes. To use an external ClickHouse instance:
clickhouse:
enabled: false
externalClickhouse:
host: "clickhouse.example.com" # Replace with your ClickHouse host
port: 8123
database: openpanelYou can enable/disable individual components:
api:
enabled: true
replicas: 1
dashboard:
enabled: true
replicas: 1
worker:
enabled: true
replicas: 1Adjust resource requests and limits based on your cluster capacity:
api:
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "2000m"Enable automatic scaling of pods based on CPU and memory utilization. HPA can be configured for the API, Dashboard, and Worker components.
Prerequisites:
- Kubernetes Metrics Server must be installed in your cluster
- Resource requests must be set for the pods (see Resource Limits above)
Basic HPA Configuration:
api:
hpa:
enabled: true
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
dashboard:
hpa:
enabled: true
minReplicas: 1
maxReplicas: 5
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
worker:
hpa:
enabled: true
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80HPA Configuration Options:
| Option | Description | Default |
|---|---|---|
enabled |
Enable/disable HPA for the component | false |
minReplicas |
Minimum number of pods | 1 |
maxReplicas |
Maximum number of pods | 10 |
targetCPUUtilizationPercentage |
Target CPU utilization percentage (optional) | 70 |
targetMemoryUtilizationPercentage |
Target memory utilization percentage (optional) | 80 |
Important Notes:
- HPA requires resource requests to be set on pods. Make sure you've configured
resources.requestsfor the component. - If both CPU and memory targets are set, HPA will scale when either threshold is exceeded.
- For production environments, consider setting
minReplicasto 2 or higher for high availability.
If your Kubernetes cluster has tainted nodes, you can configure tolerations for each component to allow pods to be scheduled on those nodes:
# Example: Allow API pods to run on nodes with a dedicated taint
api:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "api"
effect: "NoSchedule"
# Example: Allow PostgreSQL pods to run on database-dedicated nodes
postgresql:
tolerations:
- key: "database"
operator: "Equal"
value: "postgresql"
effect: "NoSchedule"
# Example: Multiple tolerations for ClickHouse
clickhouse:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "analytics"
effect: "NoSchedule"
- key: "workload"
operator: "Equal"
value: "heavy"
effect: "NoExecute"Available components:
api.tolerations- Tolerations for API podsdashboard.tolerations- Tolerations for Dashboard podsworker.tolerations- Tolerations for Worker podspostgresql.tolerations- Tolerations for PostgreSQL podsredis.tolerations- Tolerations for Redis podsclickhouse.tolerations- Tolerations for ClickHouse pods
Toleration effects:
NoSchedule- Pods will not be scheduled on tainted nodes unless they have a matching tolerationPreferNoSchedule- Kubernetes will try to avoid scheduling pods on tainted nodes, but it's not requiredNoExecute- Pods already running on the node will be evicted if they don't have a matching toleration
You can configure pod affinity and anti-affinity rules to control pod scheduling based on node labels or other pods:
# Example: Schedule API pods only on nodes with specific label
api:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: app
operator: In
values:
- openpanel
# Example: Schedule PostgreSQL pods with node affinity
postgresql:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: app
operator: In
values:
- openpanel
# Example: Pod anti-affinity to spread pods across nodes
api:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- openpanel-api
topologyKey: kubernetes.io/hostnameAvailable components:
api.affinity- Affinity rules for API podsdashboard.affinity- Affinity rules for Dashboard podsworker.affinity- Affinity rules for Worker podspostgresql.affinity- Affinity rules for PostgreSQL podsredis.affinity- Affinity rules for Redis podsclickhouse.affinity- Affinity rules for ClickHouse pods
Affinity types:
nodeAffinity- Control which nodes pods can be scheduled on based on node labelspodAffinity- Schedule pods together with other pods matching certain labelspodAntiAffinity- Avoid scheduling pods together with other pods matching certain labels
To upgrade to a newer version:
helm repo update
helm upgrade my-openpanel openpanel/openpanel --version <new-version> --namespace openpanel -f my-values.yamlReplace <new-version> with the desired version number (e.g., 0.1.1).
To uninstall OpenPanel:
helm uninstall my-openpanel --namespace openpanelkubectl get pods -n openpanel# API logs
kubectl logs -f deployment/op-api -n openpanel
# Dashboard logs
kubectl logs -f deployment/op-dashboard -n openpanel
# Worker logs
kubectl logs -f deployment/op-worker -n openpanelkubectl get svc -n openpanelkubectl get configmap openpanel-config -n openpanel -o yaml
kubectl get secret openpanel-secrets -n openpanel -o yamlSee values.yaml for all available configuration options with detailed comments.
For issues and questions, please refer to the OpenPanel documentation or create an issue in the repository. https://github.com/yashGoyal40/openpanel