Skip to content

Ghost

Modern open-source publishing platform for blogs, newsletters, and memberships. Ghost provides a polished writing editor, a built-in membership and subscription system, email newsletter delivery, and a headless CMS API — all backed by MySQL.

Key Features

  • Modern editor — clean, distraction-free writing experience with Markdown and rich cards
  • Memberships and newsletters — built-in subscription tiers and email newsletter delivery
  • Headless CMS API — Content API and Admin API for frontend frameworks and integrations
  • MySQL backend — bundled subchart or external MySQL database
  • Content persistence — PVC-backed content directory for images, media, and uploaded files
  • S3 content backup — scheduled archive of the Ghost content directory to S3-compatible storage
  • Ingress support — TLS via cert-manager with configurable ingress class

Installation

HTTPS repository:

helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install ghost helmforge/ghost

OCI registry:

helm install ghost oci://ghcr.io/helmforgedev/helm/ghost

Deployment Examples

# values.yaml — Ghost with bundled MySQL (default)
ghost:
  url: 'https://blog.example.com'

mysql:
  enabled: true
  auth:
    password: 'mysql-password'

persistence:
  enabled: true
  size: 10Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: blog.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Ghost with an existing MySQL instance
ghost:
  url: 'https://blog.example.com'

mysql:
  enabled: false

database:
  external:
    host: mysql.database.svc
    port: '3306'
    name: ghost
    username: ghost
    password: 'db-password'

persistence:
  enabled: true
  size: 10Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: blog.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Ghost with SMTP for newsletter delivery
ghost:
  url: 'https://blog.example.com'
  extraEnv:
    - name: mail__transport
      value: SMTP
    - name: mail__options__host
      value: smtp.example.com
    - name: mail__options__port
      value: '587'
    - name: mail__options__auth__user
      value: ghost@example.com
    - name: mail__options__auth__pass
      valueFrom:
        secretKeyRef:
          name: ghost-smtp-secret
          key: password
    - name: mail__from
      value: '"My Blog" <ghost@example.com>'

mysql:
  enabled: true
  auth:
    password: 'mysql-password'

persistence:
  enabled: true
  size: 10Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: blog.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Daily backup of Ghost content directory to S3
# NOTE: The backup archives the content PVC (images, media, themes).
#       MySQL data is NOT included — back up the database separately.
ghost:
  url: 'https://blog.example.com'

mysql:
  enabled: true
  auth:
    password: 'mysql-password'

persistence:
  enabled: true
  size: 10Gi

backup:
  enabled: true
  schedule: '0 3 * * *'
  s3:
    endpoint: https://s3.amazonaws.com
    bucket: my-ghost-backups
    accessKey: '<set-me>'
    secretKey: '<set-me>'

Configuration Reference

Core

ParameterTypeDefaultDescription
nameOverridestring""Override the chart name.
fullnameOverridestring""Override the full release name.
commonLabelsobject{}Extra labels added to all resources.

Image

ParameterTypeDefaultDescription
image.repositorystringdocker.io/library/ghostGhost container image.
image.tagstring"6.37.1"Image tag.
image.pullPolicystringIfNotPresentImage pull policy.
imagePullSecretsarray[]Pull secrets for private registries.

Ghost Configuration

ParameterTypeDefaultDescription
ghost.urlstring""Public URL of the Ghost instance (e.g. https://blog.example.com).
ghost.extraEnvarray[]Extra environment variables for SMTP, integrations, and advanced settings.
ghost.url must match your actual public URL

Ghost uses ghost.url to generate all links: newsletter emails, canonical URLs, webhook payloads, and API responses. If this value does not match the URL your visitors use, email links will be broken, SEO canonical tags will be wrong, and the Admin UI may fail to redirect correctly.

Ghost requires MySQL — PostgreSQL is not supported

Ghost only supports MySQL (or MariaDB) as its database engine. This chart does not support PostgreSQL. Use the bundled MySQL subchart or provide an external MySQL instance via database.external.

Configure SMTP to enable newsletter delivery

Ghost starts without SMTP configured, but newsletter sending and member invitation emails will fail silently. Configure SMTP via ghost.extraEnv using the mail__* environment variable convention shown in the “With Email (SMTP)” example above.

Database — Embedded Subchart

ParameterTypeDefaultDescription
mysql.enabledbooleantrueDeploy a bundled MySQL subchart for Ghost.
mysql.architecturestringstandaloneMySQL deployment architecture.
mysql.auth.databasestringghostDatabase name created by the subchart.
mysql.auth.usernamestringghostDatabase username created by the subchart.
mysql.auth.passwordstring""Database password (auto-generated if empty).

Database — External

ParameterTypeDefaultDescription
database.external.hoststring""External MySQL hostname or IP.
database.external.portstring"3306"External MySQL port.
database.external.namestringghostDatabase name on the external server.
database.external.usernamestringghostUsername for the external database.
database.external.passwordstring""Password for the external database (plain text — prefer secret).
database.external.existingSecretstring""Existing secret containing the database password.
database.external.existingSecretPasswordKeystringpasswordKey inside the existing secret for the password.

Content Persistence

ParameterTypeDefaultDescription
persistence.enabledbooleantrueEnable a PVC for /var/lib/ghost/content (images, media, themes).
persistence.sizestring10GiPVC size.
persistence.storageClassstring""StorageClass for the PVC.
persistence.accessModesarray["ReadWriteOnce"]PVC access modes.
persistence.existingClaimstring""Use an existing PVC instead of creating one.

Backup

S3 backup covers content files only — not the MySQL database

The S3 backup CronJob archives the Ghost content directory (/var/lib/ghost/content) — uploaded images, media files, and custom themes. It does not back up the MySQL database, which contains posts, members, settings, and newsletter data. Configure a separate MySQL backup strategy (e.g. the HelmForge MySQL chart backup feature) to protect the full Ghost dataset.

ParameterTypeDefaultDescription
backup.enabledbooleanfalseEnable scheduled S3 content backup CronJob.
backup.schedulestring"0 3 * * *"Cron schedule for backups.
backup.suspendbooleanfalseSuspend the CronJob without deleting it.
backup.concurrencyPolicystringForbidCronJob concurrency policy.
backup.successfulJobsHistoryLimitinteger3Number of successful Job records to keep.
backup.failedJobsHistoryLimitinteger3Number of failed Job records to keep.
backup.backoffLimitinteger1Job retry limit.
backup.archivePrefixstringghostPrefix for backup archive filenames.
backup.images.backupstringdocker.io/library/busybox:1.37Image used for tar archive.
backup.images.uploaderstringdocker.io/helmforge/mc:1.0.0Image used for S3 upload.
backup.resourcesobject{}Resources for backup containers.
backup.s3.endpointstring""S3-compatible endpoint URL.
backup.s3.bucketstring""Target bucket name.
backup.s3.prefixstringghostKey prefix within the bucket.
backup.s3.createBucketIfNotExistsbooleantrueCreate the bucket automatically if it does not exist.
backup.s3.existingSecretstring""Existing secret containing S3 access and secret keys.
backup.s3.existingSecretAccessKeyKeystringaccess-keyKey in the existing secret for the S3 access key.
backup.s3.existingSecretSecretKeyKeystringsecret-keyKey in the existing secret for the S3 secret key.
backup.s3.accessKeystring""Inline S3 access key (ignored when existingSecret is set).
backup.s3.secretKeystring""Inline S3 secret key (ignored when existingSecret is set).

Service

ParameterTypeDefaultDescription
service.typestringClusterIPKubernetes service type.
service.portinteger80Service port exposed to the cluster.
service.annotationsobject{}Annotations for the Service.

Ingress

ParameterTypeDefaultDescription
ingress.enabledbooleanfalseEnable an Ingress resource.
ingress.ingressClassNamestringtraefikIngress class name.
ingress.annotationsobject{}Annotations for the Ingress (e.g. cert-manager).
ingress.hostsarray[]Ingress host and path rules.
ingress.tlsarray[]TLS configuration (secret name and hosts).

Probes

Probes use the Ghost Admin API endpoint /ghost/api/admin/site/ to verify the application is ready.

ParameterTypeDefaultDescription
probes.startup.enabledbooleantrueEnable startup probe.
probes.startup.initialDelaySecondsinteger15Startup probe initial delay.
probes.startup.periodSecondsinteger5Startup probe period.
probes.startup.timeoutSecondsinteger3Startup probe timeout.
probes.startup.failureThresholdinteger30Startup probe failure threshold.
probes.liveness.enabledbooleantrueEnable liveness probe.
probes.liveness.initialDelaySecondsinteger0Liveness probe initial delay.
probes.liveness.periodSecondsinteger15Liveness probe period.
probes.liveness.timeoutSecondsinteger5Liveness probe timeout.
probes.liveness.failureThresholdinteger3Liveness probe failure threshold.
probes.readiness.enabledbooleantrueEnable readiness probe.
probes.readiness.initialDelaySecondsinteger0Readiness probe initial delay.
probes.readiness.periodSecondsinteger10Readiness probe period.
probes.readiness.timeoutSecondsinteger5Readiness probe timeout.
probes.readiness.failureThresholdinteger3Readiness probe failure threshold.

Resources and Security

ParameterTypeDefaultDescription
resourcesobject{}CPU and memory requests and limits.
podSecurityContextobject{}Pod-level security context.
securityContextobject{}Container-level security context.

Service Account

ParameterTypeDefaultDescription
serviceAccount.createbooleanfalseCreate a dedicated ServiceAccount.
serviceAccount.namestring""Override the ServiceAccount name.
serviceAccount.annotationsobject{}Annotations for the ServiceAccount.

Scheduling

ParameterTypeDefaultDescription
nodeSelectorobject{}Node selector for scheduling.
tolerationsarray[]Tolerations for scheduling.
affinityobject{}Affinity rules.
topologySpreadConstraintsarray[]Topology spread constraints.
priorityClassNamestring""PriorityClass for the pod.
terminationGracePeriodSecondsinteger30Termination grace period.
podLabelsobject{}Extra labels for the pod.
podAnnotationsobject{}Extra annotations for the pod.

Extra

ParameterTypeDefaultDescription
extraVolumesarray[]Extra volumes to attach to the pod.
extraVolumeMountsarray[]Extra volume mounts for the container.
extraManifestsarray[]Extra Kubernetes manifests deployed alongside the chart.

Common Issues

Newsletter emails not sending

Ghost starts successfully without SMTP configured, but no emails will be delivered. If member invitations, newsletter sends, or password reset emails are missing, configure the mail__* environment variables via ghost.extraEnv. Check the Ghost logs (kubectl logs) for SMTP connection errors.

Access the Admin panel

The Ghost Admin panel is available at https://blog.example.com/ghost/. On first deployment, Ghost presents a setup wizard to create the admin account and configure the publication name and description.

More Information