Miniflux: Minimal Self-Hosted RSS
RSS never died. Millions of people still use it — they just moved to centralized services like Feedly and Inoreader where someone else manages the infrastructure. If you’d rather own your reading workflow, Miniflux is the cleanest option in the self-hosted RSS space.
Miniflux is a deliberately minimalist feed reader: a single statically-compiled Go binary, a PostgreSQL database, and a server-rendered web UI with no JavaScript bloat. It’s fast, it’s simple to operate, and it integrates with Fever API clients so you can use a native mobile app if you prefer. Created by Frédéric Guillot and licensed Apache 2.0, it’s been actively maintained for years with a clear philosophy: improve what exists rather than pile on features.
Architecture
The entire application is a single Go binary with zero runtime dependencies. No Node.js, no Ruby, no external asset pipeline — just a binary and a PostgreSQL database. Static assets (HTML, CSS, the minimal JavaScript for keyboard shortcuts) are embedded into the binary at build time using Go’s embed package.
PostgreSQL is the only supported database. This is a deliberate choice to keep the codebase focused; there’s no SQLite or MySQL path, and none is planned. The database does real work — full-text search, JSONB storage, window functions — so the constraint makes the implementation cleaner than trying to abstract over multiple engines.
Resource requirements are modest: a single core and 50–200 MB of RAM handles hundreds of feeds comfortably. The bottleneck is almost always network I/O during feed polling, not CPU or memory.
Deploying with Docker Compose
Basic Setup
|
|
RUN_MIGRATIONS=1 applies database schema migrations automatically on startup. CREATE_ADMIN=1 bootstraps the initial admin account using ADMIN_USERNAME and ADMIN_PASSWORD — these are only used on the first run and ignored thereafter.
The depends_on health check ensures Miniflux waits for PostgreSQL to be ready before starting. Without this, Miniflux exits immediately on startup because it can’t connect.
Behind Traefik
For HTTPS termination via Traefik:
|
|
The database is on the internal network only — it’s not reachable from outside the Docker network. Miniflux sits on both networks, bridging the two.
Set BASE_URL to your external URL. Miniflux uses this for generating correct links in API responses and feed-level settings. If it’s wrong, API clients get broken URLs.
Environment Variable Reference
| Variable | Default | Purpose |
|---|---|---|
DATABASE_URL |
— | PostgreSQL connection string (required) |
RUN_MIGRATIONS |
0 |
Set to 1 to auto-migrate on startup |
CREATE_ADMIN |
0 |
Set to 1 to create admin on first run |
ADMIN_USERNAME |
— | Bootstrap admin username |
ADMIN_PASSWORD |
— | Bootstrap admin password |
BASE_URL |
http://localhost |
External URL — used in API and links |
LISTEN_ADDR |
0.0.0.0:8080 |
Internal bind address |
POLLING_FREQUENCY |
60 |
Minutes between polling runs |
POLLING_SCHEDULER |
round_robin |
round_robin or entry_frequency |
BATCH_SIZE |
100 |
Feeds processed per polling run |
WORKER_POOL_SIZE |
5 |
Concurrent feed fetchers |
FETCHER_TIMEOUT |
30 |
HTTP timeout in seconds |
PROXY_IMAGES |
none |
none, http-only, or all |
FETCH_YOUTUBE_WATCH_TIME |
0 |
Extract YouTube video duration |
POLLING_PARSING_ERROR_LIMIT |
10 |
Errors before disabling a feed (use ≥1) |
OAUTH2_PROVIDER |
— | google or oidc for SSO |
FETCHER_ALLOW_PRIVATE_NETWORKS |
0 |
Set to 1 for internal/homelab feeds |
Polling Schedulers
Miniflux offers two feed polling strategies:
round_robin (default) — polls feeds in a fixed rotating order at a consistent interval. Every feed gets checked on the same schedule regardless of how often it actually updates. Predictable, simple, works well when you have a small to moderate feed list where you know the sources.
entry_frequency — analyses each feed’s historical update frequency over the past week and polls accordingly. A feed that publishes 20 times a day gets checked more often than one that publishes weekly. This reduces unnecessary requests to dormant feeds and concentrates polling bandwidth on active sources. Better choice for large or mixed collections.
BATCH_SIZE controls how many feeds are processed per polling run. With POLLING_FREQUENCY=60 and BATCH_SIZE=100, up to 100 feeds are refreshed each hour. Increase WORKER_POOL_SIZE to fetch those feeds concurrently.
For a homelab with 200+ feeds, a reasonable configuration:
|
|
Feed Rules: Filtering, Rewriting, and Scraping
This is where Miniflux earns its keep for power users. Rules are configured per-feed in the feed settings.
Block and Keep Rules
Block rules discard entries whose titles or content match a regex pattern. Keep rules do the inverse — discard everything that doesn’t match. Use RE2 regex syntax.
Block rule examples:
(?i)sponsored
(?i)press release
(?i)\[ad\]
Keep rule example (only keep Kubernetes-related entries):
(?i)kubernetes|k8s|helm|kubectl
Max-age rule — drop entries older than a threshold:
max-age:7d
Units: ns, us, ms, s, m, h, d. Useful for feeds that republish old content.
Rewrite Rules
Rewrite rules transform URLs before Miniflux fetches content. The format is search_pattern@@@replacement:
# Strip tracking parameters from URLs
^(https://example\.com/article/[^?]+).*$@@@$1
# Force HTTPS
^http://(.+)$@@@https://$1
# Point to a different page variant (e.g., full article vs. paginated)
^(.+\.html).*$@@@$1?seite=all
Content Scraper
Many feeds provide only a summary or a truncated excerpt. The content scraper fetches the original page and extracts the full article — entirely locally, using a Readability-based parser with no external service.
Miniflux ships with predefined scraper rules for 100+ popular websites. For others, you can write a CSS selector rule per feed:
.article-body
article > div.content
main .post-content
If no custom rule matches, the Readability algorithm takes over as a fallback.
You can trigger scraping manually per entry with the d keyboard shortcut, or configure it to run automatically for a feed.
Keyboard Shortcuts
Miniflux’s keyboard-driven UI is one of its signature features. Navigation is Vi-style:
Global navigation:
| Shortcut | Action |
|---|---|
g h |
History |
g f |
Feeds |
g c |
Categories |
g b |
Bookmarks (starred) |
g s |
Settings |
? |
Show shortcut help |
/ |
Search |
Reading list navigation:
| Shortcut | Action |
|---|---|
j / ↓ |
Next item |
k / ↑ |
Previous item |
o |
Open selected item |
v |
Open original URL in new tab |
m |
Toggle read/unread |
A |
Mark all visible as read |
f |
Star/unstar entry |
d |
Fetch full content (scraper) |
s |
Save to external service |
# |
Remove feed |
Escape |
Close dialogs |
Firefox note: Firefox blocks the v shortcut for programmatic new-tab opens. You’ll need to authorize it in Firefox’s accessibility settings or just use middle-click.
Mobile Clients via Fever API
Miniflux implements the Fever API, which allows dedicated RSS client apps to use it as a backend. Enable it in Settings → Integrations — Miniflux auto-generates the Fever credentials.
iOS clients:
- Reeder — the most polished option; gesture-based, offline caching, excellent typography
- Unread — minimalist and focused on the reading experience
- ReadKit — native macOS/iOS, good for cross-device sync
- NetNewsWire — free and open-source, solid if you’re already in the Apple ecosystem
Android:
- Fleuron — built specifically for Miniflux using Material You design; the best native-feeling option
Miniflux also implements a subset of the Google Reader API for clients built around that protocol. Configure it separately in Settings → Integrations → Google Reader API with a dedicated username and password.
The responsive web UI itself works well on mobile for users who don’t want a separate app — it’s genuinely usable on a phone without pinching and zooming.
SSO with OIDC
Miniflux supports OAuth2/OIDC for single sign-on. If your homelab already has Authentik, Keycloak, or Authelia as an identity provider, you can wire Miniflux into it:
|
|
Note: Miniflux automatically appends /.well-known/openid-configuration to the discovery endpoint URL. Don’t include that suffix in OAUTH2_OIDC_DISCOVERY_ENDPOINT — it will result in a double-append and a 404.
OAUTH2_USER_CREATION=1 allows new users to be created automatically on first SSO login. Without it, users must be pre-created in Miniflux before they can log in via SSO.
REST API
Every operation in the UI is available via REST API. Authentication supports two methods: HTTP Basic Auth or an API key in the X-Auth-Token header. Generate API keys in Settings → API Keys.
Base URL: https://rss.yourdomain.com/v1/
Common operations:
|
|
Official client libraries exist for Go (miniflux.app/v2/client) and Python (miniflux on PyPI). The Go client is maintained in the same repository as the server.
Webhooks
Miniflux can POST to a webhook URL whenever new entries arrive. Requests are HMAC-SHA256 signed — validate the X-Miniflux-Signature header in your handler to confirm authenticity.
This makes it straightforward to wire Miniflux into n8n, a custom API, or a notification service. The community n8n node (n8n-nodes-miniflux) also exposes Miniflux operations directly in n8n’s visual workflow builder.
A simple webhook workflow:
- New entry arrives in the “Security” category
- Miniflux POSTs to your n8n webhook
- n8n filters for high-severity CVE entries
- Sends a Slack notification or creates a ticket
External Service Integrations
Miniflux has built-in save-to integrations for read-later and bookmarking services, configured in Settings → Integrations:
- Wallabag — self-hosted read-later (the obvious homelab pairing)
- Pocket — the mainstream option
- Instapaper — clean archival format
- Pinboard — for the bookmark-everything crowd
Once configured, the s keyboard shortcut saves the current article to your chosen service.
OPML Migration
Moving from another RSS reader? Export OPML from your current tool and import it:
|
|
Or use the web UI: Feeds → Import.
If migrating from Miniflux v1, expect some duplicate entries on the first refresh after import — entries are keyed differently between versions and Miniflux will see them as new. This clears up on the next polling cycle.
Comparison with Alternatives
| Miniflux | FreshRSS | Tiny Tiny RSS | NewsBlur | |
|---|---|---|---|---|
| Language | Go | PHP | PHP | Python/Django |
| Database | PostgreSQL only | SQLite / PostgreSQL / MySQL | PostgreSQL | MongoDB / PostgreSQL |
| Deployment | Single binary | PHP app | PHP app | Multi-container |
| UI philosophy | Minimal, server-rendered | Feature-rich | Feature-rich, plugin-heavy | Feature-rich |
| Mobile | Fever API + responsive web | Fever API | Paid apps | Native apps |
| Keyboard shortcuts | Yes (Vi-style) | Limited | Yes | Yes |
| Content scraper | Yes (built-in) | Via plugins | Via plugins | Yes |
| Full-text search | Yes (PostgreSQL FTS) | Yes | Yes | Yes |
| SSO/OIDC | Yes | Via plugins | Limited | No |
| Webhook support | Yes | Via plugins | Via plugins | No |
| Operational complexity | Low | Medium | Medium-High | High |
Choose Miniflux if you want something that just works with minimal operational overhead, you value a clean reading experience over a feature checklist, and you already have PostgreSQL somewhere.
Choose FreshRSS if you need MySQL/SQLite support or want a richer plugin ecosystem without PostgreSQL.
Choose TTRSS if you have very specific filtering or plugin requirements and don’t mind a rougher admin experience.
Gotchas
POLLING_PARSING_ERROR_LIMIT=0 is broken. Setting it to 0 incorrectly marks feeds as broken even when they have no errors. Use any value ≥1. The default of 10 is reasonable.
Private network feeds are blocked by default. If you’re subscribing to feeds hosted on your internal network (other homelab services, internal wikis), add:
|
|
BASE_URL must match your external URL exactly. If you access Miniflux at https://rss.yourdomain.com but BASE_URL is set to http://localhost:8080, API responses and mobile clients will get broken URLs.
No horizontal scaling. Miniflux doesn’t cluster. One instance + one PostgreSQL is the deployment model. For high availability, run a hot-standby PostgreSQL replica and failover manually.
PostgreSQL backups are the whole story. Since everything lives in PostgreSQL, your backup strategy is simply: backup the database. pg_dump on a schedule, or continuous archiving with WAL shipping, is sufficient.
The Bottom Line
Miniflux is the RSS reader for people who want to read feeds, not configure a feed reader. The deployment is as simple as self-hosted software gets — one binary, one database, one compose file — and the operational surface area is tiny.
The keyboard shortcuts and content scraper make it genuinely pleasant for heavy RSS users. The Fever API means you can use a polished native client on your phone without giving up the self-hosted backend. And the REST API and webhook support make it composable with the rest of your homelab automation stack.
If you’ve been putting off self-hosting an RSS reader because the options felt too heavy, Miniflux is the one to try first.
Comments