diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4d80e7700a22961535632eea205c4824de7223fa..ae2ef854cbce2dcc10ba83cd91b6806284fda64c 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -9,6 +9,11 @@ and this project adheres to `Semantic Versioning`_.
 Unreleased
 ----------
 
+Fixed
+~~~~~
+
+* PDF generation failed with S3 storage due to incompatibility with boto3
+
 `2.7`_ - 2022-01-24
 -------------------
 
diff --git a/aleksis/core/templates/core/base_print.html b/aleksis/core/templates/core/base_print.html
index d0b7cf6dd054a07e2e2efea7b1ce40176804c952..ed2a0c200c3798311db66980f3391b52ed67600e 100644
--- a/aleksis/core/templates/core/base_print.html
+++ b/aleksis/core/templates/core/base_print.html
@@ -5,6 +5,8 @@
 <!DOCTYPE html>
 <html lang="{{ LANGUAGE_CODE }}">
 <head>
+  <base href="{{ BASE_URL }}" />
+
   {% include "core/partials/meta.html" %}
 
   <title>
diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py
index 148d33594d2cc0a2619a1c1a64c3b8fa69dad79c..55085d91031a1c591f71e4b8712b1cc7f3178cef 100644
--- a/aleksis/core/util/core_helpers.py
+++ b/aleksis/core/util/core_helpers.py
@@ -216,6 +216,7 @@ def custom_information_processor(request: Union[HttpRequest, None]) -> dict:
         "PWA_ICONS": regrouped_pwa_icons,
         "SENTRY_ENABLED": settings.SENTRY_ENABLED,
         "SITE_PREFERENCES": get_site_preferences(),
+        "BASE_URL": settings.BASE_URL,
     }
 
     if settings.SENTRY_ENABLED:
diff --git a/aleksis/core/util/pdf.py b/aleksis/core/util/pdf.py
index d65000811b123eab7ce6ad7e7ce29b02c3d73b06..b0c83ed1ef2dfed841e1d7dd3e13203a4b35ffae 100644
--- a/aleksis/core/util/pdf.py
+++ b/aleksis/core/util/pdf.py
@@ -79,7 +79,9 @@ def generate_pdf_from_template(
         processed_context = context
     html_template = render_to_string(template_name, processed_context, request)
 
-    file_object = PDFFile.objects.create(html_file=ContentFile(html_template, name="source.html"))
+    file_object = PDFFile.objects.create(
+        html_file=ContentFile(html_template.encode(), name="source.html")
+    )
 
     # As this method may be run in background and there is no request available,
     # we have to use a predefined URL from settings then
diff --git a/docs/admin/06_storage.rst b/docs/admin/06_storage.rst
index 96b789b36d30e7d0014bc19df091b86d1433118a..f4a7f6130735644298207edc290ee72ddb4f2d65 100644
--- a/docs/admin/06_storage.rst
+++ b/docs/admin/06_storage.rst
@@ -28,6 +28,12 @@ AlekSIS allows you to configure an Amazon S3 endpoint for  media
 files. This is useful e.g. for loadbalancing with multiple AlekSIS
 instances.
 
+.. note::
+   For some background jobs, AlekSIS stores HTML snippets in the media
+   storage for later use. You must ensure your S3 endpoint is part of
+   your ``Access-Control-Allow-Origin`` CORS header, so HTML loaded from
+   there can load resources from the ALekSIS instance.
+
 Configure an S3 endpoint
 ~~~~~~~~~~~~~~~~~~~~~~~~