mirror of
https://github.com/rtomik/helm-charts.git
synced 2026-04-14 06:01:00 +00:00
joplin-server helmchart v0.0.1
This commit is contained in:
445
charts/joplin-server/readme.md
Normal file
445
charts/joplin-server/readme.md
Normal file
@ -0,0 +1,445 @@
|
||||
# Joplin Server Helm Chart
|
||||
|
||||
A Helm chart for deploying Joplin Server on Kubernetes - Note-taking and synchronization server.
|
||||
|
||||
## Introduction
|
||||
|
||||
This chart deploys [Joplin Server](https://github.com/laurent22/joplin) on a Kubernetes cluster using the Helm package manager. Joplin Server is the synchronization server for Joplin, allowing you to sync your notes across devices.
|
||||
|
||||
Source code can be found here:
|
||||
- https://github.com/rtomik/helm-charts/tree/main/charts/joplin-server
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.19+
|
||||
- Helm 3.0+
|
||||
- **External PostgreSQL database** (Required - Joplin Server does not support SQLite in production)
|
||||
- PV provisioner support in the underlying infrastructure (if persistence is needed for file storage)
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
To install the chart with the release name `joplin-server`:
|
||||
|
||||
```bash
|
||||
$ helm repo add joplin-chart https://rtomik.github.io/helm-charts
|
||||
$ helm install joplin-server joplin-chart/joplin-server
|
||||
```
|
||||
|
||||
> **Important**: You must configure PostgreSQL database settings before installation.
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
To uninstall/delete the `joplin-server` deployment:
|
||||
|
||||
```bash
|
||||
$ helm uninstall joplin-server
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
### Global parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
|------------------------|------------------------------------------------|-------|
|
||||
| `nameOverride` | String to partially override the release name | `""` |
|
||||
| `fullnameOverride` | String to fully override the release name | `""` |
|
||||
|
||||
### Image parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
|-------------------------|-----------------------------------|--------------------|
|
||||
| `image.repository` | Joplin Server image repository | `joplin/server` |
|
||||
| `image.tag` | Joplin Server image tag | `latest` |
|
||||
| `image.pullPolicy` | Joplin Server image pull policy | `IfNotPresent` |
|
||||
|
||||
### Deployment parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
|--------------------------------------|-----------------------------------------------|-----------|
|
||||
| `replicaCount` | Number of Joplin Server replicas | `1` |
|
||||
| `revisionHistoryLimit` | Number of revisions to retain for rollback | `3` |
|
||||
| `podSecurityContext.runAsNonRoot` | Run containers as non-root user | `true` |
|
||||
| `podSecurityContext.runAsUser` | User ID for the container | `1001` |
|
||||
| `podSecurityContext.fsGroup` | Group ID for the container filesystem | `1001` |
|
||||
| `containerSecurityContext` | Security context for the container | See values.yaml |
|
||||
| `nodeSelector` | Node labels for pod assignment | `{}` |
|
||||
| `tolerations` | Tolerations for pod assignment | `[]` |
|
||||
| `affinity` | Affinity for pod assignment | `{}` |
|
||||
|
||||
### Service parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
|----------------|-----------------------|-------------|
|
||||
| `service.type` | Kubernetes Service type | `ClusterIP` |
|
||||
| `service.port` | Service HTTP port | `22300` |
|
||||
|
||||
### Ingress parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
|-------------------------|-------------------------------------------|-----------------|
|
||||
| `ingress.enabled` | Enable ingress record generation | `false` |
|
||||
| `ingress.className` | IngressClass name | `""` |
|
||||
| `ingress.annotations` | Additional annotations for the Ingress | See values.yaml |
|
||||
| `ingress.hosts` | Array of host and path objects | See values.yaml |
|
||||
| `ingress.tls` | TLS configuration | See values.yaml |
|
||||
|
||||
### Environment variables
|
||||
|
||||
| Name | Description | Value |
|
||||
|---------------------------|-----------------------------------------------|--------------------------|
|
||||
| `env.APP_PORT` | Application port | `22300` |
|
||||
| `env.APP_BASE_URL` | Base URL for the application | `http://localhost:22300` |
|
||||
| `env.DB_CLIENT` | Database client (always pg for PostgreSQL) | `pg` |
|
||||
|
||||
### PostgreSQL configuration (Required)
|
||||
|
||||
| Name | Description | Value |
|
||||
|----------------------------------------|-----------------------------------------------|-----------|
|
||||
| `postgresql.external.enabled` | Use external PostgreSQL database (required) | `true` |
|
||||
| `postgresql.external.host` | PostgreSQL host | `""` |
|
||||
| `postgresql.external.port` | PostgreSQL port | `5432` |
|
||||
| `postgresql.external.database` | PostgreSQL database name | `joplin` |
|
||||
| `postgresql.external.user` | PostgreSQL username | `joplin` |
|
||||
| `postgresql.external.password` | PostgreSQL password | `""` |
|
||||
| `postgresql.external.existingSecret` | Name of existing secret with PostgreSQL credentials | `""` |
|
||||
| `postgresql.external.userKey` | Key in the secret for username | `username` |
|
||||
| `postgresql.external.passwordKey` | Key in the secret for password | `password` |
|
||||
| `postgresql.external.hostKey` | Key in the secret for host | `host` |
|
||||
| `postgresql.external.portKey` | Key in the secret for port | `port` |
|
||||
| `postgresql.external.databaseKey` | Key in the secret for database name | `database` |
|
||||
|
||||
### Joplin Server Configuration
|
||||
|
||||
#### Admin Settings
|
||||
|
||||
| Name | Description | Value |
|
||||
|----------------------------------------|-----------------------------------------------|-----------|
|
||||
| `joplin.admin.email` | First admin user email | `""` |
|
||||
| `joplin.admin.password` | First admin user password | `""` |
|
||||
| `joplin.admin.existingSecret` | Name of existing secret with admin credentials | `""` |
|
||||
| `joplin.admin.emailKey` | Key in the secret for admin email | `admin-email` |
|
||||
| `joplin.admin.passwordKey` | Key in the secret for admin password | `admin-password` |
|
||||
|
||||
#### Server Settings
|
||||
|
||||
| Name | Description | Value |
|
||||
|-------------------------------------------|-----------------------------------------------|-----------|
|
||||
| `joplin.server.maxRequestBodySize` | Maximum request body size | `200mb` |
|
||||
| `joplin.server.sessionTimeout` | Session timeout in seconds | `86400` |
|
||||
| `joplin.server.enableUserRegistration` | Enable/disable user registration | `false` |
|
||||
| `joplin.server.enableSharing` | Enable/disable sharing | `true` |
|
||||
| `joplin.server.enablePublicNotes` | Enable/disable public notes | `true` |
|
||||
|
||||
#### Storage Settings
|
||||
|
||||
| Name | Description | Value |
|
||||
|-------------------------------------------|-----------------------------------------------|--------------|
|
||||
| `joplin.storage.driver` | Storage driver (filesystem, s3, azure) | `filesystem` |
|
||||
| `joplin.storage.filesystemPath` | Path for filesystem storage | `/var/lib/joplin` |
|
||||
|
||||
##### S3 Storage (Optional)
|
||||
|
||||
| Name | Description | Value |
|
||||
|---------------------------------------------|---------------------------------------------|-----------|
|
||||
| `joplin.storage.s3.bucket` | S3 bucket name | `""` |
|
||||
| `joplin.storage.s3.region` | S3 region | `""` |
|
||||
| `joplin.storage.s3.accessKeyId` | S3 access key ID | `""` |
|
||||
| `joplin.storage.s3.secretAccessKey` | S3 secret access key | `""` |
|
||||
| `joplin.storage.s3.endpoint` | S3 endpoint (for S3-compatible services) | `""` |
|
||||
| `joplin.storage.s3.existingSecret` | Name of existing secret with S3 credentials | `""` |
|
||||
| `joplin.storage.s3.accessKeyIdKey` | Key in the secret for access key ID | `access-key-id` |
|
||||
| `joplin.storage.s3.secretAccessKeyKey` | Key in the secret for secret access key | `secret-access-key` |
|
||||
|
||||
#### Email Settings (Optional)
|
||||
|
||||
| Name | Description | Value |
|
||||
|----------------------------------------|-----------------------------------------------|-----------|
|
||||
| `joplin.email.enabled` | Enable email notifications | `false` |
|
||||
| `joplin.email.host` | SMTP host | `""` |
|
||||
| `joplin.email.port` | SMTP port | `587` |
|
||||
| `joplin.email.username` | SMTP username | `""` |
|
||||
| `joplin.email.password` | SMTP password | `""` |
|
||||
| `joplin.email.fromEmail` | From email address | `""` |
|
||||
| `joplin.email.fromName` | From name | `Joplin Server` |
|
||||
| `joplin.email.secure` | Use TLS/SSL | `true` |
|
||||
| `joplin.email.existingSecret` | Name of existing secret with email credentials | `""` |
|
||||
| `joplin.email.usernameKey` | Key in the secret for SMTP username | `email-username` |
|
||||
| `joplin.email.passwordKey` | Key in the secret for SMTP password | `email-password` |
|
||||
|
||||
#### Logging Settings
|
||||
|
||||
| Name | Description | Value |
|
||||
|--------------------------------|--------------------------------------|-----------|
|
||||
| `joplin.logging.level` | Log level (error, warn, info, debug) | `info` |
|
||||
| `joplin.logging.target` | Log target (console, file) | `console` |
|
||||
|
||||
### Persistence settings (for filesystem storage)
|
||||
|
||||
| Name | Description | Value |
|
||||
|-------------------------------|----------------------------------|-----------------|
|
||||
| `persistence.enabled` | Enable persistence using PVC | `true` |
|
||||
| `persistence.storageClass` | PVC Storage Class | `""` |
|
||||
| `persistence.accessMode` | PVC Access Mode | `ReadWriteOnce` |
|
||||
| `persistence.size` | PVC Size | `10Gi` |
|
||||
| `persistence.annotations` | Annotations for PVC | `{}` |
|
||||
|
||||
### Transcribe Service (Optional AI Transcription)
|
||||
|
||||
| Name | Description | Value |
|
||||
|-------------------------------------------|-----------------------------------------------|--------------|
|
||||
| `transcribe.enabled` | Enable transcribe service | `false` |
|
||||
| `transcribe.image.repository` | Transcribe image repository | `joplin/transcribe` |
|
||||
| `transcribe.image.tag` | Transcribe image tag | `latest` |
|
||||
| `transcribe.image.pullPolicy` | Transcribe image pull policy | `IfNotPresent` |
|
||||
| `transcribe.api.key` | Shared secret between Joplin and Transcribe | `""` |
|
||||
| `transcribe.api.existingSecret` | Name of existing secret with transcribe API key | `""` |
|
||||
| `transcribe.api.keyName` | Key in the secret for transcribe API key | `transcribe-api-key` |
|
||||
| `transcribe.service.type` | Transcribe service type | `ClusterIP` |
|
||||
| `transcribe.service.port` | Transcribe service port | `4567` |
|
||||
| `transcribe.htr.imagesFolder` | HTR images folder path | `/app/images` |
|
||||
|
||||
#### Transcribe Database (Separate from main database)
|
||||
|
||||
| Name | Description | Value |
|
||||
|---------------------------------------------|---------------------------------------------|-------------|
|
||||
| `transcribe.database.host` | Transcribe database host | `""` |
|
||||
| `transcribe.database.port` | Transcribe database port | `5432` |
|
||||
| `transcribe.database.database` | Transcribe database name | `transcribe` |
|
||||
| `transcribe.database.user` | Transcribe database username | `transcribe` |
|
||||
| `transcribe.database.password` | Transcribe database password | `""` |
|
||||
| `transcribe.database.existingSecret` | Name of existing secret with transcribe DB credentials | `""` |
|
||||
| `transcribe.database.userKey` | Key in the secret for username | `username` |
|
||||
| `transcribe.database.passwordKey` | Key in the secret for password | `password` |
|
||||
|
||||
### Resource Configuration
|
||||
|
||||
| Name | Description | Value |
|
||||
|-------------|--------------------------------------|-------|
|
||||
| `resources` | Resource limits and requests | `{}` |
|
||||
|
||||
### Health Checks
|
||||
|
||||
| Name | Description | Value |
|
||||
|-------------------------------------------|------------------------------------------|-------|
|
||||
| `probes.liveness.enabled` | Enable liveness probe | `true` |
|
||||
| `probes.liveness.initialDelaySeconds` | Initial delay for liveness probe | `60` |
|
||||
| `probes.liveness.periodSeconds` | Period for liveness probe | `30` |
|
||||
| `probes.liveness.timeoutSeconds` | Timeout for liveness probe | `10` |
|
||||
| `probes.liveness.failureThreshold` | Failure threshold for liveness probe | `3` |
|
||||
| `probes.liveness.successThreshold` | Success threshold for liveness probe | `1` |
|
||||
| `probes.liveness.path` | Path for liveness probe | `/api/ping` |
|
||||
| `probes.liveness.httpHeaders` | HTTP headers for liveness probe | `[{"name": "Host", "value": "joplin.domain.com"}]` |
|
||||
| `probes.readiness.enabled` | Enable readiness probe | `true` |
|
||||
| `probes.readiness.initialDelaySeconds` | Initial delay for readiness probe | `30` |
|
||||
| `probes.readiness.periodSeconds` | Period for readiness probe | `10` |
|
||||
| `probes.readiness.timeoutSeconds` | Timeout for readiness probe | `5` |
|
||||
| `probes.readiness.failureThreshold` | Failure threshold for readiness probe | `3` |
|
||||
| `probes.readiness.successThreshold` | Success threshold for readiness probe | `1` |
|
||||
| `probes.readiness.path` | Path for readiness probe | `/api/ping` |
|
||||
| `probes.readiness.httpHeaders` | HTTP headers for readiness probe | `[{"name": "Host", "value": "joplin.domain.com"}]` |
|
||||
|
||||
### Autoscaling
|
||||
|
||||
| Name | Description | Value |
|
||||
|---------------------------------------------|------------------------------------------|---------|
|
||||
| `autoscaling.enabled` | Enable horizontal pod autoscaling | `false` |
|
||||
| `autoscaling.minReplicas` | Minimum number of replicas | `1` |
|
||||
| `autoscaling.maxReplicas` | Maximum number of replicas | `3` |
|
||||
| `autoscaling.targetCPUUtilizationPercentage`| Target CPU utilization percentage | `80` |
|
||||
| `autoscaling.targetMemoryUtilizationPercentage`| Target memory utilization percentage | `80` |
|
||||
|
||||
### Security Settings
|
||||
|
||||
| Name | Description | Value |
|
||||
|-----------------------------------|--------------------------------------|---------|
|
||||
| `security.httpsRedirect` | Enable/disable HTTPS redirect | `false` |
|
||||
| `security.tls.enabled` | Enable custom TLS certificate | `false` |
|
||||
| `security.tls.existingSecret` | Name of existing secret with TLS cert| `""` |
|
||||
| `security.tls.certificateKey` | Key in the secret for TLS certificate| `tls.crt` |
|
||||
| `security.tls.privateKeyKey` | Key in the secret for TLS private key| `tls.key` |
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Basic Installation with PostgreSQL
|
||||
|
||||
```yaml
|
||||
postgresql:
|
||||
external:
|
||||
enabled: true
|
||||
host: "postgresql.example.com"
|
||||
port: 5432
|
||||
database: "joplin"
|
||||
user: "joplin"
|
||||
password: "secure-password"
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
hosts:
|
||||
- host: joplin.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- hosts:
|
||||
- joplin.example.com
|
||||
secretName: joplin-tls
|
||||
|
||||
env:
|
||||
APP_BASE_URL: "https://joplin.example.com"
|
||||
|
||||
# IMPORTANT: Update health check host headers to match your domain
|
||||
probes:
|
||||
liveness:
|
||||
httpHeaders:
|
||||
- name: Host
|
||||
value: joplin.example.com
|
||||
readiness:
|
||||
httpHeaders:
|
||||
- name: Host
|
||||
value: joplin.example.com
|
||||
|
||||
joplin:
|
||||
admin:
|
||||
email: "admin@example.com"
|
||||
password: "admin-password"
|
||||
server:
|
||||
enableUserRegistration: true
|
||||
```
|
||||
|
||||
### Using Kubernetes Secrets
|
||||
|
||||
```yaml
|
||||
postgresql:
|
||||
external:
|
||||
enabled: true
|
||||
existingSecret: "joplin-postgresql-secret"
|
||||
hostKey: "host"
|
||||
portKey: "port"
|
||||
databaseKey: "database"
|
||||
userKey: "username"
|
||||
passwordKey: "password"
|
||||
|
||||
joplin:
|
||||
admin:
|
||||
existingSecret: "joplin-admin-secret"
|
||||
emailKey: "email"
|
||||
passwordKey: "password"
|
||||
```
|
||||
|
||||
### S3 Storage Configuration
|
||||
|
||||
```yaml
|
||||
joplin:
|
||||
storage:
|
||||
driver: "s3"
|
||||
s3:
|
||||
bucket: "joplin-notes"
|
||||
region: "us-east-1"
|
||||
existingSecret: "joplin-s3-secret"
|
||||
accessKeyIdKey: "access-key-id"
|
||||
secretAccessKeyKey: "secret-access-key"
|
||||
|
||||
# No persistence needed when using S3
|
||||
persistence:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
### Email Notifications Setup
|
||||
|
||||
```yaml
|
||||
joplin:
|
||||
email:
|
||||
enabled: true
|
||||
host: "smtp.example.com"
|
||||
port: 587
|
||||
fromEmail: "joplin@example.com"
|
||||
fromName: "Joplin Server"
|
||||
secure: true
|
||||
existingSecret: "joplin-email-secret"
|
||||
usernameKey: "username"
|
||||
passwordKey: "password"
|
||||
```
|
||||
|
||||
### Transcribe Service (AI Features)
|
||||
|
||||
```yaml
|
||||
transcribe:
|
||||
enabled: true
|
||||
api:
|
||||
existingSecret: "joplin-transcribe-secret"
|
||||
keyName: "api-key"
|
||||
database:
|
||||
host: "postgresql.example.com"
|
||||
port: 5432
|
||||
database: "transcribe"
|
||||
user: "transcribe"
|
||||
existingSecret: "transcribe-db-secret"
|
||||
userKey: "username"
|
||||
passwordKey: "password"
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 5Gi
|
||||
```
|
||||
|
||||
## First-time Setup
|
||||
|
||||
1. **Configure PostgreSQL**: Ensure your PostgreSQL database is accessible and credentials are configured
|
||||
2. **Admin User**: Set admin email/password or access the web interface to create the first admin user
|
||||
3. **User Registration**: Configure whether users can self-register or admin approval is required
|
||||
4. **Storage**: Choose between filesystem (requires persistence) or cloud storage (S3/Azure)
|
||||
|
||||
## Security Considerations
|
||||
|
||||
For production deployments:
|
||||
|
||||
1. Use external secrets for all sensitive information (database passwords, admin credentials, etc.)
|
||||
2. Enable TLS/SSL for all communications
|
||||
3. Configure proper RBAC and network policies
|
||||
4. Use dedicated databases with proper access controls
|
||||
5. Disable user registration if not needed
|
||||
6. Use cloud storage for better scalability and backup
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Common issues and solutions:
|
||||
|
||||
1. **Health Check Issues / "No Available Server"**:
|
||||
- Ensure `probes.*.httpHeaders` includes the correct Host header matching your domain
|
||||
- Health checks use `/api/ping` endpoint which requires proper host validation
|
||||
- Example fix:
|
||||
```yaml
|
||||
probes:
|
||||
liveness:
|
||||
httpHeaders:
|
||||
- name: Host
|
||||
value: your-joplin-domain.com
|
||||
readiness:
|
||||
httpHeaders:
|
||||
- name: Host
|
||||
value: your-joplin-domain.com
|
||||
```
|
||||
|
||||
2. **Database connection issues**: Verify PostgreSQL credentials and network connectivity
|
||||
3. **Storage permissions**: Check filesystem permissions for persistent volumes
|
||||
4. **First admin user**: If no admin configured, access the web interface to create one
|
||||
5. **Transcribe issues**: Verify Docker socket access and separate database configuration
|
||||
6. **Origin validation errors**: Make sure `env.APP_BASE_URL` matches your ingress host
|
||||
|
||||
For detailed troubleshooting, check the application logs:
|
||||
|
||||
```bash
|
||||
kubectl logs -f deployment/joplin-server
|
||||
```
|
||||
|
||||
Check pod status and events:
|
||||
```bash
|
||||
kubectl describe pod -l app.kubernetes.io/name=joplin-server
|
||||
```
|
||||
|
||||
## Backing Up
|
||||
|
||||
- **Database**: Use PostgreSQL backup tools (pg_dump, etc.)
|
||||
- **File Storage**:
|
||||
- Filesystem: Backup the PVC data
|
||||
- S3: Files are already stored in S3 (ensure proper S3 backup policies)
|
||||
- **Configuration**: Backup your Kubernetes secrets and config
|
||||
Reference in New Issue
Block a user