Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env bash
- # shellcheck disable=SC2034 # Unused variables left for readability
- # MIT License
- # Permission is hereby granted, free of charge, to any person obtaining a copy
- # of this software and associated documentation files (the "Software"), to deal
- # in the Software without restriction, including without limitation the rights
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- # copies of the Software, and to permit persons to whom the Software is
- # furnished to do so, subject to the following conditions:
- # The above copyright notice and this permission notice shall be included in all
- # copies or substantial portions of the Software.
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- # SOFTWARE.
- # Author - Ideas and original and code by @bokkoman.
- # Contributors - Big thanks to @userdocs for helping with the script.
- # Testers - Thanks @Davo1624 for testing initial script. Xpenology for providing VM images.
- # Credits - https://trash-guides.info https://github.com/TRaSH-/Guides-Synology-Templates
- ## This script is adapted for generic Linux NAS systems like Ugreen 4800, supporting Docker.
- #################################################################################################################################################
- # Color me up Scotty - define some color values to use as variables in the scripts - https://robotmoon.com/256-colors/
- #################################################################################################################################################
- cr="\e[31m" clr="\e[91m" # [c]olor[r]ed [c]olor[l]ight[r]ed
- cg="\e[32m" clg="\e[92m" # [c]olor[g]reen [c]olor[l]ight[g]reen
- cy="\e[33m" cly="\e[93m" # [c]olor[y]ellow [c]olor[l]ight[y]ellow
- cb="\e[34m" clb="\e[94m" # [c]olor[b]lue [c]olor[l]ight[b]lue
- cm="\e[35m" clm="\e[38;5;212m" # [c]olor[m]agenta [c]olor[l]ight[m]agenta
- cc="\e[36m" clc="\e[38;5;81m" # [c]olor[c]yan [c]olor[l]ight[c]yan
- tb="\e[1m" td="\e[2m" tu="\e[4m" tn="\n" tbk="\e[5m" # [t]ext[b]old [t]ext[d]im [t]ext[u]nderlined [t]ext[n]ewline [t]ext[b]lin[k]
- utick="\e[32m\U2714\e[0m" uplus="\e[36m\U002b\e[0m" ucross="\e[31m\U00D7\e[0m" # [u]nicode][tick] [u]nicode][plus] [u]nicode][cross]
- urc="\e[31m\U25cf\e[0m" ulrc="\e[38;5;9m\U25cf\e[0m" # [u]nicode[r]ed[c]ircle [u]nicode[l]ight[r]ed[c]ircle
- ugc="\e[32m\U25cf\e[0m" ulgc="\e[92m\U25cf\e[0m" # [u]nicode[g]reen[c]ircle [u]nicode[l]ight[g]reen[c]ircle
- uyc="\e[33m\U25cf\e[0m" ulyc="\e[93m\U25cf\e[0m" # [u]nicode[y]ellow[c]ircle [u]nicode[l]ight[y]ellow[c]circle
- ubc="\e[34m\U25cf\e[0m" ulbc="\e[94m\U25cf\e[0m" # [u]nicode[b]lue[c]circle [u]nicode[l]ight[b]lue[c]circle
- umc="\e[35m\U25cf\e[0m" ulmc="\e[38;5;135m\U25cf\e[0m" # [u]nicode[m]agenta[c]ircle [u]nicode[l]ight[m]agenta[c]ircle
- ucc="\e[36m\U25cf\e[0m" ulcc="\e[96m\U25cf\e[0m" # [u]nicode[c]yan[c]circle [u]nicode[l]ight[c]yan[c]circle
- ugrc="\e[37m\U25cf\e[0m" ulgrcc="\e[97m\U25cf\e[0m" # [u]nicode[gr]ey[c]ircle [u]nicode[l]ight[gr]ey[c]ircle
- cdef="\e[39m" # [c]olor[def]ault
- bkend="\e[0m"
- cend="\e[0m" # [c]olor[end]
- #################################################################################################################################################
- # Banner
- #################################################################################################################################################
- printf '\n%b\n' '\e[38;2;64;81;181m ⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
- ⣿⣿⠿⠛⠋⠉⢀⣀⣀⣀⣠⣤⣤⣤⣤⣤⣀⣀⣀⠈⠉⠛⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
- ⣿⠁⣠⣴⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣤⡀⢹⣿⣿⠛⠛⠛⠛⠛⠛⠛⠛⠛⣿⠛⠛⠛⠛⠛⠛⠛⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠛⠛⠛⠻⢿⣿⣿⠛⠛⠛⣿⣿⣿⠛⠛⠛⣿⣿⣿⣿
- ⣿⠘⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⢸⣿⣿⣀⣀⣀⠀⠀⠀⣀⣀⣀⣿⠀⠀⠀⣤⣤⡄⠀⠀⢹⣿⣿⡿⠿⠿⠿⢿⣿⣿⡏⠀⠀⢠⣦⡄⠀⠀⢻⣿⠀⠀⠀⣿⣿⣿⠀⠀⠀⣿⣿⣿⣿
- ⣿⠀⡀⠀⠉⠙⠛⠛⠿⠿⠿⠿⠿⠿⠿⠿⠿⠛⠛⠛⠉⠁⢀⡀⢸⣿⣿⣿⣿⣿⠀⠀⠀⣿⣿⣿⣿⠀⠀⠀⠛⠛⠁⠀⢀⣼⣿⡁⠀⢀⣤⡀⠀⠘⣿⣷⡀⠀⠀⠀⠉⠙⠻⣿⣿⠀⠀⠀⠉⠉⠉⠀⠀⠀⣿⣿⣿⣿
- ⣿⡆⣿⣿⣶⣤⣤⣀⣀⣀⣀⠀⠀⠀⢀⣀⣀⣀⣠⣤⣴⣾⣿⠇⣾⣿⣿⣿⣿⣿⠀⠀⠀⣿⣿⣿⣿⠀⠀⠀⣦⡀⠀⠀⠻⣿⣿⠛⠋⠉⣁⡀⠀⠀⣿⠿⠿⠓⣶⣤⣄⠀⠀⢸⣿⠀⠀⠀⣶⣶⣶⠀⠀⠀⣿⣿⣿⣿
- ⣿⡇⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⣿⣿⣿⣿⣿⣿⠀⠀⠀⣿⣿⣿⣿⠀⠀⠀⣿⣿⡄⠀⠀⠹⣇⠀⠀⠘⠛⠁⠀⠀⣿⣧⠀⠀⠈⠛⠁⠀⢀⣼⣿⠀⠀⠀⣿⣿⣿⠀⠀⠀⣿⣿⣿⣿
- ⣿⣿⠸⣿⣿⣿⣿⣿⣿⣿⠏⠉⠉⠋⠙⣿⣿⣿⣿⣿⣿⣿⡟⢸⣿⣿⣿⣿⣿⣿⣶⣶⣶⣿⣿⣿⣿⣶⣶⣶⣿⣿⣿⣶⣶⣶⣿⣷⣶⣶⣶⣿⣶⣶⣾⣿⣿⣶⣶⣶⣶⣶⣿⣿⣿⣶⣶⣶⣿⣿⣿⣶⣶⣶⣿⣿⣿⣿
- ⣿⣿⠀⣿⣿⣿⣿⣿⣿⣏⠀⢠⣿⡄⠀⢈⣾⣿⣿⣿⣿⣿⡇⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
- ⣿⣿⡇⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⣿⣿⠃⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
- ⣿⣿⣇⢸⣿⣿⣷⠂⠀⢘⢿⣿⣿⣿⣿⣿⡁⠀⢻⣿⣿⣿⢀⣿⣿⣿⣿⠋⠁⠀⠀⠀⠀⠀⠉⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⢸⣿⣿⣿⣿⣿⣿⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
- ⣿⣿⣿⠈⣿⣿⣧⠀⣠⣿⣿⣿⣿⣿⠋⠿⠷⠀⢀⣿⣿⡏⢸⣿⣿⣿⠁⠀⠀⣰⣾⣿⣦⣤⣤⣼⣿⡏⠉⠉⢹⣿⡏⠉⠉⣿⣿⠉⠉⢹⣿⡿⠛⠉⠉⠛⠀⠀⠀⣿⣿⠿⠛⠉⠉⠉⠛⢿⣿⣿⠟⠋⠉⠉⠉⠛⢿⣿
- ⣿⣿⣿⡄⣿⣿⣿⣆⠀⠀⠀⢸⣿⣯⡀⠀⠀⣠⣾⣿⣿⡇⣼⣿⣿⣿⠀⠀⠀⣿⣿⠉⠉⠉⠉⠉⣿⡇⠀⠀⢸⣿⡇⠀⠀⣿⣿⠀⠀⢸⣿⠁⠀⠀⣤⣤⠀⠀⠀⣿⡏⠀⠀⣴⣶⡆⠀⠀⢹⣇⠀⠀⠚⠷⠤⢴⣾⣿
- ⣿⣿⣿⡇⠸⢿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣿⠿⠀⣿⣿⣿⣿⡀⠀⠀⠹⣿⣶⡶⠀⠀⠀⣿⡇⠀⠀⢸⣿⠃⠀⠀⣿⣿⠀⠀⢸⣿⠀⠀⠀⣿⣿⠀⠀⠀⣿⡄⠀⠀⢤⣤⣤⣤⣤⣼⣿⣦⣤⣄⣀⠀⠀⠘⣿
- ⣿⣿⣿⣷⡀⠀⠈⠉⠛⠛⠛⠛⠛⠛⠛⠛⠛⠉⠉⠀⠀⣰⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⢀⣤⣿⣧⡀⠀⠀⠀⡀⠀⠀⣿⣿⠀⠀⢸⣿⣧⡀⠀⠀⠀⡀⠀⠀⣿⣷⣀⠀⠈⠉⠁⠀⣀⣾⣧⡀⠀⠈⠉⠁⠀⣰⣿
- ⣿⣿⣿⣿⣿⣶⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣾⣿⣿⣿⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣶⣿⣿⣿⣿⣿⣷⣶⣶⣾⣿⣿⣿
- ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\e[0m'
- sleep 2
- #################################################################################################################################################
- # Disclaimer
- #################################################################################################################################################
- # Display disclaimer
- printf '\n%s\n' "DISCLAIMER: Use this script at your own risk."
- printf '\n%s\n' "This script is provided as-is without any warranty or guarantee of any kind. The author behind the script shall not be held liable for any damages or losses arising from its use."
- printf '\n%s\n' "Please note that the script may perform certain actions that can modify your system or data. It is recommended to review the script and understand its functionality before executing it."
- printf '\n%s\n' "By proceeding with the execution of this script, you acknowledge that you have read this disclaimer and agree to take full responsibility for any consequences that may arise from using the script."
- printf '\n%s\n' "If you are unsure about the script or its implications, it is recommended to seek assistance from a qualified professional before proceeding."
- printf '\n%s\n' "This script is an adaptation of the Synology guide for a generic Linux NAS. Refer to the original guide for detailed application setup at:"
- printf '%s\n' "https://trash-guides.info/Hardlinks/How-to-setup-for/Synology"
- printf '\n'
- # Prompt for confirmation
- read -erp "Do you want to continue? [y]es/[n]o: " -n 1 confirm
- echo
- # Check user's confirmation
- if [[ "${confirm}" != [Yy] ]]; then
- printf '%s\n' "Script execution canceled by the user."
- exit 0
- fi
- #################################################################################################################################################
- # check for root access and exit if the user does not have the required privileges.
- #################################################################################################################################################
- if [[ "$(id -un)" != 'root' ]]; then
- printf "\n%b\n" " ${ulrc} Please run this script with sudo to proceed"
- printf "\n%b\n\n" " ${utick} sudo ./$(basename -- "$0")"
- exit 1
- fi
- #################################################################################################################################################
- # Hide thing or show them
- #################################################################################################################################################
- if [[ "${1}" == 'show' ]]; then
- hide_all='' hide_output='' hide_error=''
- else
- hide_all='&> /dev/null' hide_output='1> /dev/null' hide_error='2> /dev/null'
- fi
- #################################################################################################################################################
- # trap to catch errors
- #################################################################################################################################################
- err_report() {
- printf '\n%b\n\n' " ${ucross} Error on line $1 - script exited to allow for debugging"
- exit 1
- }
- trap 'err_report $LINENO' ERR
- #################################################################################################################################################
- # Detect Package Manager and Install Function
- #################################################################################################################################################
- PKG_MANAGER=""
- if command -v apt-get &> /dev/null; then
- PKG_MANAGER="apt"
- elif command -v dnf &> /dev/null; then
- PKG_MANAGER="dnf"
- # Add more package managers (e.g., pacman, zypper) if needed for common NAS distros
- fi
- install_package() {
- local package_name="$1"
- printf '\n%b\n\n' " ${uplus} Installing ${package_name} using ${PKG_MANAGER}"
- case "$PKG_MANAGER" in
- "apt")
- eval apt-get update "${hide_all}"
- eval apt-get install -y "${package_name}" "${hide_all}"
- ;;
- "dnf")
- eval dnf install -y "${package_name}" "${hide_all}"
- ;;
- *)
- printf "\n%b\n\n" " ${ucross} Unsupported package manager: ${PKG_MANAGER}. Please install ${package_name} manually."
- exit 1
- ;;
- esac
- if [ $? -eq 0 ]; then
- printf '\n%b\n' " ${utick} ${package_name} installed successfully."
- else
- printf '\n%b\n' " ${ucross} Failed to install ${package_name}. Please check your internet connection or package manager configuration."
- exit 1
- fi
- }
- #################################################################################################################################################
- # Multi select function
- #################################################################################################################################################
- function _multiselect {
- printf '\n'
- # Create an array of all container names https://docs.docker.com/engine/reference/commandline/ps/#formatting
- # Ensure Docker is running to get container names
- if ! docker ps &> /dev/null; then
- printf '\n%b\n' " ${ulrc} Docker daemon is not running or not accessible. Cannot detect installed containers."
- printf '\n%b\n' " ${ulrc} Please ensure Docker is installed and running before selecting applications."
- # Attempt to start docker if it's not running but installed
- if command -v docker &> /dev/null && systemctl is-system-running &> /dev/null; then
- printf '\n%b\n' " ${ulmc} Attempting to start Docker service..."
- systemctl start docker &> /dev/null
- sleep 3 # Give Docker some time to start
- if ! docker ps &> /dev/null; then
- printf '\n%b\n' " ${ucross} Failed to start Docker. Proceeding without installed container detection."
- mapfile -t installed_containers < <(echo "") # Empty array
- else
- printf '\n%b\n' " ${utick} Docker started. Detecting installed containers."
- mapfile -t installed_containers < <(docker ps --format "{{.Names}}")
- fi
- else
- mapfile -t installed_containers < <(echo "") # Empty array if Docker isn't installed/running
- fi
- else
- mapfile -t installed_containers < <(docker ps --format "{{.Names}}")
- fi
- # Create our menu my_options associative array
- declare -A my_options
- # Fetch templates from the TRaSH-Guides GitHub repository
- eval "$(curl -sL "https://raw.githubusercontent.com/TRaSH-/Guides-Synology-Templates/main/templates/template-file-list.json" | jq -r '.templates | to_entries[]|@sh"my_options[\(.value)]=false"')"
- # Create some local arrays we need and make sure they're set to empty when the function is used/looped in the script
- local selected_values=()
- local selected_apps=()
- local lastrow
- local startrow
- # Create this global array we need fall through the function and make sure it is set to empty when the function is used/looped in the script
- selected_options=()
- # check the installed_containers array to see what is already installed, matched against our available_templates array so as not to add non template containers to the menu
- for index in "${installed_containers[@]}"; do
- if [[ "${!my_options[*]}" =~ ${index} ]]; then
- my_options["${index}"]="true"
- fi
- done
- # little helpers for terminal print control and key input
- # not really sure what this does or how it works.
- cursor_blink_on() { printf "\033[?25h"; }
- cursor_blink_off() { printf "\033[?25l"; }
- cursor_to() { printf '%b' "\033[${1};${2:-1}H"; }
- print_inactive() { printf '%b' "${2} ${1} "; }
- print_active() { printf '%b' "${2} \033[7m ${1} \033[27m"; }
- get_cursor_row() {
- IFS=';' read -rsdR -p $'\E[6n' ROW COL
- printf '%b' "${ROW#*[}"
- }
- # This will check the defaults of the my_options and set the menu option to true.
- # This eseentially switches back to an indexed array due to how the function toggle_option is working.
- for defaults in "${!my_options[@]}"; do
- if [[ "${my_options[$defaults]}" == 'true' ]]; then
- selected_values+=("true")
- else
- selected_values+=("false")
- fi
- printf "\n"
- done
- # determine current screen position for overwriting the my_options
- lastrow="$(get_cursor_row)"
- startrow="$((lastrow - ${#my_options[@]}))"
- # ensure cursor and input echoing back on upon a ctrl+c during read -s
- trap "cursor_blink_on; stty echo; printf '\n'; exit" 2
- cursor_blink_off
- # not really sure what this does or how it works.
- key_input() {
- local key
- IFS= read -rsn1 key &> /dev/null
- case "${key}" in
- '')
- echo enter
- ;;
- $'\x20')
- echo space
- ;;
- 'k')
- echo up
- ;;
- 'j')
- echo down
- ;;
- $'\x1b')
- read -rsn2 key
- case "$key" in
- '[A' | 'k')
- echo up
- ;;&
- '[B' | 'j')
- echo down
- ;;&
- esac
- ;;
- *) ;;
- esac
- }
- # Passes the toggled options and a positional parameter number, 0 to 19 for example, and then sets the index matching that number to false or true. selected_values[2]=false, selected_values[16]=false
- toggle_option() {
- local option="${1}"
- if [[ "${selected_values[option]}" == 'true' ]]; then
- selected_values["$option"]=false
- else
- selected_values["$option"]=true
- fi
- }
- # not really sure what this does or how it works.
- print_options() {
- # print options by overwriting the last lines
- local idx=0
- for option in "${!my_options[@]}"; do
- local prefix=" [\e[38;5;9m×\e[0m]"
- if [[ ${selected_values[idx]} == true ]]; then
- prefix=" [\e[38;5;46m✔\e[0m]"
- fi
- cursor_to $((startrow + idx))
- if [[ "${idx}" -eq "${1}" ]]; then
- print_active "${option}" "${prefix}"
- else
- print_inactive "${option}" "${prefix}"
- fi
- ((idx++))
- done
- }
- local active=0
- while true; do
- print_options "${active}"
- # user key control
- case $(key_input) in
- space)
- toggle_option "${active}"
- ;;
- enter)
- print_options -1
- break
- ;;
- up)
- ((active--))
- if [[ "${active}" -lt 0 ]]; then active=$((${#my_options[@]} - 1)); fi
- ;;
- down)
- ((active++))
- if [[ "${active}" -ge "${#my_options[@]}" ]]; then active=0; fi
- ;;
- esac
- done
- # cursor position back to normal
- cursor_to "${lastrow}"
- printf "\n"
- cursor_blink_on
- if [[ ! "${selected_values[*]}" =~ 'true' ]]; then
- printf '%b\n' " ${ulrc} You must select at least one option to proceed. Try again"
- _multiselect
- else
- for values in "${!my_options[@]}"; do
- selected_apps+=("$values")
- done
- for count in "${!selected_apps[@]}"; do
- my_options[${selected_apps[$count]}]=${selected_values[$count]}
- done
- for final_selection in "${!my_options[@]}"; do
- if [[ "${my_options[$final_selection]}" == 'true' ]]; then
- selected_options+=("$final_selection")
- fi
- done
- # You can use thee "${selected_options[@]}" array to install apps as it is just the name of the app.
- printf '%b\n\n' " ${utick} You have selected:"
- printf " ${uyc} %s\n" "${selected_options[@]}"
- printf '\n'
- fi
- }
- #################################################################################################################################################
- # Volumes, data and docker bootstrap
- #################################################################################################################################################
- # Create an array of all available volumes on this device
- # Using findmnt for a more robust detection of mounted filesystems (ext4, xfs, btrfs, f2fs, zfs)
- # Modified to include the root directory '/' as a valid volume option.
- mapfile -t volume_list_array < <(findmnt -l -o TARGET -n -t ext4,xfs,btrfs,f2fs,zfs | grep -E "^/mnt/|^/media/|^/data|^/volume|^/$" | sort -V)
- # If no volumes detected, exit
- if [[ "${#volume_list_array[@]}" -eq '0' ]]; then
- printf "\n%b\n" " ${ulrc} No suitable data volumes found. Please ensure your storage is mounted."
- exit 1
- fi
- [[ "${#volume_list_array[@]}" -eq '1' ]] && docker_install_volume="${volume_list_array[0]}" docker_install_volume_id="$(basename "${volume_list_array[0]}")"
- # Check if Docker is installed
- if command -v docker &> /dev/null; then
- printf "\n ${utick} %b\n" "Docker is already installed."
- install_docker="no"
- # Attempt to determine Docker's data root. Default to /var/lib if not easily found.
- docker_info_output=$(docker info --format '{{.DockerRootDir}}' 2>/dev/null)
- if [[ -n "$docker_info_output" ]]; then
- # Assuming DockerRootDir is like /var/lib/docker, we want /var/lib
- docker_install_volume="${docker_info_output%/*}"
- else
- docker_install_volume="/var/lib" # Default for Docker root on most Linux systems
- fi
- else
- install_docker="yes"
- fi
- # If Docker needs to be installed and multiple volumes exist, ask user for Docker installation volume
- if [[ "${install_docker}" == 'yes' && "${#volume_list_array[@]}" -gt '1' ]]; then
- PS3=$'\n \e[94m\U25cf\e[m '"Please select where to install Docker's data (images, containers) from the list of volumes: "$'\n\n '
- printf "\n%b\n\n" " ${uyc} This is where Docker's persistent data will be stored. It's recommended to choose a fast volume."
- select option in "${volume_list_array[@]}"; do
- if [[ "$REPLY" -gt "${#volume_list_array[@]}" ]]; then
- printf '\n%b\n\n' " ${ucross}This is not a valid volume option, try again"
- else
- docker_install_volume="$(printf '%s' "${option}")"
- read -erp $'\n \e[32m\U2714\e[0m '"You selected "$'\e[96m'"${docker_install_volume}"$'\e[m'" is this correct "$'\e[32m'"[y]es"$'\e[m'" or "$'\e[31m'"[n]o"$'\e[m'" : " -i "y" confirm
- if [[ "${confirm}" =~ ^[yY](es)?$ ]]; then
- docker_install_volume_id="$(basename "${docker_install_volume}")"
- break
- fi
- fi
- done
- fi
- # If multiple volumes, ask user for applications data volume
- if [[ "${#volume_list_array[@]}" -gt '1' ]]; then
- PS3=$'\n \e[94m\U25cf\e[m '"Please select a volume for your application's data (movies, shows, etc.): "$'\n\n '
- printf "\n%b\n\n" " ${uyc} This volume is where the media and other application data files will be stored."
- select option in "${volume_list_array[@]}"; do
- if [[ "$REPLY" -gt "${#volume_list_array[@]}" ]]; then
- printf '\n%b\n\n' " ${ucross}This is not a valid volume option, try again"
- else
- docker_data_volume="$(printf '%s' "${option}")"
- read -erp $'\n \e[32m\U2714\e[0m '"You selected "$'\e[96m'"${docker_data_volume}"$'\e[m'" is this correct "$'\e[32m'"[y]es"$'\e[m'" or "$'\e[31m'"[n]o"$'\e[m'" : " -i "y" confirm
- if [[ "${confirm}" =~ ^[yY](es)?$ ]]; then
- docker_data_dir_id="$(basename "${docker_data_volume}")"
- break
- fi
- fi
- done
- else
- # If only one volume, use it for both Docker and app data
- docker_data_volume="${volume_list_array[0]}"
- docker_data_dir_id="$(basename "${volume_list_array[0]}")"
- fi
- #################################################################################################################################################
- # Default values
- #################################################################################################################################################
- group="docker" # Standard group for Docker users on Linux.
- docker_conf_dir="${docker_install_volume}/docker_config" # Dedicated directory for docker-compose files and appdata
- docker_data_dir="${docker_data_volume:-${docker_install_volume}}/data" # /data share within the selected volume
- docker_data_dir_id="${docker_data_dir_id:-${docker_install_volume_id}}" # Just the name/id of the data volume.
- ip="$(ip route get 1 | awk '{print $NF;exit}')" # get local ip
- gateway="$(ip route | grep "$(ip route get 1 | awk '{print $7}')" | awk 'FNR==2{print $1}')" # get gateway ip
- TZ="$(realpath --relative-to /usr/share/zoneinfo /etc/localtime)" # get timezone
- qsv="/dev/dri/"
- #################################################################################################################################################
- # Install core dependencies (curl, jq) and then Docker
- #################################################################################################################################################
- # Install curl first, as it's used for downloading templates and .env files
- if ! command -v curl &> /dev/null; then
- printf '\n%b\n' " ${ulmc} curl is required for downloading files. Installing curl..."
- install_package "curl"
- else
- printf '\n%b\n' " ${utick} curl is already installed."
- fi
- # Install jq, as it's used for docker daemon.json modification
- if ! command -v jq &> /dev/null; then
- printf '\n%b\n' " ${ulmc} jq is required for Docker configuration. Installing jq..."
- install_package "jq"
- else
- printf '\n%b\n' " ${utick} jq is already installed."
- fi
- if [[ "${install_docker}" == 'yes' ]]; then
- install_package "docker.io" # For Debian/Ubuntu based systems
- # For Fedora/RHEL, it might be docker-ce, containerd.io, docker-compose-plugin
- # If docker-compose is not installed with docker.io, install it separately
- if ! command -v docker-compose &> /dev/null && ! command -v docker compose &> /dev/null; then
- install_package "docker-compose" # Separate package for docker-compose v1
- # Some newer distros use `docker compose` plugin, which is typically installed with docker-ce
- # If the above fails, users might need to install docker-compose-plugin manually
- fi
- # Configure Docker data root if it's not the default /var/lib/docker
- # This requires moving existing Docker data if it's already running on /var/lib/docker
- if [[ "${docker_install_volume}/docker" != "/var/lib/docker" ]]; then
- printf '%b\n' " ${ulmc} Configuring Docker data root to ${clc}${docker_install_volume}/docker${cend}"
- mkdir -p "${docker_install_volume}/docker"
- # Stop Docker service before modifying daemon.json
- if systemctl is-system-running &> /dev/null; then
- printf '\n%b\n' " ${ulmc} Stopping Docker service to reconfigure data root..."
- systemctl stop docker &> /dev/null
- fi
- # Ensure /etc/docker directory exists
- mkdir -p /etc/docker
- # Create or update daemon.json
- if [ ! -f /etc/docker/daemon.json ]; then
- echo '{}' > /etc/docker/daemon.json
- fi
- # Use jq to safely add or update the "data-root" entry
- if ! grep -q '"data-root":' /etc/docker/daemon.json; then
- jq --arg dr "${docker_install_volume}/docker" '. + {"data-root": $dr}' /etc/docker/daemon.json > /etc/docker/daemon.json.tmp && mv /etc/docker/daemon.json.tmp /etc/docker/daemon.json
- else
- jq --arg dr "${docker_install_volume}/docker" '.["data-root"] = $dr' /etc/docker/daemon.json > /etc/docker/daemon.json.tmp && mv /etc/docker/daemon.json.tmp /etc/docker/daemon.json
- fi
- if systemctl is-system-running &> /dev/null; then
- printf '\n%b\n' " ${ulmc} Starting Docker service after reconfiguring data root..."
- systemctl start docker &> /dev/null
- systemctl enable docker &> /dev/null
- fi
- fi
- else
- printf "\n ${utick} %b\n" "Docker is already installed"
- fi
- #################################################################################################################################################
- # Test Docker
- #################################################################################################################################################
- # Use systemctl to check Docker service status if systemd is available
- if systemctl is-system-running &> /dev/null; then
- if systemctl is-active --quiet docker; then
- printf '\n%b\n' " ${utick} Docker is running!"
- else
- printf '\n%b\n\n' " ${ucross} Docker service is not active. Please check Docker installation manually."
- exit 1
- fi
- else
- # Fallback for systems without systemd (less common for NAS, but possible)
- if docker info &> /dev/null; then
- printf '\n%b\n' " ${utick} Docker is running!"
- else
- printf '\n%b\n\n' " ${ucross} Docker is not running or not accessible. Please check Docker installation manually."
- exit 1
- fi
- fi
- #################################################################################################################################################
- # Check for user
- #################################################################################################################################################
- printf '\n%b\n' " ${ulbc} Checking if user ${clm}dockeruser${cend} exists"
- # Use a more generic user name for compatibility
- DEFAULT_USER="dockeruser"
- if id "${DEFAULT_USER}" &> /dev/null; then
- printf '\n%b\n' " ${utick} User ${clm}${DEFAULT_USER}${cend} exists!"
- user="${DEFAULT_USER}"
- else
- printf '\n%b\n' " ${ucross} The user ${clm}${DEFAULT_USER}${cend} doesn't exist, creating a user for security purposes."
- read -p "Enter a username for Docker containers (press Enter for default: ${DEFAULT_USER}): " custom_user
- user=${custom_user:-$DEFAULT_USER}
- if [ -z "$user" ]; then
- printf '\n%b\n' " ${ucross} Username cannot be empty. Aborting..."
- exit 1
- fi
- if id "$user" &> /dev/null; then
- printf '\n%b\n' " ${ucross} The user ${clm}$user${cend} already exists. Skipping user creation..."
- else
- read -s -p "Enter a password for $user: " password
- printf '\n'
- if [ -z "$password" ]; then
- printf '\n%b\n' " ${ucross} Password cannot be empty. Aborting..."
- exit 1
- fi
- # Use useradd for user creation on generic Linux
- if useradd -m -s /bin/bash "$user"; then # -m creates home directory, -s sets shell
- echo "$user:$password" | chpasswd
- printf '\n%b\n' " ${utick} User ${clm}$user${cend} created!"
- # Add user to the 'docker' group
- usermod -aG docker "$user"
- printf '\n%b\n' " ${utick} User ${clm}$user${cend} added to ${clm}docker${cend} group."
- else
- printf '\n%b\n' " ${ucross} Failed to create user ${clm}$user${cend}. Aborting..."
- exit 1
- fi
- fi
- fi
- #################################################################################################################################################
- # Create base Docker configuration and data directories and set permissions
- #################################################################################################################################################
- printf '\n%b\n' " ${ulbc} Creating base Docker configuration directory: ${clc}${docker_conf_dir}${cend}"
- mkdir -p "${docker_conf_dir}"
- # Set permissions:
- # u=rwX: User (owner) has read, write, and execute/traverse permissions.
- # g=rwX: Group (docker group) has read, write, and execute/traverse permissions.
- # o=rX: Others have read and execute/traverse permissions (important for web servers accessing media).
- # The 'X' (capital X) permission means execute for directories, and execute for files if any of the execute bits are set.
- # This ensures directories are traversable but executable flag is only set on files where appropriate.
- chown "${user}":"${group}" "${docker_conf_dir}"
- chmod u=rwX,g=rwX,o=rX "${docker_conf_dir}"
- printf '\n%b\n' " ${utick} Created and set permissions for ${clc}${docker_conf_dir}${cend}."
- printf '\n%b\n' " ${ulbc} Creating base Docker data directory: ${clc}${docker_data_dir}${cend}"
- mkdir -p "${docker_data_dir}"
- chown "${user}":"${group}" "${docker_data_dir}"
- chmod u=rwX,g=rwX,o=rX "${docker_data_dir}"
- printf '\n%b\n' " ${utick} Created and set permissions for ${clc}${docker_data_dir}${cend}."
- printf '\n%b\n' " ${ulmc} Setting final recursive permissions for main directories."
- # These recursive commands will ensure all new files/folders within are also correctly permissioned
- chown -R "${user}":"${group}" "${docker_data_dir}" "${docker_conf_dir}"
- chmod -R u=rwX,g=rwX,o=rX "${docker_data_dir}"
- chmod -R u=rwX,g=rwX,o=rX "${docker_conf_dir}"
- printf '\n%b\n' " ${utick} Initial permissions recursively applied."
- #################################################################################################################################################
- # VPN stuff
- #################################################################################################################################################
- install_tun() {
- # Check for /dev/net/tun device node
- if [[ -c /dev/net/tun ]]; then
- printf '\n%b\n' " ${utick} /dev/net/tun device node already exists."
- else
- printf '\n%b\n' " ${ulmc} Creating /dev/net/tun device node for VPN"
- mkdir -p /dev/net
- mknod /dev/net/tun c 10 200 # Create character device node
- chmod 600 /dev/net/tun # Set permissions
- fi
- # Ensure tun kernel module is loaded
- if ! lsmod | grep -q "^tun"; then
- printf '\n%b\n' " ${ulmc} Loading tun kernel module."
- modprobe tun
- if [ $? -ne 0 ]; then
- printf "\n%b\n" " ${ulrc} Failed to load 'tun' kernel module. VPN might not work."
- else
- printf '\n%b\n' " ${utick} 'tun' kernel module loaded."
- fi
- fi
- # Install/Enable systemd service if systemd is detected
- if systemctl is-system-running &> /dev/null; then # Check if systemd is running
- printf '\n%b\n' " ${ulmc} Systemd detected. Configuring tun.service."
- if curl -sL "https://raw.githubusercontent.com/TRaSH-/Guides-Synology-Templates/main/script/tun.service" -o "/etc/systemd/system/tun.service"; then
- printf '\n%b\n' " ${utick} Service file to start Tun downloaded."
- else
- printf '\n%b\n' " ${ucross} Failed to download tun.service. VPN might require manual setup."
- fi
- # Reload systemd daemon to pick up new service file
- systemctl daemon-reload &> /dev/null
- if systemctl enable tun.service &> /dev/null; then
- printf '\n%b\n' " ${utick} Service tun.service enabled to start on boot."
- else
- printf '\n%b\n' " ${ucross} Failed to enable tun.service."
- fi
- if systemctl start tun.service &> /dev/null; then
- printf '\n%b\n' " ${utick} Service tun.service started."
- else
- printf '\n%b\n' " ${ucross} Failed to start tun.service. Check logs for errors."
- fi
- if ! systemctl is-active --quiet tun.service; then
- printf "\n%b\n" " ${ulrc} Service tun.service couldn't start properly or is not active. VPN might not work."
- printf "\n%b\n" " ${tb} You may need to troubleshoot TUN device setup manually."
- # Not exiting here, as user might still want to proceed without VPN
- else
- printf '\n%b\n' " ${utick} Service tun.service is active."
- fi
- else
- printf "\n%b\n" " ${ulrc} Systemd not detected. Manual TUN setup or alternative init system configuration may be required if VPN is desired."
- fi
- }
- #################################################################################################################################################
- # Create docker-compose.yml and download .env
- #################################################################################################################################################
- #check if docker-compose already exist before overwriting.
- file="${docker_conf_dir}/appdata/docker-compose.yml"
- if [ -f "$file" ]; then
- while true; do
- read -erp $'\e[32m\U2714\e[0m docker-compose.yml already exists, overwrite and create new? \e[38;5;10m[y]es\e[m or \e[38;5;9m[n]o\e[m: ' -i "n" yesno
- case "${yesno}" in
- [Yy])
- printf '\n%b\n' " ${ulmc} Overwriting file..."
- printf '\n%b\n' " ${ulmc} Bootstrapping docker-compose.yml"
- mkdir -p "${docker_conf_dir}/appdata"
- cat > "${docker_conf_dir}/appdata/docker-compose.yml" <<EOF
- version: "3.2"
- services:
- EOF
- break
- ;;
- [Nn])
- printf '\n%b\n' " ${ulmc} Keeping current docker-compose.yml"
- break
- ;;
- *) printf '\n%b\n\n' " ${ulrc} Please answer ${clg}[y]es${cend} or ${clr}[n]o${cend}" ;;
- esac
- done
- else
- printf '\n%b\n' " ${ulmc} Bootstrapping docker-compose.yml"
- mkdir -p "${docker_conf_dir}/appdata"
- cat > "${docker_conf_dir}/appdata/docker-compose.yml" <<EOF
- version: "3.2"
- services:
- EOF
- printf '\n%b\n' " ${utick} docker-compose.yml bootstrapped"
- fi
- printf '\n%b\n' " ${ulmc} Downloading docker .env"
- if wget -qO "${docker_conf_dir}/appdata/.env" "https://raw.githubusercontent.com/TRaSH-/Guides-Synology-Templates/main/docker-compose/.env"; then
- printf '\n%b\n' " ${utick} Docker .env downloaded."
- else
- printf '\n%b\n' " ${ucross} There was a problem downloading the .env, try again"
- exit 1
- fi
- printf '\n%b\n' " ${ulmc} Setting correct User ID in .env"
- sed -i "s|PUID=1035|PUID=$(id "${user}" -u)|g" "${docker_conf_dir}/appdata/.env"
- printf '\n%b\n' " ${utick} User ID set.."
- printf '\n%b\n' " ${ulmc} Setting local IP in .env"
- sed -i "s|192.168.x.x:32400|${ip}:32400|g" "${docker_conf_dir}/appdata/.env"
- printf '\n%b\n' " ${utick} Local IP set."
- printf '\n%b\n' " ${ulmc} Setting local Gateway in .env"
- sed -i "s|LAN_NETWORK=192.168.x.0/24|LAN_NETWORK=$gateway|g" "${docker_conf_dir}/appdata/.env"
- printf '\n%b\n' " ${utick} local Gateway set."
- printf '\n%b\n' " ${ulmc} Setting timezone in .env"
- sed -i "s|Europe/Amsterdam|${TZ}|g" "${docker_conf_dir}/appdata/.env"
- printf '\n%b\n' " ${utick} Timezone set."
- printf '\n%b\n' " ${ulmc} Setting correct docker config dir in then .env"
- sed -i "s|DOCKERCONFDIR=/volume1/docker|DOCKERCONFDIR=${docker_conf_dir}|g" "${docker_conf_dir}/appdata/.env"
- printf '\n%b\n' " ${utick} ${clc}${docker_conf_dir}${cend} set."
- printf '\n%b\n' " ${ulmc} Setting correct docker storage dir in the .env"
- sed -i "s|DOCKERSTORAGEDIR=/volume1/data|DOCKERSTORAGEDIR=${docker_data_dir}|g" "${docker_conf_dir}/appdata/.env"
- printf '\n%b\n' " ${utick} ${clc}${docker_data_dir}${cend} set."
- #################################################################################################################################################
- # compose template downloader
- #################################################################################################################################################
- get_app_compose() {
- if wget -qO "${docker_conf_dir}/appdata/${1}.yml" "https://raw.githubusercontent.com/TRaSH-/Guides-Synology-Templates/main/templates/${1,,}.yml"; then
- [[ "${options}" = 'sabnzbd' ]] && sed -r 's|- 8080:8080$|- 7080:8080|g' -i "${docker_conf_dir}/appdata/${1}.yml"
- [[ "${options}" == 'dozzle' ]] && sed -r 's|- 8080:8080$|- 7081:8080|g' -i "${docker_conf_dir}/appdata/${1}.yml"
- if grep -q "^\s*${1,,}:" "${docker_conf_dir}/appdata/docker-compose.yml"; then
- printf '\n%b\n' " ${ucross} Skipped adding ${1,,} to compose, already exists."
- rm -f "${docker_conf_dir}/appdata/${1}.yml"
- else
- printf '\n' >> "${docker_conf_dir}/appdata/docker-compose.yml"
- sed -n 'p' "${docker_conf_dir}/appdata/${1}.yml" >> "${docker_conf_dir}/appdata/docker-compose.yml"
- rm -f "${docker_conf_dir}/appdata/${1}.yml"
- printf '\n%b\n' " ${utick} ${1,,} template added to compose."
- fi
- else
- printf '\n%b\n' " ${ucross} There was a problem downloading the template for ${1,,}. Please try again."
- exit 1
- fi
- }
- #################################################################################################################################################
- # Run _multiselect function
- #################################################################################################################################################
- printf '\n%b' " arrow down => down"
- printf '\n%b' " arrow up => up"
- printf '\n%b' " Space bar => toggle selection"
- printf '\n%b\n' " Enter key => confirm selection"
- _multiselect
- #################################################################################################################################################
- # Process selections
- #################################################################################################################################################
- while true; do
- read -erp $' \e[32m\U2714\e[0m '"Is this correct selection? "$'\e[38;5;10m'"[y]es"$'\e[m'" or "$'\e[38;5;9m'"[n]o"$'\e[m'" : " -i "y" yesno
- case "${yesno}" in
- [Yy]*)
- printf '\n%b\n' " ${ulmc} Creating docker-compose"
- for options in "${selected_options[@]}"; do
- mkdir -p "${docker_conf_dir}/appdata/${options}"
- get_app_compose "${options}"
- [[ "${options}" == 'plex' ]] && plex_installed="yes"
- [[ "${options}" == 'jellyfin' ]] && jellyfin_installed="yes"
- [[ "${options}" == 'qbittorrent' ]] && qbit_installed="yes" && mkdir -p "${docker_data_dir}"/torrents/{tv,movies}
- [[ "${options}" == 'radarr' ]] && mkdir -p "${docker_data_dir}/media/movies"
- [[ "${options}" == 'sonarr' ]] && mkdir -p "${docker_data_dir}/media/tv"
- [[ "${options}" =~ ^(sabnzbd|nzbget)$ ]] && mkdir -p "${docker_data_dir}"/usenet/complete/{tv,movies}
- done
- if [[ "${plex_installed}" == "yes" || "${jellyfin_installed}" == "yes" ]]; then
- #check for quick sync
- if [[ -d "$qsv" ]]; then
- ### Do nothing if $qsv exists.
- printf '\n%b\n' " ${utick} Intel Quick Sync found for Plex/Jellyfin Hardware Transcoding."
- else
- ### Take action if $qsv does not exist, by commenting out device mappings
- sed -r "s|^(.*)devices:(.*)# optional: if you have a Syno with an Intel CPU(.*)|#\1devices:\2# optional: if you have a Syno with an Intel CPU\3|g" -i "${docker_conf_dir}/appdata/docker-compose.yml"
- sed -r "s|^(.*)- /dev/dri:/dev/dri(.*)# optional: if you have a Syno with an Intel CPU(.*)|#\1- /dev/dri:/dev/dri\2# optional: if you have a Syno with an Intel CPU\3|g" -i "${docker_conf_dir}/appdata/docker-compose.yml"
- printf '\n%b\n' " ${ucross} No Intel Quick Sync found for Plex/Jellyfin Hardware Transcoding. Device mapping commented out."
- fi
- fi
- if [[ "${qbit_installed}" == "yes" ]]; then
- while true; do
- read -erp $'\n \e[32m\U2714\e[0m '"Do you want Qbittorrent installed with VPN? "$'\e[38;5;10m'"[y]es"$'\e[m'" or "$'\e[38;5;9m'"[n]o"$'\e[m'" : " -i "" yesno
- case "${yesno}" in
- [Yy]*)
- printf '\n%b\n\n' " ${utick} With VPN"
- mkdir -p "${docker_conf_dir}/appdata/qbittorrent/wireguard"
- install_tun # Call the generic install_tun function
- while true; do
- read -erp $' \e[93m\U25cf\e[0m '"Place your "$'\e[38;5;81m'"wg0.conf"$'\e[m'" in:"$'\n\n \e[38;5;81m'"${docker_conf_dir}/appdata/qbittorrent/wireguard"$'\e[m\n\n \e[93m\U25cf\e[0m '"When that is done please confirm "$'\e[38;5;10m'"[y]es"$'\e[m'" : " -i "" yes
- case "${yes}" in
- [Yy]*)
- sed -r 's|VPN_ENABLED=false|VPN_ENABLED=true|g' -i "${docker_conf_dir}/appdata/.env"
- sed -r 's|# devices:| devices:|g' -i "${docker_conf_dir}/appdata/docker-compose.yml"
- sed -r 's|# - /dev/net/tun:/dev/net/tun| - /dev/net/tun:/dev/net/tun|g' -i "${docker_conf_dir}/appdata/docker-compose.yml"
- if [[ -f "${docker_conf_dir}/appdata/qbittorrent/wireguard/wg0.conf" ]]; then
- if mv "${docker_conf_dir}/appdata/qbittorrent/wireguard/wg0.conf" "${docker_conf_dir}/appdata/qbittorrent/wireguard/wg0-fix.conf" 2> /dev/null; then
- printf '\n%b\n' " ${utick} wg0.conf found and fixed (renamed to wg0-fix.conf)."
- fi
- else
- printf '\n%b\n\n ' " ${ucross} wg0.conf not found. Place file with filename ${clc}wg0.conf${cend} and answer yes when ready."
- # Allow user to retry putting the file in place
- continue
- fi
- break 2
- ;;
- [Nn]*)
- printf '\n%b\n\n ' " ${ucross} Cancelled."
- exit 1
- ;;
- *) printf '\n%b\n\n' " ${ulrc} Please answer ${clg}[y]es${cend} to continue or ${clr}[n]o${cend} to cancel." ;;
- esac
- done
- ;;
- [Nn]*)
- printf '\n%b\n' " ${ucross} Without VPN."
- sed -r 's|VPN_ENABLED=true|VPN_ENABLED=false|g' -i "${docker_conf_dir}/appdata/.env"
- sed -r 's| devices:|# devices:|g' -i "${docker_conf_dir}/appdata/docker-compose.yml"
- sed -r 's| - /dev/net/tun:/dev/net/tun|# - /dev/net/tun:/dev/net/tun|g' -i "${docker_conf_dir}/appdata/docker-compose.yml"
- break
- ;;
- esac
- done
- fi
- printf '\n%b\n' " ${ulmc} Doing final permissions stuff"
- # Ensure proper recursive ownership and permissions for the selected directories
- chown -R "${user}":"${group}" "${docker_data_dir}" "${docker_conf_dir}/appdata"
- chmod -R u=rwX,g=rwX,o=rX "${docker_data_dir}" # User and group can read, write, execute. Others can read and execute.
- chmod -R u=rwX,g=rwX,o=rX "${docker_conf_dir}/appdata" # User and group can read, write, execute. Others can read and execute.
- printf '\n%b\n' " ${utick} Permissions set."
- printf '\n%b\n' " ${uplus} Installing Pullio for auto updates"
- if [[ -x "/usr/local/bin/pullio" ]]; then
- printf '\n%b\n' " ${ucross} Pullio is already installed."
- else
- if wget -qO /usr/local/bin/pullio "https://raw.githubusercontent.com/hotio/pullio/master/pullio.sh"; then
- chmod +x /usr/local/bin/pullio
- mkdir -p "${docker_conf_dir}/appdata/pullio"
- printf '\n%b\n' " ${utick} Pullio installed, read final message when the script is done."
- else
- printf '\n%b\n' " ${ucross} There was a problem downloading Pullio. Please install manually. Read https://trash-guides.info/Hardlinks/How-to-setup-for/Synology/#pullio-auto-update-docker-compose-the-correct-way"
- fi
- fi
- printf '\n%b\n\n' " ${uplus} Installing the selected containers"
- # Use 'docker compose' if available, otherwise fallback to 'docker-compose'
- if command -v docker &> /dev/null && docker compose version &> /dev/null; then
- DOCKER_COMPOSE_CMD="docker compose"
- elif command -v docker-compose &> /dev/null; then
- DOCKER_COMPOSE_CMD="docker-compose"
- else
- printf '\n%b\n' " ${ulmc} Docker Compose not found. Attempting to install docker-compose..."
- if [[ "${PKG_MANAGER}" == "apt" ]]; then
- apt-get update && apt-get install -y docker-compose
- elif [[ "${PKG_MANAGER}" == "dnf" ]]; then
- dnf install -y docker-compose
- fi
- if command -v docker-compose &> /dev/null; then
- DOCKER_COMPOSE_CMD="docker-compose"
- printf '\n%b\n' " ${utick} docker-compose installed and ready."
- else
- printf '\n%b\n\n' " ${ucross} Could not install docker-compose automatically. Please install it manually."
- exit 1
- fi
- fi
- cd "${docker_conf_dir}/appdata/" || return
- eval "${DOCKER_COMPOSE_CMD} up -d --remove-orphans"
- printf '\n%b\n\n' " ${utick} All set, everything should be running. If you have errors, follow the complete guide. And join our discord server."
- printf '\n%b\n\n' " ${utick} If you want to enable automatic updates, you need to create a Scheduled Task.\n Read instructions here: https://trash-guides.info/Hardlinks/How-to-setup-for/Synology/#pullio-auto-update-docker-compose-the-correct-way"
- break
- ;;
- [Nn]*)
- _multiselect
- ;;
- *) printf '\n%b\n\n' " ${ulrc} Please answer ${clg}[y]es${cend} or ${clr}[n]o${cend}" ;;
- esac
- done
- exit
Add Comment
Please, Sign In to add comment