#!/usr/bin/env bash set -eu red='\e[0;31m' yellow='\e[1;33m' cyan='\e[0;36m' reset='\e[0m' info() { printf "${cyan}info: $*${reset}\n" } warning() { printf >&2 "${yellow}warning: $*${reset}\n" } error() { printf >&2 "${red}error: $*${reset}\n" exit 1 } section() { text="$*" printf -v bar '═%.0s' {1..78} printf -v fill ' %.0s' {1..76} printf "$cyan" printf '╔%s╗\n' "$bar" printf '║ %s ║\n' "${text}${fill:${#text}}" printf '╚%s╝\n' "$bar" printf "$reset" } banner() { printf "${cyan}" cat << EOF ██╗ ██╗██████╗ ██████╗ ███████╗████████╗██╗███╗ ███╗███████╗ ██║ ██║██╔══██╗██╔══██╗██╔════╝╚══██╔══╝██║████╗ ████║██╔════╝ ██║ ██║██████╔╝██████╔╝█████╗ ██║ ██║██╔████╔██║█████╗ ██║ ██║██╔══██╗██╔══██╗██╔══╝ ██║ ██║██║╚██╔╝██║██╔══╝ ███████╗██║██████╔╝██║ ██║███████╗ ██║ ██║██║ ╚═╝ ██║███████╗ ╚══════╝╚═╝╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ EOF printf "${reset}" } SCRIPT_DIR="$( cd "$( dirname "$0")" && pwd)" version() { if [ ! -f "$SCRIPT_DIR/VERSION" ]; then make VERSION > /dev/null fi echo "LibreTime Version $(cat "$SCRIPT_DIR/VERSION")" exit 0 } usage() { cat >&2 << EOF Usage: $0 [option]... [public_url] Install LibreTime on the system. Options: --user USER, -u USER User used to run LibreTime. --listen-port PORT, -p PORT Listen port for LibreTime. --in-place, -i Install LibreTime in place. --no-setup-icecast Do not setup Icecast. --no-setup-postgresql Do not setup Postgresql. --no-setup-rabbitmq Do not setup RabbitMQ. --update-nginx Update nginx files during upgrades. Environment variables: Advanced options can be changed using environment variables (flags will take precedence over environment variables). EOF while read line; do if echo "$line" | grep -q '^#'; then line="${cyan}${line}${reset}" fi # Pretty print variable definition line=$(echo "$line" | sed -E 's/=\$\{[A-Z_]+\:-(.*)\}/=\1/g') printf " ${line}\n" done <<< "$(grep -A1 '^# >' "$0")" } # Load .env file if exists [[ -f "$SCRIPT_DIR/.env" ]] && source "$SCRIPT_DIR/.env" # Configuration # > User used to run LibreTime. LIBRETIME_USER=${LIBRETIME_USER:-"libretime"} # > Listen port for LibreTime. LIBRETIME_LISTEN_PORT=${LIBRETIME_LISTEN_PORT:-"80"} # > Public URL for LibreTime. LIBRETIME_PUBLIC_URL=${LIBRETIME_PUBLIC_URL:-} # > Timezone for LibreTime. LIBRETIME_TIMEZONE=${LIBRETIME_TIMEZONE:-} # > Install LibreTime in editable mode. # > Will keep working files in the project directory. LIBRETIME_INSTALL_IN_PLACE=${LIBRETIME_INSTALL_IN_PLACE:-false} # > Install a default icecast configuration. LIBRETIME_SETUP_ICECAST=${LIBRETIME_SETUP_ICECAST:-true} # > Create a default postgresql user with a random password. LIBRETIME_SETUP_POSTGRESQL=${LIBRETIME_SETUP_POSTGRESQL:-true} # > Create a default rabbitmq user with a random password. LIBRETIME_SETUP_RABBITMQ=${LIBRETIME_SETUP_RABBITMQ:-true} # > Update nginx files during upgrades. LIBRETIME_UPDATE_NGINX=${LIBRETIME_UPDATE_NGINX:-false} # > Comma separated list of sections to exclude from packages list. LIBRETIME_PACKAGES_EXCLUDES=${LIBRETIME_PACKAGES_EXCLUDES:-} while [[ $# -gt 0 ]]; do case "$1" in --user | -u) LIBRETIME_USER=$2 shift 2 ;; --listen-port | -p) LIBRETIME_LISTEN_PORT=$2 shift 2 ;; --in-place | -i) LIBRETIME_INSTALL_IN_PLACE=true shift 1 ;; --update-nginx) LIBRETIME_UPDATE_NGINX=true shift 1 ;; --no-setup-icecast) LIBRETIME_SETUP_ICECAST=false shift 1 ;; --no-setup-postgresql) LIBRETIME_SETUP_POSTGRESQL=false shift 1 ;; --no-setup-rabbitmq) LIBRETIME_SETUP_RABBITMQ=false shift 1 ;; --packages-excludes) LIBRETIME_PACKAGES_EXCLUDES=$2 shift 2 ;; --help | -h) usage exit 0 ;; --version) version exit 0 ;; -*) usage exit 1 ;; *) LIBRETIME_PUBLIC_URL=$1 shift 1 ;; esac done # Variables PYTHON="python3" PIP="$PYTHON -m pip" DEFAULT_WEB_USER="www-data" # Paths CONFIG_DIR="/etc/libretime" CONFIG_FILEPATH="$CONFIG_DIR/config.yml" CONFIG_TMP_FILEPATH="$CONFIG_DIR/config.yml.tmp" CONFIG_EXAMPLE_FILEPATH="$SCRIPT_DIR/installer/config.yml" WORKING_DIR="/var/lib/libretime" LOG_DIR="/var/log/libretime" STORAGE_DIR="/srv/libretime" LEGACY_WEB_ROOT="/usr/share/libretime/legacy" SERVICE_DIR="/usr/lib/systemd/system" # command_exist command_exist() { command -v "$1" > /dev/null || error "$1 command not found!" } # generate_random_password generate_random_password() { tr -cd '[:alnum:]' < /dev/urandom | head -c32 } # mkdir_and_chown mkdir_and_chown() { mkdir -p "$2" chown -R "$1:$1" "$2" } # backup_if_exists backup_if_exists() { if [[ -f "$1" ]]; then backup="$1.$(date --iso-8601=seconds).bak" warning "found existing $1, creating a backup to $backup" mv "$1" "$backup" fi } # diff_if_exists diff_if_exists() { src="$1" dest="$2" shift 2 if [[ -f "$dest" ]]; then src_explicit_filename="$(dirname "$src")/$(basename "$dest").new" cp "$src" "$src_explicit_filename" # print what the existing file $dest would become if $src is copied diff -u --color=always --ignore-trailing-space "$dest" "$src_explicit_filename" || : rm -f "$src_explicit_filename" fi } # cp_if_different cp_if_different() { if [[ -f "$2" ]] && diff -q "$1" "$2" > /dev/null; then return fi diff_if_exists "$1" "$2" backup_if_exists "$2" cp "$1" "$2" } # template_file template_file() { action="$1" src="$2" dest="$3" shift 3 tmp_file=$(mktemp) "$@" "$src" > "$tmp_file" $action "$tmp_file" "$dest" rm "$tmp_file" } # set_config set_config() { value="${1}" && shift # Build sed query query="/^${1}:/\n" while [[ $# -gt 1 ]]; do shift query+="/${1}:/\n" done query+="s|\(${1}:\).*|\1 ${value}|\n" query+="wq" echo -e "$query" | ed --quiet "$CONFIG_TMP_FILEPATH" > /dev/null } # install_python_app install_python_app() { info "installing python app from $1" $PIP install \ --upgrade \ --upgrade-strategy only-if-needed \ "$1" } # install_service # # has to be relative to the project root install_service() { command_exist systemctl local service_name="$1" local service_src="$2" local service_dest="$SERVICE_DIR/$service_name" info "deploying $service_name service" [[ -f "$service_src" ]] || error "service '$service_name' src path '$service_src' does not exists!" if [[ ! -d "$SERVICE_DIR" ]]; then mkdir -p "$SERVICE_DIR" fi template_file cp_if_different "$service_src" "$service_dest" \ sed \ -e "s|^User=.*|User=${LIBRETIME_USER}|" \ -e "s|^Group=.*|Group=${LIBRETIME_USER}|" \ -e "s|@@DEFAULT_WEB_USER@@|${DEFAULT_WEB_USER}|g" \ -e "s|@@CONFIG_DIR@@|${CONFIG_DIR}|g" \ -e "s|@@CONFIG_FILEPATH@@|${CONFIG_FILEPATH}|g" \ -e "s|@@LOG_DIR@@|${LOG_DIR}|g" \ -e "s|@@WORKING_DIR@@|${WORKING_DIR}|g" chmod 0644 "$service_dest" chown root:root "$service_dest" systemctl enable "$service_name" } # service_restart_if_active service_restart_if_active() { if systemctl is-active "$1" > /dev/null; then info "restarting $1 service" systemctl restart "$1" fi } is_ubuntu=false is_debian=false distro="unknown" check_distribution() { local ID="unknown" local VERSION_ID="unknown" if [[ -f "/etc/os-release" ]]; then source "/etc/os-release" fi # shellcheck disable=SC2034 case "$ID-$VERSION_ID" in ubuntu-20.04) is_ubuntu=true && distro="focal" ;; debian-11) is_debian=true && distro="bullseye" ;; *) error "could not determine supported distribution '$ID-$VERSION_ID' Please check the documentation to find the supported distributions. Support for installing LibreTime on Buster has dropped since 3.1.0. Support for installing LibreTime on Bionic has dropped since 3.1.0. Support for installing LibreTime on Xenial has dropped since 3.0.0-alpha.10. Support for installing LibreTime on Stretch has dropped since 3.0.0-alpha.10. Support for installing LibreTime on Jessie has dropped since 3.0.0-alpha.8." ;; esac } # list_packages list_packages() { extra_args=() for section in $LIBRETIME_PACKAGES_EXCLUDES; do extra_args+=("--exclude=$section") done "$SCRIPT_DIR/tools/packages.py" \ "$distro" \ "$1" \ --format=line \ "${extra_args[@]}" } prepare_packages_install() { if $is_ubuntu || $is_debian; then DEBIAN_FRONTEND=noninteractive apt-get -q update fi if $is_ubuntu; then install_packages software-properties-common add-apt-repository -y ppa:libretime/libretime DEBIAN_FRONTEND=noninteractive apt-get -q update fi } # install_packages install_packages() { if $is_ubuntu || $is_debian; then # shellcheck disable=SC2086 DEBIAN_FRONTEND=noninteractive apt-get -qq -y install "$@" else warning "installing dependencies is not supported for this distribution" fi } # get_system_timezone get_system_timezone() { if ! command -v timedatectl > /dev/null; then return fi timezone="$(timedatectl show --property=Timezone --value)" if [[ -n "$timezone" && ! "$timezone" =~ UTC$ ]]; then echo "$timezone" fi } load_config_defaults() { if [[ -z "$LIBRETIME_TIMEZONE" ]]; then LIBRETIME_TIMEZONE="$(get_system_timezone)" fi } # Prepare ######################################################################################## # Make sure only root can run our script (($( id -u) == 0)) || error "this script must be run as root!" banner check_distribution load_config_defaults is_first_install=true if [[ -f "$CONFIG_FILEPATH" ]]; then is_first_install=false warning "a configuration file already exists at $CONFIG_FILEPATH, only running upgrade steps!" fi section "Prepare" prepare_packages_install install_packages sudo git make ed make VERSION info "creating project user" if ! id "$LIBRETIME_USER" &> /dev/null; then useradd --no-create-home --home-dir "$WORKING_DIR" "$LIBRETIME_USER" fi info "creating project directories" mkdir -p "$CONFIG_DIR" mkdir_and_chown "$LIBRETIME_USER" "$WORKING_DIR" mkdir_and_chown "$LIBRETIME_USER" "$LOG_DIR" if $is_first_install; then [[ -f "$CONFIG_TMP_FILEPATH" ]] || cp "$CONFIG_EXAMPLE_FILEPATH" "$CONFIG_TMP_FILEPATH" chown "$LIBRETIME_USER:$LIBRETIME_USER" "$CONFIG_TMP_FILEPATH" chmod 640 "$CONFIG_TMP_FILEPATH" if [[ -n "$LIBRETIME_PUBLIC_URL" ]]; then set_config "$LIBRETIME_PUBLIC_URL" general public_url fi set_config "$(generate_random_password)" general api_key set_config "$(generate_random_password)" general secret_key if [[ -n "$LIBRETIME_TIMEZONE" ]]; then set_config "$LIBRETIME_TIMEZONE" general timezone fi mkdir_and_chown "$LIBRETIME_USER" "$STORAGE_DIR" set_config "$STORAGE_DIR" storage path fi # PostgreSQL ######################################################################################## # > LibreTime PostgreSQL user LIBRETIME_POSTGRESQL_USER=${LIBRETIME_POSTGRESQL_USER:-"libretime"} # > LibreTime PostgreSQL user password LIBRETIME_POSTGRESQL_PASSWORD=${LIBRETIME_POSTGRESQL_PASSWORD:-$(generate_random_password)} # > LibreTime PostgreSQL database LIBRETIME_POSTGRESQL_DATABASE=${LIBRETIME_POSTGRESQL_DATABASE:-"libretime"} if $LIBRETIME_SETUP_POSTGRESQL; then section "PostgreSQL" install_packages postgresql postgresql-client if $is_first_install; then if ! sudo -iH -u postgres psql --csv --tuples-only --command='\du' | grep -qw "^$LIBRETIME_POSTGRESQL_USER"; then info "creating PostgreSQL user '$LIBRETIME_POSTGRESQL_USER'" sudo -iH -u postgres createuser "$LIBRETIME_POSTGRESQL_USER" sudo -iH -u postgres psql -c "ALTER ROLE $LIBRETIME_POSTGRESQL_USER WITH PASSWORD '$LIBRETIME_POSTGRESQL_PASSWORD';" set_config "$LIBRETIME_POSTGRESQL_USER" database user set_config "$LIBRETIME_POSTGRESQL_PASSWORD" database password else warning "PostgreSQL user '$LIBRETIME_POSTGRESQL_USER' already exists!" fi if ! sudo -iH -u postgres psql --csv --tuples-only --list | grep -qw "^$LIBRETIME_POSTGRESQL_DATABASE"; then info "creating PostgreSQL database '$LIBRETIME_POSTGRESQL_DATABASE' with owner '$LIBRETIME_POSTGRESQL_USER'" sudo -iH -u postgres createdb --template=template0 --encoding=UTF-8 --owner="$LIBRETIME_POSTGRESQL_USER" "$LIBRETIME_POSTGRESQL_DATABASE" set_config "$LIBRETIME_POSTGRESQL_DATABASE" database name else warning "PostgreSQL database '$LIBRETIME_POSTGRESQL_DATABASE' already exists!" fi fi fi # RabbitMQ ######################################################################################## # > LibreTime RabbitMQ user LIBRETIME_RABBITMQ_USER=${LIBRETIME_RABBITMQ_USER:-"libretime"} # > LibreTime RabbitMQ user password LIBRETIME_RABBITMQ_PASSWORD=${LIBRETIME_RABBITMQ_PASSWORD:-$(generate_random_password)} # > LibreTime RabbitMQ vhost LIBRETIME_RABBITMQ_VHOST=${LIBRETIME_RABBITMQ_VHOST:-"/libretime"} if $LIBRETIME_SETUP_RABBITMQ; then section "RabbitMQ" install_packages rabbitmq-server if $is_first_install; then if ! rabbitmqctl --quiet list_users | grep -qw "^$LIBRETIME_RABBITMQ_USER"; then info "creating RabbitMQ user '$LIBRETIME_RABBITMQ_USER'" rabbitmqctl add_user "$LIBRETIME_RABBITMQ_USER" "$LIBRETIME_RABBITMQ_PASSWORD" set_config "$LIBRETIME_RABBITMQ_USER" rabbitmq user set_config "$LIBRETIME_RABBITMQ_PASSWORD" rabbitmq password else warning "RabbitMQ user '$LIBRETIME_RABBITMQ_USER' already exists!" fi if ! rabbitmqctl --quiet list_vhosts | grep -qw "^$LIBRETIME_RABBITMQ_VHOST"; then info "creating RabbitMQ vhost '$LIBRETIME_RABBITMQ_VHOST' with owner '$LIBRETIME_RABBITMQ_USER'" rabbitmqctl add_vhost "$LIBRETIME_RABBITMQ_VHOST" rabbitmqctl set_permissions -p "$LIBRETIME_RABBITMQ_VHOST" "$LIBRETIME_RABBITMQ_USER" '.*' '.*' '.*' set_config "$LIBRETIME_RABBITMQ_VHOST" rabbitmq vhost else warning "RabbitMQ vhost '$LIBRETIME_RABBITMQ_VHOST' already exists!" fi fi fi # Icecast ######################################################################################## # > LibreTime Icecast admin password LIBRETIME_ICECAST_ADMIN_PASSWORD=${LIBRETIME_ICECAST_ADMIN_PASSWORD:-$(generate_random_password)} # > LibreTime Icecast source password LIBRETIME_ICECAST_SOURCE_PASSWORD=${LIBRETIME_ICECAST_SOURCE_PASSWORD:-$(generate_random_password)} # > LibreTime Icecast relay password LIBRETIME_ICECAST_RELAY_PASSWORD=${LIBRETIME_ICECAST_RELAY_PASSWORD:-$(generate_random_password)} if $LIBRETIME_SETUP_ICECAST; then section "Icecast" install_packages icecast2 systemctl enable icecast2 systemctl start icecast2 if $is_first_install; then icecast_config_filepath="/etc/icecast2/icecast.xml" sed --in-place \ -e "s|[^<]*|${LIBRETIME_ICECAST_ADMIN_PASSWORD}|" \ -e "s|[^<]*|${LIBRETIME_ICECAST_SOURCE_PASSWORD}|" \ -e "s|[^<]*|${LIBRETIME_ICECAST_RELAY_PASSWORD}|" \ "$icecast_config_filepath" service_restart_if_active icecast2 set_config "$LIBRETIME_ICECAST_ADMIN_PASSWORD" stream outputs .default_icecast_output admin_password set_config "$LIBRETIME_ICECAST_SOURCE_PASSWORD" stream outputs .default_icecast_output source_password fi fi # Prepare python ######################################################################################## section "Python3" install_packages python3 python3-pip python3-wheel info "upgrading python3 tools" $PIP install --upgrade setuptools~=67.3 # Install Shared and API client ######################################################################################## section "Shared" # shellcheck disable=SC2046 install_packages $(list_packages "$SCRIPT_DIR/shared") install_python_app "$SCRIPT_DIR/shared" section "API client" install_python_app "$SCRIPT_DIR/api-client" # Install API ######################################################################################## section "API" # shellcheck disable=SC2046 install_packages $(list_packages "$SCRIPT_DIR/api") install_python_app "$SCRIPT_DIR/api[prod]" install_service "libretime-api.service" "$SCRIPT_DIR/api/install/systemd/libretime-api.service" install_service "libretime-api.socket" "$SCRIPT_DIR/api/install/systemd/libretime-api.socket" # Install Playout ######################################################################################## section "Playout" # shellcheck disable=SC2046 install_packages $(list_packages "$SCRIPT_DIR/playout") install_python_app "$SCRIPT_DIR/playout" info "creating libretime-playout working directory" mkdir_and_chown "$LIBRETIME_USER" "$WORKING_DIR/playout" install_service "libretime-liquidsoap.service" "$SCRIPT_DIR/playout/install/systemd/libretime-liquidsoap.service" install_service "libretime-playout.service" "$SCRIPT_DIR/playout/install/systemd/libretime-playout.service" info "deploying libretime-liquidsoap logrotate config" template_file cp_if_different \ "$SCRIPT_DIR/playout/install/logrotate/libretime-liquidsoap.conf" \ "/etc/logrotate.d/libretime-liquidsoap" \ sed \ -e "s|@@LOG_DIR@@|${LOG_DIR}|g" \ -e "s|@@USER@@|${LIBRETIME_USER}|g" # Install Analyzer ######################################################################################## section "Analyzer" # shellcheck disable=SC2046 install_packages $(list_packages "$SCRIPT_DIR/analyzer") install_python_app "$SCRIPT_DIR/analyzer" info "creating libretime-analyzer working directory" mkdir_and_chown "$LIBRETIME_USER" "$WORKING_DIR/analyzer" install_service "libretime-analyzer.service" "$SCRIPT_DIR/analyzer/install/systemd/libretime-analyzer.service" # Install Worker ######################################################################################## section "Worker" install_python_app "$SCRIPT_DIR/worker" info "creating libretime-worker working directory" mkdir_and_chown "$LIBRETIME_USER" "$WORKING_DIR/worker" install_service "libretime-worker.service" "$SCRIPT_DIR/worker/install/systemd/libretime-worker.service" # Install Legacy ######################################################################################## section "Legacy" install_composer() { install_packages unzip curl -sS https://composer.github.io/installer.sig > installer.sig echo " composer-setup.php" >> installer.sig curl -sS https://getcomposer.org/installer > composer-setup.php if ! sha384sum installer.sig; then rm -f composer-setup.php error "invalid composer-setup.php checksum" fi php -f composer-setup.php -- \ --install-dir=/usr/local/bin \ --filename=composer \ --quiet rm -f composer-setup.php installer.sig } # shellcheck disable=SC2046 install_packages $(list_packages "$SCRIPT_DIR/legacy") if ! command -v "composer" > /dev/null; then info "installing Composer" install_composer fi info "building libretime-legacy files" make -C legacy build cp "$SCRIPT_DIR/VERSION" "$SCRIPT_DIR/legacy/" info "deploying libretime-legacy files" if $LIBRETIME_INSTALL_IN_PLACE; then LEGACY_WEB_ROOT="$SCRIPT_DIR/legacy" else if [[ -d "$LEGACY_WEB_ROOT" ]]; then info "cleaning old libretime-legacy files" rm -Rf "$LEGACY_WEB_ROOT" fi mkdir_and_chown "$LIBRETIME_USER" "$LEGACY_WEB_ROOT" cp -R "$SCRIPT_DIR/legacy/." "$LEGACY_WEB_ROOT" chown -R "$LIBRETIME_USER:$LIBRETIME_USER" "$LEGACY_WEB_ROOT" fi PHP_VERSION="$(php-config --version | awk -F . '{ print $1 "." $2 }')" info "deploying libretime-legacy php-fpm config" template_file cp_if_different \ "$SCRIPT_DIR/legacy/install/php-fpm/libretime-legacy.conf" \ "/etc/php/$PHP_VERSION/fpm/pool.d/libretime-legacy.conf" \ sed \ -e "s|@@DEFAULT_WEB_USER@@|${DEFAULT_WEB_USER}|g" \ -e "s|@@USER@@|${LIBRETIME_USER}|g" info "deploying libretime-legacy logrotate config" template_file cp_if_different \ "$SCRIPT_DIR/legacy/install/logrotate/libretime-legacy.conf" \ "/etc/logrotate.d/libretime-legacy" \ sed \ -e "s|@@LOG_DIR@@|${LOG_DIR}|g" \ -e "s|@@USER@@|${LIBRETIME_USER}|g" # Install Nginx ######################################################################################## section "Nginx" if $is_first_install || $LIBRETIME_UPDATE_NGINX; then install_packages nginx info "disabling nginx default site" rm -f "/etc/nginx/sites-enabled/default" fi nginx_config_template_args=( "${SCRIPT_DIR}/installer/nginx/libretime.conf" "/etc/nginx/sites-available/libretime.conf" sed -e "s|@@LISTEN_PORT@@|${LIBRETIME_LISTEN_PORT}|g" -e "s|@@LEGACY_WEB_ROOT@@|${LEGACY_WEB_ROOT}|g" ) if $is_first_install || $LIBRETIME_UPDATE_NGINX; then info "deploying libretime nginx config" template_file cp_if_different "${nginx_config_template_args[@]}" else info "printing libretime nginx config differences" template_file diff_if_exists "${nginx_config_template_args[@]}" fi if $is_first_install || $LIBRETIME_UPDATE_NGINX; then info "enabling libretime nginx config" ln -s --force \ "/etc/nginx/sites-available/libretime.conf" \ "/etc/nginx/sites-enabled/libretime.conf" fi # Finalize ######################################################################################## if $is_first_install; then section "Finalize" info "moving config file in place" mv "$CONFIG_TMP_FILEPATH" "$CONFIG_FILEPATH" fi # Services ######################################################################################## section "Services" install_service "libretime.target" "$SCRIPT_DIR/installer/systemd/libretime.target" systemctl daemon-reload service_restart_if_active "php$PHP_VERSION-fpm" service_restart_if_active "nginx" # Instructions ######################################################################################## if $is_first_install; then section "Instructions" printf " ${yellow}\ To finalize the installation process, start by editing your configuration file $CONFIG_FILEPATH. Once configured, run the following command to setup the database: ${cyan}\ $ sudo -u $LIBRETIME_USER libretime-api migrate ${yellow}\ Finally, start LibreTime using the following command: ${cyan}\ $ sudo systemctl start libretime.target ${reset}" else printf " ${yellow}\ Once upgraded, run the following command to migrate the database: ${cyan}\ $ sudo -u $LIBRETIME_USER libretime-api migrate ${yellow}\ You can restart LibreTime using the following command: ${cyan}\ $ sudo systemctl restart libretime.target ${reset}" fi