diff --git a/app/Entities/Tools/ExportFormatter.php b/app/Entities/Tools/ExportFormatter.php
index eb8f6862f..b462abec5 100644
--- a/app/Entities/Tools/ExportFormatter.php
+++ b/app/Entities/Tools/ExportFormatter.php
@@ -7,7 +7,9 @@ use BookStack\Uploads\ImageService;
 use DomPDF;
 use Exception;
 use SnappyPDF;
+use League\HTMLToMarkdown\HtmlConverter;
 use Throwable;
+use ZipArchive;
 
 class ExportFormatter
 {
@@ -226,4 +228,72 @@ class ExportFormatter
         }
         return $text;
     }
+
+    /**
+     * Convert a page to a Markdown file.
+     * @throws Throwable
+     */
+    public function pageToMarkdown(Page $page)
+    {
+        if (property_exists($page, 'markdown') && $page->markdown != '') {
+            return "# " . $page->name . "\n\n" . $page->markdown;
+        } else {
+            $converter = new HtmlConverter();
+            return "# " . $page->name . "\n\n" . $converter->convert($page->html);
+        }
+    }
+
+    /**
+     * Convert a chapter to a Markdown file.
+     * @throws Throwable
+     */
+    public function chapterToMarkdown(Chapter $chapter)
+    {
+        $text = "# " . $chapter->name . "\n\n";
+        $text .= $chapter->description . "\n\n";
+        foreach ($chapter->pages as $page) {
+            $text .= $this->pageToMarkdown($page);
+        }
+        return $text;
+    }
+
+    /**
+     * Convert a book into a plain text string.
+     */
+    public function bookToMarkdown(Book $book): string
+    {
+        $bookTree = (new BookContents($book))->getTree(false, true);
+        $text = "# " . $book->name . "\n\n";
+        foreach ($bookTree as $bookChild) {
+            if ($bookChild->isA('chapter')) {
+                $text .= $this->chapterToMarkdown($bookChild);
+            } else {
+                $text .= $this->pageToMarkdown($bookChild);
+            }
+        }
+        return $text;
+    }
+
+    /**
+     * Convert a book into a zip file.
+     */
+    public function bookToZip(Book $book): string
+    {
+        // TODO: Is not unlinking the file a security risk?
+        $z = new ZipArchive();
+        $z->open("book.zip", \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
+        $bookTree = (new BookContents($book))->getTree(false, true);
+        foreach ($bookTree as $bookChild) {
+            if ($bookChild->isA('chapter')) {
+                $z->addEmptyDir($bookChild->name);
+                foreach ($bookChild->pages as $page) {
+                    $filename = $bookChild->name . "/" . $page->name . ".md";
+                    $z->addFromString($filename, $this->pageToMarkdown($page));
+                }
+            } else {
+                $z->addFromString($bookChild->name . ".md", $this->pageToMarkdown($bookChild));
+            }
+        }
+        return "book.zip";
+    }
 }
diff --git a/app/Http/Controllers/BookExportController.php b/app/Http/Controllers/BookExportController.php
index 1c1f12442..58868fa5c 100644
--- a/app/Http/Controllers/BookExportController.php
+++ b/app/Http/Controllers/BookExportController.php
@@ -52,4 +52,24 @@ class BookExportController extends Controller
         $textContent = $this->exportFormatter->bookToPlainText($book);
         return $this->downloadResponse($textContent, $bookSlug . '.txt');
     }
+
+    /**
+     * Export a book as a markdown file.
+     */
+    public function markdown(string $bookSlug)
+    {
+        $book = $this->bookRepo->getBySlug($bookSlug);
+        $textContent = $this->exportService->bookToMarkdown($book);
+        return $this->downloadResponse($textContent, $bookSlug . '.md');
+    }
+
+    /**
+     * Export a book as a zip file, made of markdown files.
+     */
+    public function zip(string $bookSlug)
+    {
+        $book = $this->bookRepo->getBySlug($bookSlug);
+        $filename = $this->exportService->bookToZip($book);
+        return response()->download($filename);
+    }
 }
diff --git a/app/Http/Controllers/ChapterExportController.php b/app/Http/Controllers/ChapterExportController.php
index 52d087442..bc709771b 100644
--- a/app/Http/Controllers/ChapterExportController.php
+++ b/app/Http/Controllers/ChapterExportController.php
@@ -54,4 +54,16 @@ class ChapterExportController extends Controller
         $chapterText = $this->exportFormatter->chapterToPlainText($chapter);
         return $this->downloadResponse($chapterText, $chapterSlug . '.txt');
     }
+
+    /**
+     * Export a chapter to a simple markdown file.
+     * @throws NotFoundException
+     */
+    public function markdown(string $bookSlug, string $chapterSlug)
+    {
+        // TODO: This should probably export to a zip file.
+        $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
+        $chapterText = $this->exportService->chapterToMarkdown($chapter);
+        return $this->downloadResponse($chapterText, $chapterSlug . '.md');
+    }
 }
diff --git a/app/Http/Controllers/PageExportController.php b/app/Http/Controllers/PageExportController.php
index e5e027fe7..d9cc5ba48 100644
--- a/app/Http/Controllers/PageExportController.php
+++ b/app/Http/Controllers/PageExportController.php
@@ -60,4 +60,15 @@ class PageExportController extends Controller
         $pageText = $this->exportFormatter->pageToPlainText($page);
         return $this->downloadResponse($pageText, $pageSlug . '.txt');
     }
+
+    /**
+     * Export a page to a simple markdown .md file.
+     * @throws NotFoundException
+     */
+    public function markdown(string $bookSlug, string $pageSlug)
+    {
+        $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
+        $pageText = $this->exportService->pageToMarkdown($page);
+        return $this->downloadResponse($pageText, $pageSlug . '.md');
+    }
 }
diff --git a/composer.json b/composer.json
index 8450a2f92..8124ccbca 100644
--- a/composer.json
+++ b/composer.json
@@ -23,6 +23,7 @@
         "laravel/socialite": "^5.1",
         "league/commonmark": "^1.5",
         "league/flysystem-aws-s3-v3": "^1.0.29",
+        "league/html-to-markdown": "^4.9",
         "nunomaduro/collision": "^3.1",
         "onelogin/php-saml": "^4.0",
         "predis/predis": "^1.1.6",
diff --git a/dev/docker/Dockerfile b/dev/docker/Dockerfile
index 895ad595a..178ea9a6c 100644
--- a/dev/docker/Dockerfile
+++ b/dev/docker/Dockerfile
@@ -5,9 +5,9 @@ WORKDIR /app
 
 # Install additional dependacnies and configure apache
 RUN apt-get update -y \
-    && apt-get install -y git zip unzip libpng-dev libldap2-dev wait-for-it \
+    && apt-get install -y git zip unzip libpng-dev libldap2-dev libzip-dev wait-for-it \
     && docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu \
-    && docker-php-ext-install pdo_mysql gd ldap \
+    && docker-php-ext-install pdo_mysql gd ldap zip \
     && a2enmod rewrite \
     && sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
     && sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
@@ -20,4 +20,4 @@ RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
 
 # Use the default production configuration and update it as required
 RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
-    && sed -i 's/memory_limit = 128M/memory_limit = 512M/g' "$PHP_INI_DIR/php.ini"
\ No newline at end of file
+    && sed -i 's/memory_limit = 128M/memory_limit = 512M/g' "$PHP_INI_DIR/php.ini"
diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php
index 462402f33..1d4632bce 100644
--- a/resources/lang/en/entities.php
+++ b/resources/lang/en/entities.php
@@ -36,6 +36,7 @@ return [
     'export_html' => 'Contained Web File',
     'export_pdf' => 'PDF File',
     'export_text' => 'Plain Text File',
+    'export_md' => 'Markdown File',
 
     // Permissions and restrictions
     'permissions' => 'Permissions',
diff --git a/resources/views/partials/entity-export-menu.blade.php b/resources/views/partials/entity-export-menu.blade.php
index 6d23af07c..2b0f5c19d 100644
--- a/resources/views/partials/entity-export-menu.blade.php
+++ b/resources/views/partials/entity-export-menu.blade.php
@@ -8,5 +8,6 @@
         <li><a href="{{ $entity->getUrl('/export/html') }}" target="_blank" rel="noopener">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li>
         <li><a href="{{ $entity->getUrl('/export/pdf') }}" target="_blank" rel="noopener">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
         <li><a href="{{ $entity->getUrl('/export/plaintext') }}" target="_blank" rel="noopener">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li>
+        <li><a href="{{ $entity->getUrl('/export/markdown') }}" target="_blank" rel="noopener">{{ trans('entities.export_md') }} <span class="text-muted float right">.md</span></a></li>
     </ul>
-</div>
\ No newline at end of file
+</div>
diff --git a/routes/web.php b/routes/web.php
index 72d089078..2bba3e2cf 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -48,6 +48,8 @@ Route::group(['middleware' => 'auth'], function () {
         Route::put('/{bookSlug}/sort', 'BookSortController@update');
         Route::get('/{bookSlug}/export/html', 'BookExportController@html');
         Route::get('/{bookSlug}/export/pdf', 'BookExportController@pdf');
+        Route::get('/{bookSlug}/export/markdown', 'BookExportController@markdown');
+        Route::get('/{bookSlug}/export/zip', 'BookExportController@zip');
         Route::get('/{bookSlug}/export/plaintext', 'BookExportController@plainText');
 
         // Pages
@@ -58,6 +60,7 @@ Route::group(['middleware' => 'auth'], function () {
         Route::get('/{bookSlug}/page/{pageSlug}', 'PageController@show');
         Route::get('/{bookSlug}/page/{pageSlug}/export/pdf', 'PageExportController@pdf');
         Route::get('/{bookSlug}/page/{pageSlug}/export/html', 'PageExportController@html');
+        Route::get('/{bookSlug}/page/{pageSlug}/export/markdown', 'PageExportController@markdown');
         Route::get('/{bookSlug}/page/{pageSlug}/export/plaintext', 'PageExportController@plainText');
         Route::get('/{bookSlug}/page/{pageSlug}/edit', 'PageController@edit');
         Route::get('/{bookSlug}/page/{pageSlug}/move', 'PageController@showMove');
@@ -92,6 +95,7 @@ Route::group(['middleware' => 'auth'], function () {
         Route::get('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@showPermissions');
         Route::get('/{bookSlug}/chapter/{chapterSlug}/export/pdf', 'ChapterExportController@pdf');
         Route::get('/{bookSlug}/chapter/{chapterSlug}/export/html', 'ChapterExportController@html');
+        Route::get('/{bookSlug}/chapter/{chapterSlug}/export/markdown', 'ChapterExportController@markdown');
         Route::get('/{bookSlug}/chapter/{chapterSlug}/export/plaintext', 'ChapterExportController@plainText');
         Route::put('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@permissions');
         Route::get('/{bookSlug}/chapter/{chapterSlug}/delete', 'ChapterController@showDelete');