MediKeep
Deploy MediKeep on Kubernetes as a self-hosted personal medical records application.
Overview
The HelmForge MediKeep chart uses the official ghcr.io/afairgiant/medikeep:v0.72.0 image. The container serves the React frontend and FastAPI backend on port 8000, stores structured records in PostgreSQL, and writes files under /app/uploads, /app/backups, and /app/logs.
MediKeep handles personal health data. Treat the PostgreSQL database, uploads PVC, backups PVC, logs, and runtime Secrets as sensitive.
Public Ingress or Gateway API exposure requires secrets.existingSecret or a
strong secrets.adminDefaultPassword; the chart rejects exposure that would
leave the upstream admin123 credential active.
MediKeep v0.72.0 adds visit relationships, broader advanced search and report
controls, and fixes health responses, SSO user identification, user-scoped tag
reads and attachment filenames. It does not change the service port, uploads
path or authentication environment contract.
Back up PostgreSQL and uploaded records before upgrading.
The chart no longer accepts the legacy app.port value. The pinned upstream
entrypoint always starts Uvicorn on container port 8000, so that value changed
only Kubernetes metadata and could break traffic. Do not use --reuse-values
for this migration because it can retain the removed default. Export the
user-supplied values, remove app.port from that file, and upgrade with
--reset-values:
helm get values medikeep --namespace medikeep -o yaml > medikeep-user-values.yaml
# Remove app.port from medikeep-user-values.yaml if it is present.
helm upgrade medikeep helmforge/medikeep --namespace medikeep \
--reset-values -f medikeep-user-values.yaml
Configure service.port when clients need a different Kubernetes Service port;
the Service targets the fixed named http listener.
Configure SSO_ONLY_MODE and SSO_AUTO_REDIRECT through app.env; they require
medikeep.sso.enabled=true and complete provider settings. Accepted boolean
values are true/false, 1/0, yes/no and on/off. Invalid values stop startup.
Recover from SSO lockout by setting SSO_ONLY_MODE=false and restarting the pod.
Set TRUSTED_PROXY_IPS through app.env to match the actual proxy addresses or
networks used for client IP resolution. See the
upstream release.
Configuration Reference
Core runtime:
image.repository,image.tag,image.pullPolicy: official pinned MediKeep image and pull behavior.replicaCount: pod count. The chart rejects values greater than1because MediKeep writes to local mounted paths.app.timezone,app.logLevel,app.debug,app.enableApiDocs,app.enableSsl.app.command,app.args,app.env,app.envFrom.commonLabels,nameOverride,fullnameOverride.
Secrets:
secrets.existingSecret: existing Secret for MediKeep runtime secrets.secrets.secretKeyKey,secrets.secretKey:SECRET_KEYsource.secrets.adminDefaultPasswordKey,secrets.adminDefaultPassword: initial admin password source.secrets.ssoClientSecretKey,secrets.ssoClientSecret: SSO client secret source.
Database:
postgresql.enabled: bundled HelmForge PostgreSQL dependency.postgresql.auth.database,postgresql.auth.username,postgresql.auth.password.database.external.host,database.external.port,database.external.name,database.external.username.database.external.existingSecret,database.external.existingSecretPasswordKey,database.external.password.
Persistence:
persistence.uploads: uploaded lab files, patient photos, and attachments.persistence.backups: backups generated by MediKeep.persistence.logs: application logs, disabled by default.
Exposure and operations:
service.type,service.port,service.annotations,service.ipFamilyPolicy,service.ipFamilies.ingress.enabled,ingress.ingressClassName,ingress.annotations,ingress.hosts,ingress.tls.gatewayAPI.enabled,gatewayAPI.httpRoutes.externalSecrets.enabled,externalSecrets.items.networkPolicy.enabled,networkPolicy.ingressFrom,networkPolicy.egress.enabled,networkPolicy.egress.allowDNS,networkPolicy.egress.extraTo,networkPolicy.egress.extraEgress.probes.startup,probes.liveness,probes.readiness.resources,podSecurityContext,securityContext,waitForDatabase.serviceAccount,pdb,nodeSelector,tolerations,affinity,topologySpreadConstraints.priorityClassName,terminationGracePeriodSeconds,podLabels,podAnnotations,extraVolumes,extraVolumeMounts,extraManifests.
MediKeep’s application listener is fixed at container port 8000 by the
upstream image. service.port is independent; for example, this exposes
Service port 8080 without changing the application process:
service:
port: 8080
Installation
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install medikeep helmforge/medikeep
OCI install:
helm install medikeep oci://ghcr.io/helmforgedev/helm/medikeep
Production Example
secrets:
existingSecret: medikeep-runtime
secretKeyKey: secret-key
adminDefaultPasswordKey: admin-password
persistence:
uploads:
size: 20Gi
backups:
size: 20Gi
logs:
enabled: true
size: 2Gi
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: medikeep.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: medikeep-tls
hosts:
- medikeep.example.com
networkPolicy:
enabled: true
Create the runtime Secret before first startup:
apiVersion: v1
kind: Secret
metadata:
name: medikeep-runtime
type: Opaque
stringData:
secret-key: replace-with-a-long-random-secret
admin-password: replace-with-a-strong-initial-password
Upstream creates admin/admin123 on fresh installs if ADMIN_DEFAULT_PASSWORD
is not set before first startup. Set a stronger initial password for production
and rotate it after first login. The chart rejects an inline admin123 value
for public exposure. Helm cannot inspect an existing Secret, so ensure the key
configured by secrets.adminDefaultPasswordKey exists and contains a strong
value. A publicly exposed pod will fail to start when the key is absent.
External PostgreSQL
postgresql:
enabled: false
database:
external:
host: postgres.example.com
name: medical_records
username: medapp
existingSecret: medikeep-db
existingSecretPasswordKey: password
Gateway API
gatewayAPI:
enabled: true
httpRoutes:
- parentRefs:
- name: public
namespace: gateway-system
hostnames:
- medikeep.example.com
External Secrets
secrets:
existingSecret: medikeep-runtime
externalSecrets:
enabled: true
items:
- fullnameOverride: medikeep-runtime
spec:
secretStoreRef:
kind: ClusterSecretStore
name: production
target:
name: medikeep-runtime
creationPolicy: Owner
data:
- secretKey: secret-key
remoteRef:
key: medikeep/app
property: secret-key
- secretKey: admin-password
remoteRef:
key: medikeep/app
property: admin-password
Backup
Back up PostgreSQL and the uploads and backups PVCs together. A database-only backup is incomplete when users attach lab files, patient photos, or generated backup archives.