diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 42ac856a22bf94f380bc762ec59895fb94a79f5f..c41a565ea2d8b2ea04619180fde591c1ae498709 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -13,6 +13,7 @@ Added
 ~~~~~
 
 * Add link to public page to events list
+* Add RSS feed of upcoming events
 
 Fixed
 ~~~~~
diff --git a/aleksis/apps/paweljong/models.py b/aleksis/apps/paweljong/models.py
index 6148f135e102823466f3d566b9774885c9b364b7..ddb97fb812692b850cc674d4da325b04bcc46ef0 100644
--- a/aleksis/apps/paweljong/models.py
+++ b/aleksis/apps/paweljong/models.py
@@ -1,6 +1,8 @@
 from datetime import datetime
 
 from django.db import models
+from django.urls import reverse
+from django.utils.timezone import now
 from django.utils.translation import gettext_lazy as _
 
 from ckeditor.fields import RichTextField
@@ -67,6 +69,9 @@ class Event(ExtensibleModel):
             return self.date_registration >= now
         return self.date_event > now
 
+    def get_absolute_url(self):
+        return reverse("event_by_name", kwargs={"slug": self.linked_group.short_name})
+
     @property
     def booked_percentage(self):
         return self.linked_group.members.count() / self.max_participants * 100
@@ -79,6 +84,10 @@ class Event(ExtensibleModel):
     def owners_persons(self):
         return self.linked_group.owners.all()
 
+    @classmethod
+    def upcoming_published_events(cls):
+        return Event.objects.filter(published=True, date_event__gte=now())
+
 
 class Voucher(ExtensibleModel):
     class Meta:
diff --git a/aleksis/apps/paweljong/urls.py b/aleksis/apps/paweljong/urls.py
index 7dd949c9f5dedf76c1d58ef175f981b698ea2784..b4a29e28b1fec9e0ed44b2ccbc36bd17af673592 100644
--- a/aleksis/apps/paweljong/urls.py
+++ b/aleksis/apps/paweljong/urls.py
@@ -40,6 +40,7 @@ urlpatterns = [
         name="register_event_by_slug_start",
     ),
     path("misc/set_email_needed/<slug:slug>", views.set_email_needed, name="set_email_needed"),
+    path("events/feed", views.UpcomingEventsRSSFeed.as_view(), name="upcoming_events_rss_feed"),
     path("events/create", views.CreateEventView.as_view(), name="create_event"),
     path("events/manage", views.manage_events, name="manage_events"),
     path("vouchers/create", views.VoucherCreateView.as_view(), name="create_vouchers"),
diff --git a/aleksis/apps/paweljong/views.py b/aleksis/apps/paweljong/views.py
index eb143d6d11dbcd968efdc527aa6e9baad0f18333..51abfdf4bc08b6878e9a2c2e8961fcad859c5c83 100644
--- a/aleksis/apps/paweljong/views.py
+++ b/aleksis/apps/paweljong/views.py
@@ -1,8 +1,9 @@
 from django.conf import settings
 from django.contrib.auth import get_user_model
+from django.contrib.syndication.views import Feed
 from django.http import HttpRequest, HttpResponse
 from django.shortcuts import redirect, render
-from django.urls import reverse_lazy
+from django.urls import reverse, reverse_lazy
 from django.utils import timezone
 from django.utils.decorators import method_decorator
 from django.utils.text import slugify
@@ -664,3 +665,34 @@ class TermEditView(PermissionRequiredMixin, AdvancedEditView):
     template_name = "paweljong/term/edit.html"
     success_url = reverse_lazy("terms")
     success_message = _("The term has been saved.")
+
+
+class UpcomingEventsRSSFeed(Feed):
+    """RSS feed for published, upcoming events."""
+
+    def title(self):
+        return _("Upcoming events")
+
+    def link(self):
+        return reverse("index")
+
+    def feed_url(self):
+        return reverse("upcoming_events_rss_feed")
+
+    def description(self):
+        return _("Announcement feed of all upcoming events")
+
+    def ttl(self):
+        date_event = Event.upcoming_published_events().order_by("-date_event").first().date_event
+        date_now = timezone.now()
+
+        return (date_event - date_now).seconds
+
+    def items(self):
+        return Event.upcoming_published_events()
+
+    def item_title(self, item):
+        return item.display_name
+
+    def item_description(self, item):
+        return item.description