# selfoss has no tag since 2.19, and its license text still disagrees

> selfoss is a self-hosted PHP feed reader whose source tree runs four years past its newest release tag. What the documentation actually settles is the deployment contract: writable data directories, trigger privileges on the database user, and a client bundle you build yourself.

**fossar/selfoss** — multipurpose rss reader, live stream, mashup, aggregation web application

- Repository: https://github.com/fossar/selfoss
- Website: https://selfoss.aditu.de
- Stars: 2,474 · Forks: 340
- Language: HTML
- License: GPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/fossar-selfoss

## No release tag since 2.19, with the branch four years ahead

selfoss is not archived and its last commit is dated 2026-09-28, yet the newest published release is tag 2.19 from 2022-10-12. The two tags before it are older still: 2.18 dates to 2018-03-05 and 2.17 to 2017-03-17. Both the README heading and package.json call the current tree 2.20-SNAPSHOT, so close to four years of work sit between the last tag and the branch head, and anyone installing from the releases page gets the 2022 code. The gap is acknowledged rather than hidden. The download section offers development builds hosted by Cloudsmith for people who want unreleased features or fixes, and a third route, the git-tracked source, marked as requiring some assembly. The status paragraph says the project is kept by Jan Tojnar in his free time and that maintenance is prioritized over new features. One detail in package.json deserves a second look: the snapshot string sits under a key named `ver` rather than `version`, so the field npm reads for a version is not the one carrying it.

## The upgrade spares data/ and config.ini, then makes you edit config.ini

The upgrade procedure is the part of the documentation most likely to lose data if it is followed loosely. It asks you to back up the database and the data/ directory, then delete every old file and directory except two things: the data/ directory and the file config.ini. New files are then copied over the root, again including the invisible .htaccess files, and NEWS.md is the file to consult for backwards incompatible changes. Two remaining steps are easy to skim past. The database is updated on its own, which again depends on the database user being allowed to create triggers. And config.ini, the one file the deletion step spares, still has to be edited by hand afterwards, because newer versions add options to it and your copy does not have them. The procedure also tells the operator to clear the browser cache, which points at the client bundle being held by the browser rather than fetched again after the swap.

## Automatic table creation still needs a user allowed to create triggers

Installation step 4 decides whether a fresh install works on your database: you do not create the tables yourself, they are created automatically, and the parenthesis that follows sets the condition, your database user is allowed to create triggers. The same requirement is repeated as step 7 of the upgrade procedure, so it is a standing condition rather than a one time setup task, and no command for granting it appears anywhere in the documentation. On SQLite none of it applies. The configuration section asks you to rename config-example.ini to config.ini, to delete any line you do not wish to override, and to look at the published site for examples, and the install steps add that nothing has to be changed in that file at all if you use SQLite. The data/sqlite directory is one of the writable directories, which means the database file lands next to the cache, the logs and the thumbnails.

## Feeds refresh from /update or cliupdate.php, and nothing else

Feed refresh is not something the web interface schedules for you. Installation step 5 asks for a cronjob or a systemd timer pointed at https://yourselfossurl.com/update and driven by wget or curl, and it names cliupdate.php as the command line route to the same job. That URL is a plain path on the same host as the reader, and no key, token or query parameter is documented for it, so whatever keeps that path from being triggered by anyone who learns the address has to come from the web server in front of the instance rather than from selfoss itself. The same shape shows up in the import path. Migrating from another reader means finding the OPML export in the old application, usually somewhere in its settings, and uploading it on the page at https://yourselfossurl.com/opml. Both routes are HTTP entry points into one installation, and both are as exposed as whatever fronts them.

## Five data subdirectories must be writable, and the invisible files get left behind

Five directories under data/ have to be writable before the application will work: data/cache, data/favicons, data/logs, data/thumbnails and data/sqlite. Three of those names say what the reader does beyond storing subscriptions. It caches parsed feeds, it fetches site icons, and it saves article thumbnails to disk. That means data/ grows on its own, and its size belongs in the same conversation as the database backup, because the upgrade procedure protects data/ and config.ini and deletes everything else around them. One more instruction disappears in an ordinary file copy: the install and upgrade steps both say to copy the invisible .htaccess files as well, so copying only visible files leaves them behind. The repository tree also ships .nginx.conf next to those files, while the install steps talk only about a document root on a PHP server.

## Parcel writes into public/, so a checkout is not a running copy

