#!/bin/bash # ____ _ _ _ _ _ _ # | _ \(_) | | (_) | | | | # | |_) |_| |__ | |_ ___ | |_ ___ ___| |__ __ _ # | _ <| | '_ \| | |/ _ \| __/ _ \/ __| '_ \ / _` | # | |_) | | |_) | | | (_) | || __/ (__| | | | (_| | # |____/|_|_.__/|_|_|\___/ \__\___|\___|_| |_|\__,_| # # Digital books need libraries too # # This install script is intended for use with Debian based # distributions. More specifically, Debian Buster, which is # currently the latest distribution release from the Debian # project. # # License # ======= # # Copyright (C) 2019 Bibliotecha Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/. # # Thanks # ===== # # This script is based on the good work of the Freedombone project: # https://code.freedombone.net/bashrc/freedombone/src/stretch/src/freedombone APT_CMD="apt -q" APT_INSTALL_CMD="$APT_CMD install -y --no-install-recommends" CALIBRE_DATABASE_PATH="/opt/calibre-database" CAPTIVE_PORTAL_PATH="/var/www/bibliotecha" CALIBRE_WEB_PATH="/var/www/calibre-web" LIGHTTPD_CONFIG_PATH="/etc/lighttpd/bibliotecha" function ensure_root_account { echo "Checking user account ..." if ! id | grep -q root; then echo "" echo "This script must be run as root" echo "You can switch to the root user account with:" echo "$ sudo -i" echo "" exit 0 fi } function show_bibliotecha_banner { echo "" echo " ____ _ _ _ _ _ _ " echo " | _ \(_) | | (_) | | | |" echo " | |_) |_| |__ | |_ ___ | |_ ___ ___| |__ __ _ " echo " | _ <| | '_ \| | |/ _ \| __/ _ \/ __| '_ \ / _' |" echo " | |_) | | |_) | | | (_) | || __/ (__| | | | (_| |" echo " |____/|_|_.__/|_|_|\___/ \__\___|\___|_| |_|\__,_|" echo "" echo " Digital books need libraries too" echo "" } function show_introduction_text { echo "" echo "Welcome to the Bibliotecha automatic installation script" echo "" echo "This script will attempt to setup the following infrastructure:" echo "" echo "* A Python 3 environment" echo "* A Wifi hotspot with DNS and DHCP services enabled" echo "* A web server" echo "* A Calibre library" echo "* A Calibre-web service" echo "" echo "Once the script is finished, please see post-install steps" echo "that are documented and available from the Bibliotecha manual:" echo "" echo " https://manual.bibliotecha.info/#post-installation" echo "" echo "If anything goes wrong, please see the troubleshooting guide" echo "" echo " https://manual.bibliotecha.info/#troubleshooting" echo "" echo "Waiting a few seconds before moving on ..." sleep 10 } function ensure_buster_based_distribution { echo "Checking distribution ..." local installing_on_buster_based=1 if [ ! -f /etc/apt/sources.list ]; then installing_on_buster_based= else if ! grep -q 'buster' /etc/apt/sources.list; then installing_on_buster_based= fi if ! grep -q 'debian' /etc/apt/sources.list; then if ! grep -q 'raspbian' /etc/apt/sources.list; then installing_on_buster_based= fi fi fi if [ ! $installing_on_buster_based ]; then echo "You should only run this on a Debian Buster based system" exit 1 fi } function run_apt_update { echo "Running a package listing update ..." $APT_CMD update } function install_networking_packages { echo "Installing networking packages ..." $APT_INSTALL_CMD \ dhcpcd \ dnsmasq \ dnsutils \ hostapd \ wireless-tools } function stop_networking_services { echo "Stopping the networking services ..." local services="dnsmasq hostapd" # shellcheck disable=SC2086 systemctl stop ${services} } function disable_avahi_service { echo "Disable the avahi service ..." systemctl stop avahi-daemon systemctl disable avahi-daemon } function ensure_predictable_network_interfaces { echo "Ensuring predictable networking interfaces ..." # shellcheck disable=SC2010 # shellcheck disable=SC2155 local ethernet_interface=$(ls /sys/class/net/ | grep en) if [[ -z "${ethernet_interface}" ]]; then echo "" echo "Could not determine the ethernet interface" echo "Please ensure you've configure 'predictable network interfaces'" echo "Please see https://manual.bibliotecha.info/#pre-installation for more" echo "" exit 1 fi # shellcheck disable=SC2010 # shellcheck disable=SC2155 local wireless_interface=$(ls /sys/class/net/ | grep wl) if [[ -z "${wireless_interface}" ]]; then echo "" echo "Could not determine the wireless interface" echo "Please ensure you've configure 'predictable network interfaces'" echo "Please see https://manual.bibliotecha.info/#pre-installation for more" echo "" exit 1 fi } function configure_network_interfaces { echo "Configuring networking interfaces ..." # shellcheck disable=SC2010 # shellcheck disable=SC2155 local ethernet_interface=$(ls /sys/class/net/ | grep en) local ethernet_filename="/etc/network/interfaces.d/${ethernet_interface}" { echo "auto ${ethernet_interface}"; echo "allow-hotplug ${ethernet_interface}"; echo "iface ${ethernet_interface} inet dhcp"; } > "${ethernet_filename}" # shellcheck disable=SC2010 # shellcheck disable=SC2155 local wireless_interface=$(ls /sys/class/net/ | grep wl) local wireless_filename="/etc/network/interfaces.d/${wireless_interface}" { echo "auto ${wireless_interface}"; echo "iface ${wireless_interface} inet static"; echo " address 10.0.0.1"; echo " netmask 255.255.255.0"; } > "${wireless_filename}" } function configure_dnsmasq { echo "Configuring dnsmasq ..." # shellcheck disable=SC2010 # shellcheck disable=SC2155 local wireless_interface=$(ls /sys/class/net/ | grep wl) local wireless_filename="/etc/dnsmasq.d/${wireless_interface}.conf" { echo "bogus-priv" echo "server=/library/10.0.0.1" echo "local=/library/" echo "address=/#/10.0.0.1" echo "interface=${wireless_interface}" echo "domain=library" echo "dhcp-range=10.0.0.50,10.0.0.200,255.255.255.0,12h" echo "dhcp-option=3,10.0.0.1" echo "dhcp-option=6,10.0.0.1" echo "dhcp-authoritative"; } > "${wireless_filename}" } function configure_hostapd { echo "Configuring hostapd ..." # shellcheck disable=SC2010 # shellcheck disable=SC2155 local wireless_interface=$(ls /sys/class/net/ | grep wl) local hostapd_filename="/etc/hostapd/hostapd.conf" { echo "interface=${wireless_interface}" echo "ssid=Bibliotecha" echo "hw_mode=g" echo "channel=11" echo "auth_algs=1"; } > "${hostapd_filename}" sed -i \ 's/#DAEMON_CONF=""/DAEMON_CONF="\/etc\/hostapd\/hostapd.conf"/g' \ /etc/default/hostapd } function configure_etc_hosts { echo "Configuring /etc/hosts entry ..." if ! grep -q "bibliotecha.library" /etc/hosts; then echo '10.0.0.1 bibliotecha.library' >> /etc/hosts fi } function enable_networking_services { echo "Enabling network services ..." local services="dnsmasq hostapd" systemctl unmask hostapd # shellcheck disable=SC2086 systemctl enable ${services} } function install_webserver { echo "Installing lighttpd ..." $APT_INSTALL_CMD lighttpd } function configure_webserver { echo "Configuring bibliotecha under lighttpd ..." if ! grep -q mod_proxy /etc/lighttpd/lighttpd.conf; then echo "" echo 'server.modules += ("mod_proxy",)' >> /etc/lighttpd/lighttpd.conf fi if ! grep -q bibliotecha /etc/lighttpd/lighttpd.conf; then echo "" echo 'include "bibliotecha/bibliotecha.conf"' >> /etc/lighttpd/lighttpd.conf fi sed -i \ 's/server.document-root.*/server.document-root = "\/var\/www"/g' \ /etc/lighttpd/lighttpd.conf mkdir -p "$LIGHTTPD_CONFIG_PATH" { echo 'server.error-handler-404 = "/bibliotecha/index.html"' echo "" # shellcheck disable=SC2016 echo '$HTTP["host"] == "bibliotecha.library" {' echo ' proxy.server = ("" => (("host" => "127.0.0.1", "port" => "8083")))' echo '}'; } > "$LIGHTTPD_CONFIG_PATH/bibliotecha.conf" } function configure_captive_portal { echo "Configuring the captive portal page ..." $APT_INSTALL_CMD wget captive_portal_url="https://git.vvvvvvaria.org/varia/bibliotecha-captive-portal/raw/branch/master/index.html" mkdir -p "$CAPTIVE_PORTAL_PATH" wget "$captive_portal_url" -O "$CAPTIVE_PORTAL_PATH/index.html" chown -R www-data: "$CAPTIVE_PORTAL_PATH" } function install_calibre { echo "Install Calibre ..." $APT_INSTALL_CMD calibre } function configure_calibre_database { echo "Configuring the Calibre database ..." mkdir -p "$CALIBRE_DATABASE_PATH" # A dirty hack to initialise a new calibre database /usr/bin/calibredb restore_database --really-do-it --with-library "$CALIBRE_DATABASE_PATH" } function install_calibreweb { echo "Installing Calibre-web ..." $APT_INSTALL_CMD git python3 python3-pip python3-dev python3-venv calibre_web_url="https://github.com/janeczku/calibre-web" if [ ! -d "$CALIBRE_WEB_PATH" ]; then git clone "$calibre_web_url" "$CALIBRE_WEB_PATH" fi if [ ! -d "$CALIBRE_WEB_PATH/.venv" ]; then # shellcheck disable=SC1091 cd "$CALIBRE_WEB_PATH" && \ python3 -m venv .venv && \ .venv/bin/pip install -r requirements.txt fi chown -R www-data: "$CALIBRE_WEB_PATH" } function configure_calibreweb { echo "Configuring Calibre-web ..." { echo "Description=Calibre-Web" echo "" echo "[Service]" echo "Type=simple" echo "User=root" echo "ExecStart=$CALIBRE_WEB_PATH/.venv/bin/python $CALIBRE_WEB_PATH/cps.py" echo "WorkingDirectory=$CALIBRE_WEB_PATH" echo "" echo "[Install]" echo "WantedBy=multi-user.target"; } > /etc/systemd/system/cps.service systemctl enable cps.service } function show_post_install_banner { echo "" echo "Installation complete!" echo "" } function install_new_motd { echo "Installing the new MOTD ..." { echo "" echo "" echo " ____ _ _ _ _ _ _ " echo " | _ \(_) | | (_) | | | |" echo " | |_) |_| |__ | |_ ___ | |_ ___ ___| |__ __ _ " echo " | _ <| | '_ \| | |/ _ \| __/ _ \/ __| '_ \ / _' |" echo " | |_) | | |_) | | | (_) | || __/ (__| | | | (_| |" echo " |____/|_|_.__/|_|_|\___/ \__\___|\___|_| |_|\__,_|" echo "" echo " Digital books need libraries too" echo "" echo ""; } > /etc/motd } function reboot_system { echo "Rebooting system ..." reboot } function run_installation { ensure_root_account ensure_buster_based_distribution ensure_predictable_network_interfaces show_bibliotecha_banner show_introduction_text run_apt_update install_networking_packages stop_networking_services disable_avahi_service configure_network_interfaces configure_dnsmasq configure_hostapd configure_etc_hosts enable_networking_services install_webserver configure_webserver configure_captive_portal install_calibre configure_calibre_database install_calibreweb configure_calibreweb show_post_install_banner install_new_motd reboot_system } run_installation exit 0