diff --git a/.config/redis.config.php b/.config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/.config/redis.config.php +++ b/.config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/.config/s3.config.php b/.config/s3.config.php index 6d0ede91..9941c562 100644 --- a/.config/s3.config.php +++ b/.config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/.config/smtp.config.php b/.config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/.config/smtp.config.php +++ b/.config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/.examples/README.md b/.examples/README.md index e962f67d..64b694b5 100644 --- a/.examples/README.md +++ b/.examples/README.md @@ -52,9 +52,6 @@ The required steps for each optional/recommended package that is not already in #### ffmpeg `apt install ffmpeg` -#### imagemagick SVG support -`apt install libmagickcore-6.q16-6-extra` - #### LibreOffice `apt install libreoffice` diff --git a/.github/workflows/images.yml b/.github/workflows/images.yml index ae9762a6..e8b70226 100644 --- a/.github/workflows/images.yml +++ b/.github/workflows/images.yml @@ -20,8 +20,8 @@ jobs: outputs: strategy: ${{ steps.generate-jobs.outputs.strategy }} steps: - - uses: actions/checkout@v3 - - uses: docker-library/bashbrew@v0.1.5 + - uses: actions/checkout@v4 + - uses: docker-library/bashbrew@HEAD - id: generate-jobs name: Generate Jobs run: | @@ -36,7 +36,7 @@ jobs: name: ${{ matrix.name }} runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Prepare Environment run: ${{ matrix.runs.prepare }} - name: Run update.sh script diff --git a/.github/workflows/update-sh.yml b/.github/workflows/update-sh.yml index 4e03239a..3b969c9e 100644 --- a/.github/workflows/update-sh.yml +++ b/.github/workflows/update-sh.yml @@ -13,7 +13,7 @@ jobs: name: Run update.sh script runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run update.sh script run: ./update.sh - name: Commit files diff --git a/.travis/test-example-dockerfiles.sh b/.travis/test-example-dockerfiles.sh deleted file mode 100755 index e28a7d7f..00000000 --- a/.travis/test-example-dockerfiles.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -set -e - -image="$1" - -cd .examples/dockerfiles - -dirs=( */ ) -dirs=( "${dirs[@]%/}" ) -for dir in "${dirs[@]}"; do - if [ -d "$dir/$VARIANT" ]; then - ( - cd "$dir/$VARIANT" - sed -ri -e 's/^FROM .*/FROM '"$image"'/g' 'Dockerfile' - docker build -t "$image-$dir" . - ) - fi -done diff --git a/27/apache/Dockerfile b/27/apache/Dockerfile index 9671fde0..8b9a64fe 100644 --- a/27/apache/Dockerfile +++ b/27/apache/Dockerfile @@ -15,7 +15,7 @@ RUN set -ex; \ rm -rf /var/lib/apt/lists/*; \ \ mkdir -p /var/spool/cron/crontabs; \ - echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/5 * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -45,11 +45,13 @@ RUN set -ex; \ ; \ \ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -138,7 +140,7 @@ RUN { \ } > /etc/apache2/conf-available/apache-limits.conf; \ a2enconf apache-limits -ENV NEXTCLOUD_VERSION 27.1.5 +ENV NEXTCLOUD_VERSION 27.1.11 RUN set -ex; \ fetchDeps=" \ @@ -148,8 +150,8 @@ RUN set -ex; \ apt-get update; \ apt-get install -y --no-install-recommends $fetchDeps; \ \ - curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-27.1.5.tar.bz2"; \ - curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-27.1.5.tar.bz2.asc"; \ + curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-27.1.11.tar.bz2"; \ + curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-27.1.11.tar.bz2.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ # gpg key from https://nextcloud.com/nextcloud.asc gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ @@ -165,7 +167,8 @@ RUN set -ex; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ rm -rf /var/lib/apt/lists/* -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/27/apache/config/redis.config.php b/27/apache/config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/27/apache/config/redis.config.php +++ b/27/apache/config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/27/apache/config/s3.config.php b/27/apache/config/s3.config.php index 6d0ede91..9941c562 100644 --- a/27/apache/config/s3.config.php +++ b/27/apache/config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/27/apache/config/smtp.config.php b/27/apache/config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/27/apache/config/smtp.config.php +++ b/27/apache/config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/27/apache/entrypoint.sh b/27/apache/entrypoint.sh index 5b627f07..ef80647a 100755 --- a/27/apache/entrypoint.sh +++ b/27/apache/entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/27/apache/occ b/27/apache/occ new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/27/apache/occ @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/27/apache/occ-cron b/27/apache/occ-cron new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/27/apache/occ-cron @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/27/fpm-alpine/Dockerfile b/27/fpm-alpine/Dockerfile index cfc8a79e..68bfba03 100644 --- a/27/fpm-alpine/Dockerfile +++ b/27/fpm-alpine/Dockerfile @@ -1,16 +1,23 @@ # DO NOT EDIT: created by update.sh from Dockerfile-alpine.template -FROM php:8.2-fpm-alpine3.18 +FROM php:8.2-fpm-alpine3.20 # entrypoint.sh and cron.sh dependencies RUN set -ex; \ \ apk add --no-cache \ imagemagick \ + imagemagick-pdf \ + imagemagick-jpeg \ + imagemagick-raw \ + imagemagick-tiff \ + imagemagick-heic \ + imagemagick-webp \ + imagemagick-svg \ rsync \ ; \ \ rm /var/spool/cron/crontabs/root; \ - echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/5 * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -36,11 +43,13 @@ RUN set -ex; \ postgresql-dev \ ; \ \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -111,7 +120,7 @@ RUN { \ VOLUME /var/www/html -ENV NEXTCLOUD_VERSION 27.1.5 +ENV NEXTCLOUD_VERSION 27.1.11 RUN set -ex; \ apk add --no-cache --virtual .fetch-deps \ @@ -119,8 +128,8 @@ RUN set -ex; \ gnupg \ ; \ \ - curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-27.1.5.tar.bz2"; \ - curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-27.1.5.tar.bz2.asc"; \ + curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-27.1.11.tar.bz2"; \ + curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-27.1.11.tar.bz2.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ # gpg key from https://nextcloud.com/nextcloud.asc gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ @@ -134,7 +143,8 @@ RUN set -ex; \ chmod +x /usr/src/nextcloud/occ; \ apk del --no-network .fetch-deps -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/27/fpm-alpine/config/redis.config.php b/27/fpm-alpine/config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/27/fpm-alpine/config/redis.config.php +++ b/27/fpm-alpine/config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/27/fpm-alpine/config/s3.config.php b/27/fpm-alpine/config/s3.config.php index 6d0ede91..9941c562 100644 --- a/27/fpm-alpine/config/s3.config.php +++ b/27/fpm-alpine/config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/27/fpm-alpine/config/smtp.config.php b/27/fpm-alpine/config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/27/fpm-alpine/config/smtp.config.php +++ b/27/fpm-alpine/config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/27/fpm-alpine/entrypoint.sh b/27/fpm-alpine/entrypoint.sh index 5b627f07..ef80647a 100755 --- a/27/fpm-alpine/entrypoint.sh +++ b/27/fpm-alpine/entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/27/fpm-alpine/occ b/27/fpm-alpine/occ new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/27/fpm-alpine/occ @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/27/fpm-alpine/occ-cron b/27/fpm-alpine/occ-cron new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/27/fpm-alpine/occ-cron @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/27/fpm/Dockerfile b/27/fpm/Dockerfile index 4ca64950..25dcc604 100644 --- a/27/fpm/Dockerfile +++ b/27/fpm/Dockerfile @@ -15,7 +15,7 @@ RUN set -ex; \ rm -rf /var/lib/apt/lists/*; \ \ mkdir -p /var/spool/cron/crontabs; \ - echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/5 * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -45,11 +45,13 @@ RUN set -ex; \ ; \ \ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -123,7 +125,7 @@ RUN { \ VOLUME /var/www/html -ENV NEXTCLOUD_VERSION 27.1.5 +ENV NEXTCLOUD_VERSION 27.1.11 RUN set -ex; \ fetchDeps=" \ @@ -133,8 +135,8 @@ RUN set -ex; \ apt-get update; \ apt-get install -y --no-install-recommends $fetchDeps; \ \ - curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-27.1.5.tar.bz2"; \ - curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-27.1.5.tar.bz2.asc"; \ + curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-27.1.11.tar.bz2"; \ + curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-27.1.11.tar.bz2.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ # gpg key from https://nextcloud.com/nextcloud.asc gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ @@ -150,7 +152,8 @@ RUN set -ex; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ rm -rf /var/lib/apt/lists/* -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/27/fpm/config/redis.config.php b/27/fpm/config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/27/fpm/config/redis.config.php +++ b/27/fpm/config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/27/fpm/config/s3.config.php b/27/fpm/config/s3.config.php index 6d0ede91..9941c562 100644 --- a/27/fpm/config/s3.config.php +++ b/27/fpm/config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/27/fpm/config/smtp.config.php b/27/fpm/config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/27/fpm/config/smtp.config.php +++ b/27/fpm/config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/27/fpm/entrypoint.sh b/27/fpm/entrypoint.sh index 5b627f07..ef80647a 100755 --- a/27/fpm/entrypoint.sh +++ b/27/fpm/entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/27/fpm/occ b/27/fpm/occ new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/27/fpm/occ @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/27/fpm/occ-cron b/27/fpm/occ-cron new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/27/fpm/occ-cron @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/28/apache/Dockerfile b/28/apache/Dockerfile index f74c1a15..d31bfc2a 100644 --- a/28/apache/Dockerfile +++ b/28/apache/Dockerfile @@ -15,7 +15,7 @@ RUN set -ex; \ rm -rf /var/lib/apt/lists/*; \ \ mkdir -p /var/spool/cron/crontabs; \ - echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/5 * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -45,11 +45,13 @@ RUN set -ex; \ ; \ \ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -138,7 +140,7 @@ RUN { \ } > /etc/apache2/conf-available/apache-limits.conf; \ a2enconf apache-limits -ENV NEXTCLOUD_VERSION 28.0.1 +ENV NEXTCLOUD_VERSION 28.0.8 RUN set -ex; \ fetchDeps=" \ @@ -148,8 +150,8 @@ RUN set -ex; \ apt-get update; \ apt-get install -y --no-install-recommends $fetchDeps; \ \ - curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-28.0.1.tar.bz2"; \ - curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-28.0.1.tar.bz2.asc"; \ + curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-28.0.8.tar.bz2"; \ + curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-28.0.8.tar.bz2.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ # gpg key from https://nextcloud.com/nextcloud.asc gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ @@ -165,7 +167,8 @@ RUN set -ex; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ rm -rf /var/lib/apt/lists/* -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/28/apache/config/redis.config.php b/28/apache/config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/28/apache/config/redis.config.php +++ b/28/apache/config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/28/apache/config/s3.config.php b/28/apache/config/s3.config.php index 6d0ede91..9941c562 100644 --- a/28/apache/config/s3.config.php +++ b/28/apache/config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/28/apache/config/smtp.config.php b/28/apache/config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/28/apache/config/smtp.config.php +++ b/28/apache/config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/28/apache/entrypoint.sh b/28/apache/entrypoint.sh index 5b627f07..ef80647a 100755 --- a/28/apache/entrypoint.sh +++ b/28/apache/entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/28/apache/occ b/28/apache/occ new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/28/apache/occ @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/28/apache/occ-cron b/28/apache/occ-cron new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/28/apache/occ-cron @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/28/fpm-alpine/Dockerfile b/28/fpm-alpine/Dockerfile index 1133744d..638a2584 100644 --- a/28/fpm-alpine/Dockerfile +++ b/28/fpm-alpine/Dockerfile @@ -1,16 +1,23 @@ # DO NOT EDIT: created by update.sh from Dockerfile-alpine.template -FROM php:8.2-fpm-alpine3.18 +FROM php:8.2-fpm-alpine3.20 # entrypoint.sh and cron.sh dependencies RUN set -ex; \ \ apk add --no-cache \ imagemagick \ + imagemagick-pdf \ + imagemagick-jpeg \ + imagemagick-raw \ + imagemagick-tiff \ + imagemagick-heic \ + imagemagick-webp \ + imagemagick-svg \ rsync \ ; \ \ rm /var/spool/cron/crontabs/root; \ - echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/5 * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -36,11 +43,13 @@ RUN set -ex; \ postgresql-dev \ ; \ \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -111,7 +120,7 @@ RUN { \ VOLUME /var/www/html -ENV NEXTCLOUD_VERSION 28.0.1 +ENV NEXTCLOUD_VERSION 28.0.8 RUN set -ex; \ apk add --no-cache --virtual .fetch-deps \ @@ -119,8 +128,8 @@ RUN set -ex; \ gnupg \ ; \ \ - curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-28.0.1.tar.bz2"; \ - curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-28.0.1.tar.bz2.asc"; \ + curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-28.0.8.tar.bz2"; \ + curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-28.0.8.tar.bz2.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ # gpg key from https://nextcloud.com/nextcloud.asc gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ @@ -134,7 +143,8 @@ RUN set -ex; \ chmod +x /usr/src/nextcloud/occ; \ apk del --no-network .fetch-deps -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/28/fpm-alpine/config/redis.config.php b/28/fpm-alpine/config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/28/fpm-alpine/config/redis.config.php +++ b/28/fpm-alpine/config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/28/fpm-alpine/config/s3.config.php b/28/fpm-alpine/config/s3.config.php index 6d0ede91..9941c562 100644 --- a/28/fpm-alpine/config/s3.config.php +++ b/28/fpm-alpine/config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/28/fpm-alpine/config/smtp.config.php b/28/fpm-alpine/config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/28/fpm-alpine/config/smtp.config.php +++ b/28/fpm-alpine/config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/28/fpm-alpine/entrypoint.sh b/28/fpm-alpine/entrypoint.sh index 5b627f07..ef80647a 100755 --- a/28/fpm-alpine/entrypoint.sh +++ b/28/fpm-alpine/entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/28/fpm-alpine/occ b/28/fpm-alpine/occ new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/28/fpm-alpine/occ @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/28/fpm-alpine/occ-cron b/28/fpm-alpine/occ-cron new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/28/fpm-alpine/occ-cron @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/28/fpm/Dockerfile b/28/fpm/Dockerfile index a4924ce8..f443ea82 100644 --- a/28/fpm/Dockerfile +++ b/28/fpm/Dockerfile @@ -15,7 +15,7 @@ RUN set -ex; \ rm -rf /var/lib/apt/lists/*; \ \ mkdir -p /var/spool/cron/crontabs; \ - echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/5 * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -45,11 +45,13 @@ RUN set -ex; \ ; \ \ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -123,7 +125,7 @@ RUN { \ VOLUME /var/www/html -ENV NEXTCLOUD_VERSION 28.0.1 +ENV NEXTCLOUD_VERSION 28.0.8 RUN set -ex; \ fetchDeps=" \ @@ -133,8 +135,8 @@ RUN set -ex; \ apt-get update; \ apt-get install -y --no-install-recommends $fetchDeps; \ \ - curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-28.0.1.tar.bz2"; \ - curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-28.0.1.tar.bz2.asc"; \ + curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-28.0.8.tar.bz2"; \ + curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-28.0.8.tar.bz2.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ # gpg key from https://nextcloud.com/nextcloud.asc gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ @@ -150,7 +152,8 @@ RUN set -ex; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ rm -rf /var/lib/apt/lists/* -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/28/fpm/config/redis.config.php b/28/fpm/config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/28/fpm/config/redis.config.php +++ b/28/fpm/config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/28/fpm/config/s3.config.php b/28/fpm/config/s3.config.php index 6d0ede91..9941c562 100644 --- a/28/fpm/config/s3.config.php +++ b/28/fpm/config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/28/fpm/config/smtp.config.php b/28/fpm/config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/28/fpm/config/smtp.config.php +++ b/28/fpm/config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/28/fpm/entrypoint.sh b/28/fpm/entrypoint.sh index 5b627f07..ef80647a 100755 --- a/28/fpm/entrypoint.sh +++ b/28/fpm/entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/28/fpm/occ b/28/fpm/occ new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/28/fpm/occ @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/28/fpm/occ-cron b/28/fpm/occ-cron new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/28/fpm/occ-cron @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/26/apache/Dockerfile b/29/apache/Dockerfile similarity index 93% rename from 26/apache/Dockerfile rename to 29/apache/Dockerfile index cc287529..8b9dc15f 100644 --- a/26/apache/Dockerfile +++ b/29/apache/Dockerfile @@ -15,7 +15,7 @@ RUN set -ex; \ rm -rf /var/lib/apt/lists/*; \ \ mkdir -p /var/spool/cron/crontabs; \ - echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/5 * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -45,11 +45,13 @@ RUN set -ex; \ ; \ \ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -138,7 +140,7 @@ RUN { \ } > /etc/apache2/conf-available/apache-limits.conf; \ a2enconf apache-limits -ENV NEXTCLOUD_VERSION 26.0.10 +ENV NEXTCLOUD_VERSION 29.0.4 RUN set -ex; \ fetchDeps=" \ @@ -148,8 +150,8 @@ RUN set -ex; \ apt-get update; \ apt-get install -y --no-install-recommends $fetchDeps; \ \ - curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-26.0.10.tar.bz2"; \ - curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-26.0.10.tar.bz2.asc"; \ + curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-29.0.4.tar.bz2"; \ + curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-29.0.4.tar.bz2.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ # gpg key from https://nextcloud.com/nextcloud.asc gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ @@ -165,7 +167,8 @@ RUN set -ex; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ rm -rf /var/lib/apt/lists/* -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/26/apache/config/apache-pretty-urls.config.php b/29/apache/config/apache-pretty-urls.config.php similarity index 100% rename from 26/apache/config/apache-pretty-urls.config.php rename to 29/apache/config/apache-pretty-urls.config.php diff --git a/26/apache/config/apcu.config.php b/29/apache/config/apcu.config.php similarity index 100% rename from 26/apache/config/apcu.config.php rename to 29/apache/config/apcu.config.php diff --git a/26/apache/config/apps.config.php b/29/apache/config/apps.config.php similarity index 100% rename from 26/apache/config/apps.config.php rename to 29/apache/config/apps.config.php diff --git a/26/apache/config/autoconfig.php b/29/apache/config/autoconfig.php similarity index 100% rename from 26/apache/config/autoconfig.php rename to 29/apache/config/autoconfig.php diff --git a/26/fpm/config/redis.config.php b/29/apache/config/redis.config.php similarity index 72% rename from 26/fpm/config/redis.config.php rename to 29/apache/config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/26/fpm/config/redis.config.php +++ b/29/apache/config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/26/apache/config/reverse-proxy.config.php b/29/apache/config/reverse-proxy.config.php similarity index 100% rename from 26/apache/config/reverse-proxy.config.php rename to 29/apache/config/reverse-proxy.config.php diff --git a/26/fpm-alpine/config/s3.config.php b/29/apache/config/s3.config.php similarity index 79% rename from 26/fpm-alpine/config/s3.config.php rename to 29/apache/config/s3.config.php index 6d0ede91..9941c562 100644 --- a/26/fpm-alpine/config/s3.config.php +++ b/29/apache/config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/26/apache/config/smtp.config.php b/29/apache/config/smtp.config.php similarity index 83% rename from 26/apache/config/smtp.config.php rename to 29/apache/config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/26/apache/config/smtp.config.php +++ b/29/apache/config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/26/apache/config/swift.config.php b/29/apache/config/swift.config.php similarity index 100% rename from 26/apache/config/swift.config.php rename to 29/apache/config/swift.config.php diff --git a/26/apache/config/upgrade-disable-web.config.php b/29/apache/config/upgrade-disable-web.config.php similarity index 100% rename from 26/apache/config/upgrade-disable-web.config.php rename to 29/apache/config/upgrade-disable-web.config.php diff --git a/26/apache/cron.sh b/29/apache/cron.sh similarity index 100% rename from 26/apache/cron.sh rename to 29/apache/cron.sh diff --git a/26/apache/entrypoint.sh b/29/apache/entrypoint.sh similarity index 87% rename from 26/apache/entrypoint.sh rename to 29/apache/entrypoint.sh index 5b627f07..ef80647a 100755 --- a/26/apache/entrypoint.sh +++ b/29/apache/entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/29/apache/occ b/29/apache/occ new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/29/apache/occ @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/29/apache/occ-cron b/29/apache/occ-cron new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/29/apache/occ-cron @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/26/apache/upgrade.exclude b/29/apache/upgrade.exclude similarity index 100% rename from 26/apache/upgrade.exclude rename to 29/apache/upgrade.exclude diff --git a/26/fpm-alpine/Dockerfile b/29/fpm-alpine/Dockerfile similarity index 88% rename from 26/fpm-alpine/Dockerfile rename to 29/fpm-alpine/Dockerfile index dce75c8b..d43b71fc 100644 --- a/26/fpm-alpine/Dockerfile +++ b/29/fpm-alpine/Dockerfile @@ -1,16 +1,23 @@ # DO NOT EDIT: created by update.sh from Dockerfile-alpine.template -FROM php:8.2-fpm-alpine3.18 +FROM php:8.2-fpm-alpine3.20 # entrypoint.sh and cron.sh dependencies RUN set -ex; \ \ apk add --no-cache \ imagemagick \ + imagemagick-pdf \ + imagemagick-jpeg \ + imagemagick-raw \ + imagemagick-tiff \ + imagemagick-heic \ + imagemagick-webp \ + imagemagick-svg \ rsync \ ; \ \ rm /var/spool/cron/crontabs/root; \ - echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/5 * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -36,11 +43,13 @@ RUN set -ex; \ postgresql-dev \ ; \ \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -111,7 +120,7 @@ RUN { \ VOLUME /var/www/html -ENV NEXTCLOUD_VERSION 26.0.10 +ENV NEXTCLOUD_VERSION 29.0.4 RUN set -ex; \ apk add --no-cache --virtual .fetch-deps \ @@ -119,8 +128,8 @@ RUN set -ex; \ gnupg \ ; \ \ - curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-26.0.10.tar.bz2"; \ - curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-26.0.10.tar.bz2.asc"; \ + curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-29.0.4.tar.bz2"; \ + curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-29.0.4.tar.bz2.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ # gpg key from https://nextcloud.com/nextcloud.asc gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ @@ -134,7 +143,8 @@ RUN set -ex; \ chmod +x /usr/src/nextcloud/occ; \ apk del --no-network .fetch-deps -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/26/fpm-alpine/config/apcu.config.php b/29/fpm-alpine/config/apcu.config.php similarity index 100% rename from 26/fpm-alpine/config/apcu.config.php rename to 29/fpm-alpine/config/apcu.config.php diff --git a/26/fpm-alpine/config/apps.config.php b/29/fpm-alpine/config/apps.config.php similarity index 100% rename from 26/fpm-alpine/config/apps.config.php rename to 29/fpm-alpine/config/apps.config.php diff --git a/26/fpm-alpine/config/autoconfig.php b/29/fpm-alpine/config/autoconfig.php similarity index 100% rename from 26/fpm-alpine/config/autoconfig.php rename to 29/fpm-alpine/config/autoconfig.php diff --git a/26/apache/config/redis.config.php b/29/fpm-alpine/config/redis.config.php similarity index 72% rename from 26/apache/config/redis.config.php rename to 29/fpm-alpine/config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/26/apache/config/redis.config.php +++ b/29/fpm-alpine/config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/26/fpm-alpine/config/reverse-proxy.config.php b/29/fpm-alpine/config/reverse-proxy.config.php similarity index 100% rename from 26/fpm-alpine/config/reverse-proxy.config.php rename to 29/fpm-alpine/config/reverse-proxy.config.php diff --git a/26/fpm/config/s3.config.php b/29/fpm-alpine/config/s3.config.php similarity index 79% rename from 26/fpm/config/s3.config.php rename to 29/fpm-alpine/config/s3.config.php index 6d0ede91..9941c562 100644 --- a/26/fpm/config/s3.config.php +++ b/29/fpm-alpine/config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/26/fpm/config/smtp.config.php b/29/fpm-alpine/config/smtp.config.php similarity index 83% rename from 26/fpm/config/smtp.config.php rename to 29/fpm-alpine/config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/26/fpm/config/smtp.config.php +++ b/29/fpm-alpine/config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/26/fpm-alpine/config/swift.config.php b/29/fpm-alpine/config/swift.config.php similarity index 100% rename from 26/fpm-alpine/config/swift.config.php rename to 29/fpm-alpine/config/swift.config.php diff --git a/26/fpm-alpine/config/upgrade-disable-web.config.php b/29/fpm-alpine/config/upgrade-disable-web.config.php similarity index 100% rename from 26/fpm-alpine/config/upgrade-disable-web.config.php rename to 29/fpm-alpine/config/upgrade-disable-web.config.php diff --git a/26/fpm-alpine/cron.sh b/29/fpm-alpine/cron.sh similarity index 100% rename from 26/fpm-alpine/cron.sh rename to 29/fpm-alpine/cron.sh diff --git a/26/fpm-alpine/entrypoint.sh b/29/fpm-alpine/entrypoint.sh similarity index 87% rename from 26/fpm-alpine/entrypoint.sh rename to 29/fpm-alpine/entrypoint.sh index 5b627f07..ef80647a 100755 --- a/26/fpm-alpine/entrypoint.sh +++ b/29/fpm-alpine/entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/29/fpm-alpine/occ b/29/fpm-alpine/occ new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/29/fpm-alpine/occ @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/29/fpm-alpine/occ-cron b/29/fpm-alpine/occ-cron new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/29/fpm-alpine/occ-cron @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/26/fpm-alpine/upgrade.exclude b/29/fpm-alpine/upgrade.exclude similarity index 100% rename from 26/fpm-alpine/upgrade.exclude rename to 29/fpm-alpine/upgrade.exclude diff --git a/26/fpm/Dockerfile b/29/fpm/Dockerfile similarity index 93% rename from 26/fpm/Dockerfile rename to 29/fpm/Dockerfile index 13250220..2fabf3ee 100644 --- a/26/fpm/Dockerfile +++ b/29/fpm/Dockerfile @@ -15,7 +15,7 @@ RUN set -ex; \ rm -rf /var/lib/apt/lists/*; \ \ mkdir -p /var/spool/cron/crontabs; \ - echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/5 * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -45,11 +45,13 @@ RUN set -ex; \ ; \ \ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -123,7 +125,7 @@ RUN { \ VOLUME /var/www/html -ENV NEXTCLOUD_VERSION 26.0.10 +ENV NEXTCLOUD_VERSION 29.0.4 RUN set -ex; \ fetchDeps=" \ @@ -133,8 +135,8 @@ RUN set -ex; \ apt-get update; \ apt-get install -y --no-install-recommends $fetchDeps; \ \ - curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-26.0.10.tar.bz2"; \ - curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-26.0.10.tar.bz2.asc"; \ + curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-29.0.4.tar.bz2"; \ + curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-29.0.4.tar.bz2.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ # gpg key from https://nextcloud.com/nextcloud.asc gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ @@ -150,7 +152,8 @@ RUN set -ex; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ rm -rf /var/lib/apt/lists/* -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/26/fpm/config/apcu.config.php b/29/fpm/config/apcu.config.php similarity index 100% rename from 26/fpm/config/apcu.config.php rename to 29/fpm/config/apcu.config.php diff --git a/26/fpm/config/apps.config.php b/29/fpm/config/apps.config.php similarity index 100% rename from 26/fpm/config/apps.config.php rename to 29/fpm/config/apps.config.php diff --git a/26/fpm/config/autoconfig.php b/29/fpm/config/autoconfig.php similarity index 100% rename from 26/fpm/config/autoconfig.php rename to 29/fpm/config/autoconfig.php diff --git a/26/fpm-alpine/config/redis.config.php b/29/fpm/config/redis.config.php similarity index 72% rename from 26/fpm-alpine/config/redis.config.php rename to 29/fpm/config/redis.config.php index a5fde3c7..a5b13da6 100644 --- a/26/fpm-alpine/config/redis.config.php +++ b/29/fpm/config/redis.config.php @@ -5,7 +5,7 @@ if (getenv('REDIS_HOST')) { 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => getenv('REDIS_HOST'), - 'password' => (string) getenv('REDIS_HOST_PASSWORD'), + 'password' => getenv('REDIS_HOST_PASSWORD_FILE') ? trim(file_get_contents(getenv('REDIS_HOST_PASSWORD_FILE'))) : (string) getenv('REDIS_HOST_PASSWORD'), ), ); diff --git a/26/fpm/config/reverse-proxy.config.php b/29/fpm/config/reverse-proxy.config.php similarity index 100% rename from 26/fpm/config/reverse-proxy.config.php rename to 29/fpm/config/reverse-proxy.config.php diff --git a/26/apache/config/s3.config.php b/29/fpm/config/s3.config.php similarity index 79% rename from 26/apache/config/s3.config.php rename to 29/fpm/config/s3.config.php index 6d0ede91..9941c562 100644 --- a/26/apache/config/s3.config.php +++ b/29/fpm/config/s3.config.php @@ -12,6 +12,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { 'region' => getenv('OBJECTSTORE_S3_REGION') ?: '', 'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '', 'port' => getenv('OBJECTSTORE_S3_PORT') ?: '', + 'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '', 'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:", 'autocreate' => (strtolower($autocreate) === 'false' || $autocreate == false) ? false : true, 'use_ssl' => (strtolower($use_ssl) === 'false' || $use_ssl == false) ? false : true, @@ -23,7 +24,7 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { ) ); - if (getenv('OBJECTSTORE_S3_KEY_FILE') && file_exists(getenv('OBJECTSTORE_S3_KEY_FILE'))) { + if (getenv('OBJECTSTORE_S3_KEY_FILE')) { $CONFIG['objectstore']['arguments']['key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_KEY_FILE'))); } elseif (getenv('OBJECTSTORE_S3_KEY')) { $CONFIG['objectstore']['arguments']['key'] = getenv('OBJECTSTORE_S3_KEY'); @@ -31,11 +32,17 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) { $CONFIG['objectstore']['arguments']['key'] = ''; } - if (getenv('OBJECTSTORE_S3_SECRET_FILE') && file_exists(getenv('OBJECTSTORE_S3_SECRET_FILE'))) { + if (getenv('OBJECTSTORE_S3_SECRET_FILE')) { $CONFIG['objectstore']['arguments']['secret'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SECRET_FILE'))); } elseif (getenv('OBJECTSTORE_S3_SECRET')) { $CONFIG['objectstore']['arguments']['secret'] = getenv('OBJECTSTORE_S3_SECRET'); } else { $CONFIG['objectstore']['arguments']['secret'] = ''; } -} + + if (getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = trim(file_get_contents(getenv('OBJECTSTORE_S3_SSE_C_KEY_FILE'))); + } elseif (getenv('OBJECTSTORE_S3_SSE_C_KEY')) { + $CONFIG['objectstore']['arguments']['sse_c_key'] = getenv('OBJECTSTORE_S3_SSE_C_KEY'); + } +} diff --git a/26/fpm-alpine/config/smtp.config.php b/29/fpm/config/smtp.config.php similarity index 83% rename from 26/fpm-alpine/config/smtp.config.php rename to 29/fpm/config/smtp.config.php index 5006fe47..66a2ef7e 100644 --- a/26/fpm-alpine/config/smtp.config.php +++ b/29/fpm/config/smtp.config.php @@ -5,14 +5,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) 'mail_smtphost' => getenv('SMTP_HOST'), 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', - 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE')))), + 'mail_smtpauth' => getenv('SMTP_NAME') && (getenv('SMTP_PASSWORD') || getenv('SMTP_PASSWORD_FILE')), 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 'mail_domain' => getenv('MAIL_DOMAIN'), ); - if (getenv('SMTP_PASSWORD_FILE') && file_exists(getenv('SMTP_PASSWORD_FILE'))) { + if (getenv('SMTP_PASSWORD_FILE')) { $CONFIG['mail_smtppassword'] = trim(file_get_contents(getenv('SMTP_PASSWORD_FILE'))); } elseif (getenv('SMTP_PASSWORD')) { $CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD'); diff --git a/26/fpm/config/swift.config.php b/29/fpm/config/swift.config.php similarity index 100% rename from 26/fpm/config/swift.config.php rename to 29/fpm/config/swift.config.php diff --git a/26/fpm/config/upgrade-disable-web.config.php b/29/fpm/config/upgrade-disable-web.config.php similarity index 100% rename from 26/fpm/config/upgrade-disable-web.config.php rename to 29/fpm/config/upgrade-disable-web.config.php diff --git a/26/fpm/cron.sh b/29/fpm/cron.sh similarity index 100% rename from 26/fpm/cron.sh rename to 29/fpm/cron.sh diff --git a/26/fpm/entrypoint.sh b/29/fpm/entrypoint.sh similarity index 87% rename from 26/fpm/entrypoint.sh rename to 29/fpm/entrypoint.sh index 5b627f07..ef80647a 100755 --- a/26/fpm/entrypoint.sh +++ b/29/fpm/entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/29/fpm/occ b/29/fpm/occ new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/29/fpm/occ @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/29/fpm/occ-cron b/29/fpm/occ-cron new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/29/fpm/occ-cron @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/26/fpm/upgrade.exclude b/29/fpm/upgrade.exclude similarity index 100% rename from 26/fpm/upgrade.exclude rename to 29/fpm/upgrade.exclude diff --git a/Dockerfile-alpine.template b/Dockerfile-alpine.template index 905077bc..b474b76b 100644 --- a/Dockerfile-alpine.template +++ b/Dockerfile-alpine.template @@ -5,11 +5,18 @@ RUN set -ex; \ \ apk add --no-cache \ imagemagick \ + imagemagick-pdf \ + imagemagick-jpeg \ + imagemagick-raw \ + imagemagick-tiff \ + imagemagick-heic \ + imagemagick-webp \ + imagemagick-svg \ rsync \ ; \ \ rm /var/spool/cron/crontabs/root; \ - echo '*/%%CRONTAB_INT%% * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/%%CRONTAB_INT%% * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -35,11 +42,13 @@ RUN set -ex; \ postgresql-dev \ ; \ \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -133,7 +142,8 @@ RUN set -ex; \ chmod +x /usr/src/nextcloud/occ; \ apk del --no-network .fetch-deps -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/Dockerfile-debian.template b/Dockerfile-debian.template index cea5d93b..65487f26 100644 --- a/Dockerfile-debian.template +++ b/Dockerfile-debian.template @@ -14,7 +14,7 @@ RUN set -ex; \ rm -rf /var/lib/apt/lists/*; \ \ mkdir -p /var/spool/cron/crontabs; \ - echo '*/%%CRONTAB_INT%% * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data + echo '*/%%CRONTAB_INT%% * * * * occ-cron' > /var/spool/cron/crontabs/www-data # install the PHP extensions we need # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html @@ -44,11 +44,13 @@ RUN set -ex; \ ; \ \ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ + docker-php-ext-configure ftp --with-openssl-dir=/usr; \ docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ + ftp \ gd \ gmp \ intl \ @@ -149,7 +151,8 @@ RUN set -ex; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ rm -rf /var/lib/apt/lists/* -COPY *.sh upgrade.exclude / +COPY entrypoint.sh cron.sh upgrade.exclude / +COPY occ occ-cron /usr/local/bin/ COPY config/* /usr/src/nextcloud/config/ ENTRYPOINT ["/entrypoint.sh"] diff --git a/README.md b/README.md index c759ecba..8760ee37 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ A safe home for all your data. Access & share your files, calendars, contacts, m ![logo](https://cdn.rawgit.com/nextcloud/docker/071b888f7f689caa62c1498b6c61cb3599bcea2b/logo.svg) -This Docker micro-service image is developed and maintained by the Nextcloud community. Nextcloud GmbH does not offer support for this Docker image. When you are looking to get professional support, you can become an [enterprise](https://nextcloud.com/enterprise/) customer or use [Nextcloud All-in-One docker image](https://github.com/nextcloud/all-in-one#nextcloud-all-in-one) - as the name suggests, Nextcloud All-in-One provides easy deployment and maintenance of Nextcloud Hub included in this one Nextcloud instance. +⚠️⚠️⚠️ This image is maintained by community volunteers and designed for expert use. For quick and easy deployment that supports the full set of Nextcloud Hub features, use the [Nextcloud All-in-One docker container](https://github.com/nextcloud/all-in-one#nextcloud-all-in-one) maintained by Nextcloud GmbH. # How to use this image This image is designed to be used in a micro-service environment. There are two versions of the image you can choose from. @@ -97,7 +97,7 @@ nextcloud ### Custom volumes If mounting additional volumes under `/var/www/html`, you should consider: -- Confirming that [upgrade.exclude](https://github.com/nextcloud/docker/blob/master/upgrade.exclude) contains the files and folders that should persist during installation and upgrades; or +- Confirming that [upgrade.exclude](https://github.com/nextcloud/docker/blob/master/upgrade.exclude) contains the files and folders that should persist during installation and upgrades; or - Mounting storage volumes to locations outside of `/var/www/html`. > [!WARNING] @@ -105,13 +105,13 @@ If mounting additional volumes under `/var/www/html`, you should consider: ## Using the Nextcloud command-line interface -To use the [Nextcloud command-line interface](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ_command.html) (aka. `occ` command): +To use the [Nextcloud command-line interface](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ_command.html) (aka. `occ` command), you can use a simple wrapper script provided by the Nextcloud image dealing with permissions: ```console -$ docker exec --user www-data CONTAINER_ID php occ +$ docker exec CONTAINER_ID occ ``` or for docker-compose: ```console -$ docker-compose exec --user www-data app php occ +$ docker-compose exec app occ ``` ## Auto configuration via environment variables @@ -163,7 +163,7 @@ If you want to use Redis you have to create a separate [Redis](https://hub.docke The use of Redis is recommended to prevent file locking problems. See the examples for further instructions. -To use an external SMTP server, you have to provide the connection details. To configure Nextcloud to use SMTP add: +To use an external SMTP server, you have to provide the connection details. Note that if you configure these values via Docker, you should **not** use the Nexcloud Web UI to configure external SMTP server parameters. Conversely, if you prefer to use the Web UI, do **not** set these variables here (because these variables will override whatever you attempt to set in the Web UI for these parameters). To configure Nextcloud to use SMTP add: - `SMTP_HOST` (not set by default): The hostname of the SMTP server. - `SMTP_SECURE` (empty by default): Set to `ssl` to use SSL, or `tls` to use STARTTLS. @@ -179,17 +179,19 @@ At least `SMTP_HOST`, `MAIL_FROM_ADDRESS` and `MAIL_DOMAIN` must be set for the Check the [Nextcloud documentation](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/email_configuration.html) for other values to configure SMTP. To use an external S3 compatible object store as primary storage, set the following variables: -- `OBJECTSTORE_S3_HOST`: The hostname of the object storage server - `OBJECTSTORE_S3_BUCKET`: The name of the bucket that Nextcloud should store the data in +- `OBJECTSTORE_S3_REGION`: The region that the S3 bucket resides in +- `OBJECTSTORE_S3_HOST`: The hostname of the object storage server +- `OBJECTSTORE_S3_PORT`: The port that the object storage server is being served over - `OBJECTSTORE_S3_KEY`: AWS style access key - `OBJECTSTORE_S3_SECRET`: AWS style secret access key -- `OBJECTSTORE_S3_PORT`: The port that the object storage server is being served over +- `OBJECTSTORE_S3_STORAGE_CLASS`: The storage class to use when adding objects to the bucket - `OBJECTSTORE_S3_SSL` (default: `true`): Whether or not SSL/TLS should be used to communicate with object storage server -- `OBJECTSTORE_S3_REGION`: The region that the S3 bucket resides in. - `OBJECTSTORE_S3_USEPATH_STYLE` (default: `false`): Not required for AWS S3 - `OBJECTSTORE_S3_LEGACYAUTH` (default: `false`): Not required for AWS S3 - `OBJECTSTORE_S3_OBJECT_PREFIX` (default: `urn:oid:`): Prefix to prepend to the fileid - `OBJECTSTORE_S3_AUTOCREATE` (default: `true`): Create the container if it does not exist +- `OBJECTSTORE_S3_SSE_C_KEY` (not set by default): Base64 encoded key with a maximum length of 32 bytes for server side encryption (SSE-C) Check the [Nextcloud documentation](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/primary_storage.html#simple-storage-service-s3) for more information. @@ -212,9 +214,21 @@ To customize other PHP limits you can simply change the following variables: - `PHP_UPLOAD_LIMIT` (default `512M`) This sets the upload limit (`post_max_size` and `upload_max_filesize`) for big files. Note that you may have to change other limits depending on your client, webserver or operating system. Check the [Nextcloud documentation](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/big_file_upload_configuration.html) for more information. To customize Apache max file upload limit you can change the following variable: -- `APACHE_BODY_LIMIT` (default `1073741824` [1GiB]) This restricts the total +- `APACHE_BODY_LIMIT` (default `1073741824` [1GiB]) This restricts the total size of the HTTP request body sent from the client. It specifies the number of _bytes_ that are allowed in a request body. A value of **0** means **unlimited**. Check the [Nextcloud documentation](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/big_file_upload_configuration.html#apache) for more information. +### Auto configuration and Nextcloud updates +The image comes with special config files for Nextcloud that set parameters specific to containerized usage (e.g. `upgrade-disable-web.config.php`) or enable auto configuration via environment variables (e.g. `reverse-proxy.config.php`). Within the image, the latest version of these config files are located in `/usr/src/nextcloud/config`. + +During a fresh Nextcloud installation, the latest version (from the image) of these files are copied into `/var/www/html/config` so that they are stored within your container's persistent volume and picked up by Nextcloud alongside your local configuration. + +The copied files, however, are **not** automatically overwritten whenever you update your environment with a newer Nextcloud image. This is to prevent local changes in `/var/www/html/config` from being unexpectedly overwritten. This may lead to your image-specific configuration files becoming outdated and image functionality not matching that which is documented. + +A warning will be generated in the container log output when outdated image-specific configuration files are detected at startup in a running container. When you see this warning, you should manually compare (or copy) the files from `/usr/src/nextcloud/config` to `/var/www/html/config`. + +As long as you have not modified any of the provided config files in `/var/www/html/config` (other than `config.php`) or only added new ones with names that do not conflict with the image specific ones, copying the new ones into place should be safe (but check the source path `/usr/src/nextcloud/config` for any newly named config files to avoid new overlaps just in case). + +Not keeping these files up-to-date when this warning appears may cause certain auto configuration environment variables to be ignored or the image to not work as documented or expected. ## Auto configuration via hook folders @@ -318,7 +332,7 @@ services: Then run `docker-compose up -d`, now you can access Nextcloud at http://localhost:8080/ from your host system. ## Base version - FPM -When using the FPM image, you need another container that acts as web server on port 80 and proxies the requests to the Nextcloud container. In this example a simple nginx container is combined with the Nextcloud-fpm image and a MariaDB database container. The data is stored in docker volumes. The nginx container also needs access to static files from your Nextcloud installation. It gets access to all the volumes mounted to Nextcloud via the `volumes_from` option.The configuration for nginx is stored in the configuration file `nginx.conf`, that is mounted into the container. An example can be found in the examples section [here](https://github.com/nextcloud/docker/tree/master/.examples). +When using the FPM image, you need another container that acts as web server on port 80 and proxies the requests to the Nextcloud container. In this example a simple nginx container is combined with the Nextcloud-fpm image and a MariaDB database container. The data is stored in docker volumes. The nginx container also needs access to static files from your Nextcloud installation. It gets access to all the volumes mounted to Nextcloud via the `volumes_from` option. The configuration for nginx is stored in the configuration file `nginx.conf`, that is mounted into the container. An example can be found in the examples section [here](https://github.com/nextcloud/docker/tree/master/.examples). As this setup does **not include encryption**, it should be run behind a proxy. @@ -600,5 +614,12 @@ You're already using Nextcloud and want to switch to docker? Great! Here are som docker-compose exec app chown -R www-data:www-data /var/www/html/custom_apps ``` -# Questions / Issues -If you got any questions or problems using the image, please visit our [Github Repository](https://github.com/nextcloud/docker) and write an issue. +# Help (Questions / Issues) + +**If you have any questions or problems while using the image, please ask for assistance on the Help Forum first (https://help.nextcloud.com)**. + +Also, most Nextcloud Server matters are covered in the [Nextcloud Admin Manual](https://docs.nextcloud.com/server/latest/admin_manual/) which is routinely updated. + +If you believe you've found a bug (or have an enhancement idea) in the image itself, please [search for already reported bugs and enhancement ideas](https://github.com/nextcloud/docker/issues). If there is an existing open issue, you can either add to the discussion there or upvote to indicate you're impacted by (or interested in) the same issue. If you believe you've found a new bug, please create a new Issue so that others can try to reproduce it and remediation can be tracked. + +Thanks for helping to make the Nextcloud community maintained micro-services image better! diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 5b627f07..ef80647a 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -11,14 +11,6 @@ directory_empty() { [ -z "$(ls -A "$1/")" ] } -run_as() { - if [ "$(id -u)" = 0 ]; then - su -p "$user" -s /bin/sh -c "$1" - else - sh -c "$1" - fi -} - # Execute all executable files in a given directory in alphanumeric order run_path() { local hook_folder_path="/docker-entrypoint-hooks.d/$1" @@ -40,7 +32,11 @@ run_path() { echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\"" - run_as "${script_file_path}" || return_code="$?" + if [ "$(id -u)" = 0 ]; then + su -p "$user" -s /bin/sh "${script_file_path}" || return_code="$?" + else + "${script_file_path}" || return_code="$?" + fi if [ "${return_code}" -ne "0" ]; then echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}" @@ -163,7 +159,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP exit 1 fi echo "Upgrading nextcloud from $installed_version ..." - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before fi if [ "$(id -u)" = 0 ]; then rsync_options="-rlDog --chown $user:$group" @@ -186,6 +182,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env NEXTCLOUD_ADMIN_PASSWORD file_env NEXTCLOUD_ADMIN_USER + install=false if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then # shellcheck disable=SC2016 install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' @@ -201,7 +198,6 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP file_env POSTGRES_PASSWORD file_env POSTGRES_USER - install=false if [ -n "${SQLITE_DATABASE+x}" ]; then echo "Installing with SQLite database" # shellcheck disable=SC2016 @@ -225,7 +221,7 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP echo "Starting nextcloud installation" max_retries=10 try=0 - until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] + until [ "$try" -gt "$max_retries" ] || eval "occ maintenance:install $install_options" do echo "Retrying install..." try=$((try+1)) @@ -240,23 +236,26 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP NC_TRUSTED_DOMAIN_IDX=1 for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') - run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" + occ config:system:set trusted_domains "$NC_TRUSTED_DOMAIN_IDX" --value="$DOMAIN" NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX+1)) done fi run_path post-installation - else - echo "Please run the web-based installer on first connect!" - fi + fi + fi + # not enough specified to do a fully automated installation + if [ "$install" = false ]; then + echo "Next step: Access your instance to finish the web-based installation!" + echo "Hint: You can specify NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD and the database variables _prior to first launch_ to fully automate initial installation." fi # Upgrade else run_path pre-upgrade - run_as 'php /var/www/html/occ upgrade' + occ upgrade - run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after + occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after echo "The following apps have been disabled:" diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 rm -f /tmp/list_before /tmp/list_after @@ -269,10 +268,21 @@ if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UP # Update htaccess after init if requested if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then - run_as 'php /var/www/html/occ maintenance:update:htaccess' + occ maintenance:update:htaccess fi ) 9> /var/www/html/nextcloud-init-sync.lock + # warn if config files on persistent storage differ from the latest version of this image + for cfgPath in /usr/src/nextcloud/config/*.php; do + cfgFile=$(basename "$cfgPath") + + if [ "$cfgFile" != "config.sample.php" ]; then + if ! cmp -s "/usr/src/nextcloud/config/$cfgFile" "/var/www/html/config/$cfgFile"; then + echo "Warning: /var/www/html/config/$cfgFile differs from the latest version of this image at /usr/src/nextcloud/config/$cfgFile" + fi + fi + done + run_path before-starting fi diff --git a/docker-occ-cron.sh b/docker-occ-cron.sh new file mode 100755 index 00000000..798cc175 --- /dev/null +++ b/docker-occ-cron.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +if [ "$(occ status 2> /dev/null | sed -ne 's/^ - installed: \(.*\)$/\1/p')" != "true" ]; then + echo "Nextcloud is not installed - cronjobs are not available" >&2 + exit 1 +fi + +[ -e /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/cron.php ] || { echo "Unable to run \`occ-cron\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/cron.php)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ-cron\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/cron.php' -- '/bin/sh' +else + exec php -f /var/www/html/cron.php +fi diff --git a/docker-occ.sh b/docker-occ.sh new file mode 100755 index 00000000..70b08e7d --- /dev/null +++ b/docker-occ.sh @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +[ -e /var/www/html/occ ] || { echo "Unable to run \`occ\`: No such file or directory" >&2 ; exit 1 ; } +[ -f /var/www/html/occ ] || { echo "Unable to run \`occ\`: Not a file" >&2 ; exit 1 ; } + +RUN_AS="$(stat -c %U /var/www/html/occ)" +[ -n "$RUN_AS" ] && [ "$RUN_AS" != "UNKNOWN" ] || { echo "Unable to run \`occ\`: Failed to determine www-data user" >&2 ; exit 1 ; } + +if [ "$(id -u)" = 0 ]; then + exec su -p "$RUN_AS" -s /bin/sh -c 'exec php -f /var/www/html/occ -- "$@"' -- '/bin/sh' "$@" +else + exec php -f /var/www/html/occ -- "$@" +fi diff --git a/generate-stackbrew-library.sh b/generate-stackbrew-library.sh index 62c5ce4a..8eaaea3b 100755 --- a/generate-stackbrew-library.sh +++ b/generate-stackbrew-library.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -Eeuo pipefail -stable_channel='27.1.5' +stable_channel='29.0.4' self="$(basename "$BASH_SOURCE")" cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" diff --git a/latest.txt b/latest.txt index eebc120d..fad4b91c 100644 --- a/latest.txt +++ b/latest.txt @@ -1 +1 @@ -28.0.1 +29.0.4 diff --git a/update.sh b/update.sh index 9556d8ce..c2852200 100755 --- a/update.sh +++ b/update.sh @@ -2,7 +2,7 @@ set -eo pipefail declare -A alpine_version=( - [default]='3.18' + [default]='3.20' ) declare -A debian_version=( @@ -84,7 +84,7 @@ variants=( fpm-alpine ) -min_version='26' +min_version='27' # version_greater_or_equal A B returns whether A >= B function version_greater_or_equal() { @@ -128,9 +128,10 @@ function create_variant() { ' "$dir/Dockerfile" # Copy the shell scripts - for name in entrypoint cron; do - cp "docker-$name.sh" "$dir/$name.sh" - done + cp "docker-entrypoint.sh" "$dir/entrypoint.sh" + cp "docker-cron.sh" "$dir/cron.sh" + cp "docker-occ.sh" "$dir/occ" + cp "docker-occ-cron.sh" "$dir/occ-cron" # Copy the upgrade.exclude cp upgrade.exclude "$dir/" diff --git a/versions.json b/versions.json index b0797107..7174afbd 100644 --- a/versions.json +++ b/versions.json @@ -1,9 +1,9 @@ { - "28": { - "branch": "28", - "version": "28.0.1", - "url": "https://download.nextcloud.com/server/releases/nextcloud-28.0.1.tar.bz2", - "ascUrl": "https://download.nextcloud.com/server/releases/nextcloud-28.0.1.tar.bz2.asc", + "29": { + "branch": "29", + "version": "29.0.4", + "url": "https://download.nextcloud.com/server/releases/nextcloud-29.0.4.tar.bz2", + "ascUrl": "https://download.nextcloud.com/server/releases/nextcloud-29.0.4.tar.bz2.asc", "variants": { "apache": { "variant": "apache", @@ -20,16 +20,42 @@ "fpm-alpine": { "variant": "fpm-alpine", "base": "alpine", - "baseVersion": "3.18", + "baseVersion": "3.20", + "phpVersion": "8.2" + } + } + }, + "28": { + "branch": "28", + "version": "28.0.8", + "url": "https://download.nextcloud.com/server/releases/nextcloud-28.0.8.tar.bz2", + "ascUrl": "https://download.nextcloud.com/server/releases/nextcloud-28.0.8.tar.bz2.asc", + "variants": { + "apache": { + "variant": "apache", + "base": "debian", + "baseVersion": "bookworm", + "phpVersion": "8.2" + }, + "fpm": { + "variant": "fpm", + "base": "debian", + "baseVersion": "bookworm", + "phpVersion": "8.2" + }, + "fpm-alpine": { + "variant": "fpm-alpine", + "base": "alpine", + "baseVersion": "3.20", "phpVersion": "8.2" } } }, "27": { "branch": "27", - "version": "27.1.5", - "url": "https://download.nextcloud.com/server/releases/nextcloud-27.1.5.tar.bz2", - "ascUrl": "https://download.nextcloud.com/server/releases/nextcloud-27.1.5.tar.bz2.asc", + "version": "27.1.11", + "url": "https://download.nextcloud.com/server/releases/nextcloud-27.1.11.tar.bz2", + "ascUrl": "https://download.nextcloud.com/server/releases/nextcloud-27.1.11.tar.bz2.asc", "variants": { "apache": { "variant": "apache", @@ -46,33 +72,7 @@ "fpm-alpine": { "variant": "fpm-alpine", "base": "alpine", - "baseVersion": "3.18", - "phpVersion": "8.2" - } - } - }, - "26": { - "branch": "26", - "version": "26.0.10", - "url": "https://download.nextcloud.com/server/releases/nextcloud-26.0.10.tar.bz2", - "ascUrl": "https://download.nextcloud.com/server/releases/nextcloud-26.0.10.tar.bz2.asc", - "variants": { - "apache": { - "variant": "apache", - "base": "debian", - "baseVersion": "bookworm", - "phpVersion": "8.2" - }, - "fpm": { - "variant": "fpm", - "base": "debian", - "baseVersion": "bookworm", - "phpVersion": "8.2" - }, - "fpm-alpine": { - "variant": "fpm-alpine", - "base": "alpine", - "baseVersion": "3.18", + "baseVersion": "3.20", "phpVersion": "8.2" } }