Repository navigation
RSS Workshop v1.0.0
First stable release. RSS Workshop turns pages that publish no feed into RSS and Atom feeds you keep, and 1.0 is the point at which its upgrade path, configuration surface and reader URLs become commitments rather than implementation details. See upgrades before installing over an existing deployment.
Upgrading from v0.2.0
- Take a backup first. Starting this version migrates the database to schema 4 in a single transaction. Every released schema upgrades directly, but an older release cannot open a newer database, so rolling back needs a backup taken before the upgrade. See backup and restore.
- Readers refetch once. Published feeds carry more than they did, so every feed's bytes change once and subscribed readers fetch a full copy on their next poll. Stories keep their identities and publication dates, so nobody sees a duplicate.
- Container logs now rotate, at three 10 MiB files per service.
docker compose logsreaches back only as far as the retained files.
Feeds readers actually want
- Full article content. Follow each story's own link, extract the article body, and publish that instead of the list page's one-line teaser. Off by default and configured per feed. Article pages are fetched with the same guarded fetcher as list pages, at most 10 per refresh so a long feed fills in over several cycles, and an article that cannot be fetched keeps its teaser rather than dropping the story or failing the refresh.
- Better published feeds. RSS keeps the article in
descriptionand repeats it incontent:encoded; Atom carries the list-page description assummaryand the article ascontent. The extracted image is published asmedia:contentand as an Atom enclosure, where readers look for a thumbnail, and is no longer repeated when the article body already contains it. The RSS channel gainsatom:link rel="self",ttl,lastBuildDateandgenerator. - Conditional requests. Reader responses honour
If-Modified-Sincealongside the existing ETag, so a reader polling from several devices costs validators rather than full copies. - OPML export. Download a subscription list of every feed and import it into your reader in one step. It contains every private reader link, so it requires an admin session and is never cached.
Knowing when something breaks
- Log levels.
LOG_LEVELselectsdebug,info,warnorerror, andLOG_FORMATswitches to JSON for a log collector. The startup line summarizes the running deployment, failed refreshes report their reason and feed, rejected sign-ins are reported with their remote address, and shutdown is logged. - Prometheus metrics. Setting
METRICS_TOKENenables/metrics, scraped with that token as a bearer credential; blank leaves the endpoint returning 404. Per-feed series carry item counts, consecutive failures and last-success timestamps, so an alert can name the feed that broke. - A failed database write no longer hammers the source. Such a refresh rolls back the feed's schedule along with everything else, so the source was refetched on every scheduler tick for as long as writing failed, while the log reported success. The feed now backs off, and the failure reports its reason.
- Retention is visible.
MAX_ITEMSapplies to stories already saved, so lowering it permanently deletes the excess at each feed's next refresh. That now appears in the log and is documented as destructive.
Running it
- Reverse proxy support.
compose.proxy.yamland a guide for a proxy running in Docker, which cannot reach the default loopback publication. - Container log rotation, configurable through
LOG_MAX_SIZEandLOG_MAX_FILES. - Stable image aliases.
latestandlatest-browserinclude Chromium;latest-staticselects the lightweight runtime. Compose follows these aliases, with version and digest pins still available. - Direct upgrades from every released schema, with frozen per-backend fixtures and tests comparing all saved feed, item and run data across upgrade and reopening. Backups support schemas 1 through 4.
Editor and examples
- Full article content is inspectable and repairable. Previews show the fetched body, so a selector matching the wrong block is visible before saving, and changing or clearing the selector discards the stored bodies so later refreshes fetch them again.
- New example recipes. The previous examples targeted five real news sites that all publish their own feeds, extracted only a title and link, and two relied on generated class names that change whenever those sites deploy. They are replaced by a demo site included in the repository, with recipes covering every field, CSS and XPath, and filtering with full article content. A test imports each example and extracts from that site.
- Reorganized documentation. The README follows install, first feed, and diagnosing a broken one, with installation variants collected below;
.env.exampleis grouped by purpose. Screenshots are refreshed and now include full article content and per-feed diagnostics.
Internal
- Security headers applied to every response are pinned by a test; the content policy is the second layer behind sanitization for extracted markup and previously had no coverage of its own.
- A refresh no longer loads every stored article body to decide which article pages to fetch.
Verifying a download
Native archives ship with a .sha256 sidecar:
sha256sum -c rss-workshop-v1.0.0-linux-amd64.tar.gz.sha256Corresponding Debian source archives for both image architectures are attached to this release. Large archives are split; reassemble before verifying:
cat debian-sources-v1.0.0-linux-amd64.tar.gz.part-* > debian-sources-v1.0.0-linux-amd64.tar.gz
sha256sum -c debian-sources-v1.0.0-linux-amd64.tar.gz.sha256Images
| Variant | Tag |
|---|---|
| Browser (default) | ghcr.io/ldogg123/rss-workshop:v1.0.0-browser |
| Static | ghcr.io/ldogg123/rss-workshop:v1.0.0-static |
The latest, latest-browser and latest-static aliases advance to this release. Pin a version tag or digest with RSS_IMAGE to stay put.