diff --git a/debian/copyright b/debian/copyright
index e0a3a8c61..74a81f861 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -67,6 +67,8 @@ Files: static/themes/default/icons/ejabberd.png
static/themes/default/icons/privoxy.png
static/themes/default/icons/privoxy.svg
static/themes/default/icons/radicale.svg
+ static/themes/default/icons/rssbridge.png
+ static/themes/default/icons/rssbridge.svg
static/themes/default/icons/zoph.png
static/themes/default/icons/zoph.svg
static/themes/default/img/network-connection.svg
@@ -82,6 +84,7 @@ Comment: Placed into public domain by authors (or)
https://commons.wikimedia.org/wiki/File:Ejabberd_icon.png
https://radicale.org/css/logo.svg
https://github.com/resiprocate/resiprocate/blob/master/resip/stack/doc/reSIProcate-logo.svg
+ https://github.com/RSS-Bridge/rss-bridge/blob/master/static/logo_600px.png
License: public-domain
Files: doc/manual/en/images/icons/*
diff --git a/plinth/modules/rssbridge/__init__.py b/plinth/modules/rssbridge/__init__.py
new file mode 100644
index 000000000..e4c89bbb0
--- /dev/null
+++ b/plinth/modules/rssbridge/__init__.py
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+"""
+FreedomBox app to configure RSS-Bridge.
+"""
+from django.urls import reverse_lazy
+from django.utils.translation import gettext_lazy as _
+
+from plinth import app as app_module
+from plinth import cfg, frontpage, menu
+from plinth.modules.apache.components import Webserver
+from plinth.modules.backups.components import BackupRestore
+from plinth.modules.firewall.components import Firewall
+from plinth.modules.users.components import UsersAndGroups
+from plinth.package import Packages
+from plinth.utils import format_lazy
+
+from . import manifest
+
+_description = [
+ _('RSS-Bridge generates RSS and Atom feeds for websites that do not have '
+ 'one. Generated feeds can be consumed by any feed reader.'),
+ format_lazy(
+ _('When enabled, RSS-Bridge can be accessed by '
+ 'any user belonging to the feed-reader group.'),
+ users_url=reverse_lazy('users:index')),
+ format_lazy(
+ _('You can use RSS-Bridge with Tiny Tiny '
+ 'RSS to follow various websites. When adding a feed, enable '
+ 'authentication and use your {box_name} credentials.'),
+ ttrss_url=reverse_lazy('ttrss:index'), box_name=cfg.box_name),
+]
+
+app = None
+
+
+class RSSBridgeApp(app_module.App):
+ """FreedomBox app for RSS-Bridge."""
+
+ app_id = 'rssbridge'
+
+ _version = 1
+
+ def __init__(self):
+ """Create components for the app."""
+ super().__init__()
+
+ groups = {'feed-reader': _('Read and subscribe to news feeds')}
+
+ info = app_module.Info(app_id=self.app_id, version=self._version,
+ name=_('RSS-Bridge'), icon_filename='rssbridge',
+ short_description=_('RSS Feed Generator'),
+ description=_description,
+ manual_page='RSSBridge', donation_url=None,
+ clients=manifest.clients)
+ self.add(info)
+
+ menu_item = menu.Menu('menu-rssbridge', info.name,
+ info.short_description, info.icon_filename,
+ 'rssbridge:index', parent_url_name='apps')
+ self.add(menu_item)
+
+ shortcut = frontpage.Shortcut('shortcut-rssbridge', name=info.name,
+ short_description=info.short_description,
+ icon=info.icon_filename,
+ url='/rss-bridge/', login_required=True,
+ allowed_groups=list(groups))
+ self.add(shortcut)
+
+ packages = Packages('packages-rssbridge', ['rss-bridge'])
+ self.add(packages)
+
+ firewall = Firewall('firewall-rssbridge', info.name,
+ ports=['http', 'https'], is_external=True)
+ self.add(firewall)
+
+ webserver = Webserver('webserver-rssbridge', 'rss-bridge',
+ urls=['https://{host}/rss-bridge/'])
+ self.add(webserver)
+
+ users_and_groups = UsersAndGroups('users-and-groups-rssbridge',
+ groups=groups)
+ self.add(users_and_groups)
+
+ backup_restore = BackupRestore('backup-restore-rssbridge',
+ **manifest.backup)
+ self.add(backup_restore)
+
+
+def setup(helper, old_version=None):
+ """Install and configure the module."""
+ app.setup(old_version)
+ helper.call('post', app.enable)
diff --git a/plinth/modules/rssbridge/data/etc/apache2/conf-available/rss-bridge.conf b/plinth/modules/rssbridge/data/etc/apache2/conf-available/rss-bridge.conf
new file mode 100644
index 000000000..e3aaf2059
--- /dev/null
+++ b/plinth/modules/rssbridge/data/etc/apache2/conf-available/rss-bridge.conf
@@ -0,0 +1,21 @@
+##
+## On all sites, provide RSS-Bridge on a default path: /rss-bridge
+## Allow valid LDAP users from groups 'feed-reader' and 'admin'.
+##
+Alias /rss-bridge /usr/share/rss-bridge
+
+
+
+ # Formats: Atom, Json, Mrss and Plaintext
+ Include includes/freedombox-auth-ldap.conf
+ Require ldap-group cn=admin,ou=groups,dc=thisbox
+ Require ldap-group cn=feed-reader,ou=groups,dc=thisbox
+
+
+ # Formats: Html and all other pages
+ Include includes/freedombox-single-sign-on.conf
+
+ TKTAuthToken "feed-reader" "admin"
+
+
+
diff --git a/plinth/modules/rssbridge/data/etc/plinth/modules-enabled/rssbridge b/plinth/modules/rssbridge/data/etc/plinth/modules-enabled/rssbridge
new file mode 100644
index 000000000..47fe69ce8
--- /dev/null
+++ b/plinth/modules/rssbridge/data/etc/plinth/modules-enabled/rssbridge
@@ -0,0 +1 @@
+plinth.modules.rssbridge
diff --git a/plinth/modules/rssbridge/manifest.py b/plinth/modules/rssbridge/manifest.py
new file mode 100644
index 000000000..289bc65d3
--- /dev/null
+++ b/plinth/modules/rssbridge/manifest.py
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+from django.utils.translation import gettext_lazy as _
+
+"""
+Application manifest for RSS-Bridge.
+"""
+
+clients = [{
+ 'name': _('RSS-Bridge'),
+ 'platforms': [{
+ 'type': 'web',
+ 'url': '/rss-bridge/'
+ }]
+}]
+
+backup = {}
diff --git a/plinth/modules/rssbridge/urls.py b/plinth/modules/rssbridge/urls.py
new file mode 100644
index 000000000..5df049814
--- /dev/null
+++ b/plinth/modules/rssbridge/urls.py
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+"""
+URLs for the RSS-Bridge module.
+"""
+
+from django.urls import re_path
+
+from plinth.views import AppView
+
+urlpatterns = [
+ re_path(r'^apps/rssbridge/$', AppView.as_view(app_id='rssbridge'),
+ name='index'),
+]
diff --git a/pyproject.toml b/pyproject.toml
index 3954de651..5ef7e8f2f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -50,6 +50,7 @@ markers = [
"quassel",
"radicale",
"roundcube",
+ "rssbridge",
"samba",
"searx",
"security",
diff --git a/static/themes/default/icons/rssbridge.png b/static/themes/default/icons/rssbridge.png
new file mode 100644
index 000000000..a01e7a5da
Binary files /dev/null and b/static/themes/default/icons/rssbridge.png differ
diff --git a/static/themes/default/icons/rssbridge.svg b/static/themes/default/icons/rssbridge.svg
new file mode 100644
index 000000000..b0f5a3c5f
--- /dev/null
+++ b/static/themes/default/icons/rssbridge.svg
@@ -0,0 +1,103 @@
+
+
+
+