The client side is built with Parcel, and the build is not automatic. After a checkout you retrieve the server dependencies with `composer install`, the JavaScript ones by calling `npm install` in the `client/` directory, or you run `npm run install-dependencies` to do both sets at once. Then the rule that decides whether your checkout works at all: every time anything in the client/ directory changes, you run `npm run build`, and the bundles are written into the public directory. Until that has happened, a Git copy of the tree is not a working copy of the application. For day to day work `npm run dev` watches for asset changes, rebuilds the bundles as needed and reloads selfoss automatically, and the documentation warns that switching between `npm run dev` and `npm run build` can leave client/.cache in a state you need to delete.

## Three npm scripts call out to python3 and black without saying so

The root package.json wires up more toolchain than the development section admits. `npm run dist`, the command that produces the zipball with dependencies bundled, runs `python3 utils/create-zipball.py`. The integration suite starts with `python3 tests/integration/run.py`. And the helper style check is `black utils/ tests/`, so the Python formatter has to be present before `npm run check:all` passes, even though the development section says selfoss uses composer and npm for installing external libraries and tells you to install the checkers with `npm run install-dependencies`. The server side runs a separate chain of `composer run-script cs`, `composer run-script lint` and `composer run-script phpstan`, matching the .php-cs-fixer.php, phpstan.dist.neon and rector.php files in the tree. A `postinstall` hook calls install-dependencies for you, and `bump-version` expands a $NODE variable that the script list itself never sets.

## Three versions of the GPL claim, and the zipball is the one left open

The licensing story has three versions of itself. The license field on the repository reads GPL-3.0, and the tree carries a COPYING file. The credits paragraph says the source code is licensed under the GNU General Public licence version 3, or at your option any later version, which is the or later form rather than the plain GPL-3.0 in the metadata. The same paragraph then says some parts of the source code can be licensed under version 3 only, that the project is currently trying to resolve it, and that the package with bundled dependencies might be distributed under version 3 only. The unresolved part is tracked as an open issue. Nothing in the tree settles which claim wins, so read COPYING together with the credits text, and treat the zipball produced by `npm run dist` as a separate case, because bundling dependencies is exactly the situation the credits single out.

## Conclusion

selfoss fits a reader who wants a self-hosted feed aggregator on ordinary PHP hosting with SQLite and no extra services, and it does not fit anyone who needs a packaged release that matches the current branch, because the newest tag is from October 2022 and the branch head is dated 2026-09-28. Before deploying, check three things against your own setup: that your database user is allowed to create triggers, that data/cache, data/favicons, data/logs, data/thumbnails and data/sqlite are writable, and that whatever sits in front of the update URL keeps it off the open internet. Then read COPYING next to the credits paragraph, because the version 3 only claim about parts of the tree is still unresolved and it is the license of the bundled zipball that is at stake.

## FAQ

### What is selfoss?

selfoss is a multipurpose RSS reader and feed aggregation web application written in PHP, so it can run on any host with a PHP server. It collects updates from web sites, social networks and other platforms in a single place, and its creator is credited as Tobias Zeising.

### How does selfoss keep feeds up to date?

You create a cronjob or a systemd timer that points at https://yourselfossurl.com/update and drives it with wget or curl. The documentation also offers cliupdate.php on the command line as the alternative way to run the same update.

### Do I have to create the selfoss database tables myself?

No. The tables are created automatically on first run, but your database user has to be allowed to create triggers, and the upgrade procedure repeats that requirement because it also updates the schema automatically. With SQLite you do not have to change anything in config.ini.

### What does a selfoss Git checkout still need?

The dependency steps: composer install for the server libraries, npm install inside the client/ directory or npm run install-dependencies for both, then npm run build after every change under client/ so Parcel writes the bundles into the public directory. The download section marks the git-tracked source as needing some assembly.

### Which selfoss directories have to be writable?

data/cache, data/favicons, data/logs, data/thumbnails and data/sqlite. The upgrade procedure tells you to delete everything except data/ and config.ini, so that directory set is what carries your state between versions.

### Is there a current selfoss release to install?

The newest published tag is 2.19 from 2022-10-12, while the README heading and package.json both say 2.20-SNAPSHOT and the last commit is dated 2026-09-28. Unreleased builds are hosted by Cloudsmith, and the status paragraph says one maintainer keeps the project going in his free time with maintenance prioritized over new features.

## Sources

- [fossar/selfoss on GitHub](https://github.com/fossar/selfoss)
- [License: GPL-3.0](https://github.com/fossar/selfoss/blob/master/LICENSE)
- [Project website](https://selfoss.aditu.de)
- [README](https://github.com/fossar/selfoss/blob/master/README.md)
- [Releases](https://github.com/fossar/selfoss/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fossar-selfoss
