Self-hosted service
anyant/rssant avatar
anyant/rssant

RSSAnt self-hosting: one Docker container, eight supervised processes and a Postgres volume

蚁阅 - 让 RSS 更好用,轻松订阅你喜欢的博客和资讯

1,657 stars135 forksPythonBSD-3-Clause

At a glance

What is it?
RSSAnt is a Django-based RSS reader with full-text extraction, podcast and video items, feed autodiscovery and image repair, shipped as a single Docker image that runs under supervisor. The build instructions in the README are detailed enough to follow, but the author states in the same file that the project is in maintenance mode with new features on hold.
Who is it for?
RSSAnt suits a reader who wants an ad-free, self-hosted reader with full-text extraction and does not mind maintaining a Postgres volume and an nginx front end inside one container. It is a poor fit if you need a frontend project with an active roadmap, because the author says new features are on hold and the GitHub repository is a mirror of the Gitee main repository with no GitHub releases published.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 29 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the application is doing behind the reader UI

RSSAnt (蚁阅) presents itself as a cross-platform reader with no advertising and no recommendation feed, full-text reading, support for podcast and video items, night mode, automatic discovery of a feed from a blog URL, and automatic repair of broken images. Underneath it is a Django project split into many small apps visible in the repository root: rssant_api, rssant_asyncapi, rssant_cli, rssant_common, rssant_config, rssant_feedlib, rssant_harbor, rssant_scheduler and rssant_worker.

The names describe the runtime shape. api and async-api are separate entry points, so a slow request and a slow feed refresh do not share a worker. worker executes background tasks and scheduler triggers them. harbor is the actor layer that fetches and retries feeds. initdb runs once at first boot and exits, which is why the process listing shows it as EXITED while everything else is RUNNING, and that is normal.

The dependency list confirms the feature claims rather than just asserting them: aiohttp for asynchronous HTTP, aiohttp-socks for proxying, readability-lxml and cssselect for article extraction, pynliner, brotli and chardet for decoding feeds and pages. That is the machinery behind full-text reading, and it is also where breakage will come from when a publisher changes their markup.

The env file where every behaviour switch lives

Deployment starts with a single env file saved as ~/rssant/rssant.env. Everything else in the guide is derived from it. The security-relevant entries are worth reading in order:

bash
RSSANT_DEBUG=0
RSSANT_SECRET_KEY=SECRET
RSSANT_ROOT_URL=http://localhost:6789
RSSANT_CHECK_FEED_MINUTES=30

The secret key is supposed to be a random string, and DEBUG is off by default with an explicit warning not to turn it on outside development testing. The root URL matters because it feeds the GitHub OAuth callback path, which the file documents as http://your-domain/api/v1/accounts/github/login/callback/.

Optional integrations each switch off cleanly. GitHub sign-in needs RSSANT_GITHUB_CLIENT_ID and RSSANT_GITHUB_SECRET and may be left empty. SMTP registration email needs RSSANT_SMTP_ENABLE=true plus host, port, SSL flag, username and password. A feed proxy exists for networks that block RSS directly, configured through RSSANT_RSS_PROXY_ENABLE, RSSANT_RSS_PROXY_URL and RSSANT_RSS_PROXY_TOKEN, and the repository carries a cloudflare_worker directory with the proxy implementation described in its own README.

One default is a deliberate security choice worth understanding:

bash
# 为保障网络安全,默认不允许订阅局域网地址,如有需要可设置为true
# RSSANT_ALLOW_PRIVATE_ADDRESS=true

Private and LAN addresses are refused by default, which blocks the SSRF pattern of a hosted reader being pointed at internal services. If you run it at home and want to subscribe to a NAS-hosted feed, you must opt in explicitly, and you then own the risk.

One container, two volumes, port 6789

The runtime is a single container, guyskk/rssant:latest, with Postgres volumes mounted inside it. Create the volumes first, because a named volume that does not exist at mount time gets created with root ownership and awkward permissions:

bash
docker volume create rssant-postgres-data || true
docker volume create rssant-postgres-logs || true

Then start it. Note that port 80 inside the container maps to 6789 outside, which is why the env file sets RSSANT_ROOT_URL to port 6789 and why the admin site later appears at http://localhost:6789/admin/.

bash
docker run -ti --name rssant -d \
    -p 6789:80 \
    --env-file ~/rssant/rssant.env \
    -v rssant-postgres-data:/var/lib/postgresql/11/main \
    -v rssant-postgres-logs:/var/log/postgresql \
    --restart unless-stopped \
    guyskk/rssant:latest

The Postgres major version in the mount path is 11, so an existing volume from a different major version will not mount correctly. Logging is capped with json-file and max-size=50m, max-file=10. Before running the script on any platform that mangled line endings, the guide tells you to run `sed -i 's/\r//' ~/rssant/start.sh`, then `bash ~/rssant/start.sh`, and tail the logs with `docker logs --tail 1000 -f rssant`.

Reading the startup log to confirm it worked

A healthy first boot prints a short block of one-time database setup, then a steady stream of feed housekeeping. The initdb lines you should see:

bash
I 2019-12-22 11:01:36 scripts.django_db_init:26   extension hstore created
I 2019-12-22 11:01:36 scripts.django_db_init:33   create admin user
I 2019-12-22 11:01:36 scripts.django_db_init:41   update site info
I 2019-12-22 11:01:36 scripts.django_db_init:53   create github social app

That `create admin user` line is what produces the admin/admin credentials, which is why the guide tells you to open http://localhost:6789/admin/, log in as admin with password admin, and immediately use the CHANGE PASSWORD button at the top right. Anyone who exposes this container before doing that has published an admin panel.

The steady-state lines are the ones from the feed actor, and they are periodic rather than errors:

bash
I 2019-12-22 13:16:08 rssant_harbor.actors.rss:418  delete 0 old feed creations
I 2019-12-22 13:16:08 rssant_harbor.actors.rss:423  retry 0 status=UPDATING feed creations
I 2019-12-22 13:16:08 rssant_harbor.actors.rss:429  retry 0 status=PENDING feed creations

The counters being zero on a fresh install is expected. Non-zero retry counts on a feed that never succeeds is the signal to look at. A stricter check is `docker exec -ti rssant supervisorctl status`, where api, async-api, harbor, nginx, postgres, scheduler and worker must all report RUNNING while initdb reports EXITED.

The hosted version, the paid tier and what maintenance means here

The README documents a subscription model for the hosted instance at https://rss.anyant.com: unlimited feeds on all tiers, the paid member version at 5 yuan per month or 30 yuan per year with priority support, a free tier limited to a 30 day trial of the full feature set, and the open source version which you deploy and maintain yourself. The author's stated reason for charging is that fetching subscriptions costs server resources.

More important for anyone evaluating the code is the paragraph titled 作者近况. It says the author went full time on independent development in early 2021, then started another project for income, and that RSSAnt is temporarily in a maintenance state with new features postponed for a while. The repository agrees: it is not archived and the last push was on 2026-09-24, but there are no GitHub releases at all, so nothing pins a known-good version for a deployment.

There is also a hosting fact that changes where you file work. The main repository lives on Gitee at gitee.com/anyant/rssant, and the GitHub repository at github.com/anyant/rssant is primarily a mirror. The author asks that pull requests go to Gitee if you have an account. An `unmaintain/` directory also sits at the root of the tree, which suggests code parked deliberately rather than abandoned by accident.

Running the backend locally for development

The development path avoids Docker for the application itself but still needs Docker for Postgres. System prerequisites are Linux or macOS, Docker, a Python environment managed through mise, uv for dependency handling, and Node.js, again through mise.

The clone and environment setup look like this:

