#!/bin/bash { #//////////////////////////////////// # DietPi Software # #//////////////////////////////////// # Created by Daniel Knight / daniel.knight@dietpi.com / dietpi.com # #//////////////////////////////////// # # Info: # - Location: /boot/dietpi/dietpi-software # - Installs "ready to run" software with optimisations unique to the device. # - Generates and uses /boot/dietpi/.installed listing installed software. USAGE=' Usage: dietpi-software [ [...]] Available commands: Interactive menu to install or uninstall software install ... Install each software given by space-separated list of IDs reinstall ... Reinstall each software given by space-separated list of IDs uninstall ... Uninstall each software given by space-separated list of IDs list [--machine-readable] Print a list with IDs and info for all available software titles free Print an unused software ID, free for a new software implementation ' #//////////////////////////////////// # Import DietPi-Globals --------------------------------------------------------------- . /boot/dietpi/func/dietpi-globals readonly G_PROGRAM_NAME='DietPi-Software' if [[ $1 != 'list' ]] then G_CHECK_ROOT_USER "$@" G_CHECK_ROOTFS_RW G_INIT fi # Import DietPi-Globals --------------------------------------------------------------- [[ $1 == 'list' && $2 == '--machine-readable' ]] && MACHINE_READABLE=1 || MACHINE_READABLE= #///////////////////////////////////////////////////////////////////////////////////// # Install states file #///////////////////////////////////////////////////////////////////////////////////// Write_InstallFileList() { # Update webserver stack meta install states aSOFTWARE_INSTALL_STATE[75]=0 aSOFTWARE_INSTALL_STATE[76]=0 aSOFTWARE_INSTALL_STATE[78]=0 aSOFTWARE_INSTALL_STATE[79]=0 aSOFTWARE_INSTALL_STATE[81]=0 aSOFTWARE_INSTALL_STATE[82]=0 if (( ${aSOFTWARE_INSTALL_STATE[89]} == 2 )) then # Apache if (( ${aSOFTWARE_INSTALL_STATE[83]} == 2 )) then (( ${aSOFTWARE_INSTALL_STATE[87]} == 2 )) && aSOFTWARE_INSTALL_STATE[75]=2 # SQLite: LASP (( ${aSOFTWARE_INSTALL_STATE[88]} == 2 )) && aSOFTWARE_INSTALL_STATE[76]=2 # MariaDB: LAMP # Nginx elif (( ${aSOFTWARE_INSTALL_STATE[85]} == 2 )) then (( ${aSOFTWARE_INSTALL_STATE[87]} == 2 )) && aSOFTWARE_INSTALL_STATE[78]=2 # SQLite: LESP (( ${aSOFTWARE_INSTALL_STATE[88]} == 2 )) && aSOFTWARE_INSTALL_STATE[79]=2 # MariaDB: LEMP # Lighttpd elif (( ${aSOFTWARE_INSTALL_STATE[84]} == 2 )) then (( ${aSOFTWARE_INSTALL_STATE[87]} == 2 )) && aSOFTWARE_INSTALL_STATE[81]=2 # SQLite: LLSP (( ${aSOFTWARE_INSTALL_STATE[88]} == 2 )) && aSOFTWARE_INSTALL_STATE[82]=2 # MariaDB: LLMP fi fi # Save installed states local i install_states for i in "${!aSOFTWARE_NAME[@]}" do # Don't save pending and uninstalled states (-1/0/1) if (( ${aSOFTWARE_INSTALL_STATE[$i]} == 2 )) then install_states+="aSOFTWARE_INSTALL_STATE[$i]=2 " # Store DietPi-RAMlog and Dropbear uninstalled state as well, as it is initialised as installed matching our image defaults elif (( $i == 103 || $i == 104 )) then install_states+="aSOFTWARE_INSTALL_STATE[$i]=0 " fi done # Save logging choice install_states+="INDEX_LOGGING=$INDEX_LOGGING" echo "$install_states" > /boot/dietpi/.installed } Read_InstallFileList() { if [[ -f '/boot/dietpi/.installed' ]] then # shellcheck disable=SC1091 if [[ $MACHINE_READABLE ]] then . /boot/dietpi/.installed else G_EXEC_DESC='Reading database' G_EXEC . /boot/dietpi/.installed fi else # Assure that the file exists to allow choice/preference selections on first run: https://github.com/MichaIng/DietPi/issues/5080 >> /boot/dietpi/.installed fi } Check_Net_and_Time_sync() { # Check network connectivity and sync system clock G_CHECK_NET /boot/dietpi/func/run_ntpd } #///////////////////////////////////////////////////////////////////////////////////// # Installation system #///////////////////////////////////////////////////////////////////////////////////// # Flag to trigger Run_Installations() GOSTARTINSTALL=0 # Flag to skip APT update in Run_Installations(), set by DietPi-Automation_Pre() SKIP_APT_UPDATE=0 # Logging choice index INDEX_LOGGING=-1 # Array to collect all installed services to be enabled after installs have finished aENABLE_SERVICES=() # Since no automated reboot is done anymore after installs, collect services to start manually, when not controlled by DietPi-Services aSTART_SERVICES=() # Global password for software installs GLOBAL_PW= Update_Global_Pw() { # Loop until password is valid or dietpi-set_software fails while : do # Read encrypted password if [[ -f '/var/lib/dietpi/dietpi-software/.GLOBAL_PW.bin' ]] then # In case of error, assure empty password to fallback to default GLOBAL_PW=$(openssl enc -d -a -md sha256 -aes-256-cbc -iter 10000 -salt -pass pass:'DietPiRocks!' -in /var/lib/dietpi/dietpi-software/.GLOBAL_PW.bin) || GLOBAL_PW= # Return on valid password [[ $GLOBAL_PW && $GLOBAL_PW != 'dietpi' ]] && return 0 G_DIETPI-NOTIFY 1 'Global software password failed to be read, is empty, or still the default. Asking to set a new one ...' fi # Apply default password as fallback if empty [[ $GLOBAL_PW ]] || GLOBAL_PW='dietpi' # In case ask for and apply new valid password /boot/dietpi/func/dietpi-set_software password software check || return 1 done } # Total physical system RAM: Used to calculate percentage based value for software cache limits, e.g.: OPcache/APCu readonly RAM_PHYS=$(free -m | mawk '/^Mem:/{print $2;exit}') # Total RAM + swap space: Used to estimate whether the swap file size needs to be increased. readonly RAM_TOTAL=$(free -tm | mawk '/^Total:/{print $2;exit}') # Whether to restart Deluge web UI once, required on fresh installs for auto-connection to work, more precisely a little delay between daemon and web UI is required RESTART_DELUGE_WEB=0 # PHP version case $G_DISTRO in 6) PHP_VERSION='7.4';; 7) PHP_VERSION='8.2';; *) PHP_VERSION='8.4';; esac # Available for [$software_id,$G_*] 2D array declare -A aSOFTWARE_AVAIL_G_HW_MODEL declare -A aSOFTWARE_AVAIL_G_HW_ARCH declare -A aSOFTWARE_AVAIL_G_DISTRO # ToDo: On RPi 4, the 64-bit kernel is now used by default, without "arm_64bit=1" set: https://forums.raspberrypi.com/viewtopic.php?p=2088935#p2088935 # - We could set "arm_64bit=0", but for now lets assure that 32-bit software is installed and see how it goes. This enables general support for RPi with 64-bit kernel running 32-bit userland. # - Also set a little flag here for the "dietpi-software list" command to correctly show that a software title is disabled because of the userland architecture, not because of the kernel architecture. RPI_64KERNEL_32OS= [[ $G_HW_MODEL == [2-9] && $G_HW_ARCH == 3 && $(dpkg --print-architecture) == 'armhf' ]] && G_HW_ARCH=2 G_HW_ARCH_NAME='armv7l' RPI_64KERNEL_32OS='32-bit image' # Generate arrays for all available software titles Software_Arrays_Init() { [[ $MACHINE_READABLE ]] || G_DIETPI-NOTIFY -2 'Initialising database' #-------------------------------------------------------------------------------- # Software categories # NB: Unique IDs, do not re-arrange or re-order! #-------------------------------------------------------------------------------- readonly aSOFTWARE_CATEGORIES=( # Use "-1" to hide software title from menu '●─ Desktops ' #0 '●─ Remote Desktop ' #1 '●─ Media Systems ' #2 '●─ BitTorrent & Download ' #3 '●─ Cloud & Backup ' #4 '●─ Gaming & Emulation ' #5 '●─ Social & Search ' #6 '●─ Camera & Surveillance ' #7 '●─ System Stats & Management ' #8 '●─ Remote Access ' #9 '●─ Hardware Projects ' #10 '●─ System Security ' #11 '●─ Webserver Stacks ' #12 '●─ DNS Servers ' #13 '●─ File Servers ' #14 '●─ VPN Servers ' #15 '●─ Advanced Networking ' #16 '●─ Home Automation ' #17 '●─ Printing ' #18 '●─ Distributed Projects ' #19 '●─ SSH Clients ' #20 '●─ File Server Clients ' #21 '●─ System ' #22 '●─ Databases & Data Stores ' #23 '●─ Development & Programming ' #24 '●─ Desktop Utilities ' #25 ) #-------------------------------------------------------------------------------- # Software items #-------------------------------------------------------------------------------- # Before adding, please check 'dietpi-software free' to list free IDs for use. # Assign unique ID to each item local software_id i # Desktops #-------------------------------------------------------------------------------- software_id=23 aSOFTWARE_NAME[$software_id]='LXDE' aSOFTWARE_DESC[$software_id]='ultra lightweight desktop' aSOFTWARE_CATX[$software_id]=0 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#lxde' aSOFTWARE_DEPS[$software_id]='5 6 browser' #------------------ software_id=24 aSOFTWARE_NAME[$software_id]='MATE' aSOFTWARE_DESC[$software_id]='desktop enviroment' aSOFTWARE_CATX[$software_id]=0 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#mate' aSOFTWARE_DEPS[$software_id]='5 6 browser' #------------------ software_id=25 aSOFTWARE_NAME[$software_id]='Xfce' aSOFTWARE_DESC[$software_id]='lightweight desktop' aSOFTWARE_CATX[$software_id]=0 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#xfce' aSOFTWARE_DEPS[$software_id]='5 6 browser' #------------------ software_id=26 aSOFTWARE_NAME[$software_id]='GNUstep' aSOFTWARE_DESC[$software_id]='lightweight desktop based on OpenStep' aSOFTWARE_CATX[$software_id]=0 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#gnustep' aSOFTWARE_DEPS[$software_id]='5 6 browser' #------------------ software_id=173 aSOFTWARE_NAME[$software_id]='LXQt' aSOFTWARE_DESC[$software_id]='lightweight desktop' aSOFTWARE_CATX[$software_id]=0 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#lxqt' aSOFTWARE_DEPS[$software_id]='5 6 browser' # Remote Desktop #-------------------------------------------------------------------------------- software_id=28 aSOFTWARE_NAME[$software_id]='TigerVNC Server' aSOFTWARE_DESC[$software_id]='desktop for remote connection' aSOFTWARE_CATX[$software_id]=1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/remote_desktop/#tigervnc-server' aSOFTWARE_DEPS[$software_id]='desktop' aSOFTWARE_CONFLICTS[$software_id]='120' #------------------ software_id=29 aSOFTWARE_NAME[$software_id]='XRDP' aSOFTWARE_DESC[$software_id]='remote desktop protocol (rdp) server' aSOFTWARE_CATX[$software_id]=1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/remote_desktop/#xrdp' aSOFTWARE_DEPS[$software_id]='desktop' #------------------ software_id=30 aSOFTWARE_NAME[$software_id]='NoMachine' aSOFTWARE_DESC[$software_id]='multi-platform server and client access' aSOFTWARE_CATX[$software_id]=1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/remote_desktop/#nomachine' aSOFTWARE_DEPS[$software_id]='desktop' # - RISC-V: https://downloads.nomachine.com/ aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=120 aSOFTWARE_NAME[$software_id]='RealVNC Server' aSOFTWARE_DESC[$software_id]='desktop for remote connection' aSOFTWARE_CATX[$software_id]=1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/remote_desktop/#realvnc-server' aSOFTWARE_DEPS[$software_id]='desktop' aSOFTWARE_CONFLICTS[$software_id]='28' # RPi only (archive.raspberrypi.com repo, libraspberrypi0 dependency, license) (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 # Media Systems #-------------------------------------------------------------------------------- software_id=31 aSOFTWARE_NAME[$software_id]='Kodi' aSOFTWARE_DESC[$software_id]='The media centre for Linux' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#kodi' aSOFTWARE_DEPS[$software_id]='5 152' #------------------ software_id=32 aSOFTWARE_NAME[$software_id]='ympd' aSOFTWARE_DESC[$software_id]='lightweight web interface music player for mpd' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#ympd' aSOFTWARE_DEPS[$software_id]='128' #------------------ software_id=148 aSOFTWARE_NAME[$software_id]='myMPD' aSOFTWARE_DESC[$software_id]='fork of ympd with improved features' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#mympd' aSOFTWARE_DEPS[$software_id]='128' # - RISC-V: https://download.opensuse.org/repositories/home:/jcorporation/Debian_Testing/ aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 # - ARMv6 Trixie: No Raspbian_Testing suite available and Bookworm package depends on libflac12 (( $G_HW_ARCH == 1 && $G_DISTRO > 7 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=119 aSOFTWARE_NAME[$software_id]='CAVA' aSOFTWARE_DESC[$software_id]='Console audio visualisation for MPD' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#cava' aSOFTWARE_DEPS[$software_id]='128' #------------------ software_id=33 aSOFTWARE_NAME[$software_id]='Airsonic-Advanced' aSOFTWARE_DESC[$software_id]='Web interface media streaming server' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#airsonic' aSOFTWARE_DEPS[$software_id]='5 7 196' #------------------ software_id=35 aSOFTWARE_NAME[$software_id]='Lyrion Music Server' aSOFTWARE_DESC[$software_id]='formerly Logitech Media Server and Squeezebox Server' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#lyrion-music-server' # - RISC-V: https://lms-community.github.io/lms-server-repository/stable.xml aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=36 aSOFTWARE_NAME[$software_id]='Squeezelite' aSOFTWARE_DESC[$software_id]='audio player for LMS & Squeezebox' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#squeezelite' aSOFTWARE_DEPS[$software_id]='5' #------------------ software_id=37 aSOFTWARE_NAME[$software_id]='Shairport Sync' aSOFTWARE_DESC[$software_id]='AirPlay audio player with multiroom sync' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#shairport-sync' aSOFTWARE_DEPS[$software_id]='5 152' #------------------ software_id=39 aSOFTWARE_NAME[$software_id]='ReadyMedia' aSOFTWARE_DESC[$software_id]='(MiniDLNA) media streaming server (DLNA, UPnP)' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#readymedia' #------------------ software_id=40 aSOFTWARE_NAME[$software_id]='Ampache' aSOFTWARE_DESC[$software_id]='web interface media streaming server' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#ampache' aSOFTWARE_DEPS[$software_id]='5 7 88 89 webserver' #------------------ software_id=41 aSOFTWARE_NAME[$software_id]='Emby' aSOFTWARE_DESC[$software_id]='web interface media streaming server' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#emby' # - ARMv6: https://github.com/MichaIng/DietPi/issues/534#issuecomment-416405968 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - RISC-V: https://github.com/MediaBrowser/Emby.Releases/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=42 aSOFTWARE_NAME[$software_id]='Plex Media Server' aSOFTWARE_DESC[$software_id]='web interface media streaming server' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#plex-media-server' # - ARMv6: https://github.com/MichaIng/DietPi/issues/648 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - RISC-V: https://www.plex.tv/media-server-downloads/?cat=computer&plat=linux#plex-media-server aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=43 aSOFTWARE_NAME[$software_id]='Mumble Server' aSOFTWARE_DESC[$software_id]='(Murmur) Low latency encrypted VoIP server' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#murmur' #------------------ software_id=118 aSOFTWARE_NAME[$software_id]='Mopidy' aSOFTWARE_DESC[$software_id]='Web interface music & radio player' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#mopidy' aSOFTWARE_DEPS[$software_id]='5 130' #------------------ software_id=121 aSOFTWARE_NAME[$software_id]='Roon Bridge' aSOFTWARE_DESC[$software_id]='Turns device into Roon capable audio player' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#roon-bridge' aSOFTWARE_DEPS[$software_id]='5' # - ARMv6 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - RISC-V: https://help.roonlabs.com/portal/en/kb/articles/linux-install aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=124 aSOFTWARE_NAME[$software_id]='NAA Daemon' aSOFTWARE_DESC[$software_id]='Signalyst Network Audio Adaptor (NAA)' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#naa-daemon' aSOFTWARE_DEPS[$software_id]='5' # - RISC-V: https://signalyst.com/bins/naa/linux/ aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 # - ARMv6/7 Trixie (( $G_HW_ARCH < 3 && $G_DISTRO > 7 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=128 aSOFTWARE_NAME[$software_id]='MPD' aSOFTWARE_DESC[$software_id]='music player daemon' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DEPS[$software_id]='5 152' #------------------ software_id=129 aSOFTWARE_NAME[$software_id]='O!MPD' aSOFTWARE_DESC[$software_id]='Feature-rich, web interface audio player for MPD' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#ompd' aSOFTWARE_DEPS[$software_id]='88 89 128 195 webserver' #------------------ software_id=135 aSOFTWARE_NAME[$software_id]='Icecast' aSOFTWARE_DESC[$software_id]='Shoutcast streaming server (+DarkIce)' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#icecast' aSOFTWARE_DEPS[$software_id]='5' #------------------ software_id=143 aSOFTWARE_NAME[$software_id]='Koel' aSOFTWARE_DESC[$software_id]='web interface audio streamer' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#koel' aSOFTWARE_DEPS[$software_id]='7 88 89' #------------------ software_id=146 aSOFTWARE_NAME[$software_id]='Tautulli' aSOFTWARE_DESC[$software_id]='monitoring and tracking tool for Plex' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#tautulli' aSOFTWARE_DEPS[$software_id]='17' #------------------ software_id=154 aSOFTWARE_NAME[$software_id]='Roon Server' aSOFTWARE_DESC[$software_id]='Roon capable audio player and core' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#roon-server' aSOFTWARE_DEPS[$software_id]='1 5 7' # x86_64 only: https://help.roonlabs.com/portal/en/kb/articles/linux-install (( $G_HW_ARCH == 10 )) || aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,$G_HW_ARCH]=0 #------------------ software_id=159 aSOFTWARE_NAME[$software_id]='Allo GUI full' aSOFTWARE_DESC[$software_id]='Audiophile web interface with all dependencies' aSOFTWARE_CATX[$software_id]=-1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/forum/t/dietpi-allo-com-web-gui-image/1523' aSOFTWARE_DEPS[$software_id]='36 37 88 89 96 128 129 152 160 163 webserver' # Roon Bridge is not supported on ARMv6 and RISC-V (( $G_HW_ARCH == 1 || $G_HW_ARCH == 11 )) || aSOFTWARE_DEPS[$software_id]+=' 121' # Netdata not available on Trixie (( $G_DISTRO > 7 )) || aSOFTWARE_DEPS[$software_id]+=' 65' # NAA Daemon not available for ARMv6/7 Trixie and RISC-V (( $G_HW_ARCH < 3 && $G_DISTRO > 7 || $G_HW_ARCH == 11 )) || aSOFTWARE_DEPS[$software_id]+=' 124' #------------------ software_id=160 aSOFTWARE_NAME[$software_id]='Allo GUI' aSOFTWARE_DESC[$software_id]='Audiophile web interface without dependencies' aSOFTWARE_CATX[$software_id]=-1 #------------------ software_id=163 aSOFTWARE_NAME[$software_id]='GMediaRender' aSOFTWARE_DESC[$software_id]='Resource efficient UPnP/DLNA renderer' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#gmediarender' aSOFTWARE_DEPS[$software_id]='5 152' #------------------ software_id=167 aSOFTWARE_NAME[$software_id]='Raspotify' aSOFTWARE_DESC[$software_id]='A Spotify Connect client that mostly Just Works™' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#raspotify' aSOFTWARE_DEPS[$software_id]='5 152' # - Bookworm/Trixie on ARMv6 (older package): "/usr/bin/librespot: error while loading shared libraries: ld-linux.so.3: cannot open shared object file: No such file or directory" (( $G_HW_ARCH == 1 && $G_DISTRO > 6 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=80 aSOFTWARE_NAME[$software_id]='Ubooquity' aSOFTWARE_DESC[$software_id]='free home server for your comics and ebooks library' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#ubooquity' aSOFTWARE_DEPS[$software_id]='196' #------------------ software_id=179 aSOFTWARE_NAME[$software_id]='Komga' aSOFTWARE_DESC[$software_id]='free and open source comics/mangas media server with web UI' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#komga' aSOFTWARE_DEPS[$software_id]='196' #------------------ software_id=86 aSOFTWARE_NAME[$software_id]='Roon Extension Manager' aSOFTWARE_DESC[$software_id]='manage extensions from within Roon' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#roon-extension-manager' aSOFTWARE_DEPS[$software_id]='162' # - ARMv6 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 #------------------ software_id=178 aSOFTWARE_NAME[$software_id]='Jellyfin' aSOFTWARE_DESC[$software_id]='FOSS web interface media streaming server' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#jellyfin' # - ARMv6: https://github.com/jellyfin/jellyfin/issues/5011 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - RISC-V: https://repo.jellyfin.org/?path=/server/debian/latest-unstable aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 # - ARMv7 Trixie: https://repo.jellyfin.org/?path=/server/debian/latest-stable/armhf (( $G_HW_ARCH == 2 && $G_DISTRO > 7 )) && aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,2]=0 #------------------ software_id=190 aSOFTWARE_NAME[$software_id]='Beets' aSOFTWARE_DESC[$software_id]='music organizer and manager' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#beets' #------------------ software_id=191 aSOFTWARE_NAME[$software_id]='Snapcast Server' aSOFTWARE_DESC[$software_id]='Multiroom audio server' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#snapcast-server' aSOFTWARE_DEPS[$software_id]='5' #------------------ software_id=192 aSOFTWARE_NAME[$software_id]='Snapcast Client' aSOFTWARE_DESC[$software_id]='Multiroom audio client' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#snapcast-client' aSOFTWARE_DEPS[$software_id]='5' #------------------ software_id=199 aSOFTWARE_NAME[$software_id]='Spotifyd' aSOFTWARE_DESC[$software_id]='Open source Spotify client running as UNIX daemon' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#spotifyd' aSOFTWARE_DEPS[$software_id]='5' # - RISC-V: No archive: https://github.com/Spotifyd/spotifyd/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=204 aSOFTWARE_NAME[$software_id]='Navidrome' aSOFTWARE_DESC[$software_id]='Web interface media streaming server' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#navidrome' aSOFTWARE_DEPS[$software_id]='5 7' # - RISC-V: https://github.com/navidrome/navidrome/releases/ aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=212 aSOFTWARE_NAME[$software_id]='Kavita' aSOFTWARE_DESC[$software_id]='open source comics/mangas/ebooks media server with web reader' aSOFTWARE_CATX[$software_id]=2 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/media/#kavita' # - ARMv6: ARM binaries are ARMv7+ Only aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - No RISC-V support yet: https://github.com/Kareadita/Kavita/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 # BitTorrent & Download #-------------------------------------------------------------------------------- software_id=44 aSOFTWARE_NAME[$software_id]='Transmission' aSOFTWARE_DESC[$software_id]='BitTorrent server with web interface (C)' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#transmission' #------------------ software_id=45 aSOFTWARE_NAME[$software_id]='Deluge' aSOFTWARE_DESC[$software_id]='BitTorrent server with web interface (Python)' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#deluge' #------------------ software_id=46 aSOFTWARE_NAME[$software_id]='qBittorrent' aSOFTWARE_DESC[$software_id]='BitTorrent server with web interface (C++)' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#qbittorrent' #------------------ software_id=107 aSOFTWARE_NAME[$software_id]='rTorrent' aSOFTWARE_DESC[$software_id]='BitTorrent server (C++) with rutorrent web interface (PHP)' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#rtorrent' aSOFTWARE_DEPS[$software_id]='89 170 webserver' #------------------ software_id=116 aSOFTWARE_NAME[$software_id]='Medusa' aSOFTWARE_DESC[$software_id]='Automatic video library manager for TV shows' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#medusa' aSOFTWARE_DEPS[$software_id]='170' # - Trixie: Outstanding Python 3.13 support: https://github.com/pymedusa/Medusa/pull/11967 aSOFTWARE_AVAIL_G_DISTRO[$software_id,8]=0 #------------------ software_id=132 aSOFTWARE_NAME[$software_id]='Aria2' aSOFTWARE_DESC[$software_id]='Download manager with web interface' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#arias' aSOFTWARE_DEPS[$software_id]='87 89 webserver' #------------------ software_id=139 aSOFTWARE_NAME[$software_id]='SABnzbd' aSOFTWARE_DESC[$software_id]='NZB download manager' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#sabnzbd' aSOFTWARE_DEPS[$software_id]='130 170' #------------------ software_id=144 aSOFTWARE_NAME[$software_id]='Sonarr' aSOFTWARE_DESC[$software_id]='Automatically download TV shows' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#sonarr' aSOFTWARE_DEPS[$software_id]='87' (( $G_HW_ARCH == 1 )) && aSOFTWARE_DEPS[$software_id]+=' 150' # - RISC-V: https://github.com/Sonarr/Sonarr/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=145 aSOFTWARE_NAME[$software_id]='Radarr' aSOFTWARE_DESC[$software_id]='Automatically download movies' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#radarr' aSOFTWARE_DEPS[$software_id]='87' (( $G_HW_ARCH == 1 )) && aSOFTWARE_DEPS[$software_id]+=' 150' # - RISC-V: https://github.com/Radarr/Radarr/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=106 aSOFTWARE_NAME[$software_id]='Lidarr' aSOFTWARE_DESC[$software_id]='Automatically download music' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#lidarr' aSOFTWARE_DEPS[$software_id]='87' (( $G_HW_ARCH == 1 )) && aSOFTWARE_DEPS[$software_id]+=' 150' # - RISC-V: https://github.com/Lidarr/Lidarr/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=180 aSOFTWARE_NAME[$software_id]='Bazarr' aSOFTWARE_DESC[$software_id]='Automatically download subtitles' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#bazarr' aSOFTWARE_DEPS[$software_id]='130' # FFmpeg x86_64 binaries are shipped with Bazarr: https://github.com/morpheus65535/bazarr-binaries/tree/master/bin/Linux/x86_64/ffmpeg (( $G_HW_ARCH == 10 )) || aSOFTWARE_DEPS[$software_id]+=' 7' # UnRAR x86_64 and ARMv8 binaries are shipped with Bazarr, ARMv6 needs to use "unar": https://github.com/morpheus65535/bazarr-binaries/tree/master/bin/Linux, https://github.com/morpheus65535/bazarr/issues/2172 (( $G_HW_ARCH == 2 || $G_HW_ARCH == 11 )) && aSOFTWARE_DEPS[$software_id]+=' 170' #------------------ software_id=147 aSOFTWARE_NAME[$software_id]='Jackett' aSOFTWARE_DESC[$software_id]='API support for your torrent trackers' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#jackett' (( $G_HW_ARCH == 1 )) && aSOFTWARE_DEPS[$software_id]='150' # - RISC-V: https://github.com/Jackett/Jackett/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=149 aSOFTWARE_NAME[$software_id]='NZBGet' aSOFTWARE_DESC[$software_id]='NZB download manager' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#nzbget' #------------------ software_id=151 aSOFTWARE_NAME[$software_id]='Prowlarr' aSOFTWARE_DESC[$software_id]='Indexer manager & proxy for PVR' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#prowlarr' aSOFTWARE_DEPS[$software_id]='87' # - ARMv6 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - RISC-V: https://github.com/Prowlarr/Prowlarr/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=203 aSOFTWARE_NAME[$software_id]='Readarr' aSOFTWARE_DESC[$software_id]='Ebook and audiobook collection manager' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#readarr' aSOFTWARE_DEPS[$software_id]='87' # - ARMv6 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - RISC-V: https://github.com/Readarr/Readarr/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=155 aSOFTWARE_NAME[$software_id]='HTPC Manager' aSOFTWARE_DESC[$software_id]='Manage your HTPC from anywhere' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#htpc-manager' aSOFTWARE_DEPS[$software_id]='17 130' #------------------ software_id=195 aSOFTWARE_NAME[$software_id]='youtube-dl' aSOFTWARE_DESC[$software_id]='Download videos from YouTube and other sites (using yt-dlp fork)' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/bittorrent/#youtube-dl' aSOFTWARE_DEPS[$software_id]='7' #------------------ software_id=169 aSOFTWARE_NAME[$software_id]='LazyLibrarian' aSOFTWARE_DESC[$software_id]='Ebook and audiobook collection manager' aSOFTWARE_CATX[$software_id]=3 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/' # TBD: add docs aSOFTWARE_DEPS[$software_id]='130' # Cloud & Backup #-------------------------------------------------------------------------------- software_id=47 aSOFTWARE_NAME[$software_id]='ownCloud' aSOFTWARE_DESC[$software_id]='File sync, sharing and collaboration platform' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#owncloud' aSOFTWARE_DEPS[$software_id]='88 89 91 webserver' # - Bookworm/Trixie: No PHP 8.x support yet (( $G_DISTRO > 6 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=114 aSOFTWARE_NAME[$software_id]='Nextcloud' aSOFTWARE_DESC[$software_id]='File sync, sharing and collaboration platform' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#nextcloud' aSOFTWARE_DEPS[$software_id]='88 89 91 webserver' #------------------ software_id=168 aSOFTWARE_NAME[$software_id]='Nextcloud Talk' aSOFTWARE_DESC[$software_id]='Video calls with configured Coturn server' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#nextcloud-talk' aSOFTWARE_DEPS[$software_id]='114' #------------------ software_id=48 aSOFTWARE_NAME[$software_id]='Pydio' aSOFTWARE_DESC[$software_id]='Feature-rich backup and sync server' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#pydio' aSOFTWARE_DEPS[$software_id]='88 89 webserver' # - Bookworm/Trixie: No support for PHP 8: https://github.com/MichaIng/DietPi/issues/3469 (( $G_DISTRO > 6 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=111 aSOFTWARE_NAME[$software_id]='UrBackup Server' aSOFTWARE_DESC[$software_id]='Full system backup server' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#urbackup' # - Trixie all but ARMv8: depends on libcurl3-nss resp. libcurl3-gnutls (( $G_DISTRO < 8 || $G_HW_ARCH == 3 )) || aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 # - ARMv6 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - RISC-V: https://www.urbackup.org/download.html#server_debian aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=49 aSOFTWARE_NAME[$software_id]='Gogs' aSOFTWARE_DESC[$software_id]='Personal Git server with web interface' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#gogs' aSOFTWARE_DEPS[$software_id]='17 88 0' aSOFTWARE_CONFLICTS[$software_id]='165 177' #------------------ software_id=50 aSOFTWARE_NAME[$software_id]='Syncthing' aSOFTWARE_DESC[$software_id]='Backup and sync server with web interface' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#syncthing' #------------------ software_id=158 aSOFTWARE_NAME[$software_id]='MinIO' aSOFTWARE_DESC[$software_id]='S3 compatible distributed object server' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#minio' # - RISC-V: https://dl.minio.io/server/minio/release/ aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=161 aSOFTWARE_NAME[$software_id]='FuguHub' aSOFTWARE_DESC[$software_id]='Lightweight WebDAV cloud with a CMS, album and blog integration' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#fuguhub' # - ARMv8 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,3]=0 # - RISC-V: https://fuguhub.com/download.lsp aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=165 aSOFTWARE_NAME[$software_id]='Gitea' aSOFTWARE_DESC[$software_id]='Git with a cup of tea' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#gitea' aSOFTWARE_DEPS[$software_id]='17 88 0' aSOFTWARE_CONFLICTS[$software_id]='49 177' #------------------ software_id=177 aSOFTWARE_NAME[$software_id]='Forgejo' aSOFTWARE_DESC[$software_id]='Self-hosted lightweight software forge. Fork of Gitea.' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#forgejo' aSOFTWARE_DEPS[$software_id]='17 88 0' aSOFTWARE_CONFLICTS[$software_id]='49 165' # - RISC-V: https://codeberg.org/forgejo/forgejo/releases aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=183 aSOFTWARE_NAME[$software_id]='vaultwarden' aSOFTWARE_DESC[$software_id]='Unofficial Bitwarden password manager server written in Rust' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#vaultwarden' aSOFTWARE_DEPS[$software_id]='87' #------------------ software_id=198 aSOFTWARE_NAME[$software_id]='File Browser' aSOFTWARE_DESC[$software_id]='web based file manager' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#filebrowser' #------------------ software_id=202 aSOFTWARE_NAME[$software_id]='Rclone' aSOFTWARE_DESC[$software_id]='Utility to sync your files to cloud storages' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#rclone' #------------------ software_id=209 aSOFTWARE_NAME[$software_id]='Restic' aSOFTWARE_DESC[$software_id]='Fast, efficient and secure command-line backup program' aSOFTWARE_CATX[$software_id]=4 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#restic' # Gaming & Emulation #-------------------------------------------------------------------------------- software_id=108 aSOFTWARE_NAME[$software_id]='Amiberry' aSOFTWARE_DESC[$software_id]='Optimised Amiga emulator for multiple platforms' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#amiberry' aSOFTWARE_DEPS[$software_id]='5' #------------------ software_id=10 aSOFTWARE_NAME[$software_id]='Amiberry-Lite' aSOFTWARE_DESC[$software_id]='Optimised Amiga emulator recommended for smaller ARM/RISC-V SBCs' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#amiberry-lite' aSOFTWARE_DEPS[$software_id]='5' # - ARMv6: Compile error: "selected processor does not support `ubfx r5,r2,...' in ARM mode" aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 #------------------ software_id=51 aSOFTWARE_NAME[$software_id]='OpenTyrian' aSOFTWARE_DESC[$software_id]='a classic retro game, addictive' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#opentyrian' aSOFTWARE_DEPS[$software_id]='5 6' # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 # - ARMv8 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,3]=0 #------------------ software_id=112 aSOFTWARE_NAME[$software_id]='DXX-Rebirth' aSOFTWARE_DESC[$software_id]='Descent 1/2' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#dxx-rebirth' aSOFTWARE_DEPS[$software_id]='5' # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 # - ARMv8 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,3]=0 #------------------ software_id=52 aSOFTWARE_NAME[$software_id]='Cuberite' aSOFTWARE_DESC[$software_id]='Minecraft server with web interface (C++)' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#cuberite' # - RISC-V: https://cuberite.org/ aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=53 aSOFTWARE_NAME[$software_id]='MineOS' aSOFTWARE_DESC[$software_id]='Minecraft servers with web interface (Java/Node.js)' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#mineos' aSOFTWARE_DEPS[$software_id]='9 17 196' #------------------ software_id=156 aSOFTWARE_NAME[$software_id]='Steam' aSOFTWARE_DESC[$software_id]='Valve gaming platform client' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#steam' aSOFTWARE_DEPS[$software_id]='5 6 desktop' # Box86 required on ARM (( $G_HW_ARCH == 2 )) && aSOFTWARE_DEPS[$software_id]+=' 62' # x86_64 and ARMv7 only aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,3]=0 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=164 aSOFTWARE_NAME[$software_id]='Nukkit' aSOFTWARE_DESC[$software_id]='A nuclear-powered server for Minecraft Pocket Edition' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#nukkit' aSOFTWARE_DEPS[$software_id]='196' #------------------ software_id=181 aSOFTWARE_NAME[$software_id]='PaperMC' aSOFTWARE_DESC[$software_id]='Highly optimised Minecraft server with plugins, written in Java' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#papermc' aSOFTWARE_DEPS[$software_id]='196' # Allow unattended installs if EULA has been accepted already [[ -f '/mnt/dietpi_userdata/papermc/eula.txt' ]] || aSOFTWARE_INTERACTIVE[$software_id]=1 #------------------ software_id=62 aSOFTWARE_NAME[$software_id]='Box86' aSOFTWARE_DESC[$software_id]='x86 userspace emulation' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#box86' # ARMv7 only (( $G_HW_ARCH == 2 )) || aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,$G_HW_ARCH]=0 #------------------ software_id=197 aSOFTWARE_NAME[$software_id]='Box64' aSOFTWARE_DESC[$software_id]='x86_64 userspace emulation' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#box64' # ARMv8 and RISC-V only aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,2]=0 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,10]=0 #------------------ software_id=207 aSOFTWARE_NAME[$software_id]='Moonlight (CLI)' aSOFTWARE_DESC[$software_id]='CLI game streaming client for Sunshine and NVIDIA GameStream' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#moonlight-cli' # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 # - ARMv6: https://github.com/moonlight-stream/moonlight-embedded/issues/832 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - Trixie on ARMv7: There is no Trixie suite yet, and the Bookworm packages depend on libssl3. On Trixie, libssl3t64 is provided instead, but it "provides" libssl3 for 64-bit only. The 64-bit time_t transition to prevent year 2038 problems is relevant for 32-bit systems only. So for 64-bit systems, libssl3t64 equals libssl3, and the package name has been changed only to align with the 32-bit one. (( $G_DISTRO > 7 && $G_HW_ARCH < 3 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=208 aSOFTWARE_NAME[$software_id]='Moonlight (GUI)' aSOFTWARE_DESC[$software_id]='GUI game streaming client for Sunshine and NVIDIA GameStream' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#moonlight-gui' # - ARMv6: https://github.com/moonlight-stream/moonlight-embedded/issues/832 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - x86_64 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,10]=0 # - Trixie on ARMv7: There is no Trixie suite yet, and the Bookworm packages depend on libssl3. On Trixie, libssl3t64 is provided instead, but it "provides" libssl3 for 64-bit only. The 64-bit time_t transition to prevent year 2038 problems is relevant for 32-bit systems only. So for 64-bit systems, libssl3t64 equals libssl3, and the package name has been changed only to align with the 32-bit one. (( $G_DISTRO > 7 && $G_HW_ARCH < 3 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=11 aSOFTWARE_NAME[$software_id]='GZDoom' aSOFTWARE_DESC[$software_id]='Modder-friendly OpenGL and Vulkan source port based on the DOOM engine' aSOFTWARE_CATX[$software_id]=5 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/gaming/#gzdoom' aSOFTWARE_DEPS[$software_id]='5' # - ARMv6/7: https://github.com/ZDoom/gzdoom/commit/1dedcee aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,2]=0 # Social & Search #-------------------------------------------------------------------------------- software_id=54 aSOFTWARE_NAME[$software_id]='phpBB' aSOFTWARE_DESC[$software_id]='bulletin board forum software' aSOFTWARE_CATX[$software_id]=6 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/social/#phpbb' aSOFTWARE_DEPS[$software_id]='88 89 webserver' #------------------ software_id=55 aSOFTWARE_NAME[$software_id]='WordPress' aSOFTWARE_DESC[$software_id]='website blog and publishing platform' aSOFTWARE_CATX[$software_id]=6 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/social/#wordpress' aSOFTWARE_DEPS[$software_id]='88 89 webserver' #------------------ software_id=38 aSOFTWARE_NAME[$software_id]='FreshRSS' aSOFTWARE_DESC[$software_id]='self-hosted RSS feed aggregator' aSOFTWARE_CATX[$software_id]=6 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/social/#freshrss' aSOFTWARE_DEPS[$software_id]='88 89 webserver' #------------------ software_id=56 aSOFTWARE_NAME[$software_id]='Single File PHP Gallery' aSOFTWARE_DESC[$software_id]='Website to host and browse your images' aSOFTWARE_CATX[$software_id]=6 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/social/#single-file-php-gallery' aSOFTWARE_DEPS[$software_id]='89 webserver' #------------------ software_id=57 aSOFTWARE_NAME[$software_id]='Baïkal' aSOFTWARE_DESC[$software_id]='lightweight caldav + carddav server' aSOFTWARE_CATX[$software_id]=6 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/social/#baikal' aSOFTWARE_DEPS[$software_id]='88 89 webserver' #------------------ software_id=125 aSOFTWARE_NAME[$software_id]='Synapse' aSOFTWARE_DESC[$software_id]='Matrix homeserver implementation' aSOFTWARE_CATX[$software_id]=6 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/social/#synapse' aSOFTWARE_DEPS[$software_id]='130 194' #----------------- software_id=16 aSOFTWARE_NAME[$software_id]='microblog.pub' aSOFTWARE_DESC[$software_id]='A self-hosted, single-user, ActivityPub powered microblog.' aSOFTWARE_CATX[$software_id]=6 aSOFTWARE_DEPS[$software_id]='17' aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/social/#microblogpub' #------------------ software_id=210 aSOFTWARE_NAME[$software_id]='MediaWiki' aSOFTWARE_DESC[$software_id]='A collaboration and documentation platform' aSOFTWARE_CATX[$software_id]=6 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/social/#mediawiki' aSOFTWARE_DEPS[$software_id]='88 89 webserver' #------------------ software_id=213 aSOFTWARE_NAME[$software_id]='soju' aSOFTWARE_DESC[$software_id]='A user-friendly IRC bouncer' aSOFTWARE_CATX[$software_id]=6 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/social/#soju' aSOFTWARE_DEPS[$software_id]='188' # Camera & Surveillance #-------------------------------------------------------------------------------- software_id=59 aSOFTWARE_NAME[$software_id]='RPi Cam Web Interface' aSOFTWARE_DESC[$software_id]='Web interface & controls for your RPi camera module' aSOFTWARE_CATX[$software_id]=7 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/camera/#rpi-cam-web-interface' aSOFTWARE_DEPS[$software_id]='89 webserver' # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 # - ARMv8: https://github.com/silvanmelchior/RPi_Cam_Web_Interface/tree/master/bin aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,3]=0 # - Bookworm: raspimjpeg depends on legacy MMAL, removed from RPi userland libs since Bookworm (( $G_DISTRO > 6 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=136 aSOFTWARE_NAME[$software_id]='motionEye' aSOFTWARE_DESC[$software_id]='Web interface & surveillance for your camera' aSOFTWARE_CATX[$software_id]=7 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/camera/#motioneye' aSOFTWARE_DEPS[$software_id]='7 130' #------------------ software_id=137 aSOFTWARE_NAME[$software_id]='mjpg-streamer' aSOFTWARE_DESC[$software_id]='Simple camera streaming tool with HTML plugin' aSOFTWARE_CATX[$software_id]=7 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/camera/#mjpg-streamer' # System Stats & Management #-------------------------------------------------------------------------------- software_id=3 aSOFTWARE_NAME[$software_id]='MC' aSOFTWARE_DESC[$software_id]='Midnight Commander - a powerful file manager' aSOFTWARE_CATX[$software_id]=8 #------------------ software_id=63 aSOFTWARE_NAME[$software_id]='LinuxDash' aSOFTWARE_DESC[$software_id]='web interface system stats' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#linuxdash' aSOFTWARE_DEPS[$software_id]='89 webserver' #------------------ software_id=64 aSOFTWARE_NAME[$software_id]='phpSysInfo' aSOFTWARE_DESC[$software_id]='web interface system stats' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#phpsysinfo' aSOFTWARE_DEPS[$software_id]='89 webserver' #------------------ software_id=65 aSOFTWARE_NAME[$software_id]='Netdata' aSOFTWARE_DESC[$software_id]='real-time performance monitoring' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#netdata' # - Trixie: https://bugs.debian.org/1107082 (( $G_DISTRO > 7 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=66 aSOFTWARE_NAME[$software_id]='RPi-Monitor' aSOFTWARE_DESC[$software_id]='Web interface for Raspberry Pi real-time monitoring' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#rpi-monitor' # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 #------------------ software_id=115 aSOFTWARE_NAME[$software_id]='Webmin' aSOFTWARE_DESC[$software_id]='web interface system management' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#webmin' #------------------ software_id=162 aSOFTWARE_NAME[$software_id]='Docker' aSOFTWARE_DESC[$software_id]='Build, ship, and run distributed applications' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#docker' #------------------ software_id=185 aSOFTWARE_NAME[$software_id]='Portainer' aSOFTWARE_DESC[$software_id]='Simplifies container management in Docker (standalone host)' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#portainer' aSOFTWARE_DEPS[$software_id]='162' # - ARMv6: https://dietpi.com/forum/t/16380/11 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 #------------------ software_id=134 aSOFTWARE_NAME[$software_id]='Docker Compose' aSOFTWARE_DESC[$software_id]='Manage multi-container Docker applications' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#docker-compose' aSOFTWARE_DEPS[$software_id]='162' #------------------ software_id=193 aSOFTWARE_NAME[$software_id]='K3s' aSOFTWARE_DESC[$software_id]='The certified Kubernetes distribution built for IoT & Edge computing' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#k3s' # - RISC-V: Not yet supported: https://get.k3s.io/ aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=142 aSOFTWARE_NAME[$software_id]='MicroK8s' aSOFTWARE_DESC[$software_id]='The simplest production-grade upstream K8s, light and focused' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/cloud/#microk8s' # - ARMv6/7/RISC-V: https://snapcraft.io/microk8s (( $G_HW_ARCH == 3 || $G_HW_ARCH == 10 )) || aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,$G_HW_ARCH]=0 #------------------ software_id=200 aSOFTWARE_NAME[$software_id]='DietPi-Dashboard' aSOFTWARE_DESC[$software_id]='Official lightweight DietPi web interface (Rust)' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#dietpi-dashboard' #------------------ software_id=99 aSOFTWARE_NAME[$software_id]='Prometheus Node Exporter' aSOFTWARE_DESC[$software_id]='Prometheus exporter for hardware and OS metrics' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#prometheus_node_exporter' #------------------ software_id=205 aSOFTWARE_NAME[$software_id]='Homer' aSOFTWARE_DESC[$software_id]='Simple HOMepage for your servER to keep your services on hand' aSOFTWARE_CATX[$software_id]=8 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_stats/#homer' aSOFTWARE_DEPS[$software_id]='webserver' # Remote Access #-------------------------------------------------------------------------------- software_id=68 aSOFTWARE_NAME[$software_id]='Remote.It' aSOFTWARE_DESC[$software_id]='Provides secure connections to your networked devices' aSOFTWARE_CATX[$software_id]=9 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/remote_desktop/#remot3it' # - RISC-V: https://www.remote.it/download-list aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=138 aSOFTWARE_NAME[$software_id]='VirtualHere' aSOFTWARE_DESC[$software_id]='server: share USB devices over the network' aSOFTWARE_CATX[$software_id]=9 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/remote_desktop/#virtualhere' aSOFTWARE_DEPS[$software_id]='152' # - RISC-V: https://github.com/virtualhere/script/blob/main/install_server aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 # Hardware Projects #-------------------------------------------------------------------------------- software_id=69 aSOFTWARE_NAME[$software_id]='Python 3 RPi.GPIO' aSOFTWARE_DESC[$software_id]='Control Raspberry Pi GPIO channels in Python 3' aSOFTWARE_CATX[$software_id]=10 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/hardware_projects/#rpigpio' # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 #------------------ software_id=70 aSOFTWARE_NAME[$software_id]='WiringPi' aSOFTWARE_DESC[$software_id]='GPIO interface library (C)' aSOFTWARE_CATX[$software_id]=10 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/hardware_projects/#wiringpi' # RPi, Odroids and Orange Pi only (( $G_HW_MODEL > 19 )) && [[ ! $G_HW_MODEL =~ ^(80|82|83|87|88|89|91|93|94|95|96|97|98)$ ]] && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 #------------------ software_id=71 aSOFTWARE_NAME[$software_id]='WebIOPi' aSOFTWARE_DESC[$software_id]='Web interface to control RPi GPIO channels' aSOFTWARE_CATX[$software_id]=10 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/hardware_projects/#webiopi' aSOFTWARE_DEPS[$software_id]='69' # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 #------------------ software_id=72 aSOFTWARE_NAME[$software_id]='I2C' aSOFTWARE_DESC[$software_id]='enables support for I2C based hardware' aSOFTWARE_CATX[$software_id]=10 # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 #------------------ software_id=100 aSOFTWARE_NAME[$software_id]='PiJuice' aSOFTWARE_DESC[$software_id]='pisupply ups' aSOFTWARE_CATX[$software_id]=10 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/hardware_projects/#pijuice' aSOFTWARE_DEPS[$software_id]='72' # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 #------------------ software_id=122 aSOFTWARE_NAME[$software_id]='Node-RED' aSOFTWARE_DESC[$software_id]='tool for wiring devices, APIs and online services' aSOFTWARE_CATX[$software_id]=10 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/hardware_projects/#node-red' aSOFTWARE_DEPS[$software_id]='9' (( $G_HW_MODEL > 9 )) || aSOFTWARE_DEPS[$software_id]+=' 69' #------------------ software_id=123 aSOFTWARE_NAME[$software_id]='Mosquitto' aSOFTWARE_DESC[$software_id]='MQTT messaging broker' aSOFTWARE_CATX[$software_id]=10 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/hardware_projects/#mosquitto' #------------------ software_id=131 aSOFTWARE_NAME[$software_id]='Blynk Server' aSOFTWARE_DESC[$software_id]='msg controller for blynk mobile app and sbcs' aSOFTWARE_CATX[$software_id]=10 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/hardware_projects/#blynk-server' aSOFTWARE_DEPS[$software_id]='196 9' #------------------ software_id=166 aSOFTWARE_NAME[$software_id]='Audiophonics PI-SPC' aSOFTWARE_DESC[$software_id]='Raspberry Pi power management module' aSOFTWARE_CATX[$software_id]=10 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/hardware_projects/#audiophonics-pi-spc' aSOFTWARE_DEPS[$software_id]='70' # RPi only (( $G_HW_MODEL > 9 )) && aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 #------------------ software_id=77 aSOFTWARE_NAME[$software_id]='Grafana' aSOFTWARE_DESC[$software_id]='platform for analytics and monitoring' aSOFTWARE_CATX[$software_id]=10 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/hardware_projects/#grafana' # - RISC-V: https://apt.grafana.com/dists/stable/main/binary-riscv64/Packages aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 # System Security #-------------------------------------------------------------------------------- software_id=73 aSOFTWARE_NAME[$software_id]='Fail2Ban' aSOFTWARE_DESC[$software_id]='prevents brute-force attacks with ip ban' aSOFTWARE_CATX[$software_id]=11 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_security/#fail2ban' #------------------ software_id=92 aSOFTWARE_NAME[$software_id]='Certbot' aSOFTWARE_DESC[$software_id]="Obtain and renew Let's Encrypt SSL certs for HTTPS" aSOFTWARE_CATX[$software_id]=11 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system_security/#lets-encrypt' # Webserver Stacks #-------------------------------------------------------------------------------- software_id=75 aSOFTWARE_NAME[$software_id]='LASP' aSOFTWARE_DESC[$software_id]='Apache + SQLite + PHP' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#lasp-web-stack' aSOFTWARE_DEPS[$software_id]='83 87 89' aSOFTWARE_CONFLICTS[$software_id]='78 79 81 82 84 85' aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,70]=0 #------------------ software_id=76 aSOFTWARE_NAME[$software_id]='LAMP' aSOFTWARE_DESC[$software_id]='Apache + MariaDB + PHP' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#lamp-web-stack' aSOFTWARE_DEPS[$software_id]='83 88 89' aSOFTWARE_CONFLICTS[$software_id]='78 79 81 82 84 85' aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,70]=0 #------------------ software_id=78 aSOFTWARE_NAME[$software_id]='LESP' aSOFTWARE_DESC[$software_id]='Nginx + SQLite + PHP' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#lesp-web-stack' aSOFTWARE_DEPS[$software_id]='85 87 89' aSOFTWARE_CONFLICTS[$software_id]='75 76 81 82 83 84' #------------------ software_id=79 aSOFTWARE_NAME[$software_id]='LEMP' aSOFTWARE_DESC[$software_id]='Nginx + MariaDB + PHP' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#lemp-web-stack' aSOFTWARE_DEPS[$software_id]='85 88 89' aSOFTWARE_CONFLICTS[$software_id]='75 76 81 82 83 84' #------------------ software_id=81 aSOFTWARE_NAME[$software_id]='LLSP' aSOFTWARE_DESC[$software_id]='Lighttpd + SQLite + PHP' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#llsp-web-stack' aSOFTWARE_DEPS[$software_id]='84 87 89' aSOFTWARE_CONFLICTS[$software_id]='75 76 78 79 83 85' #------------------ software_id=82 aSOFTWARE_NAME[$software_id]='LLMP' aSOFTWARE_DESC[$software_id]='Lighttpd + MariaDB + PHP' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#llmp-web-stack' aSOFTWARE_DEPS[$software_id]='84 88 89' aSOFTWARE_CONFLICTS[$software_id]='75 76 78 79 83 85' #------------------ software_id=83 aSOFTWARE_NAME[$software_id]='Apache' aSOFTWARE_DESC[$software_id]='Popular webserver' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#apache2' aSOFTWARE_CONFLICTS[$software_id]='78 79 81 82 84 85' aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,70]=0 #------------------ software_id=84 aSOFTWARE_NAME[$software_id]='Lighttpd' aSOFTWARE_DESC[$software_id]='Extremely lightweight webserver' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#lighttpd' aSOFTWARE_CONFLICTS[$software_id]='75 76 78 79 83 85' #------------------ software_id=85 aSOFTWARE_NAME[$software_id]='Nginx' aSOFTWARE_DESC[$software_id]='Lightweight webserver' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#nginx' aSOFTWARE_CONFLICTS[$software_id]='75 76 81 82 83 84' #------------------ software_id=89 aSOFTWARE_NAME[$software_id]='PHP' aSOFTWARE_DESC[$software_id]='Hypertext Preprocessor for dynamic web content' aSOFTWARE_CATX[$software_id]=12 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/webserver_stack/#php' # DNS Servers #-------------------------------------------------------------------------------- software_id=93 aSOFTWARE_NAME[$software_id]='Pi-hole' aSOFTWARE_DESC[$software_id]='block adverts for any device on your network' aSOFTWARE_CATX[$software_id]=13 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/dns_servers/#pi-hole' aSOFTWARE_DEPS[$software_id]='17' aSOFTWARE_INTERACTIVE[$software_id]=1 aSOFTWARE_CONFLICTS[$software_id]='126' #------------------ software_id=126 aSOFTWARE_NAME[$software_id]='AdGuard Home' aSOFTWARE_DESC[$software_id]='powerful network-wide ads & trackers blocking DNS server' aSOFTWARE_CATX[$software_id]=13 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/dns_servers/#adguard-home' aSOFTWARE_CONFLICTS[$software_id]='93' #------------------ software_id=182 aSOFTWARE_NAME[$software_id]='Unbound' aSOFTWARE_DESC[$software_id]='validating, recursive, caching DNS resolver' aSOFTWARE_CATX[$software_id]=13 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/dns_servers/#unbound' # File Servers #-------------------------------------------------------------------------------- software_id=94 aSOFTWARE_NAME[$software_id]='ProFTPD' aSOFTWARE_DESC[$software_id]='Feature-rich FTP server with Apache-like config and FTPS+SFTP modules' aSOFTWARE_CATX[$software_id]=14 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/file_servers/#proftpd' aSOFTWARE_CONFLICTS[$software_id]='95' #------------------ software_id=95 aSOFTWARE_NAME[$software_id]='vsftpd' aSOFTWARE_DESC[$software_id]='Lightweight FTP/FTPS server' aSOFTWARE_CATX[$software_id]=14 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/file_servers/#vsftpd' aSOFTWARE_CONFLICTS[$software_id]='94' #------------------ software_id=96 aSOFTWARE_NAME[$software_id]='Samba Server' aSOFTWARE_DESC[$software_id]='Feature-rich SMB/CIFS server' aSOFTWARE_CATX[$software_id]=14 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/file_servers/#samba' #------------------ software_id=109 aSOFTWARE_NAME[$software_id]='NFS Server' aSOFTWARE_DESC[$software_id]='Network File System server' aSOFTWARE_CATX[$software_id]=14 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/file_servers/#nfs' # VPN Servers #-------------------------------------------------------------------------------- software_id=97 aSOFTWARE_NAME[$software_id]='OpenVPN' aSOFTWARE_DESC[$software_id]='vpn server' aSOFTWARE_CATX[$software_id]=15 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/vpn/#openvpn' #------------------ software_id=172 aSOFTWARE_NAME[$software_id]='WireGuard' aSOFTWARE_DESC[$software_id]='an extremely simple yet fast and modern VPN' aSOFTWARE_CATX[$software_id]=15 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/vpn/#wireguard' # Requires the WireGuard kernel module: We do not support DKMS builds anymore, which were required only for legacy kernel versions, not supported by WireGuard anymore: https://dietpi.com/forum/t/15173 (( $G_HW_MODEL == 75 )) || modprobe -nq wireguard || aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]=0 #------------------ software_id=117 aSOFTWARE_NAME[$software_id]='PiVPN' aSOFTWARE_DESC[$software_id]='openvpn/wireguard server install & management tool' aSOFTWARE_CATX[$software_id]=15 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/vpn/#pivpn' aSOFTWARE_DEPS[$software_id]='17' # Require interactive install if no config file containing options for unattended install is present [[ -f '/boot/unattended_pivpn.conf' ]] || aSOFTWARE_INTERACTIVE[$software_id]=1 #------------------ software_id=58 aSOFTWARE_NAME[$software_id]='Tailscale' aSOFTWARE_DESC[$software_id]='Zero config VPN' aSOFTWARE_CATX[$software_id]=15 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/vpn/#tailscale' #----------------- software_id=201 aSOFTWARE_NAME[$software_id]='ZeroTier' aSOFTWARE_DESC[$software_id]='Free easy to deploy cloud-hosted VPN service' aSOFTWARE_CATX[$software_id]=15 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/vpn/#zerotier' # Advanced Networking #-------------------------------------------------------------------------------- software_id=60 aSOFTWARE_NAME[$software_id]='WiFi Hotspot' aSOFTWARE_DESC[$software_id]='turn your device into a WiFi hotspot' aSOFTWARE_CATX[$software_id]=16 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/advanced_networking/#wifi-hotspot' #------------------ software_id=61 aSOFTWARE_NAME[$software_id]='Tor Hotspot' aSOFTWARE_DESC[$software_id]='optional: route hotspot traffic through tor' aSOFTWARE_CATX[$software_id]=16 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/advanced_networking/#tor-hotspot' aSOFTWARE_DEPS[$software_id]='60' aSOFTWARE_CONFLICTS[$software_id]='184' #------------------ software_id=98 aSOFTWARE_NAME[$software_id]='HAProxy' aSOFTWARE_DESC[$software_id]='high performance TCP/HTTP load balancer' aSOFTWARE_CATX[$software_id]=16 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/advanced_networking/#haproxy' #------------------ software_id=152 aSOFTWARE_NAME[$software_id]='Avahi-Daemon' aSOFTWARE_DESC[$software_id]='Hostname broadcast via mDNS (Zeroconf, Bonjour)' aSOFTWARE_CATX[$software_id]=16 #------------------ software_id=171 aSOFTWARE_NAME[$software_id]='frp' aSOFTWARE_DESC[$software_id]='reverse proxy' aSOFTWARE_CATX[$software_id]=16 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/advanced_networking/#frp' # Home Automation #-------------------------------------------------------------------------------- software_id=157 aSOFTWARE_NAME[$software_id]='Home Assistant' aSOFTWARE_DESC[$software_id]='Open source home automation platform' aSOFTWARE_CATX[$software_id]=17 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/home_automation/#home-assistant' #------------------ software_id=140 aSOFTWARE_NAME[$software_id]='Domoticz' aSOFTWARE_DESC[$software_id]='Open source home automation platform' aSOFTWARE_CATX[$software_id]=17 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/home_automation/#domoticz' #------------------ software_id=27 aSOFTWARE_NAME[$software_id]='TasmoAdmin' aSOFTWARE_DESC[$software_id]='Website to manage ESP8266 devices flashed with Tasmota' aSOFTWARE_CATX[$software_id]=17 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/home_automation/#tasmoadmin' aSOFTWARE_DEPS[$software_id]='89 webserver' #------------------ software_id=206 aSOFTWARE_NAME[$software_id]='openHAB' aSOFTWARE_DESC[$software_id]='Vendor and technology agnostic FLOSS home automation software' aSOFTWARE_CATX[$software_id]=17 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/home_automation/#openhab' aSOFTWARE_DEPS[$software_id]='196' #------------------ software_id=211 aSOFTWARE_NAME[$software_id]='Homebridge' aSOFTWARE_DESC[$software_id]='Bringing HomeKit support where there is none' aSOFTWARE_CATX[$software_id]=17 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/home_automation/#homebridge' # - RISC-V: https://repo.homebridge.io/dists/stable/Release aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ # Printing #-------------------------------------------------------------------------------- software_id=153 aSOFTWARE_NAME[$software_id]='OctoPrint' aSOFTWARE_DESC[$software_id]='web interface for controlling 3d printers' aSOFTWARE_CATX[$software_id]=18 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/printing/#octoprint' aSOFTWARE_DEPS[$software_id]='130' #------------------ software_id=187 aSOFTWARE_NAME[$software_id]='CUPS' aSOFTWARE_DESC[$software_id]='common UNIX printing system' aSOFTWARE_CATX[$software_id]=18 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/printing/#cups' aSOFTWARE_DEPS[$software_id]='152' # Distributed Projects #-------------------------------------------------------------------------------- software_id=2 aSOFTWARE_NAME[$software_id]='Folding@Home' aSOFTWARE_DESC[$software_id]='Help disease research with your computing power!' aSOFTWARE_CATX[$software_id]=19 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/distributed_projects/#foldinghome' # - ARMv6/7/RISC-V: No package: https://download.foldingathome.org/releases/public/release/fahclient/ aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,2]=0 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=133 aSOFTWARE_NAME[$software_id]='YaCy' aSOFTWARE_DESC[$software_id]='decentralised open source search engine' aSOFTWARE_CATX[$software_id]=19 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/distributed_projects/#yacy' aSOFTWARE_DEPS[$software_id]='196' #------------------ software_id=141 aSOFTWARE_NAME[$software_id]='ADS-B Feeder' aSOFTWARE_DESC[$software_id]='track airplanes using SDRs and feed the data to ADS-B aggregators' aSOFTWARE_CATX[$software_id]=19 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/distributed_projects/#adsb-feeder' aSOFTWARE_DEPS[$software_id]='17 130 134 162' # Git, Python, Docker & Docker Compose #------------------ software_id=184 aSOFTWARE_NAME[$software_id]='Tor Relay' aSOFTWARE_DESC[$software_id]='add a node to the Tor network' aSOFTWARE_CATX[$software_id]=19 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/distributed_projects/#tor-relay' aSOFTWARE_CONFLICTS[$software_id]='61' #------------------ software_id=186 aSOFTWARE_NAME[$software_id]='Kubo' aSOFTWARE_DESC[$software_id]='(IPFS Node) contribute to a decentralized Internet' aSOFTWARE_CATX[$software_id]=19 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/distributed_projects/#ipfs-node' # - RISC-V: https://dist.ipfs.io/kubo/ aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 # SSH Clients #-------------------------------------------------------------------------------- software_id=0 aSOFTWARE_NAME[$software_id]='OpenSSH Client' aSOFTWARE_DESC[$software_id]='Feature-rich SSH, SFTP and SCP client' aSOFTWARE_CATX[$software_id]=20 # File Server Clients #-------------------------------------------------------------------------------- software_id=1 aSOFTWARE_NAME[$software_id]='Samba Client' aSOFTWARE_DESC[$software_id]='access SMB/CIFS/Samba network shares' aSOFTWARE_CATX[$software_id]=21 aSOFTWARE_DOCS[$software_id]=' dietpi-drive_manager > Add network drive' #------------------ software_id=110 aSOFTWARE_NAME[$software_id]='NFS Client' aSOFTWARE_DESC[$software_id]='network file system client' aSOFTWARE_CATX[$software_id]=21 aSOFTWARE_DOCS[$software_id]=' dietpi-drive_manager > Add network drive' # System #-------------------------------------------------------------------------------- software_id=5 aSOFTWARE_NAME[$software_id]='ALSA' aSOFTWARE_DESC[$software_id]='Advanced Linux Sound Architecture' aSOFTWARE_CATX[$software_id]=22 #------------------ software_id=7 aSOFTWARE_NAME[$software_id]='FFmpeg' aSOFTWARE_DESC[$software_id]='Audio & video codec library and programs' aSOFTWARE_CATX[$software_id]=22 #------------------ software_id=6 aSOFTWARE_NAME[$software_id]='X11' aSOFTWARE_DESC[$software_id]='X.Org X Window System implementation' aSOFTWARE_CATX[$software_id]=22 #------------------ software_id=170 aSOFTWARE_NAME[$software_id]='UnRAR' aSOFTWARE_DESC[$software_id]='unarchiver for .rar files' aSOFTWARE_CATX[$software_id]=22 #------------------ software_id=4 aSOFTWARE_NAME[$software_id]='fish' aSOFTWARE_DESC[$software_id]='friendly interactive shell' aSOFTWARE_CATX[$software_id]=22 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/system/#fish' # Databases & Data Stores #-------------------------------------------------------------------------------- software_id=87 aSOFTWARE_NAME[$software_id]='SQLite' aSOFTWARE_DESC[$software_id]='Persistent single-file database system' aSOFTWARE_CATX[$software_id]=23 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/databases/#sqlite' #------------------ software_id=88 aSOFTWARE_NAME[$software_id]='MariaDB' aSOFTWARE_DESC[$software_id]='Persistent cached file-per-table database server' aSOFTWARE_CATX[$software_id]=23 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/databases/#mariadb' #------------------ software_id=90 aSOFTWARE_NAME[$software_id]='phpMyAdmin' aSOFTWARE_DESC[$software_id]='Optional MariaDB web interface admin tools' aSOFTWARE_CATX[$software_id]=23 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/databases/#phpmyadmin' aSOFTWARE_DEPS[$software_id]='88 89 webserver' #------------------ software_id=91 aSOFTWARE_NAME[$software_id]='Redis' aSOFTWARE_DESC[$software_id]='Volatile in-memory non-SQL database server' aSOFTWARE_CATX[$software_id]=23 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/databases/#redis' #------------------ software_id=74 aSOFTWARE_NAME[$software_id]='InfluxDB' aSOFTWARE_DESC[$software_id]='Persistent time-series database server' aSOFTWARE_CATX[$software_id]=23 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/databases/#influxdb' #------------------ software_id=194 aSOFTWARE_NAME[$software_id]='PostgreSQL' aSOFTWARE_DESC[$software_id]='Persistent advanced object-relational database server' aSOFTWARE_CATX[$software_id]=23 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/databases/#postgresql' # Development & Programming #-------------------------------------------------------------------------------- software_id=17 aSOFTWARE_NAME[$software_id]='Git' aSOFTWARE_DESC[$software_id]='Clone and manage Git repositories locally' aSOFTWARE_CATX[$software_id]=24 #------------------ software_id=130 aSOFTWARE_NAME[$software_id]='Python 3' aSOFTWARE_DESC[$software_id]='Runtime system, pip package installer and development headers' aSOFTWARE_CATX[$software_id]=24 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/programming/#python-3' #------------------ software_id=189 aSOFTWARE_NAME[$software_id]='VSCodium' aSOFTWARE_DESC[$software_id]='FLOSS version of MS VSCode' aSOFTWARE_CATX[$software_id]=24 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/programming/#vscodium' aSOFTWARE_DEPS[$software_id]='5 6 17' # - ARMv6/7/RISC-V: https://download.vscodium.com/debs/dists/vscodium/Release aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,2]=0 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=188 aSOFTWARE_NAME[$software_id]='Go' aSOFTWARE_DESC[$software_id]='Runtime environment and package installer' aSOFTWARE_CATX[$software_id]=24 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/programming/#go' aSOFTWARE_DEPS[$software_id]='17' #------------------ software_id=8 aSOFTWARE_NAME[$software_id]='Java JDK' aSOFTWARE_DESC[$software_id]='OpenJDK Development Kit' aSOFTWARE_CATX[$software_id]=24 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/programming/#java' aSOFTWARE_DEPS[$software_id]='196' #------------------ software_id=196 aSOFTWARE_NAME[$software_id]='Java JRE' aSOFTWARE_DESC[$software_id]='OpenJDK Runtime Environment' aSOFTWARE_CATX[$software_id]=24 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/programming/#java' #------------------ software_id=9 aSOFTWARE_NAME[$software_id]='Node.js' aSOFTWARE_DESC[$software_id]='JavaScript runtime environment' aSOFTWARE_CATX[$software_id]=24 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/programming/#nodejs' #------------------ software_id=150 aSOFTWARE_NAME[$software_id]='Mono' aSOFTWARE_DESC[$software_id]='Runtime libraries and repository' aSOFTWARE_CATX[$software_id]=24 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/programming/#mono' # - RISC-V: https://download.mono-project.com/repo/debian/dists/buster/main/, https://packages.debian.org/trixie/mono-runtime aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=34 aSOFTWARE_NAME[$software_id]='PHP Composer' aSOFTWARE_DESC[$software_id]='Package manager for PHP' aSOFTWARE_CATX[$software_id]=24 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/programming/#php-composer' aSOFTWARE_DEPS[$software_id]='89' # Desktop Utilities #-------------------------------------------------------------------------------- software_id=22 aSOFTWARE_NAME[$software_id]='QuiteRSS' aSOFTWARE_DESC[$software_id]='cross-platform, free rss reader' aSOFTWARE_CATX[$software_id]=25 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#quiterss' aSOFTWARE_DEPS[$software_id]='6' # - Trixie: https://bugs.debian.org/1093725 (( $G_DISTRO > 7 )) && aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]=0 #------------------ software_id=113 aSOFTWARE_NAME[$software_id]='Chromium' aSOFTWARE_DESC[$software_id]='web browser for desktop or autostart' aSOFTWARE_CATX[$software_id]=25 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#chromium' aSOFTWARE_DEPS[$software_id]='5 6' # - ARMv6: https://github.com/RPi-Distro/chromium-browser/issues/21 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 # - RISC-V: https://packages.debian.org/trixie/chromium aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,11]=0 #------------------ software_id=67 aSOFTWARE_NAME[$software_id]='Firefox' aSOFTWARE_DESC[$software_id]='web browser for desktop' aSOFTWARE_CATX[$software_id]=25 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#firefox' aSOFTWARE_DEPS[$software_id]='5 6' # - ARMv6: https://github.com/RPi-Distro/chromium-browser/issues/21#issuecomment-997044303 aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,1]=0 #------------------ software_id=174 aSOFTWARE_NAME[$software_id]='GIMP' aSOFTWARE_DESC[$software_id]='mspaint on steroids' aSOFTWARE_CATX[$software_id]=25 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#gimp' aSOFTWARE_DEPS[$software_id]='6' #------------------ software_id=175 aSOFTWARE_NAME[$software_id]='Xfce Power Manager' aSOFTWARE_DESC[$software_id]='with brightness control, recommended for LXDE/LXQt' aSOFTWARE_CATX[$software_id]=25 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/desktop/#xfce-power-manager' aSOFTWARE_DEPS[$software_id]='6' #-------------------------------------------------------------------------------- # Logging Systems (hidden) #-------------------------------------------------------------------------------- software_id=101 aSOFTWARE_NAME[$software_id]='Logrotate' aSOFTWARE_DESC[$software_id]='Rotates and compresses old log files in /var/log' aSOFTWARE_CATX[$software_id]=-1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/log_system/#full-logging' #------------------ software_id=102 aSOFTWARE_NAME[$software_id]='Rsyslog' aSOFTWARE_DESC[$software_id]='Writes system logs (journalctl) as plain text files to /var/log' aSOFTWARE_CATX[$software_id]=-1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/log_system/#full-logging' #------------------ software_id=103 aSOFTWARE_NAME[$software_id]='DietPi-RAMlog' aSOFTWARE_DESC[$software_id]='Makes /var/log a RAM disk, preserves file structure on reboot' aSOFTWARE_CATX[$software_id]=-1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/log_system/#dietpi-ramlog' #-------------------------------------------------------------------------------- # SSH Servers (hidden) #-------------------------------------------------------------------------------- software_id=104 aSOFTWARE_NAME[$software_id]='Dropbear' aSOFTWARE_DESC[$software_id]='Lightweight SSH server' aSOFTWARE_CATX[$software_id]=-1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/ssh/#dropbear' #------------------ software_id=105 aSOFTWARE_NAME[$software_id]='OpenSSH Server' aSOFTWARE_DESC[$software_id]='Feature-rich SSH server with SFTP and SCP support' aSOFTWARE_CATX[$software_id]=-1 aSOFTWARE_DOCS[$software_id]='https://dietpi.com/docs/software/ssh/#openssh' aSOFTWARE_DEPS[$software_id]='0' #-------------------------------------------------------------------------------- # Init install state for defined software for i in "${!aSOFTWARE_NAME[@]}" do aSOFTWARE_INSTALL_STATE[$i]=0 done # - Pre-installed on DietPi images: aSOFTWARE_INSTALL_STATE[103]=2 # DietPi-RAMlog aSOFTWARE_INSTALL_STATE[104]=2 # Dropbear #-------------------------------------------------------------------------------- [[ $MACHINE_READABLE ]] || G_DIETPI-NOTIFY 0 'Initialised database' } # Unmark software installs for automated installs if user input is required Unmark_Unattended() { (( $G_INTERACTIVE )) && return for i in "${!aSOFTWARE_NAME[@]}" do if (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 && ${aSOFTWARE_INTERACTIVE[$i]:-0} == 1 )) then aSOFTWARE_INSTALL_STATE[$i]=0 G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$i]}: Install requires user input and cannot be automated." G_DIETPI-NOTIFY 1 "${aSOFTWARE_NAME[$i]}: Please run 'dietpi-software' to install manually." fi done } # Unmark all dependants of a software title # $1: software ID Unmark_Dependants() { aSOFTWARE_INSTALL_STATE[$1]=0 local i for i in "${!aSOFTWARE_NAME[@]}" do # NB: This does not work for dependencies given as "webserver", "desktop" or "browser". However, there are no conflicts among desktops and browser, and webservers only conflict with other webservers, hence obviously one is installed already which satisfies the dependency. [[ ${aSOFTWARE_INSTALL_STATE[$i]} == 1 && ${aSOFTWARE_DEPS[$i]} =~ (^|[[:blank:]])$1([[:blank:]]|$) ]] || continue aSOFTWARE_INSTALL_STATE[$i]=0 [[ $dependants_text ]] || dependants_text='\n\nThe following dependants will be unmarked as well:' dependants_text+="\n\n - ${aSOFTWARE_NAME[$i]}: It depends on ${aSOFTWARE_NAME[$1]}." # Recursive call to unmark all dependants of this dependant Unmark_Dependants "$i" done } # Unmark conflicting software titles CONFLICTS_RESOLVED=0 Unmark_Conflicts() { # Loop through marked software local i j unmarked_text dependants_text for i in "${!aSOFTWARE_NAME[@]}" do (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) || continue # Loop through installed or marked conflicts for j in ${aSOFTWARE_CONFLICTS[$i]} do (( ${aSOFTWARE_INSTALL_STATE[$j]} > 0 )) || continue # At least one conflict is installed or marked: Unmark software (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) && { unmarked_text+="\n\n${aSOFTWARE_NAME[$i]} won't be installed, as it conflicts with:"; Unmark_Dependants "$i"; } # Unmark all marked conflicts if (( ${aSOFTWARE_INSTALL_STATE[$j]} == 1 )) then unmarked_text+="\n\n - ${aSOFTWARE_NAME[$j]}: It won't be installed either." Unmark_Dependants "$j" else unmarked_text+="\n\n - ${aSOFTWARE_NAME[$j]}: It is installed already." fi done done CONFLICTS_RESOLVED=1 [[ $unmarked_text ]] || return 0 # Conflicts have been unmarked: Inform user! G_WHIP_MSG "[WARNING] Conflicting installs have been detected!$unmarked_text$dependants_text" } Select_Webserver_Dependency() { # Check for existing webserver (Apache, Nginx, Lighttpd) installation # - Do no reinstalls, as those are currently too intrusive, overriding custom configs (( ${aSOFTWARE_INSTALL_STATE[83]} < 1 && ${aSOFTWARE_INSTALL_STATE[84]} < 1 && ${aSOFTWARE_INSTALL_STATE[85]} < 1 )) || return 1 # Auto-select webserver if manually installed if dpkg-query -s 'apache2' &> /dev/null then SELECTED_WEBSERVER=83; return 0 elif dpkg-query -s 'nginx-common' &> /dev/null then SELECTED_WEBSERVER=85; return 0 elif dpkg-query -s 'lighttpd' &> /dev/null then SELECTED_WEBSERVER=84; return 0 fi local dependant=$1 preference_index=$(sed -n '/^[[:blank:]]*AUTO_SETUP_WEB_SERVER_INDEX=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) software_id # Preference index to software ID case $preference_index in -2) software_id=84;; # Lighttpd -1) software_id=85;; # Nginx *) software_id=83;; # Apache (default) esac G_WHIP_MENU_ARRAY=( "${aSOFTWARE_NAME[83]}" ": ${aSOFTWARE_DESC[83]}" "${aSOFTWARE_NAME[85]}" ": ${aSOFTWARE_DESC[85]}" "${aSOFTWARE_NAME[84]}" ": ${aSOFTWARE_DESC[84]}" ) G_WHIP_DEFAULT_ITEM=${aSOFTWARE_NAME[$software_id]} G_WHIP_BUTTON_OK_TEXT='Confirm' G_WHIP_NOCANCEL=1 G_WHIP_MENU "${aSOFTWARE_NAME[$dependant]} requires a webserver. Which one shall be installed? \n- Apache: Feature-rich and popular. Recommended for beginners and users who are looking to follow Apache based guides. \n- Nginx: Lightweight alternative to Apache. Nginx claims faster webserver performance compared to Apache. \n- Lighttpd: Extremely lightweight and is generally considered to offer the \"best\" webserver performance for SBCs. Recommended for users who expect low webserver traffic. \n- More info: https://dietpi.com/docs/software/webserver_stack/" || G_WHIP_RETURNED_VALUE=${aSOFTWARE_NAME[$software_id]} # Software name to ID and preference index if [[ $G_WHIP_RETURNED_VALUE == "${aSOFTWARE_NAME[83]}" ]] then SELECTED_WEBSERVER=83 preference_index=0 elif [[ $G_WHIP_RETURNED_VALUE == "${aSOFTWARE_NAME[85]}" ]] then SELECTED_WEBSERVER=85 preference_index=-1 elif [[ $G_WHIP_RETURNED_VALUE == "${aSOFTWARE_NAME[84]}" ]] then SELECTED_WEBSERVER=84 preference_index=-2 fi G_CONFIG_INJECT 'AUTO_SETUP_WEB_SERVER_INDEX=' "AUTO_SETUP_WEB_SERVER_INDEX=$preference_index" /boot/dietpi.txt return 0 } Select_Desktop_Dependency() { # Check for existing desktop (LXDE, MATE, Xfce, GNUstep, LXQt) installation # - Do no reinstalls, as those are loose dependencies (( ${aSOFTWARE_INSTALL_STATE[23]} < 1 && ${aSOFTWARE_INSTALL_STATE[24]} < 1 && ${aSOFTWARE_INSTALL_STATE[25]} < 1 && ${aSOFTWARE_INSTALL_STATE[26]} < 1 && ${aSOFTWARE_INSTALL_STATE[173]} < 1 )) || return 1 # Auto-select desktop if manually installed if dpkg-query -s 'lxde' &> /dev/null then SELECTED_DESKTOP=23; return 0 elif dpkg-query -s 'xfce4' &> /dev/null then SELECTED_DESKTOP=25; return 0 elif dpkg-query -s 'mate-desktop-environment-core' &> /dev/null then SELECTED_DESKTOP=24; return 0 elif dpkg-query -s 'lxqt' &> /dev/null then SELECTED_DESKTOP=173; return 0 elif dpkg-query -s 'gnustep' &> /dev/null then SELECTED_DESKTOP=26; return 0 fi local dependant=$1 preference_index=$(sed -n '/^[[:blank:]]*AUTO_SETUP_DESKTOP_INDEX=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) software_id # Preference index to software ID case $preference_index in -1) software_id=25;; # Xfce -2) software_id=24;; # MATE -3) software_id=173;; # LXQt -4) software_id=26;; # GNUstep *) software_id=23;; # LXDE (default) esac G_WHIP_MENU_ARRAY=( "${aSOFTWARE_NAME[23]}" ": ${aSOFTWARE_DESC[23]}" "${aSOFTWARE_NAME[25]}" ": ${aSOFTWARE_DESC[25]}" "${aSOFTWARE_NAME[24]}" ": ${aSOFTWARE_DESC[24]}" "${aSOFTWARE_NAME[173]}" ": ${aSOFTWARE_DESC[173]}" "${aSOFTWARE_NAME[26]}" ": ${aSOFTWARE_DESC[26]}" ) G_WHIP_DEFAULT_ITEM=${aSOFTWARE_NAME[$software_id]} G_WHIP_BUTTON_OK_TEXT='Confirm' G_WHIP_NOCANCEL=1 G_WHIP_MENU "${aSOFTWARE_NAME[$dependant]} requires a desktop. Which one shall be installed?" || G_WHIP_RETURNED_VALUE=${aSOFTWARE_NAME[$software_id]} # Software name to ID and preference index case $G_WHIP_RETURNED_VALUE in "${aSOFTWARE_NAME[25]}") SELECTED_DESKTOP=25 preference_index=-1;; "${aSOFTWARE_NAME[24]}") SELECTED_DESKTOP=24 preference_index=-2;; "${aSOFTWARE_NAME[173]}") SELECTED_DESKTOP=173 preference_index=-3;; "${aSOFTWARE_NAME[26]}") SELECTED_DESKTOP=26 preference_index=-4;; *) SELECTED_DESKTOP=23 preference_index=0;; esac G_CONFIG_INJECT 'AUTO_SETUP_DESKTOP_INDEX=' "AUTO_SETUP_DESKTOP_INDEX=$preference_index" /boot/dietpi.txt return 0 } Select_Browser_Dependency() { # Check for existing browser (Firefox, Chromium) installation # - Do no reinstalls, as those are loose dependencies (( ${aSOFTWARE_INSTALL_STATE[67]} < 1 && ${aSOFTWARE_INSTALL_STATE[113]} < 1 )) || return 1 # Disable browser preference on ARMv6 and RISC-V systems: https://github.com/RPi-Distro/chromium-browser/issues/21 (( $G_HW_ARCH == 1 || $G_HW_ARCH == 11 )) && return 1 # Auto-select browser if manually installed if dpkg-query -s 'firefox-esr' &> /dev/null then SELECTED_BROWSER=67; return 0 elif dpkg-query -s 'chromium' &> /dev/null || dpkg-query -s 'chromium-browser' &> /dev/null then SELECTED_BROWSER=113; return 0 fi local dependant=$1 preference_index=$(sed -n '/^[[:blank:]]*AUTO_SETUP_BROWSER_INDEX=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) software_id # Preference index to software ID case $preference_index in 0) return 1;; # None: Skip menu if "None" was explicitly selected or set via dietpi.txt before -2) software_id=113;; # Chromium *) software_id=67;; # Firefox (default) esac G_WHIP_MENU_ARRAY=( 'None' ': If you do not require a web browser' "${aSOFTWARE_NAME[67]}" ": ${aSOFTWARE_DESC[67]}" "${aSOFTWARE_NAME[113]}" ": ${aSOFTWARE_DESC[113]}" ) G_WHIP_DEFAULT_ITEM=${aSOFTWARE_NAME[$software_id]} G_WHIP_BUTTON_OK_TEXT='Confirm' G_WHIP_NOCANCEL=1 G_WHIP_MENU "Which web browser shall be installed with the ${aSOFTWARE_NAME[$dependant]} desktop environment?" || G_WHIP_RETURNED_VALUE=${aSOFTWARE_NAME[$software_id]} # Software name to ID and preference index case $G_WHIP_RETURNED_VALUE in 'None') preference_index=0;; "${aSOFTWARE_NAME[113]}") SELECTED_BROWSER=113 preference_index=-2;; *) SELECTED_BROWSER=67 preference_index=-1;; esac G_CONFIG_INJECT 'AUTO_SETUP_BROWSER_INDEX=' "AUTO_SETUP_BROWSER_INDEX=$preference_index" /boot/dietpi.txt [[ $G_WHIP_RETURNED_VALUE == 'None' ]] && return 1 || return 0 } # $1: software ID Resolve_Dependencies() { # Loop through dependencies local i for i in ${aSOFTWARE_DEPS[$1]} do # Resolve webserver dependency based on install state and user preference if [[ $i == 'webserver' ]] then Select_Webserver_Dependency "$1" || continue i=$SELECTED_WEBSERVER # Resolve desktop dependency based on install state elif [[ $i == 'desktop' ]] then Select_Desktop_Dependency "$1" || continue i=$SELECTED_DESKTOP # Resolve browser dependency based on install state elif [[ $i == 'browser' ]] then Select_Browser_Dependency "$1" || continue i=$SELECTED_BROWSER fi # Skip if dependency is marked for install already (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) && continue # Is it reinstalled or freshly installed? local re_installed='installed' (( ${aSOFTWARE_INSTALL_STATE[$i]} == 2 )) && re_installed='reinstalled' aSOFTWARE_INSTALL_STATE[$i]=1 G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$i]} will be $re_installed" # Recursive call to resolve dependencies of this dependency Resolve_Dependencies "$i" done } # Work out which additional software we need to install # - We do reinstall most =2 marked software as well, just to be sure. Mark_Dependencies() { G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Checking for prerequisite software' # If OctoPrint and mjpg-streamer both are installed, OctoPrint is automatically configured to use mjpg-streamer. For the integrated time-lapse feature, FFmpeg is required. if (( ${aSOFTWARE_INSTALL_STATE[137]} > 0 && ${aSOFTWARE_INSTALL_STATE[153]} > 0 && ${aSOFTWARE_INSTALL_STATE[137]} + ${aSOFTWARE_INSTALL_STATE[153]} < 4 )) then aSOFTWARE_INSTALL_STATE[7]=1 G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[7]} will be installed" fi # Loop through marked software to resolve dependencies each local i for i in "${!aSOFTWARE_NAME[@]}" do (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) || continue Resolve_Dependencies "$i" done } Create_Desktop_Shared_Items() { # Pre-create dirs G_EXEC mkdir -p /usr/share/applications /var/lib/dietpi/dietpi-software/installed/desktop/{icons,wallpapers} # Icons G_THREAD_START curl -sSfL 'https://raw.githubusercontent.com/MichaIng/DietPi-Website/master/images/dietpi-logo_128x128.png' -o /var/lib/dietpi/dietpi-software/installed/desktop/icons/dietpi-icon.png G_THREAD_START curl -sSfL "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/icons/grey_16x16.png" -o /var/lib/dietpi/dietpi-software/installed/desktop/icons/grey_16x16.png G_THREAD_START curl -sSfL "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/icons/justboom.png" -o /var/lib/dietpi/dietpi-software/installed/desktop/icons/justboom.png # Wallpapers G_THREAD_START curl -sSfL "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/wallpapers/dietpi-logo_inverted_1080p.png" -o /var/lib/dietpi/dietpi-software/installed/desktop/wallpapers/dietpi-logo_inverted_1080p.png G_THREAD_START curl -sSfL "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/wallpapers/dietpi-logo_1080p.png" -o /var/lib/dietpi/dietpi-software/installed/desktop/wallpapers/dietpi-logo_1080p.png # File manager bookmarks G_THREAD_START curl -sSfL "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/gtk/.gtk-bookmarks" -o /var/lib/dietpi/dietpi-software/installed/desktop/.gtk-bookmarks # Desktop applications local adesktop_items=( 'dietpi-software' 'dietpi-drive_manager' 'dietpi-update' 'dietpi-config' 'dietpi-backup' 'dietpi-sync' 'dietpi-services' 'dietpi-cleaner' 'dietpi-cron' 'dietpi-launcher' 'dietpi-justboom' ) local i for i in "${adesktop_items[@]}" do G_THREAD_START curl -sSfL "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/apps/$i.desktop" -o "/usr/share/applications/$i.desktop" done # Create autostart script to add default desktop icons and configs to users that login the first time into a desktop cat << '_EOF_' > /var/lib/dietpi/dietpi-software/installed/desktop/dietpi-desktop_setup.sh #!/bin/dash # Create desktop shortcuts set 'opentyrian' 'kodi' 'steam' 'dxx-rebirth' 'chromium' 'chromium-browser' 'htop' 'codium' [ $USER = 'root' ] && set "$@" 'dietpi-launcher' 'dietpi-software' 'dietpi-config' [ -d ~/Desktop ] || mkdir -p ~/Desktop for i in "$@" do [ -f /usr/share/applications/$i.desktop ] && ! [ -f ~/Desktop/$i.desktop ] && ln -sf /usr/share/applications/$i.desktop ~/Desktop/$i.desktop done # Create file manager bookmarks if ! [ -f ~/.gtk-bookmarks ] then cp /var/lib/dietpi/dietpi-software/installed/desktop/.gtk-bookmarks ~/.gtk-bookmarks sed --follow-symlinks -i "s|/root|$HOME|g" ~/.gtk-bookmarks fi # Disable this autostart entry [ -d ~/.config/autostart ] || mkdir -p ~/.config/autostart echo '[Desktop Entry]\nHidden=true' > ~/.config/autostart/dietpi-desktop_setup.desktop _EOF_ G_EXEC chmod +x /var/lib/dietpi/dietpi-software/installed/desktop/dietpi-desktop_setup.sh cat << '_EOF_' > /etc/xdg/autostart/dietpi-desktop_setup.desktop [Desktop Entry] Version=1.0 Name=DietPi-Desktop_setup Type=Application Comment=Adds default desktop entries and configs to the users desktop NoDisplay=true Exec=/var/lib/dietpi/dietpi-software/installed/desktop/dietpi-desktop_setup.sh Icon=/var/lib/dietpi/dietpi-software/installed/desktop/icons/dietpi-icon.png _EOF_ G_THREAD_WAIT # https://gitlab.xfce.org/xfce/thunar/-/merge_requests/317 > https://packages.debian.org/bookworm/thunar if (( $G_DISTRO < 7 && ${aSOFTWARE_INSTALL_STATE[25]} == 1 )) then G_DIETPI-NOTIFY 2 'Adding execute bit to our default desktop launchers/icons' adesktop_items=() for i in 'opentyrian' 'kodi' 'steam' 'dxx-rebirth' 'chromium' 'chromium-browser' 'htop' 'codium' 'dietpi-launcher' 'dietpi-software' 'dietpi-config' do [[ -f /usr/share/applications/$i.desktop ]] && adesktop_items+=("/usr/share/applications/$i.desktop") done G_EXEC chmod +x "${adesktop_items[@]}" fi } # Add desktop entry for users which logged into a desktop already and hence have DietPi-Desktop_setup disabled. # $1 = Application name Create_Desktop_Shortcut() { local uid gid app=$1 for i in /root /home/* do [[ -f $i/.config/autostart/dietpi-desktop_setup.desktop && ! -f $i/Desktop/$app.desktop ]] || continue if [[ ! -d $i/Desktop ]] then # shellcheck disable=SC2012 read -r uid gid < <(ls -dn "$i" | mawk '{print $3,$4}') G_EXEC mkdir -p "$i/Desktop" G_EXEC chown "$uid:$gid" "$i/Desktop" fi G_EXEC ln -sf "/usr/share/applications/$app.desktop" "$i/Desktop/$app.desktop" # https://gitlab.xfce.org/xfce/thunar/-/issues/50 (( ${aSOFTWARE_INSTALL_STATE[25]} > 0 )) && G_EXEC chmod +x "/usr/share/applications/$app.desktop" done } Create_Required_Dirs() { G_EXEC mkdir -p /mnt/dietpi_userdata/{Music,Pictures,Video,downloads} /var/www /opt /usr/local/bin getent passwd dietpi > /dev/null && G_EXEC chown dietpi:dietpi /mnt/dietpi_userdata/{Music,Pictures,Video,downloads} G_EXEC chmod 0775 /mnt/dietpi_userdata/{Music,Pictures,Video,downloads} } Download_Test_Media() { [[ -f '/mnt/dietpi_userdata/Music/fourdee_tech.ogg' ]] && return G_EXEC curl -sSf 'https://dietpi.com/downloads/audio/fourdee_tech.ogg' -o /mnt/dietpi_userdata/Music/fourdee_tech.ogg getent passwd dietpi > /dev/null && G_EXEC chown dietpi:dietpi /mnt/dietpi_userdata/Music/fourdee_tech.ogg G_EXEC chmod 0664 /mnt/dietpi_userdata/Music/fourdee_tech.ogg } # Return optimisation values for BitTorrent servers based on device and hardware capabilities. Optimise_BitTorrent() { local gigabit_ethernet=1 (( $G_HW_MODEL < 4 || $G_HW_MODEL == 40 || $G_HW_MODEL == 60 || $G_HW_MODEL == 70 )) && gigabit_ethernet=0 local output case $1 in 0) output=$(( $RAM_PHYS / 10 ));; # Cache size (MiB) 10% of RAM size 1) # Max active downloads output=2 # Bump up for x86_64 (( $G_HW_ARCH == 10 )) && output=3 ;; 2) # Max global connections output=20 # Bump up for Gbit Ethernet (( $gigabit_ethernet )) && output=30 # Bump up for x86_64 (( $G_HW_ARCH == 10 )) && output=40 # Reduce for RPi 1-3 due to the USB bus Ethernet in the ARM SoC, which cripples network throughput/performance/latency. case $G_HW_MODEL in 3) output=15;; 2) output=13;; 1) output=7;; *) :;; esac ;; 3) # Max upload slots output=3 # Bump up for Gbit Ethernet (( $gigabit_ethernet )) && output=4 # Bump up for x86_64 (( $G_HW_ARCH == 10 )) && output=5 # Reduce for RPi 1-3 due to the USB bus Ethernet in the ARM SoC, which cripples network throughput/performance/latency. (( $G_HW_MODEL < 4 )) && output=2 ;; *) G_DIETPI-NOTIFY 1 "Invalid argument \$1=\"$1\" for function Optimise_BitTorrent()"; return 1;; esac echo "$output" } # Usage: # Download_Install 'https://file.com/file' [/path/to/target] # dps_index=$software_id Download_Install 'conf_0' /etc/conf.conf # Optional input variables: # fallback_url='http...' = URL to use if e.g. grabbing URL from api.github.com fails # dps_index=$software_id = Download from DietPi GitHub repo based on software ID/index # aDEPS=('pkg1' 'pkg2' ...) = Install APT dependency packages # NB: This does not support installs that require user input (e.g.: a whiptail prompt for deb installs) Download_Install() { # Verify input URL if [[ $1 ]] then local url=$1 elif [[ $fallback_url ]] then G_DIETPI-NOTIFY 1 "Automatic latest ${aSOFTWARE_NAME[$software_id]} download URL detection failed." G_DIETPI-NOTIFY 1 "\"$fallback_url\" will be used as fallback, but a newer version might be available." G_DIETPI-NOTIFY 1 'Please report this at: https://github.com/MichaIng/DietPi/issues' local url=$fallback_url else G_DIETPI-NOTIFY 1 "An empty download URL was passed during ${aSOFTWARE_NAME[$software_id]} install. Please report this at: https://github.com/MichaIng/DietPi/issues" return 1 fi local target=$2 # Target path local file=${url##*/} # Grab file name from URL # DietPi-Software conf/service mode # shellcheck disable=SC2154 [[ $dps_index && ${aSOFTWARE_NAME[$dps_index]} ]] && url="https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/dps_$dps_index/$url" G_EXEC cd "$G_WORKING_DIR" # Failsafe # Add decompressor to deps list if missing case $file in *'.xz'|*'.txz') command -v xz > /dev/null || aDEPS+=('xz-utils');; *'.bz2'|*'.tbz2') command -v bzip2 > /dev/null || aDEPS+=('bzip2');; *'.zip') command -v unzip > /dev/null || aDEPS+=('unzip');; *'.7z') command -v 7zr > /dev/null || { (( $G_DISTRO > 7 )) && aDEPS+=('7zip') || aDEPS+=('p7zip'); };; *) :;; esac # Download file if [[ ${aDEPS[0]} ]] then # Check URL before starting background download, as a failure does not terminate the install # shellcheck disable=SC2154 G_CHECK_URL "$url" # Download as background thread if dependencies are to be installed G_THREAD_START curl -sSfL "$url" -o "$file" # shellcheck disable=SC2086 G_AGI "${aDEPS[@]}" aDEPS=() G_THREAD_WAIT else G_EXEC curl -sSfL "$url" -o "$file" fi unset -v fallback_url dps_index # Process downloaded file case $file in *'.gz') [[ $file == *'.tar.gz' ]] || { G_EXEC gzip -df "$file" && file=${file%.gz}; };; *'.xz') [[ $file == *'.tar.xz' ]] || { G_EXEC xz -df "$file" && file=${file%.xz}; };; *'.bz2') [[ $file == *'.tar.bz2' ]] || { G_EXEC bzip2 -df "$file" && file=${file%.bz2}; };; *) :;; esac if [[ $file == *'.deb' ]] then G_AGI "./$file" elif [[ $file == *'.zip' ]] then G_EXEC unzip -o "$file" ${target:+"-d$target"} elif [[ $file =~ \.(t?gz|t?xz|t?bz2|tar)$ ]] then G_EXEC tar xf "$file" ${target:+"--one-top-level=$target"} elif [[ $file == *'.7z' ]] then [[ $target && ! -d $target ]] && G_EXEC mkdir -p "$target" # Workaround for 7zr ignoring umask: https://github.com/MichaIng/DietPi/issues/4251 G_EXEC 7zr x -y "$file" ${target:+"-o$target"} elif [[ $target && $target != "$file" ]] then # Pre-create target dir if given: $target can be a file name only, so assure it is a path containing a dir [[ $target == *'/'* && ! -d ${target%/*} ]] && G_EXEC mkdir -p "${target%/*}" G_EXEC mv "$file" "$target" else return 0 fi [[ -f $file ]] && G_EXEC rm "$file" } Create_User() { # Parse input and mark as read-only to throw an error if given doubled local group_primary groups_supplementary home shell password user while (( $# )) do case $1 in '-g') shift; readonly group_primary=$1;; # Primary group is always pre-created and defaults to same name as user for new users '-G') shift; readonly groups_supplementary=$1;; # User is only added to supplementary groups that do exist '-d') shift; readonly home=$1;; # Home is never pre-created and defaults to "/nonexistent" which prevents login '-s') shift; readonly shell=$1;; # Shell defaults to "nologin" which prevents shell access on login even if home exists '-p') shift; readonly password=$1;; # Password is only set for new users while existing users' passwords stay untouched *) readonly user=$1;; esac shift done # Pre-create given primary group, as useradd and usermod fail if it does not exist [[ $group_primary ]] && ! getent group "$group_primary" > /dev/null && G_EXEC groupadd -r "$group_primary" # Only add to supplementary groups that do exist local group groups for group in ${groups_supplementary//,/ } do getent group "$group" > /dev/null && groups+=",$group" done groups=${groups#,} # Create user if missing, else modify it according to input if getent passwd "$user" > /dev/null then G_EXEC usermod ${group_primary:+-g "$group_primary"} ${groups:+-aG "$groups"} -d "${home:-/nonexistent}" -s "${shell:-$(command -v nologin)}" "$user" else local options='-rMU' [[ $group_primary ]] && options='-rMN' G_EXEC useradd "$options" ${group_primary:+-g "$group_primary"} ${groups:+-G "$groups"} -d "${home:-/nonexistent}" -s "${shell:-$(command -v nologin)}" "$user" [[ $password ]] && G_EXEC_DESC="Applying user password: \e[33m${password//?/*}\e[0m" G_EXEC eval "chpasswd <<< '$user:$password'" fi } # Start a service and wait for a default config file to be created. Create_Config() { local file=$1 service=$2 # Config file path and service name local timeout=${3:-25} # Optional [s] local output=$4 pid # Optional, if timeout is set, hence for startups which may take long so that showing some process becomes reasonable # shellcheck disable=SC2154 local content=$CREATE_CONFIG_CONTENT stop=$CC_STOP # Optional required config file content and whether to stop service afterwards (!= 0) unset -v CREATE_CONFIG_CONTENT CC_STOP # If file exists already and contains required content, continue install [[ -f $file ]] && { [[ ! $content ]] || grep -q "$content" "$file"; } && return 0 # Reload services G_EXEC systemctl daemon-reload # File does not exist or does not contain required content: Start service G_EXEC_DESC="Starting ${aSOFTWARE_NAME[$software_id]} to pre-create config file in max $timeout seconds" G_EXEC systemctl start "$service" # Print and follow output of the service startup [[ $output ]] && { journalctl -fn 0 -u "$service" & pid=$!; } # Wait for max $timeout seconds until config file has been created and required content added if given local i=0 until [[ -f $file ]] && { [[ ! $content ]] || grep -q "$content" "$file"; } || (( $i >= $timeout )) || ! systemctl -q is-active "$service" do ((i++)) [[ $output ]] || G_DIETPI-NOTIFY -2 "Waiting for ${aSOFTWARE_NAME[$software_id]} config file to be created ($i/$timeout)" G_SLEEP 1 done # Stop journal prints [[ $output ]] && { kill "$pid"; wait "$pid"; } 2> /dev/null # Stop service if [[ $stop != 0 ]] then G_SLEEP 1 G_EXEC_NOHALT=1 G_EXEC systemctl stop "$service" G_SLEEP 1 fi # If file exists already and contains required content, continue install if [[ -f $file ]] && { [[ ! $content ]] || grep -q "$content" "$file"; } then G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$software_id]} config file got created after $i seconds" return 0 fi G_DIETPI-NOTIFY 1 "Waiting for ${aSOFTWARE_NAME[$software_id]} config file failed, skipping pre-configuration" return 1 } # Remove obsolete SysV service # $1: Service name # $2: If set, remove defaults file as well (optional) Remove_SysV() { G_DIETPI-NOTIFY 2 "Removing obsolete $1 SysV service" [[ -f '/etc/init.d/'$1 ]] && G_EXEC rm "/etc/init.d/$1" G_EXEC update-rc.d "$1" remove [[ $2 && -f '/etc/default/'$1 ]] && G_EXEC rm "/etc/default/$1" } # Run marked software installs Install_Software() { local software_id aDEPS=() # Configure iptables to use nf_tables or legacy API, depending on which is supported by kernel Configure_iptables() { local alt='nft' iptables-nft -L &> /dev/null || alt='legacy' G_EXEC update-alternatives --set iptables "/usr/sbin/iptables-$alt" G_EXEC update-alternatives --set ip6tables "/usr/sbin/ip6tables-$alt" } Enable_memory_cgroup() { if (( $G_HW_MODEL < 10 )) then grep -Eq '(^|[[:blank:]])cgroup_enable=memory([[:blank:]]|$)' /boot/cmdline.txt || G_EXEC sed --follow-symlinks -i '/root=/s/[[:blank:]]*$/ cgroup_enable=memory/' /boot/cmdline.txt elif [[ -f '/boot/boot.scr' ]] && grep -q 'docker_optimizations' /boot/boot.scr then # DietPi mainline U-Boot [[ -f '/boot/dietpiEnv.txt' ]] && G_CONFIG_INJECT 'docker_optimizations=' 'docker_optimizations=on' /boot/dietpiEnv.txt # Armbian [[ -f '/boot/armbianEnv.txt' ]] && G_CONFIG_INJECT 'docker_optimizations=' 'docker_optimizations=on' /boot/armbianEnv.txt # Radxa Zero [[ -f '/boot/uEnv.txt' ]] && G_CONFIG_INJECT 'docker_optimizations=' 'docker_optimizations=on' /boot/uEnv.txt elif [[ -f '/boot/extlinux/extlinux.conf' ]] then grep -Eq '^[[:blank:]]*append[[:blank:]].*cgroup_enable=memory([[:blank:]]|$)' /boot/extlinux/extlinux.conf || G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*append[[:blank:]]/s/[[:blank:]]*$/ cgroup_enable=memory/' /boot/extlinux/extlinux.conf fi } # $1: Software name, so config can be created and removed per-software Enable_IP_forwarding() { if (( $G_HW_MODEL == 75 )) then [[ $(sysctl -n net.ipv4.ip_forward net.ipv6.conf.default.accept_ra net.ipv6.conf.all.accept_ra net.ipv6.conf.default.forwarding net.ipv6.conf.all.forwarding) == $'1\n2\n2\n1\n1' ]] || G_WHIP_MSG "[WARNING] IP forwarding needs to be enabled on container host \nIP forwarding is not enabled for all interfaces, hence ${aSOFTWARE_NAME[$software_id]} clients cannot access the LAN or Internet behind this DietPi system vice versa. \nIP forwarding can only be enabled on the host of this container. E.g. add the following lines to a new sysctl config file like /etc/sysctl.d/dietpi-$1.conf: net.ipv4.ip_forward=1 net.ipv6.conf.default.accept_ra=2 net.ipv6.conf.all.accept_ra=2 net.ipv6.conf.default.forwarding=1 net.ipv6.conf.all.forwarding=1 \nApply them without reboot like this: sudo sysctl -p /etc/sysctl.d/dietpi-$1.conf" else G_DIETPI-NOTIFY 2 'Enabling IP forwarding to allow access across network interfaces' G_EXEC eval "echo -e 'net.ipv4.ip_forward=1\nnet.ipv6.conf.default.accept_ra=2\nnet.ipv6.conf.all.accept_ra=2\nnet.ipv6.conf.default.forwarding=1\nnet.ipv6.conf.all.forwarding=1' > '/etc/sysctl.d/dietpi-$1.conf'" G_EXEC sysctl -p "/etc/sysctl.d/dietpi-$1.conf" fi } # Store APT dependencies for Python modules in aDEPS array, or optionally install them directly # Arguments: # --install, -i Install APT packages directly # --user, -u User to install Rust with # --rust, -r Install Rust in any case # pyenv Add APT dependencies needed to compile Python for pyenv # Add APT dependencies needed to compile and in case run the named module # Environment variables: # PYTHON_VERSION Python version in case e.g. pyenv is used Python_Deps() { local install=0 user rust=0 piwheels=0 # Can piwheels be used? if (( $G_HW_MODEL < 3 )) then if [[ $PYTHON_VERSION ]] then dpkg --compare-version "$PYTHON_VERSION" lt '3.12' && piwheels=1 else (( $G_DISTRO < 8 )) && piwheels=1 fi fi unset -v PYTHON_VERSION # Process arguments while (( $# )) do case $1 in '--install'|'-i') install=1;; '--user'|'-u') shift; user=$1;; '--rust'|'-r') rust=1;; 'av') (( $G_HW_ARCH < 3 || $G_HW_ARCH == 11 )) && aDEPS+=('libavdevice-dev');; 'bcrypt') (( $G_HW_ARCH == 11 )) && rust=1;; 'brotli'|'sabctools'|'ujson') (( $G_HW_ARCH == 11 || ( $G_HW_ARCH < 3 && ! $piwheels ) )) && aDEPS+=('g++');; 'cffi') (( $G_HW_ARCH == 11 || ( $G_HW_ARCH < 3 && ! $piwheels ) )) && aDEPS+=('gcc' 'libffi-dev');; 'cryptography') if (( $G_HW_ARCH == 1 || $G_HW_ARCH == 11 )) then aDEPS+=('pkg-config' 'libssl-dev') rust=1 fi set -- "$@" cffi ;; 'libsass') (( $G_HW_ARCH == 10 || $piwheels )) || aDEPS+=('g++');; 'lxml') (( $G_HW_ARCH == 1 || $G_HW_ARCH == 11 )) && aDEPS+=('libxslt1-dev');; 'matrix-synapse') (( $G_DISTRO > 7 || $G_HW_ARCH < 3 || $G_HW_ARCH == 11 )) && rust=1;; 'netifaces') (( $piwheels || ( $G_HW_ARCH == 10 && $G_DISTRO == 6 ) )) || aDEPS+=('gcc');; 'numpy') (( $G_HW_ARCH < 3 || $G_HW_ARCH == 11 )) && aDEPS+=('g++' 'pkg-config' 'libopenblas-pthread-dev') # cmake + make + automake > patchelf > meson-python > numpy # cmake > ninja > meson-python > numpy (( $G_HW_ARCH == 1 || $G_HW_ARCH == 11 )) && aDEPS+=('cmake' 'make' 'automake') ;; 'pillow') (( $G_HW_ARCH < 3 || $G_HW_ARCH == 11 )) && aDEPS+=('gcc' 'libjpeg62-turbo-dev');; 'poetry') # cryptography > SecretStorage > keyring > poetry set -- "$@" cryptography ;; 'psutil') (( $G_HW_ARCH < 3 || $G_HW_ARCH == 11 )) && aDEPS+=('gcc');; 'psycopg2') (( $G_HW_ARCH < 2 && $piwheels )) || aDEPS+=('gcc' 'libpq-dev');; 'pycurl') (( $G_HW_ARCH == 11 || ( $G_HW_ARCH < 3 && ! $piwheels ) )) && aDEPS+=('gcc' 'libcurl4-openssl-dev' 'libssl-dev');; 'pydantic') # pydantic_core > pydantic (( $G_HW_ARCH == 1 || $G_HW_ARCH == 11 )) && rust=1 ;; 'pyenv') # Required: gcc libc6-dev make libssl-dev zlib1g-dev # Optional to suppress warnings: libbz2-dev libreadline-dev libsqlite3-dev liblzma-dev # libffi-dev for the optional _ctypes module, needed at least for Home Assistant => include it in all pyenv builds to avoid surprises aDEPS+=('gcc' 'libc6-dev' 'make' 'libssl-dev' 'zlib1g-dev' 'libbz2-dev' 'libreadline-dev' 'libsqlite3-dev' 'liblzma-dev' 'libffi-dev') ;; 'pymicro-vad') aDEPS+=('g++');; 'pynacl') (( $G_HW_ARCH == 11 || ( $G_HW_ARCH < 3 && ! $piwheels ) )) && aDEPS+=('make') set -- "$@" cffi ;; *) G_DIETPI-NOTIFY 1 "Unknown argument \"$1\" for Python_Deps(). This should never happen unless you are developing a software implementation. Otherwise, please report this at https://github.com/MichaIng/DietPi/issues. Aborting ..."; exit 1;; esac shift done # Install Rust if needed if (( $rust )) then G_EXEC curl -sSfo rustup-init.sh 'https://sh.rustup.rs' G_EXEC chmod +x rustup-init.sh # ARMv6 Bullseye: rustup-init depends on libatomic1, not assured to be pre-installed on Bullseye (( $G_HW_ARCH == 1 && $G_DISTRO == 6 )) && G_AGI libatomic1 "${aDEPS[@]}" && aDEPS=() install=0 G_EXEC_OUTPUT=1 G_EXEC ${user:+runuser -u "$user" --} ./rustup-init.sh -y --profile minimal G_EXEC rm rustup-init.sh [[ $user ]] || export PATH="/root/.cargo/bin:$PATH" fi [[ ${aDEPS[*]} ]] || return 0 # Deduplicate declare -A dedupe for i in "${aDEPS[@]}"; do dedupe["$i"]=; done aDEPS=("${!dedupe[@]}") # Return or install packages (( $install )) || return 0 G_AGI "${aDEPS[@]}" aDEPS=() } To_Install() { (( ${aSOFTWARE_INSTALL_STATE[$1]} == 1 )) || return 1 G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" "Installing ${aSOFTWARE_NAME[$1]}: ${aSOFTWARE_DESC[$1]}" aDEPS=() # failsafe software_id=$1 shift [[ $1 ]] || return 0 [[ $(readlink -m "/etc/systemd/system/$1.service") == '/dev/null' ]] && G_EXEC systemctl --no-reload unmask "$1" aENABLE_SERVICES+=("$@") } if To_Install 4 # fish then G_AGI fish # Create DietPi source script G_EXEC mkdir -p /etc/fish/conf.d # - Run only if interactive G_EXEC eval 'echo '\''if status is-interactive'\'' > /etc/fish/conf.d/dietpi.fish' # - Take aliases from /etc/bashrc.d/dietpi.bash mawk '/# - DietPi programs/ {flag=1; next} /# - Optional DietPi software aliases/ {flag=0} flag {print}' /etc/bashrc.d/dietpi.bash >> /etc/fish/conf.d/dietpi.fish # - Launch dietpi-login script for first run setup and autostart features cat << '_EOF_' >> /etc/fish/conf.d/dietpi.fish function fish_greeting /boot/dietpi/dietpi-login end end _EOF_ G_EXEC chsh root -s /usr/bin/fish getent passwd dietpi &> /dev/null && G_EXEC chsh dietpi -s /usr/bin/fish fi if To_Install 5 # ALSA then # Get chosen sound card, use default if unset or "none" local soundcard=$(sed -n '/^[[:blank:]]*CONFIG_SOUNDCARD=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ ! $soundcard || $soundcard == 'none' ]] && soundcard='default' # Apply: Installs "alsa-utils" /boot/dietpi/func/dietpi-set_hardware soundcard "$soundcard" fi if To_Install 6 # X11 then # Generic X server and utilities aDEPS=('xserver-xorg-core' 'xserver-xorg-input-libinput' 'xinit' 'dbus-user-session' 'xfonts-base' 'x11-xserver-utils' 'x11-utils') # Pre-create config dir: https://dietpi.com/forum/t/19963 G_EXEC mkdir -p /etc/X11/xorg.conf.d # RPi if (( $G_HW_MODEL < 10 )) then # Add fbdev display driver for legacy framebuffer graphics support, as modesetting requires KMS driver overlay for /dev/dri/card0 to exists. aDEPS+=('xserver-xorg-video-fbdev') # RPi 5: Add config to force X11 using the correct DRM device: https://forums.raspberrypi.com/viewtopic.php?t=358853 (( $G_HW_MODEL == 5 )) && cat << '_EOF_' > /etc/X11/xorg.conf.d/02-dietpi-rpi5.conf Section "OutputClass" Identifier "vc4" MatchDriver "vc4" Driver "modesetting" Option "PrimaryGPU" "true" EndSection _EOF_ # x86_64 VM elif (( $G_HW_ARCH == 10 && $G_HW_MODEL == 20 )) then # If KMS/DRM is supported, add VMware DDX, which offers slightly better performance compared to modesetting. VirtualBox can emulate it as well, which is even the nowadays recommended default. # Else (e.g. Hyper-V) add classic framebuffer DDX [[ -d '/dev/dri' ]] && aDEPS+=('xserver-xorg-video-vmware') || aDEPS+=('xserver-xorg-video-fbdev') # Amlogic S905 elif [[ $G_HW_CPUID == 7 && -d '/dev/dri' ]] then cat << '_EOF_' > /etc/X11/xorg.conf.d/02-dietpi-aml-s905.conf Section "OutputClass" Identifier "Amlogic" MatchDriver "meson" Driver "modesetting" Option "PrimaryGPU" "true" EndSection Section "Screen" Identifier "Default Screen" Device "Meson" Monitor "foo" DefaultDepth 24 SubSection "Display" Depth 24 Modes "1920x1080" "1440x900" "1280x720" "1280x1024" "1280x960" "1024x768" "800x600" "640x480" "720x400" EndSubSection EndSection _EOF_ fi # Disable DPMS and screen blanking cat << '_EOF_' > /etc/X11/xorg.conf.d/98-dietpi-disable_dpms.conf Section "Extensions" Option "DPMS" "Disable" EndSection Section "ServerFlags" Option "BlankTime" "0" EndSection _EOF_ # Install packages G_AGI "${aDEPS[@]}" aDEPS=() fi if To_Install 191 snapserver # Snapcast Server then # RISC-V/Trixie: Install from Debian repo: https://github.com/badaix/snapcast/releases if (( $G_DISTRO > 7 )) then G_AGI snapserver # Install and enable snapweb web UI, not included in Debian's snapserver package: https://github.com/MichaIng/DietPi/issues/7073 local fallback_url='https://github.com/badaix/snapweb/releases/download/v0.9.1/snapweb_0.9.1-1_all.deb' Download_Install "$(curl -sSfL 'https://api.github.com/repos/badaix/snapweb/releases/latest' | mawk -F\" '/^ *"browser_download_url": ".*\/snapweb_[^"\/]*_all.deb"$/{print $4}')" G_CONFIG_INJECT 'doc_root[[:blank:]=]' 'doc_root = /usr/share/snapweb' /etc/snapserver.conf '\[http\]' # Fix /var/lib/snapserver permissions, just in case badaix's package was previously used, which uses the "snapserver" user, instead of "_snapserver" [[ -d '/var/lib/snapserver' ]] && G_EXEC chown -R '_snapserver:_snapserver' /var/lib/snapserver getent passwd snapserver > /dev/null && G_EXEC userdel snapserver else local arch=$(dpkg --print-architecture) local fallback_url="https://github.com/badaix/snapcast/releases/download/v0.32.3/snapserver_0.32.3-1_${arch}_$G_DISTRO_NAME.deb" Download_Install "$(curl -sSfL 'https://api.github.com/repos/badaix/snapcast/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/snapserver_[^\"\/]*_${arch}_$G_DISTRO_NAME.deb\"$/{print \$4}")" # Fix /var/lib/snapserver permissions, just in case Debian's package was previously used, which uses the "_snapserver" user, instead of "snapserver" [[ -d '/var/lib/snapserver' ]] && G_EXEC chown -R 'snapserver:snapserver' /var/lib/snapserver getent passwd _snapserver > /dev/null && G_EXEC userdel _snapserver fi G_EXEC systemctl stop snapserver # Disable JSON RPC by default if setting was never touched yet G_EXEC sed --follow-symlinks -i '/^\[tcp\]/,/^\[/s/^#enabled = true$/enabled = false/' /etc/snapserver.conf fi if To_Install 192 snapclient # Snapcast Client then # RISC-V/Trixie: Install from Debian repo: https://github.com/badaix/snapcast/releases if (( $G_DISTRO > 7 )) then G_AGI snapclient else local arch=$(dpkg --print-architecture) local fallback_url="https://github.com/badaix/snapcast/releases/download/v0.32.3/snapclient_0.32.3-1_${arch}_$G_DISTRO_NAME.deb" Download_Install "$(curl -sSfL 'https://api.github.com/repos/badaix/snapcast/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/snapclient_[^\"\/]*_${arch}_$G_DISTRO_NAME.deb\"$/{print \$4}")" fi G_EXEC systemctl stop snapclient # Config: Skip it host has been applied before. ToDo: v0.32.0 deprecated "--host"/"--port" in favour of "host:port" URI argument. But v0.31.0 from Debian does not support this yet. if ! grep -q '^[[:blank:]]*SNAPCLIENT_OPTS=.*["[:blank:]]-h[[:blank:]]' /etc/default/snapclient then # Ask for server, use local one by default if installed dpkg-query -s 'snapserver' &> /dev/null && G_WHIP_DEFAULT_ITEM='127.0.0.1' G_WHIP_NOCANCEL=1 G_WHIP_INPUTBOX 'Please enter the IP address or hostname of your Snapcast server to connect this client to:' if [[ $G_WHIP_RETURNED_VALUE ]] then local snapcast_server_host=$G_WHIP_RETURNED_VALUE G_WHIP_DEFAULT_ITEM=1704 G_WHIP_NOCANCEL=1 G_WHIP_INPUTBOX_REGEX='^[1-9][0-9]*$' G_WHIP_INPUTBOX_REGEX_TEXT='a valid port number' G_WHIP_INPUTBOX 'Please enter the network port of your Snapcast server (default: 1704):' local snapcast_server_port=$G_WHIP_RETURNED_VALUE G_CONFIG_INJECT 'SNAPCLIENT_OPTS=' "SNAPCLIENT_OPTS=\"-h $snapcast_server_host -p $snapcast_server_port\"" /etc/default/snapclient fi fi # If no Snapcast server was defined explicitly, e.g. on unattended install without having the server installed first, server and client use Avahi to find each other. # The client throws endless errors if Avahi is not running, and endless messages until the server announced itself: https://github.com/badaix/snapcast/issues/647 # Hence Avahi-Daemon is added as fixed dependency for the server, and added for the client hereby if no server was explicitly defined. But is this as fallback only for unattended installs. if ! grep -q '^[[:blank:]]*SNAPCLIENT_OPTS=.*["[:blank:]]-h[[:blank:]]' /etc/default/snapclient then G_DIETPI-NOTIFY 2 'Adding Avahi-Daemon as dependency for the Snapcast client to be able to auto-detect a server' aSOFTWARE_INSTALL_STATE[152]=1 fi fi if To_Install 152 avahi-daemon # Avahi-Daemon then G_AGI avahi-daemon G_EXEC systemctl stop avahi-daemon fi if To_Install 17 # Git then G_AGI git fi if To_Install 3 # Midnight Commander then G_AGI mc fi if To_Install 0 # OpenSSH Client then G_AGI openssh-client fi if To_Install 1 # Samba Client then G_AGI cifs-utils smbclient fi if To_Install 110 # NFS Client then # "netbase" is required for mounting NFSv3 and showmount to solve "clnt_create: RPC: Unknown host": https://github.com/MichaIng/DietPi/issues/1898#issuecomment-406247814 G_AGI nfs-common netbase fi if To_Install 104 dropbear # Dropbear then # Stop OpenSSH service to unbind port 22 systemctl -q is-active ssh && G_EXEC systemctl stop ssh G_AGI dropbear # Enable Dropbear daemon, obsolete since Bookworm (( $G_DISTRO > 6 )) || G_CONFIG_INJECT 'NO_START=' 'NO_START=0' /etc/default/dropbear # Apply password login setting from dietpi.txt or default (implies a restart) # - Assure service is active G_EXEC systemctl unmask dropbear G_EXEC systemctl start dropbear /boot/dietpi/func/dietpi-set_software disable_ssh_password_logins # Mark OpenSSH for uninstall dpkg-query -s 'openssh-server' &> /dev/null && aSOFTWARE_INSTALL_STATE[105]=-1 fi if To_Install 105 ssh # OpenSSH Server then # Stop Dropbear service to unbind port 22 systemctl -q is-active dropbear && G_EXEC systemctl stop dropbear G_AGI openssh-server # Apply password login setting from dietpi.txt or default (implies a restart) # - Assure service is active G_EXEC systemctl unmask ssh G_EXEC systemctl start ssh /boot/dietpi/func/dietpi-set_software disable_ssh_password_logins # Mark Dropbear for uninstall dpkg-query -s 'dropbear' &> /dev/null || dpkg-query -s 'dropbear-run' &> /dev/null && aSOFTWARE_INSTALL_STATE[104]=-1 fi if To_Install 194 postgresql # PostgreSQL then G_DIETPI-NOTIFY 2 'Preparing database directory at: /mnt/dietpi_userdata/postgresql' if [[ -d '/mnt/dietpi_userdata/postgresql' ]]; then G_DIETPI-NOTIFY 2 '/mnt/dietpi_userdata/postgresql exists, will migrate containing databases' else # Otherwise use possibly existent /var/lib/postgresql # - Remove possible dead symlinks/files: G_EXEC rm -f /mnt/dietpi_userdata/postgresql if [[ -d '/var/lib/postgresql' ]]; then G_DIETPI-NOTIFY 2 '/var/lib/postgresql exists, will migrate containing databases' # Failsafe: Move symlink target in case, otherwise readlink will resolve to dir G_EXEC mv "$(readlink -f '/var/lib/postgresql')" /mnt/dietpi_userdata/postgresql else G_EXEC mkdir /mnt/dietpi_userdata/postgresql fi fi G_EXEC rm -Rf /var/lib/postgresql G_EXEC ln -s /mnt/dietpi_userdata/postgresql /var/lib/postgresql G_AGI postgresql G_EXEC systemctl stop postgresql # Disable TCP/IP listener and assure that UNIX domain socket is enabled at expected path for i in /etc/postgresql/*/main/conf.d do [[ -d $i ]] || continue echo "# Disable TCP listener and assure that UNIX socket is enabled at expected path # NB: Do not edit this file, instead override settings via e.g.: conf.d/99local.conf listen_addresses = '' unix_socket_directories = '/run/postgresql'" > "$i/00dietpi.conf" done fi if To_Install 103 dietpi-ramlog # DietPi-RAMlog then # Install persistent tmpfs local var_log_size=$(sed -n '/^[[:blank:]]*AUTO_SETUP_RAMLOG_MAXSIZE=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) sed --follow-symlinks -i '/[[:blank:]]\/var\/log[[:blank:]]/d' /etc/fstab echo "tmpfs /var/log tmpfs size=${var_log_size:-50}M,noatime,lazytime,nodev,nosuid" >> /etc/fstab # Apply logging choice index [[ $INDEX_LOGGING == -[12] ]] || INDEX_LOGGING=-1 # Sync logs to disk once local acommand=('/boot/dietpi/func/dietpi-ramlog' '1') systemctl -q is-active dietpi-ramlog && acommand=('systemctl' 'stop' 'dietpi-ramlog') G_EXEC_DESC='Storing /var/log metadata to disk' G_EXEC "${acommand[@]}" unset -v acommand # Cleanup mount point findmnt /var/log > /dev/null && G_EXEC_DESC='Unmounting /var/log' G_EXEC_NOHALT=1 G_EXEC umount -Rfl /var/log G_EXEC_DESC='Cleaning /var/log mount point' G_EXEC rm -Rf /var/log/{,.??,.[^.]}* # Start DietPi-RAMlog G_EXEC_DESC='Mounting tmpfs to /var/log' G_EXEC mount /var/log G_EXEC_DESC='Restoring metadata to /var/log tmpfs' G_EXEC systemctl start dietpi-ramlog fi if To_Install 101 # Logrotate then G_AGI logrotate fi if To_Install 190 # Beets then # Config: Preserve existing on reinstall G_EXEC mkdir -p /mnt/dietpi_userdata/beets [[ -f '/mnt/dietpi_userdata/beets/config.yaml' ]] || G_EXEC eval 'echo -e '\''directory: /mnt/dietpi_userdata/Music\nlibrary: /mnt/dietpi_userdata/beets/library.db'\'' > /mnt/dietpi_userdata/beets/config.yaml' # Allow dietpi user and audio group members to manage library [[ -f '/mnt/dietpi_userdata/beets/library.db' ]] || > /mnt/dietpi_userdata/beets/library.db [[ -f '/mnt/dietpi_userdata/beets/state.pickle' ]] || > /mnt/dietpi_userdata/beets/state.pickle # shellcheck disable=SC2015 getent passwd dietpi > /dev/null && G_EXEC chown -R dietpi:audio /mnt/dietpi_userdata/beets || G_EXEC chgrp -R audio /mnt/dietpi_userdata/beets G_EXEC chmod -R g+w /mnt/dietpi_userdata/beets # Load global beets config in all interactive bash shells echo 'export BEETSDIR=/mnt/dietpi_userdata/beets' > /etc/bashrc.d/dietpi-beets.sh # shellcheck disable=SC1091 . /etc/bashrc.d/dietpi-beets.sh # Install G_AGI beets fi if To_Install 102 rsyslog # Rsyslog then # Workaround for dpkg failure on 1st install if service is already running but APT not installed: https://github.com/MichaIng/DietPi/pull/2277/#issuecomment-441460925 systemctl -q is-active rsyslog && G_EXEC systemctl stop rsyslog G_AGI rsyslog G_EXEC systemctl start rsyslog # Apply logging choice index grep -q '[[:blank:]]/var/log[[:blank:]]' /etc/fstab || findmnt -t tmpfs -M /var/log > /dev/null || INDEX_LOGGING=-3 fi if To_Install 7 # FFmpeg then # RPi: Enable hardware codecs (( $G_HW_MODEL > 9 )) || /boot/dietpi/func/dietpi-set_hardware rpi-codec 1 G_AGI ffmpeg fi if To_Install 196 # Java JRE then local JAVA_VERSION=21 # ARMv6/7: Install Debian's OpenJDK packages since Adoptium does not support it if (( $G_HW_ARCH < 3 )) then # ARMv6/Bullseye/Bookworm: Java 17 is the latest available one (( $G_DISTRO < 8 || $G_HW_ARCH == 1 )) && JAVA_VERSION=17 G_AGI "openjdk-$JAVA_VERSION-jre-headless" JAVA_PATH="/usr/lib/jvm/java-$JAVA_VERSION-openjdk-$(dpkg --print-architecture)/bin/java" else # APT key: https://adoptium.net/installation/linux G_EXEC mkdir -p /etc/apt/keyrings G_EXEC curl -sSfLo /etc/apt/keyrings/dietpi-adoptium.asc 'https://packages.adoptium.net/artifactory/api/gpg/key/public' # APT source G_EXEC eval "cat << '_EOF_' > /etc/apt/sources.list.d/dietpi-adoptium.sources Types: deb URIs: https://packages.adoptium.net/artifactory/deb Suites: ${G_DISTRO_NAME/forky/trixie} Components: main Signed-By: /etc/apt/keyrings/dietpi-adoptium.asc" G_AGUP # Allow Debian's OpenJDK to be autopurged G_EXEC apt-mark auto 'openjdk-*-jre-headless' G_AGI "temurin-$JAVA_VERSION-jre" JAVA_PATH="/usr/lib/jvm/temurin-$JAVA_VERSION-jre-$(dpkg --print-architecture)/bin/java" fi # Define some default max heap size here local JAVA_MAX_HEAP_SIZE=$(( $RAM_PHYS / 5 )) (( $JAVA_MAX_HEAP_SIZE < 200 )) && JAVA_MAX_HEAP_SIZE=200 # - On 32-bit systems the head size cannot be above 3 GiB (( $G_HW_ARCH < 3 && $JAVA_MAX_HEAP_SIZE > 3072 )) && JAVA_MAX_HEAP_SIZE=3072 fi if To_Install 8 # Java JDK then if (( $G_HW_ARCH < 3 )) then G_AGI "openjdk-$JAVA_VERSION-jdk-headless" else # Allow OpenJDK to be autopurged G_EXEC apt-mark auto 'openjdk-*-jdk-headless' G_AGI "temurin-$JAVA_VERSION-jdk" fi fi if To_Install 9 # Node.js then # ARMv6/7/RISC-V deps (verified 2024-07-11): https://github.com/MichaIng/DietPi/issues/3614 (( $G_HW_ARCH < 3 || $G_HW_ARCH == 11 )) && aDEPS=('libatomic1') # Download installer Download_Install 'https://raw.githubusercontent.com/MichaIng/nodejs-linux-installer/master/node-install.sh' G_EXEC chmod +x node-install.sh # ARMv6/RISC-V: Use unofficial builds to get the latest version: https://github.com/MichaIng/nodejs-linux-installer/pull/2, https://github.com/MichaIng/nodejs-linux-installer/commit/cd952fe local options=() (( $G_HW_ARCH == 1 || $G_HW_ARCH == 11 )) && options=('-u') # ARMv6/7 Bullseye: node: /usr/lib/arm-linux-gnueabihf/libstdc++.so.6: version `GLIBCXX_3.4.30'/`GLIBCXX_3.4.29' not found (required by node) if (( $G_HW_ARCH < 3 && $G_DISTRO < 7 )) then local version=22 fallback='v22.19.0' (( $G_HW_ARCH == 1 )) && version=20 fallback='v20.19.4' version=$(./node-install.sh -l | mawk "/^v$version/{print \$1;exit}") [[ $version ]] || version=$fallback options+=('-v' "$version") fi G_EXEC_OUTPUT=1 G_EXEC ./node-install.sh "${options[@]}" G_EXEC rm node-install.sh fi if To_Install 130 # Python 3 then # Allow pip to install modules on system level, and mute the warning when doing so as root (which is needed, of course) >> /etc/pip.conf G_CONFIG_INJECT '\[global\]' '[global]' /etc/pip.conf G_CONFIG_INJECT 'break-system-packages[[:blank:]]*=' 'break-system-packages=true' /etc/pip.conf '\[global\]' G_CONFIG_INJECT 'root-user-action[[:blank:]]*=' 'root-user-action=ignore' /etc/pip.conf '\[global\]' # Disable cache: It is rarely ever needed to install the very same module and version twice, hence this usually only causes unnecessary disk writes and usage. G_CONFIG_INJECT 'no-cache-dir[[:blank:]]*=' 'no-cache-dir=true' /etc/pip.conf '\[global\]' # ARMv6/7: Add piwheels (( $G_HW_ARCH < 3 )) && G_CONFIG_INJECT 'extra-index-url[[:blank:]]*=' 'extra-index-url=https://www.piwheels.org/simple/' /etc/pip.conf '\[global\]' # Perform pip3 install (which includes setuptools and wheel modules) aDEPS=('python3-dev') Download_Install 'https://bootstrap.pypa.io/get-pip.py' G_EXEC_OUTPUT=1 G_EXEC python3 get-pip.py G_EXEC rm get-pip.py fi if To_Install 150 # Mono: https://www.mono-project.com/download/stable/#download-lin-debian then # Trixie: Install from Debian repo instead: "mono-devel : Depends: libglib2.0-0 (>= 2.58.3) but it is not installable" if (( $G_DISTRO < 8 )) then # APT key G_EXEC curl -sSfL 'https://download.mono-project.com/repo/xamarin_ring.gpg' -o /etc/apt/trusted.gpg.d/dietpi-mono.gpg # APT list # - Only Buster suites are available: https://download.mono-project.com/repo/debian/dists/ # - On Raspbian use separate suite: https://github.com/MichaIng/DietPi/issues/1023 local suite='buster' (( $G_RASPBIAN )) && suite='raspbianbuster' G_EXEC eval "echo 'deb https://download.mono-project.com/repo/debian $suite main' > /etc/apt/sources.list.d/dietpi-mono.list" G_AGUP fi # APT package G_AGI mono-devel # Cleanup: https://github.com/MichaIng/DietPi/issues/1877#issuecomment-403856446 G_EXEC rm -f /tmp/mono* fi if To_Install 188 # Go then # https://go.dev/doc/install#install case $G_HW_ARCH in 3) local arch='arm64';; 10) local arch='amd64';; 11) local arch='riscv64';; *) local arch='armv6l';; esac # Get latest version local file=$(curl -sSfL 'https://go.dev/dl/?mode=json' | grep -o "go[0-9.]*\.linux-$arch\.tar\.gz" | head -1) [[ $file ]] || { file="go1.25.1.linux-$arch.tar.gz"; G_DIETPI-NOTIFY 1 "Automatic latest ${aSOFTWARE_NAME[$software_id]} version detection failed. \"$file\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } # Reinstall: Remove previous instance [[ -d '/usr/local/go' ]] && G_EXEC rm -R /usr/local/go Download_Install "https://dl.google.com/go/$file" /usr/local # Add to PATH, but do not overwrite existing script since we did set GOPATH until v8.9 and do not want to cause a breaking change for existing installs # shellcheck disable=SC2016 [[ -f '/etc/bashrc.d/go.sh' ]] || G_EXEC eval 'echo '\''export PATH="$PATH:/usr/local/go/bin"'\'' > /etc/bashrc.d/go.sh' # shellcheck disable=SC1091 . /etc/bashrc.d/go.sh # RISC-V pre-v8.24 and general failsafe action: Purge Go APT Package dpkg-query -s 'golang-go' &> /dev/null && G_AGP golang-go fi if To_Install 170 # UnRAR then # On Raspbian, only "unrar-free" is available which does not support all RAR formats, thus we use "unrar" [non-free] from Debian on ARMv7+ models: http://raspbian.raspberrypi.com/raspbian/pool/non-free/u/unrar-nonfree/ if (( $G_HW_ARCH == 1 )) then G_AGI unrar-free elif (( $G_RASPBIAN )) then Download_Install "https://dietpi.com/downloads/binaries/rpi/unrar-armhf-$G_DISTRO_NAME.deb" else G_AGI unrar fi fi if To_Install 23 # LXDE then # LXDE pulls in LightDM as dependency, which sets up itself as display manager so that the system boots automatically into it. So check whether a default display manager is present first, and if not, remove it afterwards. local display_manager=0 [[ -f '/etc/systemd/system/display-manager.service' ]] && display_manager=1 # librsvg2-common: https://github.com/MichaIng/DietPi/issues/4687 G_AGI lxde lxhotkey-plugin-openbox upower librsvg2-common [[ $display_manager == 0 && -f '/etc/systemd/system/display-manager.service' ]] && G_EXEC rm /etc/systemd/system/display-manager.service # lxpanel G_EXEC curl -sSfL "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/lxde/panel" -o /etc/xdg/lxpanel/LXDE/panels/panel # - Adjust Firefox app icon if it is not installed if (( ${aSOFTWARE_INSTALL_STATE[67]} < 1 )) then # Chromium if (( ${aSOFTWARE_INSTALL_STATE[113]} > 0 )) then local chromium='chromium' (( $G_DISTRO < 7 && $G_HW_MODEL < 10 )) && chromium='chromium-browser' G_EXEC sed --follow-symlinks -i "s/firefox-esr/$chromium/" /etc/xdg/lxpanel/LXDE/panels/panel else G_EXEC sed --follow-symlinks -i 's/firefox-esr/mousepad/' /etc/xdg/lxpanel/LXDE/panels/panel fi fi # Openbox: Enable only one desktop and disable icon animations G_CONFIG_INJECT '[0-9]*' '1' /etc/xdg/openbox/LXDE/rc.xml '' G_CONFIG_INJECT '.*' 'no' /etc/xdg/openbox/LXDE/rc.xml '' # PCmanFM: Set wallpaper and desktop icon text shadow color G_CONFIG_INJECT '\[desktop\]' '[desktop]' /etc/xdg/pcmanfm/LXDE/pcmanfm.conf G_CONFIG_INJECT 'wallpaper_mode=' 'wallpaper_mode=fit' /etc/xdg/pcmanfm/LXDE/pcmanfm.conf '\[desktop\]' G_CONFIG_INJECT 'wallpaper=' 'wallpaper=/var/lib/dietpi/dietpi-software/installed/desktop/wallpapers/dietpi-logo_inverted_1080p.png' /etc/xdg/pcmanfm/LXDE/pcmanfm.conf '\[desktop\]' G_CONFIG_INJECT 'desktop_shadow=' 'desktop_shadow=#333333' /etc/xdg/pcmanfm/LXDE/pcmanfm.conf '\[desktop\]' # Apply better default icon theme: nuoveXT2 has more individual icons than Adwaita, but lower resolution and overrides the Firefox application icon with an old low res version. G_CONFIG_INJECT 'sNet/IconThemeName=' 'sNet/IconThemeName=Adwaita' /etc/xdg/lxsession/LXDE/desktop.conf '\[GTK\]' # Workaround for "No session for pid" error: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864402 G_CONFIG_INJECT 'polkit/command=' 'polkit/command=' /etc/xdg/lxsession/LXDE/desktop.conf '\[Session\]' # Disable trash G_CONFIG_INJECT 'use_trash=' 'use_trash=0' /etc/xdg/libfm/libfm.conf '\[config\]' # Execute desktop icons and executable files directly without asking what to do G_CONFIG_INJECT 'quick_exec=' 'quick_exec=1' /etc/xdg/libfm/libfm.conf '\[config\]' Create_Desktop_Shared_Items fi if To_Install 173 # LXQt then # SpeedCrunch has been removed from Debian since Trixie: https://tracker.debian.org/pkg/speedcrunch local speedcrunch=('speedcrunch') (( $G_DISTRO > 7 )) && speedcrunch=() # lxqt-archiver is the default dependency from Trixie on, but our config uses Archiver=xarchiver. G_AGI lxqt xarchiver xscreensaver "${speedcrunch[@]}" # Configs Download_Install "https://github.com/$G_GITOWNER/DietPi/raw/$G_GITBRANCH/.conf/desktop/lxqt/lxqt-$G_DISTRO_NAME.7z" /etc/xdg/ Create_Desktop_Shared_Items # Composition manager: LXQt has one integrated with xfwm4, which is blocked by xcompmgr, breaking settings and leading to ugly results: https://github.com/MichaIng/DietPi/issues/3665 [[ -f '/etc/xdg/autostart/xcompmgr.desktop' ]] && G_EXEC rm /etc/xdg/autostart/xcompmgr.desktop fi if To_Install 24 # MATE then # Add xterm, as the mate-terminal is not compatible with desktop console shortcuts: https://github.com/MichaIng/DietPi/issues/3160#issuecomment-828305136 G_AGI mate-desktop-environment-core mate-media upower xterm Create_Desktop_Shared_Items fi if To_Install 26 # GNUstep then G_AGI wmaker gnustep gnustep-devel gnustep-games xterm Create_Desktop_Shared_Items fi if To_Install 25 # Xfce then # Elevated permissions for non-root users to perform e.g. reboot and shutdown from logout menu local polkit='polkitd' (( $G_DISTRO < 7 )) && polkit='policykit-1' G_AGI xfce4 xfce4-terminal gnome-icon-theme tango-icon-theme upower "$polkit" Create_Desktop_Shared_Items # Composition manager: Xfce has one integrated with xfwm4, which is blocked by xcompmgr, breaking settings and leading to ugly results: https://github.com/MichaIng/DietPi/issues/3665 [[ -f '/etc/xdg/autostart/xcompmgr.desktop' ]] && G_EXEC rm /etc/xdg/autostart/xcompmgr.desktop fi if To_Install 175 # Xfce Power Manager then G_AGI xfce4-power-manager fi if To_Install 22 # QuiteRSS then G_AGI quiterss fi if To_Install 67 # Firefox then # libpci3: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993308 G_AGI firefox-esr libpci3 # Config #G_CONFIG_INJECT 'pref\("extensions.update.enabled"' 'pref("extensions.update.enabled", false);' /etc/firefox-esr/firefox-esr.js #G_CONFIG_INJECT 'pref\("datareporting.healthreport.uploadEnabled"' 'pref("datareporting.healthreport.uploadEnabled", false);' /etc/firefox-esr/firefox-esr.js #G_CONFIG_INJECT 'pref\("browser.cache.disk.parent_directory"' 'pref("browser.cache.disk.parent_directory", "/tmp/firefox_cache");' /etc/firefox-esr/firefox-esr.js #G_CONFIG_INJECT 'pref\("general.smoothScroll"' 'pref("general.smoothScroll", false);' /etc/firefox-esr/firefox-esr.js fi if To_Install 174 # GIMP then G_AGI gimp fi if To_Install 29 # XRDP then G_AGI xrdp xorgxrdp aSTART_SERVICES+=('xrdp') # Workaround for failing mouse and keyboard input: https://github.com/neutrinolabs/xorgxrdp/issues/164 # - Solved on Bookworm, but G_CONFIG_INJECT detects and skips it then, and keeping it covers dist-upgraded systems. GGI_PRESERVE=1 G_CONFIG_INJECT 'Option[[:blank:]]+"DefaultServerLayout"' ' Option "DefaultServerLayout" "X11 Server"' /etc/X11/xrdp/xorg.conf 'Section[[:blank:]]+"ServerFlags"' # Enable TLS with snakeoil certificate: https://github.com/MichaIng/DietPi/issues/5976 G_EXEC usermod -aG ssl-cert xrdp fi if To_Install 30 # NoMachine then case $G_HW_ARCH in 1) local url='raspberry/v6/deb/nomachine_latest_armv6hf';; 2) local url='arm/v7/deb/nomachine_latest_armhf';; 3) local url='arm/v8/deb/nomachine_latest_arm64';; *) local url='linux/64/deb/nomachine_latest_amd64';; esac Download_Install "https://www.nomachine.com/free/$url.deb" aSTART_SERVICES+=('nxserver') fi if To_Install 200 # DietPi-Dashboard then # Stable release or nightly? # - RISC-V and Raspberry Pi 5: Use nightly builds, as stable does not work on these CPUs if (( $G_HW_ARCH == 11 || $G_HW_MODEL == 5 )) then local version='Nightly' else local version=$(sed -n '/^[[:blank:]]*SOFTWARE_DIETPI_DASHBOARD_VERSION=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $version == 'Nightly' ]] || version='Stable' G_WHIP_MENU_ARRAY=( 'Stable' ': Use a release version of DietPi-Dashboard.' 'Nightly' ': Use an unstable version of DietPi-Dashboard.' ) G_WHIP_DEFAULT_ITEM=$version G_WHIP_BUTTON_CANCEL_TEXT=$version G_WHIP_MENU 'Please choose which version of DietPi-Dashboard should be installed.' && version=$G_WHIP_RETURNED_VALUE fi # Backend only? Currently not functional! local backend= #$(sed -n '/^[[:blank:]]*SOFTWARE_DIETPI_DASHBOARD_BACKEND=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) #[[ $backend == 1 ]] && G_WHIP_DEFAULT_ITEM='Yes' || G_WHIP_DEFAULT_ITEM='No' #G_WHIP_BUTTON_OK_TEXT='Yes' G_WHIP_BUTTON_CANCEL_TEXT='No' #G_WHIP_YESNO 'Would you like to install the backend only, to view on another DietPi-Dashboard instance?' && backend='-backend' || backend= # Download binary and set config URL local config_url if [[ $version == 'Nightly' ]] then command -v unzip > /dev/null || G_AGI unzip # G_CHECK_URL => HEAD request on nightly.link always returns 404, hence prevent Download_Install() from doing concurrent unzip install, which forks the download into background and runs G_CHECK_URL first. Download_Install "https://nightly.link/ravenclaw900/DietPi-Dashboard/workflows/push-build/main/dietpi-dashboard-$G_HW_ARCH_NAME$backend.zip" /opt/dietpi-dashboard config_url='https://raw.githubusercontent.com/ravenclaw900/DietPi-Dashboard/main/config.toml' else Download_Install "$(curl -sSfL 'https://api.github.com/repos/ravenclaw900/dietpi-dashboard/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*dietpi-dashboard-$G_HW_ARCH_NAME$backend\"$/{print \$4}")" /opt/dietpi-dashboard/dietpi-dashboard config_url="https://raw.githubusercontent.com/ravenclaw900/DietPi-Dashboard/$(curl -sSfL 'https://api.github.com/repos/ravenclaw900/dietpi-dashboard/releases/latest' | mawk -F\" '/^ *"tag_name": "[^"]*",$/{print $4}')/config.toml" fi G_EXEC chmod +x /opt/dietpi-dashboard/dietpi-dashboard # Config if [[ ! -f '/opt/dietpi-dashboard/config.toml' ]] then G_EXEC curl -sSfL "$config_url" -o /opt/dietpi-dashboard/config.toml # Enable password protection with global software password by default G_CONFIG_INJECT 'pass[[:blank:]]' 'pass = true' /opt/dietpi-dashboard/config.toml G_CONFIG_INJECT 'hash[[:blank:]]' "hash = \"$(echo -n "$GLOBAL_PW" | sha512sum | mawk '{print $1}')\"" /opt/dietpi-dashboard/config.toml G_CONFIG_INJECT 'secret[[:blank:]]' "secret = \"$(openssl rand -hex 32)\"" /opt/dietpi-dashboard/config.toml fi # Service cat << '_EOF_' > /etc/systemd/system/dietpi-dashboard.service [Unit] Description=Web Dashboard (DietPi) Wants=network-online.target After=network-online.target [Service] ExecStart=/opt/dietpi-dashboard/dietpi-dashboard # TTY input is required for web terminal input StandardInput=tty TTYPath=/dev/tty42 StandardOutput=journal [Install] WantedBy=multi-user.target _EOF_ # Service needs to be started manually as dietpi-services must not control it to prevent it from stopping during software installs done via dashboard itself. aSTART_SERVICES+=('dietpi-dashboard') fi if To_Install 99 node_exporter # Prometheus Node Exporter then case $G_HW_ARCH in 1) local arch='armv6';; 2) local arch='armv7';; 3) local arch='arm64';; 11) local arch='riscv64';; *) local arch='amd64';; esac # Download binary local fallback_url="https://github.com/prometheus/node_exporter/releases/download/v1.9.1/node_exporter-1.9.1.linux-$arch.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/prometheus/node_exporter/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/node_exporter-.*\.linux-$arch\.tar\.gz\"$/{print \$4}")" G_EXEC mkdir -p /opt/node_exporter G_EXEC cp --preserve=mode node_exporter*/node_exporter /opt/node_exporter/ G_EXEC rm -R node_exporter* # User Create_User node_exporter # Services cat << '_EOF_' > /etc/systemd/system/node_exporter.service [Unit] Description=Prometheus Node Exporter (DietPi) Documentation=https://prometheus.io/docs/guides/node-exporter/ [Service] User=node_exporter RuntimeDirectory=node_exporter ExecStart=/opt/node_exporter/node_exporter --log.level=warn --collector.textfile.directory=/run/node_exporter [Install] WantedBy=multi-user.target _EOF_ # RPi: Install raspberrypi_exporter if (( $G_HW_MODEL < 10 )) then Download_Install 'https://github.com/fahlke/raspberrypi_exporter/archive/master.tar.gz' G_CONFIG_INJECT 'ConditionPathExists=' 'ConditionPathExists=/run/node_exporter' raspberrypi_exporter-master/raspberrypi_exporter.service '\[Unit\]' G_CONFIG_INJECT 'ExecStart=' 'ExecStart=/opt/node_exporter/raspberrypi_exporter' raspberrypi_exporter-master/raspberrypi_exporter.service G_CONFIG_INJECT 'METRICS_FILE=' 'METRICS_FILE='\''/run/node_exporter/raspberrypi-metrics.prom'\' raspberrypi_exporter-master/raspberrypi_exporter G_EXEC mv {raspberrypi_exporter-master,/opt/node_exporter}/raspberrypi_exporter G_EXEC mv {raspberrypi_exporter-master,/etc/systemd/system}/raspberrypi_exporter.service G_EXEC mv {raspberrypi_exporter-master,/etc/systemd/system}/raspberrypi_exporter.timer G_EXEC rm -R raspberrypi_exporter-master aENABLE_SERVICES+=('raspberrypi_exporter') fi fi if To_Install 44 transmission-daemon # Transmission then G_AGI transmission-daemon G_EXEC systemctl stop transmission-daemon # Remove obsolete service and environment files Remove_SysV transmission-daemon 1 G_EXEC rm -f /etc/init/transmission-daemon.conf # Apply optimised settings G_CONFIG_INJECT '"download-queue-size"' " \"download-queue-size\": $(Optimise_BitTorrent 1)," /etc/transmission-daemon/settings.json '^\{$' G_CONFIG_INJECT '"peer-limit-global"' " \"peer-limit-global\": $(Optimise_BitTorrent 2)," /etc/transmission-daemon/settings.json '^\{$' G_CONFIG_INJECT '"upload-slots-per-torrent"' " \"upload-slots-per-torrent\": $(Optimise_BitTorrent 3)," /etc/transmission-daemon/settings.json '^\{$' G_CONFIG_INJECT '"encryption"' ' "encryption": 2,' /etc/transmission-daemon/settings.json '^\{$' G_CONFIG_INJECT '"trash-original-torrent-files"' ' "trash-original-torrent-files": true,' /etc/transmission-daemon/settings.json '^\{$' G_CONFIG_INJECT '"download-dir"' ' "download-dir": "/mnt/dietpi_userdata/downloads",' /etc/transmission-daemon/settings.json '^\{$' G_CONFIG_INJECT '"rpc-username"' ' "rpc-username": "root",' /etc/transmission-daemon/settings.json '^\{$' G_CONFIG_INJECT '"rpc-whitelist-enabled"' ' "rpc-whitelist-enabled": false,' /etc/transmission-daemon/settings.json '^\{$' # - Generate hash from global software password: https://github.com/transmission/transmission/blob/7367d46/libtransmission/crypto-utils.cc#L58 local salt=$(tr -dc '[:alnum:]./' < /dev/random | head -c8) local hash=$(echo -n "$GLOBAL_PW$salt" | sha1sum | mawk '{print $1}') GCI_PASSWORD=1 G_CONFIG_INJECT '"rpc-password"' " \"rpc-password\": \"{$hash$salt\"," /etc/transmission-daemon/settings.json '^\{$' unset -v hash salt # Grant R/W access to and from download managers, media and file servers: Make "dietpi" the primary group, "debian-transmission" a supplementary group and create downloads with group write mode G_EXEC usermod -g dietpi -aG debian-transmission debian-transmission G_CONFIG_INJECT '"umask"' ' "umask": 7,' /etc/transmission-daemon/settings.json '^\{$' fi if To_Install 94 proftpd # ProFTPD then G_EXEC eval "debconf-set-selections <<< 'proftpd-basic shared/proftpd/inetd_or_standalone select standalone'" G_AGI proftpd-basic G_EXEC systemctl stop proftpd # Config G_BACKUP_FP /etc/proftpd/proftpd.conf dps_index=$software_id Download_Install 'conf' /etc/proftpd/proftpd.conf # Do not allow root access via FTP G_EXEC sed --follow-symlinks -i 's/^[[:blank:]]*root/#root/' /etc/ftpusers # Fix ident lookup: https://github.com/MichaIng/DietPi/issues/4666 G_EXEC sed --follow-symlinks -i '/IdentLookups/c\\nIdentLookups off\n' /etc/proftpd/proftpd.conf fi if To_Install 96 nmbd smbd # Samba Server then # Link disk cache to RAM: https://github.com/MichaIng/DietPi/issues/2396 # - Remove previous disk cache dir or symlink G_EXEC rm -Rf /var/cache/samba # - Pre-create RAM cache dir G_EXEC mkdir -p /run/samba-cache # - Link disk cache to RAM G_EXEC ln -s /run/samba-cache /var/cache/samba # - Create RAM cache dir automatically on boot echo 'd /run/samba-cache' > /etc/tmpfiles.d/dietpi-samba_cache.conf # Config: Preserve on reinstall local reinstall=1 if [[ ! -f '/etc/samba/smb.conf' ]] || diff /usr/share/samba/smb.conf /etc/samba/smb.conf &> /dev/null then reinstall=0 dps_index=$software_id Download_Install 'conf' /etc/samba/smb.conf G_CONFIG_INJECT 'max connections =' " max connections = $(( $G_HW_CPU_CORES * 2 ))" /etc/samba/smb.conf Create_User -g dietpi -d /mnt/dietpi_userdata samba G_CONFIG_INJECT 'valid users =' ' valid users = samba' /etc/samba/smb.conf fi G_AGI samba G_EXEC systemctl stop nmbd smbd (( $reinstall )) || echo -e "$GLOBAL_PW\n$GLOBAL_PW" | smbpasswd -s -a samba fi if To_Install 95 vsftpd # vsftpd then # Config: Preserve on reinstall [[ -f '/etc/vsftpd.conf' ]] || dps_index=$software_id Download_Install 'conf' /etc/vsftpd.conf G_AGI vsftpd G_EXEC systemctl stop vsftpd # Do not allow root access via FTP G_EXEC sed --follow-symlinks -i 's/^[[:blank:]]*root/#root/' /etc/ftpusers fi if To_Install 109 nfs-server # NFS Server then G_AGI nfs-kernel-server G_EXEC systemctl stop nfs-server G_EXEC mkdir -p /etc/exports.d [[ -f '/etc/exports.d/dietpi.exports' ]] || G_EXEC eval 'echo '\''/mnt/dietpi_userdata *(rw,async,no_root_squash,crossmnt,no_subtree_check)'\'' > /etc/exports.d/dietpi.exports' fi if To_Install 83 apache2 # Apache then # Pre-create a dummy port 80 vhost if it does not exist yet, so we can avoid overwriting it on reinstalls. if [[ ! -f '/etc/apache2/sites-available/000-default.conf' ]] then G_EXEC mkdir -p /etc/apache2/sites-available cat << _EOF_ > /etc/apache2/sites-available/000-default.conf # /etc/apache2/sites-available/000-default.conf ServerName $(G_GET_NET ip) _EOF_ # Otherwise assure that the webroot is changed, as all our install options depend on it. else G_EXEC sed --follow-symlinks -i 's|/var/www/html|/var/www|g' /etc/apache2/sites-available/000-default.conf fi local apackages=('apache2') # Install Certbot module if Certbot was already installed (( ${aSOFTWARE_INSTALL_STATE[92]} == 2 )) && apackages+=('python3-certbot-apache') G_AGI "${apackages[@]}" G_EXEC systemctl stop apache2 apachectl -M | grep -q 'cache_disk' || G_EXEC systemctl --no-reload disable --now apache-htcacheclean # Enable event MPM and headers module G_EXEC a2dismod -fq mpm_prefork G_EXEC a2enmod -q mpm_event headers # Disable obsolete default configs for i in 'charset' 'localized-error-pages' 'other-vhosts-access-log' 'security' 'serve-cgi-bin' do [[ -L /etc/apache2/conf-enabled/$i.conf ]] && G_EXEC a2disconf "$i" done # Config cat << _EOF_ > /etc/apache2/conf-available/dietpi.conf # /etc/apache2/conf-available/dietpi.conf # Default server name and webroot ServerName $(G_GET_NET ip) DocumentRoot /var/www # Logging to: journalctl -u apache2 ErrorLog syslog # Allow unlimited Keep-Alive requests MaxKeepAliveRequests 0 # MPM event configuration # - Run a single process which does not expire # - Limit request handler threads to 64 StartServers 1 ServerLimit 1 MaxConnectionsPerChild 0 ThreadsPerChild 64 ThreadLimit 64 MinSpareThreads 1 MaxSpareThreads 64 MaxRequestWorkers 64 # Minimize public info ServerTokens Prod ServerSignature Off TraceEnable Off # Security headers Header set X-Content-Type-Options "nosniff" Header set X-Frame-Options "sameorigin" Header set X-XSS-Protection "0" Header set X-Robots-Tag "noindex, nofollow" Header set X-Permitted-Cross-Domain-Policies "none" Header set Referrer-Policy "no-referrer" _EOF_ G_EXEC a2enconf dietpi # Force service to start after PHP-FPM G_EXEC mkdir -p /etc/systemd/system/apache2.service.d G_EXEC eval "echo -e '[Unit]\nAfter=php$PHP_VERSION-fpm.service' > /etc/systemd/system/apache2.service.d/dietpi.conf" # Webroot [[ -f '/var/www/html/index.html' && ! -f '/var/www/index.html' ]] && G_EXEC mv /var/www/html/index.html /var/www/ [[ -d '/var/www/html' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /var/www/html fi if To_Install 85 nginx # Nginx then local apackages=('nginx-light') # From Bookworm on, the "nginx" package does not include any extra modules while "nginx-light" pulls in "nginx" and additionally the "echo" module. (( $G_DISTRO > 6 )) && apackages=('nginx') # Install Certbot module if Certbot was already installed (( ${aSOFTWARE_INSTALL_STATE[92]} == 2 )) && apackages+=('python3-certbot-nginx') G_AGI "${apackages[@]}" G_EXEC systemctl stop nginx # Custom configs included by sites-enabled/default within server directive, while nginx/(conf.d|sites-enabled) is included by nginx.conf outside server directive G_EXEC mkdir -p /etc/nginx/sites-dietpi G_BACKUP_FP /etc/nginx/nginx.conf dps_index=$software_id Download_Install 'nginx.conf' /etc/nginx/nginx.conf # CPU core count G_EXEC sed --follow-symlinks -i "/worker_processes/c\worker_processes $G_HW_CPU_CORES;" /etc/nginx/nginx.conf # Default site dps_index=$software_id Download_Install 'nginx.default' /etc/nginx/sites-available/default # Force service to start after PHP-FPM G_EXEC mkdir -p /etc/systemd/system/nginx.service.d G_EXEC eval "echo -e '[Unit]\nAfter=php$PHP_VERSION-fpm.service' > /etc/systemd/system/nginx.service.d/dietpi.conf" # Webroot [[ -f '/var/www/html/index.nginx-debian.html' ]] && G_EXEC mv /var/www/html/index.nginx-debian.html /var/www/ [[ -d '/var/www/html' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /var/www/html fi if To_Install 84 lighttpd # Lighttpd then # perl is required for lighty-enable-mod, but is a recommendation only G_AGI lighttpd perl G_EXEC systemctl stop lighttpd Remove_SysV lighttpd # Change webroot from /var/www/html to /var/www G_CONFIG_INJECT 'server.document-root' 'server.document-root = "/var/www"' /etc/lighttpd/lighttpd.conf if [[ -f '/var/www/html/index.lighttpd.html' ]] then G_EXEC mv /var/www/html/index.lighttpd.html /var/www/ G_EXEC sed --follow-symlinks -i 's|/var/www/html|/var/www|' /etc/lighttpd/lighttpd.conf fi [[ -d '/var/www/html' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /var/www/html # Disable conflicting fastcgi-php module [[ -f '/etc/lighttpd/conf-enabled/15-fastcgi-php.conf' ]] && G_EXEC lighty-disable-mod fastcgi-php [[ -f '/etc/lighttpd/conf-enabled/15-fastcgi-php-fpm.conf' ]] || G_EXEC lighty-enable-mod fastcgi-php-fpm # Force service to start after PHP-FPM G_EXEC mkdir -p /etc/systemd/system/lighttpd.service.d G_EXEC eval "echo -e '[Unit]\nAfter=php$PHP_VERSION-fpm.service' > /etc/systemd/system/lighttpd.service.d/dietpi.conf" fi if To_Install 88 mariadb # MariaDB then G_DIETPI-NOTIFY 2 'Preparing database directory at: /mnt/dietpi_userdata/mysql' if [[ -d '/mnt/dietpi_userdata/mysql' ]] then G_DIETPI-NOTIFY 2 '/mnt/dietpi_userdata/mysql exists, will migrate containing databases' else # Otherwise use possibly existent /var/lib/mysql # - Remove possible dead symlinks/files: G_EXEC rm -f /mnt/dietpi_userdata/mysql if [[ -d '/var/lib/mysql' ]] then G_DIETPI-NOTIFY 2 '/var/lib/mysql exists, will migrate containing databases' # Failsafe: Move symlink target in case, otherwise readlink will resolve to dir G_EXEC mv "$(readlink -f '/var/lib/mysql')" /mnt/dietpi_userdata/mysql else G_EXEC mkdir /mnt/dietpi_userdata/mysql fi fi G_EXEC rm -Rf /var/lib/mysql G_EXEC ln -s /mnt/dietpi_userdata/mysql /var/lib/mysql local apackages=('mariadb-server') # Install PHP module if PHP was already installed (( ${aSOFTWARE_INSTALL_STATE[89]} == 2 )) && apackages+=("php$PHP_VERSION-mysql") G_AGI "${apackages[@]}" G_EXEC systemctl stop mariadb Remove_SysV mysql 1 # Assure correct owner in case the database dir got migrated from a different system: https://github.com/MichaIng/DietPi/issues/4721#issuecomment-917051930 # - The group is correctly recursively fixed by the preinst script already. [[ -d '/mnt/dietpi_userdata/mysql/mysql' && $(stat -c '%U' /mnt/dietpi_userdata/mysql/mysql) != 'mysql' ]] && find /mnt/dietpi_userdata/mysql ! -user root ! -user mysql -exec chown mysql {} + # Force service to start before cron G_EXEC mkdir -p /etc/systemd/system/mariadb.service.d G_EXEC eval 'echo -e '\''[Unit]\nBefore=cron.service'\'' > /etc/systemd/system/mariadb.service.d/dietpi.conf' fi if To_Install 87 # SQLite then local apackages=('sqlite3') # Install PHP module if PHP was already installed (( ${aSOFTWARE_INSTALL_STATE[89]} == 2 )) && apackages+=("php$PHP_VERSION-sqlite3") G_AGI "${apackages[@]}" fi if To_Install 91 redis-server # Redis then local apackages=('redis-server') # Install PHP module if PHP was already installed (( ${aSOFTWARE_INSTALL_STATE[89]} == 2 )) && apackages+=("php$PHP_VERSION-redis") G_AGI "${apackages[@]}" G_EXEC systemctl stop redis-server # Enable Redis php module if installed command -v phpenmod > /dev/null && G_EXEC phpenmod redis # Disable file logging and enable syslog instead, which resolves reported startup issues in cases as well: https://github.com/MichaIng/DietPi/issues/3291 G_CONFIG_INJECT 'loglevel[[:blank:]]' 'loglevel warning' /etc/redis/redis.conf G_CONFIG_INJECT 'logfile[[:blank:]]' 'logfile ""' /etc/redis/redis.conf G_CONFIG_INJECT 'syslog-enabled[[:blank:]]' 'syslog-enabled yes' /etc/redis/redis.conf G_CONFIG_INJECT 'always-show-logo[[:blank:]]' 'always-show-logo no' /etc/redis/redis.conf # Force service to start before cron G_EXEC mkdir -p /etc/systemd/system/redis-server.service.d G_EXEC eval 'echo -e '\''[Unit]\nBefore=cron.service'\'' > /etc/systemd/system/redis-server.service.d/dietpi.conf' # Enable memory overcomit: https://github.com/jemalloc/jemalloc/issues/1328 if (( $G_HW_MODEL == 75 )) then [[ $(sysctl -n vm.overcommit_memory) == 1 ]] || G_WHIP_MSG '[WARNING] Memory overcomit is disabled \nFor Redis to run reliably, memory overcomit should be enabled. This can only be done on the host system of this container. E.g. run the following two commands on the host: echo vm.overcommit_memory=1 | sudo tee /etc/sysctl.d/98-dietpi-redis.conf sudo sysctl -p /etc/sysctl.d/98-dietpi-redis.conf' else G_EXEC eval 'echo '\''vm.overcommit_memory=1'\'' > /etc/sysctl.d/98-dietpi-redis.conf' G_EXEC sysctl -p /etc/sysctl.d/98-dietpi-redis.conf fi fi if To_Install 89 # PHP then # Base PHP modules # - Webserver: PHP-FPM if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 || ${aSOFTWARE_INSTALL_STATE[84]} > 0 || ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then local apackages=("php$PHP_VERSION-fpm") aENABLE_SERVICES+=("php$PHP_VERSION-fpm") # - No webserver: CLI usage only (php binary) else local apackages=("php$PHP_VERSION-cli") fi # Additional PHP modules, commonly used by most web applications apackages+=("php$PHP_VERSION-apcu" "php$PHP_VERSION-curl" "php$PHP_VERSION-gd" "php$PHP_VERSION-mbstring" "php$PHP_VERSION-xml" "php$PHP_VERSION-zip") # MySQL/MariaDB PHP module (( ${aSOFTWARE_INSTALL_STATE[88]} > 0 )) && apackages+=("php$PHP_VERSION-mysql") # SQLite PHP module (( ${aSOFTWARE_INSTALL_STATE[87]} > 0 )) && apackages+=("php$PHP_VERSION-sqlite3") # Redis PHP module (( ${aSOFTWARE_INSTALL_STATE[91]} > 0 )) && apackages+=("php$PHP_VERSION-redis") G_AGI "${apackages[@]}" systemctl -q is-active "php$PHP_VERSION-fpm" && G_EXEC systemctl stop "php$PHP_VERSION-fpm" # Assure that mod_php is purged in favour of PHP-FPM G_AGP 'libapache2-mod-php*' G_EXEC rm -Rf /{etc/php,var/lib/php/modules}/*/apache2 # PHP-FPM if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 || ${aSOFTWARE_INSTALL_STATE[84]} > 0 || ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then # Optimisations based on total cores G_CONFIG_INJECT 'pm.max_children[[:blank:]=]' "pm.max_children = $(( $G_HW_CPU_CORES * 3 ))" "/etc/php/$PHP_VERSION/fpm/pool.d/www.conf" G_CONFIG_INJECT 'pm.start_servers[[:blank:]=]' "pm.start_servers = $G_HW_CPU_CORES" "/etc/php/$PHP_VERSION/fpm/pool.d/www.conf" G_CONFIG_INJECT 'pm.min_spare_servers[[:blank:]=]' "pm.min_spare_servers = $G_HW_CPU_CORES" "/etc/php/$PHP_VERSION/fpm/pool.d/www.conf" G_CONFIG_INJECT 'pm.max_spare_servers[[:blank:]=]' "pm.max_spare_servers = $G_HW_CPU_CORES" "/etc/php/$PHP_VERSION/fpm/pool.d/www.conf" # Set static PATH, not passed by Lighttpd and Nginx by default but required by some web applications: https://github.com/MichaIng/DietPi/issues/5161#issuecomment-1013381362 G_CONFIG_INJECT 'env\[PATH\][[:blank:]=]' 'env[PATH] = /usr/local/bin:/usr/bin:/bin' "/etc/php/$PHP_VERSION/fpm/pool.d/www.conf" # Force service to start after database servers G_EXEC mkdir -p "/etc/systemd/system/php$PHP_VERSION-fpm.service.d" G_EXEC eval "echo -e '[Unit]\nAfter=redis-server.service mariadb.service postgresql.service' > '/etc/systemd/system/php$PHP_VERSION-fpm.service.d/dietpi.conf'" fi # We create our own PHP mod to add DietPi specific configs. target_php_ini="/etc/php/$PHP_VERSION/mods-available/dietpi.ini" echo -e '; DietPi PHP settings\n; priority=97' > "$target_php_ini" # Session files need to be outside of /tmp and /var/tmp due to PrivateTmp=true, else phpsessionclean.service cannot clean sessions G_EXEC mkdir -p /run/php_sessions G_EXEC chmod 1733 /run/php_sessions echo -e '# Pre-create PHP sessions dir\nd /run/php_sessions 1733' > /etc/tmpfiles.d/dietpi-php_sessions.conf G_CONFIG_INJECT 'session.save_path[[:blank:]=]' 'session.save_path="/run/php_sessions"' "$target_php_ini" # File uploads: https://github.com/MichaIng/DietPi/issues/546 # - This is especially relevant for cloud software like ownCloud/Nextcloud. # - Generally we want to hold tmp upload files in RAM to reduce disk (especially SD card) writes for performance and disk wear reasons. # - By default only max 2 MiB file uploads are allowed, hold in /tmp tmpfs, which is safe but not usable for usual cloud usage. # - ownCloud/Nextcloud do/did override this limit to 512 MiB, a reasonable limit which can usually still be hold in RAM without issues. # - Low RAM devices (RPi1 256 MiB model) require a swap file for this, however, it is still better to cause disk writes through swap file during large file uploads only, then doing this for each and every uploaded file. # - When larger file uploads are required, it depends on the system total RAM, rootfs disk and available external drives if/where to move tmp file uploads, resize or move swap file. This should be then left to user. G_CONFIG_INJECT 'upload_tmp_dir[[:blank:]=]' 'upload_tmp_dir="/tmp"' "$target_php_ini" G_CONFIG_INJECT 'upload_max_filesize[[:blank:]=]' 'upload_max_filesize=512M' "$target_php_ini" G_CONFIG_INJECT 'post_max_size[[:blank:]=]' 'post_max_size=512M' "$target_php_ini" # - Nginx: https://github.com/MichaIng/DietPi/issues/546 => https://github.com/MichaIng/DietPi/blob/dev/.conf/dps_85/nginx.conf # Cache settings local cache_size=$(( $RAM_PHYS / 30 )) (( $cache_size < 16 )) && cache_size=16 # - OPcache G_CONFIG_INJECT 'opcache.memory_consumption[[:blank:]=]' "opcache.memory_consumption=$cache_size" "$target_php_ini" G_CONFIG_INJECT 'opcache.revalidate_freq[[:blank:]=]' 'opcache.revalidate_freq=60' "$target_php_ini" # 1 minute # - JIT is available since PHP 8.0 for x86_64 and since PHP 8.2 for ARMv8. Enable it with 2 MiB size, since we never saw usage far above 1 MiB for whatever reason. # - Skip on ARMv8 for now, since tracing JIT produces segmentation faults there, and function JIT requires a lot more memory: https://github.com/php/php-src/issues/7817 # - On dietpi.com x86_64 server, we suffered from segmentation faults as well for a while, but there it seems to have been solved. if (( $G_DISTRO > 6 && $G_HW_ARCH == 10 )) then G_CONFIG_INJECT 'opcache.jit[[:blank:]=]' 'opcache.jit=1' "$target_php_ini" # 1/on = "tracing", follow default for now: https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit G_CONFIG_INJECT 'opcache.jit_buffer_size[[:blank:]=]' 'opcache.jit_buffer_size=2M' "$target_php_ini" fi # - APCu G_CONFIG_INJECT 'apc.shm_size[[:blank:]=]' "apc.shm_size=$(( $cache_size / 2 ))M" "$target_php_ini" G_CONFIG_INJECT 'apc.ttl[[:blank:]=]' 'apc.ttl=259200' "$target_php_ini" # 3 days # - Enable G_EXEC phpenmod dietpi # Apache: Enable PHP-FPM command -v a2enconf > /dev/null && { G_EXEC a2enmod proxy_fcgi setenvif; G_EXEC a2enconf "php$PHP_VERSION-fpm"; } fi if To_Install 34 # PHP Composer then G_EXEC curl -sSfL 'https://getcomposer.org/composer-stable.phar' -o /usr/local/bin/composer G_EXEC chmod +x /usr/local/bin/composer fi if To_Install 90 # phpMyAdmin then # Install required PHP modules: https://docs.phpmyadmin.net/en/latest/require.html#php # - Add JSON module for PHP7, as it does not exist (embedded in core package) on PHP8 local json=() [[ $PHP_VERSION == 8* ]] || json=("php$PHP_VERSION-json") G_AGI "php$PHP_VERSION"-{curl,gd,mbstring,xml,zip} "${json[@]}" # Quick install: https://docs.phpmyadmin.net/en/latest/setup.html#quick-install # - Get latest version name local version=$(curl -sSfL 'https://api.github.com/repos/phpmyadmin/phpmyadmin/releases' | mawk -F\" '/^ *"name": "/ && $4!~/rc/ {print $4}' | sort -rV | head -1) [[ $version ]] || { version='5.2.2'; G_DIETPI-NOTIFY 1 "Automatic latest ${aSOFTWARE_NAME[$software_id]} version detection failed. Version \"$version\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } Download_Install "https://files.phpmyadmin.net/phpMyAdmin/$version/phpMyAdmin-$version-english.tar.xz" # - Reinstall: Clean install but preserve existing config file [[ -f '/var/www/phpmyadmin/config.inc.php' ]] && G_EXEC mv /var/www/phpmyadmin/config.inc.php "phpMyAdmin-$version-english/" G_EXEC rm -Rf /var/www/phpmyadmin # Include pre-v6.27 symlink: https://github.com/MichaIng/DietPi/issues/3304 # - Remove GUI setup: https://docs.phpmyadmin.net/en/latest/setup.html#securing-your-phpmyadmin-installation G_EXEC rm -R "phpMyAdmin-$version-english/setup" # - Move new instance in place G_EXEC mv "phpMyAdmin-$version-english" /var/www/phpmyadmin # Enable required PHP modules: https://docs.phpmyadmin.net/en/latest/require.html#php G_EXEC phpenmod ctype curl gd mbstring xml zip "${json[@]##*-}" # Install and enable webserver config # - Apache if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )) then dps_index=$software_id Download_Install 'apache.phpmyadmin.conf' /etc/apache2/sites-available/dietpi-phpmyadmin.conf G_EXEC a2ensite dietpi-phpmyadmin # - Lighttpd elif (( ${aSOFTWARE_INSTALL_STATE[84]} > 0 )) then dps_index=$software_id Download_Install 'lighttpd.phpmyadmin.conf' /etc/lighttpd/conf-available/98-dietpi-phpmyadmin.conf G_EXEC_POST_FUNC(){ [[ $exit_code == 2 ]] && exit_code=0; } # Do not fail if modules are enabled already G_EXEC lighty-enable-mod dietpi-phpmyadmin # - Nginx elif (( ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then dps_index=$software_id Download_Install 'nginx.phpmyadmin.conf' /etc/apache2/sites-dietpi/dietpi-phpmyadmin.conf fi # Copy default config in place and adjust if not already existent if [[ ! -f '/var/www/phpmyadmin/config.inc.php' ]] then G_EXEC cp -a /var/www/phpmyadmin/config.sample.inc.php /var/www/phpmyadmin/config.inc.php GCI_PASSWORD=1 G_CONFIG_INJECT "\\\$cfg\\['blowfish_secret'][[:blank:]]*=" "\$cfg['blowfish_secret'] = '$(openssl rand -base64 32)';" /var/www/phpmyadmin/config.inc.php fi # Create MariaDB database and user if [[ -d '/mnt/dietpi_userdata/mysql/phpmyadmin' ]] then G_DIETPI-NOTIFY 2 'phpMyAdmin MariaDB database found, will NOT overwrite.' else /boot/dietpi/func/create_mysql_db phpmyadmin phpmyadmin "$GLOBAL_PW" mysql phpmyadmin < /var/www/phpmyadmin/sql/create_tables.sql # Since "root" user cannot be used for login (unix_socket authentication), grant full admin privileges to "phpmyadmin" mysql -e 'grant all privileges on *.* to phpmyadmin@localhost with grant option;' fi # Pre-create TempDir: https://docs.phpmyadmin.net/en/latest/config.html#cfg_TempDir G_EXEC mkdir -p /var/www/phpmyadmin/tmp G_EXEC chown www-data:root /var/www/phpmyadmin/tmp G_EXEC chmod 700 /var/www/phpmyadmin/tmp fi if To_Install 125 synapse # Synapse: https://element-hq.github.io/synapse/latest/setup/installation.html#installing-as-a-python-module-from-pypi then # Dependencies Python_Deps -i bcrypt cryptography pillow psycopg2 pynacl matrix-synapse # Install G_EXEC_OUTPUT=1 G_EXEC pip3 install -U matrix-synapse psycopg2 # User Create_User -d /mnt/dietpi_userdata/synapse synapse # Service cat << '_EOF_' > /etc/systemd/system/synapse.service [Unit] Description=Synapse (DietPi) Wants=network-online.target After=network-online.target postgresql.service [Service] Type=notify SyslogIdentifier=Synapse User=synapse WorkingDirectory=/mnt/dietpi_userdata/synapse ExecStart=/usr/bin/python3 -m synapse.app.homeserver -c homeserver.yaml -c homeserver.yaml.d ExecReload=/bin/kill -HUP $MAINPID [Install] WantedBy=multi-user.target _EOF_ # Database G_EXEC systemctl start postgresql local synapse_pass=$(tr -dc '[:alnum:]' < /dev/random | head -c30) if [[ $(runuser -u postgres -- psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='synapse'") != 1 ]] then G_EXEC runuser -u postgres -- psql -c "CREATE ROLE synapse WITH LOGIN PASSWORD '$synapse_pass';" else G_EXEC runuser -u postgres -- psql -c "ALTER ROLE synapse WITH PASSWORD '$synapse_pass';" fi if [[ $(runuser -u postgres -- psql -tAc "SELECT 1 FROM pg_database WHERE datname='synapse'") != 1 ]] then G_EXEC runuser -u postgres -- createdb --encoding=UTF8 --locale=C --template=template0 --owner=synapse synapse fi # Pre-create drop-in config for database access details G_EXEC mkdir -p /mnt/dietpi_userdata/synapse/homeserver.yaml.d cat << _EOF_ > /mnt/dietpi_userdata/synapse/homeserver.yaml.d/00-dietpi.yaml # PostgreSQL access details # NB: Do not edit this file, instead override settings via e.g.: homeserver.yaml.d/99-local.conf database: name: psycopg2 args: host: /run/postgresql port: 5432 user: synapse password: $synapse_pass database: synapse cp_min: 5 cp_max: 10 _EOF_ # Config if [[ ! -f '/mnt/dietpi_userdata/synapse/homeserver.yaml' ]] then G_WHIP_DEFAULT_ITEM=$(sed -n '/^[[:blank:]]*SOFTWARE_PUBLIC_DOMAIN_NAME=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $G_WHIP_DEFAULT_ITEM ]] || G_WHIP_DEFAULT_ITEM=$(find /etc/letsencrypt/live -mindepth 1 -maxdepth 1 -type d -print -quit 2> /dev/null) [[ $G_WHIP_DEFAULT_ITEM ]] || G_WHIP_DEFAULT_ITEM=$(hostname -f) G_WHIP_NOCANCEL=1 G_WHIP_INPUTBOX 'Please enter the name for this homeserver.\nIt is recommended that this be the public domain name that this server will be hosted on.' local servername=${G_WHIP_RETURNED_VALUE#http*://} GCI_PRESERVE=1 G_CONFIG_INJECT 'SOFTWARE_PUBLIC_DOMAIN_NAME=' "SOFTWARE_PUBLIC_DOMAIN_NAME=$servername" /boot/dietpi.txt G_WHIP_DEFAULT_ITEM=$(sed -n '/^[[:blank:]]*SOFTWARE_SYNAPSE_USERNAME=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $G_WHIP_DEFAULT_ITEM ]] || G_WHIP_DEFAULT_ITEM='dietpi' G_WHIP_NOCANCEL=1 G_WHIP_INPUTBOX 'Please enter the admin username for this homeserver. It will use the default software password.' local username=$G_WHIP_RETURNED_VALUE G_EXEC cd /mnt/dietpi_userdata/synapse # Create initial config G_EXEC python3 -m synapse.app.homeserver -H "$servername" -c homeserver.yaml --generate-config --report-stats 'no' # Enable registrations via random shared secret GCI_PASSWORD=1 G_CONFIG_INJECT 'registration_shared_secret:[[:blank:]]' "registration_shared_secret: $(openssl rand -hex 16)" homeserver.yaml # Allow remote access G_CONFIG_INJECT 'bind_addresses:[[:blank:]]' " bind_addresses: ['::']" homeserver.yaml # Log to journal with log level WARNING G_EXEC sed --follow-symlinks -i 's/ handlers: \[.*\]$/ handlers: [console]/' "$servername.log.config" G_EXEC sed --follow-symlinks -i 's/ level: .*/ level: WARNING/' "$servername.log.config" # Permissions G_EXEC chown -R synapse:synapse . G_EXEC chmod 0660 homeserver.yaml{,.d/*.yaml} G_EXEC chmod 0770 homeserver.yaml.d # Register admin user G_EXEC systemctl daemon-reload G_EXEC systemctl start synapse G_EXEC_PRE_FUNC(){ acommand[4]="$GLOBAL_PW"; } # Mask password in console output G_EXEC_OUTPUT=1 G_EXEC register_new_matrix_user -u "$username" -p "${GLOBAL_PW//?/X}" -a -c homeserver.yaml 'http://127.0.0.1:8008' G_EXEC cd "$G_WORKING_DIR" unset -v servername username else # Permissions G_EXEC chown -R synapse:synapse /mnt/dietpi_userdata/synapse G_EXEC chmod 0660 /mnt/dietpi_userdata/synapse/homeserver.yaml{,.d/*.yaml} G_EXEC chmod 0770 /mnt/dietpi_userdata/synapse/homeserver.yaml.d fi fi if To_Install 128 mpd # MPD then G_AGI mpd G_EXEC systemctl stop mpd # Service # - Run systemd unit as "mpd" user instead of using config file based user change, to preserve supplementary group permissions (i.e. "dietpi") # - Skip environment file so that usage of our config file is assured G_EXEC mkdir -p /etc/systemd/system/mpd.service.d cat << '_EOF_' > /etc/systemd/system/mpd.service.d/dietpi.conf [Service] User=mpd RuntimeDirectory=mpd EnvironmentFile= ExecStart= ExecStart=/usr/bin/mpd --systemd _EOF_ (( $G_DISTRO < 7 )) && G_EXEC sed --follow-symlinks -i 's/systemd/no-daemon/' /etc/systemd/system/mpd.service.d/dietpi.conf Remove_SysV mpd 1 # Config G_CONFIG_INJECT 'music_directory[[:blank:]]' 'music_directory "/mnt/dietpi_userdata/Music"' /etc/mpd.conf G_CONFIG_INJECT 'playlist_directory[[:blank:]]' 'playlist_directory "/mnt/dietpi_userdata/Music"' /etc/mpd.conf G_CONFIG_INJECT 'db_file[[:blank:]]' 'db_file "/mnt/dietpi_userdata/.mpd_cache/db_file"' /etc/mpd.conf # - Log to journal G_EXEC sed --follow-symlinks -Ei 's/^[[:blank:]]*log_file[[:blank:]]+/#log_file /' /etc/mpd.conf # - PID file is not required for systemd G_EXEC sed --follow-symlinks -Ei 's/^[[:blank:]]*pid_file[[:blank:]]+/#pid_file /' /etc/mpd.conf G_CONFIG_INJECT 'state_file[[:blank:]]' 'state_file "/mnt/dietpi_userdata/.mpd_cache/state"' /etc/mpd.conf G_CONFIG_INJECT 'sticker_file[[:blank:]]' 'sticker_file "/mnt/dietpi_userdata/.mpd_cache/sticker.sql"' /etc/mpd.conf # - Our service starts as "mpd" user already G_EXEC sed --follow-symlinks -Ei 's/^[[:blank:]]*user[[:blank:]]+/#user /' /etc/mpd.conf G_EXEC sed --follow-symlinks -Ei 's/^[[:blank:]]*group[[:blank:]]+/#group /' /etc/mpd.conf # - Enable UNIX socket G_CONFIG_INJECT 'bind_to_address[[:blank:]]+"/run/mpd/socket"' 'bind_to_address "/run/mpd/socket"' /etc/mpd.conf # - Add simple ALSA output if none present yet grep -q '^[[:blank:]]*audio_output[[:blank:]]' /etc/mpd.conf || cat << '_EOF_' >> /etc/mpd.conf # Simple ALSA output audio_output { type "alsa" name "DietPi ALSA" } _EOF_ # RPi JustBoom can handle SOXR VH @ 192khz 32bit: https://github.com/MichaIng/DietPi/issues/581#issuecomment-256643079 if grep -q '^[[:blank:]]*CONFIG_SOUNDCARD=justboom' /boot/dietpi.txt then # Force 192khz 32bit for all outputs: Better would be to apply it to the single JustBoom output device, but we'll leave this for now for simplicity. G_CONFIG_INJECT 'audio_output_format[[:blank:]]' 'audio_output_format "32:192000:2"' /etc/mpd.conf # Use highest SOXR quality: "samplerate_converter" is actually deprecated with v0.20.0 and replaced by a "resampler" block, but we'll leave this for now for simplicity. G_CONFIG_INJECT 'samplerate_converter[[:blank:]]' 'samplerate_converter "soxr very high"' /etc/mpd.conf fi # User Create_User -g audio -G dietpi -d /mnt/dietpi_userdata/.mpd_cache mpd # Dirs # - Move possibly existing audio and playlist files to userdata [[ ! -e '/var/lib/mpd/music' || -L '/var/lib/mpd/music' || $(find /var/lib/mpd/music -maxdepth 0 -empty) ]] || G_EXEC mv -n /var/lib/mpd/music/* /mnt/dietpi_userdata/Music/ [[ ! -e '/var/lib/mpd/playlists' || -L '/var/lib/mpd/playlists' || $(find /var/lib/mpd/playlists -maxdepth 0 -empty) ]] || G_EXEC mv -n /var/lib/mpd/playlists/* /mnt/dietpi_userdata/Music/ # - Purge obsolete data and log dirs and clear cache G_EXEC rm -Rf /var/lib/mpd /var/log/mpd /mnt/dietpi_userdata/.mpd_cache # - Recreate cache dir G_EXEC mkdir /mnt/dietpi_userdata/.mpd_cache Download_Test_Media # Permissions G_EXEC chown -R mpd:root /mnt/dietpi_userdata/.mpd_cache /etc/mpd.conf fi if To_Install 54 # phpBB then # Pre-v6.33: Support old and new location PHPBB_LOC='phpbb' [[ -d '/var/www/phpBB3' ]] && PHPBB_LOC='phpBB3' # Reinstall: Skip download and install, advice to use internal updater from web UI if [[ -d /var/www/$PHPBB_LOC ]] then G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$software_id]} install dir \"/var/www/$PHPBB_LOC\" already exists. Download and install steps will be skipped. - If you want to update ${aSOFTWARE_NAME[$software_id]}, please follow the instructions from web UI ACP. - If you need to reinstall (e.g. broken instance), please manually backup your config files+data, remove the install dir and rerun \"dietpi-software (re)install $software_id\"." else local fallback_url='https://download.phpbb.com/pub/release/3.3/3.3.15/phpBB-3.3.15.tar.bz2' Download_Install "$(curl -sSf 'https://version.phpbb.com/phpbb/versions.json' | sed -En '/"stable":/,/"unstable":/s/.*"current": "(.+)",.*/\1/p' | sort -Vr | head -1)" # Files are shipped with UID:GID 1000:1000 while for security reasons it should be root:root. G_EXEC chown -R root:root phpBB3 G_EXEC mv phpBB3 /var/www/phpbb fi # Preserve old database name [[ -d '/mnt/dietpi_userdata/mysql/phpbb3' ]] || /boot/dietpi/func/create_mysql_db phpbb phpbb "$GLOBAL_PW" # Permissions: The web-based installer writes setup and database access information to this file. Upload, cache and store directories are shipped with 777 modes already. G_EXEC chown www-data "/var/www/$PHPBB_LOC/config.php" fi if To_Install 133 yacy # YaCy then # Get latest download local file=$(curl -sSfL 'https://download.yacy.net/?C=N;O=D' | grep -o 'yacy_v[0-9._a-f]*\.tar\.gz' | head -1) [[ $file ]] || { file='yacy_v1.940_202405270005_70454654f.tar.gz'; G_DIETPI-NOTIFY 1 "Automatic latest ${aSOFTWARE_NAME[$software_id]} version detection failed. \"$file\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } Download_Install "https://download.yacy.net/$file" /etc # Service cat << '_EOF_' > /etc/systemd/system/yacy.service [Unit] Description=YaCy (DietPi) Documentation=https://wiki.yacy.net/index.php/En:Start Wants=network-online.target After=network-online.target [Service] Type=forking ExecStart=/etc/yacy/startYACY.sh ExecStop=/etc/yacy/stopYACY.sh [Install] WantedBy=multi-user.target _EOF_ # Set admin interface passwd: if [[ ! -f '/etc/yacy/DATA/SETTINGS/yacy.conf' ]] then Create_Config /etc/yacy/DATA/SETTINGS/yacy.conf yacy /etc/yacy/bin/passwd.sh "$GLOBAL_PW" fi fi if To_Install 186 ipfs # Kubo then local version= case $G_HW_ARCH in 3) local arch='arm64';; 10) local arch='amd64';; *) local arch='arm' version='v0.33.2';; # latest version with 32-bit builds esac if [[ $version ]] then G_DIETPI-NOTIFY 2 "For your architecture, the latest available ${aSOFTWARE_NAME[$software_id]} builds are $version." else # Find latest version version=$(curl -sSfL 'https://dist.ipfs.tech/kubo/versions' | sed '/-rc[0-9]*$/d' | tail -1) [[ $version ]] || { version='v0.37.0'; G_DIETPI-NOTIFY 1 "Automatic latest ${aSOFTWARE_NAME[$software_id]} version detection failed. Version \"$version\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } fi Download_Install "https://dist.ipfs.tech/kubo/$version/kubo_${version}_linux-$arch.tar.gz" # Install G_EXEC_OUTPUT=1 G_EXEC kubo/install.sh # Data and config directory G_EXEC mkdir -p /mnt/dietpi_userdata/ipfs # User Create_User -d /mnt/dietpi_userdata/ipfs ipfs # Service cat << '_EOF_' > /etc/systemd/system/ipfs.service [Unit] Description=Kubo IPFS Node (DietPi) Documentation=https://docs.ipfs.io/reference/go/api/ Wants=network-online.target After=network-online.target [Service] User=ipfs Environment=IPFS_PATH=/mnt/dietpi_userdata/ipfs ExecStart=/usr/local/bin/ipfs daemon [Install] WantedBy=multi-user.target _EOF_ # Config: Preserve existing on reinstall if [[ ! -f '/mnt/dietpi_userdata/ipfs/config' ]] then IPFS_PATH='/mnt/dietpi_userdata/ipfs' G_EXEC_OUTPUT=1 G_EXEC ipfs init IPFS_PATH='/mnt/dietpi_userdata/ipfs' G_EXEC ipfs config --json Addresses.Gateway '"/ip4/0.0.0.0/tcp/8087"' IPFS_PATH='/mnt/dietpi_userdata/ipfs' G_EXEC ipfs config --json Addresses.API '"/ip4/0.0.0.0/tcp/5003"' IPFS_PATH='/mnt/dietpi_userdata/ipfs' G_EXEC ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]' fi # Permissions G_EXEC chown -R 'ipfs:ipfs' /mnt/dietpi_userdata/ipfs # CLI alias echo 'alias ipfs='\''sudo -u ipfs IPFS_PATH=/mnt/dietpi_userdata/ipfs ipfs'\' > /etc/bashrc.d/dietpi-ipfs.sh # Raise UDP buffer sizes: https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes if (( $G_HW_MODEL == 75 )) then (( $(sysctl -n net.core.rmem_max) >= 7500000 && $(sysctl -n net.core.wmem_max) >= 7500000 )) || G_WHIP_MSG '[WARNING] UDP buffer size limits might be too small \nFor QUIC, used by the Kubo, the bandwidth can be limited by the UDP buffer sizes. Hence it is recommended to raise their limit. This can only be done on the host of this container. E.g. add the following lines to a new sysctl config file like /etc/sysctl.d/dietpi-ipfs.conf: net.core.rmem_max=7500000 net.core.wmem_max=7500000 \nApply them without reboot like this: sudo sysctl -p /etc/sysctl.d/dietpi-ipfs.conf \nMore info: https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes' else G_EXEC eval 'echo -e '\''net.core.rmem_max=7500000\nnet.core.wmem_max=7500000'\'' > /etc/sysctl.d/dietpi-ipfs.conf' G_EXEC sysctl -p /etc/sysctl.d/dietpi-ipfs.conf fi fi if To_Install 16 # microblog.pub then local micro_name='microblog-pub' # Obtain latest Python 3.11.y version supported by pyenv local micro_python_version=$(curl -sSfL 'https://api.github.com/repos/pyenv/pyenv/contents/plugins/python-build/share/python-build?ref=master' | mawk -F\" '/^ *"name": "3\.11\.[0-9]*",$/{print $4}' | sort -Vr | head -1) [[ $micro_python_version ]] || { micro_python_version='3.11.13'; G_DIETPI-NOTIFY 1 "Automatic latest Python version detection failed. Version \"$micro_python_version\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } local micro_pyenv_dir="/opt/$micro_name" local micro_pyenv_activate_file="$micro_pyenv_dir/pyenv-activate.sh" local micro_virtualenv="$micro_pyenv_dir/.virtual_path" local micro_data_dir="/mnt/dietpi_userdata/$micro_name" local micro_systemd="/etc/systemd/system/$micro_name.service" local micro_functions="/etc/bashrc.d/$micro_name.sh" # Clone the repo into data dir if [[ ! -d $micro_data_dir ]] then G_EXEC_OUTPUT=1 G_EXEC git clone 'https://git.sr.ht/~tsileo/microblog.pub' "$micro_data_dir" # Enable remote access on port 8007 G_EXEC sed --follow-symlinks -i 's/uvicorn app/uvicorn --host 0.0.0.0 --port 8007 app/' "$micro_data_dir/misc/supervisord.conf" G_EXEC sed --follow-symlinks -i 's/8000/8007/' "$micro_data_dir/data/tests.toml" # Disable package mode to prevent: "Error: The current project could not be installed: No file/folder found for package microblogpub" G_CONFIG_INJECT 'package-mode[[:blank:]]' 'package-mode = false' "$micro_data_dir/pyproject.toml" '\[tool.poetry\]' fi # Disable pip cache G_EXEC mkdir -p "$micro_data_dir/.pip" G_EXEC eval "echo -e '[global]\nno-cache-dir=true' > '$micro_data_dir/.pip/pip.conf'" # User Create_User -d "$micro_data_dir" "$micro_name" G_EXEC chown -R "$micro_name:$micro_name" "$micro_data_dir" # Dependencies PYTHON_VERSION=$micro_python_version Python_Deps -u "$micro_name" pyenv poetry bcrypt brotli libsass lxml pillow # Create a Python environment via pyenv # - https://python-poetry.org/docs/managing-environments/ Download_Install 'https://github.com/pyenv/pyenv/archive/master.tar.gz' G_EXEC chown -R "$micro_name:$micro_name" pyenv-master # - Start with fresh instance to allow clean pyenv and Python updates and fix broken instances. [[ -d $micro_pyenv_dir ]] && G_EXEC rm -R "$micro_pyenv_dir" G_EXEC mv pyenv-master "$micro_pyenv_dir" # Generate script to activate pyenv echo "#!/bin/dash cd $micro_pyenv_dir || return 1 export PYENV_ROOT='$micro_pyenv_dir' || return 1 export PATH=\"\$PYENV_ROOT/bin:\$PATH\" || return 1 eval \"\$(pyenv init --path)\" || return 1 eval \"\$(pyenv init -)\" || return 1 cd $micro_data_dir [ -f '.cargo/env' ] && . .cargo/env PS1=\"(microblog.pub) \$PS1\"" > "$micro_pyenv_activate_file" G_EXEC_DESC="Compiling and installing Python $micro_python_version into pyenv, which will take a while ..." G_EXEC_OUTPUT=1 G_EXEC runuser -u "$micro_name" -- dash -c ". $micro_pyenv_activate_file; exec pyenv install $micro_python_version" G_EXEC_DESC="Setting Python $micro_python_version as global version for this pyenv instance" G_EXEC_OUTPUT=1 G_EXEC runuser -u "$micro_name" -- dash -c ". $micro_pyenv_activate_file; exec pyenv global $micro_python_version" G_EXEC_DESC='Upgrading base modules: pip setuptools wheel' G_EXEC_OUTPUT=1 G_EXEC runuser -u "$micro_name" -- dash -c ". $micro_pyenv_activate_file; exec pip3 install -U pip setuptools wheel" G_EXEC_DESC='Installing Poetry' G_EXEC_OUTPUT=1 G_EXEC runuser -u "$micro_name" -- dash -c ". $micro_pyenv_activate_file; exec pip3 install poetry" G_EXEC_DESC='Updating dependency locks' G_EXEC_OUTPUT=1 G_EXEC runuser -u "$micro_name" -- dash -c ". $micro_pyenv_activate_file; exec poetry update --lock" G_EXEC_DESC='Installing microblog.pub' G_EXEC_OUTPUT=1 G_EXEC runuser -u "$micro_name" -- dash -c ". $micro_pyenv_activate_file; exec poetry install" G_EXEC_DESC='Storing Poetry virtualenv path' G_EXEC_OUTPUT=1 G_EXEC runuser -u "$micro_name" -- dash -c ". $micro_pyenv_activate_file; poetry env info | grep -Po '(?<=^Path:\s).*/virtualenvs/.*' > '$micro_virtualenv'" read -r VENV_DIR < "$micro_virtualenv" # shellcheck disable=SC2016 G_EXEC_DESC='Checking Poetry virtualenv path' G_EXEC eval '[[ $VENV_DIR ]]' G_EXEC rm "$micro_virtualenv" # Generate functions for later configuration and install to profile cat << _EOF_ > "$micro_functions" #!/bin/dash microblog-pub() { case \$1 in c*) sudo -u '$micro_name' dash -c '. $micro_pyenv_activate_file; poetry run inv configuration-wizard && poetry run inv migrate-db' && systemctl enable '$micro_name';; u*) sudo -u '$micro_name' dash -c '. $micro_pyenv_activate_file; git pull && poetry run inv update';; v*) sudo -u '$micro_name' bash --init-file '$micro_pyenv_activate_file';; *) echo 'microblog.pub helper script usage: microblog-pub where: configure runs the configuration wizard and updates the microblog environment. update pulls the latest changes from the microblog repository and reconfigures. venv starts a virtual environment where the microblog can be configured.' && return 1;; esac sudo systemctl restart '$micro_name' } _EOF_ # Generate systemd service cat << _EOF_ > "$micro_systemd" [Unit] Description=microblog.pub (DietPi) Wants=network-online.target After=network-online.target [Service] User=$micro_name SyslogIdentifier=microblog.pub WorkingDirectory=$micro_data_dir Environment="VENV_DIR=$VENV_DIR" ExecStart=/bin/dash -c '. $micro_pyenv_activate_file; exec poetry run supervisord -c misc/supervisord.conf -n' RestartForceExitStatus=100 [Install] WantedBy=multi-user.target _EOF_ G_WHIP_MSG '[ INFO ] microblog.pub installation finished\n\nIn order to complete the setup, please run "microblog-pub configure" in a new bash session.\n\nNB: Append the port ":8007" to the domain when being asked for it if you do not use a reverse proxy.' G_DIETPI-NOTIFY 0 'microblog.pub installation finished. In order to complete the setup, please run "microblog-pub configure" in a new bash session. Append the port ":8007" to the domain when being asked for it if you do not use a reverse proxy.' fi if To_Install 2 fahclient # Folding@Home then G_DIETPI-NOTIFY 2 'Pre-configuring FAHClient DEB package' debconf-set-selections <<< 'fahclient fahclient/autostart boolean false' # Do not start SysV service after package install debconf-set-selections <<< 'fahclient fahclient/power select light' debconf-set-selections <<< 'fahclient fahclient/team string 234437' # Team "DietPi" debconf-set-selections <<< 'fahclient fahclient/user string DietPi' # User "DietPi" debconf-set-selections <<< 'fahclient fahclient/passkey string 06c869246e88c00cb05cc4d1758a97f9' # Passkey for user "DietPi" local arch1='64bit' arch2='amd64' (( $G_HW_ARCH == 3 )) && arch1='arm64' arch2='arm64' Download_Install "https://download.foldingathome.org/releases/v7/public/fahclient/debian-stable-$arch1/release/fahclient_7.6.21_$arch2.deb" # Remove obsolete config + data directories and SysV service + config [[ -d '/var/lib/fahclient' ]] && G_EXEC rm -R /var/lib/fahclient [[ -d '/etc/fahclient' ]] && G_EXEC rm -R /etc/fahclient [[ -f '/etc/default/fahclient' ]] && G_EXEC rm /etc/default/fahclient Remove_SysV FAHClient # Prepare our new config + data directory if not yet present if [[ ! -f '/mnt/dietpi_userdata/fahclient/config.xml' ]] then G_EXEC mkdir -p /mnt/dietpi_userdata/fahclient dps_index=$software_id Download_Install 'config.xml' /mnt/dietpi_userdata/fahclient/config.xml fi # Service cat << _EOF_ > /etc/systemd/system/fahclient.service [Unit] Description=Folding@Home (DietPi) Wants=network-online.target After=network-online.target [Service] User=fahclient WorkingDirectory=/mnt/dietpi_userdata/fahclient ExecStart=$(command -v FAHClient) [Install] WantedBy=multi-user.target _EOF_ # Permissions G_EXEC chown -R fahclient /mnt/dietpi_userdata/fahclient fi if To_Install 47 # ownCloud then aDEPS=("php$PHP_VERSION-intl") # https://doc.owncloud.com/server/next/admin_manual/installation/manual_installation/manual_installation_prerequisites.html#php-extensions if [[ -f '/var/www/owncloud/occ' ]] then G_DIETPI-NOTIFY 2 'Existing ownCloud installation found, will NOT overwrite...' else local datadir=$(sed -n '/^[[:blank:]]*SOFTWARE_OWNCLOUD_DATADIR=/{s/^[^=]*=//;s|/$||;p;q}' /boot/dietpi.txt) [[ $datadir ]] || datadir='/mnt/dietpi_userdata/owncloud_data' if [[ -f $datadir/dietpi-owncloud-installation-backup/occ ]] then G_DIETPI-NOTIFY 2 'ownCloud installation backup found, starting recovery...' G_EXEC cp -a "$datadir/dietpi-owncloud-installation-backup/." /var/www/owncloud/ # Correct config.php data directory entry, in case it changed due to server migration: G_CONFIG_INJECT "'datadirectory'" "'datadirectory' => '$datadir'," /var/www/owncloud/config/config.php "'dbtype'" else Download_Install 'https://download.owncloud.com/server/stable/owncloud-latest.tar.bz2' /var/www fi fi [[ ${aDEPS[0]} ]] && { G_DIETPI-NOTIFY 2 'Installing required PHP modules'; G_AGI "${aDEPS[@]}"; aDEPS=(); } G_DIETPI-NOTIFY 2 'Enabling required PHP modules' # - Add JSON module for PHP7, as it does not exist (embedded in core package) on PHP8 local json=() [[ $PHP_VERSION == 8* ]] || json=('json') G_EXEC phpenmod ctype curl dom gd iconv intl mbstring pdo_mysql posix simplexml xmlreader xmlwriter zip fileinfo opcache apcu redis exif "${json[@]}" G_DIETPI-NOTIFY 2 'Enabling APCu memory cache for PHP command line usage (CLI) as well, including ownCloud occ command and cron jobs.' echo -e '; ownCloud PHP settings\n; priority=98\napc.enable_cli=1' > "/etc/php/$PHP_VERSION/mods-available/dietpi-owncloud.ini" G_EXEC phpenmod dietpi-owncloud if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )) then G_DIETPI-NOTIFY 2 'Apache webserver found, enabling ownCloud specific configuration.' # https://doc.owncloud.com/server/next/admin_manual/installation/manual_installation/manual_installation_apache.html a2enmod rewrite headers env dir mime 1> /dev/null local owncloud_conf='/etc/apache2/sites-available/dietpi-owncloud.conf' [[ -f $owncloud_conf ]] && G_EXEC mv "$owncloud_conf" "$owncloud_conf.dietpi-old" dps_index=$software_id Download_Install 'apache.owncloud.conf' "$owncloud_conf" a2ensite dietpi-owncloud 1> /dev/null # Cal/CardDAV redirects to ownCloud DAV endpoint echo '# Redirect Cal/CardDAV requests to ownCloud endpoint: Redirect 301 /.well-known/carddav /owncloud/remote.php/dav Redirect 301 /.well-known/caldav /owncloud/remote.php/dav' > /etc/apache2/conf-available/dietpi-dav_redirect.conf a2enconf dietpi-dav_redirect elif (( ${aSOFTWARE_INSTALL_STATE[84]} > 0 )) then G_DIETPI-NOTIFY 2 'Lighttpd webserver found, enabling ownCloud specific configuration.' # Enable required modules G_CONFIG_INJECT '"mod_access",' ' "mod_access",' /etc/lighttpd/lighttpd.conf '"mod_.+",' [[ -f '/etc/lighttpd/conf-enabled/05-setenv.conf' ]] || G_EXEC lighty-enable-mod setenv # Move ownCloud configuration file in place and activate it owncloud_conf='/etc/lighttpd/conf-available/99-dietpi-owncloud.conf' [[ -f $owncloud_conf ]] && G_EXEC mv "$owncloud_conf" "$owncloud_conf.dietpi-old" dps_index=$software_id Download_Install 'lighttpd.owncloud.conf' "$owncloud_conf" G_EXEC_POST_FUNC(){ [[ $exit_code == 2 ]] && exit_code=0; } # Do not fail if modules are enabled already G_EXEC lighty-enable-mod rewrite dietpi-owncloud # Cal/CardDAV redirects to ownCloud DAV endpoint echo '# Redirect Cal/CardDAV requests to ownCloud endpoint: url.redirect += ( "^/.well-known/caldav" => "/owncloud/remote.php/dav", "^/.well-known/carddav" => "/owncloud/remote.php/dav" )' > /etc/lighttpd/conf-available/99-dietpi-dav_redirect.conf [[ -f '/etc/lighttpd/conf-enabled/99-dietpi-dav_redirect.conf' ]] || G_EXEC lighty-enable-mod dietpi-dav_redirect elif (( ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then G_DIETPI-NOTIFY 2 'Nginx webserver found, enabling ownCloud specific configuration.' # https://github.com/owncloud/docs/blob/deda107/modules/admin_manual/examples/installation/nginx/subdirectory-configuration.conf local owncloud_conf='/etc/nginx/sites-dietpi/dietpi-owncloud.conf' [[ -f $owncloud_conf ]] && G_EXEC mv "$owncloud_conf" "$owncloud_conf.dietpi-old" dps_index=$software_id Download_Install 'nginx.owncloud.conf' "$owncloud_conf" # Cal/CardDAV redirects to ownCloud DAV endpoint echo '# Redirect Cal/CardDAV requests to ownCloud endpoint: location = /.well-known/carddav { return 301 /owncloud/remote.php/dav/; } location = /.well-known/caldav { return 301 /owncloud/remote.php/dav/; }' > /etc/nginx/sites-dietpi/dietpi-dav_redirect.conf fi # Start MariaDB and Redis (for reinstalls) for database creation and occ command G_EXEC systemctl restart mariadb G_EXEC systemctl restart redis-server # Initially add occ command shortcut, will be added as alias by /etc/bashrc.d/dietpi.bash if occ file exist: occ(){ runuser -u www-data -- php /var/www/owncloud/occ "$@"; } # Adjusting config file: local config_php='/var/www/owncloud/config/config.php' local datadir=$(sed -n '/^[[:blank:]]*SOFTWARE_OWNCLOUD_DATADIR=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $datadir ]] || datadir='/mnt/dietpi_userdata/owncloud_data' G_EXEC mkdir -p "$datadir" G_EXEC chown -R www-data:www-data /var/www/owncloud "$datadir" if [[ -d '/mnt/dietpi_userdata/mysql/owncloud' ]]; then G_DIETPI-NOTIFY 2 'ownCloud database found, will NOT overwrite.' if [[ ! -f $config_php ]]; then G_WHIP_MSG '[WARNING] Existing ownCloud database was found, but no related install directory\n A remaining MariaDB "owncloud" database from an earlier installed instance was found. But the related install directory "/var/www/owncloud/config/config.php" does not exist. Since running a fresh install with an existing database can produce data corruption if the versions do not exactly match, you either need to remove the database or find and place the related install directory.\n We cannot predict your aim and do not want to mess or break your data, so please do this manually.\n To remove the existing database (including e.g. contacts, calendar, file tags etc.): # mysqladmin drop owncloud Otherwise to copy an existing instance in place: # rm -R /var/www/owncloud # mkdir /var/www/owncloud # cp -a /path/to/existing/owncloud/. /var/www/owncloud/ The install script will now exit. After applying one of the the above, rerun dietpi-software, e.g.: # dietpi-software install 47' /boot/dietpi/dietpi-services start exit 1 fi elif [[ -f $datadir/dietpi-owncloud-database-backup.sql ]]; then G_DIETPI-NOTIFY 2 'ownCloud database backup found, starting recovery...' local dbuser=$(grep -m1 "^[[:blank:]]*'dbuser'" "$config_php" | mawk -F\' '{print $4}') local dbpass=$(grep -m1 "^[[:blank:]]*'dbpassword'" "$config_php" | mawk -F\' '{print $4}') /boot/dietpi/func/create_mysql_db owncloud "$dbuser" "$dbpass" mysql owncloud < "$datadir/dietpi-owncloud-database-backup.sql" # Adjust database data directory entry, in case it changed due to server migration local datadir_old=$(grep -m1 "^[[:blank:]]*'datadirectory'" "$config_php" | mawk -F\' '{print $4}') G_EXEC mysql -e "update owncloud.oc_storages set id='local::$datadir/' where id rlike 'local::$datadir_old';" elif ! grep -q "'installed' => true," "$config_php" 2>/dev/null; then local username=$(sed -n '/^[[:blank:]]*SOFTWARE_OWNCLOUD_NEXTCLOUD_USERNAME=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $username ]] || username='admin' # For MariaDB, temporary database admin user needs to be created, as 'root' uses unix_socket login, which cannot be accessed by sudo -u www-data. # - Create random temporary alphanumeric 30 characters password local oc_password=$(tr -dc '[:alnum:]' < /dev/random | head -c30) G_EXEC mysql -e "grant all privileges on *.* to tmp_root@localhost identified by '$oc_password' with grant option;" G_EXEC_DESC='ownCloud occ install' # - Replace password strings internally to avoid printing it to console G_EXEC_PRE_FUNC(){ acommand[6]="--database-pass=$oc_password" acommand[8]="--admin-pass=$GLOBAL_PW"; } # - Checking output for stack trace to handle internal errors that do not lead to php error exit code G_EXEC_POST_FUNC(){ grep -qi 'Stack trace' "$fp_log" && exit_code=255; } G_EXEC occ maintenance:install --no-interaction --database='mysql' --database-name='owncloud' --database-user='tmp_root' --database-pass="${oc_password//?/X}" --admin-user="$username" --admin-pass="${GLOBAL_PW//?/X}" --data-dir="$datadir" G_EXEC mysql -e 'drop user tmp_root@localhost;' unset -v oc_password # Remove obsolete default data dir [[ $(readlink -f "$datadir") != $(readlink -f /var/www/owncloud/data) ]] && G_EXEC rm -R /var/www/owncloud/data fi # Enable ownCloud to use 4-byte database G_CONFIG_INJECT "'mysql.utf8mb4'" "'mysql.utf8mb4' => true," "$config_php" "'dbpassword'" # Add local IP and hostname to trusted domains. # If "1 => '" does not exist, the config.php is not copied e.g. from older instance, so we add entries. if ! grep -q "1 => '" "$config_php"; then sed --follow-symlinks -i "/0 => 'localhost'/a 1 => '$(G_GET_NET ip)'," "$config_php" sed --follow-symlinks -i "/1 => '/a 2 => '$HOSTNAME'," "$config_php" fi # Set CLI URL to ownCloud sub directory: G_EXEC sed --follow-symlinks -i "s|'http://localhost'|'http://localhost/owncloud'|" "$config_php" # Set pretty URLs (without /index.php/) on Apache: if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )); then GCI_PRESERVE=1 G_CONFIG_INJECT "'htaccess.RewriteBase'" "'htaccess.RewriteBase' => '/owncloud'," "$config_php" "'overwrite.cli.url'" occ maintenance:update:htaccess fi # APCu Memcache GCI_PRESERVE=1 G_CONFIG_INJECT "'memcache.local'" "'memcache.local' => '\\\\OC\\\\Memcache\\\\APCu'," "$config_php" "'version'" # Redis for transactional file locking: G_DIETPI-NOTIFY 2 'Enabling Redis for transactional file locking.' # https://doc.owncloud.org/server/administration_manual/configuration/server/caching_configuration.html#configuring-transactional-file-locking local redis_conf='/etc/redis/redis.conf' # - Enable Redis socket and grant www-data access to it GCI_PRESERVE=1 G_CONFIG_INJECT 'unixsocket[[:blank:]]' 'unixsocket /run/redis/redis-server.sock' "$redis_conf" G_CONFIG_INJECT 'unixsocketperm[[:blank:]]' 'unixsocketperm 770' "$redis_conf" G_EXEC usermod -aG redis www-data G_EXEC systemctl restart redis-server # - Enable ownCloud to use Redis socket for transactional file locking: G_CONFIG_INJECT "'filelocking.enabled'" "'filelocking.enabled' => true," "$config_php" "'memcache.local'" local redis_sock=$(grep -m1 '^[[:blank:]]*unixsocket[[:blank:]]' "$redis_conf" | mawk '{print $2}') # Re-estimate in case of existing custom path GCI_PRESERVE=1 GCI_NEWLINE=1 G_CONFIG_INJECT "'memcache.locking'" "'memcache.locking' => '\\\\OC\\\\Memcache\\\\Redis',\n'redis' => array ('host' => '$redis_sock', 'port' => 0,)," "$config_php" "'filelocking.enabled'" # Enable ownCloud background cron job: crontab -u www-data -l | grep -q '/var/www/owncloud/.*cron' || { crontab -u www-data -l; echo '*/15 * * * * php /var/www/owncloud/occ system:cron'; } | crontab -u www-data - occ background:cron # On <1 GiB devices assure at least 512 MiB swap space are available to stand 512 MiB file uploads + increased PHP cache and session file usage: https://github.com/MichaIng/DietPi/issues/2293 (( $RAM_PHYS < 924 && $(free -m | mawk '/^Swap:/{print $2;exit}') < 512 )) && /boot/dietpi/func/dietpi-set_swapfile 512 fi if To_Install 114 # Nextcloud then aDEPS=("php$PHP_VERSION-intl") # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation if [[ -f '/var/www/nextcloud/occ' ]] then G_DIETPI-NOTIFY 2 'Existing Nextcloud installation found, will NOT overwrite...' else local datadir=$(sed -n '/^[[:blank:]]*SOFTWARE_NEXTCLOUD_DATADIR=/{s/^[^=]*=//;s|/$||;p;q}' /boot/dietpi.txt) [[ $datadir ]] || datadir='/mnt/dietpi_userdata/nextcloud_data' if [[ -f $datadir/dietpi-nextcloud-installation-backup/occ ]] then G_DIETPI-NOTIFY 2 'Nextcloud installation backup found, starting recovery...' G_EXEC cp -a "$datadir/dietpi-nextcloud-installation-backup/." /var/www/nextcloud/ # Correct config.php data directory entry, in case it changed due to server migration: G_CONFIG_INJECT "'datadirectory'" "'datadirectory' => '$datadir'," /var/www/nextcloud/config/config.php "'dbtype'" else # Nextcloud 26 doesn't support PHP7.4 anymore: https://github.com/nextcloud/server/pull/34997 local version='latest' if (( $G_DISTRO < 7 )) then G_DIETPI-NOTIFY 2 'Downloading latest Nextcloud 25, since Nextcloud 26 does not support PHP7.4 anymore' version='latest-25' fi Download_Install "https://download.nextcloud.com/server/releases/$version.tar.bz2" /var/www fi fi # Bookworm: Patch for PHP 8.2 support, which works quite well: https://github.com/nextcloud/server/issues/32595#issuecomment-1387559520 if (( $G_DISTRO > 6 )) && grep -q '>= 80200' /var/www/nextcloud/lib/versioncheck.php then G_WHIP_MSG '[WARNING] Patching Nextcloud to support PHP 8.2 for Bookworm \nNextcloud 25 does not support PHP 8.2, but it does work quite well: - https://github.com/nextcloud/server/issues/32595#issuecomment-1387559520 \nWe are patching the PHP version check, but this has two implications: - You will see an integrity check error on Nextcloud admin panel. - You will need to redo the patch after Nextcloud updates to future 25.x versions: # sed --follow-symlinks -i '\''s/>= 80200/>= 80300/'\'' /var/www/nextcloud/lib/versioncheck.php \nWe recommend to update to Nextcloud 26 as fast as possible to get official PHP 8.2 support.' G_EXEC sed --follow-symlinks -i 's/>= 80200/>= 80300/' /var/www/nextcloud/lib/versioncheck.php fi [[ ${aDEPS[0]} ]] && { G_DIETPI-NOTIFY 2 'Installing required PHP modules'; G_AGI "${aDEPS[@]}"; aDEPS=(); } G_DIETPI-NOTIFY 2 'Enabling required PHP modules' # - Add JSON module for PHP7, as it does not exist (embedded in core package) on PHP8 local json=() [[ $PHP_VERSION == 8* ]] || json=('json') G_EXEC phpenmod ctype curl dom gd intl mbstring pdo_mysql posix simplexml xmlreader xmlwriter zip fileinfo opcache apcu redis exif "${json[@]}" G_DIETPI-NOTIFY 2 'Apply PHP override settings for Nextcloud.' # https://docs.nextcloud.com/server/stable/admin_manual/installation/server_tuning.html#enable-php-opcache local memory_consumption=$(sed -n '/^[[:blank:]]*opcache.memory_consumption=/{s/^[^=]*=//p;q}' "/etc/php/$PHP_VERSION/mods-available/dietpi.ini") (( $memory_consumption < 64 )) && memory_consumption='\nopcache.memory_consumption=64' || memory_consumption= echo -e "; Nextcloud PHP settings\n; priority=98\nmemory_limit=512M$memory_consumption\nopcache.revalidate_freq=5" > "/etc/php/$PHP_VERSION/mods-available/dietpi-nextcloud.ini" # Enable APCu for CLI only for Nextcloud 30 and lower: https://github.com/nextcloud/server/pull/46151 (( $(mawk -F[\'.] '/^\$OC_VersionString/{print $2}' /var/www/nextcloud/version.php) < 31 )) && G_EXEC eval "echo 'apc.enable_cli=1' >> '/etc/php/$PHP_VERSION/mods-available/dietpi-nextcloud.ini'" G_EXEC phpenmod dietpi-nextcloud if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )) then G_DIETPI-NOTIFY 2 'Apache webserver found, enabling Nextcloud specific configuration.' # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#apache-web-server-configuration a2enmod rewrite headers env dir mime 1> /dev/null local nextcloud_conf='/etc/apache2/sites-available/dietpi-nextcloud.conf' [[ -f $nextcloud_conf ]] && G_EXEC mv "$nextcloud_conf" "$nextcloud_conf.dietpi-old" dps_index=$software_id Download_Install 'apache.nextcloud.conf' "$nextcloud_conf" a2ensite dietpi-nextcloud 1> /dev/null # Cal/CardDAV redirects to Nextcloud DAV endpoint echo '# Redirect Cal/CardDAV requests to Nextcloud endpoint: Redirect 301 /.well-known/carddav /nextcloud/remote.php/dav Redirect 301 /.well-known/caldav /nextcloud/remote.php/dav' > /etc/apache2/conf-available/dietpi-dav_redirect.conf a2enconf dietpi-dav_redirect elif (( ${aSOFTWARE_INSTALL_STATE[84]} > 0 )) then G_DIETPI-NOTIFY 2 'Lighttpd webserver found, enabling Nextcloud specific configuration.' # Enable required modules G_CONFIG_INJECT '"mod_access",' ' "mod_access",' /etc/lighttpd/lighttpd.conf '"mod_.+",' [[ -f '/etc/lighttpd/conf-enabled/05-setenv.conf' ]] || G_EXEC lighty-enable-mod setenv # Move Nextcloud configuration file in place and activate it nextcloud_conf='/etc/lighttpd/conf-available/99-dietpi-nextcloud.conf' [[ -f $nextcloud_conf ]] && G_EXEC mv "$nextcloud_conf" "$nextcloud_conf.dietpi-old" dps_index=$software_id Download_Install 'lighttpd.nextcloud.conf' "$nextcloud_conf" G_EXEC_POST_FUNC(){ [[ $exit_code == 2 ]] && exit_code=0; } # Do not fail if modules are enabled already G_EXEC lighty-enable-mod rewrite dietpi-nextcloud # Cal/CardDAV redirects to Nextcloud DAV endpoint echo '# Redirect Cal/CardDAV requests to Nextcloud endpoint: url.redirect += ( "^/.well-known/caldav" => "/nextcloud/remote.php/dav", "^/.well-known/carddav" => "/nextcloud/remote.php/dav" )' > /etc/lighttpd/conf-available/99-dietpi-dav_redirect.conf [[ -f '/etc/lighttpd/conf-enabled/99-dietpi-dav_redirect.conf' ]] || G_EXEC lighty-enable-mod dietpi-dav_redirect elif (( ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then G_DIETPI-NOTIFY 2 'Nginx webserver found, enabling Nextcloud specific configuration.' # https://docs.nextcloud.com/server/stable/admin_manual/installation/nginx.html # shellcheck disable=SC2016 echo '# Set the "immutable" cache control option for assets with a cache busting "v=" argument map $arg_v $asset_immutable { "" ""; default ", immutable"; }' > /etc/nginx/conf.d/dietpi-nextcloud.conf local nextcloud_conf='/etc/nginx/sites-dietpi/dietpi-nextcloud.conf' [[ -f $nextcloud_conf ]] && G_EXEC mv "$nextcloud_conf" "$nextcloud_conf.dietpi-old" dps_index=$software_id Download_Install 'nginx.nextcloud.conf' "$nextcloud_conf" # Cal/CardDAV redirects to Nextcloud DAV endpoint echo '# Redirect Cal/CardDAV requests to Nextcloud endpoint: location = /.well-known/carddav { return 301 /nextcloud/remote.php/dav/; } location = /.well-known/caldav { return 301 /nextcloud/remote.php/dav/; }' > /etc/nginx/sites-dietpi/dietpi-dav_redirect.conf fi # Start MariaDB and Redis (for reinstalls) for database creation and ncc command G_EXEC systemctl restart mariadb G_EXEC systemctl restart redis-server # Initially add occ command shortcut, will be added as alias by /etc/bashrc.d/dietpi.bash if occ file exist: ncc(){ runuser -u www-data -- php /var/www/nextcloud/occ "$@"; } # Adjusting config file: local config_php='/var/www/nextcloud/config/config.php' local datadir=$(sed -n '/^[[:blank:]]*SOFTWARE_NEXTCLOUD_DATADIR=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $datadir ]] || datadir='/mnt/dietpi_userdata/nextcloud_data' G_EXEC mkdir -p "$datadir" G_EXEC chown -R www-data:www-data /var/www/nextcloud "$datadir" if [[ -d '/mnt/dietpi_userdata/mysql/nextcloud' ]]; then G_DIETPI-NOTIFY 2 'Nextcloud database found, will NOT overwrite.' if [[ ! -f $config_php ]]; then G_WHIP_MSG '[WARNING] Existing Nextcloud database was found, but no related install directory\n A remaining MariaDB "nextcloud" database from an earlier installed instance was found. But the related install directory "/var/www/nextcloud/config/config.php" does not exist. Since running a fresh install with an existing database can produce data corruption if the versions do not exactly match, you either need to remove the database or find and place the related install directory.\n We cannot predict your aim and do not want to mess or break your data, so please do this manually.\n To remove the existing database (including e.g. contacts, calendar, file tags etc.): # mysqladmin drop nextcloud Otherwise to copy an existing instance in place: # rm -R /var/www/nextcloud # mkdir /var/www/nextcloud # cp -a /path/to/existing/nextcloud/. /var/www/nextcloud/ The install script will now exit. After applying one of the the above, rerun dietpi-software, e.g.: # dietpi-software install 114' /boot/dietpi/dietpi-services start exit 1 fi elif [[ -f $datadir/dietpi-nextcloud-database-backup.sql ]]; then G_DIETPI-NOTIFY 2 'Nextcloud database backup found, starting recovery...' local dbuser=$(grep -m1 "^[[:blank:]]*'dbuser'" "$config_php" | mawk -F\' '{print $4}') local dbpass=$(grep -m1 "^[[:blank:]]*'dbpassword'" "$config_php" | mawk -F\' '{print $4}') /boot/dietpi/func/create_mysql_db nextcloud "$dbuser" "$dbpass" mysql nextcloud < "$datadir/dietpi-nextcloud-database-backup.sql" # Adjust database data directory entry, in case it changed due to server migration local datadir_old=$(grep -m1 "^[[:blank:]]*'datadirectory'" "$config_php" | mawk -F\' '{print $4}') G_EXEC mysql -e "update nextcloud.oc_storages set id='local::$datadir/' where id rlike 'local::$datadir_old';" elif ! grep -q "'installed' => true," "$config_php" 2>/dev/null; then local username=$(sed -n '/^[[:blank:]]*SOFTWARE_OWNCLOUD_NEXTCLOUD_USERNAME=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $username ]] || username='admin' # For MariaDB, temporary database admin user needs to be created, as 'root' uses unix_socket login, which cannot be accessed by sudo -u www-data. # - Create random temporary alphanumeric 30 characters password local nc_password=$(tr -dc '[:alnum:]' < /dev/random | head -c30) G_EXEC mysql -e "grant all privileges on *.* to tmp_root@localhost identified by '$nc_password' with grant option;" G_EXEC_DESC='Nextcloud ncc install' # - Replace password strings internally to avoid printing it to console G_EXEC_PRE_FUNC(){ acommand[6]="--database-pass=$nc_password" acommand[8]="--admin-pass=$GLOBAL_PW"; } # - Checking output for stack trace to handle internal errors that do not lead to php error exit code # - Workaround Nextcloud 14.0.3 throwing an error, when data dir path contains a symlink: https://github.com/nextcloud/server/issues/12247 G_EXEC_POST_FUNC(){ if (( $exit_code )); then grep -q 'Following symlinks is not allowed' "$fp_log" && { cp -a /var/www/nextcloud/core/skeleton/. "$datadir/$username/files/"; exit_code=0; } else grep -qi 'Stack trace' "$fp_log" && exit_code=255 fi } G_EXEC ncc maintenance:install --no-interaction --database='mysql' --database-name='nextcloud' --database-user='tmp_root' --database-pass="${nc_password//?/X}" --admin-user="$username" --admin-pass="${GLOBAL_PW//?/X}" --data-dir="$datadir" G_EXEC mysql -e 'drop user tmp_root@localhost;' unset -v nc_password # Remove obsolete default data dir [[ $(readlink -f "$datadir") != $(readlink -f /var/www/nextcloud/data) ]] && G_EXEC rm -R /var/www/nextcloud/data fi # Enable Nextcloud to use 4-byte database G_CONFIG_INJECT "'mysql.utf8mb4'" "'mysql.utf8mb4' => true," "$config_php" "'dbpassword'" # Disable trusted_domains. grep -q "1 => '*'" "$config_php" || sed --follow-symlinks -i "/0 => 'localhost'/a 1 => '*'," "$config_php" # Set CLI URL to Nextcloud sub directory: G_EXEC sed --follow-symlinks -i "s|'http://localhost'|'http://localhost/nextcloud'|" "$config_php" # Set pretty URLs (without /index.php/) on Apache: if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )); then GCI_PRESERVE=1 G_CONFIG_INJECT "'htaccess.RewriteBase'" "'htaccess.RewriteBase' => '/nextcloud'," "$config_php" "'overwrite.cli.url'" ncc maintenance:update:htaccess fi # APCu Memcache GCI_PRESERVE=1 G_CONFIG_INJECT "'memcache.local'" "'memcache.local' => '\\\\OC\\\\Memcache\\\\APCu'," "$config_php" "'version'" # Redis for transactional file locking: G_DIETPI-NOTIFY 2 'Enabling Redis for transactional file locking.' # https://docs.nextcloud.com/server/stable/admin_manual/configuration_files/files_locking_transactional.html local redis_conf="/etc/redis/redis.conf" # - Enable Redis socket and grant www-data access to it GCI_PRESERVE=1 G_CONFIG_INJECT 'unixsocket[[:blank:]]' 'unixsocket /run/redis/redis-server.sock' "$redis_conf" G_CONFIG_INJECT 'unixsocketperm[[:blank:]]' 'unixsocketperm 770' "$redis_conf" G_EXEC usermod -aG redis www-data G_EXEC systemctl restart redis-server # - Enable Nextcloud to use Redis socket: G_CONFIG_INJECT "'filelocking.enabled'" "'filelocking.enabled' => true," "$config_php" "'memcache.local'" local redis_sock=$(grep -m1 '^[[:blank:]]*unixsocket[[:blank:]]' "$redis_conf" | mawk '{print $2}') # Re-estimate in case of existing custom path GCI_PRESERVE=1 GCI_NEWLINE=1 G_CONFIG_INJECT "'memcache.locking'" "'memcache.locking' => '\\\\OC\\\\Memcache\\\\Redis',\n'redis' => array ('host' => '$redis_sock', 'port' => 0,)," "$config_php" "'filelocking.enabled'" # Tweak Argon2 hashing # - Use all available CPU threads GCI_PRESERVE=1 G_CONFIG_INJECT "'hashingThreads'" "'hashingThreads' => ${G_HW_CPU_CORES}," "$config_php" "'version'" # - ToDo: Configure the other settings after getting some clarification: https://github.com/nextcloud/server/pull/19023#issuecomment-660071524 #GCI_PRESERVE=1 G_CONFIG_INJECT "'hashingMemoryCost'" "'hashingMemoryCost' => 65536," $config_php "'hashingThreads'" #GCI_PRESERVE=1 G_CONFIG_INJECT "'hashingTimeCost'" "'hashingTimeCost' => 4," $config_php "'hashingMemoryCost'" # Enable Nextcloud background cron job: https://docs.nextcloud.com/server/17/admin_manual/configuration_server/background_jobs_configuration.html#cron crontab -u www-data -l | grep -q '/var/www/nextcloud/cron.php' || { crontab -u www-data -l; echo '*/5 * * * * php /var/www/nextcloud/cron.php'; } | crontab -u www-data - ncc background:cron # Convert filecache table to bigint, which is not done automatically by Nextcloud since v15 ncc db:convert-filecache-bigint -n # Add missing database columns and indices, which is not done automatically by Nextcloud ncc db:add-missing-columns ncc db:add-missing-indices ncc db:add-missing-primary-keys # On <1 GiB devices assure at least 512 MiB swap space are available to stand 512 MiB file uploads + increased PHP cache and session file usage: https://github.com/MichaIng/DietPi/issues/2293 (( $RAM_PHYS < 924 && $(free -m | mawk '/^Swap:/{print $2;exit}') < 512 )) && /boot/dietpi/func/dietpi-set_swapfile 512 fi if To_Install 168 coturn # Nextcloud Talk then G_DIETPI-NOTIFY 2 'Installing Coturn TURN server' # Install Coturn server only, install Nextcloud Talk app after Nextcloud has been fully configured G_AGI coturn G_EXEC systemctl stop coturn Remove_SysV coturn 1 # Ask user for server domain and desired TURN server port G_WHIP_DEFAULT_ITEM=$(sed -n '/^[[:blank:]]*SOFTWARE_PUBLIC_DOMAIN_NAME=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $G_WHIP_DEFAULT_ITEM ]] || G_WHIP_DEFAULT_ITEM=$(find /etc/letsencrypt/live -mindepth 1 -maxdepth 1 -type d -print -quit 2> /dev/null) [[ $G_WHIP_DEFAULT_ITEM ]] || G_WHIP_DEFAULT_ITEM=$(hostname -f) G_WHIP_NOCANCEL=1 G_WHIP_INPUTBOX 'Please enter your server'\''s public domain name to allow Nextcloud Talk access your TURN server:' local domain=${G_WHIP_RETURNED_VALUE#http*://} GCI_PRESERVE=1 G_CONFIG_INJECT 'SOFTWARE_PUBLIC_DOMAIN_NAME=' "SOFTWARE_PUBLIC_DOMAIN_NAME=$domain" /boot/dietpi.txt G_WHIP_DEFAULT_ITEM=3478 G_WHIP_NOCANCEL=1 G_WHIP_INPUTBOX_REGEX='^[1-9][0-9]*$' G_WHIP_INPUTBOX_REGEX_TEXT='a valid port number' G_WHIP_INPUTBOX 'Please enter the network port, that should be used for your TURN server: \nNB: This port (UDP + TCP) needs to be forwarded by your router and/or opened in your firewall settings. Default value is: 3478' local port=$G_WHIP_RETURNED_VALUE # Adjust Coturn settings # - If /etc/turnserver.conf is not present, use default or create empty file if [[ ! -f '/etc/turnserver.conf' ]] then # shellcheck disable=SC2015 [[ -f '/usr/share/doc/coturn/examples/etc/turnserver.conf.gz' ]] && gzip -cd /usr/share/doc/coturn/examples/etc/turnserver.conf.gz > /etc/turnserver.conf || > /etc/turnserver.conf fi # https://help.nextcloud.com/t/howto-setup-nextcloud-talk-with-turn-server/30794 G_CONFIG_INJECT 'listening-port=' "listening-port=$port" /etc/turnserver.conf G_CONFIG_INJECT 'fingerprint' 'fingerprint' /etc/turnserver.conf G_CONFIG_INJECT 'use-auth-secret' 'use-auth-secret' /etc/turnserver.conf G_CONFIG_INJECT 'realm=' "realm=$domain" /etc/turnserver.conf GCI_PRESERVE=1 G_CONFIG_INJECT 'total-quota=' 'total-quota=100' /etc/turnserver.conf GCI_PRESERVE=1 G_CONFIG_INJECT 'bps-capacity=' 'bps-capacity=0' /etc/turnserver.conf G_CONFIG_INJECT 'stale-nonce' 'stale-nonce' /etc/turnserver.conf G_EXEC sed --follow-symlinks -i 's/^[[:blank:]]*allow-loopback-peers/#allow-loopback-peers/' /etc/turnserver.conf G_CONFIG_INJECT 'no-multicast-peers' 'no-multicast-peers' /etc/turnserver.conf # Install Nextcloud Talk app G_EXEC systemctl start mariadb G_EXEC systemctl start redis-server G_EXEC ncc maintenance:mode --off if [[ ! -d '/var/www/nextcloud/apps/spreed' ]] then # Succeed if app is already installed and on "Cannot declare class" bug: https://github.com/MichaIng/DietPi/issues/3499#issuecomment-622955490 G_EXEC_POST_FUNC(){ [[ $exit_code != 0 && $(<"$fp_log") =~ (' already installed'$|' Cannot declare class ') ]] && exit_code=0; } G_EXEC ncc app:install spreed fi ncc app:enable spreed # Adjust Nextcloud Talk settings to use Coturn ncc talk:stun:add "$domain:$port" # - Generate random secret to secure TURN server access local secret=$(openssl rand -hex 32) GCI_PASSWORD=1 GCI_PRESERVE=1 G_CONFIG_INJECT 'static-auth-secret=' "static-auth-secret=$secret" /etc/turnserver.conf # - Scrape existing secret, in case user manually chose/edited it secret=$(sed -n '/^[[:blank:]]*static-auth-secret=/{s/^[^=]*=//p;q}' /etc/turnserver.conf) ncc talk:turn:add --secret "$secret" -- 'turn' "$domain:$port" 'udp,tcp' unset -v secret domain port fi if To_Install 32 ympd # ympd then G_AGI ympd fi if To_Install 148 mympd # myMPD then # Distro: https://download.opensuse.org/repositories/home:/jcorporation/ local distro='Debian_' (( $G_HW_ARCH == 1 )) && distro='Raspbian_' case $G_DISTRO in 6) distro+='11';; 7) distro+='12';; *) distro+='Testing';; esac # APT key G_EXEC curl -sSfLo '/etc/apt/trusted.gpg.d/dietpi-mympd.asc' "https://download.opensuse.org/repositories/home:/jcorporation/$distro/Release.key" # APT list G_EXEC eval "echo 'deb https://download.opensuse.org/repositories/home:/jcorporation/$distro/ /' > /etc/apt/sources.list.d/dietpi-mympd.list" G_AGUP # APT package G_AGI mympd G_EXEC systemctl stop mympd # Config: Create on fresh install # - On reinstall /var/lib/mympd exists, so use its existence as reinstall flag if [[ ! -d '/var/lib/mympd' ]] then G_EXEC_OUTPUT=1 G_EXEC systemd-run -p DynamicUser=yes -p StateDirectory=mympd -p CacheDirectory=mympd -p Environment='MYMPD_LOGLEVEL=4 MYMPD_MPD_HOST=/run/mpd/socket MYMPD_HTTP=false MYMPD_SSL_PORT=1333' mympd -c # Add myMPD CA to trusted store: https://github.com/jcorporation/myMPD/issues/914 G_EXEC mkdir -p /usr/local/share/ca-certificates G_EXEC ln -sf /var/lib/mympd/ssl/ca.pem /usr/local/share/ca-certificates/DietPi_myMPD_CA.crt G_EXEC update-ca-certificates fi # myMPD pre-v8.0.0 cleanup [[ -f '/etc/mympd.conf' ]] && G_EXEC rm /etc/mympd.conf [[ -f '/etc/mympd.conf.dist' ]] && G_EXEC rm /etc/mympd.conf.dist command -v mympd-config > /dev/null && G_EXEC rm "$(command -v mympd-config)" fi if To_Install 121 roonbridge # Roon Bridge then case $G_HW_ARCH in 2) local arch='armv7hf';; 3) local arch='armv8';; *) local arch='x64';; esac Download_Install "https://download.roonlabs.net/builds/RoonBridge_linux$arch.tar.bz2" # Always perform a clean install [[ -d '/opt/roonbridge' ]] && G_EXEC rm -R /opt/roonbridge [[ -d '/etc/roonbridge' ]] && G_EXEC rm -R /etc/roonbridge # Pre-v8.2 G_EXEC mv RoonBridge /opt/roonbridge # Pre-v8.2 migration [[ -d '/mnt/dietpi_userdata/roon' && ! -d '/mnt/dietpi_userdata/roonbridge' ]] && G_EXEC mv /mnt/dietpi_userdata/roon{,bridge} # Log to /var/log/roonbridge G_EXEC mkdir -p /mnt/dietpi_userdata/roonbridge/{RoonBridge,RAATServer} G_EXEC rm -Rf /mnt/dietpi_userdata/roonbridge/{RoonBridge,RAATServer}/Logs /var/log/roon # /var/log/roon: Pre-v8.2 G_EXEC ln -s /var/log/roonbridge /mnt/dietpi_userdata/roonbridge/RoonBridge/Logs G_EXEC ln -s /var/log/roonbridge /mnt/dietpi_userdata/roonbridge/RAATServer/Logs # User Create_User -G audio -d /mnt/dietpi_userdata/roonbridge roonbridge # Permissions G_EXEC chown -R roonbridge:root /{mnt/dietpi_userdata,opt}/roonbridge # Service cat << '_EOF_' > /etc/systemd/system/roonbridge.service [Unit] Description=Roon Bridge (DietPi) Wants=network-online.target After=network-online.target sound.target [Service] SyslogIdentifier=Roon Bridge User=roonbridge AmbientCapabilities=CAP_SYS_NICE LogsDirectory=roonbridge Environment=ROON_DATAROOT=/mnt/dietpi_userdata/roonbridge Environment=ROON_ID_DIR=/mnt/dietpi_userdata/roonbridge ExecStart=/opt/roonbridge/start.sh Restart=on-abort # Hardening PrivateTmp=true [Install] WantedBy=multi-user.target _EOF_ # Sparky SBC: Workaround for failing service start: https://dietpi.com/forum/t/allogui-not-working-apache-service-doesnt-start/15708 (( $G_HW_MODEL == 70 )) && G_EXEC sed --follow-symlinks -i '/^AmbientCapabilities=/d' /etc/systemd/system/roonbridge.service fi if To_Install 119 # CAVA then G_AGI cava # Config: Preserve existing if [[ ! -f '/root/.config/cava/config' ]] then G_EXEC mkdir -p /root/.config/cava G_EXEC cp /usr/share/cava/example_files/config /root/.config/cava/ G_CONFIG_INJECT 'method[[:blank:]]+=' 'method = fifo' /root/.config/cava/config '\[input\]' G_CONFIG_INJECT 'foreground[[:blank:]]+=' 'foreground = cyan' /root/.config/cava/config '\[color\]' fi # FIFO stream for MPD grep -q '/tmp/mpd.fifo' /etc/mpd.conf || cat << '_EOF_' >> /etc/mpd.conf # CAVA FIFO stream audio_output { type "fifo" name "CAVA" path "/tmp/mpd.fifo" format "44100:16:2" } _EOF_ fi if To_Install 118 mopidy # Mopidy: https://docs.mopidy.com/stable/installation/debian/ then # Install our config file only if not yet existent, to preserve manual user config. # - This needs to be done prior to APT install, since this would otherwise install a default config file as well. [[ -f '/etc/mopidy/mopidy.conf' ]] || dps_index=$software_id Download_Install 'mopidy.conf' /etc/mopidy/mopidy.conf # APT key local url='https://apt.mopidy.com/mopidy.gpg' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-mopidy.gpg --yes" # APT list: https://apt.mopidy.com/dists/ G_EXEC eval "echo 'deb https://apt.mopidy.com ${G_DISTRO_NAME/forky/trixie} main' > /etc/apt/sources.list.d/dietpi-mopidy.list" G_AGUP # APT package G_AGI mopidy gstreamer1.0-alsa mopidy-local G_EXEC systemctl stop mopidy G_EXEC_OUTPUT=1 G_EXEC pip3 install -U Mopidy-MusicBox-Webclient # Assure user home, data and cache dir as well on custom configs G_CONFIG_INJECT 'data_dir[[:blank:]]*=' 'data_dir = /mnt/dietpi_userdata/mopidy/data' /etc/mopidy/mopidy.conf '\[core\]' G_CONFIG_INJECT 'cache_dir[[:blank:]]*=' 'cache_dir = /mnt/dietpi_userdata/mopidy/cache' /etc/mopidy/mopidy.conf '\[core\]' # Move existing home+data to dietpi_userdata if not yet existent if [[ -d '/var/lib/mopidy' && ! -d '/mnt/dietpi_userdata/mopidy' ]] then G_EXEC mv /var/lib/mopidy /mnt/dietpi_userdata/mopidy # Workaround error about moving data dir into itself G_EXEC mkdir -p /mnt/dietpi_userdata/mopidy/.hidden_data # Non-hidden files/dirs are data G_EXEC mv /mnt/dietpi_userdata/mopidy/* /mnt/dietpi_userdata/mopidy/.hidden_data G_EXEC mv /mnt/dietpi_userdata/mopidy/.hidden_data /mnt/dietpi_userdata/mopidy/data else G_EXEC mkdir -p /mnt/dietpi_userdata/mopidy/data [[ -d '/var/lib/mopidy' ]] && G_EXEC rm -R /var/lib/mopidy fi # Move existing cache to dietpi_userdata if not yet existent if [[ -d '/var/cache/mopidy' && ! -d '/mnt/dietpi_userdata/mopidy/cache' ]] then G_EXEC mv /var/cache/mopidy /mnt/dietpi_userdata/mopidy/cache else G_EXEC mkdir -p /mnt/dietpi_userdata/mopidy/cache [[ -d '/var/cache/mopidy' ]] && G_EXEC rm -R /var/cache/mopidy fi # Permissions G_EXEC chown -R mopidy:root /mnt/dietpi_userdata/mopidy # User G_EXEC usermod -g dietpi -aG audio -d /mnt/dietpi_userdata/mopidy mopidy # Do not pre-create obsolete cache dir G_EXEC mkdir -p /etc/systemd/system/mopidy.service.d G_EXEC eval 'echo -e '\''[Service]\nExecStartPre='\'' > /etc/systemd/system/mopidy.service.d/dietpi.conf' Download_Test_Media fi if To_Install 31 # Kodi then # RPi repo if [[ -f '/etc/apt/sources.list.d/raspi.list' ]] then # Purge DietPi Bullseye build with higher epoch version [[ $G_DISTRO == 6 && $(dpkg-query -Wf '${Version}' kodi 2> /dev/null) == '3:19.1-dietpi'[1-3] ]] && G_EXEC_OUTPUT=1 G_EXEC dpkg -P kodi if (( $G_HW_MODEL < 10 )) then # Enhance 4k support on RPi 4 and above with 512 MiB CMA local cma=() (( $G_HW_MODEL > 3 )) && cma=(512) /boot/dietpi/func/dietpi-set_hardware rpi-opengl vc4-kms-v3d "${cma[@]}" # Enable hardware codecs /boot/dietpi/func/dietpi-set_hardware rpi-codec 1 fi # Bookworm: Install Kodi 21 (( $G_DISTRO == 7 )) && aDEPS=('kodi21') || aDEPS=('kodi') # Trixie: has now dedicated kodi-repository-kodi (( $G_DISTRO > 7 )) && aDEPS+=('kodi-repository-kodi') # Missing dependency aDEPS+=('libgl1-mesa-dri') # Bookworm: Apply missing dir workaround: https://github.com/RPi-Distro/repo/issues/153 (( $G_DISTRO == 7 )) && G_EXEC mkdir -p /etc/polkit-1/localauthority/50-local.d # Everything else else aDEPS=('kodi' 'kodi-repository-kodi') (( $G_HW_ARCH == 10 || $G_DISTRO > 6 )) || aDEPS+=('libgles2') # Missing ARM dependency until Bookworm fi # Desktop entry G_EXEC mkdir -p /var/lib/dietpi/dietpi-software/installed/desktop/icons /usr/share/applications G_THREAD_START curl -sSfLo /var/lib/dietpi/dietpi-software/installed/desktop/icons/kodi-icon.png "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/icons/kodi-icon.png" G_THREAD_START curl -sSfLo /usr/share/applications/kodi.desktop "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/apps/kodi.desktop" # Grant R/W access to all input and console devices for members of the "input" respectively "tty" group dps_index=$software_id Download_Install '99-dietpi-kodi.rules' /etc/udev/rules.d/99-dietpi-kodi.rules # Desktop shortcut Create_Desktop_Shortcut kodi fi if To_Install 39 minidlna # ReadyMedia then # Config [[ -f '/etc/minidlna.conf' ]] || dps_index=$software_id Download_Install 'minidlna.conf' /etc/minidlna.conf G_AGI minidlna G_EXEC systemctl stop minidlna # Remove obsolete service file Remove_SysV minidlna 1 # User: Make "dietpi" the primary group to enable cross-access to media files Create_User -g dietpi -G minidlna -d /var/lib/minidlna minidlna # Service: Debian patch enforces file logging, overriding "-S": https://github.com/MichaIng/DietPi/issues/4745 cat << '_EOF_' > /etc/systemd/system/minidlna.service [Unit] Description=ReadyMedia (DietPi) Documentation=man:minidlnad(1) man:minidlna.conf(5) Wants=network-online.target After=network-online.target remote-fs.target [Service] User=minidlna LogsDirectory=minidlna ExecStart=/usr/sbin/minidlnad -S -R -f /etc/minidlna.conf -P /dev/null [Install] WantedBy=multi-user.target _EOF_ # Cache G_EXEC mkdir -p /mnt/dietpi_userdata/.MiniDLNA_Cache G_EXEC chown -R minidlna:root /mnt/dietpi_userdata/.MiniDLNA_Cache Download_Test_Media fi if To_Install 108 # Amiberry then # RPi: Enable KMS/DRM (( $G_HW_MODEL < 10 )) && /boot/dietpi/func/dietpi-set_hardware rpi-opengl vc4-kms-v3d G_AGI amiberry # Permissions: Enable access for kickstart uploads via file servers local fp_roms='/mnt/dietpi_userdata/amiberry/roms' # - ARMv6: Amiberry v5 used a different default dir for kickstart ROMs (( $G_HW_ARCH == 1 )) && fp_roms='/mnt/dietpi_userdata/amiberry/kickstarts' G_EXEC mkdir -p "$fp_roms" G_EXEC chgrp dietpi "$fp_roms" G_EXEC chmod g=rwx "$fp_roms" # Pre-v6.26: Remove obsolete config file: https://github.com/BlitterStudio/amiberry/releases/tag/v2.25 [[ -f '/mnt/dietpi_userdata/amiberry/conf/adfdir.conf' ]] && G_EXEC rm /mnt/dietpi_userdata/amiberry/conf/adfdir.conf # Pre-v8.5: Remove obsolete library and service files if (( $G_HW_ARCH == 1 )) then [[ -e '/mnt/dietpi_userdata/amiberry/lib/libSDL2.so' ]] && G_EXEC rm -f /mnt/dietpi_userdata/amiberry/lib/libSDL2*.so{,.0.*} else [[ -d '/mnt/dietpi_userdata/amiberry/lib' ]] && G_EXEC rm -R /mnt/dietpi_userdata/amiberry/lib fi [[ -f '/etc/systemd/system/amiberry.service' ]] && G_EXEC rm /etc/systemd/system/amiberry.service fi if To_Install 10 # Amiberry-Lite then # RPi: Enable KMS/DRM (( $G_HW_MODEL < 10 )) && /boot/dietpi/func/dietpi-set_hardware rpi-opengl vc4-kms-v3d G_AGI amiberry-lite # Permissions: Enable access for kickstart uploads via file servers G_EXEC mkdir -p /mnt/dietpi_userdata/amiberry-lite/roms G_EXEC chgrp dietpi /mnt/dietpi_userdata/amiberry-lite/roms G_EXEC chmod g=rwx /mnt/dietpi_userdata/amiberry-lite/roms fi if To_Install 112 # DXX-Rebirth then aDEPS=('libsdl-mixer1.2' 'libsdl1.2debian' 'libphysfs1' 'libgl1' 'libglu1-mesa') Download_Install 'https://dietpi.com/downloads/binaries/rpi/dxx-rebirth.7z' /mnt/dietpi_userdata # Symlink savegames to root # - Remove existing symlinks G_EXEC rm -Rf /root/.d{1,2}x-rebirth G_EXEC ln -sf /mnt/dietpi_userdata/dxx-rebirth/descent_1_profiles /root/.d1x-rebirth G_EXEC ln -sf /mnt/dietpi_userdata/dxx-rebirth/descent_2_profiles /root/.d2x-rebirth # +exe G_EXEC chmod -R +x /mnt/dietpi_userdata/dxx-rebirth/* # Desktop menu entry G_EXEC mkdir -p /usr/share/applications G_EXEC ln -sf /mnt/dietpi_userdata/dxx-rebirth/dxx-rebirth.desktop /usr/share/applications/dxx-rebirth.desktop # Desktop shortcut Create_Desktop_Shortcut dxx-rebirth fi if To_Install 111 urbackupsrv # UrBackup Server then # Pre-configure backup path: Read from database on reinstall and align all configs if [[ -f '/var/urbackup/backup_server_settings.db' ]] && command -v sqlite3 > /dev/null then local backuppath=$(sqlite3 /var/urbackup/backup_server_settings.db 'select value from settings where key = "backupfolder"') else local backuppath=$(sed -n '/^[[:blank:]]*SOFTWARE_URBACKUP_BACKUPPATH=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) fi [[ $backuppath ]] || backuppath='/mnt/dietpi_userdata/urbackup' [[ -f '/etc/urbackup/backupfolder' ]] && G_EXEC eval "echo '$backuppath' > /etc/urbackup/backupfolder" [[ -f '/var/urbackup/backupfolder' ]] && G_EXEC eval "echo '$backuppath' > /var/urbackup/backupfolder" G_EXEC eval "debconf-set-selections <<< 'urbackup-server urbackup/backuppath string $backuppath'" # Install latest version local arch=$(dpkg --print-architecture) local version=$(curl -sSfL 'https://hndl.urbackup.org/Server/' | grep -Po '(?<=href=")[0-9.]+(?=/")' | sort -Vr | head -1) local file=$(curl -sSfL "https://hndl.urbackup.org/Server/$version/" | grep -Pom1 "(?<=href=\")urbackup-server_${version}_$arch\.deb(?=\")") local fallback_url="https://hndl.urbackup.org/Server/2.5.33/urbackup-server_2.5.33_$arch.deb" Download_Install "${file:+https://hndl.urbackup.org/Server/$version/$file}" G_EXEC systemctl stop urbackupsrv unset -v backuppath arch version file fi if To_Install 51 # OpenTyrian then aDEPS=('libsdl1.2debian' 'libsdl-net1.2') Download_Install 'https://dietpi.com/downloads/binaries/rpi/opentyrian_armhf.zip' / # Move to /usr/games G_EXEC cp -a /usr/local/games/opentyrian /usr/games/ G_EXEC rm -R /usr/local/games/opentyrian G_EXEC chmod +x /usr/games/opentyrian/opentyrian # Desktop menu entry G_THREAD_START curl -sSfL "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/desktop/apps/opentyrian.desktop" -o /usr/share/applications/opentyrian.desktop # Copy the DietPi run file for OpenTyrian dps_index=$software_id Download_Install 'run' /usr/games/opentyrian/run G_EXEC chmod +x /usr/games/opentyrian/run # Desktop shortcut Create_Desktop_Shortcut opentyrian G_THREAD_WAIT fi if To_Install 59 raspimjpeg # RPi Cam Web Interface then aDEPS=('gpac') Download_Install 'https://github.com/silvanmelchior/RPi_Cam_Web_Interface/archive/master.tar.gz' G_EXEC cd RPi_Cam_Web_Interface-master # Remove files which are not to be installed [[ -f 'www/status_mjpeg.txt' ]] && G_EXEC rm www/status_mjpeg.txt # Web base dir G_EXEC mkdir -p /var/www/rpicam G_EXEC cp -dR www/. /var/www/rpicam/ [[ -e '/var/www/rpicam/FIFO' ]] || G_EXEC mknod /var/www/rpicam/FIFO p [[ -e '/var/www/rpicam/FIFO1' ]] || G_EXEC mknod /var/www/rpicam/FIFO1 p # - Dynamic cam preview and status G_EXEC ln -sf /run/shm/mjpeg/cam.jpg /var/www/rpicam/cam.jpg G_EXEC ln -sf /run/shm/mjpeg/status_mjpeg.txt /var/www/rpicam/status_mjpeg.txt # Allow shutdown and reboot via web interface G_EXEC cp etc/sudoers.d/RPI_Cam_Web_Interface /etc/sudoers.d/dietpi-rpi_cam_control # Install RaspiMJPEG # - Binary G_EXEC cp {,/usr/local/}bin/raspimjpeg G_EXEC chmod +x /usr/local/bin/raspimjpeg # - Config G_EXEC cp etc/raspimjpeg/raspimjpeg.1 /etc/raspimjpeg G_EXEC ln -sf /etc/raspimjpeg /var/www/rpicam/raspimjpeg # - Web base dir grep -q '/rpicam' /etc/raspimjpeg || G_EXEC sed --follow-symlinks -i 's|/var/www|/var/www/rpicam|g' /etc/raspimjpeg # - Service dps_index=$software_id Download_Install 'raspimjpeg.sh' /var/lib/dietpi/dietpi-software/installed/raspimjpeg.sh G_EXEC chmod +x /var/lib/dietpi/dietpi-software/installed/raspimjpeg.sh cat << '_EOF_' > /etc/systemd/system/raspimjpeg.service [Unit] Description=RaspiMJPEG (DietPi) [Service] RemainAfterExit=yes ExecStart=/var/lib/dietpi/dietpi-software/installed/raspimjpeg.sh start ExecStop=/var/lib/dietpi/dietpi-software/installed/raspimjpeg.sh stop [Install] WantedBy=multi-user.target _EOF_ # Cleanup G_EXEC cd "$G_WORKING_DIR" G_EXEC rm -R RPi_Cam_Web_Interface-master # Data directory G_EXEC mkdir -p /mnt/dietpi_userdata/rpicam G_EXEC rm -Rf /var/www/rpicam/media G_EXEC ln -s /mnt/dietpi_userdata/rpicam /var/www/rpicam/media # Enable RPi camera /boot/dietpi/func/dietpi-set_hardware rpi-camera enable # Permissions G_EXEC usermod -aG video www-data G_EXEC chown -R www-data:www-data /var/www/rpicam /mnt/dietpi_userdata/rpicam fi if To_Install 45 deluged deluge-web # Deluge then # Packages G_AGI deluged deluge-web deluge-console (( $G_DISTRO > 6 )) && G_EXEC systemctl stop deluge-web G_EXEC systemctl stop deluged # Workaround for broken Bookworm package: https://github.com/MichaIng/DietPi/issues/6408 (( $G_DISTRO == 7 )) && G_EXEC_DESC='Fixing broken script in Bookworm package' G_EXEC sed --follow-symlinks -i '/bind_textdomain_codeset/d' /usr/lib/python3/dist-packages/deluge/i18n/util.py # Remove SysV service leftovers, installed by Debian APT package Remove_SysV deluged 1 [[ -d '/var/lib/deluged' ]] && G_EXEC rm -R /var/lib/deluged [[ -d '/var/log/deluged' ]] && G_EXEC rm -R /var/log/deluged # User Create_User -g dietpi -G debian-deluged -d /mnt/dietpi_userdata/deluge debian-deluged # Config if [[ ! -f '/mnt/dietpi_userdata/deluge/.config/deluge/core.conf' ]] then G_EXEC mkdir -p /mnt/dietpi_userdata/deluge/.config/deluge # Default configs dps_index=$software_id Download_Install 'deluge.conf' /mnt/dietpi_userdata/deluge/.config/deluge/core.conf dps_index=$software_id Download_Install 'deluge_web.conf' /mnt/dietpi_userdata/deluge/.config/deluge/web.conf dps_index=$software_id Download_Install 'hostlist.conf' /mnt/dietpi_userdata/deluge/.config/deluge/hostlist.conf # Apply optimised settings # - Cache size in 16 KiB units G_CONFIG_INJECT '"cache_size":' " \"cache_size\": $(( $(Optimise_BitTorrent 0) * 1024 / 16 ))," /mnt/dietpi_userdata/deluge/.config/deluge/core.conf G_CONFIG_INJECT '"max_active_limit":' " \"max_active_limit\": $(Optimise_BitTorrent 1)," /mnt/dietpi_userdata/deluge/.config/deluge/core.conf G_CONFIG_INJECT '"max_active_downloading":' " \"max_active_downloading\": $(Optimise_BitTorrent 1)," /mnt/dietpi_userdata/deluge/.config/deluge/core.conf G_CONFIG_INJECT '"max_connections_global":' " \"max_connections_global\": $(Optimise_BitTorrent 2)," /mnt/dietpi_userdata/deluge/.config/deluge/core.conf G_CONFIG_INJECT '"max_upload_slots_global":' " \"max_upload_slots_global\": $(Optimise_BitTorrent 3)," /mnt/dietpi_userdata/deluge/.config/deluge/core.conf # Web UI access local salt=$(tr -dc '0-9a-f' < /dev/random | head -c40) GCI_PASSWORD=1 G_CONFIG_INJECT '"pwd_salt":' " \"pwd_salt\": \"$salt\"," /mnt/dietpi_userdata/deluge/.config/deluge/web.conf GCI_PASSWORD=1 G_CONFIG_INJECT '"pwd_sha1":' " \"pwd_sha1\": \"$(echo -n "$salt$GLOBAL_PW" | sha1sum | mawk '{print $1}')\"," /mnt/dietpi_userdata/deluge/.config/deluge/web.conf unset -v salt # Client access local localpass=$(tr -dc '0-9a-f' < /dev/random | head -c40) > /mnt/dietpi_userdata/deluge/.config/deluge/auth G_EXEC chmod 0600 /mnt/dietpi_userdata/deluge/.config/deluge/auth echo -e "root:$GLOBAL_PW:10\nlocalclient:$localpass:10" > /mnt/dietpi_userdata/deluge/.config/deluge/auth # Web UI autoconnect local id=$(tr -dc '0-9a-f' < /dev/random | head -c32) G_EXEC chmod 0600 /mnt/dietpi_userdata/deluge/.config/deluge/hostlist.conf G_CONFIG_INJECT '"[0-9a-f]{32}"' " \"$id\"," /mnt/dietpi_userdata/deluge/.config/deluge/hostlist.conf sed --follow-symlinks -i "/\"[0-9a-f]\{40\}\"/c\ \"$localpass\"" /mnt/dietpi_userdata/deluge/.config/deluge/hostlist.conf G_CONFIG_INJECT '"default_daemon":' " \"default_daemon\": \"$id\"," /mnt/dietpi_userdata/deluge/.config/deluge/web.conf unset -v localpass id RESTART_DELUGE_WEB=1 fi # Permissions G_EXEC chown -R debian-deluged:root /mnt/dietpi_userdata/deluge # Service: https://github.com/deluge-torrent/deluge/blob/develop/packaging/systemd/deluged.service cat << '_EOF_' > /etc/systemd/system/deluged.service [Unit] Description=Deluge Daemon (DietPi) Documentation=man:deluged Wants=network-online.target After=network-online.target remote-fs.target [Service] User=debian-deluged UMask=007 ExecStart=/usr/bin/deluged -d [Install] WantedBy=multi-user.target _EOF_ # https://github.com/deluge-torrent/deluge/blob/develop/packaging/systemd/deluge-web.service cat << _EOF_ > /etc/systemd/system/deluge-web.service [Unit] Description=Deluge Web UI (DietPi) Documentation=man:deluge-web Wants=network-online.target After=network-online.target deluged.service [Service] User=debian-deluged UMask=027 ExecStart=/usr/bin/deluge-web -d [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 115 webmin # Webmin: https://github.com/webmin/webmin/blob/master/webmin-setup-repo.sh then # APT key G_EXEC curl -sSfLo '/etc/apt/trusted.gpg.d/dietpi-webmin.asc' 'https://webmin.com/developers-key.asc' # APT list G_EXEC eval 'echo '\''deb https://download.webmin.com/download/newkey/repository stable contrib'\'' > /etc/apt/sources.list.d/dietpi-webmin.list' G_AGUP # APT package G_AGI webmin G_EXEC systemctl stop webmin fi if To_Install 195 # youtube-dl then aDEPS=('python3') Download_Install 'https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp' /usr/local/bin/yt-dlp G_EXEC chmod +x /usr/local/bin/yt-dlp G_EXEC ln -sf /usr/local/bin/yt-dlp /usr/local/bin/youtube-dl # Remove obsolete /usr/local/bin/youtube-dl-py2 we used previously [[ -f '/usr/local/bin/youtube-dl-py2' ]] && G_EXEC rm /usr/local/bin/youtube-dl-py2 fi if To_Install 129 # O!MPD then Download_Install 'https://github.com/ArturSierzant/OMPD/archive/master.tar.gz' # Replace existing installs but preserve local config override if [[ -d '/var/www/ompd' ]] then [[ -f '/var/www/ompd/include/config.local.inc.php' ]] && G_EXEC mv /var/www/ompd/include/config.local.inc.php OMPD-master/include/ G_EXEC rm -R /var/www/ompd fi G_EXEC mv OMPD-master /var/www/ompd # Preserve config file, create local override if non-existent # Database will be migrated automatically, so only create new on fresh install, using local override config as flag if [[ ! -f '/var/www/ompd/include/config.local.inc.php' ]] then G_EXEC systemctl start mariadb # Create database user only, database will be created automatically mysql -e "grant all privileges on ompd.* to ompd@localhost identified by '$GLOBAL_PW';" G_EXEC systemctl stop mariadb cat << _EOF_ > /var/www/ompd/include/config.local.inc.php _EOF_ fi # Webserver configs # - Lighttpd if (( ${aSOFTWARE_INSTALL_STATE[84]} > 0 )) then dps_index=$software_id Download_Install 'lighttpd.ompd.conf' /etc/lighttpd/conf-available/99-dietpi-ompd.conf [[ -f '/etc/lighttpd/conf-enabled/99-dietpi-ompd.conf' ]] || G_EXEC lighty-enable-mod dietpi-ompd fi # Permissions: http://ompd.pl/configuration G_EXEC chown -R www-data:www-data /var/www/ompd/{tmp,stream,cache,covers,include/config.local.inc.php} fi if To_Install 135 icecast2 darkice # Icecast + DarkIce then G_AGI darkice icecast2 # Trixie does not ship init.d service anymore local darkice=() (( $G_DISTRO < 8 )) && darkice=('darkice') G_EXEC systemctl stop "${darkice[@]}" icecast2 # Icecast # - Config: Set passwords if not yet done (default found) # - HTML-encode characters with special meaning in XML. Icecast treats those correctly for authentication. local password=${GLOBAL_PW//&/\&}; password=${password//hackme/c\ $password" /etc/icecast2/icecast.xml sed --follow-symlinks -i "/hackme/c\ $password" /etc/icecast2/icecast.xml sed --follow-symlinks -i "/hackme/c\ $password" /etc/icecast2/icecast.xml unset -v password # - Service: Replace init.d service with native systemd service Remove_SysV icecast2 1 cat << _EOF_ > /etc/systemd/system/icecast2.service [Unit] Description=Icecast (DietPi) Wants=network-online.target After=network-online.target [Service] User=icecast2 Group=icecast ExecStart=/usr/bin/icecast2 -c /etc/icecast2/icecast.xml [Install] WantedBy=multi-user.target _EOF_ # DarkIce # - User Create_User -g audio -G dietpi darkice # - Config [[ -f '/etc/darkice.cfg' ]] || > /etc/darkice.cfg G_EXEC chown darkice:root /etc/darkice.cfg G_EXEC chmod 0600 /etc/darkice.cfg local input_device_index=$(arecord -l | mawk -F'[ :]' '/card/{print $2;exit}') cat << _EOF_ > /etc/darkice.cfg [general] duration = 0 bufferSecs = 3 reconnect = yes [input] device = hw:${input_device_index:-0},0 sampleRate = 44100 bitsPerSample = 16 channel = 1 [icecast2-0] bitrateMode = vbr format = vorbis quality = 0.8 server = localhost port = 8000 password = $GLOBAL_PW mountPoint = DietPi name = DietPi description = DarkIce on DietPi url = http://localhost genre = none public = no #localDumpFile = /mnt/dietpi_userdata/darkice_recording.ogg _EOF_ # - Service: Replace init.d service with native systemd service Remove_SysV darkice 1 cat << _EOF_ > /etc/systemd/system/darkice.service [Unit] Description=DarkIce (DietPi) After=icecast2.service [Service] User=darkice AmbientCapabilities=CAP_SYS_NICE ExecStart=/usr/bin/darkice [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 63 # LinuxDash then Download_Install 'https://github.com/afaqurk/linux-dash/archive/master.tar.gz' G_EXEC mkdir -p /var/www/linuxdash G_EXEC cp -a linux-dash-master/* /var/www/linuxdash/ G_EXEC rm -R linux-dash-master fi if To_Install 184 tor # Tor Relay then G_AGI tor G_EXEC systemctl stop tor local nickname= G_WHIP_BUTTON_CANCEL_TEXT='Skip' G_WHIP_INPUTBOX 'Pick a nickname for your relay.\n\nNB: This is optional, select "Skip" to leave it empty.' && nickname=$G_WHIP_RETURNED_VALUE local email= G_WHIP_BUTTON_CANCEL_TEXT='Skip' G_WHIP_INPUTBOX 'Pick a contact email for your relay.\n\nNB: This is optional but encouraged, and it will be published depending on your relay.' && email=$G_WHIP_RETURNED_VALUE local orport=443 local invalid_text= while : do G_WHIP_DEFAULT_ITEM=$orport G_WHIP_NOCANCEL=1 if G_WHIP_INPUTBOX "${invalid_text}Please enter the ORPort that people will use to connect to your Tor relay: \nNB: This port needs to be forwarded by your router and/or opened in your firewall settings. Default value is: 443, which should be changed when running a webserver. \nDo not use 9001, as this port is commonly associated with Tor and censors might scan for it." then disable_error=1 G_CHECK_VALIDINT "$G_WHIP_RETURNED_VALUE" 1 || { invalid_text='[ERROR] No valid entry found, value needs to be a sequence of integers. Please retry...\n\n'; continue; } fi orport=$G_WHIP_RETURNED_VALUE break done local ipv6= if G_GET_NET -6 -q gateway > /dev/null then for i in $(hostname -I) do [[ $i == *'.'* ]] && continue G_WHIP_DEFAULT_ITEM=$i break done G_WHIP_BUTTON_CANCEL_TEXT='Skip' G_WHIP_INPUTBOX "Please enter the private IPv6 address of this device. Skip this if you only want to use IPv4, or if this device doesn't have an IPv6 address." && ipv6=$G_WHIP_RETURNED_VALUE fi while : do G_WHIP_MENU_ARRAY=( 'Bridge' ': Use this machine as an obfs4 bridge. This is the safest to run from home.' 'Guard/Middle' ': Use this machine as a beginning or middle relay. Some info will be made public.' 'Exit' ': Use this machine as an exit relay. This is most at risk for legal complaints.' ) G_WHIP_DEFAULT_ITEM='Bridge' G_WHIP_NOCANCEL=1 G_WHIP_MENU "Please choose which type of relay this should be set up as:" if [[ $G_WHIP_RETURNED_VALUE == 'Exit' ]] then G_WHIP_BUTTON_OK_TEXT='YES' G_WHIP_BUTTON_CANCEL_TEXT='NO' G_WHIP_YESNO 'WARNING: DO NOT RUN AN EXIT RELAY FROM HOME. \nAlso, it is highly recommended that you setup exit relays on dedicated servers. \nBefore running an exit relay, check with your hosting provider to make sure they allow it. \nAlso, set a reverse DNS (PTR) record (tor-exit is a good name), and preferably edit your WHOIS record to show that this is a Tor exit node. \nWould you still like to continue?' || continue fi break done if [[ $G_WHIP_RETURNED_VALUE == 'Bridge' ]] then G_AGI obfs4proxy local obfs4port=80 invalid_text= while : do G_WHIP_DEFAULT_ITEM=$obfs4port G_WHIP_NOCANCEL=1 if G_WHIP_INPUTBOX "${invalid_text}Please enter the obfs4 port that people will use to connect to your bridge: \nNB: This port needs to be forwarded by your router and/or opened in your firewall settings. Default value is: 80. Do not use default value if running a webserver. \nDo not use 9001, as this port is commonly associated with Tor and censors might scan for it." then disable_error=1 G_CHECK_VALIDINT "$G_WHIP_RETURNED_VALUE" 1 || { invalid_text='[ERROR] No valid entry found, value needs to be a sequence of integers. Please retry...\n\n'; continue; } fi obfs4port=$G_WHIP_RETURNED_VALUE break done # Grant capability to bind to privileged ports below 1024 (( $obfs4port < 1024 )) && G_EXEC setcap cap_net_bind_service=+ep "$(command -v obfs4proxy)" cat << _EOF_ > /etc/tor/torrc BridgeRelay 1 ORPort $orport ServerTransportPlugin obfs4 exec $(command -v obfs4proxy) ServerTransportListenAddr obfs4 0.0.0.0:$obfs4port ExtORPort auto _EOF_ G_EXEC mkdir -p /etc/systemd/system/tor@.service.d G_EXEC eval "echo -e '[Service]\nNoNewPrivileges=no' > /etc/systemd/system/tor@.service.d/dietpi-relay.conf" elif [[ $G_WHIP_RETURNED_VALUE == 'Guard/Middle' ]] then cat << _EOF_ > /etc/tor/torrc ORPort $orport ExitRelay 0 SocksPort 0 ControlSocket 0 _EOF_ elif [[ $G_WHIP_RETURNED_VALUE == 'Exit' ]] then G_AGI unbound aSOFTWARE_INSTALL_STATE[182]=1 cat << _EOF_ > /etc/tor/torrc ORPort $orport ExitRelay 1 SocksPort 0 ControlSocket 0 ExitPolicy accept *:20-21 ExitPolicy accept *:43 ExitPolicy accept *:53 ExitPolicy accept *:79 ExitPolicy accept *:80-81 ExitPolicy accept *:88 ExitPolicy accept *:110 ExitPolicy accept *:143 ExitPolicy accept *:220 ExitPolicy accept *:389 ExitPolicy accept *:443 ExitPolicy accept *:464 ExitPolicy accept *:531 ExitPolicy accept *:543-544 ExitPolicy accept *:554 ExitPolicy accept *:636 ExitPolicy accept *:706 ExitPolicy accept *:749 ExitPolicy accept *:873 ExitPolicy accept *:902-904 ExitPolicy accept *:981 ExitPolicy accept *:989-990 ExitPolicy accept *:991 ExitPolicy accept *:992 ExitPolicy accept *:993 ExitPolicy accept *:995 ExitPolicy accept *:1194 ExitPolicy accept *:1220 ExitPolicy accept *:1293 ExitPolicy accept *:1500 ExitPolicy accept *:1533 ExitPolicy accept *:1677 ExitPolicy accept *:1723 ExitPolicy accept *:1755 ExitPolicy accept *:1863 ExitPolicy accept *:2082 ExitPolicy accept *:2083 ExitPolicy accept *:2086-2087 ExitPolicy accept *:2095-2096 ExitPolicy accept *:2102-2104 ExitPolicy accept *:3690 ExitPolicy accept *:4321 ExitPolicy accept *:4643 ExitPolicy accept *:5050 ExitPolicy accept *:5190 ExitPolicy accept *:5222-5223 ExitPolicy accept *:5228 ExitPolicy accept *:8008 ExitPolicy accept *:8074 ExitPolicy accept *:8082 ExitPolicy accept *:8087-8088 ExitPolicy accept *:8232-8233 ExitPolicy accept *:8332-8333 ExitPolicy accept *:8443 ExitPolicy accept *:8888 ExitPolicy accept *:9418 ExitPolicy accept *:10000 ExitPolicy accept *:11371 ExitPolicy accept *:19294 ExitPolicy accept *:19638 ExitPolicy accept *:50002 ExitPolicy accept *:64738 ExitPolicy reject *:* _EOF_ [[ $ipv6 ]] && echo 'IPv6Exit 1' >> /etc/tor/torrc # Apply Unbound as local DNS resolver for privacy reasons command -v resolvconf > /dev/null && G_EXEC sed --follow-symlinks -i 's/dns-nameservers.*$/dns-nameservers 127.0.0.1/' /etc/network/interfaces G_EXEC eval "echo 'nameserver 127.0.0.1' > /etc/resolv.conf" # Unbound is running and configured in the very next config step, so it is safe to switch the DNS nameserver right now. fi G_EXEC eval 'echo '\''ControlPort 9051'\'' >> /etc/tor/torrc' G_EXEC eval 'echo '\''CookieAuthentication 1'\'' >> /etc/tor/torrc' [[ $nickname ]] && G_EXEC eval "echo 'Nickname $nickname' >> /etc/tor/torrc" [[ $email ]] && G_EXEC eval "echo 'ContactInfo $email' >> /etc/tor/torrc" [[ $ipv6 ]] && G_EXEC eval "echo 'ORPort [$ipv6]:$orport' >> /etc/tor/torrc" fi if To_Install 182 unbound # Unbound then G_DIETPI-NOTIFY 2 'Pre-configuring Unbound to avoid port binding conflicts' # Download base configuration if it does not exist yet [[ -f '/etc/unbound/unbound.conf.d/dietpi.conf' ]] || dps_index=$software_id Download_Install 'unbound.conf' /etc/unbound/unbound.conf.d/dietpi.conf # Toggle IPv6 preference based whether there is an IPv6 default route if G_GET_NET -6 -q gateway > /dev/null then G_CONFIG_INJECT 'do-ip6:[[:blank:]]' ' do-ip6: yes' /etc/unbound/unbound.conf.d/dietpi.conf 'server:' else G_CONFIG_INJECT 'do-ip6:[[:blank:]]' ' do-ip6: no' /etc/unbound/unbound.conf.d/dietpi.conf 'server:' fi # Since IP binding might be used, start after network interfaces have been configured, not when they just start to be configured G_EXEC mkdir -p /etc/systemd/system/unbound.service.d G_EXEC eval "echo -e '[Unit]\nWants=network-online.target\nAfter=network-online.target' > /etc/systemd/system/unbound.service.d/dietpi.conf" # Pi-hole + AdGuard Home part 1 if (( ${aSOFTWARE_INSTALL_STATE[93]} > 0 || ${aSOFTWARE_INSTALL_STATE[126]} > 0 )) && grep -q '^[[:blank:]]*port:[[:blank:]][[:blank:]]*53$' /etc/unbound/unbound.conf.d/dietpi.conf then G_DIETPI-NOTIFY 2 'Configuring Unbound to work for your selected AdBlocker' grep '^[[:blank:]]*nameserver[[:blank:]]' /etc/resolv.conf | grep -qvE '[[:blank:]]127.0.0.1(:53)?$' || echo 'nameserver 9.9.9.9' >> /etc/resolv.conf # Failsafe G_CONFIG_INJECT 'port:[[:blank:]]' ' port: 5335' /etc/unbound/unbound.conf.d/dietpi.conf 'server:' G_CONFIG_INJECT 'interface:[[:blank:]]' ' interface: 127.0.0.1' /etc/unbound/unbound.conf.d/dietpi.conf 'server:' fi # Reinstall: Restart to apply possible config changes [[ -f '/lib/systemd/system/unbound.service' ]] && G_EXEC systemctl restart unbound # Disable and mask unbound-resolvconf.service: https://github.com/MichaIng/DietPi/issues/5133 [[ -f '/lib/systemd/system/unbound-resolvconf.service' ]] && G_EXEC systemctl --no-reload disable --now unbound-resolvconf G_EXEC systemctl --no-reload mask unbound-resolvconf G_AGI unbound dns-root-data Remove_SysV unbound G_EXEC systemctl enable --now unbound # Failsafe # Prevent resolvconf from disabling Unbound's exclusive recursive resolving or DoT by adding upstream resolvers of the host to Unbound's forward zone: https://salsa.debian.org/dns-team/unbound/-/blob/master/debian/resolvconf-forwards [[ -f '/etc/resolvconf/update.d/unbound' ]] && G_EXEC chmod -x /etc/resolvconf/update.d/unbound # Pi-hole part 2 if (( ${aSOFTWARE_INSTALL_STATE[93]} == 2 )) then G_DIETPI-NOTIFY 2 'Configuring Pi-hole to use Unbound' # v6 if [[ $(pihole-FTL -v) == 'v6'* ]] then G_EXEC pihole-FTL --config dns.upstreams '[ "127.0.0.1#5335" ]' fi # v5 if [[ -f '/etc/dnsmasq.d/01-pihole.conf' ]] then G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*server=/d' /etc/dnsmasq.d/01-pihole.conf G_CONFIG_INJECT 'server=' 'server=127.0.0.1#5335' /etc/dnsmasq.d/01-pihole.conf systemctl -q is-active pihole-FTL && G_EXEC systemctl restart pihole-FTL fi if [[ -f '/etc/pihole/setupVars.conf' ]] then G_CONFIG_INJECT 'PIHOLE_DNS_1=' 'PIHOLE_DNS_1=127.0.0.1#5335' /etc/pihole/setupVars.conf G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*PIHOLE_DNS_2=/d' /etc/pihole/setupVars.conf fi fi # AdGuard Home part 2 if (( ${aSOFTWARE_INSTALL_STATE[126]} == 2 )) then G_DIETPI-NOTIFY 2 'Configuring AdGuard Home to use Unbound' if [[ ! -f '/mnt/dietpi_userdata/adguardhome/dietpi-unbound.conf' ]] then echo '127.0.0.1:5335' > /mnt/dietpi_userdata/adguardhome/dietpi-unbound.conf G_CONFIG_INJECT 'upstream_dns_file:[[:blank:]]' ' upstream_dns_file: /mnt/dietpi_userdata/adguardhome/dietpi-unbound.conf' /mnt/dietpi_userdata/adguardhome/AdGuardHome.yaml systemctl -q is-active adguardhome && G_EXEC systemctl restart adguardhome fi fi # Plex Media Server: Fix secure remote access: https://dietpi.com/forum/t/cant-connect-to-plex-directly-due-to-unbound/5199 (( ${aSOFTWARE_INSTALL_STATE[42]} > 0 )) && echo -e 'server:\n\tprivate-domain: "plex.direct"' > /etc/unbound/unbound.conf.d/dietpi-plex.conf fi if To_Install 93 pihole-FTL # Pi-hole then # Download G_EXEC curl -sSfLo install.sh 'https://raw.githubusercontent.com/pi-hole/pi-hole/master/automated%20install/basic-install.sh' G_EXEC chmod +x install.sh # Check free available memory. Increase swap size to prevent gravity running out of memory. if (( $(free -m | mawk '/^Mem:/{print $7;exit}') < 512 && $(free -m | mawk '/^Swap:/{print $2;exit}') < 512 )) then G_DIETPI-NOTIFY 2 'Increasing swap size to 512 MiB for running gravity.sh, please wait...\n' /boot/dietpi/func/dietpi-set_swapfile 512 fi # Unbound: Switch port to 5335 if it was installed before, else it got just configured within its install step above if (( ${aSOFTWARE_INSTALL_STATE[182]} == 2 )) && grep -q '^[[:blank:]]*port:[[:blank:]][[:blank:]]*53$' /etc/unbound/unbound.conf.d/dietpi.conf then G_DIETPI-NOTIFY 2 'Configuring Unbound to work for Pi-hole' grep '^[[:blank:]]*nameserver[[:blank:]]' /etc/resolv.conf | grep -qvE '[[:blank:]]127.0.0.1(:53)?$' || echo 'nameserver 9.9.9.9' >> /etc/resolv.conf # Failsafe G_CONFIG_INJECT 'port:[[:blank:]]' ' port: 5335' /etc/unbound/unbound.conf.d/dietpi.conf G_CONFIG_INJECT 'interface:[[:blank:]]' ' interface: 127.0.0.1' /etc/unbound/unbound.conf.d/dietpi.conf G_EXEC systemctl restart unbound fi # Install # - Workaround "dialog" issues with "xterm" by faking "linux" terminal local retry TERM_old= [[ $TERM == 'xterm' ]] && { TERM_old=$TERM; export TERM=linux; } # - Skip query logging dialogue and set to "false", which affects file logging only, not database>web UI. G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*setLogging$/d' install.sh G_EXEC sed --follow-symlinks -i '/^QUERY_LOGGING=$/c\QUERY_LOGGING=false' install.sh # - Skip final completion dialogue since we show our own # shellcheck disable=SC2016 G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*pihole setpassword "${pw}"/,/^[[:blank:]]*dialog --no-shadow --keep-tite/s/dialog --no-shadow --keep-tite/true/' install.sh until ./install.sh do (( $G_INTERACTIVE )) && read -rp 'The Pi-hole installer failed. Do you want to retry? [yN]: ' retry [[ $retry =~ ^[yY]([eE][sS])?$ ]] || { aSOFTWARE_INSTALL_STATE[$software_id]=0; break; } done G_EXEC rm install.sh [[ $TERM_old ]] && TERM=$TERM_old unset -v retry TERM_old # Skip further setup if installer failed if (( ${aSOFTWARE_INSTALL_STATE[$software_id]} == 1 )) then # Set web UI password: https://github.com/MichaIng/DietPi/issues/662 G_EXEC_PRE_FUNC(){ acommand[2]=$GLOBAL_PW; } G_EXEC pihole setpassword "${GLOBAL_PW//?/X}" # Disable pihole.log query logging: https://github.com/pi-hole/FTL/issues/614#issuecomment-510564476 G_EXEC pihole-FTL --config dns.queryLogging 'false' # Unbound: Configure Pi-hole to use it (( ${aSOFTWARE_INSTALL_STATE[182]} > 0 )) && G_EXEC pihole-FTL --config dns.upstreams '[ "127.0.0.1#5335" ]' # Apply most resource friendly and officially recommended NULL blocking: https://docs.pi-hole.net/ftldns/blockingmode/ G_EXEC pihole-FTL --config dns.blocking.mode 'NULL' # Reduce long-term database TTL: https://github.com/MichaIng/DietPi-Docs/issues/476 G_EXEC pihole-FTL --config database.maxDBdays 2 # Change web UI port to 8089 and 8489 (HTTPS) to avoid conflict with webservers and other web applications G_EXEC pihole-FTL --config webserver.port 8089,8489s # Inform user about differences to stock Pi-hole installation G_WHIP_MSG "[ INFO ] Differences to stock Pi-hole installation \nCompared to installing Pi-hole via official one-line installer, DietPi applied the following changes: - The Pi-hole web UI can be reached on port 8089, i.e. via: http://$(G_GET_NET ip):8089/admin/ - Additionally it can be accessed via encrypted HTTPS at port 8489, i.e. via: https://$(G_GET_NET ip):8489/admin/. Note that browsers will show a warning until a TLS certificate from by a trusted public certificate authority is used. - The Pi-hole web UI is secured with the global software password you chose during first run setup, default: \"dietpi\" - DNS query logging to /var/log/pihole/pihole.log has been disabled. This does not affect the query logs in the web UI and database, but the \"pihole -t\"/\"pihole tail\" command does not show DNS queries anymore. If you want to use this command or need query logs in /var/log/pihole/pihole.log for other reasons, it can be re-enabled via web UI privacy settings or \"sudo pihole-FTL --config dns.queryLogging true\". - DNS query logging to database (as shown in web UI) has been reduced to 2 days. This can be changed via web UI privacy settings or e.g. \"sudo pihole-FTL --config database.maxDBdays 7\" to raise it to 7 days. \nFor further details, read our online docs: https://dietpi.com/docs/software/dns_servers/#pi-hole" fi fi if To_Install 126 # AdGuard Home then # Deps: apache2-utils is required for htpasswd command to create bcrypt password hashes aDEPS=('apache2-utils') if [[ -f '/mnt/dietpi_userdata/adguardhome/AdGuardHome' ]] then G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$software_id]} executable \"/mnt/dietpi_userdata/adguardhome/AdGuardHome\" already exists. Download and install steps will be skipped. - If you want to update ${aSOFTWARE_NAME[$software_id]}, please use the internal updater from web UI. - If you need to reinstall (e.g. broken instance), please manually remove the executable \"/mnt/dietpi_userdata/adguardhome/AdGuardHome\" and rerun \"dietpi-software (re)install $software_id\"." G_AGI "${aDEPS[@]}" aDEPS=() else case $G_HW_ARCH in 1) local arch='armv6';; 2) local arch='armv7';; 3) local arch='arm64';; 10) local arch='amd64';; *) local arch='riscv64';; esac Download_Install "https://static.adguard.com/adguardhome/release/AdGuardHome_linux_$arch.tar.gz" # Install to userdata until it is possible to split binary and data/config without breaking the updater: https://github.com/AdguardTeam/AdGuardHome/issues/3286 G_EXEC mkdir -p /mnt/dietpi_userdata/adguardhome G_EXEC cp -a AdGuardHome/. /mnt/dietpi_userdata/adguardhome/ G_EXEC rm -R AdGuardHome fi # Unbound: Switch port to 5335 if it was installed before, else it got just configured within its install step above if (( ${aSOFTWARE_INSTALL_STATE[182]} == 2 )) && grep -q '^[[:blank:]]*port:[[:blank:]][[:blank:]]*53$' /etc/unbound/unbound.conf.d/dietpi.conf then G_DIETPI-NOTIFY 2 'Configuring Unbound to work for AdGuard Home' grep '^[[:blank:]]*nameserver[[:blank:]]' /etc/resolv.conf | grep -qvE '[[:blank:]]127.0.0.1(:53)?$' || echo 'nameserver 9.9.9.9' >> /etc/resolv.conf # Failsafe G_CONFIG_INJECT 'port:[[:blank:]]' ' port: 5335' /etc/unbound/unbound.conf.d/dietpi.conf G_CONFIG_INJECT 'interface:[[:blank:]]' ' interface: 127.0.0.1' /etc/unbound/unbound.conf.d/dietpi.conf G_EXEC systemctl restart unbound fi # User Create_User -d /mnt/dietpi_userdata/adguardhome adguardhome # Config if [[ ! -f '/mnt/dietpi_userdata/adguardhome/AdGuardHome.yaml' ]] then dps_index=$software_id Download_Install 'AdGuardHome.yaml' /mnt/dietpi_userdata/adguardhome/AdGuardHome.yaml # shellcheck disable=SC2016 G_CONFIG_INJECT 'password:[[:blank:]]' " password: $(htpasswd -bnBC 10 '' "$GLOBAL_PW" | tr -d ':\n' | sed 's/\$2y/\$2a/')" /mnt/dietpi_userdata/adguardhome/AdGuardHome.yaml fi # Unbound: Configure AdGuard Home to use it if [[ ${aSOFTWARE_INSTALL_STATE[182]} -gt 0 && ! -f '/mnt/dietpi_userdata/adguardhome/dietpi-unbound.conf' ]] then G_DIETPI-NOTIFY 2 'Configuring AdGuard Home to use Unbound' echo '127.0.0.1:5335' > /mnt/dietpi_userdata/adguardhome/dietpi-unbound.conf G_CONFIG_INJECT 'upstream_dns_file:[[:blank:]]' ' upstream_dns_file: /mnt/dietpi_userdata/adguardhome/dietpi-unbound.conf' /mnt/dietpi_userdata/adguardhome/AdGuardHome.yaml systemctl -q is-active adguardhome && G_EXEC systemctl restart adguardhome fi # Permissions G_EXEC chown -R adguardhome:adguardhome /mnt/dietpi_userdata/adguardhome G_EXEC chmod 0755 /mnt/dietpi_userdata/adguardhome/AdGuardHome G_EXEC chmod 0600 /mnt/dietpi_userdata/adguardhome/AdGuardHome.yaml # Service cat << '_EOF_' > /etc/systemd/system/adguardhome.service [Unit] Description=AdGuard Home (DietPi) Wants=network-online.target nss-lookup.target After=network-online.target Before=nss-lookup.target StartLimitIntervalSec=60 StartLimitBurst=3 [Service] User=adguardhome AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW ExecStart=/mnt/dietpi_userdata/adguardhome/AdGuardHome ExecReload=/mnt/dietpi_userdata/adguardhome/AdGuardHome -s reload Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target _EOF_ # AdGuard Home service needs to be started manually as dietpi-services must not control it to prevent it from killing the systems own DNS server. aSTART_SERVICES+=('adguardhome') fi if To_Install 33 airsonic # Airsonic-Advanced then # Since v11 is not yet released, pull latest pre-release local fallback_url='https://github.com/airsonic-advanced/airsonic-advanced/releases/download/11.0.0-SNAPSHOT.20240424015024/airsonic.war' Download_Install "$(curl -sSfL 'https://api.github.com/repos/airsonic-advanced/airsonic-advanced/releases' | mawk -F\" '/^ *"browser_download_url": ".*\/airsonic\.war"$/{print $4}' | head -1)" /mnt/dietpi_userdata/airsonic/airsonic.war # User Create_User -g dietpi -G audio -d /mnt/dietpi_userdata/airsonic airsonic # Service cat << _EOF_ > /etc/systemd/system/airsonic.service [Unit] Description=Airsonic-Advanced (DietPi) Wants=network-online.target After=network-online.target remote-fs.target [Service] SyslogIdentifier=Airsonic User=airsonic WorkingDirectory=/mnt/dietpi_userdata/airsonic ExecStart=$JAVA_PATH -mx${JAVA_MAX_HEAP_SIZE}m -Dairsonic.home=/mnt/dietpi_userdata/airsonic -Dserver.servlet.context-path=/airsonic -Dserver.port=8080 -jar /mnt/dietpi_userdata/airsonic/airsonic.war SuccessExitStatus=143 [Install] WantedBy=multi-user.target _EOF_ # Enable FFmpeg transcode G_EXEC mkdir -p /mnt/dietpi_userdata/airsonic/transcode [[ -f '/mnt/dietpi_userdata/airsonic/transcode/ffmpeg' ]] || G_EXEC ln -sf "$(command -v ffmpeg)" /mnt/dietpi_userdata/airsonic/transcode # Permissions G_EXEC chmod +x /mnt/dietpi_userdata/airsonic/airsonic.war G_EXEC chown airsonic:root /mnt/dietpi_userdata/airsonic Download_Test_Media fi if To_Install 204 navidrome # Navidrome then case $G_HW_ARCH in 1) local arch='armv6';; 2) local arch='armv7';; 3) local arch='arm64';; *) local arch='amd64';; esac local fallback_url="https://github.com/navidrome/navidrome/releases/download/v0.58.0/navidrome_0.58.0_linux_$arch.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/navidrome/navidrome/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/navidrome_[0-9.]*_linux_$arch\.tar\.gz\"$/{print \$4}")" /opt/navidrome # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/navidrome # User Create_User -g dietpi -d /mnt/dietpi_userdata/navidrome navidrome # Config: https://www.navidrome.org/docs/usage/configuration-options/#available-options [[ -f '/mnt/dietpi_userdata/navidrome/navidrome.toml' ]] || cat << '_EOF_' > /mnt/dietpi_userdata/navidrome/navidrome.toml DataFolder = '/mnt/dietpi_userdata/navidrome/data' MusicFolder = '/mnt/dietpi_userdata/Music' ImageCacheSize = '100MiB' LogLevel = 'warn' SessionTimeout = '24h' AuthRequestLimit = '5' AuthWindowLength = '20s' ScanSchedule = '@every 1h' EnableLogRedacting = 'true' Scanner.Extractor = 'taglib' CoverJpegQuality = '75' _EOF_ # Service: https://www.navidrome.org/docs/installation/linux/#create-a-systemd-unit cat << '_EOF_' > /etc/systemd/system/navidrome.service [Unit] Description=Navidrome (DietPi) Wants=network-online.target After=network-online.target remote-fs.target AssertPathExists=/mnt/dietpi_userdata/navidrome StartLimitIntervalSec=60 StartLimitBurst=3 [Service] User=navidrome ExecStart=/opt/navidrome/navidrome --configfile "/mnt/dietpi_userdata/navidrome/navidrome.toml" WorkingDirectory=/mnt/dietpi_userdata/navidrome TimeoutStopSec=20 KillMode=process Restart=on-failure # See https://www.freedesktop.org/software/systemd/man/systemd.exec.html DevicePolicy=closed NoNewPrivileges=yes PrivateTmp=yes PrivateUsers=yes ProtectControlGroups=yes ProtectKernelModules=yes ProtectKernelTunables=yes RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 RestrictNamespaces=yes RestrictRealtime=yes SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap ReadWritePaths=/mnt/dietpi_userdata/navidrome # You can uncomment the following line if you're not using the jukebox This # will prevent navidrome from accessing any real (physical) devices #PrivateDevices=yes # You can change the following line to `strict` instead of `full` if you don't # want navidrome to be able to write anything on your filesystem outside of # /mnt/dietpi_userdata/navidrome. ProtectSystem=full # You can uncomment the following line if you don't have any media in /home/*. # This will prevent navidrome from ever reading/writing anything there. #ProtectHome=true # You can customize some Navidrome config options by setting environment variables here. Ex: #Environment=ND_BASEURL="/navidrome" [Install] WantedBy=multi-user.target _EOF_ # Permissions G_EXEC chown -R root:root /opt/navidrome G_EXEC chmod +x /opt/navidrome/navidrome G_EXEC chown -R navidrome:root /mnt/dietpi_userdata/navidrome Download_Test_Media fi if To_Install 212 kavita # Kavita then # .NET dependency: https://github.com/dotnet/docs/blob/main/docs/core/install/linux-debian.md#dependencies case $G_DISTRO in 6) aDEPS=('libicu67');; 7) aDEPS=('libicu72');; *) aDEPS=('libicu76');; esac case $G_HW_ARCH in 2) local arch='arm';; 3) local arch='arm64';; *) local arch='x64';; esac local fallback_url="https://github.com/Kareadita/Kavita/releases/download/v0.8.7/kavita-linux-$arch.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/Kareadita/Kavita/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/kavita-linux-$arch\.tar\.gz\"$/{print \$4}")" G_EXEC chmod +x Kavita/Kavita # Change default port to 2036 to avoid conflict with Shairport Sync G_CONFIG_INJECT '"Port":' ' "Port": 2036,' Kavita/config/appsettings-init.json # Reinstall: Preserve config dir if [[ -d '/opt/kavita' ]] then if [[ -d '/opt/kavita/config' ]] then G_EXEC rm -R Kavita/config G_EXEC mv /opt/kavita/config Kavita/ fi G_EXEC rm -R /opt/kavita fi G_EXEC mv Kavita /opt/kavita # User Create_User -g dietpi -d /opt/kavita kavita G_EXEC chown -R kavita:root /opt/kavita # Data G_EXEC mkdir -p /mnt/dietpi_userdata/{ebooks,comics} G_EXEC chown kavita:dietpi /mnt/dietpi_userdata/{ebooks,comics} G_EXEC chmod 0775 /mnt/dietpi_userdata/{ebooks,comics} # Service: https://wiki.kavitareader.com/en/install/linux-install cat << '_EOF_' > /etc/systemd/system/kavita.service [Unit] Description=Kavita Server (DietPi) Wants=network-online.target After=network-online.target remote-fs.target StartLimitIntervalSec=60 StartLimitBurst=3 [Service] SyslogIdentifier=Kavita User=kavita WorkingDirectory=/opt/kavita ExecStart=/opt/kavita/Kavita TimeoutStopSec=20 KillMode=process Restart=on-failure [Install] WantedBy=multi-user.target _EOF_ G_DIETPI-NOTIFY 2 'Please wait for a few minutes to let the application starts. By default it runs on port 2036.' fi if To_Install 68 # Remote.It then case $G_HW_ARCH in 3) local arch='arm64';; 10) local arch='amd64';; *) local arch='armhf' esac export R3_PLATFORM_CODE=1072 Download_Install "https://downloads.remote.it/remoteit/latest/remoteit.$arch.deb" G_WHIP_MSG "[ INFO ] The installation of Remote.It is complete. \nThe final step is to register your claim code with your desktop application. See the manual below for instructions on how to do this. \nhttps://docs.remote.it/software/device-package/installation#id-3.-claim-and-register-the-device \nYour claim code: $(mawk -F\" '/claim/{print $4}' /etc/remoteit/config.json) \nThen this DietPi device will be online as your Remote.It device and you can start using it." if dpkg-query -s 'connectd' &> /dev/null || dpkg-query -s 'weavedconnectd' &> /dev/null then G_WHIP_BUTTON_CANCEL_TEXT='Skip' G_WHIP_YESNO '[WARNING] Legacy Remote.It package detected \nOne of the legacy Remote.It packages "connectd" or "weavedconnectd" is installed on your system. These have been superseded by the new "remoteit" package. \nDo you want the legacy packages to be uninstalled now? \nNB: You can do this any time later, e.g. after connections with the new package have been set up: G_AGP connectd weavedconnectd' && G_AGP connectd weavedconnectd fi fi if To_Install 69 # Python 3 RPi.GPIO then if (( $G_DISTRO > 6 )) then G_AGI python3-rpi-lgpio else G_AGI python3-rpi.gpio fi fi if To_Install 70 # WiringPi then aDEPS=('make' 'gcc' 'libc6-dev') # RPi if (( $G_HW_MODEL < 10 )) then Download_Install 'https://github.com/WiringPi/WiringPi/archive/master.tar.gz' G_EXEC cd WiringPi-master G_EXEC mkdir -p /usr/local/include G_EXEC_OUTPUT=1 G_EXEC ./build # Odroids elif (( $G_HW_MODEL < 20 )) then aDEPS+=('automake' 'libtool' 'pkg-config' 'libgpiod-dev' 'libgpiod2') # Add libgpiod2 explicitly so purging *-dev packages, e.g. via dietpi-cleaner, does not break "gpio" Download_Install 'https://github.com/hardkernel/wiringPi/archive/master.tar.gz' G_EXEC mv {w,W}iringPi-master G_EXEC cd WiringPi-master G_EXEC_OUTPUT=1 G_EXEC ./autogen.sh G_EXEC_OUTPUT=1 G_EXEC ./configure CFLAGS='-g0 -O3' G_EXEC_OUTPUT=1 G_EXEC make "-j$(nproc)" G_EXEC_OUTPUT=1 G_EXEC make install # Orange Pi else # Requires /etc/orangepi-release or /etc/armbian-release with BOARD name: https://github.com/orangepi-xunlong/wiringOP/blob/next/wiringPi/wiringPi.c local board= case $G_HW_MODEL in 80) board='orangepi5';; 82) board='orangepi5plus';; 83) board='orangepizero3';; 87) board='orangepi3b';; 88) board='orangepizero2w';; 89) board='orangepi3-lts';; 91) board='orangepi5max';; 93) board='orangepi5pro';; 94) board='orangepi5ultra';; 95) board='orangepicm5';; 96) board='orangepi4a';; 97) board='orangepirv';; 98) board='orangepirv2';; *) G_DIETPI-NOTIFY 1 "Invalid hardware model \"$G_HW_MODEL_NAME\" (ID \"$G_HW_MODEL\"). Aborting ..."; exit 1;; esac >> /etc/orangepi-release GCI_PRESERVE=1 G_CONFIG_INJECT 'BOARD=' "BOARD=$board" /etc/orangepi-release Download_Install 'https://github.com/orangepi-xunlong/wiringOP/archive/next.tar.gz' G_EXEC mv wiringOP-next WiringPi-master G_EXEC cd WiringPi-master G_EXEC mkdir -p /usr/local/include G_EXEC_OUTPUT=1 G_EXEC ./build fi G_EXEC strip --remove-section=.comment --remove-section=.note /usr/local/*bin/gpio G_EXEC strip --strip-unneeded --remove-section=.comment --remove-section=.note /usr/local/lib/libwiringPi*.so G_EXEC ldconfig G_EXEC cd "$G_WORKING_DIR" # Move source dir to disk, as it contains additional examples to compile [[ -d '/root/wiringPi' ]] && G_EXEC rm -R /root/wiringPi # Pre-v7.2 [[ -d '/mnt/dietpi_userdata/WiringPi' ]] && G_EXEC rm -R /mnt/dietpi_userdata/WiringPi G_EXEC mv WiringPi-master /mnt/dietpi_userdata/WiringPi fi if To_Install 72 # I2C then /boot/dietpi/func/dietpi-set_hardware i2c enable fi if To_Install 100 pijuice # PiJuice then # Pre-create config so we can preserve user customisations but override the package default G_EXEC mkdir -p /var/lib/dietpi/dietpi-software/installed/pijuice /var/lib/pijuice [[ -f '/var/lib/dietpi/dietpi-software/installed/pijuice/pijuice_func1.sh' ]] || G_EXEC eval 'echo -e '\''#!/bin/dash\npoweroff'\'' > /var/lib/dietpi/dietpi-software/installed/pijuice/pijuice_func1.sh' G_EXEC chmod +x /var/lib/dietpi/dietpi-software/installed/pijuice/pijuice_func1.sh [[ -f '/var/lib/pijuice/pijuice_config.JSON' ]] || cat << '_EOF_' > /var/lib/pijuice/pijuice_config.JSON { "system_events": { "low_battery_voltage": { "function": "SYS_FUNC_HALT", "enabled": true }, "low_charge": { "function": "NO_FUNC", "enabled": true }, "button_power_off": { "function": "USER_FUNC1", "enabled": true }, "forced_power_off": { "function": "USER_FUNC2", "enabled": false }, "no_power": { "function": "SYS_FUNC_HALT_POW_OFF", "enabled": true }, "forced_sys_power_off": { "function": "USER_FUNC3", "enabled": false }, "watchdog_reset": { "function": "USER_EVENT", "enabled": true } }, "user_functions": { "USER_FUNC1": "/var/lib/dietpi/dietpi-software/installed/pijuice/pijuice_func1.sh", "USER_FUNC2": "/var/lib/dietpi/dietpi-software/installed/pijuice/pijuice_func2.sh", "USER_FUNC3": "/var/lib/dietpi/dietpi-software/installed/pijuice/pijuice_func3.sh", "USER_FUNC4": "", "USER_FUNC5": "", "USER_FUNC6": "", "USER_FUNC7": "", "USER_FUNC8": "" }, "system_task": { "watchdog": { "enabled": true, "period": "60" }, "min_bat_voltage": { "threshold": "1", "enabled": true }, "min_charge": { "threshold": "1", "enabled": true }, "enabled": true, "wakeup_on_charge": { "enabled": true, "trigger_level": "1" } } } _EOF_ # Trixie: https://archive.raspberrypi.com/debian/dists/trixie/main/binary-arm64/Packages, https://github.com/PiSupply/PiJuice/tree/master/Software/Install if apt-cache dumpavail | grep -q '^Package: pijuice-base$' then G_AGI pijuice-base else Download_Install 'https://archive.raspberrypi.com/debian/pool/main/p/pijuice-base/pijuice-base_1.8_all.deb' fi G_EXEC systemctl stop pijuice fi if To_Install 171 # frp then case $G_HW_ARCH in 1) local arch='arm';; 2) local arch='arm_hf';; 3) local arch='arm64';; 10) local arch='amd64';; *) local arch='riscv64';; esac # Download local fallback_url="https://github.com/fatedier/frp/releases/download/v0.64.0/frp_0.64.0_linux_$arch.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/fatedier/frp/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/frp_[0-9.]*_linux_$arch\.tar\.gz\"$/{print \$4}")" G_EXEC cd frp_* # Mode choice G_WHIP_MENU_ARRAY=( 'Server' ': Use this machine as a server, with a public IP' 'Client' ': Use this machine as a client, without a public IP' 'Both' ': Run the reverse proxy only on this machine' ) G_WHIP_NOCANCEL=1 G_WHIP_DEFAULT_ITEM='Both' G_WHIP_MENU 'Please choose how you are going to run frp:' local mode=${G_WHIP_RETURNED_VALUE:-Both} G_EXEC mkdir -p /etc/frp Create_User frp -d /etc/frp local token= if [[ $mode == 'Server' || $mode == 'Both' ]] then G_EXEC mv frps /usr/local/bin/frps cat << '_EOF_' > /etc/systemd/system/frps.service [Unit] Description=frp server (DietPi) Wants=network-online.target After=network-online.target StartLimitIntervalSec=60 StartLimitBurst=3 [Service] User=frp AmbientCapabilities=CAP_NET_BIND_SERVICE ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target _EOF_ # Pre-v9.9: Inform about config file migration if [[ -f '/etc/frp/frps.ini' ]] then G_WHIP_MSG '[WARNING] New toml config file will be generated \nfrp deprecated the ini format for its config files, hence /etc/frp/frps.toml will be generated and used from now on. \nAn automated conversion is not possible and hence need to be done manually if you did changes. A backup of the ini config it kept in place: - /etc/frp/frps.ini.bak \nA full overview of all config keys can be found here: - https://github.com/fatedier/frp/blob/dev/conf/frps_full_example.toml' G_EXEC mv /etc/frp/frps.ini{,.bak} fi # Pre-create config file to turn on dashboard token=$(openssl rand -hex 15) [[ -f '/etc/frp/frps.toml' ]] || cat << _EOF_ > /etc/frp/frps.toml bindAddr = "0.0.0.0" bindPort = 7000 webServer.addr = "0.0.0.0" webServer.port = 7500 webServer.user = "admin" webServer.password = "$GLOBAL_PW" auth.method = "token" auth.token = "$token" _EOF_ G_EXEC chmod 0640 /etc/frp/frps.toml G_EXEC chown root:frp /etc/frp/frps.toml aENABLE_SERVICES+=('frps') fi if [[ $mode == 'Client' || $mode == 'Both' ]] then G_EXEC mv frpc /usr/local/bin/frpc cat << '_EOF_' > /etc/systemd/system/frpc.service [Unit] Description=frp client (DietPi) Wants=network-online.target After=network-online.target frps.service StartLimitIntervalSec=60 StartLimitBurst=3 [Service] User=frp ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml ExecReload=/usr/local/bin/frpc reload -c /etc/frp/frpc.toml Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target _EOF_ # Pre-v9.9: Inform about config file migration if [[ -f '/etc/frp/frpc.ini' ]] then G_WHIP_MSG '[WARNING] New toml config file will be generated \nfrp deprecated the ini format for its config files, hence /etc/frp/frpc.toml will be generated and used from now on. \nAn automated conversion is not possible and hence need to be done manually if you did changes. A backup of the ini config it kept in place: - /etc/frp/frpc.ini.bak \nA full overview of all config keys can be found here: - https://github.com/fatedier/frp/blob/dev/conf/frpc_full_example.toml' G_EXEC mv /etc/frp/frpc.ini{,.bak} fi # Pre-create config file to turn on admin UI if [[ ! -f '/etc/frp/frpc.toml' ]] then local server_addr='127.0.0.1' server_port=7000 if [[ $G_WHIP_RETURNED_VALUE == 'Client' ]] then G_WHIP_NOCANCEL=1 G_WHIP_DEFAULT_ITEM="$server_addr:$server_port" G_WHIP_INPUTBOX_REGEX='^[0-9.:]+$' G_WHIP_INPUTBOX_REGEX_TEXT='be a valid IP address, optionally with appended network port number, like "192.168.1.100:7000"' G_WHIP_INPUTBOX 'Please enter the IP address of your frp server, optionally including port (default 7000):' [[ $G_WHIP_RETURNED_VALUE ]] && server_addr=${G_WHIP_RETURNED_VALUE%:*} [[ $G_WHIP_RETURNED_VALUE =~ : ]] && server_port=${G_WHIP_RETURNED_VALUE##*:} G_WHIP_NOCANCEL=1 G_WHIP_INPUTBOX_REGEX='*' G_WHIP_INPUTBOX 'Please enter the authentication token of your frp server:' token=$G_WHIP_RETURNED_VALUE fi cat << _EOF_ > /etc/frp/frpc.toml serverAddr = "$server_addr" serverPort = $server_port webServer.addr = "0.0.0.0" webServer.port = 7400 webServer.user = "admin" webServer.password = "$GLOBAL_PW" auth.method = "token" auth.token = "$token" _EOF_ fi G_EXEC chmod 0660 /etc/frp/frpc.toml G_EXEC chown root:frp /etc/frp/frpc.toml aENABLE_SERVICES+=('frpc') fi # Cleanup G_EXEC cd "$G_WORKING_DIR" G_EXEC rm -R frp_* fi if To_Install 122 node-red # Node-RED then # APT deps G_AGI python3 # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/node-red # User Create_User -G dialout,gpio,i2c,spi -d /mnt/dietpi_userdata/node-red nodered # - Allow sudo calls G_EXEC eval 'echo '\''nodered ALL=NOPASSWD: ALL'\'' > /etc/sudoers.d/nodered' # Permissions G_EXEC chown -R nodered:nodered /mnt/dietpi_userdata/node-red # Install as local instance for "nodered" user G_EXEC cd /mnt/dietpi_userdata/node-red # - Disable cache local cache=$(runuser -u nodered -- mktemp -d) # - Reinstall: Remove all locally installed modules, to work around update issues, but preserve installed plugins from package.json: https://github.com/MichaIng/DietPi/issues/7128 [[ -f 'package.json' ]] && G_EXEC rm -Rf node_modules .npm/_cacache # - Install v3 on ARMv6, since the @node-rs/bcrypt dependency does not support it: https://github.com/MichaIng/DietPi/issues/7252 local version='latest' (( $G_HW_ARCH == 1 )) && version=3 G_EXEC_OUTPUT=1 G_EXEC runuser -u nodered -- npm i --cache "$cache" --no-audit "node-red@$version" G_EXEC rm -R "$cache" G_EXEC cd "$G_WORKING_DIR" # Service cat << '_EOF_' > /etc/systemd/system/node-red.service [Unit] Description=Node-RED (DietPi) Wants=network-online.target After=network-online.target [Service] User=nodered ExecStart=/mnt/dietpi_userdata/node-red/node_modules/.bin/node-red -u /mnt/dietpi_userdata/node-red [Install] WantedBy=multi-user.target _EOF_ # CLI alias echo 'alias node-red-admin='\''sudo -u nodered /mnt/dietpi_userdata/node-red/node_modules/.bin/node-red-admin'\' > /etc/bashrc.d/dietpi-node-red.sh fi if To_Install 123 mosquitto # Mosquitto then # Use official APT repository where available: https://repo.mosquitto.org/debian/pool/main/m/mosquitto/ # - Current builds are not ARMv6 compatible: https://github.com/MichaIng/DietPi/issues/5140 if (( $G_DISTRO < 8 )) && [[ $G_HW_ARCH == 2 || $G_HW_ARCH == 10 || ( $G_HW_ARCH == 3 && $G_DISTRO == 7 ) ]] then # APT key local url='https://repo.mosquitto.org/debian/mosquitto-repo.gpg' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-mosquitto.gpg --yes" # APT list G_EXEC eval "echo 'deb https://repo.mosquitto.org/debian $G_DISTRO_NAME main' > /etc/apt/sources.list.d/dietpi-mosquitto.list" G_AGUP fi G_AGI mosquitto G_EXEC systemctl stop mosquitto Remove_SysV mosquitto # Password file if [[ ! -f '/etc/mosquitto/passwd' ]] then G_EXEC umask 0037 # relevant for passwd mode until v2.0.18 G_EXEC_PRE_FUNC(){ acommand[5]=$GLOBAL_PW; } G_EXEC mosquitto_passwd -c -b /etc/mosquitto/passwd mosquitto "${GLOBAL_PW//?/X}" G_EXEC chown root:mosquitto /etc/mosquitto/passwd G_EXEC chmod 0640 /etc/mosquitto/passwd # from v2.0.18 on, 0600 is the default mode, hence the "mosquitto" user has no read access G_EXEC umask 0022 fi # Config: /etc/mosquitto/conf.d exists, but doubled settings do not override each other and lead to a startup failure instead, which breaks the purpose we want to use it for. # - Disable PID file, not required for systemd handling G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*pid_file[[:blank:]]/d' /etc/mosquitto/mosquitto.conf [[ -d '/run/mosquitto' ]] && G_EXEC rm -R /run/mosquitto # - Log to default STDERR > systemd-journald G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*log_dest[[:blank:]]/d' /etc/mosquitto/mosquitto.conf [[ -d '/var/log/mosquitto' ]] && G_EXEC rm -R /var/log/mosquitto # - Add default password file for authenticated requests: https://github.com/MichaIng/DietPi/issues/4133 GCI_PRESERVE=1 G_CONFIG_INJECT 'password_file[[:blank:]]' 'password_file /etc/mosquitto/passwd' /etc/mosquitto/mosquitto.conf # - Add default listener at port 1883 not bind to loopback IP: https://github.com/MichaIng/DietPi/issues/4133 GCI_PRESERVE=1 G_CONFIG_INJECT 'listener[[:blank:]]' 'listener 1883' /etc/mosquitto/mosquitto.conf # Add/override default systemd unit: https://github.com/eclipse/mosquitto/tree/master/service/systemd cat << '_EOF_' > /etc/systemd/system/mosquitto.service [Unit] Description=Mosquitto MQTT Broker (DietPi) Documentation=man:mosquitto.conf(5) man:mosquitto(8) Wants=network-online.target After=network-online.target [Service] Type=notify NotifyAccess=main User=mosquitto ExecStart=/usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf ExecReload=/bin/kill -HUP $MAINPID [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 131 blynkserver # Blynk Server then # RPi: Install build deps for the "onoff" Node module (( $G_HW_MODEL > 9 )) || aDEPS=('python3' 'make' 'g++') Download_Install 'https://github.com/Peterkn2001/blynk-server/releases/download/v0.41.17/server-0.41.17.jar' /mnt/dietpi_userdata/blynk/blynkserver.jar # RPi: Install "onoff" for GPIO access (( $G_HW_MODEL > 9 )) || G_EXEC_OUTPUT=1 G_EXEC npm i -g --no-audit onoff@latest # Install Blynk JS library G_EXEC_OUTPUT=1 G_EXEC npm i -g --no-audit blynk-library@latest # Preserve existing config if [[ ! -f '/mnt/dietpi_userdata/blynk/server.properties' ]] then G_EXEC curl -sSfL 'https://raw.githubusercontent.com/Peterkn2001/blynk-server/master/server/core/src/main/resources/server.properties' -o /mnt/dietpi_userdata/blynk/server.properties G_EXEC chmod 0600 /mnt/dietpi_userdata/blynk/server.properties G_CONFIG_INJECT 'logs.folder=' 'logs.folder=/var/log/blynk' /mnt/dietpi_userdata/blynk/server.properties G_CONFIG_INJECT 'data.folder=' 'data.folder=/mnt/dietpi_userdata/blynk/data' /mnt/dietpi_userdata/blynk/server.properties G_CONFIG_INJECT 'http.port=' 'http.port=8442' /mnt/dietpi_userdata/blynk/server.properties GCI_PASSWORD=1 G_CONFIG_INJECT 'admin.pass=' "admin.pass=$GLOBAL_PW" /mnt/dietpi_userdata/blynk/server.properties fi # Example local TCP connection script if [[ ! -f '/mnt/dietpi_userdata/blynk/client-tcp-local.js' ]] then G_EXEC curl -sSfL 'https://raw.githubusercontent.com/vshymanskyy/blynk-library-js/master/examples/nodejs/client-tcp-local.js' -o /mnt/dietpi_userdata/blynk/client-tcp-local.js G_EXEC sed --follow-symlinks -i "s|require('blynk-library')|require('/usr/local/lib/node_modules/blynk-library')|" /mnt/dietpi_userdata/blynk/client-tcp-local.js G_EXEC chmod +x /mnt/dietpi_userdata/blynk/client-tcp-local.js fi # User Create_User -d /mnt/dietpi_userdata/blynk blynk # Service cat << _EOF_ > /etc/systemd/system/blynkserver.service [Unit] Description=Blynk Server (DietPi) Wants=network-online.target After=network-online.target [Service] SyslogIdentifier=Blynk User=blynk LogsDirectory=blynk WorkingDirectory=/mnt/dietpi_userdata/blynk ExecStart=$JAVA_PATH -mx${JAVA_MAX_HEAP_SIZE}m -jar /mnt/dietpi_userdata/blynk/blynkserver.jar SuccessExitStatus=143 # Hardening PrivateTmp=true [Install] WantedBy=multi-user.target _EOF_ # Permissions G_EXEC chown -R blynk:blynk /mnt/dietpi_userdata/blynk fi if To_Install 124 networkaudiod # NAA Daemon then # Base URL local dist=$G_DISTRO_NAME (( $G_DISTRO > 7 )) && dist='bookworm' local url="https://signalyst.com/bins/naa/linux/$dist/" # Check download dir G_CHECK_URL "$url" # Get latest version local package=$(curl -sSfL "$url" | grep -Po "(?<=href=\")networkaudiod_[^\"]*_$(dpkg --print-architecture).deb(?=\")" | tail -1) # Skip license G_EXEC eval 'debconf-set-selections <<< '\''networkaudiod networkaudiod/license note false'\' # Install Download_Install "${package:+$url$package}" G_EXEC systemctl stop networkaudiod unset -v url arch package fi if To_Install 71 webiopi # WebIOPi then # Check for reinstall local reinstall=0 [[ -f '/etc/webiopi/config' ]] && reinstall=1 aDEPS=('python3-dev' 'python3-setuptools' 'gcc' 'patch') Download_Install 'https://github.com/Freenove/WebIOPi/archive/master.tar.gz' G_EXEC cd WebIOPi-master/WebIOPi-* # Apply patch G_EXEC_OUTPUT=1 G_EXEC patch -p1 -i webiopi-pi2bplus.patch # Install for Python 3 only G_EXEC sed --follow-symlinks -i '/SEARCH="python python3"/c\SEARCH="python3"' setup.sh # Skip Weaved install prompt G_EXEC sed --follow-symlinks -i '/read response/c\response="n"' setup.sh # Run setup script, skipping APT installs G_EXEC_OUTPUT=1 G_EXEC ./setup.sh skip-apt G_EXEC cd "$G_WORKING_DIR" # Cleanup G_EXEC rm -R WebIOPi-master # On fresh installs, change port to 8002 to avoid conflict with Icecast (( $reinstall )) || G_EXEC sed --follow-symlinks -i 's/^port = 8000$/port = 8002/' /etc/webiopi/config # Service Remove_SysV webiopi 1 cat << '_EOF_' > /etc/systemd/system/webiopi.service [Unit] Description=WebIOPi (DietPi) Wants=network-online.target After=network-online.target [Service] SyslogIdentifier=WebIOPi ExecStart=/usr/bin/python3 -m webiopi -c /etc/webiopi/config # Hardening PrivateTmp=true ProtectHome=true [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 98 haproxy # HAProxy then # Dependencies aDEPS=('make' 'gcc' 'libpcre2-dev' 'libssl-dev' 'zlib1g-dev' 'libsystemd-dev') # Obtain latest version: Stick with v3. Once v4 is released, we will surely need to adjust below code. local url=$(curl -sSfL 'https://www.haproxy.org/' | grep -Po '(?<=href=")/download/3\..*/src/haproxy-.*\.tar\.gz(?=")' | head -1) local fallback_url='https://www.haproxy.org/download/3.2/src/haproxy-3.2.4.tar.gz' Download_Install "${url:+https://www.haproxy.org$url}" # Compile G_EXEC cd haproxy-3.* G_EXEC_OUTPUT=1 G_EXEC make -j "$G_HW_CPU_CORES" TARGET=linux-glibc USE_PCRE2=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_PROMEX=1 DEBUG_CFLAGS='-g0 -O3' LDFLAGS='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed' # Strip binary size G_EXEC strip --remove-section=.comment --remove-section=.note haproxy # Install G_EXEC_OUTPUT=1 G_EXEC make install # - systemd unit G_EXEC cd admin/systemd G_EXEC_OUTPUT=1 G_EXEC make G_EXEC mv {,/etc/systemd/system/}haproxy.service # - Error pages G_EXEC cd "$G_WORKING_DIR" G_EXEC mkdir -p /etc/haproxy/errors G_EXEC mv haproxy-3.*/examples/errorfiles/*.http /etc/haproxy/errors/ # Cleanup G_EXEC rm -R haproxy-3.* # Jail directory G_EXEC mkdir -p /var/lib/haproxy # Config [[ -f '/etc/haproxy/haproxy.cfg' ]] || cat << _EOF_ > /etc/haproxy/haproxy.cfg global maxconn 64 # Jail directory chroot /var/lib/haproxy stats socket /run/haproxy.sock mode 660 level admin stats timeout 30s user root group root daemon # Default SSL material locations ca-base /etc/ssl/certs crt-base /etc/ssl/private # Default ciphers to use on SSL-enabled listening sockets. ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 ssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http frontend localnodes bind *:80 mode http default_backend nodes backend nodes mode http balance roundrobin option forwardfor http-request set-header X-Forwarded-Port %[dst_port] http-request add-header X-Forwarded-Proto https if { ssl_fc } option httpchk HEAD / HTTP/1.1 http-check send meth HEAD uri / ver HTTP/1.1 hdr host localhost server web01 127.0.0.1:9000 check server web02 127.0.0.1:9001 check server web03 127.0.0.1:9002 check # Admin web page listen stats bind *:1338 stats enable stats uri / http-request use-service prometheus-exporter if { path /metrics } stats hide-version stats auth admin:$GLOBAL_PW _EOF_ G_EXEC chmod 0600 /etc/haproxy/haproxy.cfg fi if To_Install 35 lyrionmusicserver # Lyrion Music Server then # Grab architecture local arch='arm' (( $G_HW_ARCH == 10 )) && arch='amd64' # Grab latest package URL # - ARM Trixie: v9.0.3 fails to load certain perl modules, v9.1.0 however works if (( $G_HW_ARCH < 10 && $G_DISTRO > 7 )) then local fallback_url='https://downloads.lms-community.org/nightly/lyrionmusicserver_9.1.0~1752577284_arm.deb' Download_Install "$(curl -sSfL 'https://raw.githubusercontent.com/LMS-Community/lms-server-repository/master/dev.xml' | grep -om1 'https://[^"]*_arm.deb')" else local fallback_url="https://downloads.lms-community.org/nightly/lyrionmusicserver_9.0.3~1758288340_$arch.deb" Download_Install "$(curl -sSfL 'https://raw.githubusercontent.com/LMS-Community/lms-server-repository/master/stable.xml' | grep -om1 "https://[^\"]*_$arch.deb")" fi G_EXEC systemctl stop lyrionmusicserver Remove_SysV lyrionmusicserver # Grant user write access to DietPi media dirs for creating infobrowser.opml. G_EXEC usermod -aG dietpi squeezeboxserver Download_Test_Media fi if To_Install 55 # WordPress then Download_Install 'https://wordpress.org/latest.tar.gz' /var/www # Permissions G_EXEC chown -R www-data:www-data /var/www/wordpress # Create MariaDB database /boot/dietpi/func/create_mysql_db wordpress wordpress "$GLOBAL_PW" fi if To_Install 38 # FreshRSS then # Install required PHP modules: https://github.com/FreshRSS/FreshRSS#requirements aDEPS=("php$PHP_VERSION-curl" "php$PHP_VERSION-gmp" "php$PHP_VERSION-intl" "php$PHP_VERSION-mbstring" "php$PHP_VERSION-xml" "php$PHP_VERSION-zip") # - Add JSON module for PHP7, as it does not exist (embedded in core package) on PHP8 local json=() [[ $PHP_VERSION == 8* ]] || aDEPS+=("php$PHP_VERSION-json") json=('json') # Reinstall: Skip download and install, advice to use internal updater from web UI if [[ -d '/opt/FreshRSS' ]] then G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$software_id]} install dir \"/opt/FreshRSS\" already exists. Download and install steps will be skipped. - If you want to update ${aSOFTWARE_NAME[$software_id]}, please use the internal updater from web UI. - If you need to reinstall (e.g. broken instance), please manually backup your config files+data, remove the install dir and rerun \"dietpi-software (re)install $software_id\"." G_AGI "${aDEPS[@]}" aDEPS=() else # Bullseye: v1.25.0 requires PHP 8.1+: https://github.com/FreshRSS/FreshRSS/releases/tag/1.25.0 local version='1.24.3' if (( $G_DISTRO > 6 )) then version=$(curl -sSfL 'https://api.github.com/repos/FreshRSS/FreshRSS/releases/latest' | mawk -F\" '/^ *"tag_name": "[^"]*",$/{print $4}') [[ $version ]] || { version='1.27.0'; G_DIETPI-NOTIFY 1 "Automatic latest FreshRSS version detection failed. Version \"$version\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } fi Download_Install "https://github.com/FreshRSS/FreshRSS/archive/$version.tar.gz" G_EXEC mv "FreshRSS-$version" /opt/FreshRSS fi # Enable required PHP modules: https://github.com/FreshRSS/FreshRSS#requirements G_EXEC phpenmod curl gmp iconv intl pdo_mysql ctype dom mbstring xml zip "${json[@]}" # Apache config if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )) then # Required modules: https://github.com/FreshRSS/FreshRSS/blob/edge/p/.htaccess, https://github.com/FreshRSS/FreshRSS/blob/edge/p/api/.htaccess, https://github.com/FreshRSS/FreshRSS/blob/edge/p/themes/.htaccess # - Do not enable mod_deflate since it may cause issues with concurrent ownCloud and Nextcloud installs: https://docs.nextcloud.com/server/latest/admin_manual/issues/general_troubleshooting.html#web-server-and-php-modules G_EXEC a2enmod dir mime expires headers setenvif # Better compatibility with mobile clients cat << '_EOF_' > /etc/apache2/conf-available/dietpi-freshrss.conf # Based on: https://freshrss.github.io/FreshRSS/en/admins/10_ServerConfig.html AllowOverride AuthConfig FileInfo Indexes Limit Require all granted Options FollowSymLinks AllowEncodedSlashes On _EOF_ G_EXEC a2enconf dietpi-freshrss fi # Create MariaDB database and user # - Create random alphanumeric 30 characters password local password=$(tr -dc '[:alnum:]' < /dev/random | head -c30) if [[ -d '/mnt/dietpi_userdata/mysql/freshrss' ]] then G_DIETPI-NOTIFY 2 'FreshRSS MariaDB database found, will NOT overwrite.' G_EXEC systemctl restart mariadb # Update database password if do-install.php applies it to the FreshRSS config [[ -f '/opt/FreshRSS/data/applied_migrations.txt' ]] || mysql -e "grant all privileges on \`freshrss\`.* to 'freshrss'@localhost identified by '$password';flush privileges" else /boot/dietpi/func/create_mysql_db freshrss freshrss "$password" fi # Set permissions for webserver access G_EXEC chgrp -R www-data /opt/FreshRSS G_EXEC chmod -R g+r+w /opt/FreshRSS # CLI install: https://github.com/FreshRSS/FreshRSS/blob/master/cli/README.md#commands G_EXEC cd /opt/FreshRSS runuser -u www-data -- php ./cli/prepare.php runuser -u www-data -- php ./cli/do-install.php --default_user dietpi --auth_type form --environment production --title FreshRSS --db-type mysql --db-host localhost --db-user freshrss --db-password "$password" --db-base freshrss --db-prefix freshrss unset -v password runuser -u www-data -- php ./cli/create-user.php --user dietpi --password "$GLOBAL_PW" --api_password "$GLOBAL_PW" runuser -u www-data -- php ./cli/actualize-user.php --user dietpi runuser -u www-data -- php ./cli/db-optimize.php --user dietpi G_EXEC cd "$G_WORKING_DIR" # Link web interface to webroot G_EXEC rm -Rf /var/www/freshrss G_EXEC ln -s /opt/FreshRSS/p /var/www/freshrss # Create cron job for feed update every 30 minutes if it does not yet exist crontab -u www-data -l 2>/dev/null | grep -q '/opt/FreshRSS/app/actualize_script.php' || { crontab -u www-data -l 2>/dev/null ; echo '*/30 * * * * php /opt/FreshRSS/app/actualize_script.php'; } | crontab -u www-data - fi if To_Install 28 # TigerVNC Server then # tigervnc-tools ships tigervncpasswd as dedicated package since Bookworm. local apackages=() (( $G_DISTRO > 6 )) && apackages=('tigervnc-tools') G_AGI tigervnc-standalone-server tigervnc-scraping-server "${apackages[@]}" fi if To_Install 120 # RealVNC Server then local deps=() # Bullseye: Depends on libbcm_host.so but does not pull libraspberrypi0 as dependency (( $G_DISTRO < 7 )) && deps=('libraspberrypi0') # Trixie: Add Bookworm suite for this particular source package. It has been tested to be compatible with Trixie, package-wise and also practically functional. if (( $G_DISTRO > 7 )) then G_DIETPI-NOTIFY 2 'Adding Raspberry Pi repository Bookworm suite with APT pins limiting installs to RealVNC packages only' G_EXEC eval 'echo '\''deb https://archive.raspberrypi.com/debian bookworm main'\'' >> /etc/apt/sources.list.d/dietpi-realvnc.list' G_EXEC eval 'cat << '\''_EOF_'\'' > /etc/apt/preferences.d/dietpi-realvnc Package: * Pin: release n=bookworm, origin archive.raspberrypi.com Pin-Priority: -1 Package: src:realvnc-vnc Pin: release n=bookworm, origin archive.raspberrypi.com Pin-Priority: 500 _EOF_' G_AGUP fi G_AGI realvnc-vnc-server "${deps[@]}" fi # TigerVNC/RealVNC Server: Shared setup if (( ${aSOFTWARE_INSTALL_STATE[28]} == 1 || ${aSOFTWARE_INSTALL_STATE[120]} == 1 )) then # Service cat << '_EOF_' > /etc/systemd/system/vncserver.service [Unit] Description=VNC Server (DietPi) Before=xrdp.service xrdp-sesman.service Wants=network-online.target After=network-online.target [Service] RemainAfterExit=yes PAMName=login User=root Environment=HOME=/root ExecStart=/usr/local/bin/vncserver start ExecStop=/usr/local/bin/vncserver stop [Install] WantedBy=multi-user.target _EOF_ aSTART_SERVICES+=('vncserver') cat << '_EOF_' > /usr/local/bin/vncserver #!/bin/dash if [ -f '/usr/bin/vncserver-virtual' ] then echo '[ OK ] RealVNC detected' FP_BINARY='/usr/bin/vncserver-virtual -Authentication VncAuth' FP_SHARED='exec /usr/bin/vncserver-x11 -service -Authentication VncAuth' elif [ -f '/usr/bin/tigervncserver' ] then echo '[ OK ] TigerVNC detected' FP_BINARY='/usr/bin/tigervncserver' FP_SHARED="/usr/bin/X0tigervnc -display :0 -rfbauth $HOME/.vnc/passwd" else echo '[FAILED] No supported VNC server installed' exit 1 fi case "$1" in start) # Shared desktop mode if grep -q '^[[:blank:]]*SOFTWARE_VNCSERVER_SHARE_DESKTOP=1' /boot/dietpi.txt then echo '[ INFO ] Waiting for X server...' while : do until pgrep '^X' > /dev/null 2>&1; do sleep 1; done echo '[ INFO ] Connecting to shared desktop' $FP_SHARED sleep 2 pgrep '^X' > /dev/null 2>&1 && exit 1 echo '[ INFO ] X server stopped, waiting for next session...' done # Virtual desktop mode else DISPLAY=$(sed -n '/^[[:blank:]]*SOFTWARE_VNCSERVER_DISPLAY_INDEX=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) WIDTH=$(sed -n '/^[[:blank:]]*SOFTWARE_VNCSERVER_WIDTH=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) HEIGHT=$(sed -n '/^[[:blank:]]*SOFTWARE_VNCSERVER_HEIGHT=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) DEPTH=$(sed -n '/^[[:blank:]]*SOFTWARE_VNCSERVER_DEPTH=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) echo "[ INFO ] Starting virtual desktop at display :${DISPLAY:=1} in ${WIDTH:=1280}x${HEIGHT:=720}x${DEPTH:=16}" export SHELL='/bin/bash' exec $FP_BINARY ":$DISPLAY" -geometry "${WIDTH}x$HEIGHT" -depth "$DEPTH" fi ;; stop) # Shared desktop mode if grep -q '^[[:blank:]]*SOFTWARE_VNCSERVER_SHARE_DESKTOP=1' /boot/dietpi.txt then echo '[ INFO ] Disconnecting from shared desktop' killall -qw vncserver-x11-core X0tigervnc # Virtual desktop mode else DISPLAY=$(sed -n '/^[[:blank:]]*SOFTWARE_VNCSERVER_DISPLAY_INDEX=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) echo "[ INFO ] Stopping virtual desktop at display :${DISPLAY:=1}" $FP_BINARY -kill ":$DISPLAY" fi ;; *) echo "[FAILED] Invalid command ($1), please use \"start\" or \"stop\"" exit 1 ;; esac exit 0 _EOF_ G_EXEC chmod +x /usr/local/bin/vncserver # TigerVNC if (( ${aSOFTWARE_INSTALL_STATE[28]} == 1 )) then # TigerVNC: Permit remote connections which implies TLSVnc authentications being enabled additionally # shellcheck disable=SC2016 GCI_PRESERVE=1 G_CONFIG_INJECT '\$localhost[[:blank:]]*=' '$localhost = "no";' /etc/tigervnc/vncserver-config-defaults # Set control + read-only passwords local path='/root/.vnc' (( $G_DISTRO > 7 )) && path='/root/.config/tigervnc' if [[ ! -f $path/passwd ]] then G_EXEC mkdir -p "$path" tigervncpasswd -f <<< "$GLOBAL_PW $GLOBAL_PW" > "$path/passwd" G_EXEC chmod 0600 "$path/passwd" fi fi # RealVNC if (( ${aSOFTWARE_INSTALL_STATE[120]} == 1 )) then # Assure that its services are disabled when ours is enabled G_EXEC systemctl --no-reload disable vncserver-virtuald vncserver-x11-serviced # Set (+verify) virtual + shared desktop passwords: https://github.com/MichaIng/DietPi/pull/4679#issuecomment-908196511 if [[ ! -s '/root/.vnc/config.d/Xvnc' ]] then vncpasswd -virtual <<< "$GLOBAL_PW $GLOBAL_PW" vncpasswd -service <<< "$GLOBAL_PW $GLOBAL_PW" fi [[ -f '/root/.vnc/config.d/.Xvnc-v5-marker' ]] || > /root/.vnc/config.d/.Xvnc-v5-marker fi fi if To_Install 73 fail2ban # Fail2Ban then # Create jail.conf (backend = systemd) first, to prevent APT failure due to missing /var/log/auth.log: https://github.com/MichaIng/DietPi/issues/475#issuecomment-310873879 G_EXEC mkdir -p /etc/fail2ban/{fail2ban,filter}.d [[ -f '/etc/fail2ban/jail.conf' ]] || cat << '_EOF_' > /etc/fail2ban/jail.conf [DEFAULT] enabled = true ignoreip = 127.0.0.1/8 ignorecommand = backend = systemd mode = normal filter = %(__name__)s[mode=%(mode)s] findtime = 600 maxretry = 3 bantime = 600 banaction = route action = %(banaction)s[blocktype=blackhole] [dropbear] [sshd] # Mode: normal (default), ddos, extra or aggressive (combines all) # See "filter.d/sshd.conf" for details. #mode = normal _EOF_ # Log to systemd by default G_EXEC eval 'echo -e '\''[Definition]\nlogtarget = SYSOUT'\'' > /etc/fail2ban/fail2ban.d/97_dietpi.conf' # Fix Dropbear filter for STDOUT logging since Bookworm: https://github.com/fail2ban/fail2ban/pull/3597 [[ -f '/etc/fail2ban/filter.d/dropbear.local' ]] || G_EXEC curl -sSf 'https://raw.githubusercontent.com/fail2ban/fail2ban/master/config/filter.d/dropbear.conf' -o /etc/fail2ban/filter.d/dropbear.local # Trixie: python3-systemd has become hard package dependency local deps=() (( $G_DISTRO > 7 )) || deps=('python3-systemd') G_AGI "${deps[@]}" fail2ban Remove_SysV fail2ban 1 # Failsafe G_EXEC systemctl unmask fail2ban G_EXEC systemctl start fail2ban fi if To_Install 74 influxdb # InfluxDB then # APT key local url='https://repos.influxdata.com/influxdata-archive_compat.key' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-influxdb.gpg --yes" # APT list local dist=$G_DISTRO_NAME (( $G_DISTRO > 7 )) && dist='bookworm' G_EXEC eval "echo 'deb https://repos.influxdata.com/debian $dist stable' > /etc/apt/sources.list.d/dietpi-influxdb.list" G_AGUP # APT package G_AGI influxdb G_EXEC systemctl stop influxdb # Link database to userdata location if [[ -d '/mnt/dietpi_userdata/influxdb' ]] then G_DIETPI-NOTIFY 2 'Existing database/plugin directory /mnt/dietpi_userdata/influxdb found. Will not overwrite...' elif [[ -d '/var/lib/influxdb' ]] then G_EXEC mv /var/lib/influxdb /mnt/dietpi_userdata/ else G_EXEC mkdir /mnt/dietpi_userdata/influxdb G_EXEC chown -R influxdb:influxdb /mnt/dietpi_userdata/influxdb fi G_EXEC rm -Rf /var/lib/influxdb G_EXEC ln -s /mnt/dietpi_userdata/influxdb /var/lib/influxdb fi if To_Install 77 grafana-server # Grafana: https://grafana.com/docs/grafana/latest/setup-grafana/installation/debian/#install-from-apt-repository then # ARMv6: Since Grafana repo is not compatible, install package from our repo, taken from here: https://grafana.com/grafana/download?platform=arm&edition=oss if (( $G_HW_ARCH == 1 )) then G_AGI grafana-rpi else # APT key local url='https://apt.grafana.com/gpg.key' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-grafana.gpg --yes" # APT list G_EXEC eval 'echo '\''deb https://apt.grafana.com stable main'\'' > /etc/apt/sources.list.d/grafana.list' G_AGUP # APT package G_AGI grafana fi G_EXEC systemctl stop grafana-server Remove_SysV grafana-server # Link DB/plugins to userdata location if [[ -d '/mnt/dietpi_userdata/grafana' ]] then G_DIETPI-NOTIFY 2 'Existing database/plugin directory /mnt/dietpi_userdata/grafana found. Will not overwrite...' elif [[ -d '/var/lib/grafana' ]] then G_EXEC mv /var/lib/grafana /mnt/dietpi_userdata/ else G_EXEC mkdir /mnt/dietpi_userdata/grafana G_EXEC chown -R grafana:grafana /mnt/dietpi_userdata/grafana fi G_EXEC rm -Rf /var/lib/grafana G_EXEC ln -s /mnt/dietpi_userdata/grafana /var/lib/grafana # Config: Apply our defaults only if nothing was set before # - Set password, wrap into tripled double quotes in case of ; or # being contained, according to docs: http://docs.grafana.org/installation/configuration/#password GCI_PRESERVE=1 GCI_PASSWORD=1 G_CONFIG_INJECT 'admin_password[[:blank:]]*=' "admin_password = \"\"\"$GLOBAL_PW\"\"\"" /etc/grafana/grafana.ini # - Set port to 3001 (away from default 3000) to avoid conflict with Gogs and Gitea GCI_PRESERVE=1 G_CONFIG_INJECT 'http_port[[:blank:]]*=' 'http_port = 3001' /etc/grafana/grafana.ini fi if To_Install 64 # phpSysInfo then # Download Download_Install 'https://github.com/phpsysinfo/phpsysinfo/archive/stable.tar.gz' # Clean reinstall, but preserve previous config if [[ -d '/var/www/phpsysinfo' ]] then G_EXEC mv /var/www/phpsysinfo/phpsysinfo.ini phpsysinfo-stable/phpsysinfo.ini G_EXEC rm -R /var/www/phpsysinfo fi G_EXEC mv phpsysinfo-stable /var/www/phpsysinfo [[ -f '/var/www/phpsysinfo/phpsysinfo.ini' ]] || dps_index=$software_id Download_Install 'phpsysinfo.ini' /var/www/phpsysinfo/phpsysinfo.ini fi if To_Install 80 ubooquity # Ubooquity then G_EXEC curl -sSfL 'https://vaemendis.net/ubooquity/service/download.php' -o Ubooquity.zip command -v unzip > /dev/null || G_AGI unzip G_EXEC unzip -o Ubooquity.zip G_EXEC rm Ubooquity.zip G_EXEC mkdir -p /mnt/dietpi_userdata/ubooquity G_EXEC mv {,/mnt/dietpi_userdata/ubooquity/}Ubooquity.jar # User Create_User -G dietpi -d /mnt/dietpi_userdata/ubooquity ubooquity # Data G_EXEC mkdir -p /mnt/dietpi_userdata/{ebooks,comics} # Logs G_EXEC rm -Rf /mnt/dietpi_userdata/ubooquity/logs G_EXEC ln -s /var/log/ubooquity /mnt/dietpi_userdata/ubooquity/logs # Service G_DIETPI-NOTIFY 2 "Generating systemd service to start ${aSOFTWARE_NAME[$software_id]} on boot" cat << _EOF_ > /etc/systemd/system/ubooquity.service [Unit] Description=Ubooquity (DietPi) Wants=network-online.target After=network-online.target remote-fs.target [Service] SyslogIdentifier=Ubooquity User=ubooquity LogsDirectory=ubooquity WorkingDirectory=/mnt/dietpi_userdata/ubooquity ExecStart=$JAVA_PATH -mx${JAVA_MAX_HEAP_SIZE}m -jar /mnt/dietpi_userdata/ubooquity/Ubooquity.jar --headless --remoteadmin --adminport 2038 --libraryport 2039 SuccessExitStatus=143 [Install] WantedBy=multi-user.target _EOF_ # Permissions G_EXEC chmod +x /mnt/dietpi_userdata/ubooquity/Ubooquity.jar G_EXEC chown -R ubooquity /mnt/dietpi_userdata/ubooquity G_EXEC chown ubooquity:dietpi /mnt/dietpi_userdata/{ebooks,comics} G_EXEC chmod 0775 /mnt/dietpi_userdata/{ebooks,comics} fi if To_Install 179 komga # Komga then local fallback_url='https://github.com/gotson/komga/releases/download/1.23.4/komga-1.23.4.jar' Download_Install "$(curl -sSfL 'https://api.github.com/repos/gotson/komga/releases/latest' | mawk -F\" '/^ *"browser_download_url": ".*\/komga-[^"\/]*\.jar"$/{print $4}')" /mnt/dietpi_userdata/komga/komga.jar # User Create_User -G dietpi -d /mnt/dietpi_userdata/komga komga # Data G_EXEC mkdir -p /mnt/dietpi_userdata/{ebooks,comics,komga/.komga} # Config [[ -f '/mnt/dietpi_userdata/komga/application.yml' ]] || cat << _EOF_ > /mnt/dietpi_userdata/komga/application.yml komga: libraries-scan-startup: true # Scan libraries at startup libraries-scan-cron: "* 2 * * * *" # Scan libraries periodically every hour at :02 database: file: /mnt/dietpi_userdata/komga/database.sqlite remember-me: key: $(openssl rand -hex 32) logging: file: name: "" # Disable file logging, use: "journalctl -u komga" level: root: WARN # TRACE DEBUG INFO WARN ERROR server: port: 2037 _EOF_ # Service cat << _EOF_ > /etc/systemd/system/komga.service [Unit] Description=Komga (DietPi) Wants=network-online.target After=network-online.target remote-fs.target [Service] SyslogIdentifier=Komga User=komga WorkingDirectory=/mnt/dietpi_userdata/komga ExecStart=$JAVA_PATH -mx${JAVA_MAX_HEAP_SIZE}m -jar komga.jar SuccessExitStatus=143 [Install] WantedBy=multi-user.target _EOF_ # Permissions G_EXEC chmod +x /mnt/dietpi_userdata/komga/komga.jar G_EXEC chown -R komga /mnt/dietpi_userdata/komga G_EXEC chown komga:dietpi /mnt/dietpi_userdata/{ebooks,comics} G_EXEC chmod 0775 /mnt/dietpi_userdata/{ebooks,comics} fi if To_Install 56 # Single File PHP Gallery then G_DIETPI-NOTIFY 2 'Obtaining latest download from: https://sye.dk/sfpg/?latest' local file=$(curl -sSfL 'https://sye.dk/sfpg/?latest') [[ $file ]] || { file='Single_File_PHP_Gallery_4.14.0.zip'; G_DIETPI-NOTIFY 1 "Automatic latest ${aSOFTWARE_NAME[$software_id]} download detection failed. Downloading the last known \"$file\" is attempted as fallback, but may fail if a newer version is available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } # Install required PHP modules: https://sye.dk/sfpg/ aDEPS=("php$PHP_VERSION-gd") Download_Install "https://sye.dk/sfpg/$file" /var/www/gallery # Enable required PHP modules G_EXEC phpenmod gd # Thumbnails and metadata cache: Remove on reinstalls [[ -d '/var/www/gallery/_sfpg_data' ]] && G_EXEC rm -R /var/www/gallery/_sfpg_data G_EXEC mkdir /var/www/gallery/_sfpg_data G_EXEC chown www-data /var/www/gallery/_sfpg_data # Apply a random security phrase local phrase=$(tr -dc '[:alnum:]' < /dev/random | head -c30) GCI_PASSWORD=1 G_CONFIG_INJECT "define\('SECURITY_PHRASE'" "define('SECURITY_PHRASE', '$phrase');" /var/www/gallery/index.php unset -v phrase # Create test galleries G_EXEC mkdir -p /var/www/gallery/DietPi [[ -f '/var/www/gallery/DietPi/logo_256.png' ]] || G_THREAD_START curl -sSf 'https://dietpi.com/images/dietpi-logo_256x256.png' -o /var/www/gallery/DietPi/logo_256.png G_EXEC mkdir -p /var/www/gallery/Tr-Zero [[ -f '/var/www/gallery/Tr-Zero/SS_0.jpg' ]] || G_THREAD_START curl -sSfL 'https://media.indiedb.com/images/games/1/25/24673/SS_0.jpg' -o /var/www/gallery/Tr-Zero/SS_0.jpg [[ -f '/var/www/gallery/Tr-Zero/SS_1.jpg' ]] || G_THREAD_START curl -sSfL 'https://media.indiedb.com/images/games/1/25/24673/SS_44.jpg' -o /var/www/gallery/Tr-Zero/SS_1.jpg [[ -f '/var/www/gallery/Tr-Zero/SS_2.jpg' ]] || G_THREAD_START curl -sSfL 'https://media.indiedb.com/images/games/1/25/24673/3.png' -o /var/www/gallery/Tr-Zero/SS_2.jpg G_THREAD_WAIT fi if To_Install 40 # Ampache then # Required PHP modules: https://github.com/ampache/ampache/wiki/Installation#prerequisites aDEPS=("php$PHP_VERSION-curl" "php$PHP_VERSION-intl" "php$PHP_VERSION-xml") # - Add JSON module for PHP7, as it does not exist (embedded in core package) on PHP8 local json=() [[ $PHP_VERSION == 8* ]] || aDEPS+=("php$PHP_VERSION-json") json=('json') # Download: Ampache v7 requires PHP 8.2 if (( $G_DISTRO > 6 )) then local fallback_url="https://github.com/ampache/ampache/releases/download/7.7.2/ampache-7.7.2_all_php$PHP_VERSION.zip" Download_Install "$(curl -sSfL 'https://api.github.com/repos/ampache/ampache/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/ampache-[0-9\.]*_all_php$PHP_VERSION.zip\"$/{print \$4}")" ampache else local fallback_url="https://github.com/ampache/ampache/releases/download/6.6.7/ampache-6.6.7_all_php$PHP_VERSION.zip" Download_Install "$(curl -sSfL 'https://api.github.com/repos/ampache/ampache/releases' | mawk -F\" "/^ *\"browser_download_url\": \".*\/ampache-[0-9\.]*_all_php$PHP_VERSION.zip\"$/{print \$4}" | head -1)" ampache fi # Reinstall: Preserve configs from old and new paths [[ -f '/var/www/ampache/config/ampache.cfg.php' ]] && G_EXEC mv /var/www/ampache/config/ampache.cfg.php ampache/config/ [[ -f '/var/www/ampache/config/registration_agreement.php' ]] && G_EXEC mv /var/www/ampache/config/registration_agreement.php ampache/config/ [[ -f '/mnt/dietpi_userdata/ampache/config/ampache.cfg.php' ]] && G_EXEC mv /mnt/dietpi_userdata/ampache/config/ampache.cfg.php ampache/config/ [[ -f '/mnt/dietpi_userdata/ampache/config/registration_agreement.php' ]] && G_EXEC mv /mnt/dietpi_userdata/ampache/config/registration_agreement.php ampache/config/ [[ -f '/var/www/ampache/channel/.htaccess' ]] && G_EXEC mv /var/www/ampache/channel/.htaccess ampache/public/channel/ [[ -f '/var/www/ampache/rest/.htaccess' ]] && G_EXEC mv /var/www/ampache/rest/.htaccess ampache/public/rest/ [[ -f '/var/www/ampache/play/.htaccess' ]] && G_EXEC mv /var/www/ampache/play/.htaccess ampache/public/play/ [[ -d '/var/www/ampache' || -L '/var/www/ampache' ]] && G_EXEC rm -R /var/www/ampache [[ -d '/mnt/dietpi_userdata/ampache' ]] && G_EXEC rm -R /mnt/dietpi_userdata/ampache G_EXEC mv {,/mnt/dietpi_userdata/}ampache [[ -d '/mnt/dietpi_userdata/ampache/public' ]] && G_EXEC ln -s /mnt/dietpi_userdata/ampache/public /var/www/ampache Download_Test_Media # Enable required PHP modules: https://github.com/ampache/ampache/wiki/Installation#prerequisites G_EXEC phpenmod curl intl xml "${json[@]}" # Create random temporary alphanumeric 30 characters database password local password=$(tr -dc '[:alnum:]' < /dev/random | head -c30) # Fresh install: Create new config if [[ ! -f '/mnt/dietpi_userdata/ampache/config/ampache.cfg.php' ]] then G_EXEC cp /mnt/dietpi_userdata/ampache/config/ampache.cfg.php{.dist,} G_CONFIG_INJECT 'web_path[[:blank:]]+=' 'web_path = "/ampache"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'database_hostname[[:blank:]]+=' 'database_hostname = /run/mysqld/mysqld.sock' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'database_name[[:blank:]]+=' 'database_name = ampache' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'database_username[[:blank:]]+=' 'database_username = ampache' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php GCI_PASSWORD=1 G_CONFIG_INJECT 'database_password[[:blank:]]+=' "database_password = \"$password\"" /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'tmp_dir_path[[:blank:]]+=' 'tmp_dir_path = "/tmp"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'transcode_cmd[[:blank:]]+=' 'transcode_cmd = "ffmpeg"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'transcode_m4a[[:blank:]]+=' 'transcode_m4a = "required"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'transcode_flac[[:blank:]]+=' 'transcode_flac = "required"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'transcode_mpc[[:blank:]]+=' 'transcode_mpc = "required"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'transcode_ogg[[:blank:]]+=' 'transcode_ogg = "allowed"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'transcode_wav[[:blank:]]+=' 'transcode_wav = "required"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'transcode_avi[[:blank:]]+=' 'transcode_avi = "allowed"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'transcode_mkv[[:blank:]]+=' 'transcode_mkv = "allowed"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'transcode_mpg[[:blank:]]+=' 'transcode_mpg = "allowed"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'encode_target[[:blank:]]+=' 'encode_target = mp3' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'encode_video_target[[:blank:]]+=' 'encode_video_target = webm' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'generate_video_preview[[:blank:]]+=' 'generate_video_preview = "true"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php G_CONFIG_INJECT 'waveform[[:blank:]]+=' 'waveform = "true"' /mnt/dietpi_userdata/ampache/config/ampache.cfg.php # Update password as well in rare but possible case that config file still exists but database was lost elif [[ ! -d '/mnt/dietpi_userdata/mysql/ampache' ]] then GCI_PASSWORD=1 G_CONFIG_INJECT 'database_password[[:blank:]]+=' "database_password = \"$password\"" /mnt/dietpi_userdata/ampache/config/ampache.cfg.php fi # Permissions: Permit config file updates via web UI G_EXEC chown www-data /mnt/dietpi_userdata/ampache/config/ampache.cfg.php{.dist,} # Fresh install: Generate database G_EXEC systemctl start mariadb if [[ ! -d '/mnt/dietpi_userdata/mysql/ampache' ]] then /boot/dietpi/func/create_mysql_db ampache ampache "$password" # Import template G_EXEC mysql ampache < /mnt/dietpi_userdata/ampache/resources/sql/ampache.sql # Generate admin user: Replace password string internally to avoid printing it to console G_EXEC_PRE_FUNC(){ acommand[6]=$GLOBAL_PW; } G_EXEC php /mnt/dietpi_userdata/ampache/bin/cli admin:addUser -l 100 -p "${GLOBAL_PW//?/X}" dietpi # Generate local music catalogue G_EXEC_OUTPUT=1 G_EXEC php /mnt/dietpi_userdata/ampache/bin/cli run:addCatalog Music /mnt/dietpi_userdata/Music music # Scan for music files G_EXEC_OUTPUT=1 G_EXEC php /mnt/dietpi_userdata/ampache/bin/cli run:updateCatalog # Reinstall: Update database else G_EXEC_OUTPUT=1 G_EXEC php /mnt/dietpi_userdata/ampache/bin/cli admin:updateDatabase fi unset -v password fi if To_Install 58 tailscaled # Tailscale then # APT key G_EXEC curl -sSfL "https://pkgs.tailscale.com/stable/debian/$G_DISTRO_NAME.noarmor.gpg" -o /etc/apt/trusted.gpg.d/dietpi-tailscale.gpg # APT list G_EXEC eval "echo 'deb https://pkgs.tailscale.com/stable/debian $G_DISTRO_NAME main' > /etc/apt/sources.list.d/dietpi-tailscale.list" G_AGUP # APT package G_AGI tailscale Enable_IP_forwarding tailscale fi if To_Install 97 # OpenVPN Server then G_AGI openvpn iptables Remove_SysV openvpn Configure_iptables aSTART_SERVICES+=('openvpn') # Create initial server and client configs if not yet present # - Wildcard config file detection via for loop local i for i in /etc/openvpn/*.conf do # Inform user if config exist, that config generation is skipped if [[ -f $i ]] then G_DIETPI-NOTIFY 2 "Existing OpenVPN configuration found: $i - Config generation will be skipped. - If you need a fresh key/cert/config set, please remove $i and run: dietpi-software reinstall 97" break fi # Pre-v6.26 cleanup [[ -f '/etc/openvpn/dh2048.pem' ]] && G_EXEC rm /etc/openvpn/dh2048.pem dpkg-query -s easy-rsa &> /dev/null && G_AGP easy-rsa # Download latest easy-rsa from GitHub G_DIETPI-NOTIFY 2 'Downloading latest easy-rsa for certificate and key generation...' local fallback_url='https://github.com/OpenVPN/easy-rsa/releases/download/v3.1.0/EasyRSA-3.1.0.tgz' Download_Install "$(curl -sSfL 'https://api.github.com/repos/OpenVPN/easy-rsa/releases/latest' | mawk -F\" '/"browser_download_url": .*\/EasyRSA-[^"\/]*\.tgz"/{print $4}')" [[ -d '/etc/openvpn/easy-rsa' ]] && G_EXEC rm -R /etc/openvpn/easy-rsa G_EXEC mv EasyRSA-* /etc/openvpn/easy-rsa # Cert and key generation via easy-rsa G_DIETPI-NOTIFY 2 'Generating unique OpenVPN certificates and keys. Please wait...\n' G_EXEC cd /etc/openvpn/easy-rsa cat << '_EOF_' > vars set_var EASYRSA_REQ_COUNTRY "UK" set_var EASYRSA_REQ_PROVINCE "DietPi" set_var EASYRSA_REQ_CITY "DietPi" set_var EASYRSA_REQ_ORG "DietPi" set_var EASYRSA_REQ_EMAIL "noreply@dietpi.com" set_var EASYRSA_REQ_OU "DietPi" set_var EASYRSA_BATCH "1" _EOF_ ./easyrsa init-pki ./easyrsa build-ca nopass ./easyrsa gen-dh ./easyrsa build-server-full DietPi_OpenVPN_Server nopass ./easyrsa build-client-full DietPi_OpenVPN_Client nopass # Server config cp -a pki/{ca.crt,dh.pem,issued/DietPi_OpenVPN_Server.crt,private/DietPi_OpenVPN_Server.key} /etc/openvpn/ G_EXEC cd /etc/openvpn cat << '_EOF_' > server.conf port 1194 proto udp dev tun ca ca.crt cert DietPi_OpenVPN_Server.crt key DietPi_OpenVPN_Server.key dh dh.pem server 10.8.0.0 255.255.255.0 client-to-client keepalive 10 60 comp-lzo max-clients 10 user nobody group nogroup persist-key persist-tun verb 3 # Web Forwarding (uncomment to enable) #push "redirect-gateway" #push "dhcp-option DNS 10.8.0.1" _EOF_ # Client config cat << '_EOF_' > DietPi_OpenVPN_Client.ovpn client proto udp dev tun # IP/domain name of DietPi system, running OpenVPN server remote mywebsite.com 1194 resolv-retry infinite nobind user nobody group nogroup persist-key persist-tun remote-cert-tls server comp-lzo verb 3 _EOF_ # - Add CA cert, client cert and key echo -e " \n$( \n$( \n$(" >> DietPi_OpenVPN_Client.ovpn # - Copy to userdata G_EXEC cp DietPi_OpenVPN_Client.ovpn /mnt/dietpi_userdata/ # - and /boot partition G_EXEC cp DietPi_OpenVPN_Client.ovpn /boot/ G_EXEC cd "$G_WORKING_DIR" break # Always break loop which is only for single wildcard file detection done Enable_IP_forwarding openvpn # ToDo: iptables NAT rules: Those need to run via pre-up and post-down rules when the OpenSSH server starts #iptables -A FORWARD -i tun0 -j ACCEPT #iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o "$(G_GET_NET iface)" -j MASQUERADE #ip6tables -A FORWARD -i tun0 -j ACCEPT #ip6tables -t nat -A POSTROUTING -o "$(G_GET_NET iface)" -j MASQUERADE fi if To_Install 117 # PiVPN then G_EXEC curl -sSfL 'https://raw.githubusercontent.com/pivpn/pivpn/master/auto_install/install.sh' -o install.bash G_EXEC chmod +x install.bash G_DIETPI-NOTIFY 2 'Preventing reboot from within PiVPN installer' G_EXEC sed --follow-symlinks -i '/^Thank you for using PiVPN./a\exit 0' install.bash G_DIETPI-NOTIFY 2 'Preventing install of unattended-upgrades' G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*askUnattendedUpgrades$/c\UNATTUPG=0' install.bash G_DIETPI-NOTIFY 2 'Prevent dhcpcd from being installed' G_EXEC sed --follow-symlinks -i '/^checkStaticIpSupported() {$/a\return 1' install.bash # Unattended install local options=() if [[ -f '/boot/unattended_pivpn.conf' ]] then G_CONFIG_INJECT 'UNATTUPG=[[:digit:]]' 'UNATTUPG=0' /boot/unattended_pivpn.conf options=('--unattended' '/boot/unattended_pivpn.conf') fi # APT deps G_AGI bind9-dnsutils grepcidr net-tools bsdmainutils iptables-persistent # https://github.com/pivpn/pivpn/blob/master/auto_install/install.sh#L39 Configure_iptables G_EXEC_OUTPUT=1 G_EXEC_NOEXIT=1 G_EXEC ./install.bash "${options[@]}" || aSOFTWARE_INSTALL_STATE[$software_id]=0 G_EXEC rm install.bash [[ -f '/boot/unattended_pivpn.conf' ]] && G_EXEC mv /boot/unattended_pivpn.conf{,.applied} fi if To_Install 201 zerotier-one # ZeroTier then # APT key: Download from GitHub instead of https://download.zerotier.com/contact%40zerotier.com.gpg for enhanced protection against corrupted download server local url='https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/doc/contact%40zerotier.com.gpg' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-zerotier.gpg --yes" # APT list local dist=$G_DISTRO_NAME (( $G_DISTRO > 7 )) && dist='bookworm' G_EXEC eval "echo 'deb https://download.zerotier.com/debian/$dist $dist main' > /etc/apt/sources.list.d/dietpi-zerotier.list" G_AGUP # APT package G_AGI zerotier-one Remove_SysV zerotier-one # Wait for and print ZeroTier address CC_STOP=0 Create_Config '/var/lib/zerotier-one/identity.secret' 'zerotier-one' && G_DIETPI-NOTIFY 0 "Your ZeroTier address is: $(mawk -F: '{print $1}' /var/lib/zerotier-one/identity.public)" fi if To_Install 92 # Certbot then if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )) then G_AGI certbot python3-certbot-apache elif (( ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then G_AGI certbot python3-certbot-nginx else G_AGI certbot fi fi if To_Install 60 # WiFi Hotspot then local packages=('hostapd' 'isc-dhcp-server' 'iptables') G_AGI "${packages[@]}" G_EXEC systemctl stop hostapd isc-dhcp-server aSTART_SERVICES+=('hostapd' 'isc-dhcp-server') Configure_iptables # Unmask hostapd since it is masked via postinst when no config exists yet G_EXEC systemctl --no-reload unmask hostapd # Enable WiFi modules /boot/dietpi/func/dietpi-set_hardware wifimodules enable local eth_iface=$(G_GET_NET -t eth iface) local wifi_iface=$(G_GET_NET -t wlan iface) # DHCP server config G_BACKUP_FP /etc/dhcp/dhcpd.conf cat << '_EOF_' > /etc/dhcp/dhcpd.conf authoritative; #default-lease-time 43200; #max-lease-time 86400; subnet 192.168.42.0 netmask 255.255.255.0 { range 192.168.42.10 192.168.42.250; option broadcast-address 192.168.42.255; option routers 192.168.42.1; option domain-name "local"; option domain-name-servers 9.9.9.9, 149.112.112.112; } _EOF_ # Assign detected WLAN interface G_EXEC eval "echo 'INTERFACESv4=\"$wifi_iface\"' > /etc/default/isc-dhcp-server" # Remove all entries below wlan, so we can recreate them G_EXEC sed --follow-symlinks -Ei '/(allow-hotplug|auto)[[:blank:]]+wlan/q0' /etc/network/interfaces # Enable up wlan G_CONFIG_INJECT 'allow-hotplug wlan' "allow-hotplug $wifi_iface" /etc/network/interfaces # Add WiFi settings to network interfaces config cat << _EOF_ >> /etc/network/interfaces iface $wifi_iface inet static address 192.168.42.1 netmask 255.255.255.0 #gateway 192.168.0.1 #dns-nameservers 9.9.9.9 149.112.112.112 pre-up iw dev $wifi_iface set power_save off post-down iw dev $wifi_iface set power_save on # iptables NAT rules up iptables-restore < /etc/iptables.ipv4.nat up ip6tables-restore < /etc/iptables.ipv6.nat _EOF_ # Remove wireless-power setting if not supported by adapter/firmware # shellcheck disable=SC2015 iw dev "$wifi_iface" set power_save on 2> /dev/null && iw dev "$wifi_iface" set power_save off 2> /dev/null || G_EXEC sed --follow-symlinks -i '/ iw dev .* set power_save /d' /etc/network/interfaces # Access point config # - Parse dietpi.txt local ssid=$(sed -n '/^[[:blank:]]*SOFTWARE_WIFI_HOTSPOT_SSID=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) local key=$(sed -n '/^[[:blank:]]*SOFTWARE_WIFI_HOTSPOT_KEY=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) local wifi4=$(sed -n '/^[[:blank:]]*SOFTWARE_WIFI_HOTSPOT_WIFI4=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) local wifi5=$(sed -n '/^[[:blank:]]*SOFTWARE_WIFI_HOTSPOT_WIFI5=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) local wifi6=0 (( $G_DISTRO > 6 )) && wifi6=$(sed -n '/^[[:blank:]]*SOFTWARE_WIFI_HOTSPOT_WIFI6=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) local freq5=$(sed -n '/^[[:blank:]]*SOFTWARE_WIFI_HOTSPOT_5G=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) # - Sanity checks [[ $wifi4 == [01] ]] || wifi4=0 [[ $wifi5 == [01] ]] || wifi5=0 [[ $wifi6 == [01] ]] || wifi6=0 [[ $freq5 == [01] ]] || freq5=0 (( ${#key} > 8 )) || { G_DIETPI-NOTIFY 1 'WiFi key from dietpi.txt is too short (less than 8 characters), falling back to default: "dietpihotspot"'; key='dietpihotspot'; } # - WiFi 5 implies 5 GHz and 5 GHz requires at least WiFi 4 (( $wifi5 )) && freq5=1 (( $freq5 && ! $wifi5 && ! $wifi6 )) && wifi4=1 # - Enable WMM with QoS if WiFi 4 or 5 is enabled local wmm_enabled=0 (( $wifi4 || $wifi5 || $wifi6 )) && wmm_enabled=1 # - Apply mode channel based on frequency local mode='g' if (( $freq5 )) then mode='a' local channel=$(sed -n '/^[[:blank:]]*SOFTWARE_WIFI_HOTSPOT_5G_CHANNEL=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) disable_error=1 G_CHECK_VALIDINT "$channel" 32 177 || channel=36 else local channel=$(sed -n '/^[[:blank:]]*SOFTWARE_WIFI_HOTSPOT_CHANNEL=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) disable_error=1 G_CHECK_VALIDINT "$channel" 1 13 || channel=3 fi # - Create config G_BACKUP_FP /etc/hostapd/hostapd.conf cat << _EOF_ > /etc/hostapd/hostapd.conf interface=$wifi_iface driver=nl80211 ssid=${ssid:-DietPi-Hotspot} country_code=00 hw_mode=$mode channel=$channel ieee80211n=$wifi4 ieee80211ac=$wifi5 wmm_enabled=$wmm_enabled macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_passphrase=$key wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP _EOF_ (( $G_DISTRO > 6 )) && G_CONFIG_INJECT 'ieee80211ax=' "ieee80211ax=$wifi6" /etc/hostapd/hostapd.conf '^ieee80211ac' G_EXEC chmod 0600 /etc/hostapd/hostapd.conf # Set WiFi country code /boot/dietpi/func/dietpi-set_hardware wificountrycode # Enable access point config G_EXEC eval 'echo '\''DAEMON_CONF="/etc/hostapd/hostapd.conf"'\'' > /etc/default/hostapd' Enable_IP_forwarding wifihotspot # Enable iptables NAT rules iptables -t nat -A POSTROUTING -s 192.168.42.0/24 -o "$eth_iface" -j MASQUERADE iptables -A FORWARD -i "$eth_iface" -o "$wifi_iface" -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i "$wifi_iface" -o "$eth_iface" -j ACCEPT ip6tables -t nat -A POSTROUTING -o "$eth_iface" -j MASQUERADE ip6tables -A FORWARD -i "$eth_iface" -o "$wifi_iface" -m state --state RELATED,ESTABLISHED -j ACCEPT ip6tables -A FORWARD -i "$wifi_iface" -o "$eth_iface" -j ACCEPT # Save iptables rules, applied via /etc/network/interfaces iptables-save > /etc/iptables.ipv4.nat ip6tables-save > /etc/iptables.ipv6.nat # Bring up interface now G_EXEC_NOHALT=1 G_EXEC ifup "$wifi_iface" fi if To_Install 61 tor # Tor Hotspot then G_AGI tor G_EXEC systemctl stop tor Remove_SysV tor 1 # Tor config cat << '_EOF_' > /etc/tor/torrc Log notice stdout VirtualAddrNetwork 10.192.0.0/10 AutomapHostsSuffixes .onion,.exit AutomapHostsOnResolve 1 TransPort 192.168.42.1:9040 DNSPort 192.168.42.1:53 _EOF_ # Flush iptables iptables -F iptables -t nat -F ip6tables -F ip6tables -t nat -F # Generate Tor prerouting tables local wifi_iface=$(G_GET_NET -t wlan iface) iptables -t nat -A PREROUTING -i "$wifi_iface" -p tcp --dport 22 -j REDIRECT --to-ports 22 iptables -t nat -A PREROUTING -i "$wifi_iface" -p udp --dport 53 -j REDIRECT --to-ports 53 iptables -t nat -A PREROUTING -i "$wifi_iface" -p tcp --syn -j REDIRECT --to-ports 9040 ip6tables -t nat -A PREROUTING -i "$wifi_iface" -p tcp --dport 22 -j REDIRECT --to-ports 22 ip6tables -t nat -A PREROUTING -i "$wifi_iface" -p udp --dport 53 -j REDIRECT --to-ports 53 ip6tables -t nat -A PREROUTING -i "$wifi_iface" -p tcp --syn -j REDIRECT --to-ports 9040 # Save iptables rules, applied via /etc/network/interfaces iptables-save > /etc/iptables.ipv4.nat ip6tables-save > /etc/iptables.ipv6.nat # User: Test tor is functional #https://check.torproject.org fi if To_Install 189 # VSCodium then # APT key local url='https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-vscodium.gpg --yes" # APT list G_EXEC eval 'echo '\''deb https://download.vscodium.com/debs vscodium main'\'' > /etc/apt/sources.list.d/dietpi-vscodium.list' G_AGUP # APT package # - gnome-keyring is the backend daemon for the Secrets API used to store credentials, required e.g. for the GitHub PR and issues extension. G_AGI codium gnome-keyring # Desktop shortcut Create_Desktop_Shortcut codium fi if To_Install 37 shairport-sync # Shairport Sync then # AirPlay 1 vs AirPlay 2 selection local airplay2=$(sed -n '/^[[:blank:]]*SOFTWARE_SHAIRPORT_SYNC_AIRPLAY=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $airplay2 == 2 ]] && G_WHIP_DEFAULT_ITEM='ok' if G_WHIP_BUTTON_OK_TEXT='AirPlay 2' G_WHIP_BUTTON_CANCEL_TEXT='AirPlay 1' G_WHIP_YESNO '[OPTION] AirPlay 2 support \nSince Shairport Sync v4.1, an experimental AirPlay 2 build is available:\n- https://github.com/mikebrady/shairport-sync/blob/master/AIRPLAY2.md \nIt causes higher CPU load, about 150 MiB additional disk space with dependencies, the NQPTP (Not Quite PTP) companion service, and not all source systems are supported (check out the above URL). \nYou can switch between AirPlay 1 and AirPlay 2 build any time later via reinstall:\n- dietpi-software reinstall 37 \nDo you want to install the AirPlay 2 ready Shairport Sync build?' then G_CONFIG_INJECT 'SOFTWARE_SHAIRPORT_SYNC_AIRPLAY=' 'SOFTWARE_SHAIRPORT_SYNC_AIRPLAY=2' /boot/dietpi.txt airplay2='-airplay2' else G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*SOFTWARE_SHAIRPORT_SYNC_AIRPLAY=/c\#SOFTWARE_SHAIRPORT_SYNC_AIRPLAY=2' /boot/dietpi.txt airplay2= fi G_AGI "shairport-sync$airplay2" fi if To_Install 48 # Pydio then # Install required PHP modules aDEPS=("php$PHP_VERSION-apcu" "php$PHP_VERSION-gd" "php$PHP_VERSION-intl" "php$PHP_VERSION-mbstring" "php$PHP_VERSION-opcache" "php$PHP_VERSION-xml") # Reinstall: Skip download and install, advice to use internal updater from web UI if [[ -d '/var/www/pydio' ]] then G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$software_id]} install dir \"/var/www/pydio\" already exists. Download and install steps will be skipped. - If you want to update ${aSOFTWARE_NAME[$software_id]}, please use the internal updater from web UI. - If you need to reinstall (e.g. broken instance), please manually backup your config files+data, remove the install dir and rerun \"dietpi-software (re)install $software_id\"." G_AGI "${aDEPS[@]}" aDEPS=() else Download_Install 'https://download.pydio.com/pub/core/ci/pydio-latest.tar.gz' G_EXEC mv pydio-latest /var/www/pydio fi # PHP configuration G_EXEC phpenmod apcu gd intl pdo_mysql dom mbstring xml # Webserver config # - Apache if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )) then # Enable Apache rewrite engine a2enmod rewrite # Move Pydio Apache config in place dps_index=$software_id Download_Install 'apache.pydio.conf' /etc/apache2/sites-available/dietpi-pydio.conf a2ensite dietpi-pydio # - Lighttpd elif (( ${aSOFTWARE_INSTALL_STATE[84]} > 0 )) then # Enable Lighttpd setenv, access and rewrite modules G_CONFIG_INJECT '"mod_access",' ' "mod_access",' /etc/lighttpd/lighttpd.conf '"mod_.+",' [[ -f '/etc/lighttpd/conf-enabled/05-setenv.conf' ]] || G_EXEC lighty-enable-mod setenv # Move Pydio Lighttpd config in place dps_index=$software_id Download_Install 'lighttpd.pydio.conf' /etc/lighttpd/conf-available/99-dietpi-pydio.conf G_EXEC_POST_FUNC(){ [[ $exit_code == 2 ]] && exit_code=0; } # Do not fail if modules are enabled already G_EXEC lighty-enable-mod rewrite dietpi-pydio # - Nginx elif (( ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then # Move Pydio Nginx config in place dps_index=$software_id Download_Install 'nginx.pydio.conf' /etc/nginx/sites-dietpi/dietpi-pydio.conf fi # Database /boot/dietpi/func/create_mysql_db pydio pydio "$GLOBAL_PW" # Setup data directory local data_dir='/mnt/dietpi_userdata/pydio_data' # - Skip if already existent if [[ -d $data_dir ]] then G_DIETPI-NOTIFY 2 "Existing $data_dir found, will migrate..." [[ -e '/var/www/pydio/data' ]] && G_EXEC rm -R /var/www/pydio/data else # Move data structure [[ -e $data_dir || -L $data_dir ]] && G_EXEC rm -R "$data_dir" if [[ -d '/var/www/pydio/data' ]] then G_EXEC mv /var/www/pydio/data "$data_dir" else G_EXEC mkdir "$data_dir" fi fi # - Create symlink G_EXEC ln -sf "$data_dir" /var/www/pydio/data # Permissions: Fix some files being 444 mode, breaking internal updater G_EXEC chown -R www-data:www-data /var/www/pydio "$data_dir" G_EXEC chmod -R u+w /var/www/pydio fi if To_Install 36 squeezelite # Squeezelite then G_AGI squeezelite G_EXEC systemctl stop squeezelite fi if To_Install 66 rpimonitor # RPi-Monitor then Download_Install 'https://raw.githubusercontent.com/XavierBerger/RPi-Monitor-deb/develop/packages/rpimonitor_2.13-beta6_all.deb' G_EXEC systemctl stop rpimonitor # Update APT package status G_EXEC /usr/share/rpimonitor/scripts/updatePackagesStatus.pl # Fix issue to display CPU temperature correctly: https://github.com/XavierBerger/RPi-Monitor/issues/374 # shellcheck disable=SC2016 G_CONFIG_INJECT 'dynamic.1.postprocess=' 'dynamic.1.postprocess=int($1/10 + 0.5)/100' /etc/rpimonitor/template/temperature.conf # USB drive stats implementation by Rich if [[ $G_ROOTFS_DEV != '/dev/sda1' && ! -f '/etc/rpimonitor/template/usb_hdd.conf' ]] && findmnt -S /dev/sda1 > /dev/null then cat << '_EOF_' > /etc/rpimonitor/template/usb_hdd.conf ######################################################################## # Extract USB HDD (sda1) information # Page: 1 # Information Status Statistics # - USBHDD1 total - yes - yes # - USBHDD1 used - yes - yes ######################################################################## static.10.name=usbhdd_total static.10.source=df -m static.10.regexp=^/dev/sda1\s+(\d+) dynamic.14.name=usbhdd_used dynamic.14.source=df -m dynamic.14.regexp=^/dev/sda1\s+\d+\s+(\d+) dynamic.14.rrd=GAUGE web.status.1.content.9.name=USB HDD web.status.1.content.9.icon=usb_hdd.png web.status.1.content.9.line.1="/sda1 Used: "+KMG(data.usbhdd_used,'M')+" ("+Percent(data.usbhdd_used,data.usbhdd_total,'M')+") Free: "+KMG(data.usbhdd_total-data.usbhdd_used,'M')+ " Total: "+ KMG(data.usbhdd_total,'M') +"" web.status.1.content.9.line.2=ProgressBar(data.usbhdd_used,data.usbhdd_total) web.statistics.1.content.9.name=USB HDD web.statistics.1.content.9.graph.1=usbhdd_total web.statistics.1.content.9.graph.2=usbhdd_used web.statistics.1.content.9.ds_graph_options.usbhdd_total.label=USB HDD total space (MiB) web.statistics.1.content.9.ds_graph_options.usbhdd_total.color="#FF7777" web.statistics.1.content.9.ds_graph_options.usbhdd_used.label=USB HDD used space (MiB) web.statistics.1.content.9.ds_graph_options.usbhdd_used.lines={ fill: true } web.statistics.1.content.9.ds_graph_options.usbhdd_used.color="#7777FF" _EOF_ G_EXEC sed --follow-symlinks -i '\|include=/etc/rpimonitor/template/sdcard.conf|a\include=/etc/rpimonitor/template/usb_hdd.conf' /etc/rpimonitor/data.conf fi fi if To_Install 65 netdata # Netdata then G_AGI netdata G_EXEC systemctl stop netdata fi if To_Install 57 # Baïkal then # APT deps: https://github.com/sabre-io/Baikal/wiki/Baïkal-dependencies aDEPS=("php$PHP_VERSION-xml" "php$PHP_VERSION-mbstring" "php$PHP_VERSION-mysql") # Bullseye: v0.10 dropped support for PHP 7.4: https://github.com/MichaIng/DietPi/issues/7387 if (( $G_DISTRO < 7 )) then Download_Install 'https://github.com/sabre-io/Baikal/releases/download/0.9.5/baikal-0.9.5.zip' else local fallback_url='https://github.com/sabre-io/Baikal/releases/download/0.10.1/baikal-0.10.1.zip' Download_Install "$(curl -sSfL 'https://api.github.com/repos/sabre-io/Baikal/releases/latest' | mawk -F\" '/^ *"browser_download_url": ".*\/baikal-[^"\/]*\.zip"$/{print $4}')" fi # Reinstall: https://sabre.io/baikal/upgrade/ if [[ -d '/var/www/baikal' ]] then [[ -d '/var/www/baikal/Specific' ]] && G_EXEC cp -a /var/www/baikal/Specific/. baikal/Specific/ [[ -d '/var/www/baikal/config' ]] && G_EXEC cp -a /var/www/baikal/config/. baikal/config/ G_EXEC rm -R /var/www/baikal fi G_EXEC mv baikal /var/www/baikal # Enable required PHP modules: https://github.com/sabre-io/Baikal/wiki/Baïkal-dependencies G_EXEC phpenmod xml mbstring pdo_mysql # Database /boot/dietpi/func/create_mysql_db baikal baikal "$GLOBAL_PW" # Web server configs: http://sabre.io/baikal/install/ + https://github.com/bambocher/docker-baikal/blob/master/lighttpd.conf # - Apache if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )) then dps_index=$software_id Download_Install 'apache.baikal.conf' /etc/apache2/sites-available/dietpi-baikal.conf a2ensite dietpi-baikal echo '# Redirect Cal/CardDAV requests to Baïkal endpoint: Redirect 301 /.well-known/carddav /baikal/html/dav.php Redirect 301 /.well-known/caldav /baikal/html/dav.php' > /etc/apache2/conf-available/dietpi-dav_redirect.conf a2enconf dietpi-dav_redirect # - Lighttpd elif (( ${aSOFTWARE_INSTALL_STATE[84]} > 0 )) then dps_index=$software_id Download_Install 'lighttpd.baikal.conf' /etc/lighttpd/conf-available/99-dietpi-baikal.conf echo '# Redirect Cal/CardDAV requests to Baïkal endpoint: url.redirect += ( "^/.well-known/caldav" => "/baikal/html/dav.php", "^/.well-known/carddav" => "/baikal/html/dav.php" )' > /etc/lighttpd/conf-available/99-dietpi-dav_redirect.conf G_EXEC_POST_FUNC(){ [[ $exit_code == 2 ]] && exit_code=0; } # Do not fail if modules are enabled already G_EXEC lighty-enable-mod dietpi-baikal dietpi-dav_redirect # - Nginx elif (( ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then dps_index=$software_id Download_Install 'nginx.baikal.conf' /etc/nginx/sites-dietpi/dietpi-baikal.conf # shellcheck disable=SC2016 echo '# Redirect Cal/CardDAV requests to Baïkal endpoint: location = /.well-known/carddav { return 301 /baikal/html/dav.php; } location = /.well-known/caldav { return 301 /baikal/html/dav.php; }' > /etc/nginx/sites-dietpi/dietpi-dav_redirect.conf fi # Permissions G_EXEC chown -R www-data:root /var/www/baikal/{Specific,config} G_EXEC find /var/www/baikal/{Specific,config} \( -name '.ht*' -o -name '.git*' \) -exec chown root {} + fi if To_Install 43 mumble-server # Mumble Server then G_AGI mumble-server G_EXEC systemctl stop mumble-server # Trixie: config moved to sub dir and murmurd was renamed to mumble-server local conf='/etc/mumble-server.ini' cli='murmurd' (( $G_DISTRO > 7 )) && conf='/etc/mumble/mumble-server.ini' cli='mumble-server' # Cap total connections G_CONFIG_INJECT 'users=' "users=$(( $G_HW_CPU_CORES * 8 ))" "$conf" # Name the root channel G_CONFIG_INJECT 'registerName=' 'registerName=DietPi Mumble Server' "$conf" # Disable DB logging G_CONFIG_INJECT 'logdays=' 'logdays=-1' "$conf" # Set Superuser passwd: https://dietpi.com/forum/t/1371 "$cli" -ini "$conf" -supw "$GLOBAL_PW" fi if To_Install 41 emby-server # Emby then case $G_HW_ARCH in 2) local arch='armhf';; 3) local arch='arm64';; *) local arch='amd64';; esac local fallback_url="https://github.com/MediaBrowser/Emby.Releases/releases/download/4.8.11.0/emby-server-deb_4.8.11.0_$arch.deb" Download_Install "$(curl -sSfL 'https://api.github.com/repos/MediaBrowser/Emby.Releases/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/emby-server-deb_[^\"\/]*_$arch\.deb\"$/{print \$4}")" G_EXEC systemctl stop emby-server # User: The DEB package install overrides this, hence the method needs to be changed when using an APT repository! Create_User -g dietpi -G emby,video,render -d /var/lib/emby emby Download_Test_Media fi if To_Install 42 plexmediaserver # Plex Media Server then # APT key local url='https://downloads.plex.tv/plex-keys/PlexSign.key' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-plexmediaserver.gpg --yes" # APT list G_EXEC eval 'echo '\''deb https://downloads.plex.tv/repo/deb public main'\'' > /etc/apt/sources.list.d/plexmediaserver.list' G_AGUP # APT package G_AGI plexmediaserver G_EXEC systemctl stop plexmediaserver # User: Run service as "dietpi" group: https://github.com/MichaIng/DietPi/issues/350#issuecomment-423763518 Create_User -g dietpi -G plex,video,render -d /var/lib/plexmediaserver plex # - Unset explicit group in service file (applied by DEB package) as this may override supplementary group permissions G_EXEC mkdir -p /etc/systemd/system/plexmediaserver.service.d G_EXEC eval 'echo -e '\''[Service]\nGroup='\'' > /etc/systemd/system/plexmediaserver.service.d/dietpi-group.conf' # Unbound: Fix secure remote access: https://dietpi.com/forum/t/cant-connect-to-plex-directly-due-to-unbound/5199 (( ${aSOFTWARE_INSTALL_STATE[182]} == 2 )) && G_EXEC eval 'echo -e '\''server:\n\tprivate-domain: "plex.direct"'\'' > /etc/unbound/unbound.conf.d/dietpi-plex.conf' Download_Test_Media fi if To_Install 52 cuberite # Cuberite then # https://github.com/cuberite/cuberite/blob/master/easyinstall.sh case $G_HW_ARCH in 3) local arch='aarch64';; 10) local arch='x86_64';; *) local arch='armhf-raspbian';; esac Download_Install "https://download.cuberite.org/linux-$arch/Cuberite.tar.gz" /mnt/dietpi_userdata/cuberite # User Create_User -d /mnt/dietpi_userdata/cuberite cuberite # Service cat << '_EOF_' > /etc/systemd/system/cuberite.service [Unit] Description=Cuberite (DietPi) Wants=network-online.target After=network-online.target [Service] User=cuberite WorkingDirectory=/mnt/dietpi_userdata/cuberite ExecStart=/mnt/dietpi_userdata/cuberite/Cuberite --detached [Install] WantedBy=multi-user.target _EOF_ # Web UI settings: Do not overwrite existing! [[ -f '/mnt/dietpi_userdata/cuberite/webadmin.ini' ]] || > /mnt/dietpi_userdata/cuberite/webadmin.ini G_EXEC chmod 0600 /mnt/dietpi_userdata/cuberite/webadmin.ini [[ -s '/mnt/dietpi_userdata/cuberite/webadmin.ini' ]] || cat << _EOF_ > /mnt/dietpi_userdata/cuberite/webadmin.ini [User:admin] Password=$GLOBAL_PW [WebAdmin] Ports=1339 Enabled=1 _EOF_ # Permissions G_EXEC chown -R cuberite:cuberite /mnt/dietpi_userdata/cuberite G_EXEC chmod +x /mnt/dietpi_userdata/cuberite/Cuberite fi if To_Install 53 mineos # MineOS then # https://wiki.codeemo.com/install/debian_10.html local url='https://github.com/hexparrot/mineos-node' G_CHECK_URL "$url" # APT deps G_AGI rdiff-backup rsync screen make g++ # Download/Update MineOS G_EXEC mkdir -p /mnt/dietpi_userdata/mineos G_EXEC cd /mnt/dietpi_userdata/mineos if [[ -d 'minecraft' ]] then # https://wiki.codeemo.com/maint/webui.html#updating-the-webui G_EXEC cd minecraft G_EXEC_OUTPUT=1 G_EXEC git pull origin master else G_EXEC_OUTPUT=1 G_EXEC git clone "$url" minecraft G_EXEC cd minecraft fi # File modes G_EXEC git config core.filemode false G_EXEC chmod +x mineos_console.js webui.js update_webui.sh reset_webui.sh generate-sslcert.sh # Bookworm: Workaround for failing userid 1.0.0-beta.9 build on weirdly Bookworm only. Latest stable 1.2.5 seems to work well: https://github.com/MichaIng/DietPi/issues/7265 G_CONFIG_INJECT '"userid"' ' "userid": "1.2.5",' package.json # Workaround: Node.js posix needs to be installed alone first: https://github.com/MichaIng/DietPi/issues/5181 G_EXEC_OUTPUT=1 G_EXEC npm i --no-audit --no-package-lock posix@latest # Install MineOS G_EXEC_OUTPUT=1 G_EXEC npm i --no-audit # Config: Preserve existing [[ -f '/etc/mineos.conf' ]] || G_EXEC cp mineos.conf /etc/mineos.conf # Create symlinks for console and userdata dir G_EXEC ln -sf /mnt/dietpi_userdata/mineos/minecraft/mineos_console.js /usr/local/bin/mineos G_EXEC mkdir -p /var/games ../serverdata G_EXEC rm -Rf /var/games/minecraft G_EXEC ln -s /mnt/dietpi_userdata/mineos/serverdata /var/games/minecraft # Setup SSL cert G_EXEC_OUTPUT=1 G_EXEC ./generate-sslcert.sh G_EXEC cd "$G_WORKING_DIR" # Service cat << '_EOF_' > /etc/systemd/system/mineos.service [Unit] Description=MineOS (DietPi) Wants=network-online.target After=network-online.target [Service] SyslogIdentifier=MineOS WorkingDirectory=/mnt/dietpi_userdata/mineos/minecraft Environment="SHELL=/bin/bash" "HOME=/root" ExecStart=/usr/local/bin/node webui.js KillMode=process [Install] WantedBy=multi-user.target _EOF_ # User and permissions local new_user=0 getent passwd mineos &> /dev/null || new_user=1 Create_User -d /mnt/dietpi_userdata/mineos/serverdata -p "$GLOBAL_PW" mineos G_EXEC chown -R mineos /mnt/dietpi_userdata/mineos/serverdata # - Assure SHA512 password hash algorithm, as MineOS does not support yescrypt, default since Bullseye: https://github.com/hexparrot/mineos-node/issues/441 (( $new_user )) && G_EXEC eval "chpasswd --crypt-method SHA512 <<< 'mineos:$GLOBAL_PW'" fi if To_Install 46 qbittorrent # qBittorrent then G_AGI qbittorrent-nox # User Create_User -g dietpi -d /home/qbittorrent qbittorrent # Config: Create only on fresh install if [[ ! -f '/home/qbittorrent/.config/qBittorrent/qBittorrent.conf' ]]; then G_EXEC mkdir -p /home/qbittorrent/.config/qBittorrent cat << _EOF_ > /home/qbittorrent/.config/qBittorrent/qBittorrent.conf [General] ported_to_new_savepath_system=true [Application] FileLogger\Enabled=true FileLogger\Path=/var/log/qbittorrent [AutoRun] enabled=false [LegalNotice] Accepted=true [Preferences] Advanced\AnonymousMode=false Advanced\IncludeOverhead=false Bittorrent\DHT=true Bittorrent\DHTPort=6881 Bittorrent\Encryption=1 Bittorrent\LSD=true Bittorrent\MaxConnecs=$(Optimise_BitTorrent 2) Bittorrent\MaxConnecsPerTorrent=$(Optimise_BitTorrent 2) Bittorrent\MaxUploads=$(Optimise_BitTorrent 3) Bittorrent\MaxUploadsPerTorrent=$(Optimise_BitTorrent 3) Bittorrent\PeX=true Bittorrent\sameDHTPortAsBT=true Bittorrent\uTP=true Bittorrent\uTP_rate_limited=false Connection\GlobalDLLimit=-1 Connection\GlobalDLLimitAlt=10 Connection\GlobalUPLimit=-1 Connection\GlobalUPLimitAlt=10 Connection\PortRangeMin=6881 Connection\Proxy\Authentication=false Connection\ProxyPeerConnections=false Connection\ResolvePeerCountries=false Connection\UPnP=true Downloads\DiskWriteCacheSize=$(Optimise_BitTorrent 0) Downloads\DiskWriteCacheTTL=60 Downloads\PreAllocation=false Downloads\SavePath=/mnt/dietpi_userdata/downloads Downloads\TempPath=/mnt/dietpi_userdata/downloads Downloads\TempPathEnabled=false Downloads\UseIncompleteExtension=false DynDNS\Enabled=false General\Locale=en IPFilter\Enabled=false MailNotification\enabled=false Queueing\IgnoreSlowTorrents=false Queueing\MaxActiveDownloads=$(Optimise_BitTorrent 1) Queueing\MaxActiveTorrents=$(Optimise_BitTorrent 1) Queueing\MaxActiveUploads=1 Queueing\QueueingEnabled=false Scheduler\Enabled=false WebUI\CSRFProtection=true WebUI\ClickjackingProtection=true WebUI\Enabled=true WebUI\HTTPS\Enabled=false WebUI\HostHeaderValidation=false WebUI\LocalHostAuth=true WebUI\Password_PBKDF2="@ByteArray(tpgNK76AcpP14rjOZP9vwg==:rQNtOB0P4HfNj20pJtxiTBi9miduS6L1Xqqazc4Y6Gpm3Rn02jMXnPPT3KH2JMDKhFQjAaTGVJz0dz5JVw2QUQ==)" WebUI\Port=1340 WebUI\SecureCookie=true WebUI\UseUPnP=true WebUI\Username=qbittorrent _EOF_ fi # Service cat << '_EOF_' > /etc/systemd/system/qbittorrent.service [Unit] Description=qBittorrent (DietPi) Documentation=man:qbittorrent-nox(1) Wants=network-online.target After=network-online.target remote-fs.target [Service] User=qbittorrent UMask=002 LogsDirectory=qbittorrent ExecStart=/usr/bin/qbittorrent-nox [Install] WantedBy=multi-user.target _EOF_ # Permissions G_EXEC chown -R qbittorrent:root /home/qbittorrent fi if To_Install 107 rtorrent # rTorrent then aDEPS=('rtorrent' 'mediainfo') # Install ruTorrent: Web UI for rTorrent # - Grab current version local version=$(curl -sSfL 'https://api.github.com/repos/Novik/ruTorrent/releases/latest' | mawk -F\" '/^ *"tag_name": "[^"]*",$/{print $4}') [[ $version ]] || { version='v5.2.10'; G_DIETPI-NOTIFY 1 "Automatic latest ruTorrent version detection failed. Version \"$version\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } [[ $version == 'v5.'* ]] || version='v5.2.10' Download_Install "https://github.com/Novik/ruTorrent/archive/$version.tar.gz" # - Reinstall freshly with preserved configs and 3rd party plugins if [[ -d '/var/www/rutorrent' ]] then # If old configs exist, preserve them and make new config files examples [[ -f '/var/www/rutorrent/conf/config.php' ]] && { G_EXEC mv "ruTorrent-${version#v}/conf/config.php"{,.example}; G_EXEC cp -a {/var/www/rutorrent,"ruTorrent-${version#v}"}/conf/config.php; } [[ -f '/var/www/rutorrent/conf/access.ini' ]] && { G_EXEC mv "ruTorrent-${version#v}/conf/access.ini"{,.example}; G_EXEC cp -a {/var/www/rutorrent,"ruTorrent-${version#v}"}/conf/access.ini; } [[ -f '/var/www/rutorrent/conf/plugins.ini' ]] && { G_EXEC mv "ruTorrent-${version#v}/conf/plugins.ini"{,.example}; G_EXEC cp -a {/var/www/rutorrent,"ruTorrent-${version#v}"}/conf/plugins.ini; } # Preserve 3rd party plugins for i in /var/www/rutorrent/plugins/{,.??,.[^.]}* do [[ -e $i ]] || continue [[ -e ruTorrent-${version#v}/plugins/${i#/var/www/rutorrent/plugins/} ]] && continue G_EXEC cp -a "$i" "ruTorrent-${version#v}/plugins/" done # Preserve 3rd party themes for i in /var/www/rutorrent/plugins/theme/themes/{,.??,.[^.]}* do [[ -e $i ]] || continue [[ -e ruTorrent-${version#v}/plugins/theme/themes/${i#/var/www/rutorrent/plugins/theme/themes/} ]] && continue G_EXEC cp -a "$i" "ruTorrent-${version#v}/plugins/theme/themes/" done # Reinstall freshly with preserved configs, 3rd party plugins and themes G_EXEC rm -R /var/www/rutorrent fi G_EXEC mv "ruTorrent-${version#v}" /var/www/rutorrent # Install DarkBetter theme manually: https://github.com/MichaIng/DietPi/issues/3271 if [[ -d '/var/www/rutorrent/plugins/theme/themes/DarkBetter' ]] then Download_Install 'https://github.com/chocolatkey/DarkBetter/archive/master.tar.gz' G_EXEC rm -R /var/www/rutorrent/plugins/theme/themes/DarkBetter G_EXEC mv DarkBetter-master /var/www/rutorrent/plugins/theme/themes/DarkBetter fi # ruTorrent: Enable HTTP authentication and RPC # - Apache if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )) then # Enable SCGI module G_EXEC a2enmod auth_basic authn_file authz_user proxy_scgi # Enable HTTP authentication and rTorrent access via SCGI [[ -f '/etc/.rutorrent-htaccess' ]] || htpasswd -cb /etc/.rutorrent-htaccess root "$GLOBAL_PW" cat << '_EOF_' > /etc/apache2/sites-available/dietpi-rutorrent.conf AllowOverride All AuthType Basic AuthName "ruTorrent login" AuthBasicProvider file AuthUserFile "/etc/.rutorrent-htaccess" Require valid-user AuthType Basic AuthName "rTorrent login" AuthBasicProvider file AuthUserFile "/etc/.rutorrent-htaccess" Require valid-user ProxyPass "/RPC2" "unix:/mnt/dietpi_userdata/downloads/.session/rpc.socket|scgi://127.0.0.1" _EOF_ G_EXEC a2ensite dietpi-rutorrent # - Lighttpd elif (( ${aSOFTWARE_INSTALL_STATE[84]} > 0 )) then [[ -f '/etc/.rutorrent-htaccess' ]] || echo "root:rtorrent:$(echo -n "root:rtorrent:$GLOBAL_PW" | md5sum | mawk '{print $1}')" > /etc/.rutorrent-htaccess # Pre-v7.2: Remove obsolete entries from /etc/lighttpd/lighttpd.conf grep -q '^#RUTORRENT_DIETPI' /etc/lighttpd/lighttpd.conf && G_EXEC sed --follow-symlinks -i '/#RUTORRENT_DIETPI/,/#RUTORRENT_DIETPI/d' /etc/lighttpd/lighttpd.conf cat << '_EOF_' > /etc/lighttpd/conf-available/98-dietpi-rtorrent.conf server.modules += ( "mod_auth", "mod_authn_file", "mod_scgi" ) auth.backend = "htdigest" auth.backend.htdigest.userfile = "/etc/.rutorrent-htaccess" auth.require = ( "/rutorrent" => ( "method" => "digest", "realm" => "rtorrent", "require" => "valid-user" ), "/RPC2" => ( "method" => "digest", "realm" => "rtorrent", "require" => "valid-user" ) ) scgi.server = ( "/RPC2" => ( "rtorrent" => ( "socket" => "/mnt/dietpi_userdata/downloads/.session/rpc.socket", "check-local" => "disable" ) ) ) $HTTP["url"] =~ "^/rutorrent/(conf|share)($|/)" { url.access-deny = ("") } _EOF_ [[ -f '/etc/lighttpd/conf-enabled/98-dietpi-rtorrent.conf' ]] || G_EXEC lighty-enable-mod dietpi-rtorrent # - Nginx elif (( ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then # "openssl passwd -5" (sha256, even "-6" sha512) can be used from Buster on. [[ -f '/etc/.rutorrent-htaccess' ]] || echo "root:$(openssl passwd -apr1 "$GLOBAL_PW")" > /etc/.rutorrent-htaccess cat << '_EOF_' > /etc/nginx/sites-dietpi/dietpi-rutorrent.conf location ^~ /rutorrent { auth_basic "ruTorrent login"; auth_basic_user_file /etc/.rutorrent-htaccess; location ~ ^/rutorrent/(?:conf|share)(?:/|$) { return 404; } location ~ \.php(?:$|/) { include snippets/fastcgi-php.conf; fastcgi_pass php; } } location ^~ /RPC2 { auth_basic "rTorrent login"; auth_basic_user_file /etc/.rutorrent-htaccess; include scgi_params; scgi_pass unix:/mnt/dietpi_userdata/downloads/.session/rpc.socket; } _EOF_ fi G_EXEC chmod 0400 /etc/.rutorrent-htaccess G_EXEC chown www-data:www-data /etc/.rutorrent-htaccess # ruTorrent config # shellcheck disable=SC2016 G_CONFIG_INJECT '\$scgi_port[[:blank:]]' ' $scgi_port = 0;' /var/www/rutorrent/conf/config.php # shellcheck disable=SC2016 G_CONFIG_INJECT '\$scgi_host[[:blank:]]' ' $scgi_host = "unix:///mnt/dietpi_userdata/downloads/.session/rpc.socket";' /var/www/rutorrent/conf/config.php G_CONFIG_INJECT '"curl"[[:blank:]]' ' "curl" => "/usr/bin/curl",' /var/www/rutorrent/conf/config.php # Session dir G_EXEC mkdir -p /mnt/dietpi_userdata/downloads/.session # User Create_User -g dietpi -d /mnt/dietpi_userdata/rtorrent rtorrent # Service cat << _EOF_ > /etc/systemd/system/rtorrent.service [Unit] Description=rTorrent (DietPi) Wants=network-online.target After=network-online.target remote-fs.target [Service] User=rtorrent ExecStart=$(command -v rtorrent) [Install] WantedBy=multi-user.target _EOF_ # rTorrent config: Do not overwrite if existent # - Example: https://github.com/rakshasa/rtorrent/blob/master/doc/rtorrent.rc # - Deprecated commands: # https://github.com/rakshasa/rtorrent/wiki/rTorrent-0.9-Comprehensive-Command-list-(WIP) # https://github.com/rakshasa/rtorrent/blob/master/doc/scripts/update_commands_0.9.sed G_EXEC mkdir -p /mnt/dietpi_userdata/rtorrent if [[ -f '/mnt/dietpi_userdata/rtorrent/.rtorrent.rc' ]] then # In case dist-upgraded systems, assure that daemon mode is enabled G_CONFIG_INJECT 'system.daemon.set[[:blank:]=]' 'system.daemon.set = true' /mnt/dietpi_userdata/rtorrent/.rtorrent.rc # Reinstall: Assure that rpi.socket is used, else ruTorrent connection would fail G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*network.scgi.open_port[[:blank:]=]/d' /mnt/dietpi_userdata/rtorrent/.rtorrent.rc G_CONFIG_INJECT 'network.scgi.open_local[[:blank:]=]' 'network.scgi.open_local = /mnt/dietpi_userdata/downloads/.session/rpc.socket' /mnt/dietpi_userdata/rtorrent/.rtorrent.rc G_CONFIG_INJECT 'execute.nothrow[[:blank:]]*=[[:blank:]]*chmod,666,/mnt/dietpi_userdata/downloads/.session/rpc.socket' 'execute.nothrow = chmod,666,/mnt/dietpi_userdata/downloads/.session/rpc.socket' /mnt/dietpi_userdata/rtorrent/.rtorrent.rc 'network.scgi.open_local[[:blank:]=]' else cat << _EOF_ > /mnt/dietpi_userdata/rtorrent/.rtorrent.rc ### Miscellaneous settings system.daemon.set = true # Default download dir directory.default.set = /mnt/dietpi_userdata/downloads # Session dir session.path.set = /mnt/dietpi_userdata/downloads/.session # Save session every 5 minutes schedule2 = session_save, 240, 300, ((session.save)) # Close torrents on low diskspace, check every minute schedule2 = monitor_diskspace, 15, 60, ((close_low_diskspace, 1000M)) system.umask.set = 002 # Max memory mapping size, not max physical RAM usage! pieces.memory.max.set = ${RAM_PHYS}M pieces.hash.on_completion.set = no ### Connection settings # Incoming connection ports network.port_open.set = yes network.port_random.set = no network.port_range.set = 49164-49164 # SCGI connection, e.g. for ruTorrent web UI network.scgi.open_local = /mnt/dietpi_userdata/downloads/.session/rpc.socket execute.nothrow = chmod,666,/mnt/dietpi_userdata/downloads/.session/rpc.socket ### Network limits network.http.max_open.set = $(Optimise_BitTorrent 2) network.max_open_files.set = $(( $(Optimise_BitTorrent 2) * 2 )) network.max_open_sockets.set = $(Optimise_BitTorrent 2) # Global max download/upload rate in KiB, "0" for unlimited throttle.global_down.max_rate.set_kb = 0 throttle.global_up.max_rate.set_kb = 0 ### Peer settings # Max downloads/uploads accross all torrents throttle.max_downloads.global.set = $(Optimise_BitTorrent 2) throttle.max_uploads.global.set = $(Optimise_BitTorrent 2) # Max downloads/uploads per torrent throttle.max_downloads.set = $(( $(Optimise_BitTorrent 2) / 2 )) throttle.max_uploads.set = $(( $(Optimise_BitTorrent 2) / 2 )) # Min/Max connected peers throttle.min_peers.normal.set = $(( $(Optimise_BitTorrent 2) - 1)) throttle.max_peers.normal.set = $(Optimise_BitTorrent 2) throttle.min_peers.seed.set = -1 throttle.max_peers.seed.set = -1 trackers.numwant.set = $(Optimise_BitTorrent 2) # Public tracker support trackers.use_udp.set = yes dht.mode.set = on #dht.port.set = 6881 protocol.pex.set = yes protocol.encryption.set = allow_incoming,try_outgoing,enable_retry _EOF_ fi # Permissions G_EXEC chown -R rtorrent:root /mnt/dietpi_userdata/rtorrent /mnt/dietpi_userdata/downloads/.session # - ruTorrent: https://github.com/Novik/ruTorrent/wiki/Config G_EXEC chown -R www-data:root /var/www/rutorrent/share G_EXEC chown root:root /var/www/rutorrent/share/.htaccess fi if To_Install 132 aria2 # Aria2 then G_AGI aria2 # Web UI: Settings are stored client-wise, web UI files are never written by webserver. Thus root:root 022 permissions existing dir removal on reinstall can be done. Download_Install 'https://github.com/ziahamza/webui-aria2/archive/master.tar.gz' [[ -d '/var/www/aria2' ]] && G_EXEC rm -R /var/www/aria2 G_EXEC mv webui-aria2-master /var/www/aria2 # User Create_User -g dietpi -d /mnt/dietpi_userdata/aria2 aria2 # Config G_EXEC mkdir -p /mnt/dietpi_userdata/aria2 [[ -f '/mnt/dietpi_userdata/aria2/aria2.conf' ]] || cat << _EOF_ > /mnt/dietpi_userdata/aria2/aria2.conf # DietPi default aria2c options served as aria2.conf file via --conf-path # https://aria2.github.io/manual/en/html/aria2c.html#options # Logging log=/var/log/aria2.log log-level=warn # Session always-resume=true continue=true input-file=/mnt/dietpi_userdata/downloads/aria2.session save-session=/mnt/dietpi_userdata/downloads/aria2.session save-session-interval=60 # Connection listen-port=6881-6999 ftp-pasv=true check-certificate=false # - Count max-concurrent-downloads=$(Optimise_BitTorrent 1) split=$(Optimise_BitTorrent 1) max-connection-per-server=$(Optimise_BitTorrent 1) bt-max-peers=$(Optimise_BitTorrent 2) # - Bandwidth max-overall-upload-limit=0 max-upload-limit=0 max-overall-download-limit=0 max-download-limit=0 # - Retries max-file-not-found=3 max-tries=5 retry-wait=60 # RPC enable-rpc=true rpc-listen-all=true rpc-listen-port=6800 rpc-secret=$GLOBAL_PW rpc-allow-origin-all=true pause=false # Store dir=/mnt/dietpi_userdata/downloads allow-overwrite=false auto-file-renaming=false file-allocation=none check-integrity=true # Seeding seed-ratio=0.1 seed-time=0 _EOF_ # Pre-create log file local fp_log=$(sed -n '/^[[:blank:]]*log=/{s/^[^=]*=//p;q}' /mnt/dietpi_userdata/aria2/aria2.conf) [[ ${fp_log//\"} && ! -f $fp_log ]] && >> "$fp_log" # Pre-create input file local fp_input=$(sed -n '/^[[:blank:]]*input-file=/{s/^[^=]*=//p;q}' /mnt/dietpi_userdata/aria2/aria2.conf) [[ ${fp_input//\"} && ! -f $fp_input ]] && >> "$fp_input" # Permissions G_EXEC chown -R aria2:root /mnt/dietpi_userdata/aria2 "$fp_input" G_EXEC chown aria2:dietpi "$fp_log" G_EXEC chmod 600 /mnt/dietpi_userdata/aria2/aria2.conf unset -v fp_log fp_input # Service cat << _EOF_ > /etc/systemd/system/aria2.service [Unit] Description=Aria2 (DietPi) Wants=network-online.target After=network-online.target remote-fs.target [Service] User=aria2 UMask=002 ExecStart=$(command -v aria2c) --conf-path=/mnt/dietpi_userdata/aria2/aria2.conf [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 116 medusa # Medusa then aDEPS=('mediainfo' 'python3') # Reinstall: Skip download and install, advice to use internal updater from web UI if [[ -d '/mnt/dietpi_userdata/medusa' ]] then G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$software_id]} install dir \"/mnt/dietpi_userdata/medusa\" already exists. Download and install steps will be skipped. - If you want to update ${aSOFTWARE_NAME[$software_id]}, please use the internal updater from web UI. - If you need to reinstall (e.g. broken instance), please manually backup your config files+data, remove the install dir and rerun \"dietpi-software (re)install $software_id\"." G_AGI "${aDEPS[@]}" aDEPS=() else Download_Install 'https://github.com/pymedusa/Medusa/archive/master.tar.gz' G_EXEC mv Medusa-master /mnt/dietpi_userdata/medusa fi # User Create_User -g dietpi -d /mnt/dietpi_userdata/medusa medusa # Service: https://github.com/pymedusa/Medusa/blob/master/runscripts/init.systemd G_EXEC cp /mnt/dietpi_userdata/medusa/runscripts/init.systemd /etc/systemd/system/medusa.service # - Prevent unlimited restarts on failure: Permit up to three restarts in 10 minutes G_CONFIG_INJECT 'StartLimitIntervalSec=' 'StartLimitIntervalSec=600' /etc/systemd/system/medusa.service '\[Unit\]' G_CONFIG_INJECT 'StartLimitBurst=' 'StartLimitBurst=3' /etc/systemd/system/medusa.service 'StartLimitIntervalSec=' # - Remove "Group=medusa" which does not exist, instead fallback to primary group "dietpi" G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*Group=/d' /etc/systemd/system/medusa.service # - Launch from our install and data directory G_CONFIG_INJECT 'ExecStart=' 'ExecStart=/usr/bin/python3 /mnt/dietpi_userdata/medusa/start.py -q --nolaunch --datadir=/mnt/dietpi_userdata/medusa' /etc/systemd/system/medusa.service # Permissions G_EXEC chown -R medusa:dietpi /mnt/dietpi_userdata/medusa fi if To_Install 50 syncthing # Syncthing then # Reinstall: Skip download and install, advice to use internal updater from web UI if [[ -d '/opt/syncthing' ]] then G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$software_id]} install dir \"/opt/syncthing\" already exists. Download and install steps will be skipped. - If you want to update ${aSOFTWARE_NAME[$software_id]}, please use the internal updater from web UI. - If you need to reinstall (e.g. broken instance), please manually remove the install dir and rerun \"dietpi-software (re)install $software_id\"." else case $G_HW_ARCH in 3) local arch='arm64';; 10) local arch='amd64';; 11) local arch='riscv64';; *) local arch='arm';; esac local fallback_url="https://github.com/syncthing/syncthing/releases/download/v2.0.9/syncthing-linux-$arch-v2.0.9.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/syncthing/syncthing/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/syncthing-linux-$arch-[^\"\/]*\.tar\.gz\"$/{print \$4}")" G_EXEC mv syncthing-* /opt/syncthing fi # User Create_User -g dietpi -d /mnt/dietpi_userdata/syncthing syncthing # Permit self-updates G_EXEC chown -R syncthing /opt/syncthing # Generate and edit config only on fresh installs if [[ ! -f '/mnt/dietpi_userdata/syncthing/config.xml' ]] then # Failsafe: Assure that "syncthing" (its "dietpi" group) has permission to create the /mnt/dietpi_userdata/syncthing directory G_EXEC chgrp dietpi /mnt/dietpi_userdata G_EXEC chmod 'g+rwx' /mnt/dietpi_userdata # Generate config G_EXEC_OUTPUT=1 G_EXEC runuser -u syncthing -- /opt/syncthing/syncthing generate --home=/mnt/dietpi_userdata/syncthing # Allow remote access: https://docs.syncthing.net/users/faq.html#how-do-i-access-the-web-gui-from-another-computer G_EXEC sed --follow-symlinks -i '\|:8384|c\
0.0.0.0:8384
' /mnt/dietpi_userdata/syncthing/config.xml # Set default data directory G_EXEC mkdir -p /mnt/dietpi_userdata/syncthing_data G_EXEC chown -R syncthing: /mnt/dietpi_userdata/syncthing_data G_EXEC chmod 0775 /mnt/dietpi_userdata/syncthing_data if grep -q '' /mnt/dietpi_userdata/syncthing/config.xml '^ /etc/systemd/system/syncthing.service [Unit] Description=Syncthing (DietPi) Wants=network-online.target After=network-online.target StartLimitIntervalSec=60 StartLimitBurst=3 [Service] User=syncthing UMask=002 ExecStart=/opt/syncthing/syncthing --no-browser --no-restart --log-level=WARN --home=/mnt/dietpi_userdata/syncthing Restart=on-failure RestartSec=1 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 # Hardening ProtectSystem=full PrivateTmp=true SystemCallArchitectures=native MemoryDenyWriteExecute=true NoNewPrivileges=true [Install] WantedBy=multi-user.target _EOF_ # Increase fs watcher limit: https://docs.syncthing.net/users/faq.html#inotify-limits # - 8192 until Linux 5.11, 7x RAM size in MiB since Linux 5.11, up to 1048576 # Raise UDP buffer sizes: https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes if (( $G_HW_MODEL == 75 )) then (( $(sysctl -n fs.inotify.max_user_watches) >= 204800 && $(sysctl -n net.core.rmem_max) >= 7500000 && $(sysctl -n net.core.wmem_max) >= 7500000 )) || G_WHIP_MSG '[WARNING] Filesystem watcher and UDP buffer size limits might be too low \nSyncthing uses filesystem (inotify) watchers to detect changes in your folders. Depending on the amount of files, the kernel version and physical RAM size of the host system, the current limit might be too low for Syncthing to start all watchers. \nAdditionally, for HTTP3/QUIC connections, the bandwidth can be limited by UDP buffer sizes. \nBoth limits can only be raised on the host of this container. E.g. add the following lines to a new sysctl config file like /etc/sysctl.d/dietpi-syncthing.conf: fs.inotify.max_user_watches=204800 net.core.rmem_max=7500000 net.core.wmem_max=7500000 \nApply them without reboot like this: sudo sysctl -p /etc/sysctl.d/dietpi-syncthing.confs \nMore info: - https://docs.syncthing.net/users/faq.html#inotify-limits - https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Size' else G_EXEC eval 'echo -e '\''fs.inotify.max_user_watches=204800\nnet.core.rmem_max=7500000\nnet.core.wmem_max=7500000'\'' > /etc/sysctl.d/dietpi-syncthing.conf' G_EXEC sysctl -p /etc/sysctl.d/dietpi-syncthing.conf fi fi if To_Install 113 # Chromium then # libpam-systemd: Required for non-root users to start Chromium from console via "startx" if (( $G_HW_MODEL > 9 )) then G_AGI chromium libpam-systemd Create_Desktop_Shortcut chromium # RPi: Use RPi repo package including non-free FFmpeg codecs integration else # From Bookworm on, "chromium-browser" is a dummy package only if (( $G_DISTRO < 7 )) then G_AGI chromium-browser chromium-codecs-ffmpeg-extra libpam-systemd Create_Desktop_Shortcut chromium-browser else G_AGI chromium libpam-systemd Create_Desktop_Shortcut chromium fi # Enable KMS grep -Eq '^[[:blank:]]*dtoverlay=vc4-f?kms-v3d' /boot/config.txt || /boot/dietpi/func/dietpi-set_hardware rpi-opengl vc4-kms-v3d # Enable hardware codecs /boot/dietpi/func/dietpi-set_hardware rpi-codec 1 fi # Flags: Allow root (disable sandbox) and minimise CPU usage: https://peter.sh/experiments/chromium-command-line-switches/ G_EXEC eval "echo 'export CHROMIUM_FLAGS=\"\$CHROMIUM_FLAGS --no-sandbox --test-type --disable-smooth-scrolling --disable-low-res-tiling --enable-low-end-device-mode --num-raster-threads=$G_HW_CPU_CORES --disable-composited-antialiasing\"' > /etc/chromium.d/dietpi" # Autostart script for kiosk mode, based on @AYapejian: https://github.com/MichaIng/DietPi/issues/1737#issue-318697621 G_EXEC mkdir -p /var/lib/dietpi/dietpi-software/installed cat << '_EOF_' > /var/lib/dietpi/dietpi-software/installed/chromium-autostart.sh #!/bin/dash # Autostart script for kiosk mode, based on @AYapejian: https://github.com/MichaIng/DietPi/issues/1737#issue-318697621 # Resolution to use for kiosk mode, should ideally match current system resolution RES_X=$(sed -n '/^[[:blank:]]*SOFTWARE_CHROMIUM_RES_X=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) RES_Y=$(sed -n '/^[[:blank:]]*SOFTWARE_CHROMIUM_RES_Y=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) # Command line switches: https://peter.sh/experiments/chromium-command-line-switches/ # - Review and add custom flags in: /etc/chromium.d CHROMIUM_OPTS="--kiosk --window-size=${RES_X:-1280},${RES_Y:-720} --window-position=0,0" # If you want tablet mode, uncomment the next line. #CHROMIUM_OPTS="$CHROMIUM_OPTS --force-tablet-mode --tablet-ui" # Home page URL=$(sed -n '/^[[:blank:]]*SOFTWARE_CHROMIUM_AUTOSTART_URL=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) # RPi or Debian Chromium package FP_CHROMIUM=$(command -v chromium-browser) [ "$FP_CHROMIUM" ] || FP_CHROMIUM=$(command -v chromium) # Use "startx" as non-root user to get required permissions via systemd-logind STARTX='xinit' [ "$USER" = 'root' ] || STARTX='startx' exec "$STARTX" "$FP_CHROMIUM" $CHROMIUM_OPTS "${URL:-https://dietpi.com/}" _EOF_ G_EXEC chmod +x /var/lib/dietpi/dietpi-software/installed/chromium-autostart.sh fi if To_Install 136 motioneye # motionEye then # Dependencies Python_Deps -i pillow pycurl # RPi: Enable camera module (( $G_HW_MODEL > 9 )) || /boot/dietpi/func/dietpi-set_hardware rpi-camera 1 # motionEye G_EXEC_OUTPUT=1 G_EXEC pip3 install -U --pre motioneye G_EXEC_OUTPUT=1 G_EXEC motioneye_init --skip-apt-update G_EXEC systemctl stop motioneye # Prevent the conflicting motion daemon from starting G_EXEC systemctl --no-reload disable --now motion G_EXEC systemctl --no-reload mask motion # Data directory G_EXEC mkdir -p /mnt/dietpi_userdata/motioneye G_EXEC chown -R motion /mnt/dietpi_userdata/motioneye G_CONFIG_INJECT 'media_path' 'media_path /mnt/dietpi_userdata/motioneye' /etc/motioneye/motioneye.conf fi if To_Install 137 mjpg-streamer # mjpg-streamer then # Build dependencies aDEPS=('make' 'cmake' 'gcc' 'libc6-dev' 'libjpeg62-turbo-dev') # - RPi Bullseye: Add RPi Camera support by default (( $G_HW_MODEL > 9 || $G_DISTRO > 6 )) || aDEPS+=('libraspberrypi-dev') # Download sources Download_Install 'https://github.com/jacksonliam/mjpg-streamer/archive/master.tar.gz' # Compile G_EXEC cd mjpg-streamer-master/mjpg-streamer-experimental G_EXEC_OUTPUT=1 G_EXEC make CFLAGS='-g0 -O3' -j "$(nproc)" G_EXEC strip --remove-section=.comment --remove-section=.note _build/mjpg_streamer # Move all plugin libraries into the executable's directory to avoid the need for LD_LIBRARY_PATH G_EXEC mv _build/plugins/*/*.so _build/ # Remove all left build files G_EXEC rm -R _build/{{,C,c}[Mm]ake*,plugins} # Install to system, in case remove previous installs [[ -d '/opt/mjpg-streamer' ]] && G_EXEC rm -R /opt/mjpg-streamer G_EXEC mv _build /opt/mjpg-streamer # Cleanup G_EXEC cd "$G_WORKING_DIR" G_EXEC rm -R mjpg-streamer-master # User Create_User -g video -d /opt/mjpg-streamer mjpg-streamer # Service # - RPi Bullseye: If the RPi legacy camera stack is enabled already, use it by default. local input='input_uvc.so -d /dev/video0' [[ $G_HW_MODEL -gt 9 || $G_DISTRO -gt 6 || -f '/etc/modprobe.d/dietpi-disable_rpi_camera.conf' ]] || input='input_raspicam.so' cat << _EOF_ > /etc/systemd/system/mjpg-streamer.service [Unit] Description=mjpg-streamer (DietPi) Documentation=https://github.com/jacksonliam/mjpg-streamer/tree/master/mjpg-streamer-experimental Wants=network-online.target After=network-online.target remote-fs.target [Service] User=mjpg-streamer WorkingDirectory=/opt/mjpg-streamer ExecStart=/opt/mjpg-streamer/mjpg_streamer -i '$input' -o 'output_http.so -p 8082 -n' # Hardening ProtectSystem=strict PrivateTmp=true ProtectHome=true ProtectKernelTunables=true ProtectControlGroups=true [Install] WantedBy=multi-user.target _EOF_ # OctoPrint: Configure it to use mjpg-streamer if installed if [[ ${aSOFTWARE_INSTALL_STATE[153]} == 2 && -f '/mnt/dietpi_userdata/octoprint/.octoprint/config.yaml' ]] then G_DIETPI-NOTIFY 2 'Configuring OctoPrint to use mjpg-streamer for webcam support' G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set webcam.stream "http://$(G_GET_NET ip):8082/?action=stream" G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set webcam.snapshot 'http://127.0.0.1:8082/?action=snapshot' G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set webcam.ffmpeg "$(command -v ffmpeg)" fi fi if To_Install 138 virtualhere # VirtualHere then case $G_HW_ARCH in 3) local arch='arm64';; 10) local arch='x86_64';; *) local arch='arm';; esac Download_Install "https://virtualhere.com/sites/default/files/usbserver/vhusbd$arch" /opt/virtualhere/vhusbd G_EXEC chmod +x /opt/virtualhere/vhusbd # Config if [[ ! -f '/opt/virtualhere/config.ini' ]] then if [[ -f '/etc/vhusbd/config.ini' ]] then G_EXEC mv /etc/vhusbd/config.ini /opt/virtualhere/config.ini else # shellcheck disable=SC2016 echo 'ServerName=$HOSTNAME$' > /opt/virtualhere/config.ini fi fi # Service cat << '_EOF_' > /etc/systemd/system/virtualhere.service [Unit] Description=VirtualHere (DietPi) Wants=network-online.target After=network-online.target [Service] ExecStart=/opt/virtualhere/vhusbd [Install] WantedBy=multi-user.target _EOF_ # Pre-v8.4 [[ -d '/etc/vhusbd' ]] && G_EXEC rm -R /etc/vhusbd [[ -f '/var/log/virtualhere.log' ]] && G_EXEC rm /var/log/virtualhere.log fi if To_Install 139 sabnzbd # SABnzbd: https://sabnzbd.org/wiki/installation/install-off-modules then # APT deps aDEPS=('par2') (( $G_DISTRO > 7 )) && aDEPS+=('7zip') || aDEPS+=('p7zip-full') Python_Deps cffi cryptography sabctools ujson Download_Install 'https://github.com/sabnzbd/sabnzbd/archive/master.tar.gz' # Reinstall: Remove old install dir if [[ -d '/etc/sabnzbd' ]] then # Preserve old config file [[ -f '/etc/sabnzbd/sabnzbd.ini' ]] && G_EXEC mv /etc/sabnzbd/sabnzbd.ini sabnzbd-master/sabnzbd.ini G_EXEC rm -R /etc/sabnzbd fi # Install G_EXEC mv sabnzbd-master /etc/sabnzbd # Python deps G_EXEC cd /etc/sabnzbd G_EXEC_OUTPUT=1 G_EXEC pip3 install -Ur requirements.txt # User Create_User -g dietpi -d /etc/sabnzbd sabnzbd # Permissions G_EXEC chown -R sabnzbd:root . # Service: https://github.com/sabnzbd/sabnzbd/blob/master/linux/sabnzbd%40.service # - Options: https://sabnzbd.org/wiki/advanced/command-line-parameters # "-OO": Optimise code and remove doc lines (default shebang of SABnzbd.py, but we run python3 explicitly to avoid version conflicts) # "-d": Run in daemon mode without terminal and browser start (requires "-f /path/to/config.ini") # NB: In systemd unit leads to unreliable long taking webserver start. A new process is forked which allows web access, but sometimes after very long time, sometimes never: https://github.com/sabnzbd/sabnzbd/issues/1283 # "-n": Do no start browser with daemon cat << '_EOF_' > /etc/systemd/system/sabnzbd.service [Unit] Description=SABnzbd (DietPi) Documentation=https://sabnzbd.org/wiki/ Wants=network-online.target After=network-online.target remote-fs.target StartLimitIntervalSec=60 StartLimitBurst=3 [Service] SyslogIdentifier=SABnzbd User=sabnzbd ExecStart=/usr/bin/python3 -OO /etc/sabnzbd/SABnzbd.py -f /etc/sabnzbd/sabnzbd.ini -n --disable-file-log Restart=on-failure [Install] WantedBy=multi-user.target _EOF_ # Config # - Touch only if it does not yet exist, assume reinstall otherwise and preserve custom changes # - API keys and initial config are only generated during 1st run # - We need to launch program, then apply our config tweaks, else, wizard setup in web interface simply loops without API keys. if [[ ! -f '/etc/sabnzbd/sabnzbd.ini' ]] && Create_Config /etc/sabnzbd/sabnzbd.ini sabnzbd then G_SLEEP 1 # Additional wait, config being overwritten after below changes: https://dietpi.com/forum/t/bug-sabnzbd/1224 G_CONFIG_INJECT 'log_level[[:blank:]]+=' 'log_level = 0' /etc/sabnzbd/sabnzbd.ini # Warnings and errors only G_CONFIG_INJECT 'auto_browser[[:blank:]]+=' 'auto_browser = 0' /etc/sabnzbd/sabnzbd.ini G_CONFIG_INJECT 'host[[:blank:]]+=' 'host = 0.0.0.0' /etc/sabnzbd/sabnzbd.ini G_CONFIG_INJECT 'admin_dir[[:blank:]]+=' 'admin_dir = /mnt/dietpi_userdata/downloads/sabnzbd_admin' /etc/sabnzbd/sabnzbd.ini G_CONFIG_INJECT 'download_dir[[:blank:]]+=' 'download_dir = /mnt/dietpi_userdata/downloads/incomplete' /etc/sabnzbd/sabnzbd.ini G_CONFIG_INJECT 'complete_dir[[:blank:]]+=' 'complete_dir = /mnt/dietpi_userdata/downloads/complete' /etc/sabnzbd/sabnzbd.ini G_CONFIG_INJECT 'nzb_backup_dir[[:blank:]]+=' 'nzb_backup_dir = /mnt/dietpi_userdata/downloads/sabnzbd_nzb_backup' /etc/sabnzbd/sabnzbd.ini G_CONFIG_INJECT 'permissions[[:blank:]]+=' 'permissions = 0775' /etc/sabnzbd/sabnzbd.ini G_CONFIG_INJECT 'refresh_rate[[:blank:]]+=' 'refresh_rate = 2' /etc/sabnzbd/sabnzbd.ini [[ -d '/mnt/dietpi_userdata/downloads/sabnzbd_admin' ]] && G_EXEC chown -R sabnzbd:root /mnt/dietpi_userdata/downloads/sabnzbd_admin [[ -d '/mnt/dietpi_userdata/downloads/sabnzbd_nzb_backup' ]] && G_EXEC chown -R sabnzbd:root /mnt/dietpi_userdata/downloads/sabnzbd_nzb_backup [[ -d '/mnt/dietpi_userdata/downloads/incomplete' ]] && G_EXEC chown -R sabnzbd:dietpi /mnt/dietpi_userdata/downloads/incomplete [[ -d '/mnt/dietpi_userdata/downloads/complete' ]] && G_EXEC chown -R sabnzbd:dietpi /mnt/dietpi_userdata/downloads/complete fi # Install language packs: https://github.com/MichaIng/DietPi/issues/1917#issue-340631943 G_EXEC python3 -OO tools/make_mo.py G_EXEC chown -R sabnzbd:root . G_EXEC cd "$G_WORKING_DIR" fi if To_Install 183 vaultwarden # vaultwarden then G_AGI vaultwarden G_EXEC systemctl stop vaultwarden fi if To_Install 193 k3s # K3s then # APT deps local disable_apparmor=1 systemctl -q is-active apparmor && disable_apparmor=0 G_AGI apparmor iptables (( $disable_apparmor )) && G_EXEC systemctl --no-reload disable --now apparmor Configure_iptables # Fetch config file if it exists if [[ -f '/boot/dietpi-k3s.yaml' && ! -f '/etc/rancher/k3s/config.yaml' ]] then G_EXEC mkdir -p '/etc/rancher/k3s' G_EXEC cp '/boot/dietpi-k3s.yaml' '/etc/rancher/k3s/config.yaml' fi # Install G_EXEC curl -sSfL 'https://get.k3s.io/' -o install.sh G_EXEC chmod +x install.sh export INSTALL_K3S_SKIP_ENABLE=true export INSTALL_K3S_EXEC=$(sed -n '/^[[:blank:]]*SOFTWARE_K3S_EXEC=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) if G_EXEC_NOEXIT=1 G_EXEC_OUTPUT=1 G_EXEC ./install.sh then # Do not enter into a server restart loop on failure G_EXEC mkdir -p /etc/systemd/system/k3s.service.d G_EXEC eval 'echo -e '\''[Service]\nRestart=on-success'\'' > /etc/systemd/system/k3s.service.d/dietpi.conf' Enable_memory_cgroup else aSOFTWARE_INSTALL_STATE[$software_id]=-1 fi G_EXEC rm install.sh fi if To_Install 142 # MicroK8s then # MicroK8s itself is a snap, hence snapd is needed G_AGI snapd # Update snapd itself, needed on older Debian to install core20 snap. Both are pulled by the MicroK8s snap anyway, but while older snapd runs, installing MicroK8s fails at core20 before snapd is updated. if snap list snapd &> /dev/null then G_EXEC_OUTPUT=1 G_EXEC snap refresh snapd else G_EXEC_OUTPUT=1 G_EXEC snap install snapd fi # Install or update microk8s snap if snap list microk8s &> /dev/null then G_EXEC_OUTPUT=1 G_EXEC snap refresh microk8s else G_EXEC_OUTPUT=1 G_EXEC snap install microk8s --classic fi Enable_memory_cgroup fi if To_Install 143 koel # Koel then # APT dependencies: https://docs.koel.dev/guide/getting-started > https://laravel.com/docs/11.x/deployment#server-requirements / https://laravel.com/docs/10.x/deployment#server-requirements / https://laravel.com/docs/8.x/deployment#server-requirements # - Skip JSON module from PHP 8.0 on, where it is embedded into core # - pdo_sqlite module required for "artisan koel:init" < "artisan db:seed", despite MySQL database engine used aDEPS=("php$PHP_VERSION-bcmath" "php$PHP_VERSION-mbstring" "php$PHP_VERSION-sqlite3" "php$PHP_VERSION-xml") # Grab latest supported release: Koel v6 requires PHP 8.0 or higher for Laravel 9 if (( ${PHP_VERSION::1} > 7 )) then aDEPS+=("php$PHP_VERSION-curl") local fallback_url='https://github.com/koel/koel/releases/download/v7.15.1/koel-v7.15.1.tar.gz' aphp_deps=('curl' 'dom') Download_Install "$(curl -sSfL 'https://api.github.com/repos/koel/koel/releases/latest' | mawk -F\" '/^ *"browser_download_url": ".*\/koel-[^"\/]*\.tar\.gz"$/{print $4}')" else aDEPS+=("php$PHP_VERSION-json") local aphp_deps=('json') Download_Install 'https://github.com/koel/koel/releases/download/v5.1.14/koel-v5.1.14.tar.gz' fi # Reinstall: Clear previous install, but keep existing config file if [[ -d '/mnt/dietpi_userdata/koel' ]] then [[ -f '/mnt/dietpi_userdata/koel/.env' ]] && G_EXEC mv /mnt/dietpi_userdata/koel/.env koel/ G_EXEC rm -R /mnt/dietpi_userdata/koel fi [[ -f 'koel/.env' ]] || G_EXEC cp koel/.env{.example,} G_EXEC mv koel /mnt/dietpi_userdata/koel # Enable required PHP modules G_EXEC phpenmod bcmath ctype fileinfo mbstring pdo_mysql pdo_sqlite tokenizer xml "${aphp_deps[@]}" # User Create_User -g dietpi -d /mnt/dietpi_userdata/koel koel # Permissions G_EXEC cd /mnt/dietpi_userdata/koel G_EXEC chmod 0600 .env G_EXEC chown -R koel:root . # Create database and apply to config file if it does not exist yet if [[ ! -d '/mnt/dietpi_userdata/mysql/koel' ]] then # Create random alphanumeric 30 characters password local password=$(tr -dc '[:alnum:]' < /dev/random | head -c30) /boot/dietpi/func/create_mysql_db koel koel "$password" GCI_PASSWORD=1 G_CONFIG_INJECT 'DB_PASSWORD=' "DB_PASSWORD=$password" .env unset -v password G_CONFIG_INJECT 'DB_CONNECTION=' 'DB_CONNECTION=mysql' .env G_CONFIG_INJECT 'DB_HOST=' 'DB_HOST=localhost' .env G_CONFIG_INJECT 'DB_DATABASE=' 'DB_DATABASE=koel' .env G_CONFIG_INJECT 'DB_USERNAME=' 'DB_USERNAME=koel' .env G_CONFIG_INJECT 'MEDIA_PATH=' 'MEDIA_PATH=/mnt/dietpi_userdata/Music' .env G_CONFIG_INJECT 'FFMPEG_PATH=' "FFMPEG_PATH=$(command -v ffmpeg)" .env # Else assure database server runs else G_EXEC systemctl restart mariadb fi Download_Test_Media # Init G_EXEC_OUTPUT=1 G_EXEC runuser -u koel -- "php$PHP_VERSION" artisan koel:init -n --no-assets G_EXEC_OUTPUT=1 G_EXEC runuser -u koel -- "php$PHP_VERSION" artisan koel:sync G_EXEC cd "$G_WORKING_DIR" # Service: Run on port 8003 by default to avoid conflict with Icecast cat << _EOF_ > /etc/systemd/system/koel.service [Unit] Description=Koel (DietPi) Documentation=https://docs.koel.dev/ Wants=network-online.target After=network-online.target mariadb.service [Service] SyslogIdentifier=Koel User=koel WorkingDirectory=/mnt/dietpi_userdata/koel ExecStart=$(command -v "php$PHP_VERSION") /mnt/dietpi_userdata/koel/artisan serve --host 0.0.0.0 --port 8003 [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 144 sonarr # Sonarr then # Sonarr v4 does not support ARMv6 if (( $G_HW_ARCH == 1 )) then # https://sonarr.tv/#downloads-v3-linux-debian # APT key G_EXEC eval 'curl -sSf '\''https://keyserver.ubuntu.com/pks/lookup?search=0x2009837CBFFD68F45BC180471F4F90DE2A9B4BF8&op=get'\'' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-sonarr.gpg --yes' # APT list: Buster is the latest available suite: https://apt.sonarr.tv/debian/dists/ G_EXEC eval 'echo '\''deb https://apt.sonarr.tv/debian buster main'\'' > /etc/apt/sources.list.d/sonarr.list' G_AGUP # Pre-configure DEB package G_EXEC eval "debconf-set-selections <<< 'sonarr sonarr/owning_group string dietpi'" G_EXEC eval "debconf-set-selections <<< 'sonarr sonarr/config_directory string /mnt/dietpi_userdata/sonarr'" # Install Sonarr and mediainfo G_AGI sonarr mediainfo G_EXEC systemctl stop sonarr local install_dir='/usr/lib/sonarr' local exe="$(command -v mono) $install_dir/bin/Sonarr.exe" else # Pre-v9.9 cleanup [[ -f '/etc/apt/sources.list.d/sonarr.list' ]] && G_EXEC rm /etc/apt/sources.list.d/sonarr.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-sonarr.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-sonarr.gpg if dpkg-query -s 'sonarr' &> /dev/null then [[ -d '/mnt/dietpi_userdata/sonarr' ]] && G_EXEC mv /mnt/dietpi_userdata/sonarr{,_bak} G_AGP sonarr [[ -d '/mnt/dietpi_userdata/sonarr_bak' ]] && G_EXEC mv /mnt/dietpi_userdata/sonarr{_bak,} # Offer to uninstall Mono if (( ${aSOFTWARE_INSTALL_STATE[150]} == 2 )) then G_WHIP_BUTTON_OK_TEXT='Yes' G_WHIP_BUTTON_CANCEL_TEXT='No' G_WHIP_DEFAULT_ITEM='Yes' G_WHIP_YESNO '[ INFO ] Mono is no dependency of Sonarr v4 anymore \nA migration from Sonarr v3 to Sonarr v4 is done, which does not require Mono anymore. If you do not need Mono for something else, it can hence be uninstalled to free up some space. \nDo you want to uninstall Mono now? It can be done any time later via "dietpi-software".' && aSOFTWARE_INSTALL_STATE[150]=-1 fi fi # APT dependencies aDEPS=('mediainfo') # - .NET: https://github.com/dotnet/docs/blob/main/docs/core/install/linux-debian.md#dependencies case $G_DISTRO in 6) aDEPS+=('libicu67');; 7) aDEPS+=('libicu72');; *) aDEPS+=('libicu76');; esac # Download case $G_HW_ARCH in 2) local arch='arm';; 3) local arch='arm64';; *) local arch='x64';; esac local fallback_url="https://github.com/Sonarr/Sonarr/releases/download/v4.0.15.2941/Sonarr.main.4.0.15.2941.linux-$arch.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/Sonarr/Sonarr/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*linux-$arch\.tar\.gz\"$/{print \$4}")" # Install: Remove previous instance on reinstall [[ -d '/opt/sonarr' ]] && G_EXEC rm -R /opt/sonarr G_EXEC mv Sonarr /opt/sonarr local install_dir='/opt/sonarr' local exe="$install_dir/Sonarr" fi # Pre-v7.1: Remove Sonarr v2 key, PID file and database backups from DietPi-Arr_to_RAM if [[ -f '/etc/apt/trusted.gpg' && $(apt-key --keyring /etc/apt/trusted.gpg list 'A236C58F409091A18ACA53CBEBFF6B99D9B78493' 2> /dev/null) ]] then G_EXEC apt-key --keyring /etc/apt/trusted.gpg del 'A236C58F409091A18ACA53CBEBFF6B99D9B78493' [[ $(apt-key --keyring /etc/apt/trusted.gpg list 2> /dev/null) ]] || G_EXEC rm /etc/apt/trusted.gpg fi [[ -f '/mnt/dietpi_userdata/sonarr/nzbdrone.pid' ]] && G_EXEC rm /mnt/dietpi_userdata/sonarr/nzbdrone.pid [[ -f '/mnt/dietpi_userdata/sonarr/nzbdrone.db.bak' ]] && G_EXEC rm /mnt/dietpi_userdata/sonarr/nzbdrone.db.bak # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/sonarr # User Create_User -g dietpi -d /mnt/dietpi_userdata/sonarr sonarr # Service: https://github.com/Sonarr/Sonarr/blob/phantom-develop/distribution/debian/sonarr.service cat << _EOF_ > /etc/systemd/system/sonarr.service [Unit] Description=Sonarr (DietPi) Wants=network-online.target After=network-online.target remote-fs.target transmission-daemon.service qbittorrent.service rtorrent.service nzbget.service deluged.service aria2.service sabnzbd.service StartLimitIntervalSec=60 StartLimitBurst=3 [Service] SyslogIdentifier=Sonarr User=sonarr UMask=002 LogsDirectory=sonarr ExecStart=$exe -nobrowser -data=/mnt/dietpi_userdata/sonarr TimeoutStopSec=20 KillMode=process Restart=on-failure # Hardening ProtectSystem=strict ProtectHome=true PrivateDevices=true ProtectKernelTunables=true ProtectControlGroups=true ReadWritePaths=-$install_dir -/mnt -/media -/var/log/sonarr -/tmp [Install] WantedBy=multi-user.target _EOF_ # Logs to RAM G_EXEC rm -Rf /mnt/dietpi_userdata/sonarr/logs* G_EXEC ln -s /var/log/sonarr /mnt/dietpi_userdata/sonarr/logs G_EXEC ln -s /var/log/sonarr/logs.db /mnt/dietpi_userdata/sonarr/logs.db G_EXEC ln -s /var/log/sonarr/logs.db-shm /mnt/dietpi_userdata/sonarr/logs.db-shm G_EXEC ln -s /var/log/sonarr/logs.db-wal /mnt/dietpi_userdata/sonarr/logs.db-wal # Permissions G_EXEC chown -R sonarr:dietpi /mnt/dietpi_userdata/sonarr "$install_dir" fi if To_Install 145 radarr # Radarr then # APT dependencies aDEPS=('mediainfo') # - .NET: https://github.com/dotnet/docs/blob/main/docs/core/install/linux-debian.md#dependencies if (( $G_HW_ARCH != 1 )) then case $G_DISTRO in 6) aDEPS+=('libicu67');; 7) aDEPS+=('libicu72');; *) aDEPS+=('libicu76');; esac fi # Download # - ARMv6: Radarr v4 does not support Mono anymore local url='https://github.com/Radarr/Radarr/releases/download/v3.2.2.5080/Radarr.master.3.2.2.5080.linux.tar.gz' if (( $G_HW_ARCH != 1 )) then case $G_HW_ARCH in 2) local arch='arm';; 3) local arch='arm64';; *) local arch='x64';; esac url=$(curl -sSfL 'https://api.github.com/repos/Radarr/Radarr/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*linux-core-$arch\.tar\.gz\"$/{print \$4}") local fallback_url="https://github.com/Radarr/Radarr/releases/download/v5.27.5.10198/Radarr.master.5.27.5.10198.linux-core-$arch.tar.gz" fi Download_Install "$url" # Install: Remove previous instance on reinstall [[ -d '/opt/radarr' ]] && G_EXEC rm -R /opt/radarr G_EXEC mv Radarr /opt/radarr # Radarr v2: Remove old PID file and database backups from DietPi-Arr_to_RAM [[ -f '/mnt/dietpi_userdata/radarr/nzbdrone.pid' ]] && G_EXEC rm /mnt/dietpi_userdata/radarr/nzbdrone.pid [[ -f '/mnt/dietpi_userdata/radarr/nzbdrone.db.bak' ]] && G_EXEC rm /mnt/dietpi_userdata/radarr/nzbdrone.db.bak # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/radarr # User Create_User -g dietpi -d /mnt/dietpi_userdata/radarr radarr # Service: https://github.com/Radarr/Radarr/wiki/Autostart-on-Linux#service-file cat << '_EOF_' > /etc/systemd/system/radarr.service [Unit] Description=Radarr (DietPi) Wants=network-online.target After=network-online.target remote-fs.target transmission-daemon.service qbittorrent.service rtorrent.service nzbget.service deluged.service aria2.service sabnzbd.service StartLimitIntervalSec=60 StartLimitBurst=3 [Service] SyslogIdentifier=Radarr User=radarr UMask=002 LogsDirectory=radarr ExecStart=/opt/radarr/Radarr -nobrowser -data=/mnt/dietpi_userdata/radarr TimeoutStopSec=20 KillMode=process Restart=on-failure # Hardening ProtectSystem=strict ProtectHome=true PrivateDevices=true ProtectKernelTunables=true ProtectControlGroups=true ReadWritePaths=-/opt/radarr -/mnt -/media -/var/log/radarr -/tmp [Install] WantedBy=multi-user.target _EOF_ # - ARMv6 devices use Mono (( $G_HW_ARCH == 1 )) && G_CONFIG_INJECT 'ExecStart=' "ExecStart=$(command -v mono) /opt/radarr/Radarr.exe -nobrowser -data=/mnt/dietpi_userdata/radarr" /etc/systemd/system/radarr.service # Logs to RAM G_EXEC rm -Rf /mnt/dietpi_userdata/radarr/logs* G_EXEC ln -s /var/log/radarr /mnt/dietpi_userdata/radarr/logs G_EXEC ln -s /var/log/radarr/logs.db /mnt/dietpi_userdata/radarr/logs.db G_EXEC ln -s /var/log/radarr/logs.db-shm /mnt/dietpi_userdata/radarr/logs.db-shm G_EXEC ln -s /var/log/radarr/logs.db-wal /mnt/dietpi_userdata/radarr/logs.db-wal # Permissions G_EXEC chown -R radarr:dietpi /mnt/dietpi_userdata/radarr /opt/radarr fi if To_Install 106 lidarr # Lidarr then # APT dependencies aDEPS=('mediainfo') # - .NET: https://github.com/dotnet/docs/blob/main/docs/core/install/linux-debian.md#dependencies if (( $G_HW_ARCH != 1 )) then case $G_DISTRO in 6) aDEPS+=('libicu67');; 7) aDEPS+=('libicu72');; *) aDEPS+=('libicu76');; esac fi # Pre-v7.5 ARMv6: Migrate old install dir [[ -d '/opt/Lidarr' && ! -d '/opt/lidarr' ]] && G_EXEC mv /opt/{L,l}idarr # Download # - ARMv6: Lidarr v1 does not support Mono anymore local url='https://github.com/Lidarr/Lidarr/releases/download/v0.8.1.2135/Lidarr.master.0.8.1.2135.linux.tar.gz' if (( $G_HW_ARCH != 1 )) then case $G_HW_ARCH in 2) local arch='arm';; 3) local arch='arm64';; *) local arch='x64';; esac url=$(curl -sSfL 'https://api.github.com/repos/Lidarr/Lidarr/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*linux-core-$arch\.tar\.gz\"$/{print \$4}") local fallback_url="https://github.com/Lidarr/Lidarr/releases/download/v2.13.3.4711/Lidarr.master.2.13.3.4711.linux-core-$arch.tar.gz" fi Download_Install "$url" # Install: Remove previous instance on reinstall [[ -d '/opt/lidarr' ]] && G_EXEC rm -R /opt/lidarr G_EXEC mv Lidarr /opt/lidarr # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/lidarr # User Create_User -g dietpi -d /mnt/dietpi_userdata/lidarr lidarr # Service: https://github.com/lidarr/Lidarr/wiki/Autostart-on-Linux#systemd cat << _EOF_ > /etc/systemd/system/lidarr.service [Unit] Description=Lidarr (DietPi) Wants=network-online.target After=network-online.target remote-fs.target transmission-daemon.service qbittorrent.service rtorrent.service nzbget.service deluged.service aria2.service sabnzbd.service StartLimitIntervalSec=60 StartLimitBurst=3 [Service] SyslogIdentifier=Lidarr User=lidarr UMask=002 LogsDirectory=lidarr ExecStart=/opt/lidarr/Lidarr -nobrowser -data=/mnt/dietpi_userdata/lidarr TimeoutStopSec=20 KillMode=process Restart=on-failure # Hardening ProtectSystem=strict ProtectHome=true PrivateDevices=true ProtectKernelTunables=true ProtectControlGroups=true ReadWritePaths=-/opt/lidarr -/mnt -/media -/var/log/lidarr -/tmp [Install] WantedBy=multi-user.target _EOF_ # - ARMv6 devices use Mono (( $G_HW_ARCH == 1 )) && G_CONFIG_INJECT 'ExecStart=' "ExecStart=$(command -v mono) /opt/lidarr/Lidarr.exe -nobrowser -data=/mnt/dietpi_userdata/lidarr" /etc/systemd/system/lidarr.service # Logs to RAM G_EXEC rm -Rf /mnt/dietpi_userdata/lidarr/logs* G_EXEC ln -s /var/log/lidarr /mnt/dietpi_userdata/lidarr/logs G_EXEC ln -s /var/log/lidarr/logs.db /mnt/dietpi_userdata/lidarr/logs.db G_EXEC ln -s /var/log/lidarr/logs.db-shm /mnt/dietpi_userdata/lidarr/logs.db-shm G_EXEC ln -s /var/log/lidarr/logs.db-wal /mnt/dietpi_userdata/lidarr/logs.db-wal # Permissions G_EXEC chown -R lidarr:dietpi /mnt/dietpi_userdata/lidarr /opt/lidarr fi if To_Install 180 bazarr # Bazarr: https://wiki.bazarr.media/Getting-Started/Installation/Linux/linux/ then # APT deps aDEPS=('unzip') (( $G_DISTRO > 7 )) && aDEPS+=('7zip') || aDEPS+=('p7zip') # - ARMv6 does not support unrar-nonfree and Bazarr does not support unrar-free, so we need to use "unar": https://github.com/morpheus65535/bazarr/issues/2172 (( $G_HW_ARCH == 1 )) && aDEPS+=('unar') Python_Deps lxml numpy pillow # Download Download_Install 'https://github.com/morpheus65535/bazarr/releases/latest/download/bazarr.zip' bazarr # Python deps # - Allow Pillow to be compiled G_EXEC sed --follow-symlinks -i 's/ --only-binary=Pillow$//' bazarr/requirements.txt G_EXEC_OUTPUT=1 G_EXEC pip3 install -Ur bazarr/requirements.txt # Install: Remove previous instance on reinstall [[ -d '/opt/bazarr' ]] && G_EXEC rm -R /opt/bazarr G_EXEC mv bazarr /opt # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/bazarr # Log to RAM G_EXEC rm -Rf /mnt/dietpi_userdata/bazarr/log G_EXEC ln -s /var/log/bazarr /mnt/dietpi_userdata/bazarr/log # User Create_User -g dietpi -d /mnt/dietpi_userdata/bazarr bazarr # Permissions G_EXEC chown -R bazarr:0 /mnt/dietpi_userdata/bazarr /opt/bazarr # Service: https://wiki.bazarr.media/Getting-Started/Autostart/Linux/linux/ cat << '_EOF_' > /etc/systemd/system/bazarr.service [Unit] Description=Bazarr (DietPi) Wants=network-online.target After=network-online.target sonarr.service radarr.service [Service] SyslogIdentifier=Bazarr User=bazarr UMask=002 LogsDirectory=bazarr WorkingDirectory=/mnt/dietpi_userdata/bazarr ExecStart=/usr/bin/python3 /opt/bazarr/bazarr.py -c /mnt/dietpi_userdata/bazarr KillSignal=SIGINT # Hardening ProtectSystem=strict ProtectHome=true PrivateDevices=true PrivateTmp=true ProtectKernelTunables=true ProtectControlGroups=true ReadWritePaths=-/opt/bazarr -/mnt -/media -/var/log/bazarr -/tmp [Install] WantedBy=multi-user.target _EOF_ # On fresh install, pre-configure for Sonarr and Radarr when found if (( ${aSOFTWARE_INSTALL_STATE[144]} + ${aSOFTWARE_INSTALL_STATE[145]} > 0 )) && Create_Config /mnt/dietpi_userdata/bazarr/config/config.ini bazarr then # Sonarr if (( ${aSOFTWARE_INSTALL_STATE[144]} > 0 )) && CREATE_CONFIG_CONTENT='ApiKey' Create_Config /mnt/dietpi_userdata/sonarr/config.xml sonarr then local port=$(sed -nE '/[0-9]+<\/Port>/{s/^.*([0-9]+)<\/Port>.*$/\1/p;q}' /mnt/dietpi_userdata/sonarr/config.xml) local apikey=$(sed -nE '/.+<\/ApiKey>/{s/^.*(.+)<\/ApiKey>.*$/\1/p;q}' /mnt/dietpi_userdata/sonarr/config.xml) G_EXEC sed --follow-symlinks -i '/\[sonarr\]/,/^$/s/^ip = .*$/ip = 127.0.0.1/' /mnt/dietpi_userdata/bazarr/config/config.ini G_EXEC sed --follow-symlinks -i "/\[sonarr\]/,/^$/s/^port = .*$/port = $port/" /mnt/dietpi_userdata/bazarr/config/config.ini G_EXEC sed --follow-symlinks -i '/\[sonarr\]/,/^$/s/^base_url = .*$/base_url = \//' /mnt/dietpi_userdata/bazarr/config/config.ini G_EXEC sed --follow-symlinks -i "/\[sonarr\]/,/^$/s/^apikey = .*$/apikey = $apikey/" /mnt/dietpi_userdata/bazarr/config/config.ini G_CONFIG_INJECT 'use_sonarr[[:blank:]]*=' 'use_sonarr = True' /mnt/dietpi_userdata/bazarr/config/config.ini '\[general\]' fi # Radarr if (( ${aSOFTWARE_INSTALL_STATE[145]} > 0 )) && CREATE_CONFIG_CONTENT='ApiKey' Create_Config /mnt/dietpi_userdata/radarr/config.xml radarr then local port=$(sed -nE '/[0-9]+<\/Port>/{s/^.*([0-9]+)<\/Port>.*$/\1/p;q}' /mnt/dietpi_userdata/radarr/config.xml) local apikey=$(sed -nE '/.+<\/ApiKey>/{s/^.*(.+)<\/ApiKey>.*$/\1/p;q}' /mnt/dietpi_userdata/radarr/config.xml) G_EXEC sed --follow-symlinks -i '/\[radarr\]/,/^$/s/^ip = .*$/ip = 127.0.0.1/' /mnt/dietpi_userdata/bazarr/config/config.ini G_EXEC sed --follow-symlinks -i "/\[radarr\]/,/^$/s/^port = .*$/port = $port/" /mnt/dietpi_userdata/bazarr/config/config.ini G_EXEC sed --follow-symlinks -i '/\[radarr\]/,/^$/s/^base_url = .*$/base_url = \//' /mnt/dietpi_userdata/bazarr/config/config.ini G_EXEC sed --follow-symlinks -i "/\[radarr\]/,/^$/s/^apikey = .*$/apikey = $apikey/" /mnt/dietpi_userdata/bazarr/config/config.ini G_CONFIG_INJECT 'use_radarr[[:blank:]]*=' 'use_radarr = True' /mnt/dietpi_userdata/bazarr/config/config.ini '\[general\]' fi fi fi if To_Install 146 tautulli # Tautulli then # Download local url='https://github.com/Tautulli/Tautulli.git' G_CHECK_URL "$url" G_THREAD_START git clone --depth 1 "$url" G_AGI python3-pkg-resources G_THREAD_WAIT # Install: Remove previous instance on reinstall [[ -d '/opt/tautulli' ]] && G_EXEC rm -R /opt/tautulli G_EXEC mv Tautulli /opt/tautulli # User Create_User -d /mnt/dietpi_userdata/tautulli tautulli # Directory G_EXEC mkdir -p /mnt/dietpi_userdata/tautulli # Service: https://github.com/Tautulli/Tautulli/blob/master/init-scripts/init.systemd cat << '_EOF_' > /etc/systemd/system/tautulli.service [Unit] Description=Tautulli (DietPi) Wants=network-online.target After=network-online.target [Service] SyslogIdentifier=Tautulli User=tautulli ExecStart=/usr/bin/python3 /opt/tautulli/Tautulli.py -q --nolaunch --config /mnt/dietpi_userdata//tautulli/config.ini --datadir /mnt/dietpi_userdata/tautulli [Install] WantedBy=multi-user.target _EOF_ # Permissions G_EXEC chown -R tautulli:tautulli /{opt,mnt/dietpi_userdata}/tautulli fi if To_Install 147 jackett # Jackett then # ARMv6 requires Mono: https://github.com/Jackett/Jackett#installation-on-linux-armv6-or-below # .NET dependency: https://github.com/dotnet/docs/blob/main/docs/core/install/linux-debian.md#dependencies if (( $G_HW_ARCH != 1 )) then case $G_DISTRO in 6) aDEPS=('libicu67');; 7) aDEPS=('libicu72');; *) aDEPS=('libicu76');; esac fi # Download case $G_HW_ARCH in 1) local arch='Mono';; 2) local arch='LinuxARM32';; 3) local arch='LinuxARM64';; *) local arch='LinuxAMDx64';; esac local fallback_url="https://github.com/Jackett/Jackett/releases/download/v0.23.43/Jackett.Binaries.$arch.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/Jackett/Jackett/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/Jackett\.Binaries\.$arch\.tar\.gz\"$/{print \$4}")" # Move existing configs to unpacked install dir [[ -d '/opt/jackett/Jackett' ]] && G_EXEC mv /opt/jackett/Jackett Jackett/ [[ -d '/opt/jackett/.mono' ]] && G_EXEC mv /opt/jackett/.mono Jackett/ # Install: Remove previous instance on reinstall [[ -d '/opt/jackett' ]] && G_EXEC rm -R /opt/jackett G_EXEC mv Jackett /opt/jackett # User Create_User -d /opt/jackett jackett # Permissions G_EXEC chown -R jackett:jackett /opt/jackett # Service: https://github.com/Jackett/Jackett/wiki/systemd-service # - Wrap execution into shell to work around: https://github.com/Jackett/Jackett/issues/5208 cat << '_EOF_' > /etc/systemd/system/jackett.service [Unit] Description=Jackett (DietPi) Wants=network-online.target After=network-online.target StartLimitIntervalSec=60 StartLimitBurst=3 [Service] SyslogIdentifier=Jackett User=jackett WorkingDirectory=/opt/jackett Environment=XDG_CONFIG_HOME=/opt/jackett ExecStart=/bin/dash -c '/opt/jackett/jackett --NoRestart; ec=$?; while pgrep -u jackett JackettUpdater > /dev/null; do sleep 1; done; exit $ec' Restart=always RestartSec=5 # Hardening ProtectSystem=strict ProtectHome=true PrivateDevices=true PrivateTmp=true ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true NoNewPrivileges=true ReadWritePaths=-/opt/jackett [Install] WantedBy=multi-user.target _EOF_ # - ARMv6 devices use Mono (( $G_HW_ARCH == 1 )) && G_CONFIG_INJECT 'ExecStart=' "ExecStart=$(command -v mono) /opt/jackett/JackettConsole.exe --NoRestart" /etc/systemd/system/jackett.service fi if To_Install 149 nzbget # NZBGet then local reinstall=0 [[ -f '/mnt/dietpi_userdata/nzbget/nzbget.conf' ]] && reinstall=1 local fallback_url='https://github.com/nzbgetcom/nzbget/releases/download/v25.3/nzbget-25.3-bin-linux.run' Download_Install "$(curl -sSfL 'https://api.github.com/repos/nzbgetcom/nzbget/releases/latest' | mawk -F\" '/^ *"browser_download_url": ".*\/nzbget-[^"/]*-bin-linux.run"$/{print $4}')" nzbget.run G_EXEC mkdir -p /mnt/dietpi_userdata/nzbget G_EXEC_OUTPUT=1 G_EXEC dash nzbget.run --destdir /mnt/dietpi_userdata/nzbget G_EXEC rm nzbget.run # User Create_User -g dietpi -d /mnt/dietpi_userdata/nzbget nzbget # Permissions G_EXEC chmod 0600 /mnt/dietpi_userdata/nzbget/nzbget.conf G_EXEC chown -R nzbget:root /mnt/dietpi_userdata/nzbget # Config if (( ! $reinstall )) then G_CONFIG_INJECT 'MainDir=' 'MainDir=/mnt/dietpi_userdata/downloads' /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'DestDir=' 'DestDir=/mnt/dietpi_userdata/downloads/complete' /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'WriteLog=' 'WriteLog=none' /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'ControlUsername=' 'ControlUsername=admin' /mnt/dietpi_userdata/nzbget/nzbget.conf GCI_PASSWORD=1 G_CONFIG_INJECT 'ControlPassword=' "ControlPassword=$GLOBAL_PW" /mnt/dietpi_userdata/nzbget/nzbget.conf # Umask: https://github.com/MichaIng/DietPi/issues/1999 G_CONFIG_INJECT 'UMask=' 'UMask=0002' /mnt/dietpi_userdata/nzbget/nzbget.conf # Optimisations G_CONFIG_INJECT 'CrcCheck=' 'CrcCheck=no' /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'ParScan=' 'ParScan=limited' /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'ParThreads=' "ParThreads=$G_HW_CPU_CORES" /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'DebugTarget=' 'DebugTarget=none' /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'DetailTarget=' 'DetailTarget=none' /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'CrashTrace=' 'CrashTrace=no' /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'ParBuffer=' "ParBuffer=$(Optimise_BitTorrent 0)" /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'ArticleCache=' "ArticleCache=$(Optimise_BitTorrent 0)" /mnt/dietpi_userdata/nzbget/nzbget.conf G_CONFIG_INJECT 'WriteBuffer=' "WriteBuffer=$(Optimise_BitTorrent 0)" /mnt/dietpi_userdata/nzbget/nzbget.conf fi # Service cat << '_EOF_' > /etc/systemd/system/nzbget.service [Unit] Description=NZBGet (DietPi) Wants=network-online.target After=network-online.target remote-fs.target [Service] User=nzbget WorkingDirectory=/mnt/dietpi_userdata/nzbget ExecStart=/mnt/dietpi_userdata/nzbget/nzbget -so OutputMode=log [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 151 prowlarr # Prowlarr then # .NET dependency: https://github.com/dotnet/docs/blob/main/docs/core/install/linux-debian.md#dependencies case $G_DISTRO in 6) aDEPS=('libicu67');; 7) aDEPS=('libicu72');; *) aDEPS=('libicu76');; esac # Download case $G_HW_ARCH in 2) local arch='arm';; 3) local arch='arm64';; *) local arch='x64';; esac local fallback_url="https://github.com/Prowlarr/Prowlarr/releases/download/v2.0.5.5160/Prowlarr.master.2.0.5.5160.linux-core-$arch.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/Prowlarr/Prowlarr/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*linux-core-$arch\.tar\.gz\"$/{print \$4}")" # Install: Remove previous instance on reinstall [[ -d '/opt/prowlarr' ]] && G_EXEC rm -R /opt/prowlarr G_EXEC mv Prowlarr /opt/prowlarr # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/prowlarr # User Create_User -g dietpi -d /mnt/dietpi_userdata/prowlarr prowlarr # Service: https://wiki.servarr.com/prowlarr/installation cat << '_EOF_' > /etc/systemd/system/prowlarr.service [Unit] Description=Prowlarr (DietPi) Wants=network-online.target After=network-online.target remote-fs.target transmission-daemon.service qbittorrent.service rtorrent.service nzbget.service deluged.service aria2.service sabnzbd.service StartLimitIntervalSec=60 StartLimitBurst=3 [Service] SyslogIdentifier=Prowlarr User=prowlarr UMask=002 LogsDirectory=prowlarr ExecStart=/opt/prowlarr/Prowlarr -nobrowser -data=/mnt/dietpi_userdata/prowlarr TimeoutStopSec=20 KillMode=process Restart=on-failure # Hardening ProtectSystem=strict ProtectHome=true PrivateDevices=true ProtectKernelTunables=true ProtectControlGroups=true ReadWritePaths=-/opt/prowlarr -/mnt -/media -/var/log/prowlarr -/tmp [Install] WantedBy=multi-user.target _EOF_ # Logs to RAM G_EXEC rm -Rf /mnt/dietpi_userdata/prowlarr/logs* G_EXEC ln -s /var/log/prowlarr /mnt/dietpi_userdata/prowlarr/logs G_EXEC ln -s /var/log/prowlarr/logs.db /mnt/dietpi_userdata/prowlarr/logs.db G_EXEC ln -s /var/log/prowlarr/logs.db-shm /mnt/dietpi_userdata/prowlarr/logs.db-shm G_EXEC ln -s /var/log/prowlarr/logs.db-wal /mnt/dietpi_userdata/prowlarr/logs.db-wal # Permissions G_EXEC chown -R prowlarr:dietpi /mnt/dietpi_userdata/prowlarr /opt/prowlarr fi if To_Install 203 readarr # Readarr then # .NET dependency: https://github.com/dotnet/docs/blob/main/docs/core/install/linux-debian.md#dependencies case $G_DISTRO in 6) aDEPS=('libicu67');; 7) aDEPS=('libicu72');; *) aDEPS=('libicu76');; esac # Download case $G_HW_ARCH in 2) local arch='arm';; 3) local arch='arm64';; *) local arch='x64';; esac local fallback_url="https://github.com/Readarr/Readarr/releases/download/v0.4.18.2805/Readarr.develop.0.4.18.2805.linux-core-$arch.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/Readarr/Readarr/releases' | mawk -F\" "/^ *\"browser_download_url\": \".*linux-core-$arch\.tar\.gz\"$/{print \$4}" | head -1)" # Install: Remove previous instance on reinstall [[ -d '/opt/readarr' ]] && G_EXEC rm -R /opt/readarr G_EXEC mv Readarr /opt/readarr # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/readarr # User Create_User -g dietpi -d /mnt/dietpi_userdata/readarr readarr # Service: https://wiki.servarr.com/readarr/installation cat << '_EOF_' > /etc/systemd/system/readarr.service [Unit] Description=Readarr (DietPi) Wants=network-online.target After=network-online.target remote-fs.target transmission-daemon.service qbittorrent.service rtorrent.service nzbget.service deluged.service aria2.service sabnzbd.service StartLimitIntervalSec=60 StartLimitBurst=3 [Service] SyslogIdentifier=Readarr User=readarr UMask=002 LogsDirectory=readarr ExecStart=/opt/readarr/Readarr -nobrowser -data=/mnt/dietpi_userdata/readarr TimeoutStopSec=20 KillMode=process Restart=on-failure # Hardening ProtectSystem=strict ProtectHome=true PrivateDevices=true ProtectKernelTunables=true ProtectControlGroups=true ReadWritePaths=-/opt/readarr -/mnt -/media -/var/log/readarr -/tmp [Install] WantedBy=multi-user.target _EOF_ # Logs to RAM G_EXEC rm -Rf /mnt/dietpi_userdata/readarr/logs* G_EXEC ln -s /var/log/readarr /mnt/dietpi_userdata/readarr/logs G_EXEC ln -s /var/log/readarr/logs.db /mnt/dietpi_userdata/readarr/logs.db G_EXEC ln -s /var/log/readarr/logs.db-shm /mnt/dietpi_userdata/readarr/logs.db-shm G_EXEC ln -s /var/log/readarr/logs.db-wal /mnt/dietpi_userdata/readarr/logs.db-wal # Permissions G_EXEC chown -R readarr:dietpi /mnt/dietpi_userdata/readarr /opt/readarr fi if To_Install 155 htpc-manager # HTPC Manager then local url='https://github.com/HTPC-Manager/HTPC-Manager' G_CHECK_URL "$url" # APT deps Python_Deps -i cryptography pillow psutil pynacl if [[ -d '/mnt/dietpi_userdata/htpc-manager/.git' ]] then G_EXEC cd /mnt/dietpi_userdata/htpc-manager G_EXEC_OUTPUT=1 G_EXEC git remote set-url origin "$url" G_EXEC_OUTPUT=1 G_EXEC git fetch --depth=1 origin G_EXEC_OUTPUT=1 G_EXEC git reset --hard origin G_EXEC_OUTPUT=1 G_EXEC git clean -dxfe '/userdata' else G_EXEC_OUTPUT=1 G_EXEC git clone --depth=1 "$url" G_EXEC mkdir -p /mnt/dietpi_userdata/htpc-manager G_EXEC cp -a HTPC-Manager/. /mnt/dietpi_userdata/htpc-manager/ G_EXEC rm -R HTPC-Manager G_EXEC cd /mnt/dietpi_userdata/htpc-manager G_EXEC_OUTPUT=1 G_EXEC git reset --hard origin G_EXEC_OUTPUT=1 G_EXEC git clean -dxfe '/userdata' fi # Python deps G_EXEC_OUTPUT=1 G_EXEC pip3 install -Ur requirements.txt # Service cat << '_EOF_' > /etc/systemd/system/htpc-manager.service [Unit] Description=HTPC Manager (DietPi) Wants=network-online.target After=network-online.target [Service] SyslogIdentifier=HTPC Manager ExecStart=/usr/bin/python3 -OO /mnt/dietpi_userdata/htpc-manager/Htpc.py [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 153 octoprint # OctoPrint then # Pre-create user and its home directory to allow user-level (Rust and) Python instance Create_User -G dialout,tty,video -d /mnt/dietpi_userdata/octoprint octoprint G_EXEC mkdir -p /mnt/dietpi_userdata/octoprint G_EXEC chown -R octoprint:octoprint /mnt/dietpi_userdata/octoprint # Deps Python_Deps -i -u octoprint cffi netifaces psutil pydantic # Clear pip cache in case it got somehow created [[ -d '/mnt/dietpi_userdata/octoprint/.cache' ]] && G_EXEC rm -R /mnt/dietpi_userdata/octoprint/.cache # Install OctoPrint # shellcheck disable=SC2016 G_EXEC_OUTPUT=1 G_EXEC runuser -u octoprint -- dash -c 'PATH="$HOME/.cargo/bin:$PATH" pip3 install -U --user --no-warn-script-location octoprint' # Service: https://github.com/OctoPrint/OctoPrint/blob/master/scripts/octoprint.service cat << '_EOF_' > /etc/systemd/system/octoprint.service [Unit] Description=OctoPrint (DietPi) Documentation=https://dietpi.com/docs/software/printing/#octoprint Wants=network-online.target After=network-online.target mjpg-streamer.service [Service] Environment="LC_ALL=C.UTF-8" "LANG=C.UTF-8" User=octoprint ExecStart=/mnt/dietpi_userdata/octoprint/.local/bin/octoprint serve [Install] WantedBy=multi-user.target _EOF_ # CLI alias echo "alias octoprint='sudo -u octoprint /mnt/dietpi_userdata/octoprint/.local/bin/octoprint'" > /etc/bashrc.d/dietpi-octoprint.sh # On fresh installs, change listening port to 5001 to avoid conflict with Shairport Sync. [[ -f '/mnt/dietpi_userdata/octoprint/.octoprint/config.yaml' ]] || G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set server.port '5001' # Apply service and system commands: Allow execution via specific sudoers config, use "which" for "reboot" and "poweroff", since we create shell functions in dietpi-globals to bypass logind calls if logind is not running. # shellcheck disable=SC2230 echo "octoprint ALL=NOPASSWD: $(command -v systemctl) restart octoprint, $(which reboot), $(which poweroff)" > /etc/sudoers.d/octoprint G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set server.commands.serverRestartCommand 'sudo systemctl restart octoprint' G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set server.commands.systemRestartCommand 'sudo reboot' G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set server.commands.systemShutdownCommand 'sudo poweroff' # mjpg-streamer: Configure OctoPrint to use it if installed if (( ${aSOFTWARE_INSTALL_STATE[137]} > 0 )) then G_DIETPI-NOTIFY 2 'Configuring OctoPrint to use mjpg-streamer for webcam support' G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set webcam.stream "http://$(G_GET_NET ip):8082/?action=stream" G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set webcam.snapshot 'http://127.0.0.1:8082/?action=snapshot' G_EXEC runuser -u octoprint -- /mnt/dietpi_userdata/octoprint/.local/bin/octoprint config set webcam.ffmpeg "$(command -v ffmpeg)" fi fi if To_Install 187 cups # CUPS then # Download base configuration if it does not exist yet [[ -f '/etc/cups/cupsd.conf' ]] || dps_index=$software_id Download_Install 'cupsd.conf' /etc/cups/cupsd.conf G_AGI cups G_EXEC systemctl stop cups G_EXEC chown root:lp /etc/cups/ /etc/cups/ppd/ /etc/cups/ssl/ fi if To_Install 154 roonserver # Roon Server: https://help.roonlabs.com/portal/en/kb/articles/linux-install#Manual_Install then # .NET dependency: https://github.com/dotnet/docs/blob/main/docs/core/install/linux-debian.md#dependencies case $G_DISTRO in 6) aDEPS=('libicu67');; 7) aDEPS=('libicu72');; *) aDEPS=('libicu76');; esac G_WHIP_BUTTON_OK_TEXT='Early Access' G_WHIP_BUTTON_CANCEL_TEXT='Stable' G_WHIP_DEFAULT_ITEM=$(grep -cm1 '^[[:blank:]]*SOFTWARE_ROONSERVER_EARLYACCESS=1' /boot/dietpi.txt) if G_WHIP_YESNO 'Do you want to install regular stable Roon Server builds, or early access builds? \nOfficial info about the Roon Early Access Program can be found here: - https://help.roonlabs.com/portal/en/kb/articles/roon-early-access-program \nNB: Early access builds have a higher chance to contain bugs, and you may need to restore a database backup when reverting from early access to stable builds.' then Download_Install 'https://download.roonlabs.net/builds/earlyaccess/RoonServer_linuxx64.tar.bz2' G_CONFIG_INJECT 'SOFTWARE_ROONSERVER_EARLYACCESS=' 'SOFTWARE_ROONSERVER_EARLYACCESS=1' /boot/dietpi.txt else Download_Install 'https://download.roonlabs.net/builds/RoonServer_linuxx64.tar.bz2' G_CONFIG_INJECT 'SOFTWARE_ROONSERVER_EARLYACCESS=' 'SOFTWARE_ROONSERVER_EARLYACCESS=0' /boot/dietpi.txt fi # Reinstall: Replace old instance [[ -d '/opt/roonserver' ]] && G_EXEC rm -R /opt/roonserver G_EXEC mv RoonServer /opt/roonserver # Log to /var/log/roonserver G_EXEC mkdir -p /mnt/dietpi_userdata/roonserver/{RoonServer,RAATServer} G_EXEC rm -Rf /mnt/dietpi_userdata/roonserver/{RoonServer,RAATServer}/Logs G_EXEC ln -s /var/log/roonserver /mnt/dietpi_userdata/roonserver/RoonServer/Logs G_EXEC ln -s /var/log/roonserver /mnt/dietpi_userdata/roonserver/RAATServer/Logs # User: Grant sudo permissions to create a mount point and mount SMB shares Create_User -G dietpi,audio -d /mnt/dietpi_userdata/roonserver roonserver G_EXEC eval 'echo '\''roonserver ALL=NOPASSWD:SETENV: /bin/mkdir -p /mnt/RoonStorage_*, /sbin/mount.cifs'\'' > /etc/sudoers.d/roonserver' # Permissions G_EXEC chmod 0755 /opt/roonserver G_EXEC chown -R roonserver:root /{mnt/dietpi_userdata,opt}/roonserver # Service cat << '_EOF_' > /etc/systemd/system/roonserver.service [Unit] Description=Roon Server (DietPi) Wants=network-online.target After=network-online.target remote-fs.target [Service] SyslogIdentifier=Roon Server User=roonserver AmbientCapabilities=CAP_SYS_NICE LogsDirectory=roonserver Environment=ROON_DATAROOT=/mnt/dietpi_userdata/roonserver Environment=ROON_ID_DIR=/mnt/dietpi_userdata/roonserver ExecStart=/opt/roonserver/start.sh # Hardening PrivateTmp=true [Install] WantedBy=multi-user.target _EOF_ Download_Test_Media fi if To_Install 156 # Steam then # Allow non-interactive install G_EXEC eval "debconf-set-selections <<< 'steam steam/question select I AGREE'" # x86_64: Install Debian i386 package if [[ $G_HW_ARCH == 10 ]] then # Add i386 arch: https://packages.debian.org/steam [[ $(dpkg --print-foreign-architectures) == *'i386'* ]] || { G_EXEC dpkg --add-architecture i386; G_AGUP; } G_AGI steam # Reapply GPU drivers to install required i386 items local gpu_current=$(sed -n '/^[[:blank:]]*CONFIG_GPU_DRIVER=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) /boot/dietpi/func/dietpi-set_hardware gpudriver "$gpu_current" # ARM: Install repacked Debian i386 package for armhf elif [[ $G_HW_ARCH == 2 ]] then Download_Install "https://dietpi.com/downloads/binaries/$G_DISTRO_NAME/steam_$G_HW_ARCH_NAME.deb" fi # Move data dir to dietpi_userdata if [[ -d '/mnt/dietpi_userdata/steam' ]] then G_EXEC rm -Rf /root/.steam elif [[ -d '/root/.steam' ]] then G_EXEC mv /root/.steam /mnt/dietpi_userdata/steam else G_EXEC mkdir /mnt/dietpi_userdata/steam fi G_EXEC ln -s /mnt/dietpi_userdata/steam /root/.steam # Desktop shortcut Create_Desktop_Shortcut steam fi if To_Install 158 minio # MinIO then case $G_HW_ARCH in 3) local arch='arm64';; 10) local arch='amd64';; *) local arch='arm';; esac G_EXEC curl -sSfLo /usr/local/bin/minio "https://dl.minio.io/server/minio/release/linux-$arch/minio" G_EXEC chmod +x /usr/local/bin/minio # Service G_EXEC curl -sSfLo /etc/systemd/system/minio.service 'https://github.com/minio/minio-service/raw/master/linux-systemd/minio.service' # User Create_User -d /mnt/dietpi_userdata/minio-data minio-user # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/minio-data G_EXEC chown -R minio-user:minio-user /mnt/dietpi_userdata/minio-data # Config [[ -f '/etc/default/minio' ]] || cat << '_EOF_' > /etc/default/minio # Default file path MINIO_VOLUMES="/mnt/dietpi_userdata/minio-data" # Use if you want to run MinIO on a custom port. MINIO_OPTS="--address :9004 --console-address :9001" # Access key of the server. #MINIO_ACCESS_KEY=Server-Access-Key # Secret key of the server. #MINIO_SECRET_KEY=Server-Secret-Key _EOF_ fi if To_Install 162 docker # Docker then # APT packages if (( $G_HW_ARCH == 11 )) then # RISC-V: Use "docker.io" from Debian repo as the official Docker repo does not support RISC-V yet: https://download.docker.com/linux/debian/dists/ local packages=('docker.io') # Trixie: Add split "docker-cli" package: https://packages.debian.org/trixie/docker-cli (( $G_DISTRO > 7 )) && packages+=('docker-cli') else # Detect distro local distro='debian' suite=${G_DISTRO_NAME/forky/trixie} (( $G_RASPBIAN )) && distro='raspbian' suite=${suite/trixie/bookworm} # APT key local url="https://download.docker.com/linux/$distro/gpg" G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-docker.gpg --yes" # APT list G_EXEC eval "echo 'deb https://download.docker.com/linux/$distro $suite stable' > /etc/apt/sources.list.d/docker.list" G_AGUP # APT package name packages=('docker-ce') fi # APT package # - Mask service to prevent iptables related startup failure: https://github.com/MichaIng/DietPi/issues/6013 G_EXEC systemctl mask --now docker G_AGI "${packages[@]}" G_EXEC systemctl unmask docker G_EXEC systemctl start docker.socket # Change Docker service type to "simple": https://github.com/MichaIng/DietPi/issues/2238#issuecomment-439474766 G_EXEC mkdir -p /lib/systemd/system/docker.service.d G_EXEC eval "echo -e '[Service]\nType=simple' > /lib/systemd/system/docker.service.d/dietpi-simple.conf" # Config: https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file # - Move Docker containers to dietpi_userdata # - Log to systemd-journald (journalctl) by default with reduced log level: https://github.com/MichaIng/DietPi/issues/2388 # + containerd: https://github.com/docker/docker.github.io/issues/9091 G_EXEC mkdir -p /mnt/dietpi_userdata/docker-data if [[ -f '/etc/docker/daemon.json' ]] then GCI_PRESERVE=1 G_CONFIG_INJECT '"data-root":' ' "data-root": "/mnt/dietpi_userdata/docker-data",' /etc/docker/daemon.json '^\{([[:space:]]|$)' GCI_PRESERVE=1 G_CONFIG_INJECT '"log-driver":' ' "log-driver": "journald",' /etc/docker/daemon.json '^\{([[:space:]]|$)' GCI_PRESERVE=1 G_CONFIG_INJECT '"log-level":' ' "log-level": "warn",' /etc/docker/daemon.json '^\{([[:space:]]|$)' GCI_PRESERVE=1 G_CONFIG_INJECT '"debug":' ' "debug": false,' /etc/docker/daemon.json '^\{([[:space:]]|$)' else G_EXEC mkdir -p /etc/docker echo '{ "data-root": "/mnt/dietpi_userdata/docker-data", "log-driver": "journald", "log-level": "warn", "debug": false }' > /etc/docker/daemon.json fi G_CONFIG_INJECT '\[debug\]' '[debug]' /etc/containerd/config.toml GCI_PRESERVE=1 G_CONFIG_INJECT 'level[[:blank:]]*=' ' level = "warn"' /etc/containerd/config.toml '^\[debug\]' Enable_memory_cgroup Configure_iptables fi if To_Install 134 # Docker Compose then # RISC-V: Official APT repo does not support RISC-V yet if (( $G_HW_ARCH == 11 )) then G_AGI docker-compose else G_AGI docker-compose-plugin fi fi if To_Install 161 bdd # FuguHub then local arch='RaspberryPi' (( $G_HW_ARCH == 10 )) && arch='linux-x64' # Download Download_Install "https://fuguhub.com/FuguHub.$arch.tar.gz" bd # - Remove first run wizard G_EXEC rm bd/applications/Config-Wizard.zip # - SSL addon: https://fuguhub.com/SSL-Certificate-Wizard.lsp G_THREAD_START curl -sSfL 'https://fuguhub.com/unix/sslcert.zip' -o bd/applications/sslcert.zip # - Drop Box addon: https://fuguhub.com/dropbox.lsp G_THREAD_START curl -sSfL 'https://fuguhub.com/box.zip' -o bd/applications/box.zip G_THREAD_WAIT # Reinstall: Do not overwrite config and data if [[ -d '/home/bd' ]] then G_EXEC rm -R bd/{cmsdocs,data,disk} G_EXEC cp -a bd/. /home/bd/ else G_EXEC rm -R bd/disk G_EXEC mv bd /home/bd fi # File server root directory if [[ ! -d '/mnt/dietpi_userdata/fuguhub-data' ]] then if [[ -d '/home/bd/disk' ]] then G_EXEC mv /home/bd/disk /mnt/dietpi_userdata/fuguhub-data # Pre-v8.0 else G_EXEC mkdir /mnt/dietpi_userdata/fuguhub-data fi fi G_EXEC rm -Rf /home/bd/disk # Pre-v8.0 [[ -e '/mnt/dietpi_userdata/fuguhub-data/cmsdocs' ]] || G_EXEC ln -s /home/bd/cmsdocs /mnt/dietpi_userdata/fuguhub-data/cmsdocs [[ -e '/mnt/dietpi_userdata/fuguhub-data/applications' ]] || G_EXEC ln -s /home/bd/applications /mnt/dietpi_userdata/fuguhub-data/applications # Create admin account if [[ ! -f '/home/bd/user.dat' ]] then > /home/bd/user.dat G_EXEC chmod 0600 /home/bd/user.dat echo -n "{'v':{'dietpi':{'name':'dietpi','pwd':'$GLOBAL_PW','maxUsers':15,'recycle':true,'inactive':1200,'roles':{}}}}" > /home/bd/user.dat fi [[ -f '/home/bd/drvcnstr.dat' ]] || echo -n '{"v":{"admin":{"roles":["admin"],"urls":["\/*"],"methods":["GET","POST","PUT","PROPFIND","PROPPATCH","MKCOL","DELETE","MOVE","COPY"]}}}' > /home/bd/drvcnstr.dat [[ -f '/home/bd/tuncnstr.dat' ]] || echo -n '{"v":{"TunFullAcc":{"roles":["TunFullAcc"],"urls":["\/*"],"methods":["GET"]}}}' > /home/bd/tuncnstr.dat # User Create_User -d /home/bd bd # Permissions G_EXEC chown -R bd:bd /home/bd /mnt/dietpi_userdata/fuguhub-data Remove_SysV bdd # Pre-v8.0: https://github.com/MichaIng/DietPi/issues/5058 cat << '_EOF_' > /etc/systemd/system/bdd.service [Unit] Description=FuguHub (DietPi) Wants=network-online.target After=network-online.target remote-fs.target [Service] User=bd AmbientCapabilities=CAP_NET_BIND_SERVICE WorkingDirectory=/home/bd ExecStart=/home/bd/FuguHub -h/home/bd -r/mnt/dietpi_userdata/fuguhub-data --threads 3 --sessions 100 --connections 80 [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 164 nukkit # Nukkit then Download_Install 'https://ci.opencollab.dev/job/NukkitX/job/Nukkit/job/master/lastStableBuild/artifact/target/nukkit-1.0-SNAPSHOT.jar' /usr/local/bin/nukkit/nukkit.jar # Config [[ -f '/usr/local/bin/nukkit/nukkit.yml' ]] || G_EXEC curl -sSfL 'https://raw.githubusercontent.com/CloudburstMC/Languages/master/eng/nukkit.yml' -o /usr/local/bin/nukkit/nukkit.yml # Service cat << _EOF_ > /etc/systemd/system/nukkit.service [Unit] Description=Nukkit (DietPi) Wants=network-online.target After=network-online.target [Service] SyslogIdentifier=Nukkit WorkingDirectory=/usr/local/bin/nukkit ExecStart=$JAVA_PATH -jar /usr/local/bin/nukkit/nukkit.jar SuccessExitStatus=143 [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 49 gogs # Gogs then # ARMv6/ARMv7/RISC-V: No pre-compiled binaries available, so we host our own. if (( $G_HW_ARCH == 1 || $G_HW_ARCH == 2 || $G_HW_ARCH == 11 )) then local url="https://dietpi.com/downloads/binaries/$G_DISTRO_NAME/gogs_$G_HW_ARCH_NAME.7z" # Else install latest binaries from GitHub else case $G_HW_ARCH in 3) local arch='armv8';; *) local arch='amd64';; esac local fallback_url="https://github.com/gogs/gogs/releases/download/v0.13.3/gogs_0.13.3_linux_$arch.tar.gz" local url=$(curl -sSfL 'https://api.github.com/repos/gogs/gogs/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/gogs_[^\"\/]*_linux_$arch.tar.gz\"$/{print \$4}") fi Download_Install "$url" G_EXEC mkdir -p /etc/gogs G_EXEC mv gogs/gogs /etc/gogs/gogs G_EXEC rm -R gogs # Pre-v8.14: Remove unnecessary init scripts [[ -d '/etc/gogs/scripts' ]] && G_EXEC rm -R /etc/gogs/scripts # User Create_User -d /etc/gogs -s /bin/dash gogs # Directories + permissions G_EXEC mkdir -p /mnt/dietpi_userdata/gogs-repo G_EXEC chown -R gogs:gogs /etc/gogs /mnt/dietpi_userdata/gogs-repo # Database /boot/dietpi/func/create_mysql_db gogs gogs "$GLOBAL_PW" # Service: https://github.com/gogs/gogs/blob/main/scripts/systemd/gogs.service cat << '_EOF_' > /etc/systemd/system/gogs.service [Unit] Description=Gogs (DietPi) Wants=network-online.target After=network-online.target mariadb.service [Service] User=gogs LogsDirectory=gogs WorkingDirectory=/etc/gogs ExecStart=/etc/gogs/gogs web # Hardening ProtectSystem=full PrivateDevices=yes PrivateTmp=yes NoNewPrivileges=true ReadWritePaths=-/etc/gogs [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 165 gitea # Gitea then # ARMv7: As of v1.8 there were issues with ARMv7 binaries on Raspbian which are hence not provided anymore: https://github.com/go-gitea/gitea/issues/6700 case $G_HW_ARCH in 3) local arch='arm64';; 10) local arch='amd64';; 11) local arch='riscv64';; *) local arch='arm-6';; esac local fallback_url="https://github.com/go-gitea/gitea/releases/download/v1.24.6/gitea-1.24.6-linux-$arch.xz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/go-gitea/gitea/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/gitea-[^\"\/]*-linux-$arch\.xz\"$/{print \$4}")" /mnt/dietpi_userdata/gitea/gitea # User Create_User -d /mnt/dietpi_userdata/gitea -s /bin/dash gitea # Permissions G_EXEC chown -R gitea:gitea /mnt/dietpi_userdata/gitea G_EXEC chmod +x /mnt/dietpi_userdata/gitea/gitea # Database /boot/dietpi/func/create_mysql_db gitea gitea "$GLOBAL_PW" # Service cat << '_EOF_' > /etc/systemd/system/gitea.service [Unit] Description=Gitea (DietPi) Wants=network-online.target After=network-online.target mariadb.service [Service] User=gitea LogsDirectory=gitea WorkingDirectory=/mnt/dietpi_userdata/gitea ExecStart=/mnt/dietpi_userdata/gitea/gitea web # Hardening ProtectSystem=full PrivateDevices=yes PrivateTmp=yes NoNewPrivileges=true [Install] WantedBy=multi-user.target _EOF_ # Pre-v7.9: Migrate run user setting: https://github.com/MichaIng/DietPi/issues/5516 [[ -f '/mnt/dietpi_userdata/gitea/custom/conf/app.ini' ]] && G_CONFIG_INJECT 'RUN_USER[[:blank:]]' 'RUN_USER = gitea' /mnt/dietpi_userdata/gitea/custom/conf/app.ini fi if To_Install 177 forgejo # Forgejo then # ARMv7: Dedicated binaries are not provided: https://codeberg.org/forgejo/forgejo/releases case $G_HW_ARCH in 3) local arch='arm64';; 10) local arch='amd64';; *) local arch='arm-6';; esac local fallback_url="https://codeberg.org/forgejo/forgejo/releases/download/v12.0.3/forgejo-12.0.3-linux-$arch.xz" Download_Install "$(curl -sSfL 'https://codeberg.org/api/v1/repos/forgejo/forgejo/releases/latest' | mawk -v RS=, -F\" "/^\"browser_download_url\":\".*-linux-$arch\.xz\"/{print \$4;exit}")" /mnt/dietpi_userdata/forgejo/forgejo # User Create_User -d /mnt/dietpi_userdata/forgejo -s /bin/dash forgejo # Permissions G_EXEC chown -R forgejo:forgejo /mnt/dietpi_userdata/forgejo G_EXEC chmod +x /mnt/dietpi_userdata/forgejo/forgejo # Database /boot/dietpi/func/create_mysql_db forgejo forgejo "$GLOBAL_PW" # Service cat << '_EOF_' > /etc/systemd/system/forgejo.service [Unit] Description=Forgejo (DietPi) Wants=network-online.target After=network-online.target mariadb.service [Service] User=forgejo LogsDirectory=forgejo WorkingDirectory=/mnt/dietpi_userdata/forgejo ExecStart=/mnt/dietpi_userdata/forgejo/forgejo web # Hardening ProtectSystem=full PrivateDevices=yes PrivateTmp=yes NoNewPrivileges=true [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 163 gmediarender # GMediaRender then G_AGI gmediarender G_EXEC systemctl stop gmediarender fi if To_Install 160 # Allo GUI then # Download Download_Install 'https://github.com/MichaIng/DietPi-AlloGUI/archive/v14.tar.gz' G_EXEC mv DietPi-AlloGUI-14 allo # Permissions G_EXEC chmod -R 'o=,g-w' allo G_EXEC chgrp -R www-data allo G_EXEC chmod -R 'g=' allo/storage allo/bootstrap/cache G_EXEC find allo/{storage,bootstrap/cache} -type d -exec chown www-data {} + # Create database when missing, else reapply random database password local db_password=$(tr -dc '[:alnum:]' < /dev/random | head -c32) if [[ -d '/mnt/dietpi_userdata/mysql/allo' ]] then G_EXEC systemctl start mariadb mysql -e "grant all privileges on allo.* to allo@localhost identified by '$db_password';" else /boot/dietpi/func/create_mysql_db allo allo "$db_password" G_EXEC mysql -e 'create table allo.users(id tinyint unsigned primary key auto_increment, name tinytext not null, email tinytext not null, password varchar(60) not null, remember_token varchar(60), created_at timestamp, updated_at timestamp default current_timestamp);' mysql -e "insert into allo.users(name, email, password) values ('admin', 'admin@allo.com', '$(php -r "echo password_hash('$GLOBAL_PW',PASSWORD_BCRYPT);")');" fi GCI_PASSWORD=1 G_CONFIG_INJECT 'DB_PASSWORD=' "DB_PASSWORD=$db_password" allo/.env unset -v db_password # Apply new app key GCI_PASSWORD=1 G_CONFIG_INJECT 'APP_KEY=' "APP_KEY=base64:$(base64 < <(tr -dc '[:graph:]' < /dev/random | head -c32))" allo/.env # Install cleanly [[ -d '/opt/allo' ]] && G_EXEC rm -R /opt/allo G_EXEC mv allo /opt # Grant sudo permissions G_EXEC eval 'echo '\''www-data ALL=NOPASSWD: ALL'\'' > /etc/sudoers.d/allo' # Link to webroot [[ -e '/var/www/allo' ]] && G_EXEC rm -R /var/www/allo # Failsafe G_EXEC ln -sf /opt/allo/public /var/www/allo # Redirect to web interface by default G_EXEC rm -f /var/www/index\.* cat << '_EOF_' > /var/www/index.php /var/lib/dietpi/dietpi-software/installed/pi-spc/sds.sh #!/bin/dash echo 'Audiophonics PI-SPC: Shutdown script starting... Asserting pins: ShutDown : GPIO17=in, Low BootOK : GPIO22=out, High SoftShutDown : GPIO04=out, Low' [ -f '/proc/cpuinfo' ] || { echo 'Oops: Unable to determine board revision from /proc/cpuinfo: /proc/cpuinfo does not exist. Exiting ...'; exit 1; } grep -q '^Hardware' /proc/cpuinfo || { echo 'Oops: Unable to determine board revision from /proc/cpuinfo: No "Hardware" line. Exiting ...'; exit 1; } gpio -g mode 04 out gpio -g write 04 0 gpio -g mode 17 in gpio -g write 17 0 gpio -g mode 22 out gpio -g write 22 1 until [ "$(gpio -g read 17)" = 1 ] do sleep 0.25 done echo 'Audiophonics PI-SPC: Shutting down system as requested...' systemctl start poweroff.target exit 0 _EOF_ G_EXEC chmod +x /var/lib/dietpi/dietpi-software/installed/pi-spc/sds.sh cat << '_EOF_' > /etc/systemd/system/pi-spc.service [Unit] Description=Audiophonics PI-SPC (DietPi) [Service] StandardOutput=tty ExecStart=/var/lib/dietpi/dietpi-software/installed/pi-spc/sds.sh [Install] WantedBy=multi-user.target _EOF_ # Alternative: Use native GPIO shutdown and poweroff device tree overlays # systemd-logind < dbus is required for the gpio-shutdown device tree overlay to trigger the shutdown. #G_AGI dbus #G_EXEC systemctl unmask systemd-logind #G_EXEC systemctl start systemd-logind #G_CONFIG_INJECT 'dtoverlay=gpio-shutdown' 'dtoverlay=gpio-shutdown,gpio_pin=17,active_low=0,gpio_pull=down' /boot/config.txt #G_CONFIG_INJECT 'dtoverlay=gpio-poweroff' 'dtoverlay=gpio-poweroff,gpiopin=22,active_low' /boot/config.txt fi if To_Install 167 raspotify # Raspotify: https://github.com/dtcooper/raspotify/blob/master/install.sh then # ARMv6: 0.31.8.1 is the last version supporting ARMv6: https://github.com/dtcooper/raspotify/wiki/Raspotify-on-Pi-v1's-and-Pi-Zero-v1.x, https://github.com/dtcooper/raspotify/commit/345f15c if (( $G_HW_ARCH == 1 )) then Download_Install 'https://github.com/dtcooper/raspotify/releases/download/0.31.8.1/raspotify_0.31.8.1.librespot.v0.3.1-54-gf4be9bb_armhf.deb' else # APT key Download_Install 'https://dtcooper.github.io/raspotify/key.asc' /etc/apt/trusted.gpg.d/dietpi-raspotify.asc # APT list G_EXEC eval 'echo '\''deb https://dtcooper.github.io/raspotify raspotify main'\'' > /etc/apt/sources.list.d/dietpi-raspotify.list' G_AGUP # APT package G_AGI raspotify fi # Stop service G_EXEC systemctl stop raspotify fi if To_Install 86 roon-extension-manager # Roon Extension Manager then # Data dir G_EXEC mkdir -p /mnt/dietpi_userdata/roon-extension-manager # Pre-v8.2 migration if [[ -f '/etc/systemd/system/roon-extension-manager.service' ]] then G_EXEC systemctl stop roon-extension-manager G_EXEC rm /etc/systemd/system/roon-extension-manager.service fi [[ -d '/root/.roon-extension-manager' && ! -d '/mnt/dietpi_userdata/roon-extension-manager/.roon-extension-manager' ]] && G_EXEC mv /{root,mnt/dietpi_userdata/roon-extension-manager}/.roon-extension-manager # User: Create with login shell first, since the REM installer uses "su" Create_User -G docker -d /mnt/dietpi_userdata/roon-extension-manager -s /bin/dash roon-extension-manager # Permissions G_EXEC chown -R roon-extension-manager:root /mnt/dietpi_userdata/roon-extension-manager # Store installer to data dir, so we can reuse it on uninstall aDEPS=('wget') Download_Install 'https://raw.githubusercontent.com/TheAppgineer/roon-extension-manager/v1.x/rem-setup.sh' /mnt/dietpi_userdata/roon-extension-manager/rem-setup.sh G_EXEC cd /mnt/dietpi_userdata/roon-extension-manager G_EXEC chmod +x rem-setup.sh # Let the installer create everything for "roon-extension-manager" to run the service: https://github.com/MichaIng/DietPi/issues/5236 SUDO_USER='roon-extension-manager' G_EXEC_OUTPUT=1 G_EXEC ./rem-setup.sh G_EXEC systemctl stop roon-extension-manager G_EXEC usermod -s "$(command -v nologin)" roon-extension-manager fi if To_Install 178 jellyfin # Jellyfin then # RPi: Enable hardware codecs (( $G_HW_MODEL > 9 )) || /boot/dietpi/func/dietpi-set_hardware rpi-codec 1 # APT key local url='https://repo.jellyfin.org/jellyfin_team.gpg.key' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-jellyfin.gpg --yes" # APT list G_EXEC eval "echo 'deb https://repo.jellyfin.org/debian ${G_DISTRO_NAME/forky/trixie} main' > /etc/apt/sources.list.d/dietpi-jellyfin.list" G_AGUP # Mask service to prevent potential XML parsing issue due to bad termination timing G_EXEC systemctl --no-reload mask jellyfin # APT meta package: Server, web component and FFmpeg implementation # - Trixie: Workaround for missing dependency: https://github.com/jellyfin/jellyfin-packaging/issues/77 local packages=() (( $G_DISTRO > 7 )) && packages=('libicu76') G_AGI jellyfin "${packages[@]}" G_EXEC systemctl --no-reload unmask jellyfin # Grant dietpi group permissions and assure video access Create_User -G dietpi,video,render -d /mnt/dietpi_userdata/jellyfin jellyfin # Config: Only apply on fresh install, assumed when /mnt/dietpi_userdata/jellyfin does not yet exist if [[ ! -d '/mnt/dietpi_userdata/jellyfin' ]] then # Data dir # shellcheck disable=SC2015 [[ -d '/var/lib/jellyfin' ]] && G_EXEC mv /var/lib/jellyfin /mnt/dietpi_userdata/jellyfin || G_EXEC mkdir /mnt/dietpi_userdata/jellyfin G_CONFIG_INJECT 'JELLYFIN_DATA_DIR=' 'JELLYFIN_DATA_DIR=/mnt/dietpi_userdata/jellyfin' /etc/default/jellyfin # Change default WorkingDirectory G_EXEC mkdir -p /etc/systemd/system/jellyfin.service.d G_EXEC eval 'echo -e '\''[Service]\nWorkingDirectory=/mnt/dietpi_userdata/jellyfin'\'' > /etc/systemd/system/jellyfin.service.d/dietpi.conf' # Cache dir # shellcheck disable=SC2015 [[ -d '/var/cache/jellyfin' ]] && G_EXEC mv /var/cache/jellyfin /mnt/dietpi_userdata/jellyfin/cache || G_EXEC mkdir /mnt/dietpi_userdata/jellyfin/cache G_CONFIG_INJECT 'JELLYFIN_CACHE_DIR=' 'JELLYFIN_CACHE_DIR=/mnt/dietpi_userdata/jellyfin/cache' /etc/default/jellyfin # Change default port due to conflict with Emby # - This config file is not generated at service start, but only when saving network settings via web UI. This also complements any existing config with defaults, hence we pre-create one with only the changes we need. cat << '_EOF_' > /etc/jellyfin/network.xml 8097 8097 _EOF_ G_EXEC chown jellyfin: /etc/jellyfin/network.xml fi # Permissions G_EXEC chown -R jellyfin: /mnt/dietpi_userdata/jellyfin Download_Test_Media fi if To_Install 62 # Box86 then # APT deps aDEPS=('cmake' 'make' 'gcc' 'libc6-dev' 'python3-minimal') # Download local version=$(curl -sSfL 'https://api.github.com/repos/ptitSeb/box86/releases/latest' | mawk -F\" '/^ *"tag_name": "[^"]*",$/{print $4}') [[ $version ]] || { version='v0.3.8'; G_DIETPI-NOTIFY 1 "Automatic latest ${aSOFTWARE_NAME[$software_id]} version detection failed. Version \"$version\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } Download_Install "https://github.com/ptitSeb/box86/archive/$version.tar.gz" # Build for targets: https://github.com/ptitSeb/box86/blob/master/CMakeLists.txt G_EXEC mkdir "box86-${version#v}/build" G_EXEC cd "box86-${version#v}/build" # - RPi 2 if (( $G_HW_MODEL == 2 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRPI2=1 # - RPi 3 elif (( $G_HW_MODEL == 3 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRPI3=1 # - RPi 4 elif (( $G_HW_MODEL == 4 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRPI4=1 # - Odroid XU4 elif (( $G_HW_MODEL == 11 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DODROIDXU4=1 # - ASUS Tinker Board elif (( $G_HW_MODEL == 52 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRK3288=1 # - Others else G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DARM_DYNAREC=1 fi G_EXEC_OUTPUT=1 G_EXEC make CFLAGS='-g0 -O3' "-j$(nproc)" G_EXEC strip --remove-section=.comment --remove-section=.note box86 G_EXEC make install # Cleanup G_EXEC cd "$G_WORKING_DIR" G_EXEC rm -R "box86-${version#v}" # Reload binfmt if kernel module is available to have i386 binaries executed via box86 automatically from now on modprobe binfmt_misc 2> /dev/null && G_EXEC systemctl restart systemd-binfmt fi if To_Install 197 # Box64 then # APT deps aDEPS=('cmake' 'make' 'gcc' 'libc6-dev' 'python3-minimal') # Download local version=$(curl -sSfL 'https://api.github.com/repos/ptitSeb/box64/releases/latest' | mawk -F\" '/^ *"tag_name": "[^"]*",$/{print $4}') [[ $version ]] || { version='v0.3.6'; G_DIETPI-NOTIFY 1 "Automatic latest ${aSOFTWARE_NAME[$software_id]} version detection failed. Version \"$version\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } Download_Install "https://github.com/ptitSeb/box64/archive/$version.tar.gz" # Build for targets: https://github.com/ptitSeb/box64/blob/main/CMakeLists.txt G_EXEC mkdir "box64-${version#v}/build" G_EXEC cd "box64-${version#v}/build" # - RISC-V if (( $G_HW_ARCH == 11 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRV64=1 # - RPi 2/3 elif (( $G_HW_MODEL == 2 || $G_HW_MODEL == 3 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRPI3ARM64=1 # - RPi 4 elif (( $G_HW_MODEL == 4 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRPI4ARM64=1 # - RPi 5 elif (( $G_HW_MODEL == 5 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRPI5ARM64=1 # - Odroid N2 elif (( $G_HW_MODEL == 15 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DODROIDN2=1 # - RK3399 elif (( $G_HW_CPUID == 3 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRK3399=1 # - RK3588 elif (( $G_HW_CPUID == 11 )) then G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DRK3588=1 # - Generic ARMv8 else G_EXEC cmake .. -DNOGIT=1 -DCMAKE_BUILD_TYPE=Release -DARM64=1 fi G_EXEC_OUTPUT=1 G_EXEC make CFLAGS='-g0 -O3' "-j$(nproc)" G_EXEC strip --remove-section=.comment --remove-section=.note box64 G_EXEC make install # Cleanup G_EXEC cd "$G_WORKING_DIR" G_EXEC rm -R "box64-${version#v}" # Reload binfmt if kernel module is available to have x86_64 binaries executed via box64 automatically from now on modprobe binfmt_misc 2> /dev/null && G_EXEC systemctl restart systemd-binfmt fi if To_Install 207 # Moonlight (CLI): https://dl.cloudsmith.io/public/moonlight-game-streaming/moonlight-embedded/setup.deb.sh then # APT key local url='https://dl.cloudsmith.io/public/moonlight-game-streaming/moonlight-embedded/gpg.5AEE46706CF0453E.key' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-moonlight.gpg --yes" # APT list local dist=$G_DISTRO_NAME (( $G_DISTRO > 7 )) && dist='bookworm' G_EXEC eval "echo 'deb https://dl.cloudsmith.io/public/moonlight-game-streaming/moonlight-embedded/deb/raspbian $dist main' > /etc/apt/sources.list.d/dietpi-moonlight.list" G_AGUP # APT deps aDEPS=('libcec6') (( $G_DISTRO > 7 )) && aDEPS=('libcec7') # APT package G_AGI moonlight-embedded "${aDEPS[@]}" aDEPS=() # Enable required fake KMS driver: https://github.com/moonlight-stream/moonlight-embedded/wiki/Packages /boot/dietpi/func/dietpi-set_hardware rpi-opengl vc4-fkms-v3d fi if To_Install 208 # Moonlight (GUI): https://dl.cloudsmith.io/public/moonlight-game-streaming/moonlight-qt/setup.deb.sh then # APT key local url='https://dl.cloudsmith.io/public/moonlight-game-streaming/moonlight-qt/gpg.2F6AE14E1C660D44.key' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-moonlight-qt.gpg --yes" # APT list local distro='debian' suite=${G_DISTRO_NAME/forky/trixie} suite=${suite/trixie/bookworm} (( $G_HW_MODEL < 10 )) && distro='raspbian' # - RISC-V: Supported via Sid suite (( $G_HW_ARCH == 11 )) && suite='sid' G_EXEC eval "echo 'deb https://dl.cloudsmith.io/public/moonlight-game-streaming/moonlight-qt/deb/$distro $suite main' > /etc/apt/sources.list.d/dietpi-moonlight-qt.list" G_AGUP # APT package G_AGI moonlight-qt # Raspberry Pi video setup: https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Raspberry-Pi-4#hevc-and-hdr-support # - Usually requires vc4-fkms-v3d which also serves best performance # - HEVC requires rpivid-v4l2, but it is deprecated and enabled OOTB since Bullseye # - HDR requires vc4-kms-v3d, works on RPi 4 only (?) and breaks starting Moonlight from desktop # => Compatible arrangement with HEVC but no HDR if (( $G_HW_MODEL < 10 )) then /boot/dietpi/func/dietpi-set_hardware rpi-opengl vc4-fkms-v3d /boot/dietpi/func/dietpi-set_hardware rpi-codec 1 fi fi if To_Install 11 # GZDoom then G_AGI gzdoom # Enable KMS/DRM on RPi (( $G_HW_MODEL > 9 )) || /boot/dietpi/func/dietpi-set_hardware rpi-opengl vc4-kms-v3d fi if To_Install 27 # TasmoAdmin then # Install required PHP modules: https://github.com/TasmoAdmin/TasmoAdmin/wiki/Guide-for-Debian-Server-10-(Buster) aDEPS=("php$PHP_VERSION-curl" "php$PHP_VERSION-zip" "php$PHP_VERSION-mbstring" "php$PHP_VERSION-xml") local adeps=("${aDEPS[@]#*-}") # Reinstall: Skip download and install, advice to use internal updater from web UI if [[ -d '/var/www/tasmoadmin' ]] then G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$software_id]} install dir \"/var/www/tasmoadmin\" already exists. Download and install steps will be skipped. - If you want to update ${aSOFTWARE_NAME[$software_id]}, please use the internal updater from web UI. - If you need to reinstall (e.g. broken instance), please manually backup your config files+data, remove the install dir and rerun \"dietpi-software (re)install $software_id\"." G_AGI "${aDEPS[@]}" aDEPS=() else # v3 drops PHP 7.4 support: https://github.com/TasmoAdmin/TasmoAdmin/releases/tag/v3.0.0 if (( $G_DISTRO > 6 )) then local fallback_url='https://github.com/TasmoAdmin/TasmoAdmin/releases/download/v4.3.1/tasmoadmin_v4.3.1.tar.gz' Download_Install "$(curl -sSfL 'https://api.github.com/repos/TasmoAdmin/TasmoAdmin/releases/latest' | mawk -F\" '/^ *"browser_download_url": ".*\/tasmoadmin_v[^"\/]*\.tar\.gz"$/{print $4}')" else Download_Install 'https://github.com/TasmoAdmin/TasmoAdmin/releases/download/v2.4.2/tasmoadmin_v2.4.2.tar.gz' fi G_EXEC chown -R www-data:www-data tasmoadmin G_EXEC mv tasmoadmin /var/www/ fi # Webserver config # - Config file Version local version= (( $G_DISTRO > 6 )) && version='.3' if (( ${aSOFTWARE_INSTALL_STATE[83]} > 0 )) then G_DIETPI-NOTIFY 2 'Apache webserver found, enabling TasmoAdmin specific configuration.' G_EXEC a2enmod setenvif rewrite authz_core authn_core authn_file local tasmoadmin_conf='/etc/apache2/sites-available/dietpi-tasmoadmin.conf' if [[ -f $tasmoadmin_conf ]] then tasmoadmin_conf+='.dietpi-new' G_WHIP_MSG "Existing TasmoAdmin Apache configuration found, will preserve the old one and save the new one for review and comparison to: $tasmoadmin_conf" fi dps_index=$software_id Download_Install 'apache.tasmoadmin.conf' "$tasmoadmin_conf" G_EXEC a2ensite dietpi-tasmoadmin elif (( ${aSOFTWARE_INSTALL_STATE[84]} > 0 )) then G_DIETPI-NOTIFY 2 'Lighttpd webserver found, enabling TasmoAdmin specific configuration.' local tasmoadmin_conf='/etc/lighttpd/conf-available/99-dietpi-tasmoadmin.conf' if [[ -f $tasmoadmin_conf ]] then tasmoadmin_conf+='.dietpi-new' G_WHIP_MSG "Existing TasmoAdmin Lighttpd configuration found, will preserve the old one and save the new one for review and comparison to: $tasmoadmin_conf" fi dps_index=$software_id Download_Install "lighttpd.tasmoadmin$version.conf" "$tasmoadmin_conf" G_EXEC_POST_FUNC(){ [[ $exit_code == 2 ]] && exit_code=0; } # Do not fail if modules are enabled already G_EXEC lighty-enable-mod rewrite dietpi-tasmoadmin elif (( ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then G_DIETPI-NOTIFY 2 'Nginx webserver found, enabling TasmoAdmin specific configuration.' local tasmoadmin_conf='/etc/nginx/sites-dietpi/dietpi-tasmoadmin.conf' if [[ -f $tasmoadmin_conf ]] then owncloud_conf+='.dietpi-new' G_WHIP_MSG "Existing TasmoAdmin Nginx configuration found, will preserve the old one and save the new one for review and comparison to: $tasmoadmin_conf" fi dps_index=$software_id Download_Install "nginx.tasmoadmin$version.conf" "$tasmoadmin_conf" fi # Enable required PHP modules G_EXEC phpenmod "${adeps[@]}" fi if To_Install 206 openhab # openHAB: https://www.openhab.org/docs/installation/linux.html#package-repository-installation then # APT key local url='https://openhab.jfrog.io/artifactory/api/gpg/key/public' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-openhab.gpg --yes" # APT list # - Enable RISC-V support by explicitly defining arch=all, which contains exactly the same packages (well, it's Java...) local arch= (( $G_HW_ARCH == 11 )) && arch=' [arch=all]' G_EXEC eval "echo 'deb$arch https://openhab.jfrog.io/artifactory/openhab-linuxpkg stable main' > /etc/apt/sources.list.d/dietpi-openhab.list" G_AGUP # openHAB 5 requires Java 21 (( $JAVA_VERSION < 21 )) && G_EXEC eval 'cat << '\''_EOF_'\'' > /etc/apt/preferences.d/dietpi-openhab Package: src:openhab* Pin: version 5.* Pin-Priority: -1 _EOF_' # APT package G_AGI openhab G_EXEC systemctl stop openhab # Disable plain HTTP and change HTTPS TCP port to avoid conflicts with SABnzbd, Airsonic-Advanced (8000) and MineOS (8443) G_CONFIG_INJECT 'OPENHAB_HTTPS_PORT=' 'OPENHAB_HTTPS_PORT=8444' /etc/default/openhab G_CONFIG_INJECT 'OPENHAB_HTTP_PORT=' 'OPENHAB_HTTP_PORT=0' /etc/default/openhab # Do all logs to STDOUT => journalctl -u openhab G_EXEC sed --follow-symlinks -i 's|||' /var/lib/openhab/etc/log4j2.xml local line='' last='' grep -n '' /var/lib/openhab/etc/log4j2.xml | while read -r line do line=${line%%:*} (( $line == ${last:-$line} + 1 )) && G_EXEC sed --follow-symlinks -i "${last}d" /var/lib/openhab/etc/log4j2.xml last=$line done G_EXEC rm -f /var/log/openhab/* fi if To_Install 157 home-assistant # Home Assistant then local ha_user='homeassistant' local ha_home="/home/$ha_user" local ha_pyenv_activation=". $ha_home/pyenv-activate.sh" # Obtain latest Python 3.13.y version supported by pyenv local ha_python_version=$(curl -sSfL 'https://api.github.com/repos/pyenv/pyenv/contents/plugins/python-build/share/python-build?ref=master' | mawk -F\" '/^ *"name": "3\.13\.[0-9]*",$/{print $4}' | sort -Vr | head -1) [[ $ha_python_version ]] || { ha_python_version='3.13.7'; G_DIETPI-NOTIFY 1 "Automatic latest Python version detection failed. Version \"$ha_python_version\" will be installed as fallback, but a newer version might be available. Please report this at: https://github.com/MichaIng/DietPi/issues"; } G_DIETPI-NOTIFY 2 "Home Assistant user: $ha_user" G_DIETPI-NOTIFY 2 "Home Assistant home: $ha_home" G_DIETPI-NOTIFY 2 "pyenv activation: \"$ha_pyenv_activation\"" G_DIETPI-NOTIFY 2 "pyenv Python version: $ha_python_version" # User Create_User -G dialout,gpio,i2c -d "$ha_home" "$ha_user" G_EXEC mkdir -p "$ha_home" G_EXEC chown "$ha_user:$ha_user" "$ha_home" # Dependencies PYTHON_VERSION=$ha_python_version Python_Deps -u "$ha_user" av bcrypt cryptography numpy pillow pyenv pymicro-vad # - Custom dependencies, e.g. MariaDB support: G_AGI libmariadb-dev; pip3 install mysqlclient|PyMySQL local custom_apt_deps=$(sed -n '/^[[:blank:]]*SOFTWARE_HOMEASSISTANT_APT_DEPS=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) mapfile -t -d' ' -O "${#aDEPS[@]}" aDEPS < <(echo -n "$custom_apt_deps") # - Install isal compression library as faster drop-in replacement for zlib, to address a warning by aiohttp_fast_zlib: https://github.com/MichaIng/DietPi/issues/7525 local custom_pip_deps="isal $(sed -n '/^[[:blank:]]*SOFTWARE_HOMEASSISTANT_PIP_DEPS=/{s/^[^=]*=//p;q}' /boot/dietpi.txt)" # Install pyenv to $ha_home Download_Install 'https://github.com/pyenv/pyenv/archive/master.tar.gz' G_EXEC chown -R "$ha_user:$ha_user" pyenv-master # - Start with fresh instance, to allow clean pyenv and Python updates and fix broken instances. All userdata and configs are preserved in: /mnt/dietpi_userdata/homeassistant [[ -d $ha_home/.pyenv ]] && G_EXEC rm -R "$ha_home/.pyenv" [[ -f $ha_home/.python-version ]] && G_EXEC rm "$ha_home/.python-version" # pre-v9.13: remove "pyenv local" info as we use "pyenv global" now, stored to $ha_home/.python/version instead [[ -d '/srv/homeassistant' ]] && G_EXEC rm -R /srv/homeassistant # pre-v6-27 G_EXEC mv pyenv-master "$ha_home/.pyenv" # Link config and data to DietPi userdata if [[ ! -d '/mnt/dietpi_userdata/homeassistant' ]] then if [[ -d $ha_home/.homeassistant ]] then G_EXEC mv "$ha_home/.homeassistant" /mnt/dietpi_userdata/homeassistant else G_EXEC mkdir /mnt/dietpi_userdata/homeassistant fi fi [[ -d $ha_home/.homeassistant ]] && G_EXEC rm -R "$ha_home/.homeassistant" G_EXEC ln -sf /mnt/dietpi_userdata/homeassistant "$ha_home/.homeassistant" # Reset and merge pyenv and HA Python environment to avoid version mismatches on Python upgrades: https://github.com/MichaIng/DietPi/issues/6117 [[ -d '/mnt/dietpi_userdata/homeassistant/deps' ]] && G_EXEC rm -R /mnt/dietpi_userdata/homeassistant/deps G_EXEC ln -sf "$ha_home/.pyenv/versions/$ha_python_version/lib/python${ha_python_version%.*}/site-packages" /mnt/dietpi_userdata/homeassistant/deps # Disable pip cache G_EXEC mkdir -p "$ha_home/.pip" G_EXEC eval "echo -e '[global]\nno-cache-dir=true' > '$ha_home/.pip/pip.conf'" # Generate script to activate pyenv: This must be sourced from the originating shell, hence it does not require execute permissions. echo "#!/bin/dash if [ \$(whoami) != '$ha_user' ]; then echo '[FAILED] This pyenv must be activated as user \"$ha_user\". Aborting...' kill -INT \$\$ fi cd $ha_home # Permit uv to install into system Python: https://github.com/astral-sh/uv/issues/7907 export PATH=\"$ha_home/.pyenv/bin:\$PATH\" UV_SYSTEM_PYTHON=1 eval \"\$(pyenv init -)\" [ -f '.cargo/env' ] && . .cargo/env" > "$ha_home/pyenv-activate.sh" local version= # Bullseye: v2025.1.4 is the last which supports old SQLite: https://github.com/MichaIng/DietPi/issues/7374 (( $G_DISTRO < 7 )) && version='==2025.1.4' G_EXEC_DESC="Compiling and installing Python $ha_python_version into pyenv, which will take a while ..." G_EXEC_OUTPUT=1 G_EXEC runuser -u "$ha_user" -- dash -c "$ha_pyenv_activation; exec pyenv install $ha_python_version" G_EXEC_DESC="Set Python $ha_pyenv_activation as global version for this pyenv instance" G_EXEC_OUTPUT=1 G_EXEC runuser -u "$ha_user" -- dash -c "$ha_pyenv_activation; exec pyenv global $ha_python_version" G_EXEC_DESC='Upgrading base modules: pip setuptools wheel' G_EXEC_OUTPUT=1 G_EXEC runuser -u "$ha_user" -- dash -c "$ha_pyenv_activation; exec pip3 install -U pip setuptools wheel" G_EXEC_DESC="Installing additional dependencies: $custom_pip_deps" G_EXEC_OUTPUT=1 G_EXEC runuser -u "$ha_user" -- dash -c "$ha_pyenv_activation; exec pip3 install $custom_pip_deps" G_EXEC_DESC='Installing Home Assistant core module' G_EXEC_OUTPUT=1 G_EXEC runuser -u "$ha_user" -- dash -c "$ha_pyenv_activation; exec pip3 install homeassistant$version" # Generate script to launch HA using pyenv echo "#!/bin/dash $ha_pyenv_activation exec hass -c '/mnt/dietpi_userdata/homeassistant'" > "$ha_home/homeassistant-start.sh" G_EXEC chmod +x "$ha_home/homeassistant-start.sh" # Generate script to update HA within pyenv echo "#!/bin/dash exec sudo -u $ha_user dash -c '$ha_pyenv_activation; exec pip3 install -U homeassistant$version'" > "$ha_home/homeassistant-update.sh" G_EXEC chmod +x "$ha_home/homeassistant-update.sh" # Service cat << _EOF_ > /etc/systemd/system/home-assistant.service [Unit] Description=Home Assistant (DietPi) Wants=network-online.target After=network-online.target mariadb.service [Service] SyslogIdentifier=Home Assistant User=$ha_user ExecStart=$ha_home/homeassistant-start.sh RestartForceExitStatus=100 [Install] WantedBy=multi-user.target _EOF_ # Download HACS Download_Install 'https://github.com/hacs/integration/releases/latest/download/hacs.zip' hacs [[ -d '/mnt/dietpi_userdata/homeassistant/custom_components/hacs' ]] && G_EXEC rm -R /mnt/dietpi_userdata/homeassistant/custom_components/hacs G_EXEC mkdir -p /mnt/dietpi_userdata/homeassistant/custom_components G_EXEC mv hacs /mnt/dietpi_userdata/homeassistant/custom_components/ G_EXEC chown -R "$ha_user:$ha_user" /mnt/dietpi_userdata/homeassistant G_DIETPI-NOTIFY 2 "Home Assistant Community Store (HACS) has been installed in addition. To activate it, follow this guide: https://hacs.xyz/docs/configuration/basic/" fi if To_Install 181 papermc # PaperMC then # Make sure user agrees to the EULA if [[ -f '/mnt/dietpi_userdata/papermc/eula.txt' ]] || G_WHIP_BUTTON_OK_TEXT='Yes' G_WHIP_BUTTON_CANCEL_TEXT='Abort' G_WHIP_YESNO 'Do you agree to the Minecraft EULA found at:\n\nhttps://account.mojang.com/documents/minecraft_eula' then # Collect latest build of latest supported version of PaperMC local url='https://api.papermc.io/v2/projects/paper' # - Minecraft 1.20.5 and above requires Java 21: https://minecraft.wiki/w/Java_Edition_1.20.5 local version='1.20.4' (( $JAVA_VERSION < 21 )) || { version=$(curl -sSfL "$url"); version=${version%\"*} version=${version##*\"}; } local build=$(curl -sSfL "$url/versions/$version"); build=${build%]*} build=${build##*[,[]} #local file=$(curl -sSfL "$url/versions/$version/builds/$build"); file=${file##*\"name\":\"} file=${file%%\"*} # Download and install PaperMC Download_Install "$url/versions/$version/builds/$build/downloads/paper-$version-$build.jar" /opt/papermc/paperclip.jar G_EXEC mkdir -p /mnt/dietpi_userdata/papermc G_EXEC eval 'echo '\''eula=true'\'' > /mnt/dietpi_userdata/papermc/eula.txt' # User Create_User -d /mnt/dietpi_userdata/papermc papermc # Bedrock compatibility G_WHIP_BUTTON_OK_TEXT='Yes' G_WHIP_BUTTON_CANCEL_TEXT='Skip' [[ -f '/mnt/dietpi_userdata/papermc/plugins/Geyser-Spigot.jar' ]] && G_WHIP_DEFAULT_ITEM='Yes' if G_WHIP_YESNO 'Would you like to install the Geyser and Floodgate plugins for compatibility with Bedrock Edition?\n\nNote that this may be buggy.' then local version='2.2.3' (( $JAVA_VERSION < 21 )) || version='latest' Download_Install "https://download.geysermc.org/v2/projects/geyser/versions/$version/builds/latest/downloads/spigot" /mnt/dietpi_userdata/papermc/plugins/Geyser-Spigot.jar Download_Install 'https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot' /mnt/dietpi_userdata/papermc/plugins/floodgate-spigot.jar fi # Minecraft rcon client for remote administration and server maintenance scripts aDEPS=('gcc' 'libc6-dev') Download_Install 'https://github.com/Tiiffi/mcrcon/archive/master.tar.gz' G_EXEC gcc -g0 -O3 mcrcon-master/mcrcon.c -o /usr/local/bin/mcrcon G_EXEC rm -R mcrcon-master G_EXEC strip --remove-section=.comment --remove-section=.note /usr/local/bin/mcrcon # Link logs to RAM G_EXEC rm -Rf /mnt/dietpi_userdata/papermc/logs G_EXEC ln -s /var/log/papermc /mnt/dietpi_userdata/papermc/logs # Permissions G_EXEC chown -R papermc:papermc /mnt/dietpi_userdata/papermc # Assure 512 MiB heap size and 1.5 GiB overall memory (-100 MiB to avoid tiny swap space) local memory_limit=$JAVA_MAX_HEAP_SIZE if (( $memory_limit < 1024 )) then memory_limit=512 if (( $RAM_TOTAL < 1436 )) then G_DIETPI-NOTIFY 2 'Stable PaperMC operation requires at least 1.5 GiB system memory. We will now increase your swap size to satisfy this requirement.' /boot/dietpi/func/dietpi-set_swapfile $(( 1536 - $RAM_PHYS )) # Apply 1 GiB heap size on 2 GiB+ physical RAM devices elif (( $RAM_PHYS > 1848 )) then memory_limit=1024 fi fi # Service cat << _EOF_ > /etc/systemd/system/papermc.service [Unit] Description=PaperMC (DietPi) Documentation=https://paper.readthedocs.io/ Wants=network-online.target After=network-online.target [Service] SyslogIdentifier=PaperMC User=papermc LogsDirectory=papermc WorkingDirectory=/mnt/dietpi_userdata/papermc ExecStart=$JAVA_PATH -mx${memory_limit}m -jar /opt/papermc/paperclip.jar --nogui --noconsole SuccessExitStatus=143 [Install] WantedBy=multi-user.target _EOF_ # Config if [[ -f '/mnt/dietpi_userdata/papermc/plugins/Geyser-Spigot.jar' ]] then Create_Config /mnt/dietpi_userdata/papermc/plugins/Geyser-Spigot/config.yml papermc 1800 1 && G_CONFIG_INJECT 'auth-type:[[:blank:]]' ' auth-type: floodgate' /mnt/dietpi_userdata/papermc/plugins/Geyser-Spigot/config.yml else Create_Config /mnt/dietpi_userdata/papermc/permissions.yml papermc 1800 1 fi G_CONFIG_INJECT 'enable-rcon=' 'enable-rcon=true' /mnt/dietpi_userdata/papermc/server.properties GCI_PASSWORD=1 G_CONFIG_INJECT 'rcon.password=' "rcon.password=$GLOBAL_PW" /mnt/dietpi_userdata/papermc/server.properties else aSOFTWARE_INSTALL_STATE[$software_id]=0 G_DIETPI-NOTIFY 2 "${aSOFTWARE_NAME[$software_id]} install skipped due to outstanding EULA agreement" fi fi if To_Install 140 domoticz # Domoticz then G_AGI domoticz fi if To_Install 202 # Rclone then # RISC-V: No upstream packages yet, hence use Debian repo if (( $G_HW_ARCH == 11 )) then G_AGI rclone else case $G_HW_ARCH in 1) local arch='arm-v6';; 2) local arch='arm-v7';; 3) local arch='arm64';; *) local arch='amd64';; esac local fallback_url="https://github.com/rclone/rclone/releases/download/v1.71.0/rclone-v1.71.0-linux-$arch.deb" Download_Install "$(curl -sSfL 'https://api.github.com/repos/rclone/rclone/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/rclone-v[^\"\/]*-linux-$arch.deb\"$/{print \$4}")" fi fi if To_Install 209 # Restic then case $G_HW_ARCH in 3) local arch='arm64';; 10) local arch='amd64';; 11) local arch='riscv64';; *) local arch='arm';; esac local fallback_url="https://github.com/restic/restic/releases/download/v0.18.0/restic_0.18.0_linux_$arch.bz2" Download_Install "$(curl -sSfL 'https://api.github.com/repos/restic/restic/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/restic_[^\"\/]*_linux_$arch\.bz2\"$/{print \$4}")" /usr/local/bin/restic G_EXEC chmod +x /usr/local/bin/restic fi if To_Install 210 # MediaWiki then # Install required PHP modules: https://www.mediawiki.org/wiki/Manual:Installation_requirements#PHP aDEPS=("php$PHP_VERSION-gd" "php$PHP_VERSION-intl") # - Add JSON module for PHP7, as it does not exist (embedded in core package) on PHP8 [[ $PHP_VERSION == 8* ]] || aDEPS+=("php$PHP_VERSION-json") local php_modules=("${aDEPS[@]##*-}") # Create MariaDB database and user if [[ -d '/mnt/dietpi_userdata/mysql/mediawiki' ]] then G_DIETPI-NOTIFY 2 'MediaWiki MariaDB database found, will NOT overwrite.' else /boot/dietpi/func/create_mysql_db mediawiki mediawiki "$GLOBAL_PW" fi # Get latest version local fallback_url='https://releases.wikimedia.org/mediawiki/1.44/mediawiki-1.44.0.tar.gz' Download_Install "$(curl -sSfL 'https://www.mediawiki.org/wiki/Download' | grep -o 'https://releases\.wikimedia\.org/mediawiki/[^/"]*/mediawiki-[^"]*\.tar\.gz' | head -1)" # Enable required PHP modules G_EXEC phpenmod "${php_modules[@]}" # Webserver configs # - Lighttpd if (( ${aSOFTWARE_INSTALL_STATE[84]} > 0 )) then [[ -f '/etc/lighttpd/conf-enabled/05-setenv.conf' ]] || G_EXEC lighty-enable-mod setenv cat << '_EOF_' > /etc/lighttpd/conf-available/98-dietpi-mediawiki.conf $HTTP["url"] =~ "^/wiki/images($|/)" { setenv.set-response-header = ("X-Content-Type-Options" => "nosniff") } _EOF_ [[ -f '/etc/lighttpd/conf-enabled/98-dietpi-mediawiki.conf' ]] || lighty-enable-mod dietpi-mediawiki # - Nginx elif (( ${aSOFTWARE_INSTALL_STATE[85]} > 0 )) then cat << '_EOF_' > /etc/nginx/sites-dietpi/dietpi-mediawiki.conf location ^~ /wiki/images { add_header X-Content-Type-Options "nosniff" always; } _EOF_ fi # Reinstall: Clean install but preserve existing config and uploaded images if [[ -f '/var/www/wiki/LocalSettings.php' ]] then G_EXEC mv /var/www/wiki/LocalSettings.php mediawiki-*/ G_EXEC chmod 600 mediawiki-*/LocalSettings.php fi if [[ -d '/var/www/wiki/images' ]] then G_EXEC cp -a mediawiki-*/images/{.htaccess,README} /var/www/wiki/images/ G_EXEC cp -a /var/www/wiki/images/. mediawiki-*/images/ fi G_EXEC chown -R www-data:www-data mediawiki-* [[ -d '/var/www/wiki' ]] && G_EXEC rm -R /var/www/wiki # Move new instance in place G_EXEC mv mediawiki-* /var/www/wiki fi if To_Install 211 homebridge # Homebridge then # APT key local url='https://repo.homebridge.io/KEY.gpg' G_CHECK_URL "$url" G_EXEC eval "curl -sSfL '$url' | gpg --dearmor -o /etc/apt/trusted.gpg.d/dietpi-homebridge.gpg --yes" # APT list G_EXEC eval 'echo '\''deb https://repo.homebridge.io stable main'\'' > /etc/apt/sources.list.d/dietpi-homebridge.list' G_AGUP G_AGI homebridge G_EXEC systemctl stop homebridge # Workaround for bug with wrong home directory /nonexistent G_EXEC usermod -d /var/lib/homebridge homebridge fi if To_Install 205 # Homer then # Download the latest release Download_Install 'https://github.com/bastienwirtz/homer/releases/latest/download/homer.zip' homer # Backup existing instance if [[ -d '/var/www/homer' ]] then G_DIETPI-NOTIFY 2 'Existing Homer instance found, backing up to /mnt/dietpi_userdata/homer_backup ...' [[ -d '/mnt/dietpi_userdata/homer_backup' ]] && G_EXEC rm -R /mnt/dietpi_userdata/homer_backup G_EXEC cp -a /var/www/homer /mnt/dietpi_userdata/homer_backup G_DIETPI-NOTIFY 2 'Removing old assets with hash in file name ...' G_EXEC rm -Rf /var/www/homer/{workbox-*.js,resources} fi # Install latest release, preserve existing config G_EXEC cp -a homer/. /var/www/homer/ G_EXEC rm -R homer [[ -f '/var/www/homer/assets/config.yml' ]] || G_EXEC cp /var/www/homer/assets/config.yml{.dist,} fi if To_Install 198 filebrowser # File Browser then case $G_HW_ARCH in 1) local arch='armv6';; 2) local arch='armv7';; 3) local arch='arm64';; 11) local arch='riscv64';; *) local arch='amd64';; esac local fallback_url="https://github.com/filebrowser/filebrowser/releases/download/v2.43.0/linux-$arch-filebrowser.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/filebrowser/filebrowser/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/linux-$arch-filebrowser\.tar\.gz\"$/{print \$4}")" ./filebrowser/ # Reinstall [[ -d '/opt/filebrowser' ]] && G_EXEC rm -R /opt/filebrowser # Install G_EXEC mv filebrowser /opt/ # User G_EXEC mkdir -p /mnt/dietpi_userdata/filebrowser Create_User -g dietpi -d /mnt/dietpi_userdata/filebrowser filebrowser # Config if not exist if [[ ! -f '/mnt/dietpi_userdata/filebrowser/filebrowser.db' ]] then G_EXEC cd /mnt/dietpi_userdata/filebrowser G_EXEC /opt/filebrowser/filebrowser config init # Reduce minimum password length to match default software password if it is shorter local extra_args=() (( ${#GLOBAL_PW} < 12 )) && extra_args+=('--minimum-password-length' "${#GLOBAL_PW}") G_EXEC /opt/filebrowser/filebrowser config set -a 0.0.0.0 -p 8084 -r /mnt "${extra_args[@]}" G_EXEC_DESC='Setting up File Browser login user "dietpi"' G_EXEC /opt/filebrowser/filebrowser users add dietpi "$GLOBAL_PW" --perm.admin fi # Permissions G_EXEC chown -R filebrowser:root /mnt/dietpi_userdata/filebrowser /opt/filebrowser # Service cat << '_EOF_' > /etc/systemd/system/filebrowser.service [Unit] Description=File Browser (DietPi) Documentation=https://filebrowser.org/ Wants=network-online.target After=network-online.target remote-fs.target [Service] User=filebrowser UMask=002 ExecStart=/opt/filebrowser/filebrowser -d /mnt/dietpi_userdata/filebrowser/filebrowser.db [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 199 spotifyd # Spotifyd then # Obtain supported version, variant and related dependencies. It became very complicated: https://github.com/MichaIng/DietPi/issues/6419 local arch='' variant='full' version='' aDEPS=('libdbus-1-3' 'libpulse0') case $G_HW_ARCH in 1) arch='armv6' variant='slim' version='0.3.5' aDEPS=();; # Last supported version and only supported variant for ARMv6 2) arch='armv7';; 3) arch='aarch64';; *) arch='x86_64';; esac # Download specific version if given, else obtain latest version from GitHub API if [[ $version ]] then Download_Install "https://github.com/Spotifyd/spotifyd/releases/download/v$version/spotifyd-linux-$arch-$variant.tar.gz" /opt/spotifyd else local fallback_url="https://github.com/Spotifyd/spotifyd/releases/download/v0.4.1/spotifyd-linux-$arch-$variant.tar.gz" Download_Install "$(curl -sSfL 'https://api.github.com/repos/Spotifyd/spotifyd/releases/latest' | mawk -F\" "/^ *\"browser_download_url\": \".*\/spotifyd-linux-$arch-$variant\.tar\.gz\"$/{print \$4}")" /opt/spotifyd fi # User Create_User -G audio -d /mnt/dietpi_userdata/spotifyd spotifyd # Config: Do not touch on reinstall if [[ ! -f '/mnt/dietpi_userdata/spotifyd/spotifyd.conf' ]] then G_EXEC mkdir -p /mnt/dietpi_userdata/spotifyd/cache dps_index=$software_id Download_Install 'spotifyd.conf' /mnt/dietpi_userdata/spotifyd/spotifyd.conf G_EXEC chmod 0600 /mnt/dietpi_userdata/spotifyd/spotifyd.conf fi # Service: https://github.com/Spotifyd/spotifyd/blob/master/contrib/spotifyd.service cat << '_EOF_' > /etc/systemd/system/spotifyd.service [Unit] Description=Spotifyd (DietPi) Wants=network-online.target After=network-online.target sound.target [Service] User=spotifyd WorkingDirectory=/mnt/dietpi_userdata/spotifyd ExecStart=/opt/spotifyd/spotifyd --no-daemon --config-path=/mnt/dietpi_userdata/spotifyd/spotifyd.conf [Install] WantedBy=multi-user.target _EOF_ # Permissions G_EXEC chown -R spotifyd:root /mnt/dietpi_userdata/spotifyd G_EXEC chmod +x /opt/spotifyd/spotifyd fi if To_Install 185 # Portainer then # Check for existing Portainer container local container=$(docker container ls -a | mawk '/portainer\/portainer(-ce)?( |$)/{print $1;exit}') [[ $container ]] && G_EXEC docker container rm -f "$container" local image=$(docker image ls -a | mawk '/portainer\/portainer(-ce)?( |$)/{print $3;exit}') [[ $image ]] && G_EXEC docker image rm "$image" docker volume ls -q | grep -xq 'portainer_data' || G_EXEC docker volume create portainer_data # Deploy the Portainer container G_DIETPI-NOTIFY 2 'Portainer will be deployed now. This could take a while...' G_EXEC_OUTPUT=1 G_EXEC docker run -d -p '9002:9000' -p '9442:9443' --name=portainer --restart=always -v '/run/docker.sock:/var/run/docker.sock' -v '/etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro' -v 'portainer_data:/data' 'portainer/portainer-ce' fi if To_Install 141 adsb-setup adsb-docker # ADS-B Feeder then # clone the adsb-feeder repo into /tmp G_EXEC_OUTPUT=1 G_EXEC git clone -b dietpi 'https://github.com/dirkhh/adsb-feeder-image' /tmp/adsb-feeder # remove the service that isn't needed for an app install on DietPi and install the rest G_EXEC cd /tmp/adsb-feeder/src/modules/adsb-feeder/filesystem/root G_EXEC rm ./usr/lib/systemd/system/adsb-bootstrap.service G_EXEC rm ./usr/lib/systemd/system/adsb-update.service G_EXEC rm ./usr/lib/systemd/system/adsb-update.timer # Fix bash path on potentially non-usr-merged systems [[ -f '/usr/bin/bash' ]] || G_EXEC sed --follow-symlinks -i 's|/usr/bin/bash|/bin/bash|' ./usr/lib/systemd/system/adsb-*.service G_EXEC mv ./usr/lib/systemd/system/* /etc/systemd/system/ # determine the version local ADSB_FEEDER_DATE_COMPONENT=$(git log -20 --date='format:%y%m%d' --format='%ad' | uniq -c | mawk '{print $2"."$1;exit}') local ADSB_FEEDER_TAG_COMPONENT=$(git describe --match 'v[0-9]*' --long | sed 's/-[0-9]*-g[0-9a-f]*//') local ADSB_FEEDER_VERSION="$ADSB_FEEDER_TAG_COMPONENT(dietpi)-$ADSB_FEEDER_DATE_COMPONENT" # create the target directory for the app and populated with the code from the git checkout [[ -d '/opt/adsb' ]] && G_EXEC rm -R /opt/adsb G_EXEC mv /tmp/adsb-feeder/src/modules/adsb-feeder/filesystem/root/opt/adsb /opt/ G_EXEC cd /opt/adsb # remove the git clone of the repo we installed from G_EXEC rm -R /tmp/adsb-feeder # create a symlink so the config files reside where they should be in /mnt/dietpi_userdata/adsb-feeder G_EXEC mkdir -p /mnt/dietpi_userdata/adsb-feeder/config G_EXEC ln -s /mnt/dietpi_userdata/adsb-feeder/config . # set the 'image name' and version that are shown in the footer of the Web UI and mark as app, not image G_EXEC eval 'echo '\''ADSB Feeder app running on DietPi'\'' > feeder-image.name' G_EXEC eval "echo '$ADSB_FEEDER_VERSION' > adsb.im.version" G_EXEC rm -f os.adsb.feeder.image G_EXEC touch app.adsb.feeder.image # get the Python modules G_EXEC_OUTPUT=1 G_EXEC pip3 install -U flask requests # finally ensure that /run allows executables (this is needed for the containers to be able to not do excessive # writes to physical storage - which might be an SD card) G_EXEC mount -o remount,exec /run fi if To_Install 172 # WireGuard then # Pre-v8.12: Purge DKMS as it is not required and might mess with available kernel module dpkg-query -s wireguard-dkms &> /dev/null && G_AGP wireguard-dkms # Install user space tools G_AGI wireguard-tools iptables qrencode Configure_iptables # Server/Client choice G_WHIP_MENU_ARRAY=( 'Server' ': Use this machine as VPN server and allow clients to connect to it.' 'Client' ': Use this machine as VPN client to connect to another VPN server or service provider.' ) G_WHIP_DEFAULT_ITEM=$(sed -n '/^[[:blank:]]*SOFTWARE_WIREGUARD_MODE=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ ${G_WHIP_DEFAULT_ITEM,,} == 'client' ]] || G_WHIP_DEFAULT_ITEM='Server' G_WHIP_NOCANCEL=1 G_WHIP_MENU 'Please choose if this machine should be set up as VPN server or client:' G_CONFIG_INJECT 'SOFTWARE_WIREGUARD_MODE=' "SOFTWARE_WIREGUARD_MODE=$G_WHIP_RETURNED_VALUE" /boot/dietpi.txt # Server choice if [[ $G_WHIP_RETURNED_VALUE == 'Server' ]] then # Public IP/domain and desired WireGuard server port G_WHIP_DEFAULT_ITEM=$(sed -n '/^[[:blank:]]*SOFTWARE_PUBLIC_DOMAIN_NAME=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $G_WHIP_DEFAULT_ITEM ]] || G_WHIP_DEFAULT_ITEM=$(find /etc/letsencrypt/live -mindepth 1 -maxdepth 1 -type d -print -quit 2> /dev/null) [[ $G_WHIP_DEFAULT_ITEM ]] || G_WHIP_DEFAULT_ITEM=$(hostname -f) G_WHIP_NOCANCEL=1 G_WHIP_INPUTBOX 'Please enter your servers public IP/domain for WireGuard client access:' local domain=${G_WHIP_RETURNED_VALUE#http*://} GCI_PRESERVE=1 G_CONFIG_INJECT 'SOFTWARE_PUBLIC_DOMAIN_NAME=' "SOFTWARE_PUBLIC_DOMAIN_NAME=$domain" /boot/dietpi.txt G_WHIP_DEFAULT_ITEM=$(sed -n '/^[[:blank:]]*SOFTWARE_WIREGUARD_PORT=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) disable_error=1 G_CHECK_VALIDINT "$G_WHIP_DEFAULT_ITEM" 0 || G_WHIP_DEFAULT_ITEM=51820 G_WHIP_NOCANCEL=1 G_WHIP_INPUTBOX_REGEX='^[1-9][0-9]*$' G_WHIP_INPUTBOX_REGEX_TEXT='a valid port number' G_WHIP_INPUTBOX 'Please enter the network port that will be used to access your WireGuard server:\n NB: This port needs to be forwarded by your router and/or opened in your firewall settings. Default value is: 51820' local port=$G_WHIP_RETURNED_VALUE # Create everything inside WireGuard config dir G_EXEC cd /etc/wireguard # For security reasons set umask to 0077 G_EXEC umask 0077 # Create server and client keys [[ -f 'server_private.key' ]] || wg genkey > server_private.key [[ -f 'server_public.key' ]] || wg pubkey < server_private.key > server_public.key [[ -f 'client_private.key' ]] || wg genkey > client_private.key [[ -f 'client_public.key' ]] || wg pubkey < client_private.key > client_public.key # Server config [[ -f 'wg0.conf' ]] || cat << _EOF_ > wg0.conf || exit 1 [Interface] Address = 10.9.0.1/24 PrivateKey = $( wg0-client.conf [Interface] Address = 10.9.0.2/24 PrivateKey = $( /mnt/dietpi_userdata/soju/config db sqlite3 /mnt/dietpi_userdata/soju/data.db message-store fs /mnt/dietpi_userdata/soju/logs listen irc+insecure:// listen unix+admin:// _EOF_ fi # User Create_User -d /mnt/dietpi_userdata/soju soju G_EXEC chown 'soju:soju' -R /mnt/dietpi_userdata/soju G_EXEC chmod 0660 -R /mnt/dietpi_userdata/soju G_EXEC chmod 0770 /mnt/dietpi_userdata/soju # Service: https://github.com/emersion/soju/blob/master/contrib/soju.service # - CAP_NET_BIND_SERVICE needed for builtin identd server: https://github.com/emersion/soju/blob/master/doc/packaging.md#binding-to-privileged-ports cat << '_EOF_' > /etc/systemd/system/soju.service [Unit] Description=soju IRC bouncer service Documentation=https://soju.im/ Documentation=man:soju(1) man:sojuctl(1) Wants=network-online.target After=network-online.target [Service] User=soju RuntimeDirectory=soju WorkingDirectory=/mnt/dietpi_userdata/soju AmbientCapabilities=CAP_NET_BIND_SERVICE ExecStart=/usr/local/bin/soju ExecReload=/bin/kill -HUP $MAINPID [Install] WantedBy=multi-user.target _EOF_ fi if To_Install 169 lazylibrarian # LazyLibrarian then # Dependencies for venv aDEPS=('python3-venv') # Create user and data dir G_EXEC mkdir -p /mnt/dietpi_userdata/lazylibrarian Create_User -d /mnt/dietpi_userdata/lazylibrarian lazylibrarian # Download and unpack to /mnt/dietpi_userdata/lazylibrarian/LazyLibrarian-master Download_Install 'https://gitlab.com/LazyLibrarian/LazyLibrarian/-/archive/master/LazyLibrarian-master.tar.gz' /mnt/dietpi_userdata/lazylibrarian # Set permissions G_EXEC chown -R 'lazylibrarian:lazylibrarian' -R /mnt/dietpi_userdata/lazylibrarian G_EXEC chmod 0770 /mnt/dietpi_userdata/lazylibrarian # Python venv and install G_EXEC sudo -u lazylibrarian python3 -m venv /mnt/dietpi_userdata/lazylibrarian/venv G_EXEC_OUTPUT=1 sudo -u lazylibrarian /mnt/dietpi_userdata/lazylibrarian/venv/bin/python3 -m pip install -e /mnt/dietpi_userdata/lazylibrarian/LazyLibrarian-master # Service cat << '_EOF_' > /etc/systemd/system/lazylibrarian.service [Unit] Description=LazyLibrarian Documentation=https://lazylibrarian.gitlab.io Wants=network-online.target After=network-online.target [Service] User=lazylibrarian Group=lazylibrarian WorkingDirectory=/mnt/dietpi_userdata/lazylibrarian/LazyLibrarian-master ExecStart=/mnt/dietpi_userdata/lazylibrarian/venv/bin/python3 /mnt/dietpi_userdata/lazylibrarian/LazyLibrarian-master/LazyLibrarian.py Restart=always StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target _EOF_ fi } # $1: 0=None -1=Dropbear -2=OpenSSH Apply_SSHServer_Choices() { if (( $1 == 0 )) then [[ ${aSOFTWARE_INSTALL_STATE[104]} == [01] ]] && aSOFTWARE_INSTALL_STATE[104]=0 || aSOFTWARE_INSTALL_STATE[104]=-1 [[ ${aSOFTWARE_INSTALL_STATE[105]} == [01] ]] && aSOFTWARE_INSTALL_STATE[105]=0 || aSOFTWARE_INSTALL_STATE[105]=-1 elif (( $1 == -2 )) then [[ ${aSOFTWARE_INSTALL_STATE[104]} == [01] ]] && aSOFTWARE_INSTALL_STATE[104]=0 || aSOFTWARE_INSTALL_STATE[104]=-1 [[ ${aSOFTWARE_INSTALL_STATE[105]} == [01] ]] && aSOFTWARE_INSTALL_STATE[105]=1 || aSOFTWARE_INSTALL_STATE[105]=2 else [[ ${aSOFTWARE_INSTALL_STATE[104]} == [01] ]] && aSOFTWARE_INSTALL_STATE[104]=1 || aSOFTWARE_INSTALL_STATE[104]=2 [[ ${aSOFTWARE_INSTALL_STATE[105]} == [01] ]] && aSOFTWARE_INSTALL_STATE[105]=0 || aSOFTWARE_INSTALL_STATE[105]=-1 fi } # $1: 0=None -1=DietPi-RAMlog #1 -2=DietPi-RAMlog #2 -3=Full Apply_Logging_Choices() { if (( $1 == 0 )) then [[ ${aSOFTWARE_INSTALL_STATE[101]} == [01] ]] && aSOFTWARE_INSTALL_STATE[101]=0 || aSOFTWARE_INSTALL_STATE[101]=-1 [[ ${aSOFTWARE_INSTALL_STATE[102]} == [01] ]] && aSOFTWARE_INSTALL_STATE[102]=0 || aSOFTWARE_INSTALL_STATE[102]=-1 [[ ${aSOFTWARE_INSTALL_STATE[103]} == [01] ]] && aSOFTWARE_INSTALL_STATE[103]=0 || aSOFTWARE_INSTALL_STATE[103]=-1 elif (( $1 == -2 )) then [[ ${aSOFTWARE_INSTALL_STATE[101]} == [01] ]] && aSOFTWARE_INSTALL_STATE[101]=0 || aSOFTWARE_INSTALL_STATE[101]=-1 [[ ${aSOFTWARE_INSTALL_STATE[102]} == [01] ]] && aSOFTWARE_INSTALL_STATE[102]=0 || aSOFTWARE_INSTALL_STATE[102]=-1 [[ ${aSOFTWARE_INSTALL_STATE[103]} == [01] ]] && aSOFTWARE_INSTALL_STATE[103]=1 || aSOFTWARE_INSTALL_STATE[103]=2 elif (( $1 == -3 )) then [[ ${aSOFTWARE_INSTALL_STATE[101]} == [01] ]] && aSOFTWARE_INSTALL_STATE[101]=1 || aSOFTWARE_INSTALL_STATE[101]=2 [[ ${aSOFTWARE_INSTALL_STATE[102]} == [01] ]] && aSOFTWARE_INSTALL_STATE[102]=1 || aSOFTWARE_INSTALL_STATE[102]=2 [[ ${aSOFTWARE_INSTALL_STATE[103]} == [01] ]] && aSOFTWARE_INSTALL_STATE[103]=0 || aSOFTWARE_INSTALL_STATE[103]=-1 else set -- '-1' [[ ${aSOFTWARE_INSTALL_STATE[101]} == [01] ]] && aSOFTWARE_INSTALL_STATE[101]=0 || aSOFTWARE_INSTALL_STATE[101]=-1 [[ ${aSOFTWARE_INSTALL_STATE[102]} == [01] ]] && aSOFTWARE_INSTALL_STATE[102]=0 || aSOFTWARE_INSTALL_STATE[102]=-1 [[ ${aSOFTWARE_INSTALL_STATE[103]} == [01] ]] && aSOFTWARE_INSTALL_STATE[103]=1 || aSOFTWARE_INSTALL_STATE[103]=2 fi INDEX_LOGGING=$1 # If DietPi-RAMlog is and stays installed, apply logging index now to make the change permanent for DietPi-LogClear even if no actual install is required. [[ $INDEX_LOGGING == -[12] && ${aSOFTWARE_INSTALL_STATE[103]} == 2 ]] && G_CONFIG_INJECT 'INDEX_LOGGING=' "INDEX_LOGGING=$INDEX_LOGGING" /boot/dietpi/.installed } Install_Apply_GPU_Settings() { # Offer to install GPU driver when Xserver installed (x86_64 support currently only) if (( $G_HW_ARCH == 10 && $G_HW_MODEL == 21 && ${aSOFTWARE_INSTALL_STATE[6]} == 1 )) then local gpu_current=$(sed -n '/^[[:blank:]]*CONFIG_GPU_DRIVER=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ ${gpu_current,,} == 'none' ]] && G_WHIP_YESNO 'No GPU Driver is currently installed.\n\nWould you like to select a GPU driver for installation now?' && /boot/dietpi/dietpi-config 2 fi # RPi: Disable headless mode and raise memory split to default for GUI applications (( $G_HW_MODEL < 10 )) || return 0 # Kodi, Jellyfin, DXX-Rebirth, RPi Cam Web Interface, Amiberry, Chromium, Desktops, OpenTyrian, Moonlight (CLI), Moonlight (GUI), GZDoom (( ${aSOFTWARE_INSTALL_STATE[31]} == 1 || ${aSOFTWARE_INSTALL_STATE[178]} == 1 || ${aSOFTWARE_INSTALL_STATE[112]} == 1 || ${aSOFTWARE_INSTALL_STATE[59]} == 1 || ${aSOFTWARE_INSTALL_STATE[108]} == 1 || ${aSOFTWARE_INSTALL_STATE[113]} == 1 || ${aSOFTWARE_INSTALL_STATE[23]} == 1 || ${aSOFTWARE_INSTALL_STATE[24]} == 1 || ${aSOFTWARE_INSTALL_STATE[25]} == 1 || ${aSOFTWARE_INSTALL_STATE[26]} == 1 || ${aSOFTWARE_INSTALL_STATE[51]} == 1 || ${aSOFTWARE_INSTALL_STATE[173]} == 1 || ${aSOFTWARE_INSTALL_STATE[207]} == 1 || ${aSOFTWARE_INSTALL_STATE[208]} == 1 || ${aSOFTWARE_INSTALL_STATE[11]} == 1 )) || return 0 # Disable headless mode /boot/dietpi/func/dietpi-set_hardware headless 0 # Raise memory split to default local default_gpu_mem=76 (( $G_HW_MEMORY_SIZE < 1024 )) && default_gpu_mem=64 local current_gpu_mem=$(sed -n '/^[[:blank:]]*gpu_mem_1024=/{s/^[^=]*=//p;q}' /boot/config.txt) [[ $current_gpu_mem ]] || current_gpu_mem=$default_gpu_mem (( $current_gpu_mem < $default_gpu_mem )) && /boot/dietpi/func/dietpi-set_hardware gpumemsplit "$default_gpu_mem" } Uninstall_Software() { # $1: Service name # $2: Remove user named $2 or $1 if $2 == 1 (optional) # $3: Remove group named $3 or $1 if $3 == 1 (optional) Remove_Service() { local unmasked disabled if [[ -f '/etc/systemd/system/'$1'.service' ]] then G_EXEC systemctl --no-reload disable --now "$1" && disabled=1 G_EXEC rm "/etc/systemd/system/$1.service" && unmasked=1 elif [[ -f '/lib/systemd/system/'$1'.service' ]] then G_EXEC systemctl --no-reload unmask "$1" && unmasked=1 G_EXEC systemctl --no-reload disable --now "$1" && disabled=1 fi if [[ -f '/etc/init.d/'$1 ]] then [[ $unmasked ]] || G_EXEC systemctl --no-reload unmask "$1" [[ $disabled ]] || G_EXEC systemctl --no-reload disable "$1" [[ $disabled ]] || G_EXEC systemctl stop "$1" # --now does not work with generated wrapper units G_EXEC rm "/etc/init.d/$1" G_EXEC update-rc.d "$1" remove fi [[ -d '/etc/systemd/system/'$1'.service.d' ]] && G_EXEC rm -R "/etc/systemd/system/$1.service.d" [[ $2 ]] && getent passwd "${2/#1/$1}" > /dev/null && G_EXEC userdel "${2/#1/$1}" [[ $3 ]] && getent group "${3/#1/$1}" > /dev/null && G_EXEC groupdel "${3/#1/$1}" } # $1: Database and username Remove_Database() { systemctl start mariadb || return 1 mysqladmin -f drop "$1" mysql -e "drop user $1@localhost;" } # NB: "systemctl daemon-reload" is executed at the end of this function G_NOTIFY_3_MODE='Step' local software_id To_Uninstall() { (( ${aSOFTWARE_INSTALL_STATE[$1]} == -1 )) || return 1 G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" "Uninstalling ${aSOFTWARE_NAME[$1]}: ${aSOFTWARE_DESC[$1]}" software_id=$1 } if To_Uninstall 23 # LXDE then apt-mark auto lxhotkey-plugin-openbox upower librsvg2-common 2> /dev/null G_AGP lxde 'lxde-*' G_EXEC rm -Rf /{root,home/*}/.{config,cache}/{lxpanel,lxsession,lxterminal,openbox,pcmanfm,dconf} fi if To_Uninstall 173 # LXQt then apt-mark auto qterminal xarchiver lxde-icon-theme upower xscreensaver leafpad featherpad speedcrunch 2> /dev/null G_AGP lxqt G_EXEC rm -Rf /{root,home/*}/.config/lxqt fi if To_Uninstall 174 # GIMP then G_AGP gimp fi if To_Uninstall 175 # Xfce Power Manager then G_AGP xfce4-power-manager fi if To_Uninstall 24 # MATE then apt-mark auto upower policykit-1 2> /dev/null G_AGP mate-desktop-environment-core mate-media fi if To_Uninstall 26 # GNUstep then G_AGP wmaker gnustep gnustep-devel gnustep-games G_EXEC rm -Rf /{root,home/*}/GNUstep fi if To_Uninstall 25 # Xfce then apt-mark auto gnome-icon-theme tango-icon-theme upower policykit-1 polkitd 2> /dev/null G_AGP xfce4 xfce4-terminal fi if To_Uninstall 22 # QuiteRSS then G_AGP quiterss fi if To_Uninstall 30 # NoMachine then G_AGP nomachine G_EXEC rm -Rf /{root,home/*}/NoMachine fi if To_Uninstall 29 # XRDP then G_AGP xrdp xorgxrdp fi if To_Uninstall 44 # Transmission then Remove_Service transmission-daemon debian-transmission debian-transmission G_AGP transmission-daemon fi if To_Uninstall 47 # ownCloud then # Remove background cron job crontab -u www-data -l | grep -v '/var/www/owncloud/.*cron' | crontab -u www-data - # Disable and remove PHP modules command -v phpdismod > /dev/null && G_EXEC phpdismod dietpi-owncloud G_EXEC rm -f /etc/php/*/mods-available/dietpi-owncloud.ini # Disable and remove webserver configs command -v a2dissite > /dev/null && a2dissite dietpi-owncloud [[ -f '/etc/apache2/sites-available/dietpi-owncloud.conf' ]] && G_EXEC rm /etc/apache2/sites-available/dietpi-owncloud.conf [[ -f '/etc/nginx/sites-dietpi/dietpi-owncloud.conf' ]] && G_EXEC rm /etc/nginx/sites-dietpi/dietpi-owncloud.conf command -v lighty-disable-mod > /dev/null && lighty-disable-mod dietpi-owncloud [[ -f '/etc/lighttpd/conf-available/99-dietpi-owncloud.conf' ]] && G_EXEC rm /etc/lighttpd/conf-available/99-dietpi-owncloud.conf G_WHIP_MSG "DietPi will perform an automated backup of your ownCloud database and installation directory, which will be stored inside your ownCloud data directory.\n\nThe data directory won't be removed. So you can recover your whole ownCloud instance any time later.\n\nRemove the data directory manually if you don't need it anymore." # Find datadir for backups local datadir=$(grep -m1 "^[[:blank:]]*'datadirectory'" /var/www/owncloud/config/config.php | mawk '{print $3}' | sed "s/[',]//g") [[ $datadir ]] || datadir='/mnt/dietpi_userdata/owncloud_data' # Drop MariaDB users and database if systemctl start mariadb then local dbuser=$(grep -m1 "^[[:blank:]]*'dbuser'" /var/www/owncloud/config/config.php | mawk '{print $3}' | sed 's/,//') local dbhost=$(grep -m1 "^[[:blank:]]*'dbhost'" /var/www/owncloud/config/config.php | mawk '{print $3}' | sed 's/,//') mysql -e "drop user $dbuser@$dbhost;" mysql -e "drop user $dbuser;" 2> /dev/null # Perform database backup if existent, otherwise skip to not overwrite existing one [[ -d '/mnt/dietpi_userdata/mysql/owncloud' ]] && mysqldump owncloud > "$datadir/dietpi-owncloud-database-backup.sql" mysqladmin drop owncloud -f fi if [[ -d '/var/www/owncloud' ]] then # Backup ownCloud installation dir G_EXEC cp -a /var/www/owncloud/. "$datadir/dietpi-owncloud-installation-backup/" # Remove ownCloud installation dir G_EXEC rm -R /var/www/owncloud fi # Remove redirect configs if grep -q 'owncloud' /etc/lighttpd/conf-available/99-dietpi-dav_redirect.conf 2> /dev/null then command -v lighty-disable-mod > /dev/null && lighty-disable-mod dietpi-dav_redirect G_EXEC rm /etc/lighttpd/conf-available/99-dietpi-dav_redirect.conf fi if grep -q 'owncloud' /etc/apache2/conf-available/dietpi-dav_redirect.conf 2> /dev/null then command -v a2disconf > /dev/null && a2disconf dietpi-dav_redirect G_EXEC rm /etc/apache2/conf-available/dietpi-dav_redirect.conf fi grep -q 'owncloud' /etc/nginx/sites-dietpi/dietpi-dav_redirect.conf 2> /dev/null && G_EXEC rm /etc/nginx/sites-dietpi/dietpi-dav_redirect.conf fi if To_Uninstall 168 # Nextcloud Talk + Coturn server then Remove_Service coturn G_AGP coturn [[ -f '/etc/turnserver.conf' ]] && G_EXEC rm /etc/turnserver.conf systemctl start redis-server if systemctl start mariadb then runuser -u www-data -- php /var/www/nextcloud/occ maintenance:mode --off runuser -u www-data -- php /var/www/nextcloud/occ app:disable spreed fi G_DIETPI-NOTIFY 2 'Disabled Nextcloud Talk app, but you need to remove it manually from Nextcloud web UI if desired.' fi if To_Uninstall 114 # Nextcloud then crontab -u www-data -l | grep -v '/var/www/nextcloud/cron.php' | crontab -u www-data - # Disable and remove PHP modules command -v phpdismod > /dev/null && G_EXEC phpdismod dietpi-nextcloud G_EXEC rm -f /etc/php/*/mods-available/dietpi-nextcloud.ini # Disable and remove webserver configs command -v a2dissite > /dev/null && a2dissite dietpi-nextcloud [[ -f '/etc/apache2/sites-available/dietpi-nextcloud.conf' ]] && G_EXEC rm /etc/apache2/sites-available/dietpi-nextcloud.conf [[ -f '/etc/nginx/sites-dietpi/dietpi-nextcloud.conf' ]] && G_EXEC rm /etc/nginx/sites-dietpi/dietpi-nextcloud.conf command -v lighty-disable-mod > /dev/null && lighty-disable-mod dietpi-nextcloud [[ -f '/etc/lighttpd/conf-available/99-dietpi-nextcloud.conf' ]] && G_EXEC rm /etc/lighttpd/conf-available/99-dietpi-nextcloud.conf G_WHIP_MSG "DietPi will perform an automated backup of your Nextcloud database and installation directory, which will be stored inside your Nextcloud data directory.\n\nThe data directory won't be removed. So you can recover your whole Nextcloud instance any time later.\n\nRemove the data directory manually if you don't need it anymore." # Find datadir for backups local datadir=$(grep -m1 "^[[:blank:]]*'datadirectory'" /var/www/nextcloud/config/config.php | mawk '{print $3}' | sed "s/[',]//g") [[ $datadir ]] || datadir='/mnt/dietpi_userdata/nextcloud_data' # Drop MariaDB users and database if systemctl start mariadb then local dbuser=$(grep -m1 "^[[:blank:]]*'dbuser'" /var/www/nextcloud/config/config.php | mawk '{print $3}' | sed 's/,//') local dbhost=$(grep -m1 "^[[:blank:]]*'dbhost'" /var/www/nextcloud/config/config.php | mawk '{print $3}' | sed 's/,//') mysql -e "drop user $dbuser@$dbhost;" mysql -e "drop user $dbuser;" 2> /dev/null # Perform database backup if existent, otherwise skip to not overwrite existing one [[ -d '/mnt/dietpi_userdata/mysql/nextcloud' ]] && mysqldump nextcloud > "$datadir/dietpi-nextcloud-database-backup.sql" mysqladmin drop nextcloud -f fi if [[ -d '/var/www/nextcloud' ]] then # Backup Nextcloud installation dir G_EXEC cp -a /var/www/nextcloud/. "$datadir/dietpi-nextcloud-installation-backup/" # Remove Nextcloud installation dir G_EXEC rm -R /var/www/nextcloud fi # Remove redirect configs if grep -q 'nextcloud' /etc/lighttpd/conf-available/99-dietpi-dav_redirect.conf 2> /dev/null then command -v lighty-disable-mod > /dev/null && lighty-disable-mod dietpi-dav_redirect G_EXEC rm /etc/lighttpd/conf-available/99-dietpi-dav_redirect.conf fi if grep -q 'nextcloud' /etc/apache2/conf-available/dietpi-dav_redirect.conf 2> /dev/null then command -v a2disconf > /dev/null && a2disconf dietpi-dav_redirect G_EXEC rm /etc/apache2/conf-available/dietpi-dav_redirect.conf fi grep -q 'nextcloud' /etc/nginx/sites-dietpi/dietpi-dav_redirect.conf 2> /dev/null && G_EXEC rm /etc/nginx/sites-dietpi/dietpi-dav_redirect.conf fi if To_Uninstall 63 # LinuxDash then [[ -d '/var/www/linuxdash' ]] && G_EXEC rm -R /var/www/linuxdash fi if To_Uninstall 27 # TasmoAdmin then [[ -d '/var/www/tasmoadmin' ]] && G_EXEC rm -R /var/www/tasmoadmin # Remove webserver configs command -v a2dissite > /dev/null && a2dissite dietpi-tasmoadmin [[ -f '/etc/apache2/conf-available/dietpi-tasmoadmin.conf' ]] && G_EXEC rm /etc/apache2/conf-available/dietpi-tasmoadmin.conf [[ -f '/etc/nginx/sites-dietpi/dietpi-tasmoadmin.conf' ]] && G_EXEC rm /etc/nginx/sites-dietpi/dietpi-tasmoadmin.conf command -v lighty-disable-mod > /dev/null && lighty-disable-mod dietpi-tasmoadmin [[ -f '/etc/lighttpd/conf-available/99-dietpi-tasmoadmin.conf' ]] && G_EXEC rm /etc/lighttpd/conf-available/99-dietpi-tasmoadmin.conf fi if To_Uninstall 206 # openHAB then G_AGP openhab [[ -f '/etc/apt/sources.list.d/dietpi-openhab.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-openhab.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-openhab.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-openhab.gpg [[ -f '/etc/apt/preferences.d/dietpi-openhab' ]] && G_EXEC rm /etc/apt/preferences.d/dietpi-openhab fi if To_Uninstall 83 # Apache then Remove_Service apache2 G_AGP apache2 libapache2-mod-php* G_EXEC rm -Rf /{etc,var/{lib,log}}/apache2 /{etc/php,var/lib/php/modules}/*/apache2 fi if To_Uninstall 85 # Nginx then Remove_Service nginx G_AGP nginx 'nginx-*' fi if To_Uninstall 84 # Lighttpd then Remove_Service lighttpd G_AGP lighttpd # Config [[ -d '/etc/lighttpd' ]] && G_EXEC rm -R /etc/lighttpd [[ -d '/var/www/index.lighttpd.html' ]] && G_EXEC rm /var/www/index.lighttpd.html # Certbot hook [[ -f '/etc/letsencrypt/renewal-hooks/deploy/dietpi-lighttpd.sh' ]] && G_EXEC rm /etc/letsencrypt/renewal-hooks/deploy/dietpi-lighttpd.sh # - Pre-v8.0 [[ -f 'etc/systemd/system/certbot.service.d/dietpi-lighttpd.conf' ]] && G_EXEC rm /etc/systemd/system/certbot.service.d/dietpi-lighttpd.conf [[ -d '/etc/systemd/system/certbot.service.d' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /etc/systemd/system/certbot.service.d fi if To_Uninstall 91 # Redis then Remove_Service redis-server G_AGP redis-server redis-tools 'php*-redis' G_EXEC rm -f /etc/sysctl.d/98-dietpi-redis.conf fi if To_Uninstall 34 # PHP Composer then [[ -f '/usr/local/bin/composer' ]] && G_EXEC rm /usr/local/bin/composer fi if To_Uninstall 89 # PHP then Remove_Service "php$PHP_VERSION-fpm" G_AGP 'php*-*' 'libapache2-mod-php*' G_EXEC rm -Rf /{etc,var/lib}/php /var/log/php*-fpm.log [[ -f '/etc/tmpfiles.d/dietpi-php_sessions.conf' ]] && G_EXEC rm /etc/tmpfiles.d/dietpi-php_sessions.conf [[ -d '/var/tmp/php_upload_tmp' ]] && G_EXEC rm -R /var/tmp/php_upload_tmp # Pre-v6.32 fi if To_Uninstall 90 # phpMyAdmin then G_EXEC rm -Rf /var/www/phpmyadmin if [[ -f '/etc/apache2/sites-available/dietpi-phpmyadmin.conf' ]] then command -v a2dissite > /dev/null && a2dissite dietpi-phpmyadmin G_EXEC rm /etc/apache2/sites-available/dietpi-phpmyadmin.conf fi if [[ -f '/etc/lighttpd/conf-available/98-dietpi-phpmyadmin.conf' ]] then command -v lighty-disable-mod > /dev/null && lighty-disable-mod dietpi-phpmyadmin G_EXEC rm /etc/lighttpd/conf-available/98-dietpi-phpmyadmin.conf fi [[ -f '/etc/apache2/sites-dietpi/dietpi-phpmyadmin.conf' ]] && G_EXEC rm /etc/apache2/sites-dietpi/dietpi-phpmyadmin.conf Remove_Database phpmyadmin fi if To_Uninstall 184 # Tor Relay then Remove_Service tor G_AGP tor obfs4proxy fi if To_Uninstall 54 # phpBB then [[ -d '/var/www/phpbb' ]] && G_EXEC rm -R /var/www/phpbb [[ -d '/var/www/phpBB3' ]] && G_EXEC rm -R /var/www/phpBB3 # Pre-v6.33 Remove_Database phpbb Remove_Database phpbb3 # Pre-v6.33 fi if To_Uninstall 115 # Webmin then Remove_Service webmin G_AGP webmin G_EXEC rm -f /etc/apt/sources.list.d/dietpi-webmin.list /etc/apt/trusted.gpg.d/dietpi-webmin.asc fi if To_Uninstall 32 # ympd then G_AGP ympd fi if To_Uninstall 148 # myMPD then Remove_Service mympd 1 1 # user and group for pre-v8.12 if [[ -f '/usr/local/share/ca-certificates/DietPi_myMPD_CA.crt' || -L '/usr/local/share/ca-certificates/DietPi_myMPD_CA.crt' ]] then G_EXEC rm /usr/local/share/ca-certificates/DietPi_myMPD_CA.crt G_EXEC update-ca-certificates -f fi G_AGP mympd [[ -f '/etc/apt/sources.list.d/dietpi-mympd.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-mympd.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-mympd.asc' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-mympd.asc [[ -d '/var/lib/mympd' ]] && G_EXEC rm -R /var/lib/mympd [[ -d '/var/lib/private/mympd' ]] && G_EXEC rm -R /var/lib/private/mympd [[ -d '/var/cache/mympd' ]] && G_EXEC rm -R /var/cache/mympd [[ -d '/var/cache/private/mympd' ]] && G_EXEC rm -R /var/cache/private/mympd # pre-v8.0 [[ -f '/lib/systemd/system/mympd.service' ]] && G_EXEC rm /lib/systemd/system/mympd.service command -v mympd > /dev/null && G_EXEC rm "$(command -v mympd)" command -v mympd-config > /dev/null && G_EXEC rm "$(command -v mympd-config)" # myMPD pre-v8.0.0 command -v mympd-script > /dev/null && G_EXEC rm "$(command -v mympd-script)" [[ -d '/usr/share/doc/mympd' ]] && G_EXEC rm -R /usr/share/doc/mympd G_EXEC rm -f /usr/share/man/man1/mympd* /etc/mympd.conf* # /etc: myMPD pre-v8.0.0 fi if To_Uninstall 128 # MPD then Remove_Service mpd 1 1 # group for pre-v6.29 G_AGP mpd [[ -d '/var/log/mpd' ]] && G_EXEC rm -R /var/log/mpd [[ -d '/mnt/dietpi_userdata/.mpd_cache' ]] && G_EXEC rm -R /mnt/dietpi_userdata/.mpd_cache [[ -f '/etc/mpd.conf' ]] && G_EXEC rm /etc/mpd.conf [[ -f '/usr/local/etc/mpd.conf' ]] && G_EXEC rm /usr/local/etc/mpd.conf && G_EXEC rmdir --ignore-fail-on-non-empty /usr/local/etc # pre-v6.29 [[ -f '/etc/default/mpd' ]] && G_EXEC rm /etc/default/mpd # pre-v6.20 fi if To_Uninstall 122 # Node-RED then Remove_Service node-red nodered nodered # Configs [[ -f '/etc/sudoers.d/nodered' ]] && G_EXEC rm /etc/sudoers.d/nodered [[ -f '/etc/bashrc.d/dietpi-node-red.sh' ]] && G_EXEC rm /etc/bashrc.d/dietpi-node-red.sh # Data [[ -d '/mnt/dietpi_userdata/node-red' ]] && G_EXEC rm -R /mnt/dietpi_userdata/node-red G_EXEC rm -Rf /{root,home/*}/.node-red # Pre-v6.25 # Pre-v7.0 command -v npm > /dev/null && npm r -g node-red [[ -f '/usr/local/bin/node-red' ]] && G_EXEC rm /usr/local/bin/node-red [[ -f '/usr/local/bin/node-red-pi' ]] && G_EXEC rm /usr/local/bin/node-red-pi fi if To_Uninstall 195 # youtube-dl then G_EXEC rm -f /usr/local/bin/{yt-dlp,youtube-dl,youtube-dl-py2} fi if To_Uninstall 123 # Mosquitto then Remove_Service mosquitto G_AGP mosquitto [[ -d '/etc/mosquitto' ]] && G_EXEC rm -R /etc/mosquitto [[ -f '/etc/apt/sources.list.d/dietpi-mosquitto.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-mosquitto.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-mosquitto.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-mosquitto.gpg fi if To_Uninstall 124 # NAA Daemon then G_AGP networkaudiod fi if To_Uninstall 129 # O!MPD then [[ -d '/var/www/ompd' ]] && G_EXEC rm -R /var/www/ompd [[ -f '/etc/lighttpd/conf-enabled/99-dietpi-ompd.conf' ]] && G_EXEC lighty-disable-mod dietpi-ompd [[ -f '/etc/lighttpd/conf-available/99-dietpi-ompd.conf' ]] && G_EXEC rm /etc/lighttpd/conf-available/99-dietpi-ompd.conf Remove_Database ompd fi if To_Uninstall 131 # Blynk Server then Remove_Service blynkserver blynk blynk [[ -d '/mnt/dietpi_userdata/blynk' ]] && G_EXEC rm -R /mnt/dietpi_userdata/blynk [[ -d '/var/log/blynk' ]] && G_EXEC rm -R /var/log/blynk command -v npm > /dev/null && npm r -g blynk-library [[ -f '/usr/local/bin/blynk-ctrl' ]] && G_EXEC rm /usr/local/bin/blynk-ctrl [[ -f '/usr/local/bin/blynk-client' ]] && G_EXEC rm /usr/local/bin/blynk-client [[ -d '/etc/blynkserver' ]] && G_EXEC rm -R /etc/blynkserver # Pre-v6.19 fi if To_Uninstall 125 # Synapse then Remove_Service synapse 1 1 [[ -d '/mnt/dietpi_userdata/synapse' ]] && G_EXEC rm -R /mnt/dietpi_userdata/synapse command -v pip3 > /dev/null && G_EXEC_OUTPUT=1 G_EXEC pip3 uninstall -y matrix-synapse command -v dropdb > /dev/null && runuser -u postgres -- dropdb synapse command -v dropuser > /dev/null && runuser -u postgres -- dropuser synapse fi if To_Uninstall 132 # Aria2 then [[ -d '/var/www/aria2' ]] && G_EXEC rm -R /var/www/aria2 Remove_Service aria2 1 1 G_AGP aria2 [[ -d '/mnt/dietpi_userdata/aria2' ]] && G_EXEC rm -R /mnt/dietpi_userdata/aria2 [[ -f '/mnt/dietpi_userdata/downloads/aria2.session' ]] && G_EXEC rm /mnt/dietpi_userdata/downloads/aria2.session [[ -f '/usr/local/bin/aria2c' ]] && G_EXEC rm /usr/local/bin/aria2c # Previous fi if To_Uninstall 133 # YaCy then Remove_Service yacy [[ -d '/etc/yacy' ]] && G_EXEC rm -R /etc/yacy fi if To_Uninstall 141 # ADS-B Feeder then G_EXEC_NOHALT=1 G_EXEC_OUTPUT=1 G_EXEC /opt/adsb/docker-compose-adsb down Remove_Service adsb-docker Remove_Service adsb-feeder-update Remove_Service adsb-setup [[ -f '/opt/adsb/pre-uninstall-cleanup' ]] && G_EXEC /opt/adsb/pre-uninstall-cleanup G_EXEC rm -Rf /opt/adsb /mnt/dietpi_userdata/adsb-feeder /opt/adsb-feeder-update fi if To_Uninstall 2 # Folding@Home then # Un-check out all work units, so they can be picked up by other donors prior to timeout: https://github.com/FoldingAtHome/fah-issues/issues/1255 FAHClient --chdir /mnt/dietpi_userdata/fahclient --dump all Remove_Service fahclient G_AGP fahclient [[ -d '/mnt/dietpi_userdata/fahclient' ]] && G_EXEC rm -R /mnt/dietpi_userdata/fahclient fi if To_Uninstall 135 then Remove_Service darkice G_AGP darkice icecast2 fi if To_Uninstall 136 # motionEye then Remove_Service motioneye command -v pip3 > /dev/null && G_EXEC_OUTPUT=1 G_EXEC pip3 uninstall -y motioneye G_AGP motion [[ -d '/etc/motioneye' ]] && G_EXEC rm -R /etc/motioneye [[ -d '/var/log/motioneye' ]] && G_EXEC rm -R /var/log/motioneye [[ -d '/var/lib/motioneye' ]] && G_EXEC rm -R /var/lib/motioneye [[ -d '/mnt/dietpi_userdata/motioneye' ]] && G_DIETPI-NOTIFY 2 'The motionEye media directory is left in place. You can manually remove it via:\n rm -R /mnt/dietpi_userdata/motioneye' fi if To_Uninstall 137 # mjpg-streamer then Remove_Service mjpg-streamer 1 [[ -d '/opt/mjpg-streamer' ]] && G_EXEC rm -R /opt/mjpg-streamer fi if To_Uninstall 138 # VirtualHere then Remove_Service virtualhere [[ -d '/opt/virtualhere' ]] && G_EXEC rm -R /opt/virtualhere [[ -d '/etc/vhusbd' ]] && G_EXEC rm -R /etc/vhusbd # Pre-v8.4 [[ -f '/var/log/virtualhere.log' ]] && G_EXEC rm /var/log/virtualhere.log # Pre-v8.4 fi if To_Uninstall 139 # SABnzbd then Remove_Service sabnzbd 1 1 # group for pre-v6.33 [[ -d '/etc/sabnzbd' ]] && G_EXEC rm -R /etc/sabnzbd [[ -d '/mnt/dietpi_userdata/downloads/sabnzbd_admin' ]] && G_EXEC rm -R /mnt/dietpi_userdata/downloads/sabnzbd_admin [[ -d '/mnt/dietpi_userdata/downloads/sabnzbd_nzb_backup' ]] && G_EXEC rm -R /mnt/dietpi_userdata/downloads/sabnzbd_nzb_backup [[ -d '/var/log/sabnzbd' ]] && G_EXEC rm -R /var/log/sabnzbd # Pre-v7.9 fi if To_Uninstall 183 # vaultwarden then Remove_Service vaultwarden 1 1 # Pre-v8.7 G_AGP vaultwarden [[ -d '/mnt/dietpi_userdata/vaultwarden' ]] && G_EXEC rm -R /mnt/dietpi_userdata/vaultwarden [[ -d '/opt/vaultwarden' ]] && G_EXEC rm -R /opt/vaultwarden # Pre-v8.7 fi if To_Uninstall 193 # K3s then [[ -f '/usr/local/bin/k3s-uninstall.sh' ]] && G_EXEC_OUTPUT=1 G_EXEC_NOEXIT=1 G_EXEC /usr/local/bin/k3s-uninstall.sh [[ -f '/usr/local/bin/k3s-agent-uninstall.sh' ]] && G_EXEC_OUTPUT=1 G_EXEC_NOEXIT=1 G_EXEC /usr/local/bin/k3s-agent-uninstall.sh [[ -d '/etc/systemd/system/k3s.service.d' ]] && G_EXEC rm -R /etc/systemd/system/k3s.service.d [[ -d '/etc/rancher' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /etc/rancher [[ -d '/var/lib/rancher' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /var/lib/rancher fi if To_Uninstall 142 # MicroK8s then command -v snap > /dev/null && G_EXEC_OUTPUT=1 G_EXEC snap remove microk8s fi if To_Uninstall 182 # Unbound then # Pi-hole: Assure that it does not resolve via Unbound anymore # - v6 if [[ $(pihole-FTL -v) == 'v6'* ]] then G_DIETPI-NOTIFY 2 'Removing Unbound from Pi-hole upstream DNS servers, and in case add Quad9 as new one.' local upstreams=() i read -ra upstreams < <(pihole-FTL --config dns.upstreams) # Remove array brackets unset -v 'upstreams[0]' 'upstreams[${#upstreams[@]}]' for i in "${!upstreams[@]}" do # Remove loopback IP (Unbound) [[ ${upstreams[i]} == '127.0.0.1'* ]] && { unset -v 'upstreams[i]'; break; } # Remove trailing comma and readd double-quotes removed from pihole-FTL output upstreams[i]="\"${upstreams[i]%,}\"" done # Add Quad9 if no upstream DNS server is left (( ${#upstreams[@]} )) || upstreams=('"9.9.9.9"') upstreams[0]=${upstreams[*]} G_EXEC pihole-FTL --config dns.upstreams "[ ${upstreams[0]// /,} ]" fi # - v5 if [[ -f '/etc/dnsmasq.d/01-pihole.conf' ]] && grep -q '^[[:blank:]]*server=127.0.0.1' /etc/dnsmasq.d/01-pihole.conf then G_DIETPI-NOTIFY 2 'The Pi-hole upstream DNS server has been changed to Quad9 due to Unbound being uninstalled.' G_CONFIG_INJECT 'server=127.0.0.1' 'server=9.9.9.9' /etc/dnsmasq.d/01-pihole.conf systemctl -q is-active pihole-FTL && G_EXEC_NOEXIT=1 G_EXEC systemctl restart pihole-FTL fi [[ -f '/etc/pihole/setupVars.conf' ]] && grep -q '^[[:blank:]]*PIHOLE_DNS_1=127.0.0.1' /etc/pihole/setupVars.conf && G_CONFIG_INJECT 'PIHOLE_DNS_1=' 'PIHOLE_DNS_1=9.9.9.9' /etc/pihole/setupVars.conf # AdGuard Home: Assure that it does not resolve via Unbound anymore if [[ -f '/mnt/dietpi_userdata/adguardhome/dietpi-unbound.conf' ]] then G_DIETPI-NOTIFY 2 'AdGuard Home upstream DNS server has been changed back to default settings due to Unbound being uninstalled.' G_CONFIG_INJECT 'upstream_dns_file:[[:blank:]]' ' upstream_dns_file: ""' /mnt/dietpi_userdata/adguardhome/AdGuardHome.yaml [[ -f '/mnt/dietpi_userdata/adguardhome/dietpi-unbound.conf' ]] && G_EXEC rm /mnt/dietpi_userdata/adguardhome/dietpi-unbound.conf systemctl -q is-active adguardhome && G_EXEC_NOEXIT=1 G_EXEC systemctl restart adguardhome fi # Failsafe: Add Quad9 to system resolver if only Unbound was used if [[ -f '/etc/unbound/unbound.conf.d/dietpi.conf' ]] && grep -Eq '^[[:blank:]]*port:[[:blank:]]+53$' /etc/unbound/unbound.conf.d/dietpi.conf then grep '^[[:blank:]]*nameserver[[:blank:]]' /etc/resolv.conf | grep -qvE '[[:blank:]]127.0.0.1(:53)?$' || echo 'nameserver 9.9.9.9' >> /etc/resolv.conf # Failsafe fi G_AGP unbound dpkg-query -s 'dns-root-data' &> /dev/null && G_EXEC apt-mark auto dns-root-data [[ -d '/etc/unbound' ]] && G_EXEC rm -R /etc/unbound [[ -d '/var/cache/unbound' ]] && G_EXEC rm -R /var/cache/unbound fi if To_Uninstall 143 # Koel then Remove_Service koel 1 1 # group for pre-v6.33 [[ -d '/mnt/dietpi_userdata/koel' ]] && G_EXEC rm -R /mnt/dietpi_userdata/koel Remove_Database koel fi if To_Uninstall 144 # Sonarr then Remove_Service sonarr 1 1 # group for pre-v6.29 G_AGP sonarr nzbdrone # Pre-v7.1 [[ -d '/var/log/sonarr' ]] && G_EXEC rm -R /var/log/sonarr G_EXEC rm -Rf /opt/sonarr /mnt/dietpi_userdata/sonarr /opt/NzbDrone # Pre-v7.1 [[ -f '/etc/apt/sources.list.d/sonarr.list' ]] && G_EXEC rm /etc/apt/sources.list.d/sonarr.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-sonarr.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-sonarr.gpg # Pre-v7.1: Remove Sonarr v2 key if [[ -f '/etc/apt/trusted.gpg' && $(apt-key --keyring /etc/apt/trusted.gpg list 'A236C58F409091A18ACA53CBEBFF6B99D9B78493' 2> /dev/null) ]] then G_EXEC apt-key --keyring /etc/apt/trusted.gpg del 'A236C58F409091A18ACA53CBEBFF6B99D9B78493' [[ $(apt-key --keyring /etc/apt/trusted.gpg list 2> /dev/null) ]] || G_EXEC rm /etc/apt/trusted.gpg fi fi if To_Uninstall 145 # Radarr then Remove_Service radarr 1 1 # group for pre-v6.29 G_EXEC rm -Rf /opt/radarr /mnt/dietpi_userdata/radarr /var/log/radarr fi if To_Uninstall 106 # Lidarr then Remove_Service lidarr 1 1 # group for pre-v6.29 G_EXEC rm -Rf /opt/{L,l}idarr /mnt/dietpi_userdata/lidarr /var/log/lidarr fi if To_Uninstall 180 # Bazarr then Remove_Service bazarr 1 G_EXEC rm -Rf /opt/bazarr /mnt/dietpi_userdata/bazarr /var/log/bazarr fi if To_Uninstall 200 # DietPi-Dashboard then Remove_Service dietpi-dashboard [[ -d '/opt/dietpi-dashboard' ]] && G_EXEC rm -R /opt/dietpi-dashboard fi if To_Uninstall 99 # Prometheus Node Exporter then if [[ -f '/etc/systemd/system/raspberrypi_exporter.timer' ]] then G_EXEC systemctl --no-reload disable --now raspberrypi_exporter.timer G_EXEC rm /etc/systemd/system/raspberrypi_exporter.timer fi [[ -d '/etc/systemd/system/raspberrypi_exporter.timer.d' ]] && G_EXEC rm -R /etc/systemd/system/raspberrypi_exporter.timer.d Remove_Service raspberrypi_exporter Remove_Service node_exporter 1 1 [[ -d '/opt/node_exporter' ]] && G_EXEC rm -R /opt/node_exporter fi if To_Uninstall 146 # Tautulli then Remove_Service tautulli 1 1 [[ -d '/opt/tautulli' ]] && G_EXEC rm -R /opt/tautulli [[ -d '/mnt/dietpi_userdata/tautulli' ]] && G_EXEC rm -R /mnt/dietpi_userdata/tautulli fi if To_Uninstall 147 # Jackett then Remove_Service jackett 1 1 [[ -d '/opt/jackett' ]] && G_EXEC rm -R /opt/jackett fi if To_Uninstall 149 # NZBGet then Remove_Service nzbget 1 1 # group for pre-v6.33 [[ -d '/mnt/dietpi_userdata/nzbget' ]] && G_EXEC rm -R /mnt/dietpi_userdata/nzbget fi if To_Uninstall 151 # Prowlarr then Remove_Service prowlarr 1 G_EXEC rm -Rf /opt/prowlarr /mnt/dietpi_userdata/prowlarr /var/log/prowlarr fi if To_Uninstall 203 # Readarr then Remove_Service readarr 1 G_EXEC rm -Rf /opt/readarr /mnt/dietpi_userdata/readarr /var/log/readarr fi if To_Uninstall 155 # HTPC Manager then Remove_Service htpc-manager [[ -d '/mnt/dietpi_userdata/htpc-manager' ]] && G_EXEC rm -R /mnt/dietpi_userdata/htpc-manager fi if To_Uninstall 150 # Mono then # shellcheck disable=SC2046 apt-mark auto $(dpkg --get-selections 'mono-*' 'libmono-*' 2> /dev/null | mawk '{print $1}') 2> /dev/null [[ -f '/etc/apt/sources.list.d/dietpi-mono.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-mono.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-mono.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-mono.gpg fi if To_Uninstall 37 # Shairport Sync then G_AGP shairport-sync shairport-sync-airplay2 fi if To_Uninstall 152 # Avahi-Daemon then G_AGP avahi-daemon fi if To_Uninstall 153 # OctoPrint then Remove_Service octoprint 1 1 # CLI alias [[ -f '/etc/bashrc.d/dietpi-octoprint.sh' ]] && G_EXEC rm /etc/bashrc.d/dietpi-octoprint.sh # Data [[ -d '/mnt/dietpi_userdata/octoprint' ]] && G_EXEC rm -R /mnt/dietpi_userdata/octoprint # sudoers [[ -f '/etc/sudoers.d/octoprint' ]] && G_EXEC rm /etc/sudoers.d/octoprint fi if To_Uninstall 187 # CUPS then G_AGP cups [[ -d '/etc/cups' ]] && G_EXEC rm -R /etc/cups fi if To_Uninstall 121 # Roon Bridge then Remove_Service roonbridge 1 1 [[ -d '/opt/roonbridge' ]] && G_EXEC rm -R /opt/roonbridge [[ -d '/var/log/roonbridge' ]] && G_EXEC rm -R /var/log/roonbridge [[ -d '/mnt/dietpi_userdata/roonbridge' ]] && G_EXEC rm -R /mnt/dietpi_userdata/roonbridge # Pre-v8.2 [[ -d '/etc/roonbridge' ]] && G_EXEC rm -R /etc/roonbridge [[ -d '/var/log/roon' ]] && G_EXEC rm -R /var/log/roon [[ -d '/mnt/dietpi_userdata/roon' ]] && G_EXEC rm -R /mnt/dietpi_userdata/roon fi if To_Uninstall 154 # Roon Server then Remove_Service roonserver 1 1 [[ -f '/etc/sudoers.d/roonserver' ]] && G_EXEC rm /etc/sudoers.d/roonserver [[ -d '/opt/roonserver' ]] && G_EXEC rm -R /opt/roonserver [[ -d '/var/log/roonserver' ]] && G_EXEC rm -R /var/log/roonserver [[ -d '/mnt/dietpi_userdata/roonserver' ]] && G_EXEC rm -R /mnt/dietpi_userdata/roonserver fi if To_Uninstall 156 # Steam then G_AGP steam G_EXEC rm -Rf /{root,home/*}/{.steam{,path,pid},Desktop/steam.desktop} /mnt/dietpi_userdata/steam fi if To_Uninstall 62 # Box86 then [[ -f '/etc/binfmt.d/box86.conf' ]] && G_EXEC rm /etc/binfmt.d/box86.conf [[ -d '/proc/sys/fs/binfmt_misc' ]] && G_EXEC systemctl restart systemd-binfmt [[ -f '/usr/local/bin/box86' ]] && G_EXEC rm /usr/local/bin/box86 for i in /usr/lib/i386-linux-gnu/lib{gcc_s,png12,stdc++,unwind}.so* do [[ -e $i ]] && ! dpkg-query -S "$i" &> /dev/null && G_EXEC rm "$i" done [[ -d '/usr/lib/i386-linux-gnu' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /usr/lib/i386-linux-gnu fi if To_Uninstall 197 # Box64 then [[ -f '/etc/binfmt.d/box64.conf' ]] && G_EXEC rm /etc/binfmt.d/box64.conf [[ -d '/proc/sys/fs/binfmt_misc' ]] && G_EXEC systemctl restart systemd-binfmt [[ -f '/usr/local/bin/box64' ]] && G_EXEC rm /usr/local/bin/box64 for i in /usr/lib/x86_64-linux-gnu/lib{crypto,gcc_s,mbed,png12,ssl,stdc++,unwind}* do [[ -e $i ]] && ! dpkg-query -S "$i" &> /dev/null && G_EXEC rm "$i" done [[ -d '/usr/lib/x86_64-linux-gnu' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /usr/lib/x86_64-linux-gnu fi if To_Uninstall 207 # Moonlight (CLI) then G_AGP moonlight-embedded [[ -f '/etc/apt/sources.list.d/dietpi-moonlight.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-moonlight.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-moonlight.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-moonlight.gpg fi if To_Uninstall 208 # Moonlight (GUI) then dpkg-query -s 'libgl1' &> /dev/null && G_EXEC apt-mark auto libgl1 G_AGP moonlight-qt [[ -f '/etc/apt/sources.list.d/dietpi-moonlight-qt.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-moonlight-qt.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-moonlight-qt.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-moonlight-qt.gpg fi if To_Uninstall 11 # GZDoom then G_AGP gzdoom fi if To_Uninstall 119 # CAVA then G_AGP cava G_EXEC rm -Rf /{root,home/*}/.config/cava fi if To_Uninstall 118 # Mopidy then Remove_Service mopidy G_AGP 'mopidy*' [[ -f '/etc/apt/sources.list.d/dietpi-mopidy.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-mopidy.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-mopidy.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-mopidy.gpg command -v pip3 > /dev/null && G_EXEC_OUTPUT=1 G_EXEC pip3 uninstall -y Mopidy-MusicBox-Webclient getent passwd mopidy > /dev/null && G_EXEC userdel mopidy [[ -d '/mnt/dietpi_userdata/mopidy' ]] && G_EXEC rm -R /mnt/dietpi_userdata/mopidy fi if To_Uninstall 31 # Kodi then G_AGP kodi kodi-odroid kodi-aml-fbdev-odroid G_EXEC rm -Rf /{root,home/*}/{.kodi,Desktop/kodi.desktop} [[ -f '/usr/share/applications/kodi.desktop' ]] && G_EXEC rm /usr/share/applications/kodi.desktop [[ -f '/etc/udev/rules.d/99-dietpi-kodi.rules' ]] && G_EXEC rm /etc/udev/rules.d/99-dietpi-kodi.rules [[ -f '/etc/modules-load.d/dietpi-n2-kodi.conf' ]] && G_EXEC rm /etc/modules-load.d/dietpi-n2-kodi.conf [[ -f '/etc/modules-load.d/dietpi-c4-kodi.conf' ]] && G_EXEC rm /etc/modules-load.d/dietpi-c4-kodi.conf [[ -f '/var/lib/dietpi/dietpi-software/installed/desktop/icons/kodi-icon.png' ]] && G_EXEC rm /var/lib/dietpi/dietpi-software/installed/desktop/icons/kodi-icon.png fi if To_Uninstall 39 # ReadyMedia then Remove_Service minidlna 1 1 G_AGP minidlna [[ -d '/mnt/dietpi_userdata/.MiniDLNA_Cache' ]] && G_EXEC rm -R /mnt/dietpi_userdata/.MiniDLNA_Cache [[ -d '/var/log/minidlna' ]] && G_EXEC rm -R /var/log/minidlna fi if To_Uninstall 51 # OpenTyrian then # shellcheck disable=SC2046 apt-mark auto $(dpkg --get-selections libsdl1.2debian libsdl-net1.2 2> /dev/null | mawk '{print $1}') 2> /dev/null G_EXEC rm -f /{usr/share/applications,{root,home/*}/Desktop}/opentyrian.desktop [[ -d '/usr/games/opentyrian' ]] && G_EXEC rm -R /usr/games/opentyrian fi if To_Uninstall 59 # RPi Cam Web Interface then Remove_Service raspimjpeg [[ -f '/var/lib/dietpi/dietpi-software/installed/raspimjpeg.sh' ]] && G_EXEC rm /var/lib/dietpi/dietpi-software/installed/raspimjpeg.sh [[ -f '/usr/local/bin/raspimjpeg' ]] && G_EXEC rm /usr/local/bin/raspimjpeg [[ -f '/etc/raspimjpeg' ]] && G_EXEC rm /etc/raspimjpeg G_AGP gpac [[ -d '/var/www/rpicam' ]] && G_EXEC rm -R /var/www/rpicam [[ -f '/etc/sudoers.d/dietpi-rpi_cam_control' ]] && G_EXEC rm /etc/sudoers.d/dietpi-rpi_cam_control fi if To_Uninstall 45 # Deluge then Remove_Service deluge-web Remove_Service deluged debian-deluged debian-deluged [[ -d '/mnt/dietpi_userdata/deluge' ]] && G_EXEC rm -R /mnt/dietpi_userdata/deluge G_AGP deluged deluge-web deluge-console fi if To_Uninstall 94 # ProFTPD then G_AGP proftpd-basic fi if To_Uninstall 96 # Samba Server then G_AGP samba samba-common-bin getent passwd samba > /dev/null && G_EXEC userdel samba [[ -f '/etc/tmpfiles.d/dietpi-samba_cache.conf' ]] && G_EXEC rm /etc/tmpfiles.d/dietpi-samba_cache.conf [[ -d '/run/samba-cache' ]] && G_EXEC rm -R /run/samba-cache G_EXEC rm -Rf /var/cache/samba # Symlink fi if To_Uninstall 95 # vsftpd then G_AGP vsftpd fi if To_Uninstall 109 # NFS Server then G_AGP nfs-kernel-server G_EXEC rm -Rf /etc/exports{,.d} fi if To_Uninstall 93 # Pi-hole then # Uninstaller # - Skip dialogue [[ -f '/opt/pihole/uninstall.sh' ]] && G_EXEC sed --follow-symlinks -i '/^[[:blank:]]*read -rp .*Are you sure you would like to remove.* answer$/c\answer=y' /opt/pihole/uninstall.sh command -v pihole > /dev/null && G_EXEC_OUTPUT=1 G_EXEC pihole uninstall # - Call script directly if pihole command was not available (anymore) [[ -f '/opt/pihole/uninstall.sh' ]] && G_EXEC_OUTPUT=1 G_EXEC /opt/pihole/uninstall.sh # Cleanup if uninstaller was not available (anymore) # - Service Remove_Service pihole-FTL pihole pihole # - Files [[ -f '/usr/bin/pihole-FTL' ]] && G_EXEC rm /usr/bin/pihole-FTL [[ -e '/usr/local/bin/pihole' ]] && G_EXEC rm /usr/local/bin/pihole # - Dirs [[ -d '/etc/pihole' ]] && G_EXEC rm -R /etc/pihole [[ -d '/etc/.pihole' ]] && G_EXEC rm -R /etc/.pihole [[ -d '/opt/pihole' ]] && G_EXEC rm -R /opt/pihole [[ -d '/var/www/html/admin' ]] && G_EXEC rm -R /var/www/html/admin [[ -d '/var/www/html/pihole' ]] && G_EXEC rm -R /var/www/html/pihole # v5 # - Symlinks [[ -L '/var/www/pihole' ]] && G_EXEC rm /var/www/pihole [[ -L '/var/www/admin' ]] && G_EXEC rm /var/www/admin # - Webserver configs [[ -d '/etc/apache2/sites-available' ]] && G_EXEC rm -f /etc/apache2/sites-{available,enabled}/dietpi-pihole* [[ -d '/etc/lighttpd/conf-available' ]] && G_EXEC rm -f /etc/lighttpd/conf-{available,enabled}/99-dietpi-pihole* [[ -d '/etc/nginx/sites-dietpi' ]] && G_EXEC rm -f /etc/nginx/sites-dietpi/dietpi-pihole* # Unbound: Switch port to 53 if it is still installed if (( ${aSOFTWARE_INSTALL_STATE[182]} == 2 )) && grep -Eq '^[[:blank:]]*port:[[:blank:]]+5335$' /etc/unbound/unbound.conf.d/dietpi.conf then G_DIETPI-NOTIFY 2 'Reconfiguring Unbound to work on its own' G_CONFIG_INJECT 'port:[[:blank:]]' ' port: 53' /etc/unbound/unbound.conf.d/dietpi.conf G_CONFIG_INJECT 'interface:[[:blank:]]' ' interface: 0.0.0.0' /etc/unbound/unbound.conf.d/dietpi.conf grep -E '^[[:blank:]]*nameserver[[:blank:]]+127.0.0.1:5335$' /etc/resolv.conf && sed --follow-symlinks -Ei '/^[[:blank:]]*nameserver[[:blank:]]+127.0.0.1:5335$/c\nameserver 127.0.0.1' /etc/resolv.conf # Failsafe G_EXEC_NOEXIT=1 G_EXEC systemctl restart unbound else grep '^[[:blank:]]*nameserver[[:blank:]]' /etc/resolv.conf | grep -qvE '[[:blank:]]127.0.0.1(:53)?$' || echo 'nameserver 9.9.9.9' >> /etc/resolv.conf # Failsafe fi fi if To_Uninstall 126 # AdGuard Home then Remove_Service adguardhome 1 # Data directory [[ -d '/mnt/dietpi_userdata/adguardhome' ]] && G_EXEC rm -R /mnt/dietpi_userdata/adguardhome # Unbound: Switch port to 53 if it is still installed if (( ${aSOFTWARE_INSTALL_STATE[182]} == 2 )) && grep -Eq '^[[:blank:]]*port:[[:blank:]]+5335$' /etc/unbound/unbound.conf.d/dietpi.conf then G_DIETPI-NOTIFY 2 'Reconfiguring Unbound to work on its own' G_CONFIG_INJECT 'port:[[:blank:]]' ' port: 53' /etc/unbound/unbound.conf.d/dietpi.conf G_CONFIG_INJECT 'interface:[[:blank:]]' ' interface: 0.0.0.0' /etc/unbound/unbound.conf.d/dietpi.conf grep -E '^[[:blank:]]*nameserver[[:blank:]]+127.0.0.1:5335$' /etc/resolv.conf && sed --follow-symlinks -Ei '/^[[:blank:]]*nameserver[[:blank:]]+127.0.0.1:5335$/c\nameserver 127.0.0.1' /etc/resolv.conf # Failsafe G_EXEC_NOEXIT=1 G_EXEC systemctl restart unbound else grep '^[[:blank:]]*nameserver[[:blank:]]' /etc/resolv.conf | grep -qvE '[[:blank:]]127.0.0.1(:53)?$' || echo 'nameserver 9.9.9.9' >> /etc/resolv.conf # Failsafe fi fi if To_Uninstall 33 # Airsonic-Advanced then Remove_Service airsonic 1 [[ -d '/mnt/dietpi_userdata/airsonic' ]] && G_EXEC rm -R /mnt/dietpi_userdata/airsonic fi if To_Uninstall 204 # Navidrome then Remove_Service navidrome 1 G_EXEC rm -Rf /opt/navidrome /mnt/dietpi_userdata/navidrome fi if To_Uninstall 212 # Kavita then Remove_Service kavita 1 G_EXEC rm -Rf /opt/kavita fi if To_Uninstall 71 # WebIOPi then Remove_Service webiopi [[ -f '/usr/bin/webiopi' ]] && G_EXEC rm /usr/bin/webiopi # Executable [[ -f '/usr/bin/webiopi-passwd' ]] && G_EXEC rm /usr/bin/webiopi-passwd # Password generator [[ -d '/etc/webiopi' ]] && G_EXEC rm -R /etc/webiopi # Config dir [[ -d '/usr/share/webiopi' ]] && G_EXEC rm -R /usr/share/webiopi # HTML resources G_EXEC rm -Rf /usr/local/lib/python*/dist-packages/WebIOPi* # Python packages fi if To_Uninstall 68 # Remote.It then G_AGP remoteit connectd weavedconnectd # connectd: pre-v8.10, weavedconnectd: pre-v6.22 fi if To_Uninstall 186 # Kubo then Remove_Service ipfs 1 1 G_EXEC rm -Rf /usr/local/bin/ipfs /etc/bashrc.d/dietpi-ipfs.sh /etc/sysctl.d/dietpi-ipfs.conf /mnt/dietpi_userdata/ipfs fi if To_Uninstall 16 # microblog.pub then Remove_Service microblog-pub 1 1 [[ -f '/etc/bashrc.d/microblog-pub.sh' ]] && G_EXEC rm /etc/bashrc.d/microblog-pub.sh [[ -d '/opt/microblog-pub' ]] && G_EXEC rm -R /opt/microblog-pub G_DIETPI-NOTIFY 2 'All microblog.pub data and settings are still retained.\n - You can remove these manually: rm -R /mnt/dietpi_userdata/microblog-pub' fi if To_Uninstall 98 # HAProxy then Remove_Service haproxy G_EXEC rm -Rf /{etc,var/lib,/usr/local/{doc,sbin}}/haproxy /usr/local/share/man/man1/haproxy.1 [[ -d '/usr/local/share/man/man1' ]] && G_EXEC rmdir -p --ignore-fail-on-non-empty /usr/local/share/man/man1 fi if To_Uninstall 35 # Lyrion Music Server then # Stop systemd service, which is not done by postinst, failing to remove user then Remove_Service lyrionmusicserver G_AGP lyrionmusicserver [[ -d '/var/lib/squeezeboxserver' ]] && G_EXEC rm -R /var/lib/squeezeboxserver fi if To_Uninstall 55 # WordPress then [[ -d '/var/www/wordpress' ]] && G_EXEC rm -R /var/www/wordpress Remove_Database wordpress fi if To_Uninstall 38 # FreshRSS then crontab -u www-data -l | grep -v '/opt/FreshRSS/app/actualize_script.php' | crontab -u www-data - a2disconf dietpi-freshrss 2> /dev/null [[ -f '/etc/apache2/conf-available/dietpi-freshrss.conf' ]] && G_EXEC rm /etc/apache2/conf-available/dietpi-freshrss.conf G_EXEC rm -Rf /var/www/freshrss # symlink [[ -d '/opt/FreshRSS' ]] && G_EXEC rm -R /opt/FreshRSS [[ -f '/var/log/freshrss.log' ]] && G_EXEC rm /var/log/freshrss.log Remove_Database freshrss fi if To_Uninstall 28 || To_Uninstall 120 # TigerVNC/RealVNC then # RealVNC services Remove_Service vncserver-x11-serviced Remove_Service vncserver-virtuald G_AGP 'tigervnc-*' x11vnc realvnc-vnc-server Remove_Service vncserver [[ -f '/usr/local/bin/vncserver' ]] && G_EXEC rm /usr/local/bin/vncserver G_EXEC rm -Rf /{root,home/*}/.vnc fi if To_Uninstall 73 # Fail2Ban then G_AGP fail2ban dpkg-query -s 'python3-systemd' &> /dev/null && G_EXEC apt-mark auto python3-systemd [[ -d '/etc/fail2ban' ]] && G_EXEC rm -R /etc/fail2ban fi if To_Uninstall 64 # phpSysInfo then [[ -d '/var/www/phpsysinfo' ]] && G_EXEC rm -R /var/www/phpsysinfo fi if To_Uninstall 56 # Single File PHP Gallery then [[ -f '/var/www/gallery/index.php' ]] && G_EXEC rm /var/www/gallery/index.php [[ -f '/var/www/gallery/readme.txt' ]] && G_EXEC rm /var/www/gallery/readme.txt [[ -d '/var/www/gallery/_sfpg_data' ]] && G_EXEC rm -R /var/www/gallery/_sfpg_data G_DIETPI-NOTIFY 2 'The plain gallery image files are not removed. You may do this manually via "rm -R /var/www/gallery".' fi if To_Uninstall 40 # Ampache then [[ -d '/var/www/ampache' || -L '/var/www/ampache' ]] && G_EXEC rm -R /var/www/ampache [[ -d '/mnt/dietpi_userdata/ampache' ]] && G_EXEC rm -R /mnt/dietpi_userdata/ampache Remove_Database ampache fi if To_Uninstall 117 # PiVPN then [[ -f '/opt/pivpn/uninstall.sh' ]] && G_EXEC sed --follow-symlinks -i 's/ askreboot;//' /opt/pivpn/uninstall.sh command -v pivpn > /dev/null && G_EXEC_OUTPUT=1 G_EXEC pivpn -u getent passwd pivpn > /dev/null && G_EXEC userdel pivpn getent group pivpn > /dev/null && G_EXEC groupdel pivpn [[ -f '/etc/apt/sources.list.d/swupdate.openvpn.net.list' ]] && G_EXEC rm /etc/apt/sources.list.d/swupdate.openvpn.net.list # Not part of current installer anymore fi if To_Uninstall 201 # ZeroTier then G_AGP zerotier-one [[ -d '/etc/systemd/system/zerotier-one.service.d' ]] && G_EXEC rm -R /etc/systemd/system/zerotier-one.service.d [[ -d '/var/lib/zerotier-one' ]] && G_EXEC rm -R /var/lib/zerotier-one [[ -f '/etc/apt/sources.list.d/dietpi-zerotier.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-zerotier.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-zerotier.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-zerotier.gpg fi if To_Uninstall 97 # OpenVPN Server then G_AGP openvpn [[ -d '/etc/systemd/system/openvpn.service.d' ]] && G_EXEC rm -R /etc/systemd/system/openvpn.service.d [[ -d '/etc/openvpn' ]] && G_EXEC rm -R /etc/openvpn [[ -f '/etc/sysctl.d/dietpi-openvpn.conf' ]] && G_EXEC rm /etc/sysctl.d/dietpi-openvpn.conf fi if To_Uninstall 172 # WireGuard then G_AGP 'wireguard*' [[ -d '/etc/systemd/system/wg-quick@wg0.service.d' ]] && G_EXEC rm -R /etc/systemd/system/wg-quick@wg0.service.d [[ -d '/etc/wireguard' ]] && G_EXEC rm -R /etc/wireguard [[ -f '/etc/apt/sources.list.d/dietpi-wireguard.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-wireguard.list fi if To_Uninstall 58 # Tailscale then G_AGP tailscale [[ -d '/etc/systemd/system/tailscaled.service.d' ]] && G_EXEC rm -R /etc/systemd/system/tailscaled.service.d [[ -d '/var/lib/tailscale' ]] && G_EXEC rm -R /var/lib/tailscale [[ -f '/etc/sysctl.d/dietpi-tailscale.conf' ]] && G_EXEC rm /etc/sysctl.d/dietpi-tailscale.conf [[ -f '/etc/apt/sources.list.d/dietpi-tailscale.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-tailscale.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-tailscale.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-tailscale.gpg fi if To_Uninstall 92 # Certbot then G_AGP python3-certbot-apache python3-certbot-nginx certbot [[ -d '/etc/systemd/system/certbot.service.d' ]] && G_EXEC rm -R /etc/systemd/system/certbot.service.d fi if To_Uninstall 69 # Python 3 RPi.GPIO then G_AGP python3-rpi-lgpio python3-rpi.gpio fi if To_Uninstall 72 # I2C then G_AGP i2c-tools /boot/dietpi/func/dietpi-set_hardware i2c disable fi if To_Uninstall 70 # WiringPi then if [[ -d '/mnt/dietpi_userdata/WiringPi' ]] then G_EXEC cd /mnt/dietpi_userdata/WiringPi if [[ -f ./build ]] then G_EXEC_NOEXIT=1 G_EXEC_OUTPUT=1 G_EXEC ./build uninstall # RPi and pre-v8.5 Odroids elif [[ -f ./Makefile ]] then G_EXEC_NOEXIT=1 G_EXEC_OUTPUT=1 G_EXEC make uninstall # Odroids fi G_EXEC cd "$G_WORKING_DIR" G_EXEC rm -R /mnt/dietpi_userdata/WiringPi fi # Pre-v7.2 if [[ -d '/root/wiringPi' ]] then G_EXEC cd /root/wiringPi G_EXEC_NOEXIT=1 G_EXEC_OUTPUT=1 G_EXEC ./build uninstall G_EXEC cd "$G_WORKING_DIR" G_EXEC rm -R /root/wiringPi fi # GPIO utility [[ -f '/usr/local/bin/gpio' ]] && G_EXEC rm /usr/local/bin/gpio [[ -f '/usr/local/sbin/gpio' ]] && G_EXEC rm /usr/local/sbin/gpio [[ -f '/usr/local/share/man/man1/gpio.1' ]] && G_EXEC rm /usr/local/share/man/man1/gpio.1 [[ -d '/usr/local/share/man/man1' ]] && G_EXEC rmdir -p --ignore-fail-on-non-empty /usr/local/share/man/man1 # Library G_EXEC rm -f /usr/local/lib/libwiringPi.so* # Device library G_EXEC rm -f /usr/local/lib/libwiringPiDev.so* # Headers G_EXEC rm -f /usr/local/include/wiringPi*.h # Orange Pi [[ -f '/etc/orangepi-release' ]] && grep -q '^# Added by DietPi:$' /etc/orangepi-release && G_EXEC rm /etc/orangepi-release fi if To_Uninstall 61 # Tor Hotspot then G_AGP tor [[ -d '/var/log/tor' ]] && G_EXEC rm -R /var/log/tor # pre-v6.27 # Uninstall WiFi Hotspot too, due to iptables needing reset aSOFTWARE_INSTALL_STATE[60]=-1 fi if To_Uninstall 60 # WiFi Hotspot then G_AGP hostapd isc-dhcp-server [[ -f '/etc/dhcp/dhcpd.conf' ]] && G_EXEC rm /etc/dhcp/dhcpd.conf [[ -f '/etc/hostapd/hostapd.conf' ]] && G_EXEC rm /etc/hostapd/hostapd.conf [[ -f '/etc/default/isc-dhcp-server' ]] && G_EXEC rm /etc/default/isc-dhcp-server [[ -f '/etc/default/hostapd' ]] && G_EXEC rm /etc/default/hostapd [[ -f '/etc/iptables.ipv4.nat' ]] && G_EXEC rm /etc/iptables.ipv4.nat [[ -f '/etc/iptables.ipv6.nat' ]] && G_EXEC rm /etc/iptables.ipv6.nat [[ -f '/etc/sysctl.d/dietpi-wifihotspot.conf' ]] && G_EXEC rm /etc/sysctl.d/dietpi-wifihotspot.conf # Set WiFi interface back to inactive and ready for use with dietpi-config. local wifi_iface=$(G_GET_NET -t wlan iface) # - Remove WLAN block, so we can recreate it G_EXEC sed --follow-symlinks -Ei '/(allow-hotplug|auto)[[:blank:]]+wlan/q0' /etc/network/interfaces # - Disable G_EXEC sed --follow-symlinks -i "/allow-hotplug wlan/c\#allow-hotplug $wifi_iface" /etc/network/interfaces # - Add default WiFi settings to network interfaces config cat << _EOF_ >> /etc/network/interfaces iface $wifi_iface inet dhcp address 192.168.0.101 netmask 255.255.255.0 #gateway 192.168.0.1 #dns-nameservers 9.9.9.9 149.112.112.112 pre-up iw dev $wifi_iface set power_save off post-down iw dev $wifi_iface set power_save on wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf _EOF_ # shellcheck disable=SC2015 iw dev "$wifi_iface" set power_save on 2> /dev/null && iw dev "$wifi_iface" set power_save off 2> /dev/null || G_EXEC sed --follow-symlinks -i '/ iw dev .* set power_save /d' /etc/network/interfaces # - Flush iptables iptables -F iptables -t nat -F ip6tables -F ip6tables -t nat -F fi if To_Uninstall 48 # Pydio then [[ -d '/var/www/pydio' ]] && G_EXEC rm -R /var/www/pydio # Remove webserver configs command -v a2dissite > /dev/null && a2dissite dietpi-pydio [[ -f '/etc/apache2/conf-available/dietpi-pydio.conf' ]] && G_EXEC rm /etc/apache2/conf-available/dietpi-pydio.conf [[ -f '/etc/nginx/sites-dietpi/dietpi-pydio.conf' ]] && G_EXEC rm /etc/nginx/sites-dietpi/dietpi-pydio.conf command -v lighty-disable-mod > /dev/null && lighty-disable-mod dietpi-pydio [[ -f '/etc/lighttpd/conf-available/99-dietpi-pydio.conf' ]] && G_EXEC rm /etc/lighttpd/conf-available/99-dietpi-pydio.conf Remove_Database pydio fi if To_Uninstall 36 # Squeezelite then G_AGP squeezelite Remove_Service squeezelite 1 1 # Pre-v7.3 fi if To_Uninstall 66 # RPi-Monitor then G_AGP rpimonitor [[ -d '/etc/rpimonitor' ]] && G_EXEC rm -R /etc/rpimonitor [[ -d '/var/lib/rpimonitor' ]] && G_EXEC rm -R /var/lib/rpimonitor [[ -f '/var/log/rpimonitor.log' ]] && G_EXEC rm /var/log/rpimonitor.log fi if To_Uninstall 57 # Baïkal then # Remove webserver configs # - Lighttpd if [[ -f '/etc/lighttpd/conf-available/99-dietpi-dav_redirect.conf' ]] then command -v lighty-disable-mod > /dev/null && lighty-disable-mod dietpi-dav_redirect G_EXEC rm /etc/lighttpd/conf-available/99-dietpi-dav_redirect.conf fi if [[ -f '/etc/lighttpd/conf-available/99-dietpi-baikal.conf' ]] then command -v lighty-disable-mod > /dev/null && lighty-disable-mod dietpi-baikal G_EXEC rm /etc/lighttpd/conf-available/99-dietpi-baikal.conf fi # - Apache if [[ -f '/etc/apache2/conf-available/dietpi-dav_redirect.conf' ]] then command -v a2disconf > /dev/null && a2disconf dietpi-dav_redirect G_EXEC rm /etc/apache2/conf-available/dietpi-dav_redirect.conf fi if [[ -f '/etc/apache2/sites-available/dietpi-baikal.conf' ]] then command -v a2dissite > /dev/null && a2dissite dietpi-baikal G_EXEC rm /etc/apache2/sites-available/dietpi-baikal.conf fi # - Nginx [[ -f '/etc/nginx/sites-dietpi/dietpi-dav_redirect.conf' ]] && G_EXEC rm /etc/nginx/sites-dietpi/dietpi-dav_redirect.conf [[ -f '/etc/nginx/sites-dietpi/dietpi-baikal.conf' ]] && G_EXEC rm /etc/nginx/sites-dietpi/dietpi-baikal.conf [[ -d '/var/www/baikal' ]] && G_EXEC rm -R /var/www/baikal Remove_Database baikal fi if To_Uninstall 65 # Netdata then G_AGP netdata fi if To_Uninstall 43 # Mumble Server then G_AGP mumble-server fi if To_Uninstall 41 # Emby then G_AGP emby-server fi if To_Uninstall 42 # Plex Media Server then # Force deletion of plex group which is not removed automatically because it is not the primary group of user plex Remove_Service plexmediaserver plex plex # Remove systemd unit which currently survives the package purging: https://github.com/MichaIng/DietPi/issues/3551 [[ -f '/lib/systemd/system/plexmediaserver.service' ]] && G_EXEC rm /lib/systemd/system/plexmediaserver.service G_AGP plexmediaserver [[ -d '/var/lib/plexmediaserver' ]] && G_EXEC rm -R /var/lib/plexmediaserver # Left over from purging package, still... [[ -f '/etc/unbound/unbound.conf.d/dietpi-plex.conf' ]] && G_EXEC rm /etc/unbound/unbound.conf.d/dietpi-plex.conf fi if To_Uninstall 52 # Cuberite then Remove_Service cuberite 1 1 [[ -d '/mnt/dietpi_userdata/cuberite' ]] && G_EXEC rm -R /mnt/dietpi_userdata/cuberite fi if To_Uninstall 53 # MineOS then Remove_Service mineos 1 1 [[ -d '/mnt/dietpi_userdata/mineos' ]] && G_EXEC rm -R /mnt/dietpi_userdata/mineos [[ -f '/etc/mineos.conf' ]] && G_EXEC rm /etc/mineos.conf G_EXEC rm -Rf /var/games/minecraft /usr/local/bin/mineos /etc/ssl/certs/mineos.* # Symlinks and SSL cert [[ -d '/home/mineos' ]] && G_EXEC rm -R /home/mineos # pre-v6.34 fi if To_Uninstall 49 # Gogs then Remove_Service gogs 1 1 # Data [[ -d '/etc/gogs' ]] && G_EXEC rm -R /etc/gogs [[ -d '/var/log/gogs' ]] && G_EXEC rm -R /var/log/gogs Remove_Database gogs fi if To_Uninstall 46 # qBittorrent then Remove_Service qbittorrent 1 1 # group for pre-v6.29 G_AGP qbittorrent-nox [[ -d '/home/qbittorrent' ]] && G_EXEC rm -R /home/qbittorrent [[ -d '/var/log/qbittorrent' ]] && G_EXEC rm -R /var/log/qbittorrent fi if To_Uninstall 50 # Syncthing then Remove_Service syncthing 1 [[ -d '/opt/syncthing' ]] && G_EXEC rm -R /opt/syncthing [[ -d '/mnt/dietpi_userdata/syncthing' ]] && G_EXEC rm -R /mnt/dietpi_userdata/syncthing #[[ -d '/mnt/dietpi_userdata/syncthing_data' ]] && G_EXEC rm -R /mnt/dietpi_userdata/syncthing_data # Leave data in place [[ -f '/etc/sysctl.d/dietpi-syncthing.conf' ]] && G_EXEC rm /etc/sysctl.d/dietpi-syncthing.conf fi if To_Uninstall 116 # Medusa then Remove_Service medusa 1 1 # group for pre-v6.33 [[ -d '/mnt/dietpi_userdata/medusa' ]] && G_EXEC rm -R /mnt/dietpi_userdata/medusa fi if To_Uninstall 107 # rTorrent then # ruTorrent [[ -d '/var/www/rutorrent' ]] && G_EXEC rm -R /var/www/rutorrent # - Authentication [[ -f '/etc/.rutorrent-htaccess' ]] && G_EXEC rm /etc/.rutorrent-htaccess # - Lighttpd # Pre-v7.2: Remove from #RUTORRENT_DIETPI to #RUTORRENT_DIETPI in /etc/lighttpd/lighttpd.conf if exist [[ -f '/etc/lighttpd/lighttpd.conf' ]] && grep -q '^#RUTORRENT_DIETPI' /etc/lighttpd/lighttpd.conf && G_EXEC sed --follow-symlinks -i '/#RUTORRENT_DIETPI/,/#RUTORRENT_DIETPI/d' /etc/lighttpd/lighttpd.conf # Remove rTorrent config from Lighttpd [[ -f '/etc/lighttpd/conf-enabled/98-dietpi-rtorrent.conf' ]] && G_EXEC lighty-disable-mod dietpi-rtorrent [[ -f '/etc/lighttpd/conf-available/98-dietpi-rtorrent.conf' ]] && G_EXEC rm /etc/lighttpd/conf-available/98-dietpi-rtorrent.conf # - Nginx [[ -f '/etc/nginx/sites-dietpi/dietpi-rutorrent.conf' ]] && G_EXEC rm /etc/nginx/sites-dietpi/dietpi-rutorrent.conf # - Apache command -v a2dissite &> /dev/null && a2dissite dietpi-rutorrent [[ -f '/etc/apache2/sites-available/dietpi-rutorrent.conf' ]] && G_EXEC rm /etc/apache2/sites-available/dietpi-rutorrent.conf # rTorrent Remove_Service rtorrent 1 1 # group for pre-v6.29 G_AGP rtorrent [[ -d '/mnt/dietpi_userdata/rtorrent' ]] && G_EXEC rm -R /mnt/dietpi_userdata/rtorrent [[ -d '/mnt/dietpi_userdata/downloads/.session' ]] && G_EXEC rm -R /mnt/dietpi_userdata/downloads/.session fi if To_Uninstall 108 # Amiberry then G_AGP amiberry Remove_Service amiberry # pre-v8.5 # Files [[ -d '/mnt/dietpi_userdata/amiberry' ]] && G_EXEC rm -R /mnt/dietpi_userdata/amiberry # Autostart index: If currently Amiberry, revert to console login [[ -f '/boot/dietpi/.dietpi-autostart_index' && $( /dev/null | mawk '{print $1}') 2> /dev/null fi if To_Uninstall 113 # Chromium then # Package G_AGP 'chromium*' # Files [[ -d '/etc/chromium.d' ]] && G_EXEC rm -R /etc/chromium.d [[ -d '/usr/lib/chromium' ]] && G_EXEC rm -R /usr/lib/chromium [[ -d '/usr/lib/chromium-browser' ]] && G_EXEC rm -R /usr/lib/chromium-browser G_EXEC rm -Rf /{root,home/*}/{.chromium-browser.init,.{cache,config}/chromium,Desktop/chromium{,-browser}.desktop} [[ -f '/var/lib/dietpi/dietpi-software/installed/chromium-autostart.sh' ]] && G_EXEC rm /var/lib/dietpi/dietpi-software/installed/chromium-autostart.sh # Autostart index: If currently Chromium, revert to console login [[ -f '/boot/dietpi/.dietpi-autostart_index' && $( /dev/null && command -v pip3 > /dev/null && G_EXEC_OUTPUT=1 G_EXEC pip3 uninstall -y docker-compose # Pre-v8.2 fi if To_Uninstall 162 # Docker then Remove_Service docker # Packages, repo and key G_AGP docker-ce docker-ce-cli docker.io [[ -f '/etc/apt/sources.list.d/docker.list' ]] && G_EXEC rm /etc/apt/sources.list.d/docker.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-docker.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-docker.gpg # DietPi data dir [[ -d '/mnt/dietpi_userdata/docker-data' ]] && G_EXEC rm -R /mnt/dietpi_userdata/docker-data # Default data dir [[ -d '/var/lib/docker' ]] && G_EXEC rm -R /var/lib/docker # Config dir [[ -d '/etc/docker' ]] && G_EXEC rm -R /etc/docker # Set Portainer as not installed aSOFTWARE_INSTALL_STATE[185]=0 fi if To_Uninstall 164 # Nukkit then Remove_Service nukkit [[ -d '/usr/local/bin/nukkit' ]] && G_EXEC rm -R /usr/local/bin/nukkit fi if To_Uninstall 163 # GMediaRender then G_AGP gmediarender fi if To_Uninstall 67 # Firefox then G_AGP firefox-esr G_EXEC rm -Rf /{root,home/*}/.mozilla/firefox for i in /{root,home/*}/.mozilla; do [[ -d $i ]] && G_EXEC rmdir --ignore-fail-on-non-empty "$i"; done fi if To_Uninstall 159 # Allo GUI full then # Mark standalone version for uninstall aSOFTWARE_INSTALL_STATE[160]=-1 fi if To_Uninstall 160 # Allo GUI then # Files [[ -f '/var/www/index.php' ]] && G_EXEC rm /var/www/index.php G_EXEC rm -Rf /var/www/allo [[ -d '/opt/allo' ]] && G_EXEC rm -R /opt/allo [[ -f '/etc/sudoers.d/allo' ]] && G_EXEC rm /etc/sudoers.d/allo # Database Remove_Database allo # Mark full version as uninstalled aSOFTWARE_INSTALL_STATE[159]=0 fi if To_Uninstall 88 # MariaDB then # Do a full database backup if binary is still available: https://github.com/MichaIng/DietPi/issues/3257#issuecomment-568764107 if command -v mysqldump > /dev/null then G_WHIP_MSG "Creating MariaDB database backup before uninstallation:\n\nIn case of accident, we create a database backup for you. You can remove it manually if you are sure that you don't need it any more.\n\n/mnt/dietpi_userdata/mariadb-database-backup.sql" G_EXEC systemctl start mariadb mysqldump --all-databases > /mnt/dietpi_userdata/mariadb-database-backup.sql systemctl stop mariadb fi G_AGP mariadb-server 'php*-mysql' G_EXEC rm -Rf /{mnt/dietpi_userdata,var/lib,var/log,etc}/mysql /{root,home/*}/.mysql_history fi if To_Uninstall 77 # Grafana then Remove_Service grafana-server grafana grafana G_AGP grafana [[ -f '/etc/apt/sources.list.d/grafana.list' ]] && G_EXEC rm /etc/apt/sources.list.d/grafana.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-grafana.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-grafana.gpg G_EXEC rm -Rf /{mnt/dietpi_userdata,var/{lib,log},etc}/grafana fi if To_Uninstall 74 # InfluxDB then Remove_Service influxdb 1 1 G_AGP influxdb [[ -f '/etc/apt/sources.list.d/dietpi-influxdb.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-influxdb.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-influxdb.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-influxdb.gpg G_EXEC rm -Rf /{mnt/dietpi_userdata,var/{lib,log},etc}/influxdb fi if To_Uninstall 80 # Ubooquity then Remove_Service ubooquity 1 1 [[ -d '/mnt/dietpi_userdata/ubooquity' ]] && G_EXEC rm -R /mnt/dietpi_userdata/ubooquity fi if To_Uninstall 179 # Komga then Remove_Service komga 1 1 [[ -d '/mnt/dietpi_userdata/komga' ]] && G_EXEC rm -R /mnt/dietpi_userdata/komga fi if To_Uninstall 86 # Roon Extension Manager then local installer='/mnt/dietpi_userdata/roon-extension-manager/rem-setup.sh' user='roon-extension-manager' # Pre-v8.2 if [[ ! -f $installer ]] then G_EXEC curl -sSfL 'https://raw.githubusercontent.com/TheAppgineer/roon-extension-manager/v1.x/rem-setup.sh' -o rem-setup.sh G_EXEC chmod +x rem-setup.sh installer='./rem-setup.sh' user='root' fi SUDO_USER=$user G_EXEC_OUTPUT=1 G_EXEC "$installer" --uninstall G_EXEC rm "$installer" getent passwd roon-extension-manager > /dev/null && G_EXEC userdel roon-extension-manager getent group roon-extension-manager > /dev/null && G_EXEC groupdel roon-extension-manager [[ -d '/mnt/dietpi_userdata/roon-extension-manager' ]] && G_EXEC rm -R /mnt/dietpi_userdata/roon-extension-manager fi if To_Uninstall 178 # Jellyfin then G_AGP jellyfin 'jellyfin-*' [[ -f '/etc/apt/sources.list.d/dietpi-jellyfin.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-jellyfin.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-jellyfin.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-jellyfin.gpg [[ -d '/etc/systemd/system/jellyfin.service.d' ]] && G_EXEC rm -R /etc/systemd/system/jellyfin.service.d [[ -d '/mnt/dietpi_userdata/jellyfin' ]] && G_EXEC rm -R /mnt/dietpi_userdata/jellyfin fi if To_Uninstall 3 # Midnight Commander then G_AGP mc fi if To_Uninstall 0 # OpenSSH Client then # The OpenSSH server depends on the OpenSSH client, hence only mark it for autoremoval only. dpkg-query -s 'openssh-client' &> /dev/null && G_EXEC apt-mark auto openssh-client fi if To_Uninstall 1 # Samba Client then # Unmount default mount point findmnt /mnt/samba > /dev/null && G_EXEC umount -Rfl /mnt/samba # Remove from fstab G_EXEC sed --follow-symlinks -i '\|/mnt/samba|d' /etc/fstab G_AGP cifs-utils smbclient [[ -d '/mnt/samba' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /mnt/samba fi if To_Uninstall 110 # NFS Client then # Unmount default mount point findmnt /mnt/nfs_client > /dev/null && G_EXEC umount -Rfl /mnt/nfs_client # Remove from fstab G_EXEC sed --follow-symlinks -i '\|/mnt/nfs_client|d' /etc/fstab # nfs-kernel-server depends on nfs-common dpkg-query -s 'nfs-common' &> /dev/null && G_EXEC apt-mark auto nfs-common [[ -d '/mnt/nfs_client' ]] && G_EXEC rmdir --ignore-fail-on-non-empty /mnt/nfs_client fi if To_Uninstall 111 # UrBackup Server then # Pre-v6.29: ARMv8 source build and the package attempts to remove the non-existent "/etc/init.d/urbackup_srv" ... Remove_Service urbackupsrv urbackup urbackup if [[ -f '/var/urbackup/backup_server_settings.db' ]] && command -v sqlite3 > /dev/null then local backuppath=$(sqlite3 /var/urbackup/backup_server_settings.db 'select value from settings where key = "backupfolder"') else local backuppath=$(sed -n '/^[[:blank:]]*SOFTWARE_URBACKUP_BACKUPPATH=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) fi G_AGP urbackup-server G_EXEC rm -Rf /var/log/urbackup.log "${backuppath:-/mnt/dietpi_userdata/urbackup}" unset -v backuppath # Pre-v6.29: ARMv8 source build command -v urbackupsrv > /dev/null && G_EXEC rm "$(command -v urbackupsrv)" command -v urbackup_mount_helper > /dev/null && G_EXEC rm "$(command -v urbackup_mount_helper)" command -v urbackup_snapshot_helper > /dev/null && G_EXEC rm "$(command -v urbackup_snapshot_helper)" [[ -d '/usr/share/urbackup' ]] && G_EXEC rm -R /usr/share/urbackup [[ -d '/usr/local/share/urbackup' ]] && G_EXEC rm -R /usr/local/share/urbackup [[ -d '/var/urbackup' ]] && G_EXEC rm -R /var/urbackup [[ -f '/etc/default/urbackupsrv' ]] && G_EXEC rm /etc/default/urbackupsrv [[ -f '/etc/logrotate.d/urbackupsrv' ]] && G_EXEC rm /etc/logrotate.d/urbackupsrv fi if To_Uninstall 171 # frp then Remove_Service frpc Remove_Service frps frp frp # Binaries and configs [[ -f '/usr/local/bin/frpc' ]] && G_EXEC rm /usr/local/bin/frpc [[ -f '/usr/local/bin/frps' ]] && G_EXEC rm /usr/local/bin/frps [[ -d '/etc/frp' ]] && G_EXEC rm -R /etc/frp fi if To_Uninstall 17 # Git then G_AGP git fi if To_Uninstall 4 # fish then getent passwd | while read -r line do [[ $line == *':/usr/bin/fish' ]] || continue local user=${line%%:*} G_EXEC chsh "$user" -s /bin/bash done G_AGP fish [[ -d '/etc/fish/conf.d' ]] && G_EXEC rm -R /etc/fish/conf.d fi if To_Uninstall 5 # ALSA then /boot/dietpi/func/dietpi-set_hardware soundcard none G_AGP alsa-utils libasound2-plugin-equal firmware-intel-sound [[ -d '/etc/systemd/system/alsa-state.service.d' ]] && G_EXEC rm -R /etc/systemd/system/alsa-state.service.d fi if To_Uninstall 6 # X11 then # shellcheck disable=SC2046 apt-mark auto $(dpkg --get-selections 'x11-*' dbus-x11 dbus-user-session 'libegl1*' 'libgles2*' libgl1-mesa-dri 'mesa-*' libdrm-rockchip1 libmali-rk-utgard-450-r7p0 'xf86-video-*' malit628-odroid mali450-odroid aml-libs-odroid 'libump*' firmware-samsung 2> /dev/null | mawk '{print $1}') 2> /dev/null G_AGP 'xorg*' 'xserver-xorg*' xinit xcompmgr xterm xfonts-base G_EXEC rm -f /etc/xdg/autostart/xcompmgr.desktop /etc/X11/xorg.conf /etc/X11/xorg.conf.d/98-dietpi-disable_dpms.conf fi if To_Uninstall 7 # FFmpeg then G_AGP ffmpeg fi if To_Uninstall 8 # Java JDK then # shellcheck disable=SC2046 apt-mark auto $(dpkg --get-selections 'temurin-*-jdk' 'default-jdk*' 'openjdk-*-jdk*' 'openjdk-*-doc' 'openjdk-*-demo' 'openjdk-*-source' 'openjdk-*-testsupport' 2> /dev/null | mawk '{print $1}') 2> /dev/null fi if To_Uninstall 196 # Java JRE then # shellcheck disable=SC2046 apt-mark auto $(dpkg --get-selections 'temurin-*-jre' 'default-jre*' 'openjdk-*-jre*' 'openjdk-*-dbg' ca-certificates-java 2> /dev/null | mawk '{print $1}') 2> /dev/null fi if To_Uninstall 104 # Dropbear then G_AGP 'dropbear*' fi if To_Uninstall 105 # OpenSSH Server then G_AGP openssh-{,sftp-}server fi if To_Uninstall 181 # PaperMC then Remove_Service papermc 1 1 # Files [[ -d '/opt/papermc' ]] && G_EXEC rm -R /opt/papermc [[ -d '/var/log/papermc' ]] && G_EXEC rm -R /var/log/papermc [[ -d '/mnt/dietpi_userdata/papermc' ]] && G_EXEC rm -R /mnt/dietpi_userdata/papermc [[ -f '/usr/local/bin/mcrcon' ]] && G_EXEC rm /usr/local/bin/mcrcon fi if To_Uninstall 101 # Logrotate then G_AGP logrotate fi if To_Uninstall 102 # Rsyslog then dpkg-query -s 'rsyslog' &> /dev/null && G_EXEC apt-mark auto rsyslog # https://github.com/MichaIng/DietPi/issues/2454 # Update logging choice index if [[ $INDEX_LOGGING == -3 ]] then grep -q '[[:blank:]]/var/log[[:blank:]]' /etc/fstab || findmnt -t tmpfs -M /var/log > /dev/null && INDEX_LOGGING=-1 || INDEX_LOGGING=0 fi fi if To_Uninstall 103 # DietPi-RAMlog then G_EXEC sed --follow-symlinks -i '/[[:blank:]]\/var\/log[[:blank:]]/d' /etc/fstab G_EXEC mkdir -p /var/lib/dietpi/dietpi-ramlog cat << '_EOF_' > /var/lib/dietpi/dietpi-ramlog/disable.sh #!/bin/dash { systemctl --no-reload disable dietpi-ramlog systemctl stop dietpi-ramlog rm -R /var/tmp/dietpi/logs/dietpi-ramlog_store if systemctl -q is-enabled rsyslog 2> /dev/null then sed --follow-symlinks -i '/^[[:blank:]]*INDEX_LOGGING=/c\INDEX_LOGGING=-3' /boot/dietpi/.installed else sed --follow-symlinks -i '/^[[:blank:]]*INDEX_LOGGING=/c\INDEX_LOGGING=0' /boot/dietpi/.installed fi systemctl --no-reload disable dietpi-ramlog_disable rm /etc/systemd/system/dietpi-ramlog_disable.service rm /var/lib/dietpi/dietpi-ramlog/disable.sh } _EOF_ G_EXEC chmod +x /var/lib/dietpi/dietpi-ramlog/disable.sh cat << '_EOF_' > /etc/systemd/system/dietpi-ramlog_disable.service [Unit] Description=DietPi-RAMlog_disable After=dietpi-ramlog.service Before=dietpi-preboot.service rsyslog.service syslog.service [Service] Type=oneshot StandardOutput=tty ExecStart=/bin/dash -c '/var/lib/dietpi/dietpi-ramlog/disable.sh > /var/tmp/dietpi/logs/dietpi-ramlog_disable_debug.log 2>&1' [Install] WantedBy=local-fs.target _EOF_ G_EXEC systemctl daemon-reload G_EXEC systemctl --no-reload enable dietpi-ramlog_disable fi if To_Uninstall 9 # Node.js then command -v npm > /dev/null && npm r -g n yarn npm # Old install via repo G_AGP nodejs [[ -f '/etc/apt/sources.list.d/nodesource_nodejs.list' ]] && G_EXEC rm /etc/apt/sources.list.d/nodesource_nodejs.list [[ -f '/usr/local/bin/node' ]] && G_EXEC rm /usr/local/bin/node [[ -d '/usr/local/n' ]] && G_EXEC rm -R /usr/local/n [[ -d '/usr/local/yarn' ]] && G_EXEC rm -R /usr/local/yarn [[ -d '/usr/local/include/node' ]] && G_EXEC rm -R /usr/local/include/node [[ -d '/usr/local/lib/node_modules' ]] && G_EXEC rm -R /usr/local/lib/node_modules [[ -d '/usr/local/share/doc/node' ]] && G_EXEC rm -R /usr/local/share/doc/node [[ -f '/usr/local/man/man1/node.1' ]] && G_EXEC rm /usr/local/man/man1/node.1 [[ -f '/usr/local/share/man/man1/node.1' ]] && G_EXEC rm /usr/local/share/man/man1/node.1 [[ -f '/usr/local/README.md' ]] && G_EXEC rm /usr/local/README.md [[ -f '/usr/local/CHANGELOG.md' ]] && G_EXEC rm /usr/local/CHANGELOG.md [[ -f '/usr/local/LICENSE' ]] && G_EXEC rm /usr/local/LICENSE [[ -f '/usr/local/share/systemtap/tapset/node.stp' ]] && G_EXEC rm /usr/local/share/systemtap/tapset/node.stp [[ -d '/root/.npm' ]] && G_EXEC rm -R /root/.npm [[ -f '/root/.config/configstore/update-notifier-npm.json' ]] && G_EXEC rm /root/.config/configstore/update-notifier-npm.json fi if To_Uninstall 170 # UnRAR then G_AGP unrar fi if To_Uninstall 130 # Python 3 then command -v pip3 > /dev/null && G_EXEC_OUTPUT=1 G_EXEC pip3 uninstall -y pip setuptools wheel G_AGP python3-dev python3-pip # python3-pip: Pre-v6.32 [[ -f '/etc/pip.conf' ]] && G_EXEC rm /etc/pip.conf G_EXEC rm -Rf /{root,home/*}/.cache/pip fi if To_Uninstall 188 # Go then G_AGP golang-go [[ -f '/etc/bashrc.d/go.sh' ]] && G_EXEC rm /etc/bashrc.d/go.sh [[ -d '/usr/local/go' ]] && G_EXEC rm -R /usr/local/go fi if To_Uninstall 191 # Snapcast Server then G_AGP snapserver # Remove users from Debian's and badaix's packages, to cleanly cover upgrades from one to the other. getent passwd snapserver > /dev/null && G_EXEC userdel snapserver getent passwd _snapserver > /dev/null && G_EXEC userdel _snapserver fi if To_Uninstall 192 # Snapcast Client then G_AGP snapclient fi if To_Uninstall 194 # PostgreSQL then G_AGP postgresql 'postgresql-*' G_EXEC rm -Rf /etc/postgresql* [[ -d '/mnt/dietpi_userdata/postgresql' ]] && G_EXEC rm -R /mnt/dietpi_userdata/postgresql fi if To_Uninstall 87 # SQLite then G_AGP sqlite3 'php*-sqlite3' fi if To_Uninstall 202 # Rclone then G_AGP rclone G_EXEC rm -Rf /{root,home/*}/.config/rclone fi if To_Uninstall 209 # Restic then [[ -f '/usr/local/bin/restic' ]] && G_EXEC rm /usr/local/bin/restic fi if To_Uninstall 210 # MediaWiki then [[ -d '/var/www/wiki' ]] && G_EXEC rm -R /var/www/wiki Remove_Database mediawiki fi if To_Uninstall 211 # Homebridge then Remove_Service homebridge 1 1 G_AGP homebridge [[ -f '/etc/apt/sources.list.d/dietpi-homebridge.list' ]] && G_EXEC rm /etc/apt/sources.list.d/dietpi-homebridge.list [[ -f '/etc/apt/trusted.gpg.d/dietpi-homebridge.gpg' ]] && G_EXEC rm /etc/apt/trusted.gpg.d/dietpi-homebridge.gpg fi if To_Uninstall 198 # File Browser then Remove_Service filebrowser 1 [[ -d '/opt/filebrowser' ]] && G_EXEC rm -R /opt/filebrowser [[ -d '/mnt/dietpi_userdata/filebrowser' ]] && G_EXEC rm -R /mnt/dietpi_userdata/filebrowser fi if To_Uninstall 199 # Spotifyd then Remove_Service spotifyd 1 1 [[ -d '/opt/spotifyd' ]] && G_EXEC rm -R /opt/spotifyd [[ -d '/mnt/dietpi_userdata/spotifyd' ]] && G_EXEC rm -R /mnt/dietpi_userdata/spotifyd fi if To_Uninstall 213 # soju then Remove_Service soju 1 1 local x local commands=('soju' 'sojuctl' 'sojudb') local manpages=('soju.1' 'sojuctl.1') for x in "${commands[@]}" do [[ -f /usr/local/bin/$x ]] && G_EXEC rm "/usr/local/bin/$x" done for x in "${manpages[@]}" do [[ -f /usr/local/share/man/man1/$x ]] && G_EXEC rm "/usr/local/share/man/man1/$x" done [[ -d '/usr/local/share/man/man1' ]] && G_EXEC rmdir -p --ignore-fail-on-non-empty /usr/local/share/man/man1 [[ -d '/mnt/dietpi_userdata/soju' ]] && G_EXEC rm -Rf /mnt/dietpi_userdata/soju fi if To_Uninstall 169 # LazyLibrarian then Remove_Service lazylibrarian 1 1 [[ -d '/mnt/dietpi_userdata/lazylibrarian' ]] && G_EXEC rm -Rf /mnt/dietpi_userdata/lazylibrarian fi G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Finalising uninstall' # Uninstall finished, set all uninstalled software to state 0 (not installed) for i in "${!aSOFTWARE_NAME[@]}" do (( ${aSOFTWARE_INSTALL_STATE[$i]} == -1 )) && aSOFTWARE_INSTALL_STATE[$i]=0 done G_AGA G_EXEC systemctl daemon-reload #---------------------------------------------------------------------- G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Uninstall completed' #---------------------------------------------------------------------- } Run_Installations() { G_NOTIFY_3_MODE='Step' #------------------------------------------------------------ G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Checking for conflicts and missing inputs' # Unmark software which requires user input during automated installs Unmark_Unattended # Unmark conflicting software if not done after interactive software selection already (( $CONFLICTS_RESOLVED )) || Unmark_Conflicts # Abort install if no selections are left and not first run setup if (( $G_DIETPI_INSTALL_STAGE == 2 )) then local abort=1 for i in "${!aSOFTWARE_NAME[@]}" do (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) || continue abort=0 break done (( $abort )) && { G_DIETPI-NOTIFY 1 'No software installs are done. Aborting...'; exit 1; } fi #------------------------------------------------------------ # Disable powersaving on main screen during installation command -v setterm > /dev/null && setterm -blank 0 -powersave off 2> /dev/null # Mark dependencies for install Mark_Dependencies # Check network connectivity, DNS resolving and network time sync: https://github.com/MichaIng/DietPi/issues/786 # - Skip on first run installs where it is done in DietPi-Automation_Pre() already (( $G_DIETPI_INSTALL_STAGE == 2 )) || Check_Net_and_Time_sync # Pre-create directories which are required for many software installs Create_Required_Dirs # Read global software password Update_Global_Pw # Stop all services # shellcheck disable=SC2154 [[ $G_SERVICE_CONTROL == 0 ]] || /boot/dietpi/dietpi-services stop # Update package cache: Skip when flag was set by first run setup (( $SKIP_APT_UPDATE )) || G_AGUP # Install software Install_Software # Uninstall software if required by e.g. DietPi choice system for i in "${!aSOFTWARE_NAME[@]}" do (( ${aSOFTWARE_INSTALL_STATE[$i]} == -1 )) || continue Uninstall_Software break done G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Finalising install' # Enable installed services if [[ ${aENABLE_SERVICES[0]}${aSTART_SERVICES[0]} ]] then G_DIETPI-NOTIFY 2 'Enabling installed services' for i in "${aENABLE_SERVICES[@]}" "${aSTART_SERVICES[@]}" do G_EXEC_NOHALT=1 G_EXEC systemctl --no-reload enable "$i" done fi # Reload systemd units G_EXEC systemctl daemon-reload # Unmask systemd-logind if Kodi or Chromium were installed, it's set in dietpi.txt or libpam-systemd was installed if [[ $(readlink /etc/systemd/system/systemd-logind.service) == '/dev/null' ]] && { (( ${aSOFTWARE_INSTALL_STATE[31]} == 1 || ${aSOFTWARE_INSTALL_STATE[113]} == 1 )) || grep -q '^[[:blank:]]*AUTO_UNMASK_LOGIND=1' /boot/dietpi.txt || dpkg-query -s 'libpam-systemd' &> /dev/null; } then G_DIETPI-NOTIFY 2 'Enabling systemd-logind' # dbus is required for systemd-logind to start dpkg-query -s dbus &> /dev/null || G_AGI dbus G_EXEC systemctl unmask dbus G_EXEC systemctl start dbus G_EXEC systemctl unmask systemd-logind G_EXEC systemctl start systemd-logind fi # Sync DietPi-RAMlog to disk: https://github.com/MichaIng/DietPi/issues/4884 systemctl -q is-enabled dietpi-ramlog 2> /dev/null && /boot/dietpi/func/dietpi-ramlog 1 # Apply GPU Memory Splits Install_Apply_GPU_Settings # Offer to change DietPi-AutoStart option if (( $G_DIETPI_INSTALL_STAGE == 2 )) && (( ${aSOFTWARE_INSTALL_STATE[23]} == 1 || ${aSOFTWARE_INSTALL_STATE[24]} == 1 || ${aSOFTWARE_INSTALL_STATE[25]} == 1 || ${aSOFTWARE_INSTALL_STATE[26]} == 1 || ${aSOFTWARE_INSTALL_STATE[31]} == 1 || ${aSOFTWARE_INSTALL_STATE[51]} == 1 || ${aSOFTWARE_INSTALL_STATE[108]} == 1 || ${aSOFTWARE_INSTALL_STATE[112]} == 1 || ${aSOFTWARE_INSTALL_STATE[113]} == 1 || ${aSOFTWARE_INSTALL_STATE[119]} == 1 || ${aSOFTWARE_INSTALL_STATE[173]} == 1 )) then G_WHIP_YESNO 'Would you like to configure the DietPi-AutoStart option? \nThis will allow you to choose which program loads automatically, after the system has booted up, e.g.: - Console\n - Desktop\n - Kodi' && /boot/dietpi/dietpi-autostart fi # Final user info # - Home Assistant: https://dietpi.com/forum/t/home-assistant-finally-integrates-python-3-11/17033/40 if (( ${aSOFTWARE_INSTALL_STATE[157]} == 1 )) then G_WHIP_MSG '[ INFO ] Home Assistant may require a manual restart \nOn first service start, Home Assistant installs and in case compiles a bunch of required Python module. This can take another while. \nThe compilation of those modules can fail on first attempt for unknown reasons, but succeeds after restarting the service: - sudo systemctl restart home-assistant \nAlso check our documentation about this matter: - https://dietpi.com/docs/software/home_automation/#home-assistant' fi # Install finished, set all installed software to state 2 (installed) for i in "${!aSOFTWARE_NAME[@]}" do (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) && aSOFTWARE_INSTALL_STATE[$i]=2 done # Write to .installed state file Write_InstallFileList } #///////////////////////////////////////////////////////////////////////////////////// # First Run / Automation function #///////////////////////////////////////////////////////////////////////////////////// # Setup steps prior to software installs DietPi-Automation_Pre() { G_NOTIFY_3_MODE='Step' G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Applying initial first run setup steps' # Get settings AUTOINSTALL_ENABLED=$(grep -cm1 '^[[:blank:]]*AUTO_SETUP_AUTOMATED=1' /boot/dietpi.txt) AUTOINSTALL_AUTOSTARTTARGET=$(sed -n '/^[[:blank:]]*AUTO_SETUP_AUTOSTART_TARGET_INDEX=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) local AUTOINSTALL_SSHINDEX=$(sed -n '/^[[:blank:]]*AUTO_SETUP_SSH_SERVER_INDEX=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) local AUTOINSTALL_LOGGINGINDEX=$(sed -n '/^[[:blank:]]*AUTO_SETUP_LOGGING_INDEX=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) AUTOINSTALL_CUSTOMSCRIPTURL=$(sed -n '/^[[:blank:]]*AUTO_SETUP_CUSTOM_SCRIPT_EXEC=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) local AUTOINSTALL_RESTORE=$(sed -n '/^[[:blank:]]*AUTO_SETUP_BACKUP_RESTORE=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) local AUTOINSTALL_RAMLOG_SIZE=$(sed -n '/^[[:blank:]]*AUTO_SETUP_RAMLOG_MAXSIZE=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) AUTO_SETUP_DHCP_TO_STATIC=$(grep -cm1 '^[[:blank:]]*AUTO_SETUP_DHCP_TO_STATIC=1' /boot/dietpi.txt) # Else set defaults [[ $AUTOINSTALL_AUTOSTARTTARGET ]] || AUTOINSTALL_AUTOSTARTTARGET=0 [[ $AUTOINSTALL_SSHINDEX ]] || AUTOINSTALL_SSHINDEX=-1 [[ $AUTOINSTALL_LOGGINGINDEX ]] || AUTOINSTALL_LOGGINGINDEX=-1 [[ $AUTOINSTALL_CUSTOMSCRIPTURL ]] || AUTOINSTALL_CUSTOMSCRIPTURL=0 [[ $AUTOINSTALL_RESTORE ]] || AUTOINSTALL_RESTORE=0 [[ $AUTOINSTALL_RAMLOG_SIZE ]] || AUTOINSTALL_RAMLOG_SIZE=50 # Restore DietPi-Backup if (( $AUTOINSTALL_RESTORE )); then # Reboot only when backup restore succeeded restore_succeeded=0 G_DIETPI-NOTIFY 2 'DietPi-Backup restore selected, scanning and mounting attached drives...' i=0 while read -r line do # Mount drives to temporary mount points mkdir -p "/mnt/dietpi-backup$i" && mount "$line" "/mnt/dietpi-backup$i" ((i++)) done < <(lsblk -rnpo NAME,UUID,MOUNTPOINT | mawk '$2 && ! $3 {print $1}') G_DIETPI-NOTIFY 2 'Searching all drives for DietPi-Backup instances...' mapfile -t alist < <(find /mnt -type f -name '.dietpi-backup_stats') # Interactive restore if [[ $AUTOINSTALL_RESTORE == 1 ]]; then # Do we have any results? if [[ ${alist[0]} ]] then # Create List for Whiptail G_WHIP_MENU_ARRAY=() for i in "${alist[@]}" do last_backup_date=$(sed -n '/ompleted/s/^.*: //p' "$i" | tail -1) # Date of last backup for this backup backup_directory=${i%/.dietpi-backup_stats} # Backup directory (minus the backup file), that we can use for target backup directory. G_WHIP_MENU_ARRAY+=("$backup_directory" ": $last_backup_date") done export G_DIETPI_SERVICES_DISABLE=1 G_WHIP_MENU 'Please select a previous backup to restore:' && /boot/dietpi/dietpi-backup -1 "$G_WHIP_RETURNED_VALUE" && restore_succeeded=1 unset -v G_DIETPI_SERVICES_DISABLE else G_WHIP_MSG 'No previous backups were found in /mnt/*. Install will continue like normal.' fi # Non-interactive restore elif [[ $AUTOINSTALL_RESTORE == 2 ]]; then # Do we have any results? if [[ ${alist[0]} ]] then # Restore first found backup export G_DIETPI_SERVICES_DISABLE=1 /boot/dietpi/dietpi-backup -1 "${alist[0]%/.dietpi-backup_stats}" && restore_succeeded=1 unset -v G_DIETPI_SERVICES_DISABLE else G_DIETPI-NOTIFY 1 'DietPi-Backup auto-restore was selected but no backup has been found in /mnt/*. Install will continue like normal.' fi # Downgrade dietpi.txt option G_CONFIG_INJECT 'AUTO_SETUP_BACKUP_RESTORE=' 'AUTO_SETUP_BACKUP_RESTORE=1' /boot/dietpi.txt fi # Remove mounted drives and mount points findmnt /mnt/dietpi-backup[0-9]* > /dev/null && umount /mnt/dietpi-backup[0-9]* [[ -d '/mnt/dietpi-backup0' ]] && rmdir /mnt/dietpi-backup[0-9]* # Reboot on successful restore if (( $restore_succeeded )) then G_DIETPI-NOTIFY 2 'The system will now reboot into the restored system' sync # Failsafe G_SLEEP 3 reboot fi fi # Check network connectivity, DNS resolving and network time sync: https://github.com/MichaIng/DietPi/issues/786 Check_Net_and_Time_sync # Full package upgrade on first run installs: https://github.com/MichaIng/DietPi/issues/3098 if [[ ! -f '/boot/dietpi/.skip_distro_upgrade' ]] then G_AGUP G_AGDUG G_AGA # Create a persistent flag to not repeat G_AGDUG and rule out a reboot loop when kernel modules remain missing G_EXEC eval '> /boot/dietpi/.skip_distro_upgrade' # Perform a reboot if required as of missing kernel modules G_CHECK_KERNEL || { G_DIETPI-NOTIFY 2 'A reboot is done to finalise the kernel upgrade'; sync; reboot; exit 0; } # Do not repeat APT update in Run_Installations() SKIP_APT_UPDATE=1 fi # Change password if default has not been changed via dietpi.txt # - Non-automated interactive first run setup: Show password prompts if (( ! $AUTOINSTALL_ENABLED && $G_INTERACTIVE )) then # Local console: Prompt to select keyboard layout first if default is still set: https://github.com/MichaIng/DietPi/issues/5925 [[ $(tty) == '/dev/tty1' ]] && grep -q '^XKBLAYOUT="gb"' /etc/default/keyboard && /boot/dietpi/func/dietpi-set_hardware keyboard /boot/dietpi/func/dietpi-set_software password users check Update_Global_Pw # - Automated or non-interactive first run setup else # Update_Global_Pw is always executed right before installs start and in case forces users to change the default on any next interactive execution. # Set flag for dietpi-login to check user passwords to in case enforce a change on next interactive login. G_EXEC touch /var/lib/dietpi/.check_user_passwords fi # Disable serial console? if (( $G_HW_MODEL != 75 )) && ! grep -q '^[[:blank:]]*CONFIG_SERIAL_CONSOLE_ENABLE=0' /boot/dietpi.txt && [[ ! $(tty) =~ ^/dev/(serial|tty(S|AMA|SAC|AML|SC|GS|FIQ|MV)|hvc)[0-9] ]] && G_WHIP_BUTTON_OK_TEXT='Yes' G_WHIP_BUTTON_CANCEL_TEXT='No' G_WHIP_YESNO 'A serial/UART console is currently enabled, would you like to disable it? \nTL;DR: If you do not know what a UART device or a serial console is, it is safe to select "Yes", which frees some MiB memory by stopping the related process(es). \nA serial console is a way to interact with a system without any screen or network (SSH) required, but from another system physically connected. It is accessed with a UART adapter cable (often UART-to-USB), connected to a special UART port or GPIO pins. It can then be accessed via COM port from the attached system with a serial console client, e.g. PuTTY (which supports both, SSH and serial console access). \nAnother benefit is that you can view early boot logs, before network or even screen output is up, which makes it a great way to debug issues with the bootloader or kernel. However, to allow as well common user logins via serial console, at least one additional login prompt process is running, which you may want to avoid when not using this feature at all. \nSerial consoles can re-enabled at any time via dietpi-config > Advanced Options > Serial/UART' then /boot/dietpi/func/dietpi-set_hardware serialconsole disable fi # RPi: Convert "serial0" to its actual symlink target without breaking the possibly currently used serial connection or starting a doubled console on the same serial device. if (( $G_HW_MODEL < 10 )) && ! grep -q '^[[:blank:]]*CONFIG_SERIAL_CONSOLE_ENABLE=0' /boot/dietpi.txt then if [[ -e '/dev/serial0' ]] then local tty=$(realpath /dev/serial0); tty=${tty#/dev/} G_DIETPI-NOTIFY 2 "Converting serial console from symlink /dev/serial0 to native /dev/$tty" if [[ $( /dev/null && G_EXEC mount -o remount /var/log # Set time sync mode if no container system (( $G_HW_MODEL == 75 )) || /boot/dietpi/func/dietpi-set_software ntpd-mode # Apply choice and preference system settings Apply_SSHServer_Choices "$AUTOINSTALL_SSHINDEX" Apply_Logging_Choices "$AUTOINSTALL_LOGGINGINDEX" G_DIETPI-NOTIFY 0 'Applied initial first run setup steps' # Automated installs (( $AUTOINSTALL_ENABLED )) || return 0 G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Running automated install' TARGETMENUID=-1 # Skip menu loop GOSTARTINSTALL=1 # Set install start flag # Find all software entries of AUTO_SETUP_INSTALL_SOFTWARE_ID= in dietpi.txt. Then set to state 1 for installation. G_DIETPI-NOTIFY 2 'Checking AUTO_SETUP_INSTALL_SOFTWARE_ID entries' # - Pre-v9.10: Support multiple AUTO_SETUP_INSTALL_SOFTWARE_ID lines while read -ra software_ids do # v9.10: Support multiple IDs per AUTO_SETUP_INSTALL_SOFTWARE_ID line for software_id in "${software_ids[@]}" do # Skip if software does not exist, is not supported on architecture, hardware model or Debian version if [[ ! ${aSOFTWARE_NAME[$software_id]} ]] then G_DIETPI-NOTIFY 1 "Software title with ID $software_id does not exist. Skipping it." elif (( ! ${aSOFTWARE_AVAIL_G_HW_ARCH[$software_id,$G_HW_ARCH]:=1} )) then G_DIETPI-NOTIFY 1 "Software title ${aSOFTWARE_NAME[$software_id]} is not supported on ${RPI_64KERNEL_32OS:-$G_HW_ARCH_NAME} systems. Skipping it." elif (( ! ${aSOFTWARE_AVAIL_G_HW_MODEL[$software_id,$G_HW_MODEL]:=1} )) then G_DIETPI-NOTIFY 1 "Software title ${aSOFTWARE_NAME[$software_id]} is not supported on $G_HW_MODEL_NAME. Skipping it." elif (( ! ${aSOFTWARE_AVAIL_G_DISTRO[$software_id,$G_DISTRO]:=1} )); then G_DIETPI-NOTIFY 1 "Software title ${aSOFTWARE_NAME[$software_id]} is not supported on Debian ${G_DISTRO_NAME^}. Skipping it." else aSOFTWARE_INSTALL_STATE[$software_id]=1 G_DIETPI-NOTIFY 0 "Software title ${aSOFTWARE_NAME[$software_id]} flagged for installation." fi done done < <(grep '^[[:blank:]]*AUTO_SETUP_INSTALL_SOFTWARE_ID=' /boot/dietpi.txt | sed -e 's/^[^=]*=//' -e 's/#.*$//') } # Setup steps after software installs DietPi-Automation_Post() { G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Applying final first run setup steps' # Remove fake-hwclock if real hwclock is available # REMOVED: "hwclock" succeeds if an RTC connector is available but no battery attached (or empty), hence we cannot guarantee correct RTC time on boot by only testing "hwclock". #hwclock &> /dev/null && G_AGP fake-hwclock # x86_64 PC: Install microcode updates if (( $G_HW_MODEL == 21 )) then grep -qi 'vendor_id.*intel' /proc/cpuinfo && G_AGI intel-microcode grep -qi 'vendor_id.*amd' /proc/cpuinfo && G_AGI amd64-microcode # VM: Enable QEMU guest agent if detected elif (( $G_HW_MODEL == 20 )) then /boot/dietpi/func/dietpi-set_hardware qga 1 # RPi 4/5 EEPROM update: https://github.com/MichaIng/DietPi/issues/3217 elif [[ $G_HW_MODEL == [45] ]] then /boot/dietpi/func/dietpi-set_hardware rpi-eeprom fi # Install GPU driver if set local gpu_driver=$(sed -n '/^[[:blank:]]*CONFIG_GPU_DRIVER=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) [[ $gpu_driver && ${gpu_driver,,} != 'none' ]] && /boot/dietpi/func/dietpi-set_hardware gpudriver "$gpu_driver" # Apply DHCP leased network settings as static network settings if requested if (( $AUTO_SETUP_DHCP_TO_STATIC )) then G_DIETPI-NOTIFY 2 'Applying DHCP leased network settings as static network settings' # Function to convert CIDR notation into dot-decimal notation cidr2mask() { local i mask full_octets=$(( $1 / 8 )) partial_octet=$(( $1%8 )) for i in {0..3} do if (( $i < $full_octets )) then mask+='255' elif (( $i == $full_octets )) then mask+=$(( 256 - 2 ** ( 8 - $partial_octet ) )) else mask+='0' fi (( $i < 3 )) && mask+=. done echo "$mask" } # Get Ethernet index local nameservers eth_index=$(sed -En '/^[[:blank:]]*(allow-hotplug|auto)[[:blank:]]+eth[0-9]+$/{s/^.*eth//p;q}' /etc/network/interfaces) # - Is enabled and uses DHCP if [[ $eth_index ]] && grep -Eq "^[[:blank:]]*iface[[:blank:]]+eth${eth_index}[[:blank:]]+inet[[:blank:]]+dhcp$" /etc/network/interfaces then G_DIETPI-NOTIFY 2 'Applying DHCP leased Ethernet settings as static Ethernet settings' # Get current network info local eth_ip=$(ip -br -f inet a s "eth$eth_index" | mawk '{print $3}' | sed 's|/.*$||') local eth_mask=$(cidr2mask "$(ip -br -f inet a s "eth$eth_index" | mawk '{print $3}' | sed 's|^.*/||')") local eth_gateway=$(ip r l dev "eth$eth_index" 0/0 | mawk '{print $3;exit}') nameservers=$(mawk '/^[[:blank:]]*nameserver[[:blank:]]/{print $2}' ORS=' ' /etc/resolv.conf) # Apply current network settings statically G_CONFIG_INJECT "iface[[:blank:]]+eth$eth_index" "iface eth$eth_index inet static" /etc/network/interfaces sed --follow-symlinks -i "0,\|^.*address[[:blank:]].*\$|s||address $eth_ip|" /etc/network/interfaces sed --follow-symlinks -i "0,\|^.*netmask[[:blank:]].*\$|s||netmask $eth_mask|" /etc/network/interfaces sed --follow-symlinks -i "0,\|^.*gateway[[:blank:]].*\$|s||gateway $eth_gateway|" /etc/network/interfaces fi # Get WiFi index local wlan_index=$(sed -En '/^[[:blank:]]*(allow-hotplug|auto)[[:blank:]]+wlan[0-9]+$/{s/^.*wlan//p;q}' /etc/network/interfaces) # - Is enabled and uses DHCP if [[ $wlan_index ]] && grep -Eq "^[[:blank:]]*iface[[:blank:]]+wlan${wlan_index}[[:blank:]]+inet[[:blank:]]+dhcp$" /etc/network/interfaces then G_DIETPI-NOTIFY 2 'Applying DHCP leased WiFi settings as static WiFi settings' # Get current network info local wlan_ip=$(ip -br -f inet a s "wlan$wlan_index" | mawk '{print $3}' | sed 's|/.*$||') local wlan_mask=$(cidr2mask "$(ip -br -f inet a s "wlan$wlan_index" | mawk '{print $3}' | sed 's|^.*/||')") local wlan_gateway=$(ip r l dev "wlan$wlan_index" 0/0 | mawk '{print $3;exit}') [[ $nameservers ]] || nameservers=$(mawk '/^[[:blank:]]*nameserver[[:blank:]]/{print $2}' ORS=' ' /etc/resolv.conf) # Apply current network settings statically G_CONFIG_INJECT "iface[[:blank:]]+wlan$wlan_index" "iface wlan$wlan_index inet static" /etc/network/interfaces sed --follow-symlinks -i "\|^iface wlan|,\$s|^.*address[[:blank:]].*\$|address $wlan_ip|" /etc/network/interfaces sed --follow-symlinks -i "\|^iface wlan|,\$s|^.*netmask[[:blank:]].*\$|netmask $wlan_mask|" /etc/network/interfaces sed --follow-symlinks -i "\|^iface wlan|,\$s|^.*gateway[[:blank:]].*\$|gateway $wlan_gateway|" /etc/network/interfaces fi unset -f cidr2mask # Apply DNS nameservers if [[ $nameservers ]] then G_DIETPI-NOTIFY 2 'Applying DHCP leased DNS nameservers as static nameservers' if command -v resolvconf > /dev/null then sed --follow-symlinks -i "/dns-nameservers[[:blank:]]/c\dns-nameservers ${nameservers% }" /etc/network/interfaces else sed --follow-symlinks -i "/dns-nameservers[[:blank:]]/c\#dns-nameservers ${nameservers% }" /etc/network/interfaces > /etc/resolv.conf for i in $nameservers; do echo "nameserver $i" >> /etc/resolv.conf; done fi fi G_DIETPI-NOTIFY 0 'Network changes will become effective with next reboot' fi # RPi: Disable onboard WiFi if WiFi modules didn't get enabled until now: https://github.com/MichaIng/DietPi/issues/5391 [[ $G_HW_MODEL -gt 9 || ! -f '/etc/modprobe.d/dietpi-disable_wifi.conf' ]] || /boot/dietpi/func/dietpi-set_hardware wifimodules onboard_disable # Apply AutoStart choice /boot/dietpi/dietpi-autostart "$AUTOINSTALL_AUTOSTARTTARGET" # Disable console on TTY1 for purely headless SBCs, enabled for automated first run setup [[ $G_HW_MODEL =~ ^(47|48|55|56|57|59|60|64|65|73)$ ]] && G_EXEC systemctl --no-reload disable getty@tty1 # Images are shipped with cron disabled, hence enable it now after first run setup has finished G_EXEC systemctl enable cron # Set install stage to finished G_DIETPI_INSTALL_STAGE=2 G_EXEC eval 'echo 2 > /boot/dietpi/.install_stage' # Remove now obsolete flag [[ -f '/boot/dietpi/.skip_distro_upgrade' ]] && G_EXEC rm /boot/dietpi/.skip_distro_upgrade G_DIETPI-NOTIFY 0 'Applied final first run setup steps' # Process automatic APT package installs local packages=() package read -ra packages < <(sed -n '/^[[:blank:]]*AUTO_SETUP_APT_INSTALLS=/{s/^[^=]*=//p;q}' /boot/dietpi.txt) for package in "${packages[@]}" do G_EXEC_NOHALT=1 G_AGI "$package" done # Custom 1st run script [[ $AUTOINSTALL_CUSTOMSCRIPTURL != '0' || -f '/boot/Automation_Custom_Script.sh' ]] || return 0 # Download online script [[ -f '/boot/Automation_Custom_Script.sh' ]] || G_EXEC_NOEXIT=1 G_EXEC curl -sSfL "$AUTOINSTALL_CUSTOMSCRIPTURL" -o /boot/Automation_Custom_Script.sh || return $? G_DIETPI-NOTIFY 2 'Running custom script, please wait...' [[ -x '/boot/Automation_Custom_Script.sh' ]] || G_EXEC_NOEXIT=1 G_EXEC chmod +x /boot/Automation_Custom_Script.sh /boot/Automation_Custom_Script.sh 2>&1 | tee /var/tmp/dietpi/logs/dietpi-automation_custom_script.log G_DIETPI-NOTIFY $(( ! ! ${PIPESTATUS[0]} )) 'Custom script: /var/tmp/dietpi/logs/dietpi-automation_custom_script.log' } #///////////////////////////////////////////////////////////////////////////////////// # Globals #///////////////////////////////////////////////////////////////////////////////////// Input_Modes() { # Process software and exit if [[ $1 == 'install' || $1 == 'reinstall' || $1 == 'uninstall' ]]; then G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" "Automated $1" # Make sure we have at least one entry [[ $2 ]] || { G_DIETPI-NOTIFY 1 'Please enter at least one software ID to process'; return 1; } # Process software IDs local command=$1 shift for i in "$@" do # Check if input software ID exists, install state was defined if disable_error=1 G_CHECK_VALIDINT "$i" 0 && disable_error=1 G_CHECK_VALIDINT "${aSOFTWARE_INSTALL_STATE[$i]}"; then if [[ $command == 'uninstall' ]]; then if (( ${aSOFTWARE_INSTALL_STATE[$i]} == 2 )); then aSOFTWARE_INSTALL_STATE[$i]=-1 G_DIETPI-NOTIFY 0 "Uninstalling ${aSOFTWARE_NAME[$i]}: ${aSOFTWARE_DESC[$i]}" elif (( ${aSOFTWARE_INSTALL_STATE[$i]} != -1 )); then G_DIETPI-NOTIFY 2 "$i: ${aSOFTWARE_NAME[$i]} is not currently installed" G_DIETPI-NOTIFY 0 "No changes applied for: ${aSOFTWARE_NAME[$i]}" fi elif [[ $command == 'reinstall' ]]; then (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) && continue if (( ${aSOFTWARE_INSTALL_STATE[$i]} != 2 )); then G_DIETPI-NOTIFY 2 "$i: ${aSOFTWARE_NAME[$i]} is not currently installed" G_DIETPI-NOTIFY 2 "Use \"dietpi-software install $i\" to install ${aSOFTWARE_NAME[$i]}." G_DIETPI-NOTIFY 0 "No changes applied for: ${aSOFTWARE_NAME[$i]}" elif (( ! ${aSOFTWARE_AVAIL_G_HW_ARCH[$i,$G_HW_ARCH]:=1} )); then G_DIETPI-NOTIFY 1 "Software title (${aSOFTWARE_NAME[$i]}) is not supported on $G_HW_ARCH_NAME systems." elif (( ! ${aSOFTWARE_AVAIL_G_HW_MODEL[$i,$G_HW_MODEL]:=1} )); then G_DIETPI-NOTIFY 1 "Software title (${aSOFTWARE_NAME[$i]}) is not supported for $G_HW_MODEL_NAME." elif (( ! ${aSOFTWARE_AVAIL_G_DISTRO[$i,$G_DISTRO]:=1} )); then G_DIETPI-NOTIFY 1 "Software title (${aSOFTWARE_NAME[$i]}) is not supported on Debian ${G_DISTRO_NAME^}." else aSOFTWARE_INSTALL_STATE[$i]=1 GOSTARTINSTALL=1 # Set install start flag G_DIETPI-NOTIFY 0 "Reinstalling ${aSOFTWARE_NAME[$i]}: ${aSOFTWARE_DESC[$i]}" fi elif [[ $command == 'install' ]]; then (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) && continue if (( ! ${aSOFTWARE_AVAIL_G_HW_ARCH[$i,$G_HW_ARCH]:=1} )); then G_DIETPI-NOTIFY 1 "Software title (${aSOFTWARE_NAME[$i]}) is not supported on $G_HW_ARCH_NAME systems." elif (( ! ${aSOFTWARE_AVAIL_G_HW_MODEL[$i,$G_HW_MODEL]:=1} )); then G_DIETPI-NOTIFY 1 "Software title (${aSOFTWARE_NAME[$i]}) is not supported for $G_HW_MODEL_NAME." elif (( ! ${aSOFTWARE_AVAIL_G_DISTRO[$i,$G_DISTRO]:=1} )); then G_DIETPI-NOTIFY 1 "Software title (${aSOFTWARE_NAME[$i]}) is not supported on Debian ${G_DISTRO_NAME^}." elif (( ${aSOFTWARE_INSTALL_STATE[$i]} != 2 )); then aSOFTWARE_INSTALL_STATE[$i]=1 GOSTARTINSTALL=1 # Set install start flag G_DIETPI-NOTIFY 0 "Installing ${aSOFTWARE_NAME[$i]}: ${aSOFTWARE_DESC[$i]}" else G_DIETPI-NOTIFY 2 "$i: ${aSOFTWARE_NAME[$i]} is already installed" G_DIETPI-NOTIFY 2 "Use \"dietpi-software reinstall $i\" to force rerun of installation and configuration steps for ${aSOFTWARE_NAME[$i]}." G_DIETPI-NOTIFY 0 "No changes applied for: ${aSOFTWARE_NAME[$i]}" fi fi fi done # Reinstall, prompt for backup if [[ $command == 'reinstall' && $GOSTARTINSTALL == 1 ]]; then G_PROMPT_BACKUP CONFLICTS_RESOLVED=1 # Uninstall | Finish up and clear non-required packages elif [[ $command == 'uninstall' ]]; then for i in "${!aSOFTWARE_NAME[@]}" do (( ${aSOFTWARE_INSTALL_STATE[$i]} == -1 )) || continue Uninstall_Software Write_InstallFileList break done fi # List software IDs, names and additional info elif [[ $1 == 'list' ]]; then if [[ $MACHINE_READABLE ]] then for i in "${!aSOFTWARE_NAME[@]}" do # ID local string=$i # Show if disabled (( ${aSOFTWARE_AVAIL_G_HW_ARCH[$i,$G_HW_ARCH]:=1} && ${aSOFTWARE_AVAIL_G_HW_MODEL[$i,$G_HW_MODEL]:=1} && ${aSOFTWARE_AVAIL_G_DISTRO[$i,$G_DISTRO]:=1} )) || string+=' DISABLED' # Install state, software name, and description string+="|${aSOFTWARE_INSTALL_STATE[$i]}|${aSOFTWARE_NAME[$i]}|${aSOFTWARE_DESC[$i]}|" # Append dependencies for j in ${aSOFTWARE_DEPS[$i]} do # Add software name or raw meta dependencies to string [[ $j == *[^0-9]* ]] && string+="$j," || string+="${aSOFTWARE_NAME[$j]}," done echo "${string%,}|${aSOFTWARE_DOCS[$i]}" done else for i in "${!aSOFTWARE_NAME[@]}" do # ID, install state, software name and description local string="ID $i | =${aSOFTWARE_INSTALL_STATE[$i]} | ${aSOFTWARE_NAME[$i]}:\e[0m \e[90m${aSOFTWARE_DESC[$i]}\e[0m |" # Paint green if installed (( ${aSOFTWARE_INSTALL_STATE[$i]} == 2 )) && string="\e[32m$string" # Append dependencies for j in ${aSOFTWARE_DEPS[$i]} do # Add software name or raw meta dependencies to string [[ $j == *[^0-9]* ]] && string+=" +$j" || string+=" +${aSOFTWARE_NAME[$j]}" done # Available for G_HW_ARCH? if (( ! ${aSOFTWARE_AVAIL_G_HW_ARCH[$i,$G_HW_ARCH]:=1} )); then string+=" \e[31mDISABLED for ${RPI_64KERNEL_32OS:-$G_HW_ARCH_NAME}\e[0m" # Available for G_HW_MODEL? elif (( ! ${aSOFTWARE_AVAIL_G_HW_MODEL[$i,$G_HW_MODEL]:=1} )); then string+=" \e[31mDISABLED for $G_HW_MODEL_NAME\e[0m" # Available for G_DISTRO? elif (( ! ${aSOFTWARE_AVAIL_G_DISTRO[$i,$G_DISTRO]:=1} )); then string+=" \e[31mDISABLED for Debian $G_DISTRO_NAME\e[0m" fi # Append online docs if available [[ ${aSOFTWARE_DOCS[$i]} ]] && string+=" | \e[90m${aSOFTWARE_DOCS[$i]}\e[0m" echo -e "$string" done fi elif [[ $1 == 'free' ]]; then # Get highest software array index local max=0 for max in "${!aSOFTWARE_NAME[@]}"; do :; done # Check for unused indices local free= for (( i=0; i<=$max; i++ )); do [[ ${aSOFTWARE_NAME[$i]} ]] || free+=" $i"; done echo "Free software ID(s):${free:- None, so use $(($max+1))!}" else G_DIETPI-NOTIFY 1 "Invalid input command ($1). Aborting...\n$USAGE" exit 1 fi } #///////////////////////////////////////////////////////////////////////////////////// # Whip menus #///////////////////////////////////////////////////////////////////////////////////// MENU_MAIN_LASTITEM='Help!' TARGETMENUID=0 # $1=search: Show search box and show only matches in menu Menu_CreateSoftwareList() { local i j selected reset=() # Search mode if [[ $1 == 'search' ]] then G_WHIP_INPUTBOX 'Please enter a software title, ID or keyword to search, e.g.: desktop/cloud/media/torrent' || return 0 G_WHIP_CHECKLIST_ARRAY=() # Loop through all software titles for i in "${!aSOFTWARE_NAME[@]}" do # Check if this software is available for hardware, arch and distro (( ${aSOFTWARE_AVAIL_G_HW_MODEL[$i,$G_HW_MODEL]:=1} && ${aSOFTWARE_AVAIL_G_HW_ARCH[$i,$G_HW_ARCH]:=1} && ${aSOFTWARE_AVAIL_G_DISTRO[$i,$G_DISTRO]:=1} )) || continue # Check if input matches software ID, name or description [[ $G_WHIP_RETURNED_VALUE == "$i" || ${aSOFTWARE_NAME[$i],,} == *"${G_WHIP_RETURNED_VALUE,,}"* || ${aSOFTWARE_DESC[$i],,} == *"${G_WHIP_RETURNED_VALUE,,}"* ]] || continue # Set checkbox based on install state, including previous selection (( ${aSOFTWARE_INSTALL_STATE[$i]} > 0 )) && selected='on' || selected='off' # Add this software title to whiptail menu G_WHIP_CHECKLIST_ARRAY+=("$i" "${aSOFTWARE_NAME[$i]}: ${aSOFTWARE_DESC[$i]}" "$selected") # Add previously selected items to array to be unmarked if deselected when selection is confirmed. (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) && reset+=("$i") done (( ${#G_WHIP_CHECKLIST_ARRAY[@]} )) || { G_WHIP_MSG "We couldn't find any available software title for the search term: \"$G_WHIP_RETURNED_VALUE\""; return 0; } # Generate whiptail menu list of all software titles, sorted by category else G_WHIP_CHECKLIST_ARRAY=() # Loop through software category IDs for i in "${!aSOFTWARE_CATEGORIES[@]}" do # Add category to whiptail menu G_WHIP_CHECKLIST_ARRAY+=('' "${aSOFTWARE_CATEGORIES[$i]}" 'off') # Loop through software title IDs for j in "${!aSOFTWARE_CATX[@]}" do # Check if this software's category matches the current category (( ${aSOFTWARE_CATX[$j]} == $i )) || continue # Check if this software is available for hardware, arch and distro (( ${aSOFTWARE_AVAIL_G_HW_MODEL[$j,$G_HW_MODEL]:=1} && ${aSOFTWARE_AVAIL_G_HW_ARCH[$j,$G_HW_ARCH]:=1} && ${aSOFTWARE_AVAIL_G_DISTRO[$j,$G_DISTRO]:=1} )) || continue # Set checkbox based on install state, including previous selection (( ${aSOFTWARE_INSTALL_STATE[$j]} > 0 )) && selected='on' || selected='off' # Add this software title to whiptail menu G_WHIP_CHECKLIST_ARRAY+=("$j" "${aSOFTWARE_NAME[$j]}: ${aSOFTWARE_DESC[$j]}" "$selected") # Add previously selected items to array to be unmarked if deselected when selection is confirmed. (( ${aSOFTWARE_INSTALL_STATE[$j]} == 1 )) && reset+=("$j") done done fi G_WHIP_SIZE_X_MAX=96 # Assure this is enough to show full software descriptions + scroll bar G_WHIP_BUTTON_OK_TEXT='Confirm' G_WHIP_CHECKLIST 'Please use the spacebar to select the software you wish to install. Then press ENTER/RETURN or select to confirm. - Press ESC or select to discard changes made. - Software and usage details: https://dietpi.com/docs/software/' || return 0 # Unmark all listed pending state items, so deselected items are not installed. for i in "${reset[@]}" do aSOFTWARE_INSTALL_STATE[$i]=0 done # Mark selected items for install for i in $G_WHIP_RETURNED_VALUE do (( ${aSOFTWARE_INSTALL_STATE[$i]} == 2 )) || aSOFTWARE_INSTALL_STATE[$i]=1 done # Unmark conflicting software Unmark_Conflicts #----------------------------------------------------------------------------- # Install info/warnings/inputs # DietPi-Drive_Manager can be used to setup Samba/NFS shares with ease! (( ${aSOFTWARE_INSTALL_STATE[1]} == 1 || ${aSOFTWARE_INSTALL_STATE[110]} == 1 )) && G_WHIP_MSG "[ INFO ] Mount NFS/Samba shares via DietPi-Drive_Manager \nDietPi-Drive_Manager is a powerful tool which vastly simplifies the mounting of NFS and Samba shares. \nOnce $G_PROGRAM_NAME has finished installation, simply run 'dietpi-drive_manager' to setup required network mounts." # PaperMC: Inform user about long install/startup time and possible swap file usage if (( ${aSOFTWARE_INSTALL_STATE[181]} == 1 )) then local swap_info= (( $RAM_PHYS < 924 )) && swap_info='\n\nThe server will be started with with minimal required memory usage, but a swap file will be created to assure that no out-of-memory crash can happen. On servers with less than 1 GiB physical memory, we strongly recommend to move the swap file to an external drive if your system runs on an SD card, since during normal PaperMC operation this swap space will be heavily used.' G_WHIP_MSG "PaperMC will be started during install to allow pre-configuring it's default configuration files. Especially on smaller SBCs, like Raspberry Pi Zero, this can take a long time. We allow it to take up to 30 minutes, it's process can be followed, please be patient.$swap_info" fi # mjpg-streamer: Warn about unprotected stream and inform about additional plugins (( ${aSOFTWARE_INSTALL_STATE[137]} == 1 )) && G_WHIP_MSG '[ WARN ] The mjpg-streamer camera stream will be accessible unprotected at port 8082 by default. \nYou can configure a password protection, but this will break embedding the stream into other web interfaces, like OctoPrint. \nWe hence recommend to not forward port 8082 through your NAT and/or block public access via firewall. \nIf you require access from outside your local network to a web interface that embeds the camera stream, we recommend to setup a VPN connection for this. \nRead more about this matter and how to configure mjpg-streamer at our online documentation: https://dietpi.com/docs/software/camera/#mjpg-streamer \n[ INFO ] mjpg-streamer will not be compiled with all available plugins by default. \nIf you require other input or output plugins, simply install the required dependencies. Plugins will be compiled automatically if dependencies are met. \nFor available plugins and their dependencies, watch the info printed during the build and check out the official GitHub repository: https://github.com/jacksonliam/mjpg-streamer' # RPi Cam Web Interface: Warn user of locking out camera: https://github.com/MichaIng/DietPi/issues/249 (( ${aSOFTWARE_INSTALL_STATE[59]} == 1 )) && G_WHIP_MSG 'RPi Cam Web Interface will automatically start and activate the camera during boot. This will prevent other programs (like raspistill) from using the camera. \nYou can free up the camera by selecting "Stop Camera" from the web interface:\n - http://myip/rpicam' # Offer to install Unbound along with AdGuard Home and Pi-hole if (( ${aSOFTWARE_INSTALL_STATE[93]} == 1 || ${aSOFTWARE_INSTALL_STATE[126]} == 1 )) then # Add option to use Unbound as upstream DNS server if (( ${aSOFTWARE_INSTALL_STATE[182]} == 0 )) then G_WHIP_BUTTON_CANCEL_TEXT='Skip' G_WHIP_YESNO 'Would you like to use Unbound, a tiny recursive DNS server hosted on your device, as your upstream DNS server? \nThis will increase privacy, because you will not be sending data to Google etc. \nHowever, the downside is that some websites may load slower the first time you visit them.' && aSOFTWARE_INSTALL_STATE[182]=1 fi # Prompt for static IP if G_WHIP_BUTTON_CANCEL_TEXT='Skip' G_WHIP_YESNO 'A static IP address is essential for a DNS server installation. DietPi-Config can be used to quickly setup your static IP address. \nIf you have already setup your static IP, please ignore this message.\n\nWould you like to setup your static IP address now?' then G_WHIP_MSG 'DietPi-Config will now be launched. Simply select your Ethernet or Wifi connection from the menu to access the IP address settings. \nThe "copy current address to STATIC" menu option can be used to quickly setup your static IP. Please ensure you change the mode "DHCP" to "STATIC". \nOnce completed, select "Apply Save Changes", then exit DietPi-Config to resume setup.' /boot/dietpi/dietpi-config 8 fi fi # WiFi Hotspot Criteria if (( ${aSOFTWARE_INSTALL_STATE[60]} == 1 || ${aSOFTWARE_INSTALL_STATE[61]} == 1 )) then # Enable WiFi modules /boot/dietpi/func/dietpi-set_hardware wifimodules enable while : do local criteria_passed=1 local output_string='The following criteria must be met for the installation of WiFi Hotspot to succeed:' if [[ $(G_GET_NET -q -t eth ip) ]] then output_string+='\n\n - Ethernet online: PASSED' else criteria_passed=0 output_string+='\n\n - Ethernet online: FAILED.\nUse dietpi-config to connect and configure Ethernet.' fi if [[ $(G_GET_NET -q -t wlan iface) ]] then output_string+='\n\n - WiFi adapter detected: PASSED' else criteria_passed=0 output_string+='\n\n - WiFi adapter detected: FAILED.\nPlease connect a WiFi adapter and try again.' fi # Passed if (( $criteria_passed )) then output_string+='\n\nPASSED: Criteria met. Good to go.' G_WHIP_MSG "$output_string" break # Failed, retry? else output_string+='\n\nFAILED: Criteria not met. Would you like to check again?' G_WHIP_YESNO "$output_string" && continue (( ${aSOFTWARE_INSTALL_STATE[60]} == 1 )) && aSOFTWARE_INSTALL_STATE[60]=0 (( ${aSOFTWARE_INSTALL_STATE[61]} == 1 )) && aSOFTWARE_INSTALL_STATE[61]=0 G_WHIP_MSG 'WiFi Hotspot criteria were not met. The software will not be installed.' break fi done fi # Let's Encrypt (( ${aSOFTWARE_INSTALL_STATE[92]} == 1 )) && G_WHIP_MSG 'The DietPi installation of Certbot supports all offered web servers.\n\nOnce the installation has finished, you can setup your free SSL cert with: - DietPi-LetsEncrypt\n\nThis is an easy to use frontend for Certbot and allows integration into DietPi systems.\n\nMore information:\n - https://dietpi.com/docs/software/system_security/#lets-encrypt' # Steam on ARMv7 via Box86 warning (( ${aSOFTWARE_INSTALL_STATE[156]} == 1 && $G_HW_ARCH == 2 )) && G_WHIP_MSG '[WARNING] Steam natively only runs on the x86 systems.\n\nBox86 will be used to run it on ARM, however there may be performance and compatibility issues.' # Home Assistant: Inform about long install/build time: https://github.com/MichaIng/DietPi/issues/2897 (( ${aSOFTWARE_INSTALL_STATE[157]} == 1 )) && G_WHIP_MSG '[ INFO ] Home Assistant: Grab yourself a coffee \nThe install process of Home Assistant within the virtual environment, especially the Python build, can take more than one hour, especially on slower SBCs like RPi Zero and similar. \nPlease be patient. In the meantime you may study the documentation: - https://dietpi.com/docs/software/home_automation/#home-assistant' } Menu_Main() { # Selected SSH server choice local sshserver_text='None' if (( ${aSOFTWARE_INSTALL_STATE[104]} > 0 )); then sshserver_text=${aSOFTWARE_NAME[104]} # Dropbear elif (( ${aSOFTWARE_INSTALL_STATE[105]} > 0 )); then sshserver_text=${aSOFTWARE_NAME[105]} # OpenSSH fi # Selected logging system choice local index_logging_text='None' if (( $INDEX_LOGGING == -1 )); then index_logging_text='DietPi-RAMlog #1' elif (( $INDEX_LOGGING == -2 )); then index_logging_text='DietPi-RAMlog #2' elif (( $INDEX_LOGGING == -3 )); then index_logging_text='Full' fi # Get real userdata location local user_data_location_current=$(readlink -f /mnt/dietpi_userdata) local user_data_location_description="Custom | $user_data_location_current" if [[ $user_data_location_current == '/mnt/dietpi_userdata' ]]; then user_data_location_description="SD/eMMC | $user_data_location_current" elif [[ $user_data_location_current == "$(findmnt -Ufnro TARGET -S /dev/sda1)" ]]; then user_data_location_description="USB Drive | $user_data_location_current" fi # Software to be installed or removed based on choice system local tobeinstalled_text toberemoved_text G_WHIP_MENU_ARRAY=( 'Help!' ': Links to online guides, docs and information' 'DietPi-Config' ': Feature-rich configuration tool for your device' '' '●─ Select Software ' 'Search Software' ': Find software to install via search box' 'Browse Software' ': Select software from the full list' 'SSH Server' ": [$sshserver_text]" 'Log System' ": [$index_logging_text]" 'User Data Location' ": [$user_data_location_description]" '' '●─ Install or Remove Software ' 'Uninstall' ': Select installed software for removal' 'Install' ': Go >> Start installation for selected software' ) G_WHIP_DEFAULT_ITEM=$MENU_MAIN_LASTITEM G_WHIP_BUTTON_CANCEL_TEXT='Exit' G_WHIP_SIZE_X_MAX=80 if G_WHIP_MENU; then MENU_MAIN_LASTITEM=$G_WHIP_RETURNED_VALUE case "$G_WHIP_RETURNED_VALUE" in 'Uninstall') Menu_Uninstall_Software;; 'Search Software') Menu_CreateSoftwareList search;; 'Browse Software') Menu_CreateSoftwareList;; 'SSH Server') G_WHIP_MENU_ARRAY=( 'None' ': Not required / manual setup' "${aSOFTWARE_NAME[104]}" ": ${aSOFTWARE_DESC[104]} (recommended)" "${aSOFTWARE_NAME[105]}" ": ${aSOFTWARE_DESC[105]}" ) G_WHIP_DEFAULT_ITEM=$sshserver_text G_WHIP_BUTTON_CANCEL_TEXT='Back' G_WHIP_MENU 'Please select desired SSH server: \n- None: Selecting this option will uninstall all SSH servers. This reduces system resources and improves performance. Useful for users who do NOT require networked/remote terminal access. \n- Dropbear (recommended): Lightweight SSH server, installed by default on DietPi systems. \n- OpenSSH: A feature-rich SSH server with SFTP/SCP support, at the cost of increased resource usage.' || return 0 # Apply selection case "$G_WHIP_RETURNED_VALUE" in 'None') Apply_SSHServer_Choices 0;; "${aSOFTWARE_NAME[105]}") Apply_SSHServer_Choices -2;; *) Apply_SSHServer_Choices -1;; esac # Check for changes for i in 104 105 do (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) && tobeinstalled_text+="\n - ${aSOFTWARE_NAME[$i]}" (( ${aSOFTWARE_INSTALL_STATE[$i]} == -1 )) && toberemoved_text+="\n - ${aSOFTWARE_NAME[$i]}" done [[ $tobeinstalled_text || $toberemoved_text ]] || return 0 [[ $tobeinstalled_text ]] && tobeinstalled_text="\n\nThe following software will be installed:$tobeinstalled_text" [[ $toberemoved_text ]] && toberemoved_text="\n\nThe following software will be uninstalled:$toberemoved_text" G_WHIP_MSG "$G_WHIP_RETURNED_VALUE has been selected:\n- Your choice will be applied when 'Install Go >> Start installation' is selected.$tobeinstalled_text$toberemoved_text" ;; 'Log System') G_WHIP_MENU_ARRAY=( 'None' ': Not required / manual setup' 'DietPi-RAMlog #1' ': Hourly clear (recommended)' 'DietPi-RAMlog #2' ': Hourly save, then clear' 'Full' ': Logrotate and Rsyslog' ) G_WHIP_DEFAULT_ITEM=$index_logging_text G_WHIP_BUTTON_CANCEL_TEXT='Back' G_WHIP_MENU 'Please select desired logging system: \n- None: Selecting this option will uninstall DietPi-RAMlog, Logrotate and Rsyslog. \n- DietPi-RAMlog #1 (Max performance): Mounts /var/log to RAM, reducing filesystem I/O. Logfiles are cleared every hour. Does NOT save logfiles to disk. \n- DietPi-RAMlog #2: Same as #1, with the added feature of appending logfile contents to disk at /root/logfile_storage, before being cleared. \n- Full (Reduces performance): Leaves /var/log on DISK, reduces SD card lifespan. Full logging system with Logrotate and Rsyslog.' || return 0 # Apply selection case "$G_WHIP_RETURNED_VALUE" in 'None') Apply_Logging_Choices 0;; 'DietPi-RAMlog #2') Apply_Logging_Choices -2;; 'Full') Apply_Logging_Choices -3;; *) Apply_Logging_Choices -1;; esac # Check for changes for i in 101 102 103 do (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) && tobeinstalled_text+="\n - ${aSOFTWARE_NAME[$i]}" (( ${aSOFTWARE_INSTALL_STATE[$i]} == -1 )) && toberemoved_text+="\n - ${aSOFTWARE_NAME[$i]}" done [[ $tobeinstalled_text || $toberemoved_text ]] || return 0 [[ $tobeinstalled_text ]] && tobeinstalled_text="\n\nThe following software will be installed:$tobeinstalled_text" [[ $toberemoved_text ]] && toberemoved_text="\n\nThe following software will be uninstalled:$toberemoved_text" G_WHIP_MSG "$G_WHIP_RETURNED_VALUE has been selected:\n- Your choice will be applied when 'Install : Go >> Start installation' is selected.$tobeinstalled_text$toberemoved_text" ;; 'User Data Location') # - Vars if we need to move data. local move_data_target=$user_data_location_current G_WHIP_MENU_ARRAY=( 'List' ': Select from a list of available drives to move user data.' 'Custom' ': Manually enter a location to move user data.' 'Drive' ': Launch DietPi-Drive_Manager.' ) G_WHIP_BUTTON_CANCEL_TEXT='Back' G_WHIP_MENU 'Choose where to store your user data. User data includes software such as ownCloud data store, BitTorrent downloads etc. \nMore information on user data in DietPi:\n- https://dietpi.com/docs/dietpi_tools/#quick-selections \n- DietPi-Drive_Manager: Launch DietPi-Drive_Manager to setup external drives, and, move user data to different locations.' || return 0 # Launch DietPi-Drive_Manager if [[ $G_WHIP_RETURNED_VALUE == 'Drive' ]]; then /boot/dietpi/dietpi-drive_manager return 0 # List elif [[ $G_WHIP_RETURNED_VALUE == 'List' ]]; then /boot/dietpi/dietpi-drive_manager 1 || return 1 local return_value=$(> Start installation' } Menu_StartInstall() { local tobeinstalled_text toberemoved_text summary_text # Obtain list of pending software installs and uninstalls for i in "${!aSOFTWARE_NAME[@]}" do (( ${aSOFTWARE_INSTALL_STATE[$i]} == 1 )) && tobeinstalled_text+="\n - ${aSOFTWARE_NAME[$i]}: ${aSOFTWARE_DESC[$i]}" (( ${aSOFTWARE_INSTALL_STATE[$i]} == -1 )) && toberemoved_text+="\n - ${aSOFTWARE_NAME[$i]}: ${aSOFTWARE_DESC[$i]}" done # Check if user made/changed software selections if [[ $tobeinstalled_text || $toberemoved_text ]] then # List selections and ask for confirmation [[ $tobeinstalled_text ]] && tobeinstalled_text="\n\nThe following software will be installed:$tobeinstalled_text" [[ $toberemoved_text ]] && toberemoved_text="\n\nThe following software will be uninstalled:$toberemoved_text" [[ $G_SERVICE_CONTROL == 0 ]] || summary_text='\n\nNB: Software services will be temporarily controlled (stopped) by DietPi during this process. Please inform connected users, before continuing. SSH and VNC are not affected.' G_WHIP_DEFAULT_ITEM='ok' G_WHIP_YESNO "DietPi is now ready to apply your software choices:$tobeinstalled_text$toberemoved_text$summary_text \nSoftware details, usernames, passwords etc:\n - https://dietpi.com/docs/software/\n\nWould you like to begin?" || return 0 # If due to choice changes only uninstalls are done and it is not the first run setup, skip the install function and call the uninstall function directly. if [[ $G_DIETPI_INSTALL_STAGE == 2 && ! $tobeinstalled_text ]] then Uninstall_Software Write_InstallFileList else GOSTARTINSTALL=1 # Set install start flag fi TARGETMENUID=-1 # Exit menu loop # After first run setup has finished, abort install without any selections elif (( $G_DIETPI_INSTALL_STAGE == 2 )) then G_WHIP_MSG 'No changes have been detected. Unable to start installation.' # Allow to finish first run setup without any selections else G_WHIP_DEFAULT_ITEM='ok' G_WHIP_YESNO 'DietPi was unable to detect any additional software selections for install. \nNB: You can use dietpi-software at a later date, to install optimised software from our catalogue as required. \nDo you wish to continue with DietPi as a pure minimal image?' || return 0 TARGETMENUID=-1 # Exit menu loop GOSTARTINSTALL=1 # Set install start flag fi } Menu_Uninstall_Software() { # Array which will hold all software IDs to be removed. G_WHIP_CHECKLIST_ARRAY=() # Obtain list of installed software local i for i in "${!aSOFTWARE_NAME[@]}" do (( ${aSOFTWARE_INSTALL_STATE[$i]} == 2 )) || continue # Skip webserver stacks: Their install states will be aligned with webserver/database install states automatically. [[ $i =~ ^(75|76|78|79|81|82)$ ]] || G_WHIP_CHECKLIST_ARRAY+=("$i" "${aSOFTWARE_NAME[$i]}: ${aSOFTWARE_DESC[$i]}" 'off') done # No software installed if (( ! ${#G_WHIP_CHECKLIST_ARRAY[@]} )) then G_WHIP_MSG 'No software is currently installed.' # Run menu else G_WHIP_DEFAULT_ITEM='ok' G_WHIP_BUTTON_CANCEL_TEXT='Back' G_WHIP_CHECKLIST 'Use the spacebar to select the software you would like to remove:' && [[ $G_WHIP_RETURNED_VALUE ]] || return 0 # Create list for user to review before removal local output_string='The following software will be REMOVED from your system:' for i in $G_WHIP_RETURNED_VALUE do output_string+="\n - ${aSOFTWARE_NAME[$i]} (ID=$i): ${aSOFTWARE_DESC[$i]}" done G_WHIP_YESNO "$output_string \nNB: Uninstalling usually PURGES any related userdata and configs. If you only need to repair or update software, please use \"dietpi-software reinstall \" instead. \nDo you wish to continue?" || return 0 # Mark for uninstall for i in $G_WHIP_RETURNED_VALUE do aSOFTWARE_INSTALL_STATE[$i]=-1 done # Run uninstall Uninstall_Software # Save install states Write_InstallFileList G_WHIP_MSG 'Uninstall completed' fi } #///////////////////////////////////////////////////////////////////////////////////// # Main Loop #///////////////////////////////////////////////////////////////////////////////////// # Abort if a reboot is required as of missing kernel modules if [[ $1 != 'list' && $G_DIETPI_INSTALL_STAGE == 2 ]] && ! G_CHECK_KERNEL then G_WHIP_BUTTON_CANCEL_TEXT='Abort' G_WHIP_YESNO "[ INFO ] A reboot is required \nKernel modules for the loaded kernel at /lib/modules/$(uname -r) are missing. This is most likely the case as of a recently applied kernel upgrade where a reboot is required to load the new kernel. \nTo assure that $G_PROGRAM_NAME can run successfully, especially when performing installs, it is required that you perform a reboot so that kernel modules can be loaded ondemand. \nThere may be rare cases where no dedicated kernel modules are used but all require modules are builtin. If this is the case, please create the mentioned directory manually to proceed. \nDo you want to reboot now?" && reboot || exit 1 fi # Init software arrays Software_Arrays_Init #------------------------------------------------------------------------------------- # Load .installed file, update vars if it exists Read_InstallFileList #------------------------------------------------------------------------------------- # CLI input mode: Force menu mode on first run if [[ $1 && $G_DIETPI_INSTALL_STAGE == 2 ]] then Input_Modes "$@" #------------------------------------------------------------------------------------- # Standard launch else # DietPi-Automation pre install steps (( $G_DIETPI_INSTALL_STAGE == 2 )) || DietPi-Automation_Pre # Start DietPi Menu until (( $TARGETMENUID < 0 )) do G_TERM_CLEAR Menu_Main done fi #------------------------------------------------------------------------------------- # Start DietPi-Software installs (( $GOSTARTINSTALL )) || exit 0 # Userdata location verify G_CHECK_USERDATA # Start software installs Run_Installations # DietPi-Automation post install steps (( $G_DIETPI_INSTALL_STAGE == 2 )) || DietPi-Automation_Post G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Install completed' # Upload DietPi-Survey data if opted in, prompt user choice if no settings file exists # - Skip if G_SERVICE_CONTROL == 0, exported by "patches" (DietPi-Update) which sends survey already # Start services, restart to reload configs of possibly running services if [[ $G_SERVICE_CONTROL != 0 ]] then /boot/dietpi/dietpi-survey 1 /boot/dietpi/dietpi-services restart (( $RESTART_DELUGE_WEB )) && { G_SLEEP 1; G_EXEC_NOHALT=1 G_EXEC systemctl restart deluge-web; } fi # Start installed services, not controlled by DietPi-Services [[ ${aSTART_SERVICES[0]} ]] || exit 0 G_DIETPI-NOTIFY 2 'Starting installed services not controlled by DietPi-Services' for i in "${aSTART_SERVICES[@]}" do G_EXEC_NOHALT=1 G_EXEC systemctl start "$i" done #------------------------------------------------------------------------------------- exit 0 #------------------------------------------------------------------------------------- }