Deploy Miniflux (RSS feedreader) via Argo CD
Design bead: hl-sy06
Status: Design
Date: 2026-06-12
Summary
Section titled “Summary”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.
Grounding traces
Section titled “Grounding traces”Recorded on hl-sy06 (Rule 7):
grounding/probe— no prior art; greenfield. Reuse the deploy pattern fromdocs/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 (endpointhttps://karakeep.fzymgc.house/api/v1/bookmarks+ Karakeep API key + optional tags);save_entrywebhook for automation; Fever API + Google Reader API for native clients;AUTH_PROXY_HEADER/TRUSTED_REVERSE_PROXY_NETWORKSfor 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-mainCNPG pattern viaargocd/app-configs/cnpg/db-mealie.yaml+users-mealie.yaml(ADRhl-msh): aDatabaseCR (cluster: main,owner: <app>) + amain-<app>-credentialsExternalSecret, both in thepostgresnamespace. Corrected D3 away from a dedicatedCluster+hstore.
Decisions
Section titled “Decisions”- 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=oidcagainst an Authentik OIDC provider provisioned intf/authentik/matches the existing IaC-for-Authentik pattern and avoids an outpost/forward-auth dependency.OAUTH2_USER_CREATION=1so first OIDC login provisions the account; local admin retained as break-glass. - D3 — CNPG Postgres on the shared
maincluster. Follow the established cluster convention (ADRhl-msh; mirrors mealie/grafana/octopus): aDatabaseCR (argocd/app-configs/cnpg/db-miniflux.yaml,cluster: main,owner: miniflux) plus a role-credentials ExternalSecret (users-miniflux.yaml→main-miniflux-credentials), both in thepostgresnamespace. No dedicatedCluster, nohstore: Miniflux dropped thehstorerequirement 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 ownRUN_MIGRATIONS=1on 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.
Components
Section titled “Components”- ArgoCD Application
miniflux— withresources-finalizer.argocd.argoproj.ioso teardown cascades to all child resources (finalizer-per-Application lesson), plus the houseignoreDifferencesblock for ExternalSecretconversionStrategy/decodingStrategy/metadataPolicyfields (per the karakeep/fovea convention). - Namespace
miniflux. - CNPG
Database+ role on sharedmain—db-miniflux.yaml(Database CR) +users-miniflux.yaml(ExternalSecretmain-miniflux-credentialsreadingfzymgc-house/cluster/postgres/users/main-miniflux), both in thepostgresnamespace, mirroringdb-mealie.yaml/users-mealie.yaml. No dedicated cluster, no extensions. Miniflux’sDATABASE_URLis assembled from those credentials. - Miniflux Deployment + Service + Ingress — image pinned ≥ 2.2.10;
host
miniflux.fzymgc.house; cert-manager TLS;/healthcheckprobe; Reloader annotation for secret-rotation restarts. - ExternalSecrets — (a) app namespace
miniflux:secret/fzymgc-house/cluster/minifluxfor the OIDC client secret; (b)postgresnamespace:main-miniflux-credentialsfromfzymgc-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. - Authentik OIDC provider + application in
tf/authentik/— redirect URIhttps://miniflux.fzymgc.house/oauth2/oidc/callback; client id/secret mirrored into the Miniflux Vault path.
Data flow
Section titled “Data flow”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)Error handling & ops
Section titled “Error handling & ops”- DB: CNPG owns HA/backups;
RUN_MIGRATIONS=1reconciles 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.
Validation
Section titled “Validation”- ArgoCD
minifluxApplication Synced + Healthy; pod Ready;/healthcheck200. - Authentik OIDC login succeeds; first login auto-provisions the user.
- OPML import of the 17 feeds populates categories/feeds; first poll succeeds.
- A chosen iOS app (NetNewsWire) connects via Google Reader API and syncs read-state both ways.
- Save an entry → it appears in Karakeep as a
source: "rss"-style bookmark and gets AI-tagged. - Cutover: disable the 11 remaining Karakeep auto-save feeds; confirm all 17 now live only in Miniflux.
Deferred to the implementation plan
Section titled “Deferred to the implementation plan”- 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-configurationitself, so store the base path, not the full well-known URL (don’t copykarakeep.tf’soauth_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).