Created
December 11, 2025 02:22
-
-
Save devsteppe9/17b83f51ca05c5012632d32c5e42cea5 to your computer and use it in GitHub Desktop.
Kubernetes file for configuring self-hosted immich server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| apiVersion: v1 | |
| kind: Namespace | |
| metadata: | |
| name: immich | |
| --- | |
| kind: PersistentVolume | |
| apiVersion: v1 | |
| metadata: | |
| name: immich-db-pv | |
| namespace: immich | |
| labels: | |
| app: immich-postgresql | |
| spec: | |
| capacity: | |
| storage: 10Gi | |
| accessModes: | |
| - ReadWriteMany | |
| hostPath: | |
| path: /mnt/homelab/immich-db-data | |
| persistentVolumeReclaimPolicy: Retain | |
| --- | |
| kind: PersistentVolumeClaim | |
| apiVersion: v1 | |
| metadata: | |
| name: immich-db-pvc | |
| namespace: immich | |
| labels: | |
| app: immich | |
| spec: | |
| accessModes: | |
| - ReadWriteMany | |
| resources: | |
| requests: | |
| storage: 10Gi # Match or be less than the PV's capacity | |
| volumeName: immich-db-pv # Bind explicitly to the PV created above | |
| storageClassName: '' | |
| --- | |
| kind: PersistentVolume | |
| apiVersion: v1 | |
| metadata: | |
| name: immich-library-pv | |
| namespace: immich | |
| labels: | |
| app: immich | |
| spec: | |
| capacity: | |
| storage: 500Gi # Adjust the storage size as needed | |
| accessModes: | |
| - ReadWriteMany | |
| hostPath: | |
| path: /mnt/homelab/immich-library-data | |
| --- | |
| kind: PersistentVolumeClaim | |
| apiVersion: v1 | |
| metadata: | |
| name: immich-library-pvc | |
| namespace: immich | |
| labels: | |
| app: immich | |
| spec: | |
| accessModes: | |
| - ReadWriteMany | |
| resources: | |
| requests: | |
| storage: 500Gi # Match or be less than the PV's capacity | |
| volumeName: immich-library-pv # Bind explicitly to the PV created above | |
| storageClassName: '' | |
| --- | |
| kind: ConfigMap | |
| apiVersion: v1 | |
| metadata: | |
| name: immich-env | |
| namespace: immich | |
| labels: | |
| app: immich | |
| data: | |
| DB_DATABASE_NAME: "immich" | |
| DB_HOSTNAME: "immich-database" | |
| DB_USERNAME: "immich" | |
| IMMICH_MACHINE_LEARNING_URL: "http://immich-machine-learning:3003" | |
| REDIS_HOSTNAME: "redis-server.redis-server.svc.cluster.local" | |
| REDIS_PORT: "6379" | |
| REDIS_DBINDEX: "0" | |
| REDIS_PASSWORD: "" | |
| DISABLE_REVERSE_GEOCODING: "false" | |
| REVERSE_GEOCODING_PRECISION: "2" | |
| PUBLIC_LOGIN_PAGE_MESSAGE: "" | |
| PUID: "0" | |
| PGID: "0" | |
| DB_PASSWORD: "password" | |
| --- | |
| apiVersion: apps/v1 | |
| kind: Deployment | |
| metadata: | |
| name: immich-database | |
| namespace: immich | |
| spec: | |
| replicas: 1 | |
| selector: | |
| matchLabels: | |
| app: immich-database | |
| template: | |
| metadata: | |
| labels: | |
| app: immich-database | |
| spec: | |
| containers: | |
| - name: immich-postgres | |
| image: "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0" | |
| imagePullPolicy: Always | |
| ports: | |
| - containerPort: 5432 | |
| env: | |
| - name: POSTGRES_USER | |
| valueFrom: | |
| configMapKeyRef: | |
| name: immich-env | |
| key: DB_USERNAME | |
| - name: POSTGRES_PASSWORD | |
| valueFrom: | |
| configMapKeyRef: | |
| name: immich-env | |
| key: DB_PASSWORD | |
| - name: POSTGRES_DB | |
| valueFrom: | |
| configMapKeyRef: | |
| name: immich-env | |
| key: DB_DATABASE_NAME | |
| volumeMounts: | |
| - name: pgdata | |
| mountPath: /var/lib/postgresql/data | |
| subPath: postgres | |
| resources: {} | |
| volumes: | |
| - name: pgdata | |
| persistentVolumeClaim: | |
| claimName: immich-db-pvc | |
| --- | |
| kind: Deployment | |
| apiVersion: apps/v1 | |
| metadata: | |
| name: immich-server | |
| namespace: immich | |
| labels: | |
| app: immich-server | |
| spec: | |
| strategy: | |
| type: Recreate | |
| selector: | |
| matchLabels: | |
| app: immich-server | |
| template: | |
| metadata: | |
| labels: | |
| app: immich-server | |
| annotations: | |
| k8s.v1.cni.cncf.io/networks: | | |
| [{ | |
| "name": "multus-iot", | |
| "namespace": "default", | |
| "mac": "2e:f8:57:99:6e:31", | |
| "ips": ["192.168.1.192/24"] | |
| }] | |
| spec: | |
| securityContext: | |
| fsGroup: 0 | |
| serviceAccountName: default | |
| dnsPolicy: ClusterFirst | |
| initContainers: | |
| - name: postgresql-isready | |
| image: "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0" | |
| imagePullPolicy: Always | |
| env: | |
| - name: POSTGRES_USER | |
| valueFrom: | |
| configMapKeyRef: | |
| name: immich-env | |
| key: DB_USERNAME | |
| - name: POSTGRES_DB | |
| valueFrom: | |
| configMapKeyRef: | |
| name: immich-env | |
| key: DB_DATABASE_NAME | |
| command: | |
| - /bin/sh | |
| - -c | |
| - until pg_isready -U "${POSTGRES_USER}" -d "dbname=${POSTGRES_DB}" | |
| -h immich-database -p 5432 ; do sleep 2 ; done | |
| containers: | |
| - name: immich-server | |
| image: "ghcr.io/immich-app/immich-server:release" | |
| imagePullPolicy: Always | |
| securityContext: | |
| runAsUser: 0 | |
| ports: | |
| - containerPort: 3001 | |
| env: | |
| - name: DB_PASSWORD | |
| valueFrom: | |
| configMapKeyRef: | |
| name: immich-env | |
| key: DB_PASSWORD | |
| envFrom: | |
| - configMapRef: | |
| name: immich-env | |
| optional: false | |
| livenessProbe: | |
| failureThreshold: 120 | |
| httpGet: | |
| path: /server/ping | |
| port: 2283 | |
| initialDelaySeconds: 10 | |
| periodSeconds: 120 | |
| timeoutSeconds: 1 | |
| readinessProbe: | |
| failureThreshold: 120 | |
| httpGet: | |
| path: /server/ping | |
| port: 2283 | |
| initialDelaySeconds: 10 | |
| periodSeconds: 120 | |
| timeoutSeconds: 1 | |
| volumeMounts: | |
| - name: library | |
| mountPath: /usr/src/app/upload | |
| subPath: library | |
| volumes: | |
| - name: library | |
| persistentVolumeClaim: | |
| claimName: immich-library-pvc | |
| --- | |
| kind: Deployment | |
| apiVersion: apps/v1 | |
| metadata: | |
| name: immich-machine-learning | |
| namespace: immich | |
| labels: | |
| app: immich-machine-learning | |
| spec: | |
| strategy: | |
| type: Recreate | |
| selector: | |
| matchLabels: | |
| app: immich-machine-learning | |
| template: | |
| metadata: | |
| labels: | |
| app: immich-machine-learning | |
| spec: | |
| securityContext: | |
| fsGroup: 0 | |
| serviceAccountName: default | |
| automountServiceAccountToken: true | |
| dnsPolicy: ClusterFirst | |
| enableServiceLinks: true | |
| containers: | |
| - name: immich-machine-learning | |
| image: "ghcr.io/immich-app/immich-machine-learning:release" | |
| imagePullPolicy: Always | |
| ports: | |
| - containerPort: 3003 | |
| env: | |
| - name: DB_PASSWORD | |
| valueFrom: | |
| configMapKeyRef: | |
| name: immich-env | |
| key: DB_PASSWORD | |
| - name: TRANSFORMERS_CACHE | |
| value: /cache | |
| envFrom: | |
| - configMapRef: | |
| name: immich-env | |
| optional: false | |
| livenessProbe: | |
| failureThreshold: 3 | |
| httpGet: | |
| path: /ping | |
| port: 3003 | |
| initialDelaySeconds: 0 | |
| periodSeconds: 10 | |
| timeoutSeconds: 1 | |
| readinessProbe: | |
| failureThreshold: 3 | |
| httpGet: | |
| path: /ping | |
| port: 3003 | |
| initialDelaySeconds: 0 | |
| periodSeconds: 10 | |
| timeoutSeconds: 1 | |
| volumeMounts: | |
| - name: cache | |
| mountPath: /cache | |
| resources: {} | |
| volumes: | |
| - name: cache | |
| emptyDir: {} | |
| --- | |
| kind: Service | |
| apiVersion: v1 | |
| metadata: | |
| name: immich-database | |
| namespace: immich | |
| labels: | |
| app: immich-database | |
| spec: | |
| type: ClusterIP | |
| selector: | |
| app: immich-database | |
| ports: | |
| - name: tcp-postgresql | |
| port: 5432 | |
| targetPort: 5432 | |
| --- | |
| kind: Service | |
| apiVersion: v1 | |
| metadata: | |
| name: immich-machine-learning | |
| namespace: immich | |
| labels: | |
| app: immich-machine-learning | |
| spec: | |
| type: ClusterIP | |
| selector: | |
| app: immich-machine-learning | |
| ports: | |
| - port: 3003 | |
| targetPort: 3003 | |
| protocol: TCP | |
| --- | |
| kind: Service | |
| apiVersion: v1 | |
| metadata: | |
| name: immich-server | |
| namespace: immich | |
| labels: | |
| app: immich-server | |
| spec: | |
| type: LoadBalancer | |
| selector: | |
| app: immich-server | |
| ports: | |
| - port: 2283 | |
| targetPort: 2283 | |
| protocol: TCP | |
| --- | |
| apiVersion: v1 | |
| kind: Namespace | |
| metadata: | |
| name: immich-restic-backup | |
| --- | |
| apiVersion: v1 | |
| kind: Secret | |
| metadata: | |
| name: aws-creds | |
| namespace: immich-restic-backup | |
| type: Opaque | |
| stringData: | |
| AWS_ACCESS_KEY_ID: "YOUR_SECRET" | |
| AWS_SECRET_ACCESS_KEY: "YOUR_SECRET" | |
| --- | |
| apiVersion: v1 | |
| kind: ConfigMap | |
| metadata: | |
| name: restic-config | |
| namespace: immich-restic-backup | |
| data: | |
| RESTIC_REPOSITORY: "s3:s3.us-east-1.amazonaws.com/r620-immich-cold-backup" | |
| RESTIC_PASSWORD: "CHANGE_ME" | |
| --- | |
| # --- INIT REPOSITORY (run one time only) --- | |
| apiVersion: batch/v1 | |
| kind: Job | |
| metadata: | |
| name: restic-init | |
| namespace: immich-restic-backup | |
| annotations: | |
| argocd.argoproj.io/sync-options: Force=true,Replace=true | |
| spec: | |
| template: | |
| spec: | |
| restartPolicy: Never | |
| containers: | |
| - name: restic-init | |
| image: restic/restic:0.18.1 | |
| env: | |
| - name: GOMAXPROCS | |
| value: "32" | |
| - name: RESTIC_PACK_SIZE | |
| value: "128" # 128MB | |
| envFrom: | |
| - configMapRef: | |
| name: restic-config | |
| - secretRef: | |
| name: aws-creds | |
| volumeMounts: | |
| - name: immich-data | |
| mountPath: /data | |
| command: | |
| - /bin/sh | |
| - -c | |
| - | | |
| echo "Initializing restic repository..." | |
| restic -r ${RESTIC_REPOSITORY} init || echo "Repository already exists." | |
| restic -r ${RESTIC_REPOSITORY} --verbose backup -o s3.storage-class=GLACIER -o s3.connections=16 /data --compression off --exclude "/data/thumbs" --exclude "/data/encoded-video" --skip-if-unchanged | |
| volumes: | |
| - name: immich-data | |
| hostPath: | |
| path: /mnt/homelab/immich-library-data/library | |
| type: Directory | |
| --- | |
| # --- BACKUP CRONJOB --- | |
| apiVersion: batch/v1 | |
| kind: CronJob | |
| metadata: | |
| name: restic-backup-cron | |
| namespace: immich-restic-backup | |
| spec: | |
| schedule: "0 3 * * *" # every day at 3am | |
| jobTemplate: | |
| spec: | |
| template: | |
| spec: | |
| restartPolicy: OnFailure | |
| containers: | |
| - name: restic-backup | |
| image: restic/restic:0.18.1 | |
| envFrom: | |
| - configMapRef: | |
| name: restic-config | |
| - secretRef: | |
| name: aws-creds | |
| volumeMounts: | |
| - name: immich-data | |
| mountPath: /data | |
| command: | |
| - /bin/sh | |
| - -c | |
| - | | |
| echo "Running backup…" | |
| restic -r ${RESTIC_REPOSITORY} --verbose backup -o s3.storage-class=GLACIER -o s3.connections=16 /data --compression off --exclude "/data/thumbs" --exclude "/data/encoded-video" --skip-if-unchanged | |
| restic forget --keep-monthly 1 --prune | |
| volumes: | |
| - name: immich-data | |
| hostPath: | |
| path: /mnt/homelab/immich-library-data/library | |
| type: Directory | |
| --- | |
| apiVersion: v1 | |
| kind: Namespace | |
| metadata: | |
| name: redis-server | |
| --- | |
| apiVersion: apps/v1 | |
| kind: Deployment | |
| metadata: | |
| name: redis-server | |
| namespace: redis-server | |
| labels: | |
| app: redis-server | |
| spec: | |
| selector: | |
| matchLabels: | |
| app: redis-server | |
| replicas: 1 | |
| template: | |
| metadata: | |
| labels: | |
| app: redis-server | |
| spec: | |
| containers: | |
| - image: redis:alpine | |
| name: redis-server | |
| ports: | |
| - containerPort: 6379 | |
| restartPolicy: Always | |
| --- | |
| apiVersion: v1 | |
| kind: Service | |
| metadata: | |
| name: redis-server | |
| namespace: redis-server | |
| labels: | |
| app: redis-server | |
| spec: | |
| ports: | |
| - port: 6379 | |
| selector: | |
| app: redis-server |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment