Skip to content

Wallabag

Self-hosted read-it-later application. Wallabag saves articles from the web by extracting their full text and storing them in your own PostgreSQL database. Read your saved articles offline across any device, organize them with tags, annotations, and reading lists, and share them with configurable access controls.

Key Features

  • Full-text extraction — saves the complete article content, not just a link
  • Multi-device access — web UI, mobile apps, browser extensions, and e-reader exports
  • Tag and annotation system — organize articles with tags, highlights, and notes
  • PostgreSQL backend — bundled subchart or external database
  • Optional Redis caching — subchart or external Redis for session and query caching
  • Persistent storage — PVC-backed data directory for extracted images and local cache
  • S3 backup — scheduled pg_dump of the Wallabag database 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 wallabag helmforge/wallabag

OCI registry:

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

Deployment Examples

# values.yaml — Wallabag with bundled PostgreSQL (default)
wallabag:
  domainName: 'https://wallabag.example.com'
  secret: 'a-random-symfony-app-secret-here'

postgresql:
  enabled: true
  auth:
    password: 'postgres-password'

persistence:
  enabled: true
  size: 5Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: wallabag.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Wallabag with PostgreSQL and Redis for caching
wallabag:
  domainName: 'https://wallabag.example.com'
  secret: 'a-random-symfony-app-secret-here'

postgresql:
  enabled: true
  auth:
    password: 'postgres-password'

redis:
  enabled: true
  auth:
    password: 'redis-password'

persistence:
  enabled: true
  size: 5Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: wallabag.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Wallabag with external PostgreSQL and Redis
wallabag:
  domainName: 'https://wallabag.example.com'
  secret: 'a-random-symfony-app-secret-here'

postgresql:
  enabled: false

database:
  external:
    host: postgresql.database.svc
    port: '5432'
    name: wallabag
    username: wallabag
    password: 'db-password'

redis:
  enabled: false

externalRedis:
  host: redis.cache.svc
  port: '6379'

persistence:
  enabled: true
  size: 5Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: wallabag.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Daily backup of the Wallabag database to S3
wallabag:
  domainName: 'https://wallabag.example.com'
  secret: 'a-random-symfony-app-secret-here'

postgresql:
  enabled: true
  auth:
    password: 'postgres-password'

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

persistence:
  enabled: true
  size: 5Gi

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/wallabag/wallabagWallabag container image.
image.tagstring"2.6.14"Image tag.
image.pullPolicystringIfNotPresentImage pull policy.
imagePullSecretsarray[]Pull secrets for private registries.

Wallabag Configuration

ParameterTypeDefaultDescription
wallabag.portinteger80Internal HTTP port for the Wallabag container.
wallabag.domainNamestring"https://wallabag.example.com"Public URL of the Wallabag instance. Must be changed before deploying.
wallabag.secretstring""Symfony APP_SECRET for cookie signing and CSRF protection.
wallabag.existingSecretstring""Existing Kubernetes Secret containing the Symfony secret.
wallabag.existingSecretKeystringsymfony-secretKey inside the existing secret holding the secret value.
wallabag.registrationbooleanfalseAllow new user registrations. Disabled by default for security.
wallabag.extraEnvarray[]Extra environment variables injected into the Wallabag container.
Change domainName before deploying

The default wallabag.domainName is https://wallabag.example.com. Wallabag uses this value to generate internal links for article sharing, e-reader exports, and API responses. Deploy with your actual public URL or internal links will be broken.

Always set wallabag.secret explicitly

If wallabag.secret is empty, the chart auto-generates a Symfony APP_SECRET. If the pod is recreated without a persistent secret, all user sessions are invalidated and CSRF tokens become invalid. Always set an explicit secret or use wallabag.existingSecret.

User registration is disabled by default

wallabag.registration: false is the chart default. After the initial deploy, create your admin account via the Wallabag setup wizard at /install. Enable registration: true only if you want public self-service sign-ups.

Database — Embedded Subchart

ParameterTypeDefaultDescription
postgresql.enabledbooleantrueDeploy a bundled PostgreSQL subchart for Wallabag.
postgresql.architecturestringstandalonePostgreSQL deployment architecture.
postgresql.auth.databasestringwallabagDatabase name created by the subchart.
postgresql.auth.usernamestringwallabagDatabase username created by the subchart.
postgresql.auth.passwordstring""Database password (auto-generated if empty).

Database — External

ParameterTypeDefaultDescription
database.external.hoststring""External PostgreSQL hostname or IP.
database.external.portstring"5432"External PostgreSQL port.
database.external.namestringwallabagDatabase name on the external server.
database.external.usernamestringwallabagUsername 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.

Cache — Redis Subchart

ParameterTypeDefaultDescription
redis.enabledbooleanfalseDeploy a bundled Redis subchart for session and query caching.
redis.architecturestringstandaloneRedis deployment architecture.
redis.auth.passwordstring""Redis password (auto-generated if empty).

Cache — External Redis

ParameterTypeDefaultDescription
externalRedis.hoststring""External Redis hostname or IP.
externalRedis.portstring6379External Redis port.

Persistence

ParameterTypeDefaultDescription
persistence.enabledbooleantrueEnable a PVC for /var/www/wallabag/data.
persistence.sizestring2GiPVC size.
persistence.storageClassstring""StorageClass for the PVC.
persistence.accessModesarray["ReadWriteOnce"]PVC access modes.
persistence.existingClaimstring""Use an existing PVC instead of creating one.

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

ParameterTypeDefaultDescription
probes.startup.enabledbooleantrueEnable startup probe.
probes.startup.initialDelaySecondsinteger15Startup probe initial delay.
probes.startup.periodSecondsinteger10Startup probe period.
probes.startup.timeoutSecondsinteger5Startup 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.

Backup

The backup CronJob runs pg_dump against the Wallabag PostgreSQL database and uploads the archive to S3. This protects all saved articles, tags, annotations, and user accounts.

ParameterTypeDefaultDescription
backup.enabledbooleanfalseEnable scheduled S3 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.archivePrefixstringwallabagPrefix for backup archive filenames.
backup.images.postgresqlstringdocker.io/library/postgres:18-alpineImage used for pg_dump.
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.prefixstringwallabagKey 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).
backup.database.hoststring""Override database host for backup (uses app credentials if empty).
backup.database.portstring""Override database port for backup.
backup.database.namestring""Override database name for backup.
backup.database.usernamestring""Override database username for backup.
backup.database.passwordstring""Override database password for backup.
backup.database.existingSecretstring""Existing secret containing backup database credentials.
backup.database.existingSecretPasswordKeystringpasswordKey in the existing secret for the backup database password.
backup.database.postgresDumpArgsstring""Extra arguments passed to pg_dump.

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

Articles not loading — domainName mismatch

If articles fail to load or share links are broken, verify that wallabag.domainName matches the exact public URL you are using to access Wallabag, including the https:// prefix and without a trailing slash. A mismatch causes Wallabag to generate internal links pointing to the wrong host.

Enable Redis for better performance under load

Redis is optional but recommended for multi-user setups. With Redis enabled, Wallabag offloads session storage and query result caching, reducing database load and improving response times for concurrent users.

More Information