How to bring back RSS feeds for sites that removed them, scrape full article content, and unify everything in a single self-hosted reader.
RSS isn’t dead — it’s just been abandoned by publishers chasing engagement metrics and walled gardens. Websites that once offered clean XML feeds now force you into newsletters, push notifications, or algorithmic timelines. But with a bit of self-hosting, you can take that control back.
This post walks through my setup: FreshRSS as the reader, RSS-Bridge as the scraper for sites that killed their feeds, all running on TrueNAS Scale with Docker and exposed through Tailscale for secure remote access.
The Architecture
The data flow is straightforward:
(no RSS)
scrapes & generates feed
polls & displays
browser / app
For sites that still offer RSS, FreshRSS subscribes directly. For sites that removed their feeds, RSS-Bridge sits in between — it loads the page, parses the HTML with CSS selectors, and generates a standard Atom feed that FreshRSS can consume like any other subscription.
Why RSS-Bridge Over Alternatives
There are several tools that can generate feeds from websites. I chose RSS-Bridge for a few reasons:
Lightweight. RSS-Bridge is PHP-based and runs in about 50 MB of RAM. Compare that with RSSHub (Node.js, 300 MB+) or Huginn (Ruby, even heavier). On a NAS where every container counts, this matters.
FreshRSS integration. There’s a native FreshRSS extension (xExtension-RssBridge) if you want tight integration, though the simpler approach — just subscribing to the generated feed URL — works perfectly and survives app updates.
CssSelectorBridge. This built-in bridge is incredibly flexible. Give it a URL, tell it which CSS selectors match your articles, and it produces a feed. No coding required, no custom JavaScript routes to maintain.
Deploying RSS-Bridge on TrueNAS
I run RSS-Bridge as a Docker container through Portainer. First, create the config directory and enable all bridges:
bash# Create config directory on ZFS
sudo mkdir -p /mnt/zfs_tank/docker/rss-bridge
# Enable all bridges
sudo tee /mnt/zfs_tank/docker/rss-bridge/config.ini.php << 'EOF'
[system]
enabled_bridges[] = *
EOF
Then deploy the stack in Portainer:
docker-composeversion: "3"
services:
rss-bridge:
image: rssbridge/rss-bridge:latest
container_name: rss-bridge
restart: unless-stopped
ports:
- "3001:80"
volumes:
- /mnt/zfs_tank/docker/rss-bridge:/config
RSS-Bridge is now accessible at http://<truenas-ip>:3001.
Remote Access with Tailscale Serve
If you already run a Tailscale container on your TrueNAS box, you can expose RSS-Bridge through it:
bashdocker exec ix-tailscale-tailscale-1 tailscale serve --bg --https 3001 http://localhost:3001
This makes RSS-Bridge available at https://your-machine.tailnet-name.ts.net:3001/ from any device on your tailnet. Use a non-443 port to avoid overwriting your TrueNAS GUI’s Tailscale Serve config.
http://192.168.0.13:3001/...) rather than the Tailscale hostname. Both services run on the same box, so going through the LAN is faster and more reliable — and the FreshRSS container may not have Tailscale DNS available.
Scraping a Site: A Real Example
The Greek tech blog techblog.gr removed its RSS feed during a 2025 site redesign. Here’s how I brought it back.
Step 1 — Identify the selectors
Open the site, right-click an article title, and choose Inspect. On techblog.gr, each article title is an <a> inside an <h3>. On article pages, the content lives inside div.article-content.
Step 2 — Configure CssSelectorBridge
In the RSS-Bridge web UI, find CSS Selector and fill in:
| Field | Value |
|---|---|
| Site URL | https://techblog.gr/ |
| Selector for article links | h3 a |
| URL pattern | (empty) |
| Expand article content | .article-content |
| Content cleanup | (empty) |
| Title cleanup | | Techblog.gr |
| Limit | 20 |
Step 3 — Generate and subscribe
Click Generate feed, right-click the Atom button and copy the link. In FreshRSS, go to Subscription management → Add a feed and paste the URL. Done — full article content in your reader, from a site with no RSS feed.
Finding the Right CSS Selectors
For the article link selector: On the homepage, right-click an article title → Inspect. Look at the tag structure. Common patterns are h2 a, h3 a, or .post-title a. If the site uses generic <a> tags everywhere, combine with a URL pattern to filter (e.g. /blog/202 to match only blog post URLs).
For the content selector: Open any individual article, right-click the body text → Inspect. Look at the parent <div> wrapping all the paragraphs. WordPress sites typically use .entry-content or .article-content. Drupal sites often use .field-name-body or .node-content.
<iframe> elements if the content selector doesn’t seem to work.
Setting Sensible Limits
The Limit field controls how many items RSS-Bridge returns per request. Since FreshRSS remembers articles it has already seen, you only need enough to cover new posts between polling intervals:
| Feed type | Limit | Reasoning |
|---|---|---|
| News sites | 20 | High frequency, many posts per day |
| Blogs | 10 | Weekly or monthly posts |
| Job boards | 10 | Few listings, slow turnover |
What About Paywalled Sites?
RSS-Bridge has limits. If a site blocks automated requests (returning 403 errors) or loads content via JavaScript that requires authentication, RSS-Bridge can’t help. This applies to most academic journals and some major news outlets.
For journals like NEJM, the publisher’s RSS feed is your only option — and it often contains just titles and volume/page references, no abstracts. A useful workaround for medical journals: use PubMed’s RSS feeds instead. PubMed indexes the same articles and includes full abstracts. Search for a journal, save the search, and create an RSS feed from the results.
Unifying Multiple Feed Readers
If you’re migrating from a desktop reader like Akregator to a self-hosted FreshRSS instance, both support OPML import/export. Export from both, then compare the feed URLs to identify:
Feeds in both — already synced, nothing to do.
Feeds only in the old reader — evaluate whether to add them to FreshRSS or drop them.
Feeds only in FreshRSS — typically your newer RSS-Bridge feeds replacing broken native feeds.
Watch for feeds that exist in both but with different URLs — same source, different CDN, or an old Politepol/feed proxy URL that you’ve since replaced with RSS-Bridge.
Closing Thoughts
This setup takes about 30 minutes to deploy and configure. What you get in return is a single, self-hosted interface for consuming content from any website — with or without their cooperation. No algorithms deciding what you see, no newsletters cluttering your inbox, no tracking pixels following you around.
RSS never died. It just needs a little infrastructure.




