Memos
Deploy Memos on Kubernetes as a lightweight self-hosted note-taking service.
Overview
The HelmForge Memos chart uses the official docker.io/neosmemo/memos:0.30.0 image and deploys a StatefulSet.
Memos listens on port 5230 and stores durable data under /var/opt/memos.
Memos 0.30 adds the Web Clipper, a rebuilt Markdown editor, multi-column feeds, signed webhooks, a rebuilt MCP toolset, and file-backed deployment
configuration. The chart uses the upstream /healthz endpoint for startup, readiness, and liveness probes.
The default topology is one persistent pod with SQLite. PostgreSQL and MySQL are supported through MEMOS_DRIVER and MEMOS_DSN, but the
data PVC remains required because Memos can still store local assets and instance data on disk.
Configuration Reference
Core runtime:
image.repository,image.tag,image.pullPolicy: official pinned Memos image and pull behavior.imagePullSecrets: optional registry pull secrets.replicaCount: Memos pod count. Keep1with SQLite; scale external database mode only with sharedMEMOS_DATAstorage.app.port: HTTP port.app.command,app.args: optional command and argument overrides.app.env,app.envFrom,app.extraEnv: additional runtime environment and Secret or ConfigMap imports.commonLabels,nameOverride,fullnameOverride: naming and common metadata controls.
Memos application:
memos.addr: bind address passed toMEMOS_ADDR.memos.instanceUrl: public URL for Ingress, Gateway API, or another reverse proxy.memos.demo: upstream demo mode. Keep disabled for real instances.memos.allowPrivateWebhooks: private webhook target control.memos.logLevel:debug,info,warn, orerror.
Database and storage:
database.driver:sqlite,mysql, orpostgres.database.dsn: inline lab DSN for MySQL or PostgreSQL.database.existingSecret,database.existingSecretKey: production DSN Secret.persistence.enabled,persistence.size,persistence.storageClass: Memos data directory storage.persistence.accessModes,persistence.existingClaim,persistence.mountPath.- The chart rejects SQLite scaling, external database without DSN, external database without a data volume, and scaled MySQL/PostgreSQL without
persistence.existingClaim. provisioning.existingSecret,provisioning.defaultMode: read-only Memos deployment-configuration files mounted at/etc/secrets.
Exposure and operations:
serviceAccount.create,serviceAccount.name,serviceAccount.annotations,serviceAccount.automountServiceAccountToken.service.type,service.port,service.annotations,service.ipFamilyPolicy,service.ipFamilies.ingress.enabled,ingress.ingressClassName,ingress.annotations,ingress.hosts,ingress.tls. Setingress.ingressClassName: ""to omitspec.ingressClassName.gateway.enabled,gateway.parentRefs,gateway.hostnames,gateway.path,gateway.pathType.pdb.enabled,pdb.minAvailable.networkPolicy.enabled,networkPolicy.ingressFrom,networkPolicy.egressIsolation,networkPolicy.dnsEgress,networkPolicy.httpsEgress,networkPolicy.extraEgress. Enabling onlynetworkPolicy.enabledcreates an ingress-only policy. SetnetworkPolicy.egressIsolation=truefor baseline DNS and HTTPS egress rules without custom rules.networkPolicy.dnsEgressdefaults tokube-systempods labeledk8s-app: kube-dnsand can be overridden for different DNS labels.networkPolicy.httpsEgressdefaults to IPv4 and IPv6 internet destinations on port 443 and can be overridden for restricted webhook or integration destinations. SettingnetworkPolicy.extraEgressalso enables egress isolation and appends the supplied rules.probes.startup,probes.liveness,probes.readiness: enable flags and timing values.resources,podSecurityContext,securityContext,nodeSelector,tolerations,affinity.topologySpreadConstraints,priorityClassName,terminationGracePeriodSeconds.podLabels,podAnnotations,extraVolumes,extraVolumeMounts,extraManifests.
Installation
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install memos helmforge/memos
OCI install:
helm install memos oci://ghcr.io/helmforgedev/helm/memos
Production Example
memos:
instanceUrl: https://memos.example.com
persistence:
enabled: true
size: 20Gi
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: memos.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: memos-tls
hosts:
- memos.example.com
networkPolicy:
enabled: true
Set memos.instanceUrl when Memos is behind Ingress, Gateway API, or another reverse proxy.
In Memos 0.30, an unset instance URL also selects private mode, redirects anonymous visitors to sign in, and disables RSS.
Set networkPolicy.egressIsolation=true when outbound DNS and HTTPS should be explicitly allowed by the chart-managed NetworkPolicy.
Deployment Configuration
Memos can load OAuth2 identity providers and instance settings from a Kubernetes Secret:
provisioning:
existingSecret: memos-provisioning
The Secret keys become filenames under /etc/secrets. Identity-provider files use
memos-idp-<label>.json; instance settings use the fixed filenames
memos-instance-setting-general.json, memos-instance-setting-storage.json,
memos-instance-setting-memo-related.json, memos-instance-setting-notification.json, and
memos-instance-setting-ai.json. Unsupported instance-setting suffixes are ignored. For example:
apiVersion: v1
kind: Secret
metadata:
name: memos-provisioning
type: Opaque
stringData:
memos-instance-setting-general.json: |
{
"key": "GENERAL",
"generalSetting": {
"disallowUserRegistration": false,
"disallowPasswordAuth": false,
"weekStartDayOffset": 1
}
}
Memos validates the complete file set before serving traffic. Each setting file replaces its complete database-backed group rather than merging with
it; omitted scalar fields reset to defaults, so include every required field needed to preserve the intended configuration. Files cannot be edited
through the UI/API while mounted. Every replica must mount identical files, and Secret changes require an orderly restart of every replica. Supported
setting keys are GENERAL, STORAGE, MEMO_RELATED, NOTIFICATION, and AI.
External Database
database:
driver: postgres
existingSecret: memos-postgres
existingSecretKey: dsn
persistence:
existingClaim: memos-shared-data
The Secret should contain a Memos-compatible DSN:
apiVersion: v1
kind: Secret
metadata:
name: memos-postgres
type: Opaque
stringData:
dsn: postgres://memos:password@postgresql:5432/memos?sslmode=disable
The chart blocks unsafe configurations:
- multiple replicas with SQLite
- multiple replicas with MySQL/PostgreSQL and no shared existing data claim
- MySQL/PostgreSQL without a DSN Secret or inline DSN
- external database with no data volume
Upgrading To Memos 0.30
Back up the PVC, any external database, and the Secret selected by provisioning.existingSecret first. The Secret backup must preserve the mounted
OAuth2/IdP and instance-setting JSON files. Check these upstream compatibility changes:
- set
memos.instanceUrlto preserve public anonymous access and RSS - shared-memo clients must use
GET /api/v1/shares/{share_token}/memo - saved time filters use CEL timestamp fields and
nowinstead ofnow(); for example,created_ts >= now - duration("24h") - MCP clients must use the stateless tools-only
/mcpendpoint and service-prefixed tool names
Security
The chart runs the upstream non-root UID/GID 10001, disables ServiceAccount token automount by default, drops Linux capabilities, and keeps
memos.allowPrivateWebhooks=false.
Only enable private webhooks when the targets are trusted internal services and cluster egress is controlled.
Backup
Back up the PVC in every mode. With SQLite, it contains the database and assets. With PostgreSQL or MySQL, it can still contain local assets and instance data, so database backup alone is not enough.