Scripts for the Script-Guided Installation

Introduction

The purpose of the provided scripts is to ease installation or upgrades of ownCloud instances. Using these scripts, you can also reapply ownership and access rights on linked directories if needed.

General Info

It is important to understand how these scripts work and why things are done to process all the steps for a successful, smooth and secure installation or upgrade.

Do not use this script in conjunction with Upgrading ownCloud with the Updater App. When using the Updater App, your web server must have write access to core files to overwrite them. Therefore it is necessary to set much weaker permissions when using the Updater app which can be in some circumstances a security issue. The scripts used with the Script-Guided Installation use strong permissions to prevent the web server overwriting core files. The web server can only write to defined locations handled by the script. This greatly increases security and hardens the environment of the ownCloud server.
Installation

When you do a fresh installation using this set of scripts, consider using links for the data/ and apps-external/ directories. Any copying or moving big directories can cause issues which can be avoided by using links. When doing an upgrade after an installation, the scripts can re-link those directories but will not "migrate" standard ones. If standard directories are used, the admin has to select a suitable method to migrate those directories as part of the upgrade process. You will get notified about this task if necessary.

Migrating from standard to linked directories

You can at any time relocate your data/ and apps-external/ directories and link them to the old location using symlinks. This does not impact the functionality but eases upgrade steps a lot. In such a case, parametrize the instance script with the proper values to be prepared for the next upgrade. See some details at the configuration section below.

Do not try to use the script to migrate between directory types. Your environment will break and data loss can occur. Any migration from one type to another must be done manually and before using the script.

Upgrading

When upgrading, the scripts rename the current ownCloud directory (usually owncloud) to owncloud-timestamp. A new and fresh owncloud directory will be created where the files from the tar archive get extracted to. By doing so, nothing gets deleted, overwritten or moved and the existing instance is secured to go back to in case it is needed. Note that the script does not take care of the database. You have to manage a database backup yourself. When you have decided to use links for data/ and apps-external/, the script will re-link these directories. Nothing gets moved. You can also (re)run the scrips on linked directories to set correct ownership and permissions. When using standard directories, you have to manually migrate them according to your environment and also manually check for correct ownership and permissions.

The scripts take care of your configuration. The relevant files are copied from the backup.

If the upgrade was successful, you can delete the backup or keep it based on your requirements.

Scripts

There are two scripts available. The instance script defines the environment for your ownCloud while the preparation script called by the instance script performs the main tasks. Note that the preparation script asks a couple of questions to decide what you want to achieve.

If you administrate more than one ownCloud instance, you still only need the one owncloud_prep.sh script. This script is doing the main job. Have as many instance scripts as you have instances to maintain. Only the instance scripts need configuration, like the respective target directory and other predefined information. The instance.sh script (or however you will name it) calls owncloud_prep.sh with the configuration you defined for the respective instance.

The scripts are written for the bash shell. After you copy and pasted them, save both in a location for easy access.

Use the following scripts at your own risk. They may not work as expected if not properly configured.
The scripts are only working with tar archives as sources for installations and upgrades.
You can also use these scripts if you want to set or reapply strong permissions on linked drectories.

Configuration

  • This is a brief overview of main directories in case you use linking. Note that /mnt/owncloud_data can be for example nfs mounted. The script takes care of proper linking the source to the target.

    /mnt/owncloud_data
     └ apps-external
     └ data
    
    /var/www/owncloud
     └ apps
     └ apps-external -> /mnt/owncloud_data/apps-external
     └ data -> /mnt/owncloud_data/data
      ..
  • This is a brief overview of main directories in case you use standard directories

    /var/www/owncloud
     └ apps
     └ apps-external
     └ data
      ..

While this makes no difference for an installation, upgrading is much easier as you do not need to take care of migrating directories as they are simply re-linked.

You only need to edit the instance.sh script (or however you name it), if you want to change the default settings.

The following table illustrates the variables to be configured and what they mean.

Variable Description

ocname

The name of your directory containing the owncloud files (default is owncloud)

ocroot

The path to ocname, usually /var/www (no trailing slash, default is /var/www)

linkroot

The path to your source directory for linking data and apps-external (default /mnt/owncloud_data). You have to prepare this directory in advance and give it proper ownership and r/w permissions for the webserver user. Note that the apps directory is always part of the tar archive and therefore be extracted at its default location without being linked.

htuser

The webserver user (default www-data)

htgroup

The webserver group (default www-data)

rootuser

The root user (default root). Necessary to run some commands in the script. Note that the script is not intended to run as superuser for security reasons.

  1. ocname
    This is the directory name where your ownCloud files will be saved. Suggestion: Use owncloud for a single instance but feel free to pick any name you like. Do not use slashes (/).

    With only one site to serve, use html as it requires no additional settings to maintain on the Apache webserver after the installation. If you use any other name like owncloud, you need to set the correct directory in the Apache configuration. For more information, see the Apache documentation. If you are hosting additional websites on the same server, better use a name different from the Apache default (html).
  2. ocroot
    This is the path where ocname will be created, for example /var/www.
    The path must be resolvable! Do not use trailing slashes (/).
    ocroot/ocname is the path/directory where your webserver points to (document root).
    The script resolves this for example to /var/www/owncloud.

  3. linkroot
    Although not mandatory, it is highly recommended that you use symbolic links for the data and apps-external directories. The data directory can grow very large and any copy or move process might take a long time on upgrades. Therefore this directory is often put on external drives or on NFS mounts. The apps-external directory is used for all apps not provided by the ownCloud installation. With any physical upgrade you perform, manual intervention like copying may be necessary before finalizing and upgrade if you are not using links. The use of symbolic links makes the administration much easier and less error-prone.

    The script uses linkroot as base for both the data and apps-external directories. If not already present, it creates the directories from scratch and links them, both for the installation and on upgrades.

    If you consider using symbolic links, create a base directory at the location of choice (for example: /mnt/oc_data) and let that directory be owned by your webserver’s user or group. Use this directory as your linkroot. Do not use trailing slashes (/).

  4. htuser and htgroup
    This is the user and group the webserver uses, usually www-data.

  5. rootuser
    This is the name of the root user, usually root.

Usage

It is mandatory to run this script with root privileges, because files and directories will be created and ownership and permissions will be set. Call the instance script like:

sudo ./instance.sh

The script asks you a couple of questions which follow a logical path. Default answers are capitalized.

When installing

the script extracts the files with tar and automatically extracts them to the target location without copying.

In case of an upgrade

the old instance path is backed up by renaming and adding a time stamp. A new target folder with the old name is created. This ensures that in case of extracting and preparation issues, you can easily go back to the previous version. After a successful upgrade, you must manually remove the backup folder.

If you do not install or upgrade, the script sets ownership and permissions on linked directories only.
In case of upgrading, if you have customized the .htaccess or .user.ini file in the ownCloud webroot, you have to manually restore any changes made after the script has finished from the backup folder. Take care to only restore the changes made but not the complete file as this file will be recreated on upgrades by the tar source and may contain different settings provided by ownCloud. Customizing .htaccess can be necessary when you e.g. Integrate ownCloud into Microsoft Teams.
In case of upgrading, if you have created links to the apps-external/ and data/ directory, the script will re-link these directories. If you used standard directories, you have to manually migrate any content of these directories back after the script has run. Check that ownership and permissions are correct after migration and in doubt, let the scrips set the correct ones when using linked directories or set them manually - which can take a while depending on the size of the data/ directory. Take care not to overwrite new app versions with older ones.

Script Questions

  • Do you want to secure your .htaccess files post installing/upgrade (y/N)?
    Use this if you have configured or upgraded your instance successfully to protect your .htaccess files.

  • Do you want to install a new instance (y/N)?
    Self explaining

  • Do you want to upgrade an existing installation (y/N)?
    Use this if you already have a running instance. Prepare your instance by enabling maintenance mode. For security reasons, you will be asked before the script continues!

  • Use links for data and apps-external directories (Y/n)?
    The script uses respectively checks if links or local directories will be / are used.

  • Do you want to chmod/chown these links (y/N)?
    This question is only asked when you use links. If you are not installing or upgrading, answering with yes, you can e.g. re-apply ownership and permissions to the linked data and apps-external directories. As written above, the data directory can be very large and may take long to complete. Note, by design, there is no progressbar…​

  • Please specify the tar file to extract with full path:
    Used when installing or upgrading only. Enter the full path/filename to the tar source file, downloaded from ownCloud.

Final Steps

After running the script, you will see success messages when it finishes.

When installing

Enter the URL of your ownCloud instance in a browser and continue the setup via the graphical installation wizard. For more information, see The Installation Wizard. The URL you need to enter in the browser depends on the webserver setup and is either an external URL or, if you installed locally, you should be able to access your ownCloud instance via a browser at http://127.0.0.1/owncloud/ or http://localhost/owncloud/.

When upgrading

Follow the steps printed on the screen, especially when using standard directories where you have to migrate the data/ and apps-external/ directories manually before finalizing the upgrade. Do not forget to reapply manually made changes made to .htaccess and .user.ini in your owncloud root directory.

How to see the difference between two files quickly

The following example command shows you the difference between two files, which is helpful for reapplying manual changes to .htaccess and .user.ini. Change the paths, directories and files accordingly.

diff -y -W 70 --suppress-common-lines owncloud/.user.ini owncloud_2022-02-15-09.18.48/.user.ini
post_max_size=513M                |     post_max_size=1G

Creating the scripts

Save both scripts together in a directory of your choice. Name the instance.sh script according to your needs, so you can easily identify to which ownCloud installation it applies. However, the script owncloud_prep.sh is called with exactly that name by the instance script, therefore you must save it with exactly that name.

Edit your version of the instance.sh script with the parameters that apply to your environment.

Next, make both scripts executable (use the correct script names instead of the placeholder):

sudo chmod +x scriptname.sh
  1. The instance.sh script

    #!/bin/bash
    # Script Version 2022.06.23
    
    # This script prepares the parameters for owncloud_prep.sh
    # Handy if you have more instances to maintain where the process stays the same with different parameters
    # The processing script is expected in the same directory of this script.
    
    # To setup this script for your environment, adopt the following variables to your needs:
    #
    # ocname        the name of your directory containing the owncloud files
    # ocroot        the path to ocname, usually /var/www (no trailing slash)
    # linkroot      the path to your source directory for linking data and apps-external (no trailing slash)
    # htuser        the webserver user
    # htgroup       the webserver group
    # rootuser      the root user
    
    ocname='owncloud'
    ocroot='/var/www'
    
    linkroot='/mnt/owncloud_data'
    
    htuser='www-data'
    htgroup='www-data'
    rootuser='root'
    
    if [ "$(id -u)" != 0 ]; then
      printf "\nThis script should be run as root user to allow filesystem modifications\nExiting\n\n"
    fi
    
    printf "\nConsider backing up the database before you continue when upgrading!\n\n"
    
    # Resolve the absolute path this script is located and expects the called script to be there too
    DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
    
    $DIR/owncloud_prep.sh "$ocname" "$ocroot" "$linkroot" "$htuser" "$htgroup" "$rootuser"
  2. The owncloud_prep.sh script

    #!/bin/bash
    # Script Version 2023.01.25
    
    # To set up this script for your environment, hand over the following variables according your needs:
    #
    # ocname        the name of your directory containing the owncloud files
    # ocroot        the path to ocname, usually /var/www (no trailing slash)
    # linkroot      the path to your source directory for linking data and apps-external (no trailing slash)
    # htuser        the webserver user
    # htgroup       the webserver group
    # rootuser      the root user
    
    # Short description for parameters used in find
    #
    # -L       ... Follow symbolic links. Needed in case if links are used or present
    # -path    ... The path to process
    # -prune   ... If the file is a directory, do not descend into it (used to exclude directories)
    # -o       ... OR (to add more parameters)
    # -type    ... File is of type [d ... directory, f ... file]
    # -print0  ... Print the full file name on the standard output, followed by a null character
    # xargs -0 ... Reads items from the standard input, input items are terminated by a null character
    
    
    ocname=$1
    ocroot=$2
    ocpath=$ocroot/$ocname
    ocdata=$ocroot/$ocname/'data'
    ocapps_external=$ocpath/'apps-external'
    oldocpath=$ocroot/$ocname'_'$(date +%F-%H.%M.%S)
    
    linkroot=$3
    linkdata=$linkroot/'data'
    linkapps_external=$linkroot/'apps-external'
    
    htuser=$4
    htgroup=$5
    rootuser=$6
    
    arguments=6
    
    filmod="0640"
    dirmod="0750"
    htamod="0640"
    
    # Because the data directory can be huge or on external storage, an automatic chmod/chown can take a while.
    # Therefore this directory can be treated differently.
    # If you have already created an external "data" and "apps-external" directory which you want to link,
    # set the paths above accordingly. This script can link and set the proper rights and permissions
    # depending what you enter when running the script.
    
    # When the instance is setup either post a fresh install or after an upgrade, run this script again but
    # only for securing ".htaccess files". This sets the appropriate ownership and permission for them.
    
    # In case you upgrade an existing installation, your original directory will be renamed including a timestamp
    
    
    if [ "$#" -ne "$arguments" ]; then
      printf "\nThis script needs $arguments arguments, $# given.\n\n"
    fi
    
    printf "\nFollowing parameters used\n\n"
    printf "ocname: $ocname\nocroot: $ocroot\nlinkroot: $linkroot\nhtuser: $htuser\nhtgroup:  $htgroup\nrootuser:  $rootuser\n"
    
    function get_tar {
      read -p "Please specify the tar file to extract with full path: " -r -e tarFile
      if [ ! -f "$tarFile" ]; then
        echo "tar file to extract not found. Exiting."
        echo
        exit
      fi
    }
    
    echo
    
    read -p "Do you want to secure your .htaccess files post installing/upgrade (y/N)? " -r -e answer
    (echo "$answer" | grep -iq "^y") && do_secure="y" || do_secure="n"
    
    if [ "$do_secure" = "y" ]; then
      printf "\nSecuring .htaccess files with chmod/chown\n"
      if [ -f ${ocpath}/.htaccess ]; then
        chmod $htamod ${ocpath}/.htaccess
        chown ${rootuser}:${htgroup} ${ocpath}/.htaccess
      fi
      if [ -f ${ocdata}/.htaccess ];then
        chmod $htamod ${ocdata}/.htaccess
        chown ${rootuser}:${htgroup} ${ocdata}/.htaccess
      fi
      printf "\nDone\n\n"
      exit
    fi
    
    
    read -p "Do you want to install a new instance (y/N)? " -r -e answer
    (echo "$answer" | grep -iq "^y") && do_new="y" || do_new="n"
    
    
    if [ "$do_new" = "n" ]; then
        read -p "Do you want to upgrade an existing installation (y/N)? " -r -e answer
        (echo "$answer" | grep -iq "^y") && do_upgrade="y" || do_upgrade="n"
    fi
    
    read -p "Use links for data and apps-external directories (Y/n)? " -r -e answer
    (echo "$answer" | grep -iq "^n") && uselinks="n" || uselinks="y"
    
    if [ "$uselinks" = "y" ]; then
      read -p "Do you want to chmod/chown these links (y/N)? " -r -e answer
      (echo "$answer" | grep -iq "^y") && chmdir="y" || chmdir="n"
    fi
    
    # check if upgrading an existing installation
    if [ "$do_upgrade" = "y" ]; then
      read -p "Is the instance in maintenance mode? (y/N)? " -r -e answer
      (echo "$answer" | grep -iq "^y") && mmode="y" || mmode="n"
      if [ "$mmode" = "n" ]; then
        echo "Please enable maintenance mode first: sudo -u$htuser ./occ maintenance:mode --on"
        echo
        exit
      fi
      get_tar
      # rename the source for backup reasons
      if [ -d ${ocpath} ]; then
        mv $ocpath $oldocpath
      fi
    fi
    
    # get the tar file for new installs
    if [ "$do_new" = "y" ]; then
      get_tar
    fi
    
    # in case of upgrade or new, extract the source
    if [ "$do_upgrade" = "y" ] || [ "$do_new" = "y" ]; then
      mkdir -p $ocpath
      tar xvf "$tarFile" -C $ocpath --strip-components=1
    
      if [ $? != 0 ]; then
        echo
        echo "tar extract failed, please check !"
        echo
        # rename back in case of tar errors
        if [ "$do_upgrade" = "y" ] && [ -d ${oldocpath} ]; then
          rm -r $ocpath
          mv $oldocpath $ocpath
        fi
        exit
      fi
    fi
    
    # create / link missing directories
    printf "\nCreating or linking possible missing directories \n"
    mkdir -p $ocpath/updater
    # check if directory creation is possible and create if ok
    if [ "$uselinks" = "n" ]; then
      if [ -L ${ocdata} ]; then
        echo "Symlink for $ocdata found but mkdir requested. Exiting."
        echo
        exit
      else
        echo "mkdir $ocdata"
        echo
        mkdir -p $ocdata
      fi
      if [ -L ${ocapps_external} ]; then
        echo "Symlink for $ocapps_external found but mkdir requested. Exiting."
        echo
        exit
      else
        printf "mkdir $ocapps_external \n"
        mkdir -p $ocapps_external
      fi
    else
      if [ -d ${ocdata} ] && [ ! -L $ocdata ]; then
        echo "Directory for $ocdata found but link requested. Exiting."
        echo
        exit
      else
        printf "ln $ocdata --> $linkdata\n"
        mkdir -p $linkdata
        ln -sfn $linkdata $ocdata
      fi
      if [ -d ${ocapps_external} ] && [ ! -L $ocapps_external ]; then
        echo "Directory for $ocapps_external found but link requested. Exiting."
        echo
        exit
      else
        printf "ln $ocapps_external --> $linkapps_external\n"
        mkdir -p $linkapps_external
        ln -sfn $linkapps_external $ocapps_external
      fi
    fi
    
    # copy existing *config.php and all .json files which are required for the new webUI
    if [ "$do_upgrade" = "y" ]; then
      # check if at minimum a config.php file is present
      # note that you can have more than one config.php representing different settings
      if [ -f ${oldocpath}/config/config.php ]; then
        printf "\nCopy existing *config.php and *.json files \n"
        # using find to omit messages if no files found
        find ${oldocpath}/config/ -name \*config.php -exec cp {} ${ocpath}/config/ \;
        find ${oldocpath}/config/ -name \*.json -exec cp {} ${ocpath}/config/ \;
      else
        printf "Skip to copy old config.php, file not found: ${oldocpath}/config/config.php \n"
      fi
    fi
    
    printf "\nchmod files and directories excluding data and apps-external directory\n"
    
    # check if there are files to chmod/chown available. If not, exiting.
    # chmod
    if [ ! "$(find $ocpath -maxdepth 1 -type f)" ]; then
      echo "Something is wrong. There are no files to chmod. Exiting."
      exit
    fi
    
    find -L ${ocpath} -path ${ocdata} -prune -o -path ${ocapps_external} -prune -o -type f -print0 | xargs -0 chmod $filmod
    find -L ${ocpath} -path ${ocdata} -prune -o -path ${ocapps_external} -prune -o -type d -print0 | xargs -0 chmod $dirmod
    
    # no error messages on empty directories
    if [ "$chmdir" = "n" ] && [ "$uselinks" = "n" ]; then
    
      printf "chmod data and apps-external directory (mkdir) \n"
    
      if [ -n "$(ls -A $ocdata)" ]; then
        find ${ocdata}/ -type f -print0 | xargs -0 chmod $filemod
      fi
      find ${ocdata}/ -type d -print0 | xargs -0 chmod $dirmod
      if [ -n "$(ls -A $ocapps_external)" ]; then
        find ${ocapps_external}/ -type f -print0 | xargs -0 chmod $filemod
      fi
      find ${ocapps_external}/ -type d -print0 | xargs -0 chmod $dirmod
    fi
    
    if [ "$chmdir" = "y" ] && [ "$uselinks" = "y" ]; then
    
      printf "chmod data and apps-external directory (linked) \n"
    
      if [ -n "$(ls -A $ocdata)" ]; then
        find -L ${ocdata}/ -type f -print0 | xargs -0 chmod $filmod
      fi
      find -L ${ocdata}/ -type d -print0 | xargs -0 chmod $dirmod
      if [ -n "$(ls -A $ocapps_external)" ]; then
        find -L ${ocapps_external}/ -type f -print0 | xargs -0 chmod $filmod
      fi
      find -L ${ocapps_external}/ -type d -print0 | xargs -0 chmod $dirmod
    fi
    
    #chown
    printf "chown files and directories excluding data and apps-external directory \n"
    
    find  -L $ocpath  -path ${ocdata} -prune -o -path ${ocapps_external} -prune -o -type d -print0 | xargs -0 chown ${rootuser}:${htgroup}
    find  -L $ocpath  -path ${ocdata} -prune -o -path ${ocapps_external} -prune -o -type f -print0 | xargs -0 chown ${rootuser}:${htgroup}
    
    # do only if directories are present
    if [ -d ${ocpath}/apps/ ]; then
      printf "chown apps directory \n"
      chown -R ${htuser}:${htgroup} ${ocpath}/apps/
    fi
    if [ -d ${ocpath}/config/ ]; then
      printf "chown config directory \n"
      chown -R ${htuser}:${htgroup} ${ocpath}/config/
    fi
    if [ -d ${ocpath}/updater/ ]; then
      printf "chown updater directory \n"
      chown -R ${htuser}:${htgroup} ${ocpath}/updater
    fi
    
    if [ "$chmdir" = "n" ] && [ "$uselinks" = "n" ]; then
      printf "chown data and apps-external directories (mkdir) \n"
      chown -R ${htuser}:${htgroup} ${ocapps_external}/
      chown -R ${htuser}:${htgroup} ${ocdata}/
    fi
    if [ "$chmdir" = "y" ] && [ "$uselinks" = "y" ]; then
      printf "chown data and apps-external directories (linked) \n"
      chown -R ${htuser}:${htgroup} ${ocapps_external}/
      chown -R ${htuser}:${htgroup} ${ocdata}/
    fi
    
    printf "\nchmod occ command to make it executable \n"
    if [ -f ${ocpath}/occ ]; then
      chmod +x ${ocpath}/occ
    fi
    
    
    # tell to remove the old instance, do upgrade and end maintenance mode etc.
    printf "\nSUCCESS\n\n"
    if [ "$do_upgrade" = "y" ]; then
      if [ "$uselinks" = "n" ]; then
        echo "Please migrate (move/copy) your data/ and apps-external/ directory manually back to the original location BEFORE running the upgrade command!"
        echo
      fi
      echo "Please change to your upgraded ownCloud directory: cd $ocroot/$ocname"
      echo "Please manually run: sudo -u $htuser ./occ maintenance:mode --off"
      echo "Please manually run: sudo -u $htuser ./occ upgrade"
      echo "Copy any changes manually added in .user.ini and .htaccess from the backup directory"
      echo "Please manually remove the directory of the old instance: $oldocpath"
      echo "When successfully done, re-run this script to secure your .htaccess files"
      echo
    fi
    
    if [ "$do_new" = "y" ]; then
      echo "Open your browser, configure your instance and rerun this script to secure your .htaccess files"
      echo
    fi