# Miniflux

Minimal self-hosted RSS reader ([miniflux.app](https://miniflux.app/),
Apache 2.0, ~30 MB Go single-binary). One unified inbox for tech
blogs, Hacker News, Lobste.rs, and selected subreddits.

## Why this stack

The fleet doesn't have a feed reader yet. Reddit subreddits expose
clean RSS feeds at `https://reddit.com/r/<sub>/.rss`, so subscribing
to your relevant subs alongside HN / blogs gives you a single place
to scan recent activity — no Reddit account needed, no polling
multiple sites by hand.

Self-hosted on `ana-docker` (10.250.50.70). Postgres bundled in the
stack rather than sharing pfi-postgres — keeps the dependency graph
flat and the DB is tiny (single-user).

## Deploy

```bash
scripts/elway ana-docker --playbook playbooks/deploy-miniflux.yaml
```

Cold deploy budget: ~250 MB image pull (postgres:16 + miniflux),
~10 s startup, ~1 s warmup.

After deploy, the .env on ana-docker still has placeholder passwords
— **edit those before first start succeeds**:

```bash
ssh ana-docker '
  cd /opt/docker/compose/miniflux
  sed -i "s|^MINIFLUX_DB_PASSWORD=.*|MINIFLUX_DB_PASSWORD=$(openssl rand -base64 24)|" .env
  sed -i "s|^MINIFLUX_ADMIN_PASSWORD=.*|MINIFLUX_ADMIN_PASSWORD=$(openssl rand -base64 18)|" .env
  grep ^MINIFLUX_ADMIN_PASSWORD .env  # one-time copy this for first login
  docker compose up -d
'
```

Then login at <http://10.250.50.70:8080> with the username from `.env`
(`lkraven` by default) and the printed admin password.

## Initial feed setup — OPML import

A starter OPML at `stacks/miniflux/starter-feeds.opml` covers:
- Hacker News + Lobste.rs
- r/selfhosted, r/homelab, r/LocalLLaMA
- r/nba (with spoiler caveat — see below)

Import via Miniflux UI: **Settings → Import → Choose File** → select
the OPML → Submit. All feeds appear in their categories; first
refresh fetches the most recent posts within seconds.

## r/nba spoiler block-list

Subreddit-RSS titles for game-day threads include final scores
(e.g. `Lakers 108 - Warriors 102 [Final]`). Miniflux supports
per-feed regex block rules to skip these.

After importing the OPML:

1. Go to **Feeds** → click **r/nba** → **Edit Feed**
2. In the **Block Filter** field, paste:

   ```
   \b\d{2,3}\s*[-–]\s*\d{2,3}\b|\[Final|Final Score|Game Thread.*\d{2,3}
   ```

3. Save. Past matching entries stay (they were already fetched);
   future fetches skip score-bearing headlines. Discussion threads,
   highlights, and meta-content still come through.

If a real post slips through with a score in the title, refine the
regex.

## Adding subreddits later

Reddit RSS URL patterns:

| URL | Returns |
|---|---|
| `https://reddit.com/r/<sub>/.rss` | Newest posts (firehose) |
| `https://reddit.com/r/<sub>/top/.rss?t=day` | Top-of-day (less spam) |
| `https://reddit.com/r/<sub>/top/.rss?t=week` | Top-of-week |
| `https://reddit.com/r/<sub>/hot/.rss` | Currently hot |

`top/.rss?t=day` is the lowest-noise option for high-volume subs
where you want highlights only.

In Miniflux: **Feeds → New Feed → URL**, paste, pick a category.

## Backup

Miniflux state lives in the named volume `miniflux-db-data`. To
include in restic, add a `pre-backup.sh` step on ana-docker that
dumps the DB to a stage path:

```bash
docker exec miniflux-db pg_dump -U miniflux miniflux \
  > /var/lib/restic/stage/miniflux.sql
```

Then restic's regular sweep picks up the SQL file. Subscriptions and
read-state are tiny (~MB even with months of history); the dump is
fast.

## Updating

```bash
ssh ana-docker '
  cd /opt/docker/compose/miniflux
  sed -i "s|^MINIFLUX_VERSION=.*|MINIFLUX_VERSION=<new>|" .env
  docker compose pull miniflux
  docker compose up -d
'
```

Migrations run automatically on container start (`RUN_MIGRATIONS=1`
in compose.yaml).
