Compare commits

..

1 Commits

Author SHA1 Message Date
af1ecd86cb Release paperlessngx helmchart v0.0.1 2025-09-14 17:37:28 +02:00
11 changed files with 1301 additions and 0 deletions

View File

@ -0,0 +1,18 @@
apiVersion: v2
name: paperless-ngx
description: Paperless-ngx helm chart for Kubernetes
type: application
version: 0.0.1
appVersion: "latest"
maintainers:
- name: Richard Tomik
email: no@m.com
keywords:
- productivity
- document-management
- paperless
- paperless-ngx
- ocr
home: https://github.com/rtomik/helm-charts
sources:
- https://github.com/paperless-ngx/paperless-ngx

View File

@ -0,0 +1,92 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "paperless-ngx.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "paperless-ngx.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "paperless-ngx.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "paperless-ngx.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8000 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8000:$CONTAINER_PORT
{{- end }}
2. Application is accessible at port {{ .Values.service.port }}
3. Paperless-ngx is configured with:
- Database: PostgreSQL (external)
- Redis: External service
- OCR Language: {{ .Values.config.ocr.language }}
- Time Zone: {{ .Values.config.timeZone }}
4. External Dependencies Required:
- PostgreSQL server: {{ include "paperless-ngx.postgresql.host" . }}:{{ include "paperless-ngx.postgresql.port" . }}
- Redis server: {{ include "paperless-ngx.redis.host" . }}:{{ include "paperless-ngx.redis.port" . }}
{{- if or .Values.persistence.data.enabled .Values.persistence.media.enabled .Values.persistence.consume.enabled .Values.persistence.export.enabled }}
5. Persistent Storage:
{{- if .Values.persistence.data.enabled }}
- Data directory: {{ include "paperless-ngx.fullname" . }}-data ({{ .Values.persistence.data.size }})
{{- end }}
{{- if .Values.persistence.media.enabled }}
- Media directory: {{ include "paperless-ngx.fullname" . }}-media ({{ .Values.persistence.media.size }})
{{- end }}
{{- if .Values.persistence.consume.enabled }}
- Consume directory: {{ include "paperless-ngx.fullname" . }}-consume ({{ .Values.persistence.consume.size }})
{{- end }}
{{- if .Values.persistence.export.enabled }}
- Export directory: {{ include "paperless-ngx.fullname" . }}-export ({{ .Values.persistence.export.size }})
{{- end }}
{{- else }}
5. WARNING: No persistent storage enabled. Data will be lost when pods are restarted.
Enable persistence in values.yaml for production use.
{{- end }}
{{- if .Values.config.admin.user }}
6. Admin User: {{ .Values.config.admin.user }}
The admin user will be created automatically on first startup.
{{- else }}
6. No admin user configured. You'll need to create a superuser manually:
kubectl exec -it deployment/{{ include "paperless-ngx.fullname" . }} -- python manage.py createsuperuser
{{- end }}
{{- if or .Values.config.secretKey.existingSecret .Values.postgresql.external.existingSecret .Values.config.admin.existingSecret }}
7. Using external secrets for sensitive information:
{{- if .Values.config.secretKey.existingSecret }}
- Secret key from: {{ .Values.config.secretKey.existingSecret }}
{{- end }}
{{- if .Values.postgresql.external.existingSecret }}
- PostgreSQL password from: {{ .Values.postgresql.external.existingSecret }}
{{- end }}
{{- if .Values.config.admin.existingSecret }}
- Admin credentials from: {{ .Values.config.admin.existingSecret }}
{{- end }}
{{- else }}
7. SECURITY NOTE: For production use, it's recommended to store sensitive data in Kubernetes Secrets.
- Set config.secretKey.existingSecret to use an external secret for the secret key
- Set postgresql.external.existingSecret to use an external secret for database credentials
- Set config.admin.existingSecret to use an external secret for admin credentials
{{- end }}
{{- if .Values.config.consumer.barcodes.enabled }}
8. Barcode processing is enabled with scanner: {{ .Values.config.consumer.barcodeScanner }}
{{- end }}
{{- if .Values.config.tika.enabled }}
9. Tika integration is enabled for Office document processing
- Tika endpoint: {{ .Values.config.tika.endpoint }}
- Gotenberg endpoint: {{ .Values.config.tika.gotenbergEndpoint }}
{{- end }}
For more information about using this Helm chart and Paperless-ngx configuration,
please refer to the README.md file and the official Paperless-ngx documentation.

View File

@ -0,0 +1,238 @@
# Paperless-ngx Helm Chart
A Helm chart for deploying Paperless-ngx document management system on Kubernetes.
## Introduction
This chart deploys [Paperless-ngx](https://github.com/paperless-ngx/paperless-ngx) on a Kubernetes cluster using the Helm package manager.
Paperless-ngx is a community-supported supercharged version of paperless: scan, index and archive all your physical documents.
Source code can be found here:
- https://github.com/rtomik/helm-charts/tree/main/charts/paperless-ngx
## Prerequisites
- Kubernetes 1.19+
- Helm 3.0+
- PV provisioner support in the underlying infrastructure
- **External PostgreSQL database** (required)
- **External Redis server** (required)
## External Dependencies
This chart requires external PostgreSQL and Redis services. It does not deploy these dependencies to avoid resource conflicts on centralized servers.
### PostgreSQL Setup
Paperless-ngx requires PostgreSQL 11+ as its database backend. Ensure you have:
- A PostgreSQL database created for Paperless-ngx
- Database credentials configured in values.yaml or via secrets
### Redis Setup
Redis is required for background task processing. Ensure you have:
- A Redis server accessible from the cluster
- Connection details configured in values.yaml
## Installing the Chart
To install the chart with the release name `paperless-ngx`:
```bash
$ helm repo add paperless-chart https://rtomik.github.io/helm-charts
$ helm install paperless-ngx paperless-chart/paperless-ngx
```
Or install directly from this repository:
```bash
$ git clone https://github.com/rtomik/helm-charts.git
$ cd helm-charts/charts/paperless-ngx
$ helm install paperless-ngx .
```
> **Tip**: List all releases using `helm list`
## Configuration
The following table lists the configurable parameters and their default values.
### 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` | Paperless-ngx image repository | `ghcr.io/paperless-ngx/paperless-ngx` |
| `image.tag` | Paperless-ngx image tag | `latest` |
| `image.pullPolicy` | Paperless-ngx image pull policy | `IfNotPresent` |
### External Dependencies
| Name | Description | Value |
|----------------------------------------|--------------------------------------------------------------------|-------------------------------------------|
| `postgresql.external.enabled` | Enable external PostgreSQL configuration | `true` |
| `postgresql.external.host` | External PostgreSQL host | `postgresql.default.svc.cluster.local` |
| `postgresql.external.port` | External PostgreSQL port | `5432` |
| `postgresql.external.database` | External PostgreSQL database name | `paperless` |
| `postgresql.external.username` | External PostgreSQL username | `paperless` |
| `postgresql.external.existingSecret` | Existing secret with PostgreSQL credentials | `""` |
| `postgresql.external.passwordKey` | Key in existing secret for PostgreSQL password | `postgresql-password` |
| `redis.external.enabled` | Enable external Redis configuration | `true` |
| `redis.external.host` | External Redis host | `redis.default.svc.cluster.local` |
| `redis.external.port` | External Redis port | `6379` |
| `redis.external.database` | External Redis database number | `0` |
### Security Configuration
| Name | Description | Value |
|----------------------------------------|--------------------------------------------------------------------|---------------------|
| `config.secretKey.existingSecret` | Name of existing secret for Django secret key | `""` |
| `config.secretKey.secretKey` | Key in the existing secret for Django secret key | `secret-key` |
| `config.admin.user` | Admin username to create on startup | `""` |
| `config.admin.password` | Admin password (use existingSecret for production) | `""` |
| `config.admin.email` | Admin email address | `root@localhost` |
| `config.admin.existingSecret` | Name of existing secret for admin credentials | `""` |
### Application Configuration
| Name | Description | Value |
|----------------------------------------|--------------------------------------------------------------------|---------------------|
| `config.url` | External URL for Paperless-ngx (e.g., https://paperless.domain.com) | `""` |
| `config.allowedHosts` | Comma-separated list of allowed hosts | `*` |
| `config.timeZone` | Application timezone | `UTC` |
| `config.ocr.language` | OCR language (3-letter code) | `eng` |
| `config.ocr.mode` | OCR mode (skip, redo, force) | `skip` |
| `config.consumer.recursive` | Enable recursive consumption directory watching | `false` |
| `config.consumer.subdirsAsTags` | Use subdirectory names as tags | `false` |
### Persistence Parameters
| Name | Description | Value |
|----------------------------------------|--------------------------------------------------------------------|---------------------|
| `persistence.data.enabled` | Enable persistence for data directory | `true` |
| `persistence.data.size` | Size of data PVC | `1Gi` |
| `persistence.media.enabled` | Enable persistence for media directory | `true` |
| `persistence.media.size` | Size of media PVC | `10Gi` |
| `persistence.consume.enabled` | Enable persistence for consume directory | `true` |
| `persistence.consume.size` | Size of consume PVC | `5Gi` |
| `persistence.export.enabled` | Enable persistence for export directory | `true` |
| `persistence.export.size` | Size of export PVC | `1Gi` |
### Service Parameters
| Name | Description | Value |
|----------------------------|------------------------------------------------------|-------------|
| `service.type` | Kubernetes Service type | `ClusterIP` |
| `service.port` | Service HTTP port | `8000` |
### Ingress Parameters
| Name | Description | Value |
|----------------------------|------------------------------------------------------|----------------------|
| `ingress.enabled` | Enable ingress record generation | `false` |
| `ingress.className` | IngressClass name | `""` |
| `ingress.annotations` | Additional annotations for the Ingress resource | See values.yaml |
| `ingress.hosts` | Array of host and path objects | See values.yaml |
| `ingress.tls` | TLS configuration | See values.yaml |
## Usage Examples
### Basic Installation
```bash
helm install paperless-ngx . \
--set postgresql.external.host=my-postgres.example.com \
--set postgresql.external.password=secretpassword \
--set redis.external.host=my-redis.example.com
```
### Production Installation with External Secrets
```yaml
# values-production.yaml
config:
url: "https://paperless.example.com"
allowedHosts: "paperless.example.com"
secretKey:
existingSecret: "paperless-secrets"
secretKey: "django-secret-key"
admin:
user: "admin"
existingSecret: "paperless-admin-secrets"
postgresql:
external:
host: "postgresql.database.svc.cluster.local"
existingSecret: "paperless-db-secrets"
passwordKey: "password"
redis:
external:
host: "redis.cache.svc.cluster.local"
ingress:
enabled: true
className: "nginx"
hosts:
- host: paperless.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: paperless-tls
hosts:
- paperless.example.com
```
```bash
helm install paperless-ngx . -f values-production.yaml
```
## Security Considerations
1. **Use external secrets** for production deployments to store sensitive data like database passwords and the Django secret key.
2. **Set a proper PAPERLESS_URL** when exposing the application externally.
3. **Configure ALLOWED_HOSTS** to restrict which hosts can access the application.
4. **Use HTTPS** when exposing the application to the internet.
5. **Container Security**: The container runs as root initially to allow s6-overlay to set up the runtime environment, then drops privileges to UID 1000. This is required for the Paperless-ngx Docker image to function properly.
## Volumes and Data
Paperless-ngx uses several directories:
- **Data directory**: Contains the search index, classification model, and SQLite database (if used)
- **Media directory**: Contains all uploaded documents and thumbnails
- **Consume directory**: Drop documents here for automatic processing
- **Export directory**: Used for document exports
All directories can be configured with separate PVCs and storage classes.
## Uninstalling the Chart
To uninstall/delete the `paperless-ngx` deployment:
```bash
helm uninstall paperless-ngx
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Contributing
Please feel free to contribute by opening issues or pull requests at:
https://github.com/rtomik/helm-charts
## License
This Helm chart is licensed under the MIT License.
## Links
- [Paperless-ngx Documentation](https://docs.paperless-ngx.com/)
- [Paperless-ngx GitHub Repository](https://github.com/paperless-ngx/paperless-ngx)
- [Docker Hub](https://hub.docker.com/r/ghcr.io/paperless-ngx/paperless-ngx)

View File

@ -0,0 +1,99 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "paperless-ngx.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "paperless-ngx.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s" $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "paperless-ngx.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "paperless-ngx.labels" -}}
helm.sh/chart: {{ include "paperless-ngx.chart" . }}
{{ include "paperless-ngx.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "paperless-ngx.selectorLabels" -}}
app.kubernetes.io/name: {{ include "paperless-ngx.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
PostgreSQL host
*/}}
{{- define "paperless-ngx.postgresql.host" -}}
{{- if .Values.postgresql.external.enabled }}
{{- .Values.postgresql.external.host }}
{{- else }}
{{- printf "%s-postgresql" (include "paperless-ngx.fullname" .) }}
{{- end }}
{{- end }}
{{/*
PostgreSQL port
*/}}
{{- define "paperless-ngx.postgresql.port" -}}
{{- if .Values.postgresql.external.enabled }}
{{- .Values.postgresql.external.port | toString }}
{{- else }}
{{- "5432" }}
{{- end }}
{{- end }}
{{/*
Redis host
*/}}
{{- define "paperless-ngx.redis.host" -}}
{{- if .Values.redis.external.enabled }}
{{- .Values.redis.external.host }}
{{- else }}
{{- printf "%s-redis" (include "paperless-ngx.fullname" .) }}
{{- end }}
{{- end }}
{{/*
Redis port
*/}}
{{- define "paperless-ngx.redis.port" -}}
{{- if .Values.redis.external.enabled }}
{{- .Values.redis.external.port | toString }}
{{- else }}
{{- "6379" }}
{{- end }}
{{- end }}
{{/*
Redis URL
*/}}
{{- define "paperless-ngx.redis.url" -}}
{{- $host := include "paperless-ngx.redis.host" . }}
{{- $port := include "paperless-ngx.redis.port" . }}
{{- $database := .Values.redis.external.database | toString }}
{{- printf "redis://%s:%s/%s" $host $port $database }}
{{- end }}

View File

@ -0,0 +1,13 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "paperless-ngx.fullname" . }}-configmap
labels:
{{- include "paperless-ngx.labels" . | nindent 4 }}
data:
# Additional configuration files can be added here if needed
# Most Paperless-ngx configuration is handled via environment variables
README.txt: |
This ConfigMap can be used to store additional configuration files
for Paperless-ngx if needed. The main configuration is handled via
environment variables in the deployment.

View File

@ -0,0 +1,366 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "paperless-ngx.fullname" . }}
labels:
{{- include "paperless-ngx.labels" . | nindent 4 }}
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
spec:
replicas: {{ .Values.replicaCount }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels:
{{- include "paperless-ngx.selectorLabels" . | nindent 6 }}
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
{{- include "paperless-ngx.selectorLabels" . | nindent 8 }}
annotations:
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.containerSecurityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
{{- if .Values.probes.liveness.enabled }}
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
successThreshold: {{ .Values.probes.liveness.successThreshold }}
{{- end }}
{{- if .Values.probes.readiness.enabled }}
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
successThreshold: {{ .Values.probes.readiness.successThreshold }}
{{- end }}
env:
# Required services
- name: PAPERLESS_REDIS
value: {{ include "paperless-ngx.redis.url" . | quote }}
- name: PAPERLESS_DBHOST
value: {{ include "paperless-ngx.postgresql.host" . | quote }}
- name: PAPERLESS_DBPORT
value: {{ include "paperless-ngx.postgresql.port" . | quote }}
- name: PAPERLESS_DBNAME
value: {{ .Values.postgresql.external.database | quote }}
- name: PAPERLESS_DBUSER
value: {{ .Values.postgresql.external.username | quote }}
# Database password from secret
- name: PAPERLESS_DBPASS
valueFrom:
secretKeyRef:
name: {{ .Values.postgresql.external.existingSecret | default (printf "%s-secrets" (include "paperless-ngx.fullname" .)) }}
key: {{ .Values.postgresql.external.passwordKey | default "postgresql-password" }}
# Security
- name: PAPERLESS_SECRET_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.config.secretKey.existingSecret | default (printf "%s-secrets" (include "paperless-ngx.fullname" .)) }}
key: {{ .Values.config.secretKey.secretKey | default "secret-key" }}
# Basic configuration
{{- if .Values.config.url }}
- name: PAPERLESS_URL
value: {{ .Values.config.url | quote }}
{{- end }}
- name: PAPERLESS_ALLOWED_HOSTS
value: {{ .Values.config.allowedHosts | quote }}
{{- if .Values.config.csrfTrustedOrigins }}
- name: PAPERLESS_CSRF_TRUSTED_ORIGINS
value: {{ .Values.config.csrfTrustedOrigins | quote }}
{{- end }}
- name: PAPERLESS_CORS_ALLOWED_HOSTS
value: {{ .Values.config.corsAllowedHosts | quote }}
{{- if .Values.config.forceScriptName }}
- name: PAPERLESS_FORCE_SCRIPT_NAME
value: {{ .Values.config.forceScriptName | quote }}
{{- end }}
# Paths
- name: PAPERLESS_DATA_DIR
value: "/usr/src/paperless/data"
- name: PAPERLESS_MEDIA_ROOT
value: "/usr/src/paperless/media"
- name: PAPERLESS_CONSUMPTION_DIR
value: "/usr/src/paperless/consume"
# Docker/User settings (s6-overlay compatible)
- name: USERMAP_UID
value: "1000"
- name: USERMAP_GID
value: "1000"
# OCR settings
- name: PAPERLESS_OCR_LANGUAGE
value: {{ .Values.config.ocr.language | quote }}
- name: PAPERLESS_OCR_MODE
value: {{ .Values.config.ocr.mode | quote }}
- name: PAPERLESS_OCR_SKIP_ARCHIVE_FILE
value: {{ .Values.config.ocr.skipArchiveFile | quote }}
- name: PAPERLESS_OCR_CLEAN
value: {{ .Values.config.ocr.clean | quote }}
- name: PAPERLESS_OCR_DESKEW
value: {{ .Values.config.ocr.deskew | quote }}
- name: PAPERLESS_OCR_ROTATE_PAGES
value: {{ .Values.config.ocr.rotatePages | quote }}
- name: PAPERLESS_OCR_ROTATE_PAGES_THRESHOLD
value: {{ .Values.config.ocr.rotatePagesThreshold | quote }}
- name: PAPERLESS_OCR_OUTPUT_TYPE
value: {{ .Values.config.ocr.outputType | quote }}
{{- if ne (.Values.config.ocr.pages | int) 0 }}
- name: PAPERLESS_OCR_PAGES
value: {{ .Values.config.ocr.pages | quote }}
{{- end }}
{{- if ne (.Values.config.ocr.imageDpi | int) 0 }}
- name: PAPERLESS_OCR_IMAGE_DPI
value: {{ .Values.config.ocr.imageDpi | quote }}
{{- end }}
{{- if ne (.Values.config.ocr.maxImagePixels | int) 0 }}
- name: PAPERLESS_OCR_MAX_IMAGE_PIXELS
value: {{ .Values.config.ocr.maxImagePixels | quote }}
{{- end }}
{{- if ne .Values.config.ocr.userArgs "{}" }}
- name: PAPERLESS_OCR_USER_ARGS
value: {{ .Values.config.ocr.userArgs | quote }}
{{- end }}
# Time and locale
- name: PAPERLESS_TIME_ZONE
value: {{ .Values.config.timeZone | quote }}
# Consumer settings
- name: PAPERLESS_CONSUMER_RECURSIVE
value: {{ .Values.config.consumer.recursive | quote }}
- name: PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS
value: {{ .Values.config.consumer.subdirsAsTags | quote }}
- name: PAPERLESS_CONSUMER_DELETE_DUPLICATES
value: {{ .Values.config.consumer.deleteDocumentDuplicates | quote }}
- name: PAPERLESS_CONSUMER_IGNORE_PATTERNS
value: {{ .Values.config.consumer.ignorePatterns | quote }}
- name: PAPERLESS_CONSUMER_BARCODE_SCANNER
value: {{ .Values.config.consumer.barcodeScanner | quote }}
# Barcode settings
{{- if .Values.config.consumer.barcodes.enabled }}
- name: PAPERLESS_CONSUMER_ENABLE_BARCODES
value: "true"
- name: PAPERLESS_CONSUMER_BARCODE_TIFF_SUPPORT
value: {{ .Values.config.consumer.barcodes.tiffSupport | quote }}
- name: PAPERLESS_CONSUMER_BARCODE_STRING
value: {{ .Values.config.consumer.barcodes.string | quote }}
- name: PAPERLESS_CONSUMER_BARCODE_RETAIN_SPLIT_PAGES
value: {{ .Values.config.consumer.barcodes.retainSplitPages | quote }}
{{- if ne (.Values.config.consumer.barcodes.upscale | float64) 0.0 }}
- name: PAPERLESS_CONSUMER_BARCODE_UPSCALE
value: {{ .Values.config.consumer.barcodes.upscale | quote }}
{{- end }}
- name: PAPERLESS_CONSUMER_BARCODE_DPI
value: {{ .Values.config.consumer.barcodes.dpi | quote }}
{{- if ne (.Values.config.consumer.barcodes.maxPages | int) 0 }}
- name: PAPERLESS_CONSUMER_BARCODE_MAX_PAGES
value: {{ .Values.config.consumer.barcodes.maxPages | quote }}
{{- end }}
{{- end }}
# ASN barcode settings
{{- if .Values.config.consumer.barcodes.asnEnabled }}
- name: PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE
value: "true"
- name: PAPERLESS_CONSUMER_ASN_BARCODE_PREFIX
value: {{ .Values.config.consumer.barcodes.asnPrefix | quote }}
{{- end }}
# Tag barcode settings
{{- if .Values.config.consumer.barcodes.tagEnabled }}
- name: PAPERLESS_CONSUMER_ENABLE_TAG_BARCODE
value: "true"
- name: PAPERLESS_CONSUMER_TAG_BARCODE_MAPPING
value: {{ .Values.config.consumer.barcodes.tagMapping | quote }}
{{- end }}
# Tika settings
{{- if .Values.config.tika.enabled }}
- name: PAPERLESS_TIKA_ENABLED
value: "true"
- name: PAPERLESS_TIKA_ENDPOINT
value: {{ .Values.config.tika.endpoint | quote }}
- name: PAPERLESS_TIKA_GOTENBERG_ENDPOINT
value: {{ .Values.config.tika.gotenbergEndpoint | quote }}
{{- end }}
# Admin user
{{- if .Values.config.admin.user }}
- name: PAPERLESS_ADMIN_USER
value: {{ .Values.config.admin.user | quote }}
- name: PAPERLESS_ADMIN_MAIL
value: {{ .Values.config.admin.email | quote }}
- name: PAPERLESS_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.config.admin.existingSecret | default (printf "%s-secrets" (include "paperless-ngx.fullname" .)) }}
key: {{ .Values.config.admin.passwordKey | default "admin-password" }}
{{- end }}
# Email settings
{{- if .Values.config.email.host }}
- name: PAPERLESS_EMAIL_HOST
value: {{ .Values.config.email.host | quote }}
- name: PAPERLESS_EMAIL_PORT
value: {{ .Values.config.email.port | quote }}
{{- if .Values.config.email.user }}
- name: PAPERLESS_EMAIL_HOST_USER
value: {{ .Values.config.email.user | quote }}
- name: PAPERLESS_EMAIL_HOST_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.config.email.existingSecret | default (printf "%s-secrets" (include "paperless-ngx.fullname" .)) }}
key: {{ .Values.config.email.passwordKey | default "email-password" }}
{{- end }}
{{- if .Values.config.email.from }}
- name: PAPERLESS_EMAIL_FROM
value: {{ .Values.config.email.from | quote }}
{{- end }}
- name: PAPERLESS_EMAIL_USE_TLS
value: {{ .Values.config.email.useTls | quote }}
- name: PAPERLESS_EMAIL_USE_SSL
value: {{ .Values.config.email.useSsl | quote }}
{{- end }}
# Task processing
- name: PAPERLESS_TASK_WORKERS
value: {{ .Values.config.taskWorkers | quote }}
- name: PAPERLESS_THREADS_PER_WORKER
value: {{ .Values.config.threadsPerWorker | quote }}
- name: PAPERLESS_WORKER_TIMEOUT
value: {{ .Values.config.workerTimeout | quote }}
# Advanced settings
- name: PAPERLESS_ENABLE_NLTK
value: {{ .Values.config.enableNltk | quote }}
{{- if .Values.config.filenameFormat }}
- name: PAPERLESS_FILENAME_FORMAT
value: {{ .Values.config.filenameFormat | quote }}
- name: PAPERLESS_FILENAME_FORMAT_REMOVE_NONE
value: {{ .Values.config.filenameFormatRemoveNone | quote }}
{{- end }}
{{- if ne (.Values.config.convertMemoryLimit | int) 0 }}
- name: PAPERLESS_CONVERT_MEMORY_LIMIT
value: {{ .Values.config.convertMemoryLimit | quote }}
{{- end }}
{{- if .Values.config.convertTmpDir }}
- name: PAPERLESS_CONVERT_TMPDIR
value: {{ .Values.config.convertTmpDir | quote }}
{{- end }}
{{- if ne (.Values.config.maxImagePixels | int) 0 }}
- name: PAPERLESS_MAX_IMAGE_PIXELS
value: {{ .Values.config.maxImagePixels | quote }}
{{- end }}
# Custom environment variables
{{- range .Values.env }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
{{- with .Values.extraEnv }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.extraEnvFrom }}
envFrom:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
- name: data
mountPath: /usr/src/paperless/data
- name: media
mountPath: /usr/src/paperless/media
- name: export
mountPath: /usr/src/paperless/export
- name: consume
mountPath: /usr/src/paperless/consume
{{- with .Values.extraVolumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumes:
{{- if .Values.persistence.data.enabled }}
- name: data
persistentVolumeClaim:
claimName: {{ include "paperless-ngx.fullname" . }}-data
{{- else }}
- name: data
emptyDir: {}
{{- end }}
{{- if .Values.persistence.media.enabled }}
- name: media
persistentVolumeClaim:
claimName: {{ include "paperless-ngx.fullname" . }}-media
{{- else }}
- name: media
emptyDir: {}
{{- end }}
{{- if .Values.persistence.export.enabled }}
- name: export
persistentVolumeClaim:
claimName: {{ include "paperless-ngx.fullname" . }}-export
{{- else }}
- name: export
emptyDir: {}
{{- end }}
{{- if .Values.persistence.consume.enabled }}
- name: consume
persistentVolumeClaim:
claimName: {{ include "paperless-ngx.fullname" . }}-consume
{{- else }}
- name: consume
emptyDir: {}
{{- end }}
{{- with .Values.extraVolumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@ -0,0 +1,43 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "paperless-ngx.fullname" . }}
labels:
{{- include "paperless-ngx.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
{{- if .secretName }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "paperless-ngx.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,90 @@
{{- if .Values.persistence.data.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "paperless-ngx.fullname" . }}-data
labels:
{{- include "paperless-ngx.labels" . | nindent 4 }}
{{- with .Values.persistence.data.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.data.accessMode | quote }}
{{- if .Values.persistence.data.storageClass }}
storageClassName: {{ .Values.persistence.data.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.data.size | quote }}
---
{{- end }}
{{- if .Values.persistence.media.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "paperless-ngx.fullname" . }}-media
labels:
{{- include "paperless-ngx.labels" . | nindent 4 }}
{{- with .Values.persistence.media.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.media.accessMode | quote }}
{{- if .Values.persistence.media.storageClass }}
storageClassName: {{ .Values.persistence.media.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.media.size | quote }}
---
{{- end }}
{{- if .Values.persistence.export.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "paperless-ngx.fullname" . }}-export
labels:
{{- include "paperless-ngx.labels" . | nindent 4 }}
{{- with .Values.persistence.export.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.export.accessMode | quote }}
{{- if .Values.persistence.export.storageClass }}
storageClassName: {{ .Values.persistence.export.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.export.size | quote }}
---
{{- end }}
{{- if .Values.persistence.consume.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "paperless-ngx.fullname" . }}-consume
labels:
{{- include "paperless-ngx.labels" . | nindent 4 }}
{{- with .Values.persistence.consume.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.consume.accessMode | quote }}
{{- if .Values.persistence.consume.storageClass }}
storageClassName: {{ .Values.persistence.consume.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.consume.size | quote }}
{{- end }}

View File

@ -0,0 +1,38 @@
{{- $needsSecret := false -}}
{{- if not .Values.config.secretKey.existingSecret -}}
{{- $needsSecret = true -}}
{{- end -}}
{{- if not .Values.postgresql.external.existingSecret -}}
{{- $needsSecret = true -}}
{{- end -}}
{{- if and .Values.config.admin.user (not .Values.config.admin.existingSecret) -}}
{{- $needsSecret = true -}}
{{- end -}}
{{- if and .Values.config.email.host .Values.config.email.user (not .Values.config.email.existingSecret) -}}
{{- $needsSecret = true -}}
{{- end -}}
{{- if $needsSecret }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "paperless-ngx.fullname" . }}-secrets
labels:
{{- include "paperless-ngx.labels" . | nindent 4 }}
type: Opaque
data:
{{- if not .Values.config.secretKey.existingSecret }}
{{ .Values.config.secretKey.secretKey | default "secret-key" }}: {{ .Values.config.secretKey.value | default "change-me-paperless-secret-key-at-least-32-characters-long" | b64enc }}
{{- end }}
{{- if not .Values.postgresql.external.existingSecret }}
{{ .Values.postgresql.external.passwordKey | default "postgresql-password" }}: {{ .Values.postgresql.external.password | default "paperless" | b64enc }}
{{- end }}
{{- if and .Values.config.admin.user (not .Values.config.admin.existingSecret) }}
{{ .Values.config.admin.userKey | default "admin-user" }}: {{ .Values.config.admin.user | b64enc }}
{{ .Values.config.admin.passwordKey | default "admin-password" }}: {{ .Values.config.admin.password | default "changeme" | b64enc }}
{{- end }}
{{- if and .Values.config.email.host .Values.config.email.user (not .Values.config.email.existingSecret) }}
{{ .Values.config.email.userKey | default "email-user" }}: {{ .Values.config.email.user | b64enc }}
{{ .Values.config.email.passwordKey | default "email-password" }}: {{ .Values.config.email.password | default "" | b64enc }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "paperless-ngx.fullname" . }}
labels:
{{- include "paperless-ngx.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "paperless-ngx.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,289 @@
## Global settings
nameOverride: ""
fullnameOverride: ""
## Image settings
image:
repository: ghcr.io/paperless-ngx/paperless-ngx
tag: "2.18.4"
pullPolicy: IfNotPresent
## Deployment settings
replicaCount: 1
revisionHistoryLimit: 3
# Pod security settings
# Note: Paperless-ngx uses s6-overlay which requires root access during initialization
# The container will drop privileges after setup
podSecurityContext:
runAsNonRoot: false
runAsUser: 0
fsGroup: 1000
containerSecurityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
capabilities:
drop:
- ALL
add:
- CHOWN
- DAC_OVERRIDE
- FOWNER
- SETGID
- SETUID
## Pod scheduling
nodeSelector: {}
tolerations: []
affinity: {}
## Service settings
service:
type: ClusterIP
port: 8000
## Ingress settings
ingress:
enabled: false
className: ""
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
hosts:
- host: paperless.domain.com
paths:
- path: /
pathType: Prefix
tls:
- hosts:
- paperless.domain.com
# Optional: specify the name of an existing TLS secret
# secretName: "existing-tls-secret"
## Persistence settings
persistence:
# Paperless data directory (search index, classification model, etc.)
data:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 1Gi
annotations: {}
# Paperless media directory (documents and thumbnails)
media:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 10Gi
annotations: {}
# Export directory (for exporting documents)
export:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 1Gi
annotations: {}
# Consume directory (for importing documents)
consume:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 5Gi
annotations: {}
# Extra volume mounts
extraVolumeMounts: []
# Extra volumes
extraVolumes: []
## Resource limits and requests
# resources:
# limits:
# cpu: 1000m
# memory: 1Gi
# requests:
# cpu: 200m
# memory: 512Mi
## Application health checks
probes:
liveness:
enabled: true
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
successThreshold: 1
path: /
readiness:
enabled: true
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
successThreshold: 1
path: /
## Autoscaling configuration
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 3
targetCPUUtilizationPercentage: 80
targetMemoryUtilizationPercentage: 80
## External Dependencies Configuration
## These should point to external PostgreSQL and Redis services
# External PostgreSQL database configuration
postgresql:
# External PostgreSQL connection details
external:
enabled: true
host: "postgresql.default.svc.cluster.local"
port: 5432
database: "paperless"
username: "paperless"
# Use existingSecret for credentials
existingSecret: ""
passwordKey: "postgresql-password"
# Or set password directly (not recommended for production)
password: ""
# External Redis configuration
redis:
external:
enabled: true
host: "redis.default.svc.cluster.local"
port: 6379
database: 0
# Use existingSecret for credentials if Redis has auth
existingSecret: ""
passwordKey: "redis-password"
# Or set password directly (leave empty if no auth)
password: ""
## Paperless-ngx Configuration
config:
# Basic server configuration
url: "" # Set to your external URL, e.g., https://paperless.domain.com
allowedHosts: "*" # Comma-separated list of allowed hosts
csrfTrustedOrigins: "" # Comma-separated list of trusted origins
corsAllowedHosts: "http://localhost:8000"
forceScriptName: "" # For hosting under subpath, e.g., /paperless
# Security settings
secretKey:
# Use existingSecret for production
existingSecret: ""
secretKey: "secret-key"
# Or set directly (not recommended for production)
value: ""
# OCR Configuration
ocr:
language: "eng" # OCR language (3-letter code)
mode: "skip" # skip, redo, or force
skipArchiveFile: "never" # never, with_text, always
clean: "clean" # clean, clean-final, none
deskew: true
rotatePages: true
rotatePagesThreshold: 12
outputType: "pdfa"
pages: 0 # 0 = all pages
imageDpi: 0 # 0 = auto
maxImagePixels: 0 # 0 = use Pillow default
userArgs: "{}" # JSON string of additional OCRmyPDF arguments
# Time and locale settings
timeZone: "UTC"
# Consumer settings
consumer:
recursive: false
subdirsAsTags: false
deleteDocumentDuplicates: false
ignorePatterns: '[".DS_Store", ".DS_STORE", "._*", ".stfolder/*", ".stversions/*", ".localized/*", "desktop.ini", "@eaDir/*", "Thumbs.db"]'
barcodeScanner: "PYZBAR"
# Barcode processing
barcodes:
enabled: false
tiffSupport: false
string: "PATCHT"
retainSplitPages: false
upscale: 0.0
dpi: 300
maxPages: 0
# ASN barcode settings
asnEnabled: false
asnPrefix: "ASN"
# Tag barcode settings
tagEnabled: false
tagMapping: '{"TAG:(.*)": "\\g<1>"}'
# Optional Tika settings (for Office documents)
tika:
enabled: false
endpoint: "http://tika:9998"
gotenbergEndpoint: "http://gotenberg:3000"
# Admin user creation (optional)
admin:
user: "" # Set to create admin user on startup
password: "" # Required if admin.user is set
email: "root@localhost"
# Use existingSecret for credentials
existingSecret: ""
userKey: "admin-user"
passwordKey: "admin-password"
# Email configuration (optional)
email:
host: ""
port: 25
user: ""
password: ""
from: ""
useTls: false
useSsl: false
# Use existingSecret for credentials
existingSecret: ""
userKey: "email-user"
passwordKey: "email-password"
# Logging
logging:
dir: "" # Uses PAPERLESS_DATA_DIR/log/ if empty
# Task processing
taskWorkers: 1
threadsPerWorker: 1
workerTimeout: 1800
# Advanced settings
filenameFormat: ""
filenameFormatRemoveNone: false
enableNltk: true
convertMemoryLimit: 0
convertTmpDir: ""
maxImagePixels: 0
# Environment variables
env: []
# Example additional env vars:
# - name: PAPERLESS_ENABLE_HTTP_REMOTE_USER
# value: "false"
# Extra environment variables from secrets
extraEnvFrom: []
# - secretRef:
# name: paperless-extra-secrets
# Extra environment variables (for advanced use cases)
extraEnv: []