Skip to content

Instantly share code, notes, and snippets.

Last active December 20, 2023 06:04
Show Gist options
  • Save othmanalikhan/322f83a77c15dfd1c91a2afe0b6a6fc2 to your computer and use it in GitHub Desktop.
Save othmanalikhan/322f83a77c15dfd1c91a2afe0b6a6fc2 to your computer and use it in GitHub Desktop.
Installing BookStack (Debian 11) (2022-11)

Installation: Installing BookStack (Debian 11)

The following guide assumes running the commands below as root for simplicity. Later in the guide directory permissions are restricted to follow the principle of least privilege.

  1. Install dependencies.

    apt install -y git unzip apache2 php7.4 curl php7.4-fpm php7.4-curl php7.4-mbstring php7.4-ldap \
    php7.4-tidy php7.4-xml php7.4-zip php7.4-gd php7.4-mysql libapache2-mod-php7.4 \
  2. Setup database.

    # You can manually define the password below or autogenerate it.
    DB_PASS="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13)"
    # TODO: Consider moving away from 'mysql_native_password' to a more secure authentication mechanism.
    mysql -u root --execute="CREATE DATABASE bookstack;"
    mysql -u root --execute="CREATE USER 'bookstack'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
    mysql -u root --execute="GRANT ALL ON bookstack.* TO 'bookstack'@'localhost';FLUSH PRIVILEGES;"

    QA: Running mysql -u root --execute="SELECT user FROM mysql.user" should show the created user 'bookstack'.

  3. Install PHP package manager.

    # Install composer
    EXPECTED_CHECKSUM="$(php -r 'copy("", "php://stdout");')"
    php -r "copy('', 'composer-setup.php');"
    ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
        >&2 echo 'ERROR: Invalid composer installer checksum'
        rm composer-setup.php
        exit 1
    php composer-setup.php --quiet
    rm composer-setup.php
    # Move composer to global installation
    mv composer.phar /usr/local/bin/composer

    QA: Running composer about should output some text.

  4. Download BookStack PHP webapp files.

    cd /var/www
    git clone --branch release --single-branch bookstack
    cd bookstack
  5. Define BookStack environment variables (Change BASE_URL value below!).

    # Change the BASE_URL value to either an IP or hostname. See the three examples below (delete all except one BASE_URL)
    # Copy and update BookStack environment variables
    cp .env.example .env
    sed -i.bak "s@APP_URL=.*\$@APP_URL=$BASE_URL@" .env
    sed -i.bak 's/DB_DATABASE=.*$/DB_DATABASE=bookstack/' .env
    sed -i.bak 's/DB_USERNAME=.*$/DB_USERNAME=bookstack/' .env
    sed -i.bak "s/DB_PASSWORD=.*\$/DB_PASSWORD=$DB_PASS/" .env

    QA: Inspect the contents of the '.env' file and confirm that the four variables (APP_URL, DB_DATABASE, DB_USERNAME, DB_PASSWORD) have valid values.

  6. Configure BookStack.

    # Install BookStack composer dependencies
    php /usr/local/bin/composer install --no-dev --no-plugins
    # Generate the application key
    php artisan key:generate --no-interaction --force
    # Migrate the databases
    php artisan migrate --no-interaction --force
    # Set file and folder permissions
    chown www-data:www-data -R bootstrap/cache public/uploads storage && chmod -R 755 bootstrap/cache public/uploads storage
  7. Configure Apache to serve new BookStack app.

    # Set up apache
    a2enmod rewrite
    a2enmod php7.4
    # Create apache config file to serve webapp
    vim /etc/apache2/sites-available/bookstack.conf
        <VirtualHost *:80>
                # Set the 'ServerName' to a static IP address unless you have a DNS entry for the hostname already.
                ServerAdmin webmaster@localhost
                DocumentRoot /var/www/bookstack/public/
            <Directory /var/www/bookstack/public/>
                Options Indexes FollowSymLinks
                AllowOverride None
                Require all granted
                <IfModule mod_rewrite.c>
                    <IfModule mod_negotiation.c>
                        Options -MultiViews -Indexes
                    RewriteEngine On
                    # Handle Authorization Header
                    RewriteCond %{HTTP:Authorization} .
                    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
                    # Redirect Trailing Slashes If Not A Folder...
                    RewriteCond %{REQUEST_FILENAME} !-d
                    RewriteCond %{REQUEST_URI} (.+)/$
                    RewriteRule ^ %1 [L,R=301]
                    # Handle Front Controller...
                    RewriteCond %{REQUEST_FILENAME} !-d
                    RewriteCond %{REQUEST_FILENAME} !-f
                    RewriteRule ^ index.php [L]
                ErrorLog ${APACHE_LOG_DIR}/error.log
                CustomLog ${APACHE_LOG_DIR}/access.log combined
  8. Verify config file and enable it

    /usr/sbin/a2ensite bookstack.conf               # You need to enable it before using `apachectl configtest`
    /usr/sbin/apachectl configtest                  # You might see a `AH00558` warning message. It is safe to ignore (related to DNS lookup).
                                                    # The main thing to see is a `Syntax OK` message.
    /usr/sbin/a2dissite 000-default.conf            # Disable default website
    systemctl restart apache2
  9. Login into Bookstack: Browser > http://$BOOKSTACK_IP:80 > Login('', 'password')

Common Issues

  • Problem: I messed up during the mysql steps and lost the password! How can I reset the password for the 'bookstack' user?
  • Solution: mysql -u root --execute="SET PASSWORD FOR 'bookstack'@'localhost' = PASSWORD('AWESOME_NEW_PASSWORD')"
Copy link

Thanks for the snipet/collapsible tip/link @othmanalikhan ! I will definitely give it a lot of use now that I'm more active on github, so I honestly really appreciate it.

You were right indeed, Apache2 wasn't liking the comment on the same line as the argument.

Now I am able to restart Apache2 without problems, however, Bookstack is still unavailable. 😕 No error message or anything. Just blank. Apache2 error and access logs show nothing. Although there were some remainders from some previous access that shown the browser was able to pull the favicon.ico from Bookstack, and that was all I was seeing from the website. As soon as I cleared the logs and restarted everything, it was gone.

Do you know if there's anywhere else I can dig into logs to hopefully debug what is going on? Keep in mind I'm running this on a Gcloud VM. Thanks again for all the help! And please, if you have a buymeacoffee account, pass it on so I can thank you for your help a bit more! :)

EDIT: Yep, seems that when I bind the public IP of my GCloud instance, I get some response, but not the one we're looking for; here's the logs for Apache2 access.log:

tail -f /var/log/apache2/access.log 
[What seems to be a Linode Public IP Hmmm 🤔] - - [28/Oct/2022:01:09:54 +0000] "\x16\x03\x01" 400 486 "-" "-"
[My Public IP] - - [28/Oct/2022:01:17:23 +0000] "GET / HTTP/1.1" 500 185 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6.1 Safari/605.1.15"

EDIT2: Nevermind the Linode ip address. I forgot Gcloud VMs get bombarded with probes from 🤖

EDIT3: I will redo the VM and see if it works.

EDIT4: Redone it, not it's even worse 🤣 Now I access the pub_ip and Apache appends a www. to my ip. This is the output of Apache error log with debug level:

tail -f /var/log/apache2/error.log 
[Fri Oct 28 01:55:58.887621 2022] [authz_core:debug] [pid 19418] mod_authz_core.c(815): [client 181.XX.185.XX:25342] AH01626: authorization result of Require all granted: granted
[Fri Oct 28 01:55:58.887678 2022] [authz_core:debug] [pid 19418] mod_authz_core.c(815): [client 181.XX.185.XX:25342] AH01626: authorization result of <RequireAny>: granted
[Fri Oct 28 01:55:58.887874 2022] [authz_core:debug] [pid 19418] mod_authz_core.c(815): [client 181.XX.185.XX:25342] AH01626: authorization result of Require all granted: granted
[Fri Oct 28 01:55:58.887882 2022] [authz_core:debug] [pid 19418] mod_authz_core.c(815): [client 181.XX.185.XX:25342] AH01626: authorization result of <RequireAny>: granted

EDIT5: Welp, messing around with the .env file didn't seem to help either. My question being: Can I use an ip address in APP_URL?

EDIT6: All over again from scratch. Will redo the VM and try yet again. 😰

EDIT7: sigh I gave up and went with Wiki.js. Hope one day I can resolve the issues with Bookstack and get it to work!

@mariano-daniel How is Wiki.js going for you? Hopefully the deployment process was more straightforward than BookStack.

Apologies for the late reply, I had plans on deploying BookStack on a GCloud instance to verify the issues you are experiencing when I got more free time (which is right now) but it seems that Google Cloud Platform keeps rejecting my payment method.

In case you ever do come back to deploying BookStack, below are some things you can try to isolate whether the issue is from BookStack config itself or the GCloud config is to try the following:

  • To isolate any public routing/networking issues: After deploying BookStack on GCloud, try accessing the BookStack URL via the same machine using curl (e.g. curl -k localhost:80).
  • To isolate issues related to Apache: Try accessing the default Apache website that comes with Apache by default (you might need to re-enable it). First try accessing it locally via curl, then via a remote machine on the internet (e.g. your PC).

And lastly, thanks for sharing the buymeacoffee website! A very interesting website, wasn't aware of it. I appreciate the gesture and that is more than enough for me. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment