A dead-simple, self-hosted RSS reader. Go backend with an htmx web UI, a JSON API for browser extensions, per-user accounts, feed discovery, and SQLite storage.
- Author-centric — every feed belongs to an author; feeds are always viewed through the author who publishes them.
- Automagical adds — paste a URL and nanoflux discovers the feed, derives the title/home url, and creates an author with their first feed attached.
- Collections — group feeds into folders.
- Item preview — view items without leaving the app.
- Multi-user — username/password accounts, per-user data, simple signup page. (no emails)
- Multi-user — Admin panel and admin cli.
- Browser Extension — for quickly adding a new feed, or saving the current page to a list when it has no feed.
- Lists & saved pages — group items into named lists (bookmarks and favorites are built in), and keep arbitrary pages as bookmarks that live in your lists and search without cluttering the unread stream.
- Magic sort — order any list by feed taste instead of time: favorites rank feeds up, and you can raise or lower a feed manually from the algorithm editor.
- Optional S3 support — Nanoflux uses local file storage by default, but supports S3.
- Backups — Configurable Automatic backup every 1 day, keeping the 7 most recent or trigger them manually.
- Polite fetching — per-feed adaptive intervals, conditional GET, and per-host rate-limit backoff, so a throttled site never starves the rest of your feeds. See
docs/fetching.md. - Auto-read — old unread items are marked read automatically (3, 7, 30, or 60 days; off), so a backlog you never cared about fades away. Reversible with "mark all unread".
The recommended approach is to use the docker container.
docker run -d --name nanoflux -p 8080:8080 \
-v nanoflux-db:/data \
-v nanoflux-files:/filestore \
-e NF_FILE_STORE=/filestore \
ghcr.io/metruzanca/nanoflux:latestWe also include a docker-compose.yml and have setup a Makefile with admin/maintenance commands.
Making the easiest way to run nanoflux, clone the repository and run make start
git clone https://github.com/metruzanca/nanoflux
cd nanoflux
make startUpdating nanoflux is also made easy with the Makefile, just run make update.
On a fresh install there is no account yet: signup is open for exactly one
account, and the first person to sign up becomes the admin. Signups close
automatically right after. Re-open them from /admin, or create/recover an
admin from the CLI inside the container (see CLI).
For selfhosting convenience, I've setup a Makefile with the most likely commands you'll need, most are wrappers of docker exec. It also supports podman.
| Command | What it does |
|---|---|
make start |
start the app (pulls the image, creates .env on first run) |
make stop |
shut the app down (containers and data kept) |
make restart |
restart the app |
make status |
show container status |
make logs |
tail the app logs |
make shell |
open a shell in the app container |
make version |
print the running app's version |
make backup |
snapshot the database and file store into backups/ |
make restore ARCHIVE=backups/<file>.tar.gz |
stop, restore from a backup, and restart |
make plugins |
rebuild every plugin in plugins/ (run before make update) |
Some admin operations are more easily done via a CLI app.
Nanoflux ships with one, you can access it easily by running
make shell to get shell access into your container.
Then you can run nanoflux as a cli tool:
nanoflux user list
nanoflux user create <username> # prompts for the password; --admin grants admin
nanoflux user set-admin <username> true
nanoflux user reset-password <username> # prompts for the new password
nanoflux user delete <username> # prompts to confirm; use --yes to skip
nanoflux feed list # every feed across users (no item content)
nanoflux item backfill-thumbs # fill missing YouTube thumbnails (no network)
nanoflux user --help
nanoflux backup # writes backups/nanoflux-<timestamp>-<version>.tar.gz
nanoflux restore backups/nanoflux-20260921-120000-1.0.0.tar.gz # refuses while the server is runningConfiguration is done with environment variables. See
.env.example for the full list, including defaults and
descriptions. Copy it to .env and edit as needed.
make backup writes a tarball of the database and file store to backups/:
make backup
ls backups/
make restore ARCHIVE=backups/nanoflux-20260921-120000-1.0.0.tar.gzNanoflux has a browser extension for adding feeds quickly and easily.
You can install it by loading the extension directory as an "unpacked extension"
OR by downloading the unpacked extension from the user settings page.
When the current page has no feed, the extension offers to save the page
instead. A saved page is stored as a bookmark by default (or any list you
pick or name) with its title, description and thumbnail fetched from the page.
It appears in your lists, bookmarks, favorites and search, but not in the
unread/read streams or home, so it stays out of your reading flow until you open
it. Bookmarks and favorites are the built-in lists; create others from /lists.
Nanoflux is a progressive web app, you can install it for convenience on Android/IOS. Installing nanoflux as a PWA also registers it as a share target allowing you to quickly add a feed.
nanoflux supports external feed plugins — small executables dropped into
plugins/ that add site-specific sources. Build them with make plugins. See
docs/writing-plugins.md to write your own.
Security: plugins are arbitrary executables. An external plugin runs as a child process with the same OS privileges as the nanoflux server, and it can read or modify anything the server can, including its database and files. Only put plugin binaries you trust into
plugins/, and make sure that directory is not writable by untrusted users or processes. There is no sandbox. If you do not need external plugins, leave the directory empty.
- nanoflux-plugin-x↗ — X (Twitter) profile feeds, fetched with your own logged-in session. Use at your own risk.
- No default account. The first signup on a fresh install becomes the admin
and closes signups; there is no shipped username/password. Recover a locked
instance with
nanoflux user create <name> --adminornanoflux user set-admin <name> true(ordocker compose run --rm nanoflux user ...). - Untrusted feed HTML is sanitized at ingest, so a malicious feed cannot run script in your session.
- Outbound fetches refuse private addresses (loopback, RFC1918, link-local,
cloud metadata). Set
NF_ALLOW_PRIVATE_FETCH=1if your feeds are on your LAN. - Sessions and CSRF tokens are stored hashed; cookies are
HttpOnlyandSameSite=Lax, and the app ships a strict Content-Security-Policy. - Plugins are the main trust boundary — see the warning above. Run nanoflux behind TLS (a reverse proxy is fine) for any non-local deployment.
I'm not accepting contributions at this time — but issues are very welcome for feature requests and bug reports.
This is an AI coding project: if your agent can write a feature, mine probably can too. The difference is that I have a better understanding of the project goals, so I'd rather build it myself. A clear issue describing the feature or the bug is the most useful thing you can send — though coffee is a close second:
License: MIT Open source under the MIT License. Free to use, modify, and self-host.
- Website: https://nanoflux.app
- Source: https://github.com/metruzanca/nanoflux
UI icons are from Lucide, used under the ISC License (Copyright © Lucide Contributors).