@@ -4,115 +4,172 @@ echo "This script installs a new BookStack instance on a fresh Ubuntu 22.04 serv
44echo " This script does not ensure system security."
55echo " "
66
7- # Check we're running as root and exit if not
8- if [[ $EUID -gt 0 ]]
9- then
10- >&2 echo " ERROR: This script must be ran with root/sudo privileges"
11- exit 1
12- fi
7+ # Generate a path for a log file to output into for debugging
8+ LOGPATH=$( realpath " bookstack_install_log_$( date +%s) .log" )
139
1410# Get the current user running the script
1511SCRIPT_USER=" ${SUDO_USER:- $USER } "
1612
1713# Get the current machine IP address
1814CURRENT_IP=$( ip addr | grep ' state UP' -A4 | grep ' inet ' | awk ' {print $2}' | cut -f1 -d' /' )
1915
20- # Fetch domain to use from first provided parameter,
21- # Otherwise request the user to input their domain
16+ # Generate a password for the database
17+ DB_PASS=" $( head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13) "
18+
19+ # The directory to install BookStack into
20+ BOOKSTACK_DIR=" /var/www/bookstack"
21+
22+ # Get the domain from the arguments (Requested later if not set)
2223DOMAIN=$1
23- if [ -z " $1 " ]
24- then
25- echo " "
26- echo " Enter the domain (or IP if not using a domain) you want to host BookStack on and press [ENTER]."
27- echo " Examples: my-site.com or docs.my-site.com or ${CURRENT_IP} "
28- read -r DOMAIN
29- fi
30-
31- # Ensure a domain was provided otherwise display
32- # an error message and stop the script
33- if [ -z " $DOMAIN " ]
34- then
35- >&2 echo ' ERROR: A domain must be provided to run this script'
24+
25+ # Prevent interactive prompts in applications
26+ export DEBIAN_FRONTEND=noninteractive
27+
28+ # Echo out an error message to the command line and exit the program
29+ # Also logs the message to the log file
30+ function error_out() {
31+ echo " ERROR: $1 " | tee -a " $LOGPATH " 1>&2
3632 exit 1
37- fi
33+ }
34+
35+ # Echo out an information message to both the command line and log file
36+ function info_msg() {
37+ echo " $1 " | tee -a " $LOGPATH "
38+ }
39+
40+ # Run some checks before installation to help prevent messing up an existing
41+ # web-server setup.
42+ function run_pre_install_checks() {
43+ # Check we're running as root and exit if not
44+ if [[ $EUID -gt 0 ]]
45+ then
46+ error_out " This script must be ran with root/sudo privileges"
47+ fi
48+
49+ # Check if Apache appears to be installed and exit if so
50+ if [ -d " /etc/apache2/sites-enabled" ]
51+ then
52+ error_out " This script is intended for a fresh server install, existing apache config found, aborting install"
53+ fi
54+
55+ # Check if MySQL appears to be installed and exit if so
56+ if [ -d " /var/lib/mysql" ]
57+ then
58+ error_out " This script is intended for a fresh server install, existing MySQL data found, aborting install"
59+ fi
60+ }
61+
62+ # Fetch domain to use from first provided parameter,
63+ # Otherwise request the user to input their domain
64+ function run_prompt_for_domain_if_required() {
65+ if [ -z " $DOMAIN " ]
66+ then
67+ info_msg " "
68+ info_msg " Enter the domain (or IP if not using a domain) you want to host BookStack on and press [ENTER]."
69+ info_msg " Examples: my-site.com or docs.my-site.com or ${CURRENT_IP} "
70+ read -r DOMAIN
71+ fi
72+
73+ # Error out if no domain was provided
74+ if [ -z " $DOMAIN " ]
75+ then
76+ error_out " A domain must be provided to run this script"
77+ fi
78+ }
3879
3980# Install core system packages
40- export DEBIAN_FRONTEND=noninteractive
41- apt update
42- apt install -y git unzip apache2 php8.1 curl php8.1-curl php8.1-mbstring php8.1-ldap \
43- php8.1-xml php8.1-zip php8.1-gd php8.1-mysql mysql-server-8.0 libapache2-mod-php8.1
81+ function run_package_installs() {
82+ apt update
83+ apt install -y git unzip apache2 php8.1 curl php8.1-curl php8.1-mbstring php8.1-ldap \
84+ php8.1-xml php8.1-zip php8.1-gd php8.1-mysql mysql-server-8.0 libapache2-mod-php8.1
85+ }
4486
4587# Set up database
46- DB_PASS=" $( head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13) "
47- mysql -u root --execute=" CREATE DATABASE bookstack;"
48- mysql -u root --execute=" CREATE USER 'bookstack'@'localhost' IDENTIFIED WITH mysql_native_password BY '$DB_PASS ';"
49- mysql -u root --execute=" GRANT ALL ON bookstack.* TO 'bookstack'@'localhost';FLUSH PRIVILEGES;"
88+ function run_database_setup() {
89+ mysql -u root --execute=" CREATE DATABASE bookstack;"
90+ mysql -u root --execute=" CREATE USER 'bookstack'@'localhost' IDENTIFIED WITH mysql_native_password BY '$DB_PASS ';"
91+ mysql -u root --execute=" GRANT ALL ON bookstack.* TO 'bookstack'@'localhost';FLUSH PRIVILEGES;"
92+ }
5093
5194# Download BookStack
52- cd /var/www || exit
53- git clone https://github.com/BookStackApp/BookStack.git --branch release --single-branch bookstack
54- BOOKSTACK_DIR=" /var/www/bookstack"
55-
56- # Move into the BookStack install directory
57- cd $BOOKSTACK_DIR || exit
95+ function run_bookstack_download() {
96+ cd /var/www || exit
97+ git clone https://github.com/BookStackApp/BookStack.git --branch release --single-branch bookstack
98+ }
5899
59100# Install composer
60- EXPECTED_CHECKSUM=" $( php -r ' copy("https://composer.github.io/installer.sig", "php://stdout");' ) "
61- php -r " copy('https://getcomposer.org/installer', 'composer-setup.php');"
62- ACTUAL_CHECKSUM=" $( php -r " echo hash_file('sha384', 'composer-setup.php');" ) "
101+ function run_install_composer() {
102+ EXPECTED_CHECKSUM=" $( php -r ' copy("https://composer.github.io/installer.sig", "php://stdout");' ) "
103+ php -r " copy('https://getcomposer.org/installer', 'composer-setup.php');"
104+ ACTUAL_CHECKSUM=" $( php -r " echo hash_file('sha384', 'composer-setup.php');" ) "
63105
64- if [ " $EXPECTED_CHECKSUM " != " $ACTUAL_CHECKSUM " ]
65- then
66- >&2 echo ' ERROR: Invalid composer installer checksum'
67- rm composer-setup.php
68- exit 1
69- fi
106+ if [ " $EXPECTED_CHECKSUM " != " $ACTUAL_CHECKSUM " ]
107+ then
108+ >&2 echo ' ERROR: Invalid composer installer checksum'
109+ rm composer-setup.php
110+ exit 1
111+ fi
70112
71- php composer-setup.php --quiet
72- rm composer-setup.php
113+ php composer-setup.php --quiet
114+ rm composer-setup.php
73115
74- # Move composer to global installation
75- mv composer.phar /usr/local/bin/composer
116+ # Move composer to global installation
117+ mv composer.phar /usr/local/bin/composer
118+ }
76119
77120# Install BookStack composer dependencies
78- export COMPOSER_ALLOW_SUPERUSER=1
79- php /usr/local/bin/composer install --no-dev --no-plugins
121+ function run_install_bookstack_composer_deps() {
122+ cd " $BOOKSTACK_DIR " || exit
123+ export COMPOSER_ALLOW_SUPERUSER=1
124+ php /usr/local/bin/composer install --no-dev --no-plugins
125+ }
80126
81127# Copy and update BookStack environment variables
82- cp .env.example .env
83- sed -i.bak " s@APP_URL=.*\$ @APP_URL=http://$DOMAIN @" .env
84- sed -i.bak ' s/DB_DATABASE=.*$/DB_DATABASE=bookstack/' .env
85- sed -i.bak ' s/DB_USERNAME=.*$/DB_USERNAME=bookstack/' .env
86- sed -i.bak " s/DB_PASSWORD=.*\$ /DB_PASSWORD=$DB_PASS /" .env
87-
88- # Generate the application key
89- php artisan key:generate --no-interaction --force
90- # Migrate the databases
91- php artisan migrate --no-interaction --force
128+ function run_update_bookstack_env() {
129+ cd " $BOOKSTACK_DIR " || exit
130+ cp .env.example .env
131+ sed -i.bak " s@APP_URL=.*\$ @APP_URL=http://$DOMAIN @" .env
132+ sed -i.bak ' s/DB_DATABASE=.*$/DB_DATABASE=bookstack/' .env
133+ sed -i.bak ' s/DB_USERNAME=.*$/DB_USERNAME=bookstack/' .env
134+ sed -i.bak " s/DB_PASSWORD=.*\$ /DB_PASSWORD=$DB_PASS /" .env
135+ # Generate the application key
136+ php artisan key:generate --no-interaction --force
137+ }
138+
139+ # Run the BookStack database migrations for the first time
140+ function run_bookstack_database_migrations() {
141+ cd " $BOOKSTACK_DIR " || exit
142+ php artisan migrate --no-interaction --force
143+ }
92144
93145# Set file and folder permissions
94146# Sets current user as owner user and www-data as owner group then
95147# provides group write access only to required directories.
96148# Hides the `.env` file so it's not visible to other users on the system.
97- chown -R " $SCRIPT_USER " :www-data ./
98- chmod -R 755 ./
99- chmod -R 775 bootstrap/cache public/uploads storage
100- chmod 740 .env
101-
102- # Tell git to ignore permission changes
103- git config core.fileMode false
104-
105- # Enable required apache modules
106- a2enmod rewrite
107- a2enmod php8.1
108-
109- # Set-up the required BookStack apache config
110- cat > /etc/apache2/sites-available/bookstack.conf << EOL
149+ function run_set_application_file_permissions() {
150+ cd " $BOOKSTACK_DIR " || exit
151+ chown -R " $SCRIPT_USER " :www-data ./
152+ chmod -R 755 ./
153+ chmod -R 775 bootstrap/cache public/uploads storage
154+ chmod 740 .env
155+
156+ # Tell git to ignore permission changes
157+ git config core.fileMode false
158+ }
159+
160+ # Setup apache with the needed modules and config
161+ function run_configure_apache() {
162+ # Enable required apache modules
163+ a2enmod rewrite
164+ a2enmod php8.1
165+
166+ # Set-up the required BookStack apache config
167+ cat > /etc/apache2/sites-available/bookstack.conf << EOL
111168<VirtualHost *:80>
112- ServerName ${DOMAIN}
169+ ServerName ${DOMAIN}
113170
114- ServerAdmin webmaster@localhost
115- DocumentRoot /var/www/bookstack/public/
171+ ServerAdmin webmaster@localhost
172+ DocumentRoot /var/www/bookstack/public/
116173
117174 <Directory /var/www/bookstack/public/>
118175 Options -Indexes +FollowSymLinks
@@ -141,22 +198,62 @@ cat >/etc/apache2/sites-available/bookstack.conf <<EOL
141198 </IfModule>
142199 </Directory>
143200
144- ErrorLog \$ {APACHE_LOG_DIR}/error.log
145- CustomLog \$ {APACHE_LOG_DIR}/access.log combined
201+ ErrorLog \$ {APACHE_LOG_DIR}/error.log
202+ CustomLog \$ {APACHE_LOG_DIR}/access.log combined
146203
147204</VirtualHost>
148205EOL
149206
150- # Disable the default apache site and enable BookStack
151- a2dissite 000-default.conf
152- a2ensite bookstack.conf
207+ # Disable the default apache site and enable BookStack
208+ a2dissite 000-default.conf
209+ a2ensite bookstack.conf
153210
154- # Restart apache to load new config
155- systemctl restart apache2
211+ # Restart apache to load new config
212+ systemctl restart apache2
213+ }
156214
157- echo " "
158- echo " Setup Finished, Your BookStack instance should now be installed."
159- echo " You can login with the email 'admin@admin.com' and password of 'password'"
160- echo " MySQL was installed without a root password, It is recommended that you set a root MySQL password."
161- echo " "
162- echo " You can access your BookStack instance at: http://$CURRENT_IP / or http://$DOMAIN /"
215+ info_msg " This script logs full output to $LOGPATH which may help upon issues."
216+ sleep 1
217+
218+ run_pre_install_checks
219+ run_prompt_for_domain_if_required
220+ info_msg " "
221+ info_msg " Installing using the domain/IP \" $DOMAIN \" "
222+ info_msg " "
223+ sleep 1
224+
225+ info_msg " [1/9] Installing required system packages... (This may take several minutes)"
226+ run_package_installs >> " $LOGPATH " 2>&1
227+
228+ info_msg " [2/9] Preparing MySQL database..."
229+ run_database_setup >> " $LOGPATH " 2>&1
230+
231+ info_msg " [3/9] Downloading BookStack to ${BOOKSTACK_DIR} ..."
232+ run_bookstack_download >> " $LOGPATH " 2>&1
233+
234+ info_msg " [4/9] Installing Composer (PHP dependency manager)..."
235+ run_install_composer >> " $LOGPATH " 2>&1
236+
237+ info_msg " [5/9] Installing PHP dependencies using composer..."
238+ run_install_bookstack_composer_deps >> " $LOGPATH " 2>&1
239+
240+ info_msg " [6/9] Creating and populating BookStack .env file..."
241+ run_update_bookstack_env >> " $LOGPATH " 2>&1
242+
243+ info_msg " [7/9] Running initial BookStack database migrations..."
244+ run_bookstack_database_migrations >> " $LOGPATH " 2>&1
245+
246+ info_msg " [8/9] Setting BookStack file & folder permissions..."
247+ run_set_application_file_permissions >> " $LOGPATH " 2>&1
248+
249+ info_msg " [9/9] Configuring apache server..."
250+ run_configure_apache >> " $LOGPATH " 2>&1
251+
252+ info_msg " ----------------------------------------------------------------"
253+ info_msg " Setup finished, your BookStack instance should now be installed!"
254+ info_msg " Default login email: admin@admin.com"
255+ info_msg " Default login password: password"
256+ info_msg " Access URL: http://$CURRENT_IP / or http://$DOMAIN /"
257+ info_msg " BookStack Install Directory: $BOOKSTACK_DIR "
258+ info_msg " Install Script Log: $LOGPATH "
259+ info_msg " ---------------------------------------------------------------"
0 commit comments