bash
git clone [email protected]:anyant/rssant.git
cd rssant
mise install [email protected]
python -m venv .venv
bash ./setup.sh

Then start the database and initialise the schema:

bash
bash ./scripts/postgres_start.sh
python manage.py migrate
python manage.py runscript django_db_init

Four processes have to run at once, in separate terminals, which is why the scripts are separate files rather than one supervisor command:

bash
bash ./rundev-api.sh
bash ./rundev-worker.sh
python ./run-scheduler.py
python ./run-asyncapi.py

The interactive API console then lives at http://127.0.0.1:6788/doc/v1/ with admin/admin, and the README's smoke test is to use Interact on the feed import endpoint with a real blog URL such as https://www.ruanyifeng.com/blog/ and watch the background task console print feed discovery logs. Tests run under pytest. The frontend is a separate repository, rssant-web, installed with Node 16 via mise, served with `npm run serve`, and it runs on 127.0.0.1:6789.

How it differs from FreshRSS and Miniflux

FreshRSS is the closest comparison in spirit: both are self-hosted readers aimed at pulling full article text rather than a feed summary. The differences are structural. FreshRSS is a single PHP application with one container and no bundled database, so upgrades are a pull and a database migration. RSSAnt packages the web server, the API, the async API, the scheduler, the worker, the feed actor and Postgres into one image under supervisor, which means the container is the unit of backup and upgrade, and a failure in any one supervised process is a container-level incident rather than a page-level one.

Miniflux goes the other way. It is Go, deliberately minimal, and treats full-text extraction as optional scraping you configure per feed rather than a default behaviour. RSSAnt makes extraction the default and adds discovery from a plain blog URL plus image repair, which is convenient and is also the part most likely to need attention when a publisher redesigns.

So the trade is roughly: more moving parts and more built-in convenience against a smaller project with a paused feature roadmap.

Editorial conclusion

RSSAnt suits a reader who wants an ad-free, self-hosted reader with full-text extraction and does not mind maintaining a Postgres volume and an nginx front end inside one container. It is a poor fit if you need a frontend project with an active roadmap, because the author says new features are on hold and the GitHub repository is a mirror of the Gitee main repository with no GitHub releases published. Verify first that `docker exec -ti rssant supervisorctl status` reports api, harbor, nginx, postgres, scheduler and worker as RUNNING, and change the default admin password before anything else.

Frequently asked questions

What do I need to self-host RSSAnt?

The README specifies Linux with 1G of memory, Docker, and a mirror accelerator for image pulls. Configuration lives in a single env file at ~/rssant/rssant.env and the app runs as one container with Postgres volumes.

How do I change the default admin password in RSSAnt?

Open http://localhost:6789/admin/ and sign in with username admin and password admin, which initdb creates on first boot. Then use the CHANGE PASSWORD button at the top right of the page.

How do I back up RSSAnt data?

Back up the rssant-postgres-data volume, and ignore the other volumes. The README states that this single volume holds what matters.

Can RSSAnt subscribe to feeds on my local network?

Not by default. Private and LAN addresses are refused to protect network security, and the env file ships the opt-in `RSSANT_ALLOW_PRIVATE_ADDRESS=true` commented out with a note that you should only enable it if you need to.

Why does the initdb process show EXITED in supervisorctl status?

initdb is a one-time setup job that creates the hstore extension, the admin user, site info and the GitHub social app, then exits on purpose. Only api, async-api, harbor, nginx, postgres, scheduler and worker need to be RUNNING.

Is RSSAnt still getting new features?

The README says the project is temporarily in a maintenance state because the author moved on to another project, and that new features are postponed. The repository is not archived and the last push was on 2026-09-24, but no GitHub releases exist.

Official sources

  1. anyant/rssant on GitHub
  2. Issues
  3. License: BSD-3-Clause
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/anyant-rssant.svg)](https://hysenlabs.com/projects/anyant-rssant)

Was this useful?