Skip to main content

Bash Script Installation on Debian 11

Based on the Manual Installation steps, I have created a simple bash script to automate the BookStack with LEMP stack install.

Copy the following code into a bash file, and run the script with sudo.

#!/bin/bash

#Simple script to install BookStack with LEMP Stack 
#Script follows the manual Installation method documented at https://www.bookstackapp.com/docs/admin/installation/#manual

#Install Nginx
sudo apt install -y nginx

#Start nginx on boot
sudo systemctl enable nginx

#Install MariaDB
sudo apt install -y mariadb-server mariadb-client

#start mariadb on boot
sudo systemctl enable mariadb

#Install system utilities
sudo apt install -y gnupg git unzip curl 

#Add PHP 8.1 Repo
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/php.list
wget -qO - https://packages.sury.org/php/apt.gpg | sudo apt-key add -
sudo apt update

#install BookStack required PHP 8.1 Packages
sudo apt install -y php8.1 php8.1-{curl,mbstring,ldap,xml,zip,gd,mysql,fpm}

#start php8.1-fpm on boot
sudo systemctl enable php8.1-fpm

#Prompt for a DB Password
TEMP1=true
while $TEMP1
do
    echo "Enter a new database password :"
    read db_pass1
    echo "Enter the password again:"
    read db_pass2

    if [ "$db_pass1" == "$db_pass2" ]
        then
            TEMP1=false
    else
        echo "Password did not match. Try Again."
    fi
done

#Create local BookStack Database
sudo mysql -u root --execute="CREATE DATABASE bookstack;"
sudo mysql -u root --execute="CREATE USER 'bookstack'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$db_pass2');"
sudo mysql -u root --execute="GRANT ALL ON bookstack.* TO 'bookstack'@'localhost';FLUSH PRIVILEGES;"

#Perform mysql_secure_installation queries
TEMP2=true
while $TEMP2
do
    echo "Enter a new SQL root user password :"
    read mysql_pass1
    echo "Enter the password again:"
    read mysql_pass2

    if [ "$mysql_pass1" == "$mysql_pass2" ]
        then
            TEMP2=false
    else
        echo "Password did not match. Try Again."
    fi
done

# Kill the anonymous users
sudo mysql -u root --execute="DROP USER ''@'localhost'"
# Because our hostname varies we'll use some Bash magic here.
sudo mysql -u root --execute="DROP USER ''@'$(hostname)'"
# Kill off the demo database
sudo mysql -u root --execute="DROP DATABASE test"
# Make sure that NOBODY can access the server without a password
sudo mysql -u root --execute="SET PASSWORD FOR 'root'@'localhost' = PASSWORD('$mysql_pass2')"
# Make our changes take effect
sudo mysql -u root --execute="FLUSH PRIVILEGES"
# Any subsequent tries to run queries this way will get access denied because lack of usr/pwd param

#Install Composer
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '55ce33d7678c5a611085589f1f3ddf8b3c52d662cd01d4ba75c0ee0459970c2200a51f492d557530c71c15d8dba01eae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

sudo mv composer.phar /usr/local/bin/composer

#Install BookStack

cd /var/www/

sudo git clone https://github.com/BookStackApp/BookStack.git --branch release --single-branch

cd BookStack
sudo composer install --no-dev

sudo cp .env.example .env

#Set Database connections and other env detais
sudo sed -i "s/DB_DATABASE=database_database/DB_DATABASE=bookstack/g" .env
sudo sed -i "s/DB_USERNAME=database_username/DB_USERNAME=bookstack/g" .env
sudo sed -i "s/DB_PASSWORD=database_user_password/DB_PASSWORD=$db_pass2/g" .env

FQDN="$(hostname -f)"
sed -i "s,APP_URL=https://example.com,APP_URL=https://$FQDN,g" .env

#Make sure storage, bootstrap/cache & public/uploads folders are writable by the web server
sudo chown -R www-data:www-data storage bootstrap/cache public/uploads

#Generate unique application keys for encryption
sudo php artisan key:generate

#Update Database
sudo php artisan migrate

Once the script finishes, modify and edit your Nginx config to allow HTTPS connection.

Example Nginx config:

server {
  listen 443 ssl;
  server_name server.example.com;

  #SSL Cert Location
  ssl_certificate SSL_Cert_Location;
  ssl_certificate_key SSL_Cert_Key_Location;
  
  #Disable NGINX current version reporting on error pages
  server_tokens off;
  
  #Force strong TLS
  ssl_protocols      TLSv1.3;
  ssl_prefer_server_ciphers   on;
  
  #Disable weak ciphers
  ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA HIGH !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";

  #Increase Upload Size.
  client_max_body_size 12M;
  
  #Root folder of BookStack
  root /var/www/BookStack/public;
  index index.php index.html;

  location / {
    try_files $uri $uri/ /index.php?$query_string;
  }
  
  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    #Modify the following to match your php-fpm version
    fastcgi_pass unix:/run/php/php8.1-fpm.sock;
  }
}