diff --git a/aleksis/apps/alsijil/admin.py b/aleksis/apps/alsijil/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..7deb5c6735ef6ebe8180b1ce0cf0a5d52ccd3fcb
--- /dev/null
+++ b/aleksis/apps/alsijil/admin.py
@@ -0,0 +1,5 @@
+from django.contrib import admin
+
+from .models import Instruction
+
+admin.site.register(Instruction)
diff --git a/aleksis/apps/alsijil/menus.py b/aleksis/apps/alsijil/menus.py
index eb2f7e0a61f815c3a2f39f22707940065d5de39d..1bf7be599fabf83bf1df5c22b614b0f03963d965 100644
--- a/aleksis/apps/alsijil/menus.py
+++ b/aleksis/apps/alsijil/menus.py
@@ -67,6 +67,17 @@ MENUS = {
                         ),
                     ],
                 },
+                {
+                    "name": _("Instructions"),
+                    "url": "instructions",
+                    "icon": "rule_folder",
+                    "validators": [
+                        (
+                            "aleksis.core.util.predicates.permission_validator",
+                            "alsijil.view_instructions_rule",
+                        ),
+                    ],
+                },
                 {
                     "name": _("Assign group role"),
                     "url": "assign_group_role_multiple",
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 8d387dbeeb31b4757852f0c43c2df55d8e261a70..3001bd54df8fd50962a52329b71ab6ad536c3681 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -490,6 +490,9 @@ class Instruction(SchoolTermRelatedExtensibleModel):
         ),
     )
 
+    def __str__(self):
+        return self.name
+
     class Meta:
         verbose_name = _("Instruction")
         verbose_name_plural = _("Instructions")
diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py
index 0b418af8cb20cb96a109a4b8e55a16a707e38b6d..0aaaa477f23f35775e87d5a5d40ae97d0f88bb40 100644
--- a/aleksis/apps/alsijil/rules.py
+++ b/aleksis/apps/alsijil/rules.py
@@ -308,3 +308,6 @@ view_register_objects_list_predicate = has_person & (
     | has_global_perm("core.view_full_register")
 )
 add_perm("alsijil.view_register_objects_list_rule", view_register_objects_list_predicate)
+
+view_instructions_predicate = has_person
+add_perm("alsijil.view_instructions_rule", view_instructions_predicate)
diff --git a/aleksis/apps/alsijil/templates/alsijil/instruction/list.html b/aleksis/apps/alsijil/templates/alsijil/instruction/list.html
new file mode 100644
index 0000000000000000000000000000000000000000..da3c384b39440f78e27ac4700124a3ed58d3984b
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/instruction/list.html
@@ -0,0 +1,23 @@
+{# -*- engine:django -*- #}
+
+{% extends "core/base.html" %}
+
+{% load i18n %}
+
+{% block browser_title %}{% blocktrans %}Instructions{% endblocktrans %}{% endblock %}
+{% block page_title %}{% blocktrans %}Instructions{% endblocktrans %}{% endblock %}
+
+{% block content %}
+  <ul class="collection">
+    {% for instruction in instruction_list %}
+      <li class="collection-item avatar">
+        <i class="material-icons materialize-circle primary-color">{{ instruction.icon|default:"rule" }}</i>
+        <span class="title"> {{ instruction.name }}</span>
+          <a class="btn-flat waves-effect waves-green right" href="{{ instruction.pdf_file.url }}" target="_blank">
+            <i class="material-icons left">picture_as_pdf</i>
+            {% trans "Show PDF file with instruction" %}
+          </a>
+      </li>
+    {% endfor %}
+  </ul>
+{% endblock %}
diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py
index 8fb31b625ba068fc3c6ba731fe39155f9974d76e..91fbb68bc428a3ff2f63686a59dc7135bf9c3223 100644
--- a/aleksis/apps/alsijil/urls.py
+++ b/aleksis/apps/alsijil/urls.py
@@ -101,4 +101,5 @@ urlpatterns = [
         name="assign_group_role_multiple",
     ),
     path("all/", views.AllRegisterObjectsView.as_view(), name="all_register_objects"),
+    path("instructions/", views.InstructionsListView.as_view(), name="instructions"),
 ]
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 3999324f22796719df6586dc7a99a38851fda495..19eb2760379911de509840eca51d6d189eb6af73 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -16,7 +16,7 @@ from django.utils.http import url_has_allowed_host_and_scheme
 from django.utils.translation import ugettext as _
 from django.views import View
 from django.views.decorators.cache import never_cache
-from django.views.generic import DetailView
+from django.views.generic import DetailView, ListView
 
 import reversion
 from calendarweek import CalendarWeek
@@ -62,6 +62,7 @@ from .models import (
     ExtraMark,
     GroupRole,
     GroupRoleAssignment,
+    Instruction,
     LessonDocumentation,
     PersonalNote,
 )
@@ -1351,3 +1352,11 @@ class AllRegisterObjectsView(PermissionRequiredMixin, View):
         if self.action_form.is_valid():
             self.action_form.execute()
         return render(request, "alsijil/class_register/all_objects.html", context)
+
+
+class InstructionsListView(PermissionRequiredMixin, ListView):
+    """Table of all excuse types."""
+
+    model = Instruction
+    permission_required = "alsijil.view_instructions_rule"
+    template_name = "alsijil/instruction/list.html"