After a while of using Bookstack you’ll soon notice your collection of knowledgeable things increase, and maybe you’ll start to worry about backing things up or keeping all this data accessible.
Worry no more, I got you covered!
Backing up Bookstack is easier than you might think, let me share you my way of backing up my dockerized Bookstack instance.
Backing up the config
Dir
#
Your Bookstack docker-compose.yml
contains a volume mount for all of your uploaded data similar to this:
volumes:
- /path/to/config:/config
The following command will archive this directory and safe a tarball like bookstack_config_backup-<timestamp>.tar.gz
in the destination directory.
This can be used in a cron job for example:
/bin/tar -czvf /path/to/bookstack_config-backups/bookstack_config_backup-$(date '+%Y%m%d-%H%M').tar.gz /path/to/bookstack/config
/path/to/bookstack_config-backups/
Source directory:
/path/to/bookstack/config
Exporting all Books as HTML files #
PDF exports are a great way to keep your documentation at hand even when your Bookstack wiki might be down.
I found a great PHP script to accomplish exactly that but can’t remember the source, so if you’re the author or know him feel free to contact me and I gladly add the source.
Creating API Token #
To authenticate this script to your Bookstack API you have to create an API token first.
Edit your profile (top right corner), scroll all the way down to the section “API Tokens” and click on “CREATE TOKEN”.
Set a name and leave Expiry Date
empty.
Obtain Token ID
and Token Secret
of the freshly generated token.
PHP Script #
Use this bookstack-export.php
script in a cron job for example:
Click for bookstack-export.php ...
#!/usr/bin/env php
<?php
// API Credentials
// You can either provide them as environment variables
// or hard-code them in the empty strings below.
$apiUrl = 'https://bookstack.domain.tld' ?: ''; // http://bookstack.local/
$clientId = 'API_CLIENT_ID' ?: '';
$clientSecret = 'API_CLIENT_SECRET' ?: '';
// Export Format & Location
// Can be provided as a arguments when calling the script
// or be hard-coded as strings below.
$exportFormat = 'html' ;
$exportLocation = '/path/to/bookstack-export' ; // Destination path for the export
// Script logic
////////////////
$books = getAllBooks();
$outDir = realpath($exportLocation);
$extensionByFormat = [
'pdf' => 'pdf',
'html' => 'html',
'plaintext' => 'txt',
];
foreach ($books as $book) {
$id = $book['id'];
$extension = $extensionByFormat[$exportFormat] ?? $exportFormat;
$content = apiGet("api/books/{$id}/export/{$exportFormat}");
$outPath = $outDir . "/{$book['slug']}.{$extension}";
file_put_contents($outPath, $content);
}
/**
* Get all books from the system API.
*/
function getAllBooks() {
$count = 100;
$offset = 0;
$total = 0;
$allBooks = [];
do {
$endpoint = 'api/books?' . http_build_query(['count' => $count, 'offset' => $offset]);
$resp = apiGetJson($endpoint);
// Only set total on first request, due to API bug:
// https://github.com/BookStackApp/BookStack/issues/2043
if ($offset == 0) {
$total = $resp['total'] ?? 0;
}
$newBooks = $resp['data'] ?? [];
array_push($allBooks, ...$newBooks);
$offset += $count;
} while ($offset < $total);
return $allBooks;
}
/**
* Make a simple GET HTTP request to the API.
*/
function apiGet(string $endpoint): string {
global $apiUrl, $clientId, $clientSecret;
$url = rtrim($apiUrl, '/') . '/' . ltrim($endpoint, '/');
$opts = ['http' => ['header' => "Authorization: Token {$clientId}:{$clientSecret}"]];
$context = stream_context_create($opts);
return file_get_contents($url, false, $context);
}
/**
* Make a simple GET HTTP request to the API &
* decode the JSON response to an array.
*/
function apiGetJson(string $endpoint): array {
$data = apiGet($endpoint);
return json_decode($data, true);
}
/**
* DEBUG: Dump out the given variables and exit.
*/
function dd(...$args) {
foreach ($args as $arg) {
var_dump($arg);
}
exit(1);
}
Token ID
and Token Secret
as $clientId
and $clientSecret
in the script.
Set $apiUrl
and $exportLocation
accordingly to your setup.
Final thoughts #
If you follow this guide your Bookstack instance is both, backed up and always available to you.
Both Scripts can be combined in a single Bash-Script like this:
#!/bin/bash
/bin/tar -czvf /path/to/bookstack_config-backups/bookstack_config_backup-$(date '+%Y%m%d-%H%M').tar.gz /path/to/bookstack/config &&
/usr/bin/php /path/to/bookstack-export.php
Create a daily cron job, and you’re all set:
# Bookstack Backup (daily at 08:00 am)
0 8 * * * /path/to/bookstack_backup.sh > /dev/null