Skip to content

Deploy Miniflux (RSS feedreader) via Argo CD

Design bead: hl-sy06 Status: Design Date: 2026-06-12

Miniflux is a minimalist, self-hosted RSS feedreader (single Go binary + Postgres). It replaces the reading/triage half of the just-cancelled Readwise Reader. The companion bookmark archive, Karakeep, stays — Miniflux feeds deliberate keepers into it via Miniflux’s native Karakeep save integration (added upstream in v2.2.10). The division of labour:

  • Miniflux = the river. Poll all feeds, skim/triage, mark read. Disposable.
  • Karakeep = the archive. Receives only entries you actively Save, then crawls + AI-tags them (existing in-cluster agentgateway LLM pipeline).

This collapses the manual-save-vs-auto-push question into a single correct behaviour: a deliberate one-click Save is the push. Auto-pushing every starred item was rejected — it rebuilds the firehose this migration just dismantled.

Recorded on hl-sy06 (Rule 7):

  • grounding/probe — no prior art; greenfield. Reuse the deploy pattern from docs/engineering/specs/2026-06-09-fovea-deploy-design.md (ArgoCD Application + ExternalSecret + secret/fzymgc-house/cluster/<app> under the wildcard reader policy).
  • grounding/context7 /miniflux/website — native Karakeep save integration (endpoint https://karakeep.fzymgc.house/api/v1/bookmarks + Karakeep API key + optional tags); save_entry webhook for automation; Fever API + Google Reader API for native clients; AUTH_PROXY_HEADER / TRUSTED_REVERSE_PROXY_NETWORKS for forward-auth, plus native generic OIDC.
  • grounding/context7 /freshrss/freshrss — richer web UI but Karakeep save is not native (extension/bridge required); heavier PHP+DB stack. Rejected.
  • grounding/probe (round 2, post-review) — confirmed the shared-main CNPG pattern via argocd/app-configs/cnpg/db-mealie.yaml + users-mealie.yaml (ADR hl-msh): a Database CR (cluster: main, owner: <app>) + a main-<app>-credentials ExternalSecret, both in the postgres namespace. Corrected D3 away from a dedicated Cluster + hstore.
  • D1 — Miniflux over FreshRSS. Native one-click Karakeep save (zero glue), single-binary ops, and open sync protocols outweigh FreshRSS’s richer built-in web UI. Since the iOS client is a swappable front-end (see D4), the Miniflux web UI only has to be a competent desktop triage pane, which it is.
  • D2 — Authentik OIDC, not forward-auth. Miniflux’s native OAUTH2_PROVIDER=oidc against an Authentik OIDC provider provisioned in tf/authentik/ matches the existing IaC-for-Authentik pattern and avoids an outpost/forward-auth dependency. OAUTH2_USER_CREATION=1 so first OIDC login provisions the account; local admin retained as break-glass.
  • D3 — CNPG Postgres on the shared main cluster. Follow the established cluster convention (ADR hl-msh; mirrors mealie/grafana/octopus): a Database CR (argocd/app-configs/cnpg/db-miniflux.yaml, cluster: main, owner: miniflux) plus a role-credentials ExternalSecret (users-miniflux.yamlmain-miniflux-credentials), both in the postgres namespace. No dedicated Cluster, no hstore: Miniflux dropped the hstore requirement in v2.0.27 and v2.2.14 migrates the extension out, so the ≥ 2.2.10 target needs no extension wiring. Schema is applied by Miniflux’s own RUN_MIGRATIONS=1 on startup.
  • D4 — Client is open-protocol, not bundled. Miniflux’s Google Reader API + Fever API stay enabled (default). iOS client is the user’s choice (NetNewsWire via Google Reader API recommended; Fiery Feeds has native Miniflux support); not a deployment concern.
  • D5 — Feeds model: read-all / save-keepers. Import all 17 feeds (the cleaned ~/Downloads/karakeep-feeds.txt / Reader OPML) into Miniflux. Disable the 11 remaining Karakeep auto-save feeds at cutover (the 6 firehoses are already disabled), so nothing double-archives and there is no read-coverage gap between now and Miniflux going live.
  • D6 — Karakeep integration is post-deploy config. The Karakeep API key + endpoint are entered once in Miniflux Settings → Integrations (per-user, stored in Miniflux’s DB), not a k8s Secret. Uses the rotated Karakeep key.
  1. ArgoCD Application miniflux — with resources-finalizer.argocd.argoproj.io so teardown cascades to all child resources (finalizer-per-Application lesson), plus the house ignoreDifferences block for ExternalSecret conversionStrategy/decodingStrategy/metadataPolicy fields (per the karakeep/fovea convention).
  2. Namespace miniflux.
  3. CNPG Database + role on shared maindb-miniflux.yaml (Database CR) + users-miniflux.yaml (ExternalSecret main-miniflux-credentials reading fzymgc-house/cluster/postgres/users/main-miniflux), both in the postgres namespace, mirroring db-mealie.yaml/users-mealie.yaml. No dedicated cluster, no extensions. Miniflux’s DATABASE_URL is assembled from those credentials.
  4. Miniflux Deployment + Service + Ingress — image pinned ≥ 2.2.10; host miniflux.fzymgc.house; cert-manager TLS; /healthcheck probe; Reloader annotation for secret-rotation restarts.
  5. ExternalSecrets — (a) app namespace miniflux: secret/fzymgc-house/cluster/miniflux for the OIDC client secret; (b) postgres namespace: main-miniflux-credentials from fzymgc-house/cluster/postgres/users/main-miniflux (DB role creds, manually populated like mealie). Both paths sit under the wildcard reader policy — no Vault policy edit.
  6. Authentik OIDC provider + application in tf/authentik/ — redirect URI https://miniflux.fzymgc.house/oauth2/oidc/callback; client id/secret mirrored into the Miniflux Vault path.
feeds ──poll──> Miniflux ──> entries
├─ read: Miniflux web (desktop) | iOS app via Google Reader/Fever API
└─ Save (deliberate) ──> POST karakeep/api/v1/bookmarks
└─> Karakeep crawl + AI-tag (agentgateway LLM)
  • DB: CNPG owns HA/backups; RUN_MIGRATIONS=1 reconciles schema on start.
  • Polling failures: surfaced per-feed in Miniflux UI (parsing_error_count); no cluster impact.
  • Karakeep save failure: Miniflux reports the integration error on Save; the entry stays in Miniflux (no silent loss). Karakeep being down never blocks reading.
  • OIDC outage: local admin account is break-glass.
  • Secret rotation: Reloader restarts the Deployment on ExternalSecret change.
  1. ArgoCD miniflux Application Synced + Healthy; pod Ready; /healthcheck 200.
  2. Authentik OIDC login succeeds; first login auto-provisions the user.
  3. OPML import of the 17 feeds populates categories/feeds; first poll succeeds.
  4. A chosen iOS app (NetNewsWire) connects via Google Reader API and syncs read-state both ways.
  5. Save an entry → it appears in Karakeep as a source: "rss"-style bookmark and gets AI-tagged.
  6. Cutover: disable the 11 remaining Karakeep auto-save feeds; confirm all 17 now live only in Miniflux.
  • Exact Miniflux image tag (latest stable ≥ 2.2.10).
  • Precise OIDC env var names (OAUTH2_OIDC_DISCOVERY_ENDPOINT, OAUTH2_CLIENT_ID/SECRET, OAUTH2_REDIRECT_URL, OAUTH2_OIDC_PROVIDER_NAME) verified against the pinned version. Note: Authentik’s discovery endpoint requires a trailing slash (https://<authentik>/application/o/miniflux/), unlike some providers — pin the exact slug-based URL. Miniflux appends /.well-known/openid-configuration itself, so store the base path, not the full well-known URL (don’t copy karakeep.tf’s oauth_wellknown_url, which is the full URL for NextAuth).
  • Ingress class + TLS issuer to match the Karakeep/cluster convention.
  • Whether NetworkPolicy is required (per the fovea clickstack precedent).