diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py
index 0539b2aeb..881a2fde9 100644
--- a/ietf/meeting/tests_views.py
+++ b/ietf/meeting/tests_views.py
@@ -293,6 +293,18 @@ class MeetingTests(TestCase):
         self.assertEqual(r.status_code,200)
         self.assertTrue(all([x in unicontent(r) for x in ['var all_items', 'maximize', 'draw_calendar', ]]))
 
+    @override_settings(SERVE_MEETING_MATERIALS_LOCALLY=False)
+    def test_materials_through_cdn(self):
+        meeting = make_meeting_test_data()
+        session = Session.objects.filter(meeting=meeting, group__acronym="mars").first()
+        self.write_materials_files(meeting, session)
+        for document in (session.agenda(),session.minutes(),session.slides()[0]):
+            url = urlreverse("ietf.meeting.views.materials_document",
+                                           kwargs=dict(num=meeting.number, document=document))
+            r = self.client.get(url)
+            self.assertEqual(r.status_code,302)
+            self.assertEqual(r['Location'],document.get_href())
+
     def test_materials(self):
         meeting = make_meeting_test_data()
         session = Session.objects.filter(meeting=meeting, group__acronym="mars").first()
@@ -307,6 +319,7 @@ class MeetingTests(TestCase):
 
         self.do_test_materials(meeting, session)
 
+    @override_settings(SERVE_MEETING_MATERIALS_LOCALLY=True)
     def do_test_materials(self, meeting, session):
 
         self.write_materials_files(meeting, session)
@@ -2523,6 +2536,7 @@ class MaterialsTests(TestCase):
             r = self.client.post(url,dict(file=test_file,apply_to_all=False))
             self.assertEqual(r.status_code, 410)
 
+    @override_settings(SERVE_MEETING_MATERIALS_LOCALLY=True)
     def test_upload_minutes_agenda_interim(self):
         session=SessionFactory(meeting__type_id='interim')
         for doctype in ('minutes','agenda'):
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 467eeda3e..10c883106 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -220,29 +220,33 @@ def materials_document(request, document, num=None, ext=None):
     _, basename = os.path.split(filename)
     if not os.path.exists(filename):
         raise Http404("File not found: %s" % filename)
-    with io.open(filename, 'rb') as file:
-        bytes = file.read()
-    
-    mtype, chset = get_mime_type(bytes)
-    content_type = "%s; charset=%s" % (mtype, chset)
 
-    file_ext = os.path.splitext(filename)
-    if len(file_ext) == 2 and file_ext[1] == '.md' and mtype == 'text/plain':
-        sorted_accept = sort_accept_tuple(request.META.get('HTTP_ACCEPT'))
-        for atype in sorted_accept:
-            if atype[0] == 'text/markdown':
-                content_type = content_type.replace('plain', 'markdown', 1)
-                break;
-            elif atype[0] == 'text/html':
-                bytes = "<html>\n<head></head>\n<body>\n%s\n</body>\n</html>\n" % markdown2.markdown(bytes)
-                content_type = content_type.replace('plain', 'html', 1)
-                break;
-            elif atype[0] == 'text/plain':
-                break;
+    if settings.SERVE_MEETING_MATERIALS_LOCALLY :
+        with io.open(filename, 'rb') as file:
+            bytes = file.read()
+        
+        mtype, chset = get_mime_type(bytes)
+        content_type = "%s; charset=%s" % (mtype, chset)
 
-    response = HttpResponse(bytes, content_type=content_type)
-    response['Content-Disposition'] = 'inline; filename="%s"' % basename
-    return response
+        file_ext = os.path.splitext(filename)
+        if len(file_ext) == 2 and file_ext[1] == '.md' and mtype == 'text/plain':
+            sorted_accept = sort_accept_tuple(request.META.get('HTTP_ACCEPT'))
+            for atype in sorted_accept:
+                if atype[0] == 'text/markdown':
+                    content_type = content_type.replace('plain', 'markdown', 1)
+                    break;
+                elif atype[0] == 'text/html':
+                    bytes = "<html>\n<head></head>\n<body>\n%s\n</body>\n</html>\n" % markdown2.markdown(bytes)
+                    content_type = content_type.replace('plain', 'html', 1)
+                    break;
+                elif atype[0] == 'text/plain':
+                    break;
+
+        response = HttpResponse(bytes, content_type=content_type)
+        response['Content-Disposition'] = 'inline; filename="%s"' % basename
+        return response
+    else:
+        return HttpResponseRedirect(redirect_to=doc.get_href())
 
 @login_required
 def materials_editable_groups(request, num=None):
diff --git a/ietf/settings.py b/ietf/settings.py
index 9250c38de..81b6e6745 100644
--- a/ietf/settings.py
+++ b/ietf/settings.py
@@ -691,7 +691,13 @@ DOC_HREFS = {
     "liai-att": "%s{doc.uploaded_filename}" % LIAISON_ATTACH_URL,
 }
 
-MEETING_DOC_HREFS = {
+SERVE_MEETING_MATERIALS_LOCALLY = False
+
+# If you override SERVE_MEETING_MATERIALS_LOCALLY in your settings_local.conf, you will need to
+# set the right value for MEETING_DOC_HREFS there as well. LOCAL_MEETING_DOC_HREFS and 
+# CDN_MEETING_DOC_HREFS are defined here to make that simpler.
+
+LOCAL_MEETING_DOC_HREFS = {
     "agenda": "/meeting/{meeting.number}/materials/{doc.name}-{doc.rev}",
     "minutes": "/meeting/{meeting.number}/materials/{doc.name}-{doc.rev}",
     "slides": "/meeting/{meeting.number}/materials/{doc.name}-{doc.rev}",
@@ -699,6 +705,16 @@ MEETING_DOC_HREFS = {
     "bluesheets": "https://www.ietf.org/proceedings/{meeting.number}/bluesheets/{doc.uploaded_filename}",
 }
 
+CDN_MEETING_DOC_HREFS = {
+    "agenda": "https://www.ietf.org/proceedings/{meeting.number}/agenda/{doc.name}-{doc.rev}",
+    "minutes": "https://www.ietf.org/proceedings/{meeting.number}/minutes/{doc.name}-{doc.rev}",
+    "slides": "https://www.ietf.org/proceedings/{meeting.number}/slides/{doc.name}-{doc.rev}",
+    "recording": "{doc.external_url}",
+    "bluesheets": "https://www.ietf.org/proceedings/{meeting.number}/bluesheets/{doc.uploaded_filename}",
+}
+
+MEETING_DOC_HREFS = LOCAL_MEETING_DOC_HREFS if SERVE_MEETING_MATERIALS_LOCALLY else CDN_MEETING_DOC_HREFS
+
 MEETING_DOC_OLD_HREFS = {
     "agenda": "/meeting/{meeting.number}/materials/{doc.name}",
     "minutes": "/meeting/{meeting.number}/materials/{doc.name}",
@@ -716,6 +732,7 @@ MEETING_DOC_GREFS = {
     "bluesheets": "https://www.ietf.org/proceedings/{meeting.number}/bluesheets/{doc.uploaded_filename}",
 }
 
+
 # Valid MIME types for cases where text is uploaded and immediately extracted,
 # e.g. a charter or a review. Must be a tuple, not a list.
 DOC_TEXT_FILE_VALID_UPLOAD_MIME_TYPES = ('text/plain', 'text/markdown', 'text/x-rst')