diff --git a/.gitignore b/.gitignore index 4e945dd..f8b4314 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ logs/ deploy/nextcloud deploy/opt build/mnt +dev/** diff --git a/deploy/start b/deploy/start index 7ba4c55..c9b227e 100755 --- a/deploy/start +++ b/deploy/start @@ -1,6 +1,6 @@ #!/bin/bash -if dcp=$(./dcp $1); then - eval "$dcp up $2" +if dcp=$(./dcp "$@"); then + eval "$dcp up -d" else echo no environment file passed ${1:-$ENV_FILE} -fi \ No newline at end of file +fi diff --git a/dev/build b/dev/build index 0650dd4..46518ba 100755 --- a/dev/build +++ b/dev/build @@ -2,9 +2,9 @@ [[ $1 = "-f" ]] && force=force && shift if [[ ! $(udbuild image exists -e ../build/.env) || $force ]] ; then echo $force building image - pushd ../build || exit + pushd ../build > /dev/null || exit ./build -p -e .env -a build.env $@ - popd + popd > /dev/null echo done building image else echo using existing image, use -f to force rebuild diff --git a/dev/dcstart b/dev/dcstart old mode 100644 new mode 100755 index 7d0dc6c..ac0f341 --- a/dev/dcstart +++ b/dev/dcstart @@ -1 +1,3 @@ -docker-compose up \ No newline at end of file +CMD=$1 +CMD=${CMD:-idle} docker-compose up -d +[[ ! $CMD ]] && docker exec -it try-ucommandit-nextcloud /opt/bin/entrypoint nextcloud shell \ No newline at end of file diff --git a/dev/debug b/dev/debug index 00f5b6b..ed1fb75 100755 --- a/dev/debug +++ b/dev/debug @@ -1,6 +1,5 @@ #!/bin/bash # # check for image and build -source ./build $1 -[[ $force ]] && shift 1 -mkdir dopt -udbuild try -e ../build/.env -f nextcloud.env -m opt -h dopt -o '-p 8080:8080' -k shell \ No newline at end of file +./build "$@" +mkdir opt &> /dev/null +./try -v NEXTCLOUD_DEV=clean nextcloud shell \ No newline at end of file diff --git a/dev/devsync b/dev/devsync index 8e806c9..25063e9 100755 --- a/dev/devsync +++ b/dev/devsync @@ -1,5 +1,8 @@ -rsync -r ../src/rootfs/opt/lib/ opt/lib/ -rsync -r ../src/rootfs/opt/supervisor/ opt/supervisor/ -rsync -r ../src/rootfs/opt/bin/ opt/bin/ -rsync -r ../src/rootfs/opt/env/ opt/env/ -rsync -r ../src/rootfs/opt/caddy/conf/ opt/caddy/conf \ No newline at end of file +opt=${1:-opt} +rsync -r ../src/rootfs/opt/lib/ $opt/lib/ +rsync -r ../src/rootfs/opt/supervisor/ $opt/supervisor/ +rsync -a ../src/rootfs/opt/bin/ $opt/bin/ +rsync -r ../src/rootfs/opt/env/ $opt/env/ +rsync -r ../src/rootfs/opt/nextcloud/config/ $opt/nextcloud/config +rsync -r ../src/rootfs/opt/caddy/conf/ $opt/caddy/conf +rsync -r ../src/rootfs/opt/nextcloud/db/ $opt/nextcloud/db \ No newline at end of file diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml index b840d34..0408a5f 100644 --- a/dev/docker-compose.yml +++ b/dev/docker-compose.yml @@ -1,40 +1,59 @@ -version: '3' services: nextcloud-app: image: ucommandit/nextcloud container_name: try-ucommandit-nextcloud - # use exec to substitute shell script at PID 1 ? - entrypoint: ['exec /opt/bin/boot'] + # restart: ${RESTART:-unless-stopped} + command: ['nextcloud', "${CMD:-idle}" ] hostname: compose-uci-nextcloud env_file: nextcloud.env volumes: - # - nextcloud:/opt/nextcloud - - opt:/opt + # required volume to save state of nextcloud instance + - nextcloud:/opt/nextcloud + # for pre-downloaded releases + - releases:/opt/releases + # for full dev development + # - opt:/opt + # for minimal development (just the nextcloud cli) + # - lib:/opt/lib ports: + # required: the nextcloud web server - 8080:8080 - - 9001:9001 + # if using ssh access to container + - 8022:22 + # this is for supervisor interface + # - 9001:9001 + volumes: - # db: - # driver: local - # driver_opts: - # o: bind - # type: none - # device: ${HOST_NEXTCLOUD_DB} - - opt: + + nextcloud: driver: local driver_opts: o: bind type: none - device: ${PWD}/opt + device: ${PWD}/devcloud - # nextcloud: + releases: + driver: local + driver_opts: + o: bind + type: none + device: ${PWD}/releases + + # lib: # driver: local # driver_opts: # o: bind # type: none - # device: ${PWD}/nextcloud + # device: ${PWD}/lib + + # opt: + # driver: local + # driver_opts: + # o: bind + # type: none + # device: ${PWD}/opt + # user-files: # driver: local # driver_opts: diff --git a/dev/nextcloud.env.example b/dev/nextcloud.env.example index c359e36..669bf41 100644 --- a/dev/nextcloud.env.example +++ b/dev/nextcloud.env.example @@ -6,27 +6,6 @@ COMPOSE_PROJECT_NAME=nextcloud # https://timezonedb.com/time-zones TZ=America/Los_Angles -# default is sqlite, mariadb or mysql, postgres -# SQL_DB_TYPE=mysql - -# sqlite default db name -# SQLITE_DATABASE=nextcloud-db - -# mariadb/mysql -# MYSQL_ROOT_PASSWORD=nextcloud1234 -# MYSQL_HOST=nextcloud -# MYSQL_PASSWORD=nextcloud1234 -# MYSQL_DATABASE=nextcloud -# MYSQL_USER=nextcloud - -# postgres -# MYSQL_ROOT_PASSWORD=nextcloud1234 -# MYSQL_PASSWORD=nextcloud1234 -# MYSQL_DATABASE=nextcloud -# MYSQL_USER=nextcloud - - - # NEXTCLOUD TRUSTED_PROXIES="" NEXTCLOUD_DOMAIN="" @@ -46,14 +25,11 @@ SMTP_PORT=465 SMTP_NAME="" SMTP_PASSWORD="" -# volumes can be found at /var/lib/docker/volumes but can be bound else via below -# DOCKER HOST Volume Bindings Parent Directory -# use only if you need/want to bind the three volumes elsewhere for easier access -# will create up to three directories parent/nextcloud/ -# must pre make all the directories /nextcloud/ == db,src,user-files -# must uncomment driver and driver opts in docker-compose.yml in the volumes stanza -# HOST_NEXTCLOUD_PARENT_DIR=/data +SSH_USER=root +SSH_PUBKEY="the public key" +SSH_ADDRESS=10.0.0.43 +SSH_HOST_PORT diff --git a/dev/shell b/dev/shell index 8a77f00..aefa36d 100755 --- a/dev/shell +++ b/dev/shell @@ -2,4 +2,4 @@ # # check for image and build source ./build $1 [[ $force ]] && shift 1 -./try -k "$@" nextcloud shell \ No newline at end of file +./try -k "$@" shell \ No newline at end of file diff --git a/dev/term b/dev/term index 316c481..eb54a7f 100755 --- a/dev/term +++ b/dev/term @@ -1 +1 @@ -docker exec -t try-ucommandit-nextcloud /bin/bash -l \ No newline at end of file +docker exec -it try-ucommandit-nextcloud $@ \ No newline at end of file diff --git a/dev/try b/dev/try index 7a6e1fb..3560626 100755 --- a/dev/try +++ b/dev/try @@ -1,5 +1,3 @@ #!/bin/bash # # check for image and build -source ./build $1 -[[ $force ]] && shift 1 -udbuild try -e ../build/.env -f nextcloud.env -m opt -h opt -o '-p 8080:8080' -o '-p 9001:9001' -o '--dns=10.0.0.1' "$@" +udbuild try -k -e ../build/.env -f nextcloud.env -m opt -h opt -o '-p 8080:8080 -p 8022:22 --dns=10.0.0.1' "$@" diff --git a/src/init/init.sh b/src/init/init.sh index 443e70d..b503674 100755 --- a/src/init/init.sh +++ b/src/init/init.sh @@ -18,7 +18,7 @@ PHP_VERSION="${PHP_VERSION#php}" ln -s $(which php-fpm$PHP_VERSION) /bin/php-fpm echo -e "export PHP_INI_DIR=$PHP_INI_DIR\nexport PHP_VERSION=$PHP_VERSION" >> $ENV_DIR/php.env -cat $ENV_DIR/php.env +quiet cat $ENV_DIR/php.env cat < $PHP_INI_DIR/conf.d/03-opcache-recommended.ini opcache.enable=1 @@ -41,13 +41,13 @@ mysql.max_links=-1 mysql.default_port= mysql.default_socket=/run/nextcloud/db.sock mysql.default_host=localhost -mysql.default_user=${MYSQL_USER:-nextcloud} -mysql.default_password=${MYSQL_PASSWORD:-nextcloud1234} +mysql.default_user=${NEXTCLOUD_DB_USER:-nextcloud} +mysql.default_password=${NEXTCLOUD_DB_PASSWORD:-nextcloud} mysql.connect_timeout=60 mysql.trace_mode=Off [Pdo_mysql] -pdo_mysql.default_socket=/opt/nextcloud/db/db.sock +pdo_mysql.default_socket=/run/nextcloud/db.sock PHP cat < "${PHP_INI_DIR}/conf.d/03-ext-apcu.ini" @@ -66,7 +66,7 @@ rm $PHP_INI_DIR/php-fpm.d/www.conf cat < $PHP_INI_DIR/php-fpm.d/nextcloud.conf [global] -error_log = $NEXTCLOUD_LOGS_DIR/php-fpm.err +error_log = $NEXTCLOUD_LOGS_DIR/php-fpm.error.log log_level = ${PHP_LOG_LEVEL:-warning} emergency_restart_threshold = 10 emergency_restart_interval = 1m @@ -105,8 +105,8 @@ php_admin_value[session.save_path] = /var/tmp/nextcloud php_admin_value[sys_temp_dir] = /var/tmp/nextcloud php_admin_value[upload_tmp_dir] = /var/tmp/nextcloud php_admin_flag[log_errors] = on -php_admin_value[error_log] = $NEXTCLOUD_LOGS_DIR/admin.php.error.log -php_admin_value[opcache.error_log] = $NEXTCLOUD_LOGS_DIR/admin.opcache.php.error.log +php_admin_value[error_log] = $NEXTCLOUD_LOGS_DIR/php.admin.error.log +php_admin_value[opcache.error_log] = $NEXTCLOUD_LOGS_DIR/php.admin.opcache.error.log php_admin_flag[output_buffering] = false php_admin_value[disable_functions] = exec,passthru,system,proc_open,curl_multi_exec,show_source php_admin_flag[opcache.enable_cli] = true @@ -117,18 +117,23 @@ php_admin_value[opcache.memory_consumption] = 128 php_admin_value[opcache.revalidate_freq] = 1 catch_workers_output = yes -slowlog = $NEXTCLOUD_LOGS_DIR/slow.log -access.log = $NEXTCLOUD_LOGS_DIR/access.log +slowlog = $NEXTCLOUD_LOGS_DIR/php-slow.log +access.log = $NEXTCLOUD_LOGS_DIR/php-access.log PHP +# create php temp directory and set ownership +mkdir -p /var/tmp/nextcloud +chown -R $USER:$USER /var/tmp/nextcloud + + # ls -la $PHP_INI_DIR/conf.d -ls -la $PHP_INI_DIR/php-fpm.d +quiet ls -la $PHP_INI_DIR/php-fpm.d # cat $PHP_INI_DIR/conf.d/03-opcache-recommended.ini # cat "${PHP_INI_DIR}/conf.d/03-docker-php-ext-apcu.ini" # cat $PHP_INI_DIR/conf.d/03-nextcloud.ini -cat $PHP_INI_DIR/php-fpm.d/nextcloud.conf +quiet cat $PHP_INI_DIR/php-fpm.d/nextcloud.conf -# allow only occ as part of nextcloud +# remove any occ not part of nextcloud source rm -f /usr/bin/occ source $LIB_DIR/caddy.lib @@ -138,4 +143,40 @@ chown -R $USER:$USER $CADDY_HOME echo "vm.overcommit_memory = 1" | sudo tee /etc/sysctl.d/nextcloud-memory-overcommit.conf +mkdir /opt/releases +chown -R $USER:$USER /opt/releases + +echo keeping a copy of /opt/nextcloud core files for later updates in /opt/nextcloud-container +mkdir /opt/nextcloud-container +chown -R $USER:$USER /opt/nextcloud-container +rsync -r /opt/nextcloud/ /opt/nextcloud-container + +echo creating crontab file @ /etc/crontabs/$USER +echo "*/5 * * * * $(which php) -f $NEXTCLOUD_SRC_DIR/cron.php" > /etc/crontabs/$USER +chown $USER:$USER /etc/crontabs/$USER +chmod 0600 /etc/crontabs/$USER +cat /etc/crontabs/$USER + +echo generating ssh server keys +ssh-keygen -A +echo adding nextcloud sourcing for root ssh session + +source /opt/lib/release.lib + +cat << EOF > /container-build +container: + name: ${BUILD_NAME:-Ucommandit Nextcloud Container} + desc: ${BUILD_DESC:-nextcloud} + id: $(date '+%Y%m%d%H%M%S') + tag: ${BUILD_TAG:-$(date '+%Y.%m.%d')} + date: $(date) + php: $PHP_VERSION + mysql: $(mysql --version | cut -f1 -d- | rev | cut -f1 -d' ' | rev) + caddy: $(/usr/sbin/caddy -v | cut -f2 -dv) + redis: $(redis-server -v | cut -f3 -d ' ' | cut -f2 -d=) + nc-tested: ${NEXCLOUD_TESTED_VERSION:-$(nextcloud_releases latest)} +EOF + +chmod 0600 /container-build + echo -e "********** Done: Nextcloud Setup and Install ***************" diff --git a/src/packages/packages.sh b/src/packages/packages.sh old mode 100644 new mode 100755 index 838bf51..364a726 --- a/src/packages/packages.sh +++ b/src/packages/packages.sh @@ -1,20 +1,31 @@ -# php version estatablished in php.env via run.env - - echo "----- Installing php version $PHP_VERSION specific system packages in $file ---------------" - while IFS= read -r pkg || [ -n "$pkg" ]; do - echo installing: php$PHP_VERSION-$pkg - silence $INSTALL_PKGS php$PHP_VERSION-$pkg - done < ./php-ver.mods - echo "done ----- Installing System Packages from $file ---------------" - -echo adding php version specific modules based on php version installed: $PHP_VERSION -silence $INSTALL_PKGS php$PHP_VERSION-pecl-imagick -silence $INSTALL_PKGS php$PHP_VERSION-pdo_mysql -silence $INSTALL_PKGS php$PHP_VERSION-pecl-redis -silence $INSTALL_PKGS php$PHP_VERSION-pecl-apcu - - - - +#!/bin/bash +source $LIB_DIR/verbose.lib +source $ENV_DIR/run.env +source php-modules.sh +update_supervisor () { +supver=$(/usr/bin/supervisord --version) +pkgs=/usr/lib/python3.12/site-packages +echo updating supervisord $supver to latest commit from https://github.com/Supervisor/supervisor.git +mv $pkgs/supervisor $pkgs/supervisor-$supver +git clone https://github.com/Supervisor/supervisor.git /tmp/supervisor +mv /tmp/supervisor/supervisor $pkgs/supervisor +if [[ $(/usr/bin/supervisord --version) == *dev* ]]; then + echo supervisord has been updated to latest commit + /usr/bin/supervisord --version + rm -rf /tmp/supervisor + rm -rf $pkgs/supervisor-$supver + else + unable to update supervisord, rolling back to latest release $supver + rm -rf $pkgs/supervisor + mv $pkgs/supervisor-$supver $pkgs/supervisor + if [[ $(/usr/bin/supervisord --version) == "$supver" ]]; then + echo restore succesfull + else + echo WARNING: restore failed + return 1 + fi +fi +} +[[ $UPDATE_SUPERVISOR ]] && update_supervisor \ No newline at end of file diff --git a/src/packages/php-modules.sh b/src/packages/php-modules.sh new file mode 100755 index 0000000..a6b19be --- /dev/null +++ b/src/packages/php-modules.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# php version estatablished in php.env via run.env +list="" +list+=" $(ls ./php-modules/*.mods 2> /dev/null)" +silence echo list of files containg php$PHPVERSION modules to install: $list +for file in $list; do + [ -f "$file" ] || break + echo installing php$PHPVERSION modules from $file + cat $file | head -n 1 + #sed -e 'h;s/[^#]*//1;x;s/#.*//;${1};G;s/(.*)\n/\1/' < $file + sed '/^[[:space:]]*#[^!]/d; /#$/d' $file | sed '/^\s*$/ d' | cut -f1 -d\ | while IFS= read -r mod || [ -n "$mod" ]; do + echo installing module $mod as $LINUX_DISTRO package php$PHP_VERSION-$mod + silence $INSTALL_PKGS php$PHP_VERSION-$mod + done + echo "done ----- Installing php$PHP_VERSION modules from $file ---------------" +done +echo "done ----- Installing all php$PHP_VERSION modules for build ---------------" diff --git a/src/packages/php-modules/01-required.mods b/src/packages/php-modules/01-required.mods new file mode 100644 index 0000000..0f74772 --- /dev/null +++ b/src/packages/php-modules/01-required.mods @@ -0,0 +1,18 @@ +# Required Modules for Nextcloud +# https://docs.nextcloud.com/server/latest/admin_manual/installation/php_configuration.html +ctype # this is a comment after +curl +dom +fileinfo (included with PHP) +gd +# JSON (included with PHP >= 8.0) +xml (Linux package libxml2 must be >=2.7.0) +mbstring +# openssl (included with PHP >= 8.0) +posix +session +simplexml +xmlreader +xmlwriter +zip +zlib \ No newline at end of file diff --git a/src/packages/php-modules/02-database.mods b/src/packages/php-modules/02-database.mods new file mode 100644 index 0000000..6b6180a --- /dev/null +++ b/src/packages/php-modules/02-database.mods @@ -0,0 +1,4 @@ +# database Modules +# pdo_sqlite (>= 3, usually not recommended for performance reasons) +pdo_mysql (MySQL/MariaDB) +# pdo_pgsql (PostgreSQL) \ No newline at end of file diff --git a/src/packages/php-modules/03-recommended.mods b/src/packages/php-modules/03-recommended.mods new file mode 100644 index 0000000..b18b275 --- /dev/null +++ b/src/packages/php-modules/03-recommended.mods @@ -0,0 +1,9 @@ +# Recommended Modules + +# no translation needed so no need +intl (increases language translation performance and fixes sorting of non-ASCII characters) + +sodium (for Argon2 for password hashing. bcrypt is used as fallback, but if passwords were hashed with Argon2 already and the module is missing, your users can't log in. Included with PHP >= 7.2) + +pcntl (enables command interruption by pressing ``ctrl-c``) +sysvsem \ No newline at end of file diff --git a/src/packages/php-modules/04-cache.mods b/src/packages/php-modules/04-cache.mods new file mode 100644 index 0000000..5f7b7f1 --- /dev/null +++ b/src/packages/php-modules/04-cache.mods @@ -0,0 +1,5 @@ +# cache modules +pecl-memcached +pecl-redis +pecl-apcu +opcache \ No newline at end of file diff --git a/src/packages/php-modules/05-required-by-apps.mods b/src/packages/php-modules/05-required-by-apps.mods new file mode 100644 index 0000000..754f0ef --- /dev/null +++ b/src/packages/php-modules/05-required-by-apps.mods @@ -0,0 +1,16 @@ +# Required for specific apps: + +# ldap (for LDAP integration) +# smbclient (SMB/CIFS integration, see :doc:`../configuration_files/external_storage/smb`) +# ftp (for FTP storage / external user authentication) +imap (for external user authentication) +bcmath (for passwordless login) +gmp (for passwordless login, sftp) + +# Recommended + +exif (for image rotation in pictures app) + +# For preview generation (*optional*): + +pecl-imagick diff --git a/src/packages/php-ver.mods b/src/packages/php-ver.mods deleted file mode 100644 index 8937a3a..0000000 --- a/src/packages/php-ver.mods +++ /dev/null @@ -1,5 +0,0 @@ -pecl-imagick -pdo_mysql -pecl-redis -pecl-apcu -sysvsem \ No newline at end of file diff --git a/src/packages/system/01-core.pkgs b/src/packages/system/01-core.pkgs index a42cfdf..cac0929 100644 --- a/src/packages/system/01-core.pkgs +++ b/src/packages/system/01-core.pkgs @@ -1,4 +1,5 @@ -jq +yq-go rsync envsubst -supervisor \ No newline at end of file +supervisor +openssh \ No newline at end of file diff --git a/src/packages/system/02-php-pkgs b/src/packages/system/02-php.pkgs similarity index 54% rename from src/packages/system/02-php-pkgs rename to src/packages/system/02-php.pkgs index b7ea69d..893bcdd 100644 --- a/src/packages/system/02-php-pkgs +++ b/src/packages/system/02-php.pkgs @@ -1,2 +1,3 @@ php php-fpm +phpmyadmin \ No newline at end of file diff --git a/src/packages/system/03-helper.pkgs b/src/packages/system/03-helper.pkgs new file mode 100644 index 0000000..b5d1996 --- /dev/null +++ b/src/packages/system/03-helper.pkgs @@ -0,0 +1,5 @@ +caddy +redis +imagemagick +imagemagick-svg +supercronic \ No newline at end of file diff --git a/src/packages/system/03-nextcloud.pkgs b/src/packages/system/03-nextcloud.pkgs deleted file mode 100644 index ee2b621..0000000 --- a/src/packages/system/03-nextcloud.pkgs +++ /dev/null @@ -1,4 +0,0 @@ -nextcloud -nextcloud-initscript -caddy -redis \ No newline at end of file diff --git a/src/packages/system/04-db.pkgs b/src/packages/system/04-db.pkgs new file mode 100644 index 0000000..4d6ebc5 --- /dev/null +++ b/src/packages/system/04-db.pkgs @@ -0,0 +1,3 @@ +mariadb +mariadb-client +mariadb-server-utils \ No newline at end of file diff --git a/src/packages/system/04-nextcloud-db.pkgs b/src/packages/system/04-nextcloud-db.pkgs deleted file mode 100644 index be079d0..0000000 --- a/src/packages/system/04-nextcloud-db.pkgs +++ /dev/null @@ -1,4 +0,0 @@ -nextcloud-sqlite -mariadb -mariadb-client -nextcloud-mysql diff --git a/src/packages/system/05-nextcloud-apps.pkgs b/src/packages/system/05-nextcloud-apps.pkgs deleted file mode 100644 index a8de958..0000000 --- a/src/packages/system/05-nextcloud-apps.pkgs +++ /dev/null @@ -1,6 +0,0 @@ -nextcloud-files_pdfviewer -nextcloud-text -nextcloud-notifications -nextcloud-files_videoplayer -nextcloud-files_external -nextcloud-default-apps \ No newline at end of file diff --git a/src/rootfs/etc/profile b/src/rootfs/etc/profile deleted file mode 100644 index dfc8913..0000000 --- a/src/rootfs/etc/profile +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash - -# do not add code here for non-interative login shell -# rather put additional non-interactive profile script code in files in /etc/profile.d - -# this files is sourced for all login shells and also interactive non-login shells via /etc/bash.bashrc -# more info see http://www.linuxfromscratch.org/blfs/view/svn/postlfs/profile.html - -# interactive non-login and login shells will call the BASH_SHELL_LOAD script below -# non-interative login shells only source /etc/profile.d -# in profile.d is 03-startup.sh which will call -# any of the scripts in a repo's startup subdirectory -# non-interactive non-login shells are not handled here only via /etc/bash.bashrc -# interactive login - - -([ -n "$SSH_CONNECTION" ] || [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]) && export SSH_SESSION=true -[[ $- == *i* ]] && export SHELL_INTERACTIVE=true -shopt -q login_shell && export SHELL_LOGIN=true -[ $EUID -eq 0 ] && export USER_ROOT=true - -# uncomment for debugging non-interactive login shell, i.e. $ . /etc/profile -#unset SHELL_INTERACTIVE - -#uncomment these for debugging. -# echo ---- sourcing system /etc/profile --- -# [[ $USER_ROOT ]] && echo 'Root User' || echo 'Non Root User' -# [[ $SHELL_INTERACTIVE ]] && echo 'Interactive' || echo 'Not interactive' -# [[ $SHELL_LOGIN ]] && echo 'Login shell' || echo 'Not login shell' -# [[ $SSH_SESSION ]] && echo ssh remote user || echo local user -# echo --------------------- - -# Set the initial path -export PATH=/bin:/usr/bin:/usr/local/bin -# set directory for base shell repo -export BASH_SHELL_BASE=/shell -# now bootstrap by souring the shell repo envinroment -source $BASH_SHELL_BASE/shell.env -# set $BASH_SAFE_MODE=true in shell.env to disable UCI interactive shell from loading -# TODO see if $NO_BASH_SHELL_SSH=true in user or host directory (at the remote machine) -# if so don't source the load command below and make just a simple prompt. -if [[ $SHELL_INTERACTIVE ]]; then - if [[ ! $BASH_SAFE_MODE ]]; then - # echo interactive shell loading $BASH_SHELL_LOAD - source "$BASH_SHELL_LOAD" - else - # safe mode - # just set a simple prompt instead - NORMAL="\[\e[0m\]" - RED="\[\e[1;31m\]" - GREEN="\[\e[1;32m\]" - YELLOW='\e[1;33m' - if [[ $EUID == 0 ]] ; then - PS1="${YELLOW}SAFE:$RED\u [ $NORMAL\w$RED ]# $NORMAL" - else - PS1="${YELLOW}SAFE:$GREEN \u [ $NORMAL\w$GREEN ]\$ $NORMAL" - fi - unset RED GREEN NORMAL YELLOW - fi -else - # this is non-interactive login (e.g. at user machine login) - if [[ $EUID -ne 0 ]] && [[ ! $SSH_SESSION ]]; then - export LOGIN_LOG=$HOME/logs/login.log - mkdir -p $HOME/logs - touch $LOGIN_LOG - llog () { - echo "$@" >> $LOGIN_LOG 2>&1 - } - export -f llog - llog "$(env | grep BASH)" - echo "$(date)" > $LOGIN_LOG - llog "non-interactive login shell for $USER" - if [ -d /etc/profile.d ]; then - for i in /etc/profile.d/*.sh; do - if [ -r $i ]; then - llog "sourcing $i" - source $i - fi - done - unset i - fi - fi -fi diff --git a/src/rootfs/etc/profile.d/02-root.sh b/src/rootfs/etc/profile.d/02-root.sh deleted file mode 100644 index 0d85643..0000000 --- a/src/rootfs/etc/profile.d/02-root.sh +++ /dev/null @@ -1,6 +0,0 @@ -# root login setup only, put in if block -if [ $EUID -eq 0 ] ; then # if root user - echo login profile, root specific setup - export PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin - unset HISTFILE -fi diff --git a/src/rootfs/etc/profile.d/03-startup.sh b/src/rootfs/etc/profile.d/03-startup.sh deleted file mode 100644 index 42bd158..0000000 --- a/src/rootfs/etc/profile.d/03-startup.sh +++ /dev/null @@ -1,10 +0,0 @@ -# this runs startups for bash shell base system - # don't run statup if user logs in via su - if [ "$SHELL" = "/bin/bash" ] && [ "${BASH_SHELL_STARTUP}" ] && [ "$(ps -o comm= $PPID)" != "su" ]; then - # uncomment for debugging - if [[ -f $BASH_SHELL_STARTUP ]] && [[ $EUID -ne 0 ]]; then - llog "sourcing startup script $BASH_SHELL_STARTUP" - # (${BASH_SHELL_STARTUP}) & - source ${BASH_SHELL_STARTUP} - fi - fi diff --git a/src/rootfs/etc/ssh/sshd_config b/src/rootfs/etc/ssh/sshd_config new file mode 100644 index 0000000..145b7f6 --- /dev/null +++ b/src/rootfs/etc/ssh/sshd_config @@ -0,0 +1,2 @@ +# use configuration files +Include /etc/ssh/sshd_config.d/*.conf diff --git a/src/rootfs/etc/ssh/sshd_config.d/01-lockdown.conf b/src/rootfs/etc/ssh/sshd_config.d/01-lockdown.conf new file mode 100644 index 0000000..097acc0 --- /dev/null +++ b/src/rootfs/etc/ssh/sshd_config.d/01-lockdown.conf @@ -0,0 +1,8 @@ +PermitRootLogin no +ChallengeResponseAuthentication no +KbdInteractiveAuthentication no +PubkeyAuthentication no +KbdInteractiveAuthentication no +PasswordAuthentication no +PrintMotd no + diff --git a/src/rootfs/etc/ssh/sshd_config.d/02-sftp.conf b/src/rootfs/etc/ssh/sshd_config.d/02-sftp.conf new file mode 100644 index 0000000..91ce3bb --- /dev/null +++ b/src/rootfs/etc/ssh/sshd_config.d/02-sftp.conf @@ -0,0 +1 @@ + Subsystem sftp internal-sftp \ No newline at end of file diff --git a/src/rootfs/etc/ssh/sshd_config.d/03-container-key-access.conf.tmpl b/src/rootfs/etc/ssh/sshd_config.d/03-container-key-access.conf.tmpl new file mode 100644 index 0000000..7c2cf0d --- /dev/null +++ b/src/rootfs/etc/ssh/sshd_config.d/03-container-key-access.conf.tmpl @@ -0,0 +1,2 @@ + PubkeyAuthentication yes + PermitRootLogin prohibit-password \ No newline at end of file diff --git a/src/rootfs/opt/bin/boot b/src/rootfs/opt/bin/boot deleted file mode 100755 index 2c7c8b8..0000000 --- a/src/rootfs/opt/bin/boot +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -source /opt/core_run.env -source $LIB_DIR/nextcloud.lib -export BOOT=true - -ps -ea - -exec nextcloud supstart -n - -# get this to be process zero -# /usr/bin/python3 /usr/bin/supervisord -c /opt/supervisor/supervisord.conf -n - - -# # catch shutdown signals -# trap nextcloud shutdown SIGTERM SIGHUP SIGQUIT SIGINT -# # wait $RUNIT -# sleep 5 -# ps -ea - -# echo "killing any other processes (zombie) still running in the container" -# for _pid in $(ps -eo pid | grep -v PID | tr -d ' ' | grep -v '^1$' | head -n -6); do -# timeout 5 /bin/sh -c "kill $_pid && wait $_pid || kill -9 $_pid" -# done - -# https://docs.docker.com/config/containers/multi-service_container/ -# https://github.com/phusion/baseimage-docker -# https://computingforgeeks.com/use-tini-init-system-in-docker-containers/#google_vignette \ No newline at end of file diff --git a/src/rootfs/opt/bin/nextcloud b/src/rootfs/opt/bin/nextcloud index 1b762db..3f199f8 100755 --- a/src/rootfs/opt/bin/nextcloud +++ b/src/rootfs/opt/bin/nextcloud @@ -3,21 +3,47 @@ source $LIB_DIR/nextcloud.lib nextcloud () { - -if ! { [[ $(installed) ]] || [[ $NEXTCLOUD_DEV ]] || [[ $NEXTCLOUD_INSTALLING ]]; }; then - if ! { [[ $1 == "install" ]] || [[ $1 == "supstart" ]] || [[ $1 == "start" ]] || [[ $1 == "installed" ]]; }; then - echo "nextcloud not installed, only valid nextcloud subcommands are 'supstart', 'start', 'installed' or 'install '" - echo exiting now from passed subcommand: $1 - return 1 - fi -fi - +local cmd cmd=$1 + +if [[ $cmd == "install" ]]; then + shift + if [[ $(installed) ]] && [[ ! $1 == "--force" ]]; then + echo nextcloud is already installed + echo use \'nextcloud upgrade\' + else + echo installing nextcloud ...... + export NEXTCLOUD_INSTALLING=true + source $LIB_DIR/install.lib + if nextcloud_install "$@"; then + echo nextcloud succesfull installed, nextcloud commands now available + else + [[ $? == 2 ]] && echo nextcloud not fully installed + fi + unset NEXTCLOUD_INSTALLING + fi + echo returning from install + return +fi + +# env > /opt/netcloud/logs/temp.log + +if ! installed; then + if ! [[ $cmd == "idle" || $cmd == "shell" ]]; then + if [[ ! $NEXTCLOUD_INSTALLING ]] && [[ ! $NEXTCLOUD_DEV ]]; then + echo "nextcloud not installed, Only shell, idle and install commands are available" + echo start a container with 'nextcloud idle' + echo then enter container via a shell and + echo "run 'nextcloud install' from a container terminal" + return 1 + fi + fi +fi + + case "$cmd" in idle) ;& shell) ;& - install) ;& - installed) ;& caddy) ;& db) ;& redis) ;& @@ -26,21 +52,46 @@ case "$cmd" in reinstall) ;& redis) ;& start) ;& + state) ;& + repair) ;& + restart) ;& run) ;& suprld) ;& supctl) ;& supstart) ;& supstop) ;& - config_update) ;& app) ;& + history) ;& config) ;& occ) ;& - func);& - version);& - config) + func) ;& + version) ;& + config) ;& + update) ;& + cron) ;& + ssh) ;& + log) shift 1 $cmd "$@" ;; + boot) + if [ -t 1 ] ; then + echo can not run boot command from terminal, only at container startup + else + if nextcloud supctl pid &>> $NEXTCLOUD_LOGS_DIR/boot.log ; then + echo supervisor already running ignoring boot command >> $NEXTCLOUD_LOGS_DIR/boot.log + return 1 + fi + echo nextcloud boot requested $(date) > $NEXTCLOUD_LOGS_DIR/boot.log + nextcloud ssh boot &>> $NEXTCLOUD_LOGS_DIR/boot.log & + { sleep 10; echo pid: $$; ps -ea; nextcloud state; } &>> $NEXTCLOUD_LOGS_DIR/boot.log & + echo nextcloud booted > /tmp/ncbooted + BOOT=true exec /usr/bin/supervisord -n --loglevel warn -c $SUPERVISOR_CONF &>> $NEXTCLOUD_LOGS_DIR/boot.log + fi + ;; + booted) + if [[ -f /tmp/ncbooted ]]; then echo nextcloud was booted; return 0; else return 1; fi + ;; *) occ "$@" ;; diff --git a/src/rootfs/opt/caddy/conf/.Caddyfile b/src/rootfs/opt/caddy/conf/.Caddyfile index 2f44378..c2ab514 100644 --- a/src/rootfs/opt/caddy/conf/.Caddyfile +++ b/src/rootfs/opt/caddy/conf/.Caddyfile @@ -1,28 +1,49 @@ -:8080 { - redir /.well-known/webfinger /index.php/.well-known/webfinger 301 +# https://caddy.community/t/caddy-v2-configuration-nextcloud-docker-php-fpm-with-rules-from-htaccess/20662 +http://{$NEXTCLOUD_DOMAIN}:8080 { + # redir /.well-known/webfinger /index.php/.well-known/webfinger 301 redir /.well-known/carddav /remote.php/dav 301 redir /.well-known/caldav /remote.php/dav 301 + redir /.well-known/* /index.php{uri} 301 # Nextcloud front-controller handles routes to /.well-known + redir /remote/* /remote.php{uri} 301 header { - # enable HSTS - Strict-Transport-Security max-age=31536000; + Strict-Transport-Security "max-age=31536000; includeSubDomains" + Permissions-Policy interest-cohort=() + X-Content-Type-Options nosniff + X-Frame-Options SAMEORIGIN + Referrer-Policy no-referrer + X-XSS-Protection "1; mode=block" + X-Permitted-Cross-Domain-Policies none + X-Robots-Tag "noindex, nofollow" + -X-Powered-By } - # .htaccess / data / config / ... shouldn't be accessible from outside + # From .htaccess, deny access to sensible files and directories @forbidden { - path /.htaccess - path /data/* - path /config/* - path /db_structure - path /.xml - path /README - path /3rdparty/* - path /lib/* - path /templates/* - path /occ - path /console.php + path /build/* /tests/* /config/* /lib/* /3rdparty/* /templates/* /data/* + path /.* /autotest* /occ* /issue* /indie* /db_* /console* + not path /.well-known/* } - respond @forbidden 404 + error @forbidden 404 + + # From .htaccess, set cache for versioned static files (cache-busting) + @immutable { + path *.css *.js *.mjs *.svg *.gif *.png *.jpg *.ico *.wasm *.tflite + query v=* + } + header @immutable Cache-Control "max-age=15778463, immutable" + + # From .htaccess, set cache for normal static files + @static { + path *.css *.js *.mjs *.svg *.gif *.png *.jpg *.ico *.wasm *.tflite + not query v=* + } + header @static Cache-Control "max-age=15778463" + + # From .htaccess, cache fonts for 1 week + @woff2 path *.woff2 + header @woff2 Cache-Control "max-age=604800" + @collabora { path /browser/* # Browser is the client part of LibreOffice Online @@ -50,3 +71,16 @@ } file_server } + + +:8081 { + log { + output file {$NEXTCLOUD_LOGS_DIR}/phpmyadmin-caddy.log + } + + root * /usr/share/webapps/phpmyadmin + php_fastcgi unix//run/nextcloud/fastcgi.sock { + root /usr/share/webapps/phpmyadmin + } + file_server +} \ No newline at end of file diff --git a/src/rootfs/opt/lib/cmds.lib b/src/rootfs/opt/lib/cmds.lib index 2d7b170..e9b7046 100644 --- a/src/rootfs/opt/lib/cmds.lib +++ b/src/rootfs/opt/lib/cmds.lib @@ -1,98 +1,98 @@ #!/bin/bash shell () { -/bin/bash -c "cd ${DEFAULT_DIR:-/}; exec bash -l" + /bin/bash -c "cd ${DEFAULT_DIR:-/}; exec bash -l" } func () { -local func=$1 -shift 1 -$func $@ -} - -run() { - if [ "$(id -u)" = 0 ]; then - sudo -u "${NEXTCLOUD_USER:-nextcloud}" bash -c "source /opt/core_run.env; $*" - fi -} - - -idle () { -sleep infinity -} - -config_update() { - echo config.php update - backup=$NEXTCLOUD_CONFIG_DIR/config.$(date +%F-%H-%M-%S).php - echo making copy of config.php to $backup - /bin/cp $NEXTCLOUD_CONFIG_FILE $backup - echo "merging additional configurations into config.php now" - ls -la $NEXTCLOUD_CONFIG_DIR/*.config.php - [[ $NEXTCLOUD_DEV ]] && mv -f $NEXTCLOUD_CONFIG_DIR/config.org.php $NEXTCLOUD_CONFIG_FILE && echo dev mode original config.php used - # echo current settings - # if [[ $1 ]]; then grep -A6 $1 $NEXTCLOUD_CONFIG_FILE; else cat $NEXTCLOUD_CONFIG_FILE; fi - nextcloud occ config:system:delete configs_merged &>/dev/null - nextcloud occ config:system:set --value true update_config &>/dev/null - nextcloud occ config:system:delete update_config &>/dev/null - if nextcloud occ config:system:get configs_merged &>/dev/null; then - echo configuration files merged successfully - echo "***************************" - if [[ $1 ]]; then grep -A6 $1 $NEXTCLOUD_CONFIG_FILE; else cat $NEXTCLOUD_CONFIG_FILE; fi - echo "***************************" + local lib + [[ $1 == "-l" ]] && lib="source $LIB_DIR/$2.lib" && shift 2 + local func=$1 + shift 1 + $lib + if declare -F "$func" > /dev/null; then + $func $@ else - echo failed to merge configuration files + no function $func return 1 fi } +# execute whatever is passed at the nextcloud linux user +run() { + if [ "$(id -u)" = 0 ]; then + sudo -u "${NEXTCLOUD_USER:-nextcloud}" bash -c "source /opt/core_run.env; $*" + fi +} + + +idle () { + sleep infinity +} + start () { - if nextcloud installed; then - if nextcloud supstart; then - if nextcloud db start; then - sleep 5 - if nextcloud db online nextcloud; then - nextcloud supctl start caddy - nextcloud redis start - nextcloud supctl start php-fpm - sleep 5 - if nextcloud supctl status mysql caddy redis php-fpm; then - nextcloud config_update - echo nextcloud services are all online - ps -ea - echo "------------------------" - echo Success! Nextcloud is online - [[ $NEXTCLOUD_DOMAIN ]] && echo at $NEXTCLOUD_DOMAIN - echo "------------------------" - else - echo FATAL! unable to bring nextcloud online - nextcloud stop - fi - else - echo unable to access the nextcloud database: ${MYSQL_DATABASE:-nextcloud} - echo FATAL! can not start nextcloud - nextcloud db stop - return 1 - fi - else - echo unable to start mysql server - echo FATAL! can not start nextcloud + + if nextcloud supstart > /dev/null; then + + if [[ $1 ]]; then + if [[ $1 == "status" ]]; then nextcloud state; return; fi + + if nextcloud supctl start nextcloud:$1 > /dev/null; then + sleep 3 + if ! nextcloud state $1 > /dev/null; then return 1; fi + return + else + echo unable to start process $1 return 1 - fi - else - echo "unable to start supervisor, can't start nextcloud" + fi fi - else - if [[ ! $NEXTCLOUD_DEV ]]; then - echo unable to start nextcloud because it is not installed - echo installing now... - nextcloud install + + if nextcloud state &> /dev/null; then + echo nextcloud already started and available at $NEXTCLOUD_DOMAIN + return 0 fi + + nextcloud supctl start nextcloud: + sleep 5 + if ! nextcloud state >/dev/null ; then nextcloud state; echo FATAL: could not bring nextcloud online; nextcloud stop; return 1; fi + if ! nextcloud db > /dev/null; then echo WARNING: could not reach database $NEXTCLOUD_DB; fi + # if ! nextcloud config update; then nextcloud stop; return 1; fi + echo nextcloud should be online at $NEXTCLOUD_DOMAIN + else + echo "unable to start supervisor, so can't start nextcloud" fi } +stop () { + if nextcloud state >/dev/null; then nextcloud supctl stop nextcloud:"$*"; fi +} + +restart () { + if nextcloud stop "$@"; then + sleep 4 + nextcloud start "$@" + fi +} + +state () { + if [[ $1 ]]; then + nextcloud supctl status nextcloud:$1 + return $? + fi + if nextcloud supctl status nextcloud: ; then + echo all nextcloud processes active + echo nextcloud should be available at $NEXTCLOUD_DOMAIN + return 0 + else + echo "!!!!!!!!!!!!!!!!!!!!!!!!!!" + echo WARNING: one are more required processes are dead! + return 1 + fi +} + supctl () { - /usr/bin/supervisorctl -c $SUPERVISOR_CONF "$@" + /usr/bin/supervisorctl -c $SUPERVISOR_CONF "$@" } suprld () { @@ -100,110 +100,96 @@ suprld () { } supstart () { - if ! supctl pid > /dev/null ; then - echo supervisord was not running, starting now - [[ $1 == -n ]] && echo running in foreground || echo running as daemon - BOOT=${BOOT:-false} /usr/bin/supervisord -c $SUPERVISOR_CONF $@ + if supctl pid > /dev/null ; then + echo supervisor already running else - echo supervisor already running - fi + BOOT=false AUTORESTART=false /usr/bin/supervisord --loglevel warn -c $SUPERVISOR_CONF $@ + sleep 4 + if ! supctl pid > /dev/null ; then echo WARNING: supervisord did start; return 1; fi + fi } supstop () { if supctl pid > /dev/null ; then echo killing supervisord at $(cat $SUPERVISOR_HOME/supervisor.pid) kill -s SIGTERM $(cat $SUPERVISOR_HOME/supervisor.pid) - sleep 2 - ps -ea + sleep 4 + if supctl pid > /dev/null ; then echo WARNING: supervisord did not stop; return 1; fi else echo supervisord was not running so not stopping fi } -stop () { - nextcloud supctl stop "${@:-all}" -} - occ () { local _occ=$NEXTCLOUD_SRC_DIR/occ [[ ! -f $_occ ]] && echo "FATAL! no occ command found in $NEXTCLOUD_SRC_DIR" && return 1 - sudo -u nextcloud -E php $_occ "$@" -} - -config () { -nextcloud occ config:list --private | grep -A5 -B5 $1 -} - -install () { - -if [[ ! -f $NEXTCLOUD_SRC_DIR/installed || $NEXTCLOUD_DEV ]]; then - if nextcloud supstart > /dev/null; then - echo installing nextcloud with args: $@ - . $LIB_DIR/install/install.sh "$@" - else - echo unable to run supervisord, thus unable to install nextcloud - fi -else - echo nextcloud already installed -fi - + sudo -u $NEXTCLOUD_USER -E php $_occ "$@" } upgrade () { - if [[ -f $NEXTCLOUD_SRC_DIR/installed ]]; then - local cur=$(version) - local src=$(version source) - echo checking for upgrade from $cur to $src - if upgradable $src $cur; then - echo upgradable, beginning upgrade process - else - echo not upgradable - if [[ "$cur" == "$src" ]]; then - echo same versions nothing to upgrade - echo to upgrade pull/build an updated docker image - fi - fi - else - echo "nextcloud not installed, can not upgrade" + if nextcloud booted; then echo can not do an upgrade on booted container, stop container and start with idle; return 1; fi + if ! nextcloud state > /dev/null; then + echo to upgrade nextcloud must be online, starting now + if ! nextcloud start; then echo could not bring nextcloud online so can not upgrade; return 1; fi + fi + . $LIB_DIR/upgrade.lib "$@" + NEXTCLOUD_UPGRADING=true + if ! upgrade_prepare; then echo upgrade prepare failed, aborting upgrade; return 1; fi + if upgrade_run; then + echo upgrade success + echo now running $(version) + else + echo TODO: run 'nextcloud upgrade rollback' fi - + unset NEXTCLOUD_UPGRADING } - -reinstall () { - - if [[ $(installed) ]]; then - if [[ $1 == 'yes' ]]; then - echo nextcloud install force - else - echo reinstall requested. - echo because reinstall will potentially trash your current install - echo "you need to make sure you have backups of the app (source), the database, and user-files" - echo " and then issue the command 'nextcloud reinstall yes" +# todo guard with YES +# enable rollback +repair () { + # TODO mm + if nextcloud db backup $1; then + if nextcloud db migration >/dev/null; then + if occ maintenance:repair --include-expensive &>/dev/null; then + echo repair successfull + else + echo db maintenance repair failed + return 2 + fi + else + echo db migration failed, aborting repar + return 2 fi - else - echo nextcloud not installed so reinstall will now do install - install -fi + else + echo unable to backup database so will not run repair + fi } app () { -case "$1" in - remove) ;& - uninstall) - shift 1 - acmd=remove - ;; - install) - shift 1 - ;& - *) - acmd=install - ;; + case "$1" in + remove) ;& + uninstall) + shift 1 + acmd=remove + ;; + disable) + shift 1 + acmd=disable + ;; + enable) + shift 1 + acmd=enable + ;; + install) + shift 1 + ;& + *) + acmd=install + ;; -esac + esac if [[ $1 == "-c" ]]; then shift 1 @@ -236,4 +222,168 @@ esac fi } +# TODO use jq/yq to parse logs +log () { + local sub=$1 + case $sub in + clear) + if [[ $2 == "all" ]]; then + truncate -s 0 $NEXTCLOUD_LOGS_DIR/*.log + else + truncate -s 0 $NEXTCLOUD_LOGS_DIR/nextcloud.log + fi + ;; + *) + if [[ $1 ]]; then + cat $NEXTCLOUD_LOGS_DIR/nextcloud.log | yq -p=json | grep $1 + else + cat $NEXTCLOUD_LOGS_DIR/nextcloud.log | yq -p=json + fi + ;; + esac +} + +config () { + local sub=$1 + shift 1 + if ! nextcloud start > /dev/null; then echo for config nextcloud must be started; fi + case $sub in + list) + if [[ $1 ]]; then + nextcloud config:list --private system | grep $1 + else + nextcloud config:list --private system + fi + ;; + raw) + if [[ $1 ]]; then + cat $NEXTCLOUD_CONFIG_FILE | grep $1 + else + cat $NEXTCLOUD_CONFIG_FILE + fi + ;; + get) + if ! nextcloud config:system:get $1; then + return 1 + fi + ;; + del) + nextcloud config:system:delete $1 + ;; + array) + shift 1 + config_add_array "$@" + echo $(nextcloud occ config:system:get $1) + ;; + set) + if ! nextcloud occ config:system:set "$1" --type=${3:-string} --value="$2" ; then + return 1 + fi + ;; + backup) + backup=$NEXTCLOUD_CONFIG_DIR/config.$(version)-$(date '+%Y%m%d%H%M%S').php + echo making copy of config.php to $backup + /bin/cp $NEXTCLOUD_CONFIG_FILE $backup + ;; + update) + echo updating $NEXTCLOUD_CONFIG_FILE by merging these files + (cd $NEXTCLOUD_CONFIG_DIR && ls *.config.php) + nextcloud config backup + nextcloud occ config:system:delete configs_merged &>/dev/null + nextcloud occ config:system:set --value true update_config &>/dev/null + nextcloud occ config:system:delete update_config &>/dev/null + if nextcloud occ config:system:get configs_merged &>/dev/null; then + echo configuration files merged successfully + else + echo failed to merge configuration files + return 1 + fi + ;; + *) + sub=$1 + nextcloud occ config:$sub "$@" + ;; + esac +} + +cron () { + echo running cron.php + sudo -u nextcloud php -f $NEXTCLOUD_SRC_DIR/cron.php & +} + +## guard with confirm +update () { + # TODO mmode + if nextcloud booted; then echo can not do an update on booted container, stop container and start with idle; return 1; fi + nextcloud func mmode on + echo updating any changes to the containers base nextcloud directory + echo first stopping nextcloud + if ! nextcloud stop > /dev/null; then echo ERROR: could not take nextcloud offline; return 1; fi + echo syncing /opt/nextcloud-container to $NEXTCLOUD_HOME + chown -R $NEXTCLOUD_USER:$NEXTCLOUD_USER /opt/nextcloud-container/ + rsync -a /opt/nextcloud-container/ $NEXTCLOUD_HOME + echo updating database server configuration + nextcloud db config update + echo updating redis server configuration + nextcloud redis update + sleep 3 + echo starting nextcloud + if ! nextcloud restart ; then nextcloud state; echo ERROR: could not bring nextcloud online; return 1; fi + echo "--------------------" + if ! nextcloud config update; then echo WARNING: issue updating the config.php; fi + echo "done with nextcloud update" + nextcloud func mmode off +} + +history () { + local sub=$1 + local id + shift 1 + id=${1:-$(date '+%Y%m%d%H%M%S')} + case $sub in + upgrade) + if [[ $NEXTCLOUD_UPGRADING ]]; then + cat << EOF >> $NEXTCLOUD_HOME/version-history + - id: $id + date: $(date) + type: upgrade + version: $(version) + previous-version: $(cat $NEXTCLOUD_HOME/previous-version) + $(while read; do echo " $REPLY"; done $NEXTCLOUD_HOME/version-history + history: + - id: $id + date: $(date) + type: install + version: $(version) + database: + name: ${NEXTCLOUD_DB:-nextcloud} + server: ${DB_TYPE:-mysql} + user: ${NEXTCLOUD_DB_USER:-nextcloud} + password: ${NEXTCLOUD_DB_PASSWORD:-nextcloud} + admin: ${NEXTCLOUD_ADMIN_USER:-admin} + $(while read; do echo " $REPLY"; done # Example 1 +# > # The preferred way to use confirm +# > confirm Delete file1? && echo rm file1 +# > or +# > [[ confirm Delete file1 ]]; then +# > rm file1 +# > fi +# > +# > # Example 2 +# > # Use the $? variable to examine confirm's return value +# > confirm Delete file2? +# > if [ $? -eq 0 ] +# > then +# > echo Another file deleted +# > fi +# > +# > # Example 3 +# > # Tell bash to exit right away if any command returns a non-zero code +# > set -o errexit +# > confirm Do you want to run the rest of the script? +# > echo Here is the rest of the script +# +# ====================================================================== + +function confirm() +{ + local res="y Y yes YES Yes Sure sure SURE OK ok Ok" + local strong="yes YES Yes" + [[ $1 = "-s" ]] && { res=$strong; strong=true shift; } || strong="" + echo -n "$@" "$([[ $strong ]] && echo \< $res \>) ? " + read -e answer + for response in $res + do + if [ "_$answer" == "_$response" ] + then + return 0 + fi + done + + # Any answer other than the list above is considered a "no" answer + return 1 +} diff --git a/src/rootfs/opt/lib/db.lib b/src/rootfs/opt/lib/db.lib index 585c5b9..26629a3 100644 --- a/src/rootfs/opt/lib/db.lib +++ b/src/rootfs/opt/lib/db.lib @@ -1,123 +1,133 @@ #!/bin/bash - +source "$LIB_DIR/${DB_TYPE:-mysql}.lib" db () { case "$1" in - init) - source $LIB_DIR/install/mysql.lib - echo "Intialzing MySQL server" - if mysql_init; then - echo mysql server successfully intialized - else - echo FATAL: mysql initialization failed - return 1 - fi + version) + nextcloud db cmd "SHOW VARIABLES LIKE 'version';" | tail -n1 | cut -f2 | cut -f1 -d- + ;; + config) + shift + case "$1" in + section) + sed -nr "/^\["$2"\]/ { :l /^\s*[^#].*/ p; n; /^\[/ q; b l; }" $DB_CONF + ;; + edit) + cp $DB_HOME/${DB_TYPE:-mysql}.conf.tmpl $DB_HOME/${DB_TYPE:-mysql}.conf.tmpl.sav + nano $DB_HOME/${DB_TYPE:-mysql}.conf.tmpl + echo run \'nextcloud db config update\' + echo backup copy saved to ${DB_TYPE:-mysql}.conf.tmpl.sav + ;; + update) + nextcloud func process_template $DB_CONF + ;; + *) + [[ ! -f $DB_CONF ]] && db update + [[ $1 ]] && cat $DB_CONF | grep $1 || cat $DB_CONF; + esac + ;; + repair) + nextcloud repair $2 + ;; + migration) + nextcloud db:add-missing-columns + nextcloud db:add-missing-indices + nextcloud db:add-missing-primary-keys + ;; + backup) + local target + shift + id=${1:-$(date '+%Y%m%d%H%M%S')} + target=$NEXTCLOUD_HOME/db-$(version)-$id + echo stopping database + if ! nextcloud db stop > /dev/null; then echo unable to shut down db server before backup, aborting; return 1; fi + echo backing up $DB_HOME to $target + sleep 3 + if ! rsync -a --info=progress2 $DB_HOME/ $target; then + echo ERROR rsync error, copying failed + rm -rf $target + return 2 + fi + if [[ ! -d $target/$NEXTCLOUD_DB ]]; then + echo ERROR database backup to $target was not succesful! + rm -rf $target + return 2 + fi + echo created backup: "$target" + if ! nextcloud db start; then echo WARNING: mysql server not back online after backup; return 1; fi + sleep 3 + if ! nextcloud db; then echo WARNING: could not access $NEXTCLOUD_DB after backup; fi ;; start) - nextcloud supstart - if nextcloud supctl status mysql 1> /dev/null; then - echo MySQL service already online - else - nextcloud supctl start mysql 1>/dev/null; - sleep 4 - if nextcloud supctl status mysql 1>/dev/null; then - echo mysql service online - else - echo ERROR: unable to start mysql service - return 1 - fi - fi + nextcloud start db ;; restart) - nextcloud supctl restart mysql + nextcloud stop db + nextcloud start db + ;; + upgrade ) + cver=$(yq '.history | map(select(.type == "install")) | .[] | .container.mysql' < $NEXTCLOUD_HOME/version-history) + ver=$(nextcloud db version) + ver=10.10.8 + echo -e "$cver\n$ver" | sort -V + if [[ "$cver" == "$(echo -e "$cver\n$ver" | sort -V | head -n1)" ]]; then + echo $ver and $cver are the same, nothing to upgrade + else + echo the installed version $ver is older than the container version $cver + echo doing database upgrade + if ! nextcloud db backup $ver; then echo could not backup database so will not upgrade; return 1; fi + mysql_upgrade $DB_SERVER_OPTS --force -u root + fi ;; stop) - if nextcloud supctl status mysql; then - nextcloud supctl stop mysql; - else - echo msyql server was not running, nothing to stop - return 0 - fi + echo stopping db server + nextcloud stop db + sleep 3 + if nextcloud state db > /dev/null; then return 1; fi ;; - mkncdb) - source $LIB_DIR/install/mysql.lib - mysql_create_nextcloud_db - ;; - online) - shift 1 - case "$1" in - core) - ;& - nextcloud) - if [[ $1 == "core" ]]; then - dcmd="$DB_CLIENT_BIN $DB_SERVER_OPTS -uroot mysql" - else - dcmd="nextcloud run $DB_CLIENT_BIN $DB_SERVER_OPTS $MYSQL_DATABASE" - fi - echo checking status of database $MYSQL_DATABASE - if nextcloud db online 1> /dev/null ; then - # echo DEBUG: command to run $dcmd - if timeout 10s bash -c "source /opt/bin/nextcloud; _db_online $dcmd" ; then - echo database $1 is online - return 0 - else - echo database $1 is offline - return 1 - fi - else - echo database server is not online so can not check status of database $1 - fi - ;; - *) - echo checking to see if db server is online - if nextcloud supctl status mysql >/dev/null ; then - echo mysql server daemon is running - return 0 - else - echo mysql server daemon is offline - sleep 1 - return 1 - fi - - esac - - ;; - root) - if db online mysql; then - shift 1 - # -e \"$*\" - cmd="$DB_CLIENT_BIN $DB_SERVER_OPTS -uroot mysql" - if [[ $* ]]; then - echo $* - query="$*" - echo $query - $cmd <<< $query - else - $cmd - fi - else - echo mysql server is offline or no root mysql database has been created - fi + cmd) + shift + [[ $1 == "root" ]] && set -- "-r" "${@:2}" + db_cli "$@" + ;; + remote) + echo when functional this will + echo set up a remote user + echo with access to the database + # if [[ $DB_REMOTE_PASSWORD ]]; then + # echo creating remote user for remote access ${DB_REMOTE_PASSWORD} + # $DB_CLIENT_BIN -uroot << EOF + # CREATE USER '${DB_REMOTE_USER:-remote}'@'localhost' IDENTIFIED BY '$DB_ROOT_PASSWORD'; + # GRANT ALL PRIVILEGES on *.* to 'remote'@'localhost'; + # FLUSH privileges; + # EOF ;; *) - cmd="nextcloud run $DB_CLIENT_BIN $DB_SERVER_OPTS $MYSQL_DATABASE" - echo $cmd - [[ $* ]] && $cmd <<< "$*" || $cmd + if nextcloud db cmd "select 1" &>/dev/null; then + echo nextcloud database online + else + echo nextcloud database offline + return 1 + fi esac } -_db_online () { - # echo $@ - if $@ <<< "select 1" >/dev/null 2>&1 ; then - return 0 - else - sleep 1 - # echo trying to connect to database - _db_online $@ - return 1 - fi -} + + + +# _db_online () { +# # echo $@ +# if $@ <<< "select 1" >/dev/null 2>&1 ; then +# return 0 +# else +# sleep 1 +# # echo trying to connect to database +# _db_online $@ +# return 1 +# fi +# } + diff --git a/src/rootfs/opt/lib/helpers.lib b/src/rootfs/opt/lib/helpers.lib index 46d22e8..3b474e9 100644 --- a/src/rootfs/opt/lib/helpers.lib +++ b/src/rootfs/opt/lib/helpers.lib @@ -6,66 +6,44 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -# usage: file_env VAR [DEFAULT] -# ie: file_env 'XYZ_DB_PASSWORD' 'example' -# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of -# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) -# file_env() { -# local var="$1" -# local fileVar="${var}_FILE" -# local def="${2:-}" -# local varValue=$(env | grep -E "^${var}=" | sed -E -e "s/^${var}=//") -# local fileVarValue=$(env | grep -E "^${fileVar}=" | sed -E -e "s/^${fileVar}=//") -# if [ -n "${varValue}" ] && [ -n "${fileVarValue}" ]; then -# echo >&2 "error: both $var and $fileVar are set (but are exclusive)" -# exit 1 -# fi -# if [ -n "${varValue}" ]; then -# export "$var"="${varValue}" -# elif [ -n "${fileVarValue}" ]; then -# export "$var"="$(cat "${fileVarValue}")" -# elif [ -n "${def}" ]; then -# export "$var"="$def" -# fi -# unset "$fileVar" -# } +installed () { + # TODO return version from version history + [[ -f $NEXTCLOUD_HOME/version-history ]] || return 1 +} + +version_directories () { + +/usr/bin/find "$NEXTCLOUD_RELEASES_DIR" -type d -maxdepth 1 -mindepth 1 -exec basename {} \; \ +| cut -f1 -d'/' \ +| sort -Vr \ +| if [[ $1 == "latest" ]]; then head -n 1; shift; else cat; fi \ +| if [[ $1 && ! $1 == "latest" ]]; then grep -w ^$1; else cat; fi + +} version () { local ver - if [[ $1 == "image" ]]; then - ver=$(php -d display_errors="0" -r 'require "'$NEXTCLOUD_INSTALL_FROM_DIR'/version.php"; echo implode(".",$OC_Version);' 2>/dev/null) - if [[ ! $ver ]]; then - echo "SUPER FATAL ERROR NO NEXTCLOUD ALPINE IMAGE SOURCE FOUND AT $NEXTCLOUD_INSTALL_FROM_DIR" - return 1 - else - echo $ver + local key='$OC_VersionString' + local dir=$NEXTCLOUD_SRC_DIR + [[ $1 == "-f" ]] && key='implode(".",$OC_Version)' && shift + if [[ $1 == "release" ]]; then + if [[ $2 ]]; then + dir=$NEXTCLOUD_RELEASES_DIR/$2 + shift + else + dir=$NEXTCLOUD_RELEASES_DIR/$(version_directories latest) fi - else - ver=$(php -d display_errors="0" -r 'require "'$NEXTCLOUD_SRC_DIR'/version.php"; echo implode(".",$OC_Version);' 2>/dev/null) - if [[ ! $ver ]]; then - unset NEXTCLOUD_INSTALLED + shift + fi + [[ $1 ]] && dir=$1 + ver=$(php -d display_errors="0" -r 'require "'$dir'/version.php"; echo '$key';' 2>/dev/null) + if [[ ! $ver ]]; then return 1 - else + else echo $ver - fi fi } -installed () { - if [[ -f $NEXTCLOUD_HOME/installed ]]; then - echo $(cat $NEXTCLOUD_HOME/installed) - return 0 - else - # echo "WARNING: nextcloud not installed, run 'nextcloud install'" - return 1 - fi -} - -upgradable () { - # printf '%s\n' $1 $2 | sort -t '.' -n -k1,1 -k2,2 -k3,3 -k4,4 - # | head -n 1 - [ "$(printf '%s\n' $1 $2 | sort -t '.' -n -k1,1 -k2,2 -k3,3 -k4,4 | head -n 1)" != "$1" ] -} process_template () { @@ -77,8 +55,6 @@ fi } -# TODO PHP - list_php_settings () { cat $PHP_INI_DIR/$1 | grep -v '^;' | grep -v '^$' } @@ -89,6 +65,8 @@ php -m } edit_phpfpm_config () { + echo warning: editing these settings will not survive a container restart + echo and should only be done in troubleshooting nano /etc/php$PHP_VERSION/php-fpm.d/nextcloud.conf } @@ -105,7 +83,6 @@ config_array() { done } - config_add_array() { local idx=0 local item @@ -119,45 +96,28 @@ config_add_array() { done } -config () { -local sub=$1 -shift 1 -case $sub in - list) - nextcloud config:list --private system - ;; - get) - if ! nextcloud config:system:get $1; then - return 1 - fi - ;; - del) - nextcloud config:system:delete $1 - ;; - array) - shift 1 - config_add_array "$@" - echo $(nextcloud occ config:system:get $1) - ;; - set) - if ! nextcloud occ config:system:set $1 --value=$2 ; then - return 1 - fi - ;; - *) - sub=$1 - nextcloud occ config:$sub "$@" - ;; -esac +# maintenance mode +mmode () { + local state + local op + state=$([[ $(nextcloud status | grep maintenance | cut -f2 -d: | xargs echo -n) == "true" ]] && echo on || echo off) + if [[ $1 == "enabled" ]]; then + [[ $state == "off" ]] && return 1 + return 0 + fi + if [[ $1 ]]; then + [[ $1 == "on" ]] && op="--on" + [[ $1 == "off" ]] && op="--off" + else + echo toggling current state $state + [[ $state == "on" ]] && op="--off" || op="--on" + fi + if [[ $op == --$state ]]; then + echo maintenance mode already $state + else + echo changing $(nextcloud maintenance:mode $op) + state=$([[ $(nextcloud status | grep maintenance | cut -f2 -d: | xargs echo -n) == "true" ]] && echo on || echo off) + echo maintenance mode now $state + fi } -docker_latest_image() { - image=$1 - major=${2:-1} - tokenUri="https://auth.docker.io/token" - data=("service=registry.docker.io" "scope=repository:$image:pull") - token="$(curl --silent --get --data-urlencode ${data[0]} --data-urlencode ${data[1]} $tokenUri | jq --raw-output '.token')" - listUri="https://registry-1.docker.io/v2/$image/tags/list" - curl --silent --get -H "Accept: application/json" -H "Authorization: Bearer $token" $listUri \ - | jq --raw-output ".tags[] | select(. | startswith(\"$major.\"))" | sort -V | sed -n \$p - } diff --git a/src/rootfs/opt/lib/install/install.exclude b/src/rootfs/opt/lib/install.exclude similarity index 80% rename from src/rootfs/opt/lib/install/install.exclude rename to src/rootfs/opt/lib/install.exclude index a3e5e9f..3ca4a83 100644 --- a/src/rootfs/opt/lib/install/install.exclude +++ b/src/rootfs/opt/lib/install.exclude @@ -2,3 +2,4 @@ /apps/ /themes/ /apps-appstore/ +/updater/ diff --git a/src/rootfs/opt/lib/install.lib b/src/rootfs/opt/lib/install.lib new file mode 100644 index 0000000..ef6f4e1 --- /dev/null +++ b/src/rootfs/opt/lib/install.lib @@ -0,0 +1,318 @@ +#!/bin/bash + +source $LIB_DIR/release.lib +source $LIB_DIR/confirm.func +source $BIN_DIR/nextcloud + +declare -A steps=(["0"]="0: no install steps completed" ["1"]="1: download a release" ["2"]="2: create database" ["3"]="3: copy release source" ["4"]="4: initialize nextcloud" ["5"]="5: update config, save install info") + +step () { + local s + local save + # local desc + # [[ $1 = "-n" ]] && desc=true && shift + save="$NEXTCLOUD_HOME/install-step" + [[ ! -f $save ]] && echo "0" > $save + s=$(cat $save) + if [[ $1 == "reset" ]]; then + echo 0 > $save + return + fi + if [[ $1 == "cur" ]]; then + echo ${steps[$(($s + 1))]} + return + fi + if [[ $1 == "get" ]]; then + echo $s + return + fi + if [[ $1 == "set" ]]; then + s=$2 + echo $s > $save + return + fi + if [[ $1 == "done" || $1 == "next" ]]; then + ((s++)) + echo $s > $save + return + fi + if [[ $1 ]]; then + # echo $1, $s + [[ $1 -eq $s ]] || return 1 + else + echo ${steps["$s"]} + fi +} + +install_scrub () { + if [[ $1 == "yes" ]]; then + [[ -f $SUPERVISOR_HOME/supervisor.pid ]] && kill -s SIGTERM $(cat $SUPERVISOR_HOME/supervisor.pid) + sleep 3 + /bin/rm -rf $NEXTCLOUD_HOME/* + /bin/rm -rf $NEXTCLOUD_DATA_DIR/* + rsync -r /opt/nextcloud-container/ $NEXTCLOUD_HOME + step reset + else + echo scrubbing an install is super dangerous, you must use 'install_scrub yes' in order to actually scrub the install + fi +} + +install_release () { + + echo step: ${steps["1"]} + + local rel + + NEXTCLOUD_INSTALL_VERSION=${1:-$NEXTCLOUD_INSTALL_VERSION} + rel=$NEXTCLOUD_INSTALL_VERSION + if [[ $rel ]]; then + [[ ! $rel == *.* ]] && echo latest version of $rel will be installed && rel="latest $rel" + else + rel=latest + echo latest nextcloud release will be installed + fi + + if NEXTCLOUD_INSTALL_VERSION=$(nextcloud_releases $rel); then + if confirm -s nextcloud version $NEXTCLOUD_INSTALL_VERSION will be installed; then + echo $NEXTCLOUD_INSTALL_VERSION > $NEXTCLOUD_HOME/install-version + if version release $NEXTCLOUD_INSTALL_VERSION > /dev/null ; then + echo $NEXTCLOUD_INSTALL_VERSION already downloaded + echo step: ${steps["1"]}, completed + step next + else + echo downloading $NEXTCLOUD_INSTALL_VERSION now + if nextcloud_pull $NEXTCLOUD_INSTALL_VERSION; then + echo step: ${steps["1"]}, completed + step next + else + return 1 + fi + fi + else + return 1 + fi + else + echo unable to determine a vaild install version, aborting install + rm -f $NEXTCLOUD_HOME/install-version + return 1 + fi + + +} + +install_database () { + + echo step: ${steps["2"]} + + # make sure any db server is off + + # rm -rf $DB_HOME/* + # cp -f /opt/nextcloud-container/db/mysql.conf.tmpl $DB_HOME + + + if ! nextcloud db config update; then echo unable to create server config file from template; return 1; fi + if ! nextcloud db stop &> /dev/null; then echo unable to stop database service so can not initialize; return 1; fi + if ! db_init; then + echo ${DB_TYPE:-mysql} server initialization failed + echo scrubbing any created files in $DB_HOME + rm -rf $DB_HOME/* + cp -f /opt/nextcloud-container/db/${DB_TYPE:-mysql}.conf.tmpl $DB_HOME + return 1 + fi + echo ${DB_TYPE:-mysql} server successfully initialized + + if ! nextcloud start db; then echo unable to start database server so can not finish install; return 1; fi + + local cmd + + cmd="CREATE DATABASE IF NOT EXISTS ${NEXTCLOUD_DB:-nextcloud} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" + echo creating nextcloud database: ${NEXTCLOUD_DB:-nextcloud} + # echo $cmd + if ! nextcloud db cmd root "$cmd"; then + echo could not create nextcloud databas ${NEXTCLOUD_DB:-nextcloud} + return 1; + fi + + + cmd="ALTER USER ${NEXTCLOUD_DB_USER:-nextcloud}@localhost IDENTIFIED BY '${NEXTCLOUD_DB_PASSWORD:-nextcloud}'" + # echo $cmd + if ! nextcloud db cmd root "$cmd"; then + echo could not set a password for nextcloud db user: ${NEXTCLOUD_DB_USER:-nextcloud}; + return 1; + fi + + if ! nextcloud db; then return 1; fi + + echo step: ${steps["2"]}, completed + step next + +} + +install_source () { + + echo step: ${steps["3"]} + + local SRC + if ! SRC=$NEXTCLOUD_RELEASES_DIR/$(version release $NEXTCLOUD_INSTALL_VERSION); then + echo no version $NEXTCLOUD_INSTALL_VERSION to install, rerun \'nextcloud install\' + unset NEXTCLOUD_INSTALL + return 1 + fi + + echo copying nextcloud source at $SRC to the install directory $NEXTCLOUD_SRC_DIR + if ! confirm -s continue; then return 3; fi + # rm -rf $NEXTCLOUD_SRC_DIR/* + + if ! rsync -rlD --info=progress2 --chown=$NEXTCLOUD_USER:$NEXTCLOUD_USER --exclude-from=$LIB_DIR/install.exclude $SRC/ $NEXTCLOUD_SRC_DIR/; then + return 1; fi + + echo copying nextcloud apps at $SRC/apps to the apps directory $NEXTCLOUD_APPS_DIR + if ! rsync -rlD --info=progress2 --chown=$NEXTCLOUD_USER:$NEXTCLOUD_USER $SRC/apps/ $NEXTCLOUD_APPS_DIR/; then + return 1; fi + echo copying nextcloud themes at $SRC/themes to themes directory $NEXTCLOUD_THEMES_DIR + if ! rsync -rlD --info=progress2 --chown=$NEXTCLOUD_USER:$NEXTCLOUD_USER $SRC/themes/ $NEXTCLOUD_THEMES_DIR/; then + return 1; fi + + rm -rf $NEXTCLOUD_SRC_DIR/config + ln -sf $NEXTCLOUD_APPS_DIR $NEXTCLOUD_SRC_DIR/apps + ln -sf $NEXTCLOUD_THEMES_DIR $NEXTCLOUD_SRC_DIR/themes + ln -sf $NEXTCLOUD_CONFIG_DIR $NEXTCLOUD_SRC_DIR/config + + if [[ $NEXTCLOUD_INSTALL_VERSION == $(version) ]]; then + echo source copied succesfully + echo step: ${steps["3"]}, completed + step next + else + echo can not confirm copied version $NEXTCLOUD_INSTALL_VERSION:$(version), copy failed + return 2 + fi +} + +install_nextcloud () { + + echo step: ${steps["4"]} + + local options + + if ! nextcloud db start; then echo the nextcloud database: ${NEXTCLOUD_DB:-nextcloud} not online, can not run maintenance:install; return 1; fi + + options="--admin-user ${NEXTCLOUD_ADMIN_USER:-admin} --admin-pass ${NEXTCLOUD_ADMIN_PASSWORD:-admin} --admin-email ${NEXTCLOUD_ADMIN_EMAIL:-xxx@gmail.com} " + options+=" --data-dir ${NEXTCLOUD_DATA_DIR}" + options+=" --database ${DB_TYPE:-mysql} --database-name ${NEXTCLOUD_DB:-nextcloud} --database-user ${NEXTCLOUD_DB_USER:-nextcloud} --database-pass ${NEXTCLOUD_DB_PASSWORD:-nextcloud} --database-host localhost:/run/nextcloud/db.sock" + echo getting ready to start the nextcloud system initialization + echo the maintenance:install options are + echo $options + if ! confirm -s confirm correct options; then echo aborting install; return 1; fi + echo initializing nextcloud via maintence:install...please wait + cmd=" sudo -u $NEXTCLOUD_USER -E $(which php) $NEXTCLOUD_SRC_DIR/occ maintenance:install $options" + if $cmd; then + echo maintenance:install succeeded! nextcloud is installed + echo step: ${steps["4"]}, completed + step next + else + return 1 + fi +} + +install_finish () { + + echo step: ${steps["5"]} + + echo "**** NOTE: default administrator login is user:${NEXTCLOUD_ADMIN_USER:-admin} password: ${NEXTCLOUD_ADMIN_PASSWORD:-admin} ***" + + # make initial copy of config.php + /bin/cp $NEXTCLOUD_CONFIG_FILE $NEXTCLOUD_CONFIG_DIR/config.init.php + + if ! nextcloud redis update; then + echo unable to initialize redis + return 1 + fi + + if ! nextcloud start; then + echo FATAL: unable to bring nextcloud up even though all the install steps completed + echo see readme file for troubleshooting + return 1 + fi + + echo running a repair after install + if ! nextcloud repair >/dev/null; then echo WARN: could not complete a nextcloud repair; return 1; fi + echo + echo any nextcloud issues repaired + + echo this assumes you have a reverse proxy set up to the docker mapped host port you set + echo "otherwise try http://localhost:" + echo see readme file for information on completing the production deployment + + echo saving install history to $NEXTCLOUD_HOME/version-history + echo "--------------------------------------" + nextcloud history install + nextcloud history + echo "--------------------------------------" + echo step: ${steps["5"]}, completed + step next + return 0 + +} + +nextcloud_install () { + +## TODO look at key in version-history +if [[ $1 == "--force" ]]; then + shift + echo Danger, you have requesed a force install + echo absolutely everything will be scrubbed! including all users and their data + echo this is really suitable only in development + if ! confirm -s "continue"; then return 1; fi + install_scrub yes + else + if installed; then + echo nextcloud is already installed + echo use --force if you want to scrub and reinstall + return 1 + fi +fi + +if nextcloud supstart > /dev/null; then + if [[ $(step get) -gt 0 ]]; then + + NEXTCLOUD_INSTALL_VERSION=${NEXTCLOUD_INSTALL_VERSION:-$(cat $NEXTCLOUD_HOME/install-version)} + if [[ $NEXTCLOUD_INSTALL_VERSION ]]; then + echo install was not finished, continuing to install $NEXTCLOUD_INSTALL_VERSION at step $(step cur) + else + echo unable to determine the current version of nextcloud being installed + echo you must use --force to start again + return 1 + fi + fi + + if step 0; then install_release $1; fi + if step 1; then install_database; fi + if step 2; then install_source; fi + if step 3; then install_nextcloud; fi + if step 4; then install_finish; fi + if step 5; then + echo all installation steps completed + echo nextcloud should be online and available $NEXTCLOUD_DOMAIN + unset NEXTCLOUD_INSTALLING + unset NEXTCLOUD_INSTALL_VERSION + rm -f $NEXTCLOUD_HOME/install-version + rm -f $NEXTCLOUD_HOME/install-step + else + echo "*********** INSTALL FAILED ******************" + echo install failed at step $(step cur) + + echo fix any issue and run \'nextcloud install\' again + echo to continue installation at that point + echo + echo or use \'nextcloud install --force\' to scrub and start install from the beginning + echo "**********************************" + nextcloud stop + return 2 + fi + else + echo unable to run supervisord, thus unable to begin the installation + return 1 +fi + + +} \ No newline at end of file diff --git a/src/rootfs/opt/lib/install/install.sh b/src/rootfs/opt/lib/install/install.sh deleted file mode 100644 index d0476fd..0000000 --- a/src/rootfs/opt/lib/install/install.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/bin/bash - -nc_scrub () { - if [[ $1 == "yes" ]]; then - rm -rf $NEXTCLOUD_SRC_DIR/* - rm -rf $NEXTCLOUD_DATA_DIR/* - rm -rf $NEXTCLOUD_THEMES_DIR/* - rm $NEXTCLOUD_CONFIG_FILE - else - echo nc_scrub is super dangerous function, you must use 'nc_scrub yes' in order to actually scrub the install - fi -} - -install_failed () { - unset NEXTCLOUD_INSTALLING - echo doing cleanup from failed install -} - -if [[ -f $NEXTCLOUD_SRC_DIR/version.php || -f $NEXTCLOUD_CONFIG_FILE ]]; then -echo this is not a clean install there are files in $NEXTCLOUD_SRC_DIR -echo or $NEXTCLOUD_CONFIG_FILE exists -echo to avoid possibly overwriting the configuration/install by mistake -echo "this install is aborted, use 'nextcloud update' instead" -[[ ! ( $NEXTCLOUD_DEV || $1 == "force" ) ]] && return 1 || echo dev or force mode, continuing install -fi - -export NEXTCLOUD_INSTALLING=true - -if [[ ! -f $NEXTCLOUD_SRC_DIR/version.php ]]; then -export NEXTCLOUD_APPS_DIR=$NEXTCLOUD_HOME/apps -echo copying nextcloud source at $NEXTCLOUD_INSTALL_FROM_DIR to the instance directory $NEXTCLOUD_SRC_DIR -rsync -rlD --chown=$NEXTCLOUD_USER:$NEXTCLOUD_USER --exclude-from=$LIB_DIR/install/install.exclude $NEXTCLOUD_INSTALL_FROM_DIR/ $NEXTCLOUD_SRC_DIR/ -echo copying nextcloud apps at $NEXTCLOUD_INSTALL_FROM_DIR/apps to the apps directory $NEXTCLOUD_APPS_DIR -rsync -rlD --chown=$NEXTCLOUD_USER:$NEXTCLOUD_USER $NEXTCLOUD_INSTALL_FROM_DIR/apps/ $NEXTCLOUD_APPS_DIR/ -echo copying nextcloud themes at $NEXTCLOUD_INSTALL_FROM_DIR/themes to themes directory $NEXTCLOUD_THEMES_DIR -rsync -rlD --chown=$NEXTCLOUD_USER:$NEXTCLOUD_USER $NEXTCLOUD_INSTALL_FROM_DIR/themes/ $NEXTCLOUD_THEMES_DIR/ - -rm $NEXTCLOUD_SRC_DIR/apps-appstore -rm $NEXTCLOUD_SRC_DIR/config - -ln -s $NEXTCLOUD_APPS_DIR $NEXTCLOUD_SRC_DIR/apps -ln -s $NEXTCLOUD_THEMES_DIR $NEXTCLOUD_SRC_DIR/themes -ln -s $NEXTCLOUD_CONFIG_DIR $NEXTCLOUD_SRC_DIR/config -else - echo source files already installed, skipping source files copy -fi - -# --database=DATABASE Supported database type [default: "sqlite"] -# --database-name=DATABASE-NAME Name of the database -# --database-host=DATABASE-HOST Hostname of the database [default: "localhost"] -# --database-port=DATABASE-PORT Port the database is listening on -# --database-user=DATABASE-USER User name to connect to the database -# --database-pass[=DATABASE-PASS] Password of the database user -# --database-table-space[=DATABASE-TABLE-SPACE] Table space of the database (oci only) -# --admin-user=ADMIN-USER User name of the admin account [default: "admin"] -# --admin-pass=ADMIN-PASS Password of the admin account -# --admin-email[=ADMIN-EMAIL] E-Mail of the admin account -# --data-dir=DATA-DIR - -install_options="--admin-user ${NEXTCLOUD_ADMIN_USER:-admin} --admin-pass ${NEXTCLOUD_ADMIN_PASSWORD:-admin} --admin-email ${NEXTCLOUD_ADMIN_EMAIL:-xxx@gmail.com} " -install_options+=" --data-dir $NEXTCLOUD_DATA_DIR" - -# DB setup and admin user are set via autoconfig.php - -if [[ $NEXTCLOUD_DEV ]]; then - nextcloud stop - sleep 3 - echo dev mode, moving config.php and deleting nextcloud db - mv $NEXTCLOUD_HOME/config/config.php $NEXTCLOUD_HOME/config/config.php.sav 2>/dev/null - /bin/rm -rf $NEXTCLOUD_HOME/user-files/* - mv $NEXTCLOUD_HOME/db/mysql.conf.tmpl /tmp/ - /bin/rm -rf $NEXTCLOUD_HOME/db/* - mv /tmp/mysql.conf.tmpl $NEXTCLOUD_HOME/db -fi - -# set database -source $LIB_DIR/db.lib -echo intializing mysql server databases for nextcloud use...be patient -if ! db init; then echo unable to initialze mysql database, thus nextcloud install failed; return 1; fi -echo bringing now ready mysql server online to complete nextcloud installation -nextcloud db start -sleep 5 -if nextcloud supctl status mysql; then - if nextcloud db online nextcloud; then - install_options+=" --database mysql --database-name $MYSQL_DATABASE --database-user nextcloud --database-pass nextcloud --database-host localhost:/run/nextcloud/db.sock" - echo initializing nextcloud via maintence:install...please wait - cmd="sudo -u nextcloud $NEXTCLOUD_SRC_DIR/occ maintenance:install $install_options" - [[ $NEXTCLOUD_DEV ]] && echo DEBUG: $cmd - if $cmd; then - /bin/cp $NEXTCLOUD_CONFIG_FILE $NEXTCLOUD_CONFIG_DIR/config.init.php - echo SUCCESS: maintenance:install succeeded! Nextcloud is installed - echo installed version $(version) on > $NEXTCLOUD_HOME/installed - echo $(date) >> $NEXTCLOUD_HOME/installed - cat $NEXTCLOUD_HOME/installed - echo "**** NOTE: default administrator login is user:${NEXTCLOUD_ADMIN_USER:-admin} password: ${NEXTCLOUD_ADMIN_PASSWORD:-admin} ***" - echo merging config files into config.php - echo starting nextcloud now - if nextcloud start; then - unset NEXTCLOUD_INSTALLING - if [[ $NEXTCLOUD_APPS ]]; then - echo installing nextcloud apps from list - echo $NEXTCLOUD_APPS - nextcloud app install $NEXTCLOUD_APPS - echo "done installing apps" - fi - else - echo FATAL! could not bring up nextcloud after successfull install - install_failed - return 1 - fi - else - echo FATAL! - Install was not successful - install_failed - return 1 - fi - else - echo nextcloud database never came online - echo FATAL! unable to finish nextcloud installation - install_failed - return 1 - fi -else - echo FATAL! unable to bring up mysql database, install FAILED - install_failed - return 1 -fi - diff --git a/src/rootfs/opt/lib/install/mysql.lib b/src/rootfs/opt/lib/install/mysql.lib deleted file mode 100644 index 5bcd7d2..0000000 --- a/src/rootfs/opt/lib/install/mysql.lib +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash - -# ENVIRONENT VARIABLES as get in db.env -# as set in $ENV_DIR/mysql.env -# export DB_HOME=$NEXTCLOUD_DB_DIR -# export DB_CONF=$DB_HOME/mysql.conf -# export DB_SERVER_BIN="$(which mysqld)" -# export DB_SERVER_BIN="$(which mysqld)" -# export DB_CLIENT_BIN="$(which mysql)" -# export DB_SERVER_OPTS=" --defaults-file=$DB_CONF" -# export MYSQL_DATABASE=${MYSQL_DATABASE:-nextcloud} -# export MYSQL_USER=${MYSQL_USER:-nextcloud} -# export MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD:-nextcloud1234} -# export MYSQL_PASSWORD=${MYSQL_PASSWORD:-$MYSQL_ROOT_PASSWORD} - - mysql_init () { - -if nextcloud func process_template $DB_CONF; then - if [ -d $DB_HOME/mysql ]; then - echo "MySQL system DB $DB_HOME/mysql already present, skipping initial creation" - else - echo "MySQL data directory not found, creating initial mysql DBs" - chown -R nextcloud:nextcloud $DB_HOME - # mysql_install_db is a mysql cli command - if mysql_install_db $DB_SERVER_OPTS >/dev/null; then - echo mysql system DBs succesfully created - if nextcloud db start; then - if nextcloud db online mysql; then - echo creating additional root user with root password - $DB_CLIENT_BIN $DB_SERVER_OPTS -uroot << EOF - CREATE USER 'root'@'%' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD'; - GRANT ALL PRIVILEGES on *.* to 'root'@'%'; - FLUSH privileges; -EOF - echo creating empty nextcloud DB... - if mysql_create_nextcloud_db; then - echo Success! - echo MySQL initialzed for Nextcloud on $(date) > $DB_HOME/installed - cat $DB_HOME/installed - else - echo FATAL: unable to to create user and database nextcloud - return 1 - fi - else - echo FATAL: could not access mysql system database - return 1 - fi - else - echo FATAL: could not start mysql daemon - return 1 - fi - else - echo FATAL: unable to make mysql system DB. - return 1 - fi - fi -else - echo unable to make mysql.conf from template in $DB_HOME - return 1 -fi - -} - - -mysql_create_nextcloud_db () { - - echo creating nextcloud db user and database - $DB_CLIENT_BIN $DB_SERVER_OPTS -uroot << EOF - CREATE DATABASE IF NOT EXISTS $MYSQL_DATABASE CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; - GRANT ALL PRIVILEGES on $MYSQL_DATABASE.* to 'nextcloud'@'localhost'; - CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD'; - GRANT ALL PRIVILEGES on $MYSQL_DATABASE.* to '$MYSQL_USER'@'%'; - FLUSH privileges; -EOF - sleep 5 - if nextcloud db online nextcloud; then - echo "nextcloud database successfully created" - else - echo FATAL! error attemping to create nextcloud database with mysql - return 1 - fi -} \ No newline at end of file diff --git a/src/rootfs/opt/lib/mysql.lib b/src/rootfs/opt/lib/mysql.lib new file mode 100644 index 0000000..e2c5665 --- /dev/null +++ b/src/rootfs/opt/lib/mysql.lib @@ -0,0 +1,40 @@ +#!/bin/bash + +db_init () { +# only run this from install_database function + + # initializing mysql server by creating mysql db + if [[ ! -d $DB_HOME/mysql ]]; then + echo "mysql server system databases not found, installing now" + echo "....please wait" + # mysql_install_db is a mysql cli command that starts a server by itself + if mysql_install_db $DB_SERVER_OPTS >/dev/null; then + echo mysql system databases succesfully created + return + else + echo install of mysql system databases failed + pgrep -x mysql_install_db | xargs kill -9 + return 1 + fi + else + echo mysql system databases already created on server + fi + +} + +db_cli () { +local user +local db +local cmd +db=${NEXTCLOUD_DB:-nextcloud} +[[ $NEXTCLOUD_DB_PASSWORD ]] && user=" -u ${NEXTCLOUD_DB_USER:-nextcloud} -p${NEXTCLOUD_DB_PASSWORD}" +if [[ $1 == "-r" ]] || [[ $1 == "--root" ]]; then user="-u root"; db="mysql"; shift; fi +cmd="$DB_CLIENT_BIN ${user} ${db}" +if [[ $1 ]]; then + $cmd <<< "$1;" + else + $cmd +fi + +} + diff --git a/src/rootfs/opt/lib/nextcloud.lib b/src/rootfs/opt/lib/nextcloud.lib index b1d9b31..b289390 100644 --- a/src/rootfs/opt/lib/nextcloud.lib +++ b/src/rootfs/opt/lib/nextcloud.lib @@ -1,9 +1,12 @@ #!/bin/bash -source $LIB_DIR/verbose.lib +# source $LIB_DIR/verbose.lib +source $LIB_DIR/confirm.func source $LIB_DIR/helpers.lib source $LIB_DIR/db.lib source $LIB_DIR/redis.lib source $LIB_DIR/caddy.lib +source $LIB_DIR/ssh.lib source $LIB_DIR/cmds.lib + diff --git a/src/rootfs/opt/nextcloud/src/phpinfo.php b/src/rootfs/opt/lib/php/phpinfo.php similarity index 100% rename from src/rootfs/opt/nextcloud/src/phpinfo.php rename to src/rootfs/opt/lib/php/phpinfo.php diff --git a/src/rootfs/opt/nextcloud/src/redis-test.php b/src/rootfs/opt/lib/php/redis-test.php similarity index 100% rename from src/rootfs/opt/nextcloud/src/redis-test.php rename to src/rootfs/opt/lib/php/redis-test.php diff --git a/src/rootfs/opt/lib/redis.lib b/src/rootfs/opt/lib/redis.lib index 7489a25..0722da8 100644 --- a/src/rootfs/opt/lib/redis.lib +++ b/src/rootfs/opt/lib/redis.lib @@ -5,11 +5,7 @@ redis () { case "$1" in start) - if nextcloud supctl status redis 1> /dev/null; then - echo Redis server already running - else - nextcloud supctl start redis; - fi + return $(nextcloud start redis) ;; restart) nextcloud supctl restart redis @@ -22,9 +18,10 @@ case "$1" in return 0 fi ;; - init) + update) if ! nextcloud func process_template $REDIS_CONF; then echo unable to make $REDIS_CONF + return 1 fi ;; diff --git a/src/rootfs/opt/lib/release.lib b/src/rootfs/opt/lib/release.lib new file mode 100644 index 0000000..8537749 --- /dev/null +++ b/src/rootfs/opt/lib/release.lib @@ -0,0 +1,111 @@ +#!/bin/bash + +export NEXTCLOUD_RELEASES_URL=https://download.nextcloud.com/server/releases + +nextcloud_pull () { + + local ver + local file + + echo determining release .... + if [[ $1 ]]; then + if [[ $1 == *.* ]] ; then + ver=$1 + if ! nextcloud_releases $ver > /dev/null; then + echo no version $ver in releases nothing to pull + echo possible valid releases are + sleep 2 + nextcloud_releases + return 1 + fi + else + if ! ver=$(nextcloud_releases latest $1); then + unable to find lastest minor release for version $1 + return 1 + fi + fi + else + if ! ver=$(nextcloud_releases latest) ; then + echo unable to determine any latest release + return 1 + fi + + fi + + if version release $ver > /dev/null ; then + read -p "local copy of $ver already exists do you want to pull it again?, [yY]" -n 1 -r + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "\n !!! aborting pull !!! \n" + return 4 + fi + fi + + file=nextcloud-$ver.tar.bz2 + + if ! nextcloud_release_exists $file; then + echo ERROR: file $file does not exist at repository nothing to pull + return 1 + fi + + read -p "do you want to pull and extract version: $ver, file: $file?, [yY]" -n 1 -r + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo -e "\n --- pulling now --- \n" + else + echo -e "\n !!! aborting pull !!! \n" + return 4 + fi + + # echo curl -o /tmp/$file $NEXTCLOUD_RELEASES_URL/$file + + if ([[ -f /tmp/$file ]] && ( echo $file already pulled; true; ) || curl -o /tmp/$file $NEXTCLOUD_RELEASES_URL/$file) ; then + echo success downloading $file to /tmp + echo attempting to extact $file to $NEXTCLOUD_RELEASES_DIR/$ver + mkdir -p $NEXTCLOUD_RELEASES_DIR/$ver + if tar -xjf /tmp/$file --strip-components=1 -C $NEXTCLOUD_RELEASES_DIR/$ver; then + echo extraction sucessfull to $NEXTCLOUD_RELEASES_DIR/$ver + echo confirming version: + if version release $ver > /dev/null ; then rm -f /tmp/$file; fi + else + echo unable to extract $file to $NEXTCLOUD_RELEASES_DIR + echo $file may be corrupted. + echo deleting /tmp/$file, will need to pull again + rm -f /tmp/$file + return 2 + fi + else + echo unable to download and extract $file + return 1; + fi + +} + +nextcloud_release_exists () { + local code + local url + url="$NEXTCLOUD_RELEASES_URL/$1" + code=$(curl -o /dev/null --silent -Iw '%{http_code}' $url) + [[ $code == 200 ]] && return 0 + echo can not confirm existance of $1 at + echo $url + return 1 +} + +nextcloud_releases () { + + local vers=nextcloud; local latest; local vout + [[ $1 == "major" ]] && vers=latest && shift + [[ $1 == "latest" ]] && latest=true && shift + + vout=$(curl -s $NEXTCLOUD_RELEASES_URL/ \ + | grep "<\/a>\n/2' \ + | grep href \ + | sed -e 's/.*/dev/null; then + echo ssh server is already running can not boot/start + else + if ssh_make_authorized_keys; then + ssh_make_conf + echo starting ssh server + /usr/sbin/sshd $boot -E $NEXTCLOUD_LOGS_DIR/ssh.log "$@" + sleep 1 + if pgrep sshd >/dev/null ; then + echo ssh server started + else + echo ssh server failed to start + return 1 + fi + fi + fi + ;; + conf) + ssh_make_conf + ;; + pubkey) + ssh_make_authorized_keys + ;; + stop) + for proc in $(pgrep sshd); do kill $proc; done + sleep 1 + if pgrep sshd; then echo unable to stop ssh server; return 1; fi + ;; + *) + if pgrep sshd >/dev/null; then + echo ssh server is running + else + echo ssh server is down + return 1 + fi + esac + + else + echo to use ssh you MUST set either SSH_ADDRESS and/or SSH_HOST + return 1 + fi + else + echo to use ssh you MUST set both SSH_USER and SSH_PUBKEY + return 1 + fi + +} + + +ssh_make_conf () { + +conf=/etc/ssh/sshd_config.d/03-container-key-access.conf + +cat < $conf +Match User $SSH_USER $([[ $SSH_ADDRESS ]] && echo Address $SSH_ADDRESS) $([[ $SSH_HOST ]] && echo Host $SSH_HOST) +$(cat $conf.tmpl) +EOF + +echo added Match line to $conf +cat $conf + +} + +ssh_make_authorized_keys () { + + if getent passwd $SSH_USER | grep -q '/bin/bash' ;then + local home + home=$( [[ $SSH_USER == "root" ]] && echo /root/.ssh || echo /home/$SSH_USER/.ssh ) + mkdir $home 2>/dev/null + chmod 700 $home + echo -e "$SSH_PUBKEY\n" > $home/authorized_keys + chmod 600 $home/authorized_keys + chown -R $SSH_USER:$SSH_USER $home + echo made authorized_keys file at $home with key + ls -ls $home + cat $home/authorized_keys + else + echo user $SSH_USER does not have bash login privilidges, can not set up as ssh user + return 1 + fi + +} + +# if script was executed then call the function +(return 0 2>/dev/null) || ssh "$@" \ No newline at end of file diff --git a/src/rootfs/opt/lib/upgrade.exclude b/src/rootfs/opt/lib/upgrade.exclude index 321b6b8..27be63c 100644 --- a/src/rootfs/opt/lib/upgrade.exclude +++ b/src/rootfs/opt/lib/upgrade.exclude @@ -1,6 +1,5 @@ /config/ /data/ -/custom_apps/ +/apps/ /themes/ -/version.php -/nextcloud-init-sync.lock \ No newline at end of file +/updater/ diff --git a/src/rootfs/opt/lib/upgrade.lib b/src/rootfs/opt/lib/upgrade.lib new file mode 100644 index 0000000..2a393a0 --- /dev/null +++ b/src/rootfs/opt/lib/upgrade.lib @@ -0,0 +1,200 @@ +#!/bin/bash + +export NEXTCLOUD_UPGRADE_VERSION="" +source $LIB_DIR/release.lib +source $LIB_DIR/db.lib + +upgrade_container () { +echo upgrade container image files /tmp/nextcloud +rsync -rlDv --info=progress2 /tmp/nextcloud/ $NEXTCLOUD_SRC_DIR +} + +upgradable () { + # https://stackoverflow.com/a/4024263 + local vfrom=$1 + local vto=$2 + [[ $vto == "$vfrom" ]] && return 1 + if ! printf '%s\n' $$vto $vfrom | sort -C -V ; then + local diff=$(($(echo $vto | cut -f1 -d.)-$(echo $vfrom | cut -f1 -d.))) + [[ $diff -gt 1 ]] && echo can not upgrade two major versions $vfrom to $vto && return 2 + if [[ $diff == 1 ]]; then + local latest=$(nextcloud_releases latest $(echo $vfrom | cut -f1 -d.)) + if [[ ! $vfrom == "$latest" ]]; then + echo $vfrom is not the latest minor version which is $latest + echo must upgrade first to $latest before upgrading to $vto + return 1 + fi + fi + fi +} + +upgrade_version () { + local cur=$1 + if cur=${cur:-$(version)}; then + local minor=$(nextcloud_releases latest $(echo $cur | cut -f1 -d.)) + echo checking for minor upgrade for current version, $cur + if upgradable $cur $minor; then + echo minor upgrade to $minor available + export NEXTCLOUD_UPGRADE_VERSION=$minor + else + if [[ "$minor" == "$cur" ]]; then + echo current version, $cur, is latest version minor for $(echo $cur | cut -f1 -d.) + echo checking for major upgrade + local major=$(nextcloud_releases latest $(($(echo $cur | cut -f1 -d.)+1))) + if [[ $major ]]; then + echo major version upgrade available, $major + export NEXTCLOUD_UPGRADE_VERSION=$major + else + echo current version $cur is latest major available, nothing to upgrade + export NEXTCLOUD_UPGRADE_VERSION="" + return 1 + fi + else + echo $cur not upgradable to $minor + export NEXTCLOUD_UPGRADE_VERSION="" + return 1 + fi + fi + else + echo "can't determine current version likely nextcloud is not installed, can not upgrade" + return 1 + fi + +} + +upgrade_prepare () { + [[ $1 == "container" ]] && ( upgrade_container; return $?; ) + if ! nextcloud state > /dev/null; then echo $NEXTCLOUD_NAME is not currenly running, must be running to upgrade; return 1; fi + if ! installed > /dev/null ; then echo nextcloud not installed, can not upgrade; return 4; fi + if [[ "$1" == "-f" ]]; then + if [[ $(nextcloud_releases $2 | wc -l) -eq "1" ]]; then + NEXTCLOUD_UPGRADE_VERSION=$2 + shift 2 + else + echo forced upgrade release $2 does not exist + echo these are the available releases for $(echo $2 | cut -f1 -d.) + nextcloud_releases $(echo $2 | cut -f1 -d.) + echo aborting upgrade + return 3 + fi + fi + local cur=${1:-$(version)} + [[ ! $cur ]] && echo unable to determine current version, is nextcloud installed? && return 2 + if [[ $NEXTCLOUD_UPGRADE_VERSION ]]; then + if upgradable $cur $NEXTCLOUD_UPGRADE_VERSION; then + echo current version $cur can be upgraded to $NEXTCLOUD_UPGRADE_VERSION + if confirm -s Do you want to download version $NEXTCLOUD_UPGRADE_VERSION?; then + if version release $NEXTCLOUD_UPGRADE_VERSION > /dev/null ; then + echo $NEXTCLOUD_UPGRADE_VERSION already downloaded + echo upgrade prepared + else + echo downloading $NEXTCLOUD_UPGRADE_VERSION now, be patient.... + if ! nextcloud_pull $NEXTCLOUD_UPGRADE_VERSION; then echo download/extract failed; return 1; fi + echo download/extract successful, upgrade prepared + fi + else + echo upgrade aborted + return 1 + fi + else + echo $cur can not be upgraded to $NEXTCLOUD_UPGRADE_VERSION + return 1 + fi + else + if upgrade_version $cur; then + upgrade_prepare $cur + else + echo can not determine upgrade version, upgrade aborted + return 1 + fi + fi +} + +# do the actual upgrade +upgrade_run () { + + NEXTCLOUD_UPGRADE_ID=$(date '+%Y%m%d%H%M%S') + + nextcloud config backup + echo saving copy of database + if ! nextcloud db backup $NEXTCLOUD_UPGRADE_ID ; then + echo database backup failed + echo can not continue with upgrade + return 2 + fi + + if ! nextcloud update; then + echo FAILED: nextcloud update with container failed, aborting upgrade + return 3 + fi + + if ! nextcloud func mmode on; then echo unable to enter maintenance mode, aborting upgrade; return 1; fi + + local previous=$(version) + [[ ! $previous ]] && echo unable to determine current version, aborting upgrade && return 5 + echo $previous > $NEXTCLOUD_HOME/previous-version + + local SRC + if ! SRC=$NEXTCLOUD_RELEASES_DIR/$(version release $NEXTCLOUD_UPGRADE_VERSION); then + echo no version $NEXTCLOUD_UPGRADE_VERSION to install, rerun \'nextcloud upgrade\' + unset NEXTCLOUD_UPGRADE_VERSION + return 1 + fi + + echo saving list of current apps + nextcloud occ app:list > $NEXTCLOUD_APPS_DIR/apps-list + echo saving nextcloud $previous source + mv $NEXTCLOUD_SRC_DIR/ $NEXTCLOUD_SRC_DIR-$previous + if ! version $NEXTCLOUD_SRC_DIR-$previous > /dev/null; then + echo unable to save current version $previous of source + echo can not continue upgrade + return 3 + fi + + echo copying new nextcloud source at $SRC to the instance directory $NEXTCLOUD_SRC_DIR + if ! rsync -rlD --info=progress2 --chown=$NEXTCLOUD_USER:$NEXTCLOUD_USER --exclude-from=$LIB_DIR/upgrade.exclude $SRC/ $NEXTCLOUD_SRC_DIR; then + echo ERROR: unable to copy new release source code + return 4 + fi + + if [[ ! $NEXTCLOUD_UPGRADE_VERSION == $(version) ]]; then + echo unable to confirm that new source is version $NEXTCLOUD_UPGRADE_VERSION + return 5 + fi + + echo backup apps directory + mv $NEXTCLOUD_APPS_DIR $NEXTCLOUD_APPS_DIR-$previous-$NEXTCLOUD_UPGRADE_ID + echo copying new apps directory + rsync -rlD --info=progress2 --chown=$NEXTCLOUD_USER:$NEXTCLOUD_USER $SRC/apps/ $NEXTCLOUD_APPS_DIR + + + echo create links to apps, themes, and config + ln -s $NEXTCLOUD_APPS_DIR $NEXTCLOUD_SRC_DIR/apps + ln -s $NEXTCLOUD_THEMES_DIR $NEXTCLOUD_SRC_DIR/themes + ln -s $NEXTCLOUD_CONFIG_DIR $NEXTCLOUD_SRC_DIR/config + + echo starting upgrade processing now... please wait + if nextcloud occ upgrade &> $NEXTCLOUD_LOGS_DIR/upgrade-$NEXTCLOUD_UPGRADE_VERSION-$NEXTCLOUD_UPGRADE_ID; then + echo nextcloud system upgrade was successfull + else + echo FATAL: unable to complete upgrade, need to run nextcloud upgrade rollback + return 7 + fi + + nextcloud func mmode off + echo restarting nextcloud + if ! nextcloud restart >/dev/null; then echo could not restart nextcloud after upgrade, see troubleshooting; return 1; fi + + echo running a repair after upgrade + if ! nextcloud repair >/dev/null; then echo WARN: could not complete a nextcloud repair; return 1; fi + echo + echo any nextcloud issues repaired + + nextcloud history upgrade $NEXTCLOUD_UPGRADE_ID + nextcloud history + + unset NEXTCLOUD_UPGRADE_VERSION + unset NEXTCLOUD_UPGRADE_ID + +} + diff --git a/src/rootfs/opt/nextcloud/config/misc.config.php b/src/rootfs/opt/nextcloud/config/misc.config.php index eeed297..0ae64c1 100644 --- a/src/rootfs/opt/nextcloud/config/misc.config.php +++ b/src/rootfs/opt/nextcloud/config/misc.config.php @@ -3,4 +3,6 @@ $CONFIG = array ( 'logfile' =>getenv('NEXTCLOUD_LOGS_DIR') ?: '/opt/nextcloud/logs'.'/nextcloud.log', 'default_phone_region' => getenv('NEXTCLOUD_REGION') ?: 'US', 'configs_merged' => true, + 'backgroundjobs_mode' => 'cron', + 'maintenance_window_start' => getenv('MAINTENANCE_WINDOW_START')/1 ?: 1 ); \ No newline at end of file diff --git a/src/rootfs/opt/nextcloud/config/reverse-proxy.config.php b/src/rootfs/opt/nextcloud/config/reverse-proxy.config.php index 35214f6..c4559d2 100644 --- a/src/rootfs/opt/nextcloud/config/reverse-proxy.config.php +++ b/src/rootfs/opt/nextcloud/config/reverse-proxy.config.php @@ -26,6 +26,6 @@ if ($overwriteCondAddr) { $trustedProxies = getenv('NEXTCLOUD_TRUSTED_PROXIES'); if ($trustedProxies) { - $CONFIG['trusted_proxies'] = array_filter(array_map('trim', explode(' ', $trustedProxies))); - $CONFIG['forwarded_for_headers'] => array('HTTP_X_FORWARDED_FOR'), + $CONFIG['trusted_proxies'] = explode(' ', $trustedProxies); + $CONFIG['forwarded_for_headers'] = array('HTTP_X_FORWARDED_FOR'); } diff --git a/src/rootfs/opt/nextcloud/db/mysql.conf.tmpl b/src/rootfs/opt/nextcloud/db/mysql.conf.tmpl index 9cb6ca6..f38c9cf 100644 --- a/src/rootfs/opt/nextcloud/db/mysql.conf.tmpl +++ b/src/rootfs/opt/nextcloud/db/mysql.conf.tmpl @@ -11,15 +11,17 @@ query_cache_size = 64M tmp_table_size= 64M max_heap_table_size= 64M slow_query_log = 1 -slow_query_log_file = $NEXTCLOUD_LOGS_DIR/db-slow.log +slow_query_log_file = $NEXTCLOUD_LOGS_DIR/mysql-slow.log long_query_time = 1 -general_log_file = $NEXTCLOUD_LOGS_DIR/db.log +general_log_file = $NEXTCLOUD_LOGS_DIR/mysql.log general_log = 1 [client] default-character-set = utf8mb4 user = nextcloud +password = nextcloud socket = /run/nextcloud/db.sock +protocol = socket [mariadb] user = nextcloud @@ -31,10 +33,15 @@ bind-address = 127.0.0.1 character_set_server = utf8mb4 collation_server = utf8mb4_general_ci transaction_isolation = READ-COMMITTED -log-bin = 1 +# disable binary logs +# log-bin = 1 binlog_format = ROW innodb_file_per_table=1 [mysqld_safe] -log-error=$NEXTCLOUD_LOGS_DIR/mysql_safe.err +log-error=$NEXTCLOUD_LOGS_DIR/mysql_safe.erorr.log # pid-file=$DB_HOME/mysqld.pid + +[mysql_install_db] +admin-user = nextcloud +insecure = 1 diff --git a/src/rootfs/opt/supervisor/caddy.ini b/src/rootfs/opt/supervisor/caddy.ini index 0f5f8fc..0570019 100644 --- a/src/rootfs/opt/supervisor/caddy.ini +++ b/src/rootfs/opt/supervisor/caddy.ini @@ -1,11 +1,11 @@ [program:caddy] command=%(ENV_CADDY_BIN)s run --config %(ENV_CADDY_CONF)s/.Caddyfile --adapter caddyfile stopsignal=QUIT -autostart=false -;autorestart=unexpected +autostart=%(ENV_BOOT)s +autorestart=%(ENV_AUTORESTART)s priority=2 user=nextcloud -stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/supervisor/caddy.log -stdout_logfile_maxbytes=0 -stderr_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/supervisor/caddy.err -stderr_logfile_maxbytes=0 \ No newline at end of file +stdout_logfile_backups=1 +stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/caddy.log +stdout_logfile_maxbytes=10MB +redirect_stderr=true \ No newline at end of file diff --git a/src/rootfs/opt/supervisor/cron.ini b/src/rootfs/opt/supervisor/cron.ini new file mode 100644 index 0000000..7f98485 --- /dev/null +++ b/src/rootfs/opt/supervisor/cron.ini @@ -0,0 +1,10 @@ +[program:cron] +command = /usr/bin/supercronic --passthrough-logs -json /etc/crontabs/nextcloud +autostart=%(ENV_BOOT)s +autorestart=%(ENV_AUTORESTART)s +priority=10 +user=nextcloud +stdout_logfile_backups=1 +stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/cron.log +stdout_logfile_maxbytes=10MB +redirect_stderr=true \ No newline at end of file diff --git a/src/rootfs/opt/supervisor/db.ini b/src/rootfs/opt/supervisor/db.ini new file mode 100644 index 0000000..fa49e81 --- /dev/null +++ b/src/rootfs/opt/supervisor/db.ini @@ -0,0 +1,10 @@ +[program:db] +command=/usr/bin/pidproxy /run/nextcloud/db.pid /usr/bin/mysqld_safe %(ENV_DB_SERVER_OPTS)s +autostart=%(ENV_BOOT)s +autorestart=%(ENV_AUTORESTART)s +priority=1 +user=nextcloud +stdout_logfile_backups=1 +stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/db.log +stdout_logfile_maxbytes=10MB +redirect_stderr=true \ No newline at end of file diff --git a/src/rootfs/opt/supervisor/mysql.ini b/src/rootfs/opt/supervisor/mysql.ini deleted file mode 100644 index e92ad2e..0000000 --- a/src/rootfs/opt/supervisor/mysql.ini +++ /dev/null @@ -1,10 +0,0 @@ -[program:mysql] -command=/usr/bin/pidproxy /run/nextcloud/db.pid /usr/bin/mysqld_safe %(ENV_DB_SERVER_OPTS)s -autostart=false -;autorestart=unexpected -priority=1 -user=nextcloud -stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/supervisor/mysql.log -stdout_logfile_maxbytes=0 -stderr_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/supervisor/mysql.err -stderr_logfile_maxbytes=0 \ No newline at end of file diff --git a/src/rootfs/opt/supervisor/nextcloud.ini b/src/rootfs/opt/supervisor/nextcloud.ini deleted file mode 100644 index 451a39f..0000000 --- a/src/rootfs/opt/supervisor/nextcloud.ini +++ /dev/null @@ -1,10 +0,0 @@ -[program:nextcloud] -priority=1 -command=/opt/bin/nextcloud start -stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/start.log -stdout_logfile_maxbytes=0 -stderr_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/start.err -stderr_logfile_maxbytes=0 -autostart=%(ENV_BOOT)s -autorestart=false -startsecs=0 diff --git a/src/rootfs/opt/supervisor/php-fpm.ini b/src/rootfs/opt/supervisor/php-fpm.ini deleted file mode 100644 index 6c2a2af..0000000 --- a/src/rootfs/opt/supervisor/php-fpm.ini +++ /dev/null @@ -1,24 +0,0 @@ -[program:php-fpm] -command = /bin/php-fpm -g /run/nextcloud/php-fpm.pid -F -autostart=false -; autorestart=unexpected -priority=3 -user=nextcloud -stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/supervisor/php-fpm.log -stdout_logfile_maxbytes=0 -stderr_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/supervisor/php-fpm.err -stderr_logfile_maxbytes=0 - - -; [program:php-fpm] -; command = /bin/php-fpm --force-stderr --nodaemonize --fpm-config -; autostart=false -; ;autorestart=true -; priority=5 -; stdout_events_enabled=true -; stderr_events_enabled=true -; stdout_logfile=/dev/stdout -; stdout_logfile_maxbytes=0 -; stderr_logfile=/dev/stderr -; stderr_logfile_maxbytes=0 -; stopsignal=QUIT \ No newline at end of file diff --git a/src/rootfs/opt/supervisor/php.ini b/src/rootfs/opt/supervisor/php.ini new file mode 100644 index 0000000..cec90e5 --- /dev/null +++ b/src/rootfs/opt/supervisor/php.ini @@ -0,0 +1,10 @@ +[program:php-fpm] +command = /bin/php-fpm -g /run/nextcloud/php-fpm.pid -F +autostart=%(ENV_BOOT)s +autorestart=%(ENV_AUTORESTART)s +priority=3 +user=nextcloud +stdout_logfile_backups=1 +stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/php-fpm.log +stdout_logfile_maxbytes=10MB +redirect_stderr=true \ No newline at end of file diff --git a/src/rootfs/opt/supervisor/redis.ini b/src/rootfs/opt/supervisor/redis.ini index cba3d6f..c8c3279 100644 --- a/src/rootfs/opt/supervisor/redis.ini +++ b/src/rootfs/opt/supervisor/redis.ini @@ -1,10 +1,11 @@ [program:redis] command=%(ENV_REDIS_BIN)s %(ENV_REDIS_CONF)s directory=%(ENV_REDIS_HOME)s -autostart=false -priority=1 +autostart=%(ENV_BOOT)s +autorestart=%(ENV_AUTORESTART)s +priority=4 user=nextcloud -stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/supervisor/redis.log -stdout_logfile_maxbytes=0 -stderr_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/supervisor/redis.err -stderr_logfile_maxbytes=0 \ No newline at end of file +stdout_logfile_backups=1 +stdout_logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/redis.log +stdout_logfile_maxbytes=10MB +redirect_stderr=true diff --git a/src/rootfs/opt/supervisor/supervisord.conf b/src/rootfs/opt/supervisor/supervisord.conf index 0df827f..4fdf2d3 100644 --- a/src/rootfs/opt/supervisor/supervisord.conf +++ b/src/rootfs/opt/supervisor/supervisord.conf @@ -9,6 +9,10 @@ port=0.0.0.0:9001 ; (ip_address:port specifier, *:port for all iface) [supervisord] ;nodaemon=true +logfile_maxbytes=10MB ; max main logfile bytes b4 rotation; default 50MB +logfile_backups=1 ; # of main logfile backups; 0 means none, default 10 +loglevel=warn +;silent=true user=root logfile=%(ENV_NEXTCLOUD_LOGS_DIR)s/supervisor.log pidfile=%(ENV_SUPERVISOR_HOME)s/supervisor.pid @@ -21,4 +25,13 @@ supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface serverurl=unix:///run/nextcloud/supervisor.sock [include] -files = %(ENV_SUPERVISOR_HOME)s/*.ini \ No newline at end of file +files = %(ENV_SUPERVISOR_HOME)s/*.ini + +[group:nextcloud] +programs=db,caddy,php-fpm,redis,cron + +; https://thepracticalsysadmin.com/quicktip-manage-memory-usage-with-supervisord/ +; memory watch + +; watchdog that kills supervisor is any child is fatal +; https://github.com/Supervisor/supervisor/issues/712#issuecomment-184668764 diff --git a/src/rootfs/root/shell/load/complete b/src/rootfs/root/shell/load/complete new file mode 100644 index 0000000..df5b3ac --- /dev/null +++ b/src/rootfs/root/shell/load/complete @@ -0,0 +1 @@ +complete -E -W nextcloud \ No newline at end of file diff --git a/src/rootfs/root/shell/load/ssh b/src/rootfs/root/shell/load/ssh new file mode 100644 index 0000000..8b31e5c --- /dev/null +++ b/src/rootfs/root/shell/load/ssh @@ -0,0 +1,12 @@ +#!/bin/bash +if [[ $SSH_SESSION ]]; then + if [[ -f /tmp/passed.env ]]; then + while IFS== read -r key value; do + printf -v "$key" %s "$value" && export "$key" >/dev/null + done < /tmp/passed.env + fi + source /opt/core_run.env + source /opt/bin/nextcloud + cd "$NEXTCLOUD_HOME" +fi +