From a73765ae5bf9183baedf2fec780b384fff266a35 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 7 Oct 2026 22:31:26 +0000 Subject: [PATCH 01/13] feat(images): unify app release and daily build sources Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .docker/app/Dockerfile | 48 ++++++++++++++++++++++++++++++++------- .docker/app/Dockerfile.35 | 40 -------------------------------- Makefile | 6 ++--- docker-compose.yml | 4 ++-- 4 files changed, 45 insertions(+), 53 deletions(-) delete mode 100644 .docker/app/Dockerfile.35 diff --git a/.docker/app/Dockerfile b/.docker/app/Dockerfile index 6ca75aa..7936c7a 100644 --- a/.docker/app/Dockerfile +++ b/.docker/app/Dockerfile @@ -1,9 +1,39 @@ -ARG NEXTCLOUD_VERSION=stable-fpm +ARG NEXTCLOUD_BASE_IMAGE=nextcloud:stable-fpm -FROM nextcloud:${NEXTCLOUD_VERSION} +FROM ${NEXTCLOUD_BASE_IMAGE} + +ARG NEXTCLOUD_SOURCE=release +ARG NEXTCLOUD_DAILY_URL= +ARG PHP_EXTENSION_INSTALLER_VERSION=2.12.0 +ARG PHP_EXTENSION_INSTALLER_SHA256=3f49c71fa66c79b8b2b96bc0ce92885dafd7946f3b5a46f545b390d6f1617e2c + +RUN set -eux; \ + case "${NEXTCLOUD_SOURCE}" in \ + release) \ + ;; \ + daily) \ + test -n "${NEXTCLOUD_DAILY_URL}"; \ + archive_name="$(basename "${NEXTCLOUD_DAILY_URL}")"; \ + curl -fsSL "${NEXTCLOUD_DAILY_URL}" -o "/tmp/${archive_name}"; \ + curl -fsSL "${NEXTCLOUD_DAILY_URL}.sha512" -o "/tmp/${archive_name}.sha512"; \ + expected_sha512="$(awk -v archive="${archive_name}" '$2 == archive { print $1; exit }' "/tmp/${archive_name}.sha512")"; \ + test -n "${expected_sha512}"; \ + echo "${expected_sha512} /tmp/${archive_name}" | sha512sum -c -; \ + rm -rf /usr/src/nextcloud; \ + tar -xjf "/tmp/${archive_name}" -C /usr/src/; \ + rm -f "/tmp/${archive_name}" "/tmp/${archive_name}.sha512"; \ + rm -rf /usr/src/nextcloud/updater; \ + mkdir -p /usr/src/nextcloud/data /usr/src/nextcloud/custom_apps; \ + chmod +x /usr/src/nextcloud/occ; \ + ;; \ + *) \ + echo "Unsupported NEXTCLOUD_SOURCE: ${NEXTCLOUD_SOURCE}" >&2; \ + exit 2; \ + ;; \ + esac RUN apt-get update \ - && apt-get install -y \ + && apt-get install -y --no-install-recommends \ gzip \ locales \ postgresql-client \ @@ -16,10 +46,12 @@ ENV LANG=en_US.UTF-8 ENV LANGUAGE=en_US:en ENV LC_ALL=en_US.UTF-8 -ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ -RUN chmod uga+x /usr/local/bin/install-php-extensions && sync \ - && install-php-extensions \ - bz2 \ - imagick +RUN set -eux; \ + curl -fsSL \ + "https://github.com/mlocati/docker-php-extension-installer/releases/download/${PHP_EXTENSION_INSTALLER_VERSION}/install-php-extensions" \ + -o /usr/local/bin/install-php-extensions; \ + echo "${PHP_EXTENSION_INSTALLER_SHA256} /usr/local/bin/install-php-extensions" | sha256sum -c -; \ + chmod uga+x /usr/local/bin/install-php-extensions; \ + install-php-extensions bz2 imagick COPY config/php.ini /usr/local/etc/php/conf.d/ diff --git a/.docker/app/Dockerfile.35 b/.docker/app/Dockerfile.35 deleted file mode 100644 index b3b078b..0000000 --- a/.docker/app/Dockerfile.35 +++ /dev/null @@ -1,40 +0,0 @@ -ARG NEXTCLOUD_BASE_IMAGE=nextcloud:34-fpm - -FROM ${NEXTCLOUD_BASE_IMAGE} - -ARG NEXTCLOUD_DAILY_URL=https://download.nextcloud.com/server/daily/latest-master.tar.bz2 - -RUN set -eux; \ - curl -fsSL "${NEXTCLOUD_DAILY_URL}" -o /tmp/nextcloud.tar.bz2; \ - curl -fsSL "${NEXTCLOUD_DAILY_URL}.sha512" -o /tmp/nextcloud.tar.bz2.sha512; \ - cd /tmp; \ - expected_sha512="$(awk '$2 == "latest-master.tar.bz2" { print $1 }' nextcloud.tar.bz2.sha512)"; \ - test -n "${expected_sha512}"; \ - echo "${expected_sha512} nextcloud.tar.bz2" | sha512sum -c -; \ - rm -rf /usr/src/nextcloud; \ - tar -xjf nextcloud.tar.bz2 -C /usr/src/; \ - nextcloud_major="$(php -r 'require "/usr/src/nextcloud/version.php"; echo $OC_Version[0];')"; \ - test "${nextcloud_major}" = 35; \ - rm -f /tmp/nextcloud.tar.bz2 /tmp/nextcloud.tar.bz2.sha512; \ - rm -rf /usr/src/nextcloud/updater; \ - mkdir -p /usr/src/nextcloud/data /usr/src/nextcloud/custom_apps; \ - chmod +x /usr/src/nextcloud/occ - -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - locales \ - poppler-utils \ - postgresql-client \ - && sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \ - && locale-gen \ - && rm -rf /var/lib/apt/lists/* - -ENV LANG=en_US.UTF-8 -ENV LANGUAGE=en_US:en -ENV LC_ALL=en_US.UTF-8 - -ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ -RUN chmod uga+x /usr/local/bin/install-php-extensions && sync \ - && install-php-extensions bz2 imagick - -COPY config/php.ini /usr/local/etc/php/conf.d/ diff --git a/Makefile b/Makefile index 16e5fcc..879d763 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ test-current-app-image: version="$$(sed -n 's/^NEXTCLOUD_VERSION=//p' .env.example | head -n 1)"; \ test -n "$$version" || { echo 'NEXTCLOUD_VERSION is missing from .env.example' >&2; exit 1; }; \ docker buildx build --platform linux/amd64 --load --tag "$(APP_TEST_IMAGE)" \ - --build-arg "NEXTCLOUD_VERSION=$$version" --file .docker/app/Dockerfile .docker/app; \ + --build-arg "NEXTCLOUD_BASE_IMAGE=nextcloud:$version" --file .docker/app/Dockerfile .docker/app; \ $(MAKE) test-app-image APP_IMAGE="$(APP_TEST_IMAGE)" scan-images: @@ -53,9 +53,9 @@ scan-images: version="$$(sed -n 's/^NEXTCLOUD_VERSION=//p' .env.example | head -n 1)"; \ test -n "$$version" || { echo 'NEXTCLOUD_VERSION is missing from .env.example' >&2; exit 1; }; \ docker buildx build --platform linux/amd64 --load --tag nextcloud-app:scan-amd64 \ - --build-arg "NEXTCLOUD_VERSION=$$version" --file .docker/app/Dockerfile .docker/app; \ + --build-arg "NEXTCLOUD_BASE_IMAGE=nextcloud:$version" --file .docker/app/Dockerfile .docker/app; \ docker buildx build --platform linux/arm64 --load --tag nextcloud-app:scan-arm64 \ - --build-arg "NEXTCLOUD_VERSION=$$version" --file .docker/app/Dockerfile .docker/app; \ + --build-arg "NEXTCLOUD_BASE_IMAGE=nextcloud:$version" --file .docker/app/Dockerfile .docker/app; \ docker buildx build --platform linux/amd64 --load --tag nextcloud-web:scan-amd64 \ --file .docker/web/Dockerfile .docker/web; \ docker buildx build --platform linux/arm64 --load --tag nextcloud-web:scan-arm64 \ diff --git a/docker-compose.yml b/docker-compose.yml index 736eb46..b9c2385 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,7 +16,7 @@ services: build: context: .docker/app args: - NEXTCLOUD_VERSION: ${NEXTCLOUD_VERSION:-stable-fpm} + NEXTCLOUD_BASE_IMAGE: nextcloud:${NEXTCLOUD_VERSION:-stable-fpm} volumes: - ./volumes/nextcloud:/var/www/html - ./volumes/backups:/backups @@ -70,7 +70,7 @@ services: build: context: .docker/app args: - NEXTCLOUD_VERSION: ${NEXTCLOUD_VERSION:-stable-fpm} + NEXTCLOUD_BASE_IMAGE: nextcloud:${NEXTCLOUD_VERSION:-stable-fpm} restart: unless-stopped environment: - TZ From 5eb7d7a339867d99f73f56cc9ca38d8b9a88b962 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 7 Oct 2026 22:32:20 +0000 Subject: [PATCH 02/13] ci(images): validate master with the generic app foundation Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .github/actions/build-and-scan/action.yml | 4 +- .../workflows/nextcloud-35-development.yml | 52 ---------- .github/workflows/nextcloud-development.yml | 96 +++++++++++++++++++ 3 files changed, 98 insertions(+), 54 deletions(-) delete mode 100644 .github/workflows/nextcloud-35-development.yml create mode 100644 .github/workflows/nextcloud-development.yml diff --git a/.github/actions/build-and-scan/action.yml b/.github/actions/build-and-scan/action.yml index f633326..0e8a3e5 100644 --- a/.github/actions/build-and-scan/action.yml +++ b/.github/actions/build-and-scan/action.yml @@ -30,7 +30,7 @@ runs: platforms: linux/amd64 load: true build-args: | - NEXTCLOUD_VERSION=${{ inputs.nextcloud_version }} + NEXTCLOUD_BASE_IMAGE=nextcloud:${{ inputs.nextcloud_version }} tags: scan/app:amd64 cache-from: type=gha cache-to: type=gha,mode=max @@ -42,7 +42,7 @@ runs: platforms: linux/arm64 load: true build-args: | - NEXTCLOUD_VERSION=${{ inputs.nextcloud_version }} + NEXTCLOUD_BASE_IMAGE=nextcloud:${{ inputs.nextcloud_version }} tags: scan/app:arm64 cache-from: type=gha cache-to: type=gha,mode=max diff --git a/.github/workflows/nextcloud-35-development.yml b/.github/workflows/nextcloud-35-development.yml deleted file mode 100644 index 388676e..0000000 --- a/.github/workflows/nextcloud-35-development.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Build Nextcloud 35 Development Image - -on: - workflow_dispatch: - push: - branches: - - main - paths: - - .docker/app/Dockerfile.35 - - .docker/app/config/** - - .github/workflows/nextcloud-35-development.yml - -concurrency: - group: nextcloud-35-development - cancel-in-progress: true - -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }}-app - -jobs: - build: - name: Build and push app:35 - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push Nextcloud 35 development image - uses: docker/build-push-action@v6 - with: - context: .docker/app - file: .docker/app/Dockerfile.35 - platforms: linux/amd64 - push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:35 - cache-from: type=gha,scope=nextcloud-35-development - cache-to: type=gha,mode=max,scope=nextcloud-35-development diff --git a/.github/workflows/nextcloud-development.yml b/.github/workflows/nextcloud-development.yml new file mode 100644 index 0000000..9f16dc5 --- /dev/null +++ b/.github/workflows/nextcloud-development.yml @@ -0,0 +1,96 @@ +name: Validate Nextcloud master image + +on: + pull_request: + branches: + - main + paths: + - '.docker/app/**' + - 'tests/app-image.bats' + - 'scripts/scan-images.sh' + - 'trivy.yaml' + - '.github/workflows/nextcloud-development.yml' + push: + branches: + - main + paths: + - '.docker/app/**' + - 'tests/app-image.bats' + - 'scripts/scan-images.sh' + - 'trivy.yaml' + - '.github/workflows/nextcloud-development.yml' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: nextcloud-master-validation-${{ github.ref }} + cancel-in-progress: true + +jobs: + validate: + name: master-fpm / linux/${{ matrix.arch }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + arch: + - amd64 + - arm64 + + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Set up QEMU + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3 + with: + platforms: arm64 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + + - name: Setup Bats + uses: bats-core/bats-action@77d6fb60505b4d0d1d73e48bd035b55074bbfb43 # 4.0.0 + with: + support-install: false + assert-install: false + detik-install: false + file-install: false + + - name: Build Nextcloud master app image + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + with: + context: .docker/app + platforms: linux/${{ matrix.arch }} + load: true + build-args: | + NEXTCLOUD_BASE_IMAGE=nextcloud:stable-fpm + NEXTCLOUD_SOURCE=daily + NEXTCLOUD_DAILY_URL=https://download.nextcloud.com/server/daily/latest-master.tar.bz2 + tags: scan/master:${{ matrix.arch }} + cache-from: type=gha,scope=master-${{ matrix.arch }} + cache-to: type=gha,mode=max,scope=master-${{ matrix.arch }} + + - name: Install Trivy + uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 + with: + version: v0.74.0 + cache: true + + - name: Scan Nextcloud master app image + shell: bash + env: + ARCH: ${{ matrix.arch }} + run: | + bash scripts/scan-images.sh "app@linux/${ARCH}=scan/master:${ARCH}" + + - name: Runtime acceptance + shell: bash + env: + APP_IMAGE: scan/master:${{ matrix.arch }} + run: bats tests/app-image.bats From 8843e764dc60d207b835f11e9ef45e7fda0f36d0 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 7 Oct 2026 22:32:55 +0000 Subject: [PATCH 03/13] docs(images): describe the generic app build foundation Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- docs/images.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/docs/images.md b/docs/images.md index a04aa50..e5d93ba 100644 --- a/docs/images.md +++ b/docs/images.md @@ -149,6 +149,23 @@ Immutable web image: ghcr.io/librecodecoop/nextcloud-docker-web@sha256: ``` +## App image build sources + +The app image uses a single `.docker/app/Dockerfile` for both release and development builds. + +The Dockerfile has two explicit source modes: + +- `NEXTCLOUD_SOURCE=release` keeps the Nextcloud payload provided by the selected official Nextcloud base image; +- `NEXTCLOUD_SOURCE=daily` replaces that payload with a verified upstream daily archive. + +The base runtime and the Nextcloud server payload are separate inputs. A development build can therefore follow Nextcloud Server `master` without introducing a Dockerfile or image identity tied to a future major. + +For daily builds, `NEXTCLOUD_DAILY_URL` is required. The Dockerfile downloads the matching `.sha512` file, verifies the archive, and prepares `/usr/src/nextcloud` in the layout expected by the official Nextcloud entrypoint. + +The repository Compose environment keeps `NEXTCLOUD_VERSION` as its user-facing version setting and maps it to the generic official base image. There is no second Compose stack for development images. + +The external PHP extension installer is pinned to an explicit release and SHA-256 instead of a mutable `latest` download. + ## Runtime acceptance The app image has a runtime acceptance test based on the same behavioral checks used by the official Nextcloud container projects. @@ -171,12 +188,12 @@ CI must run this test against the exact locally loaded app images produced by th ## Implementation boundary -This document defines the target contract. It does not by itself migrate the current Dockerfiles, workflows, or historical tags. +This document defines the target contract and the generic app-image foundation now implements the release/daily source split. -The image-foundation work in #47 must implement this convention incrementally. In particular: +Remaining work in #47 must continue incrementally. In particular: -- use one generic app image build path instead of a Dockerfile per Nextcloud major; -- keep the development channel tied to Nextcloud Server `master`; +- publish development images from the generic foundation using the documented `:master-fpm` contract; +- add the remaining OCI traceability metadata to published images; - keep LibreSign-specific behavior out of the generic runtime; -- test and scan images before publication; -- preserve the existing Compose environment until its replacement path is validated. +- preserve scan and runtime-acceptance gates before publication; +- preserve the existing Compose environment until a replacement is explicitly validated. From 588f4dbadceae1355dfc24abfc08194f727b546a Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 01:40:43 +0000 Subject: [PATCH 04/13] refactor(images): simplify build sources and automate dependency updates Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .docker/app/Dockerfile | 58 ++++++++------------- .github/actions/build-and-scan/action.yml | 1 + .github/workflows/nextcloud-development.yml | 1 + docs/images.md | 8 +-- renovate.json | 39 ++++++++++++++ 5 files changed, 68 insertions(+), 39 deletions(-) create mode 100644 renovate.json diff --git a/.docker/app/Dockerfile b/.docker/app/Dockerfile index 7936c7a..cc850e6 100644 --- a/.docker/app/Dockerfile +++ b/.docker/app/Dockerfile @@ -1,36 +1,28 @@ ARG NEXTCLOUD_BASE_IMAGE=nextcloud:stable-fpm +ARG NEXTCLOUD_SOURCE=release -FROM ${NEXTCLOUD_BASE_IMAGE} +FROM mlocati/php-extension-installer:2.12.0 AS php-extension-installer -ARG NEXTCLOUD_SOURCE=release -ARG NEXTCLOUD_DAILY_URL= -ARG PHP_EXTENSION_INSTALLER_VERSION=2.12.0 -ARG PHP_EXTENSION_INSTALLER_SHA256=3f49c71fa66c79b8b2b96bc0ce92885dafd7946f3b5a46f545b390d6f1617e2c +FROM ${NEXTCLOUD_BASE_IMAGE} AS release +FROM ${NEXTCLOUD_BASE_IMAGE} AS daily +ARG NEXTCLOUD_DAILY_URL RUN set -eux; \ - case "${NEXTCLOUD_SOURCE}" in \ - release) \ - ;; \ - daily) \ - test -n "${NEXTCLOUD_DAILY_URL}"; \ - archive_name="$(basename "${NEXTCLOUD_DAILY_URL}")"; \ - curl -fsSL "${NEXTCLOUD_DAILY_URL}" -o "/tmp/${archive_name}"; \ - curl -fsSL "${NEXTCLOUD_DAILY_URL}.sha512" -o "/tmp/${archive_name}.sha512"; \ - expected_sha512="$(awk -v archive="${archive_name}" '$2 == archive { print $1; exit }' "/tmp/${archive_name}.sha512")"; \ - test -n "${expected_sha512}"; \ - echo "${expected_sha512} /tmp/${archive_name}" | sha512sum -c -; \ - rm -rf /usr/src/nextcloud; \ - tar -xjf "/tmp/${archive_name}" -C /usr/src/; \ - rm -f "/tmp/${archive_name}" "/tmp/${archive_name}.sha512"; \ - rm -rf /usr/src/nextcloud/updater; \ - mkdir -p /usr/src/nextcloud/data /usr/src/nextcloud/custom_apps; \ - chmod +x /usr/src/nextcloud/occ; \ - ;; \ - *) \ - echo "Unsupported NEXTCLOUD_SOURCE: ${NEXTCLOUD_SOURCE}" >&2; \ - exit 2; \ - ;; \ - esac + test -n "${NEXTCLOUD_DAILY_URL}"; \ + archive_name="$(basename "${NEXTCLOUD_DAILY_URL}")"; \ + curl -fsSL "${NEXTCLOUD_DAILY_URL}" -o "/tmp/${archive_name}"; \ + curl -fsSL "${NEXTCLOUD_DAILY_URL}.sha512" -o "/tmp/${archive_name}.sha512"; \ + expected_sha512="$(awk -v archive="${archive_name}" '$2 == archive { print $1; exit }' "/tmp/${archive_name}.sha512")"; \ + test -n "${expected_sha512}"; \ + echo "${expected_sha512} /tmp/${archive_name}" | sha512sum -c -; \ + rm -rf /usr/src/nextcloud; \ + tar -xjf "/tmp/${archive_name}" -C /usr/src/; \ + rm -f "/tmp/${archive_name}" "/tmp/${archive_name}.sha512"; \ + rm -rf /usr/src/nextcloud/updater; \ + mkdir -p /usr/src/nextcloud/data /usr/src/nextcloud/custom_apps; \ + chmod +x /usr/src/nextcloud/occ + +FROM ${NEXTCLOUD_SOURCE} AS runtime RUN apt-get update \ && apt-get install -y --no-install-recommends \ @@ -46,12 +38,8 @@ ENV LANG=en_US.UTF-8 ENV LANGUAGE=en_US:en ENV LC_ALL=en_US.UTF-8 -RUN set -eux; \ - curl -fsSL \ - "https://github.com/mlocati/docker-php-extension-installer/releases/download/${PHP_EXTENSION_INSTALLER_VERSION}/install-php-extensions" \ - -o /usr/local/bin/install-php-extensions; \ - echo "${PHP_EXTENSION_INSTALLER_SHA256} /usr/local/bin/install-php-extensions" | sha256sum -c -; \ - chmod uga+x /usr/local/bin/install-php-extensions; \ - install-php-extensions bz2 imagick +COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/install-php-extensions +RUN install-php-extensions bz2 imagick \ + && rm /usr/local/bin/install-php-extensions COPY config/php.ini /usr/local/etc/php/conf.d/ diff --git a/.github/actions/build-and-scan/action.yml b/.github/actions/build-and-scan/action.yml index 0e8a3e5..00bc095 100644 --- a/.github/actions/build-and-scan/action.yml +++ b/.github/actions/build-and-scan/action.yml @@ -70,6 +70,7 @@ runs: - name: Install Trivy uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 with: + # renovate: datasource=github-releases depName=aquasecurity/trivy version: v0.74.0 cache: true diff --git a/.github/workflows/nextcloud-development.yml b/.github/workflows/nextcloud-development.yml index 9f16dc5..a1401c9 100644 --- a/.github/workflows/nextcloud-development.yml +++ b/.github/workflows/nextcloud-development.yml @@ -79,6 +79,7 @@ jobs: - name: Install Trivy uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 with: + # renovate: datasource=github-releases depName=aquasecurity/trivy version: v0.74.0 cache: true diff --git a/docs/images.md b/docs/images.md index e5d93ba..875a687 100644 --- a/docs/images.md +++ b/docs/images.md @@ -153,10 +153,10 @@ ghcr.io/librecodecoop/nextcloud-docker-web@sha256: The app image uses a single `.docker/app/Dockerfile` for both release and development builds. -The Dockerfile has two explicit source modes: +The Dockerfile models its two source modes as Docker build stages instead of runtime shell branching: -- `NEXTCLOUD_SOURCE=release` keeps the Nextcloud payload provided by the selected official Nextcloud base image; -- `NEXTCLOUD_SOURCE=daily` replaces that payload with a verified upstream daily archive. +- `NEXTCLOUD_SOURCE=release` selects the stage that keeps the Nextcloud payload provided by the selected official Nextcloud base image; +- `NEXTCLOUD_SOURCE=daily` selects the stage that replaces that payload with a verified upstream daily archive. The base runtime and the Nextcloud server payload are separate inputs. A development build can therefore follow Nextcloud Server `master` without introducing a Dockerfile or image identity tied to a future major. @@ -164,7 +164,7 @@ For daily builds, `NEXTCLOUD_DAILY_URL` is required. The Dockerfile downloads th The repository Compose environment keeps `NEXTCLOUD_VERSION` as its user-facing version setting and maps it to the generic official base image. There is no second Compose stack for development images. -The external PHP extension installer is pinned to an explicit release and SHA-256 instead of a mutable `latest` download. +The PHP extension installer is consumed from its published Docker image instead of being downloaded by ad-hoc shell logic. Renovate tracks that Docker dependency and the explicit Trivy binary version used by CI, while GitHub Actions dependencies are also managed through Renovate. ## Runtime acceptance diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..cf02720 --- /dev/null +++ b/renovate.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "enabledManagers": [ + "dockerfile", + "github-actions", + "custom.regex" + ], + "dependencyDashboard": false, + "customManagers": [ + { + "customType": "regex", + "managerFilePatterns": [ + "/^\\.github/actions/build-and-scan/action\\.yml$/", + "/^\\.github/workflows/nextcloud-development\\.yml$/" + ], + "matchStrings": [ + "# renovate: datasource=(?\\S+) depName=(?\\S+)\\s+version: (?v?\\d+\\.\\d+\\.\\d+)" + ], + "versioningTemplate": "semver-coerced" + } + ], + "packageRules": [ + { + "matchManagers": [ + "dockerfile" + ], + "matchDepNames": [ + "mlocati/php-extension-installer" + ], + "pinDigests": true + }, + { + "matchManagers": [ + "github-actions" + ], + "pinDigests": true + } + ] +} From 83ffb15ef1f0592d5ff2e6d1b10b1f0bcf6a8cc2 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 01:42:52 +0000 Subject: [PATCH 05/13] chore(ci): update Trivy to v0.75.0 Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .github/actions/build-and-scan/action.yml | 2 +- .github/workflows/nextcloud-development.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-and-scan/action.yml b/.github/actions/build-and-scan/action.yml index 00bc095..02d9955 100644 --- a/.github/actions/build-and-scan/action.yml +++ b/.github/actions/build-and-scan/action.yml @@ -71,7 +71,7 @@ runs: uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 with: # renovate: datasource=github-releases depName=aquasecurity/trivy - version: v0.74.0 + version: v0.75.0 cache: true - name: Scan runtime images diff --git a/.github/workflows/nextcloud-development.yml b/.github/workflows/nextcloud-development.yml index a1401c9..137628f 100644 --- a/.github/workflows/nextcloud-development.yml +++ b/.github/workflows/nextcloud-development.yml @@ -80,7 +80,7 @@ jobs: uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 with: # renovate: datasource=github-releases depName=aquasecurity/trivy - version: v0.74.0 + version: v0.75.0 cache: true - name: Scan Nextcloud master app image From b1ff1e291735c31a40166f7d116796682ed3c6cb Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 01:51:47 +0000 Subject: [PATCH 06/13] chore(deps): separate Dependabot and Renovate ownership Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .github/dependabot.yml | 23 +++++++++++++++++++++++ docs/images.md | 2 +- renovate.json | 19 ------------------- 3 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8c8a80f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,23 @@ +version: 2 + +updates: + - package-ecosystem: docker + directory: /.docker/app + schedule: + interval: weekly + cooldown: + default-days: 7 + + - package-ecosystem: docker + directory: /.docker/web + schedule: + interval: weekly + cooldown: + default-days: 7 + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + cooldown: + default-days: 7 diff --git a/docs/images.md b/docs/images.md index 875a687..fc6d146 100644 --- a/docs/images.md +++ b/docs/images.md @@ -164,7 +164,7 @@ For daily builds, `NEXTCLOUD_DAILY_URL` is required. The Dockerfile downloads th The repository Compose environment keeps `NEXTCLOUD_VERSION` as its user-facing version setting and maps it to the generic official base image. There is no second Compose stack for development images. -The PHP extension installer is consumed from its published Docker image instead of being downloaded by ad-hoc shell logic. Renovate tracks that Docker dependency and the explicit Trivy binary version used by CI, while GitHub Actions dependencies are also managed through Renovate. +The PHP extension installer is consumed from its published Docker image instead of being downloaded by ad-hoc shell logic. Dependabot owns Docker and GitHub Actions updates in this repository. Renovate is deliberately restricted to custom regex-managed values that Dependabot cannot see, currently the explicit Trivy binary version used by CI. The two bots must not manage the same dependency. ## Runtime acceptance diff --git a/renovate.json b/renovate.json index cf02720..d705793 100644 --- a/renovate.json +++ b/renovate.json @@ -1,8 +1,6 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "enabledManagers": [ - "dockerfile", - "github-actions", "custom.regex" ], "dependencyDashboard": false, @@ -18,22 +16,5 @@ ], "versioningTemplate": "semver-coerced" } - ], - "packageRules": [ - { - "matchManagers": [ - "dockerfile" - ], - "matchDepNames": [ - "mlocati/php-extension-installer" - ], - "pinDigests": true - }, - { - "matchManagers": [ - "github-actions" - ], - "pinDigests": true - } ] } From 41b94904e07bd24c22167954f8d8a6d27bc626cd Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 01:56:19 +0000 Subject: [PATCH 07/13] refactor(images): avoid reinstalling upstream imagick Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .docker/app/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docker/app/Dockerfile b/.docker/app/Dockerfile index cc850e6..6fa301d 100644 --- a/.docker/app/Dockerfile +++ b/.docker/app/Dockerfile @@ -39,7 +39,7 @@ ENV LANGUAGE=en_US:en ENV LC_ALL=en_US.UTF-8 COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/install-php-extensions -RUN install-php-extensions bz2 imagick \ +RUN install-php-extensions bz2 \ && rm /usr/local/bin/install-php-extensions COPY config/php.ini /usr/local/etc/php/conf.d/ From 5145c59fd34cdb8c5a85a49ebd3eb51aa413d380 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 01:57:05 +0000 Subject: [PATCH 08/13] refactor(images): remove LibreSign-specific runtime packages Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .docker/app/Dockerfile | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.docker/app/Dockerfile b/.docker/app/Dockerfile index 6fa301d..e858c1c 100644 --- a/.docker/app/Dockerfile +++ b/.docker/app/Dockerfile @@ -27,17 +27,9 @@ FROM ${NEXTCLOUD_SOURCE} AS runtime RUN apt-get update \ && apt-get install -y --no-install-recommends \ gzip \ - locales \ postgresql-client \ - poppler-utils \ - && sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \ - && locale-gen \ && rm -rf /var/lib/apt/lists/* -ENV LANG=en_US.UTF-8 -ENV LANGUAGE=en_US:en -ENV LC_ALL=en_US.UTF-8 - COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/install-php-extensions RUN install-php-extensions bz2 \ && rm /usr/local/bin/install-php-extensions From b571aa204be8473746a11546f7424dc2eb820dc1 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 01:58:19 +0000 Subject: [PATCH 09/13] refactor(images): align generic runtime with upstream extensions Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .docker/app/Dockerfile | 6 ------ docs/images.md | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.docker/app/Dockerfile b/.docker/app/Dockerfile index e858c1c..0171472 100644 --- a/.docker/app/Dockerfile +++ b/.docker/app/Dockerfile @@ -1,8 +1,6 @@ ARG NEXTCLOUD_BASE_IMAGE=nextcloud:stable-fpm ARG NEXTCLOUD_SOURCE=release -FROM mlocati/php-extension-installer:2.12.0 AS php-extension-installer - FROM ${NEXTCLOUD_BASE_IMAGE} AS release FROM ${NEXTCLOUD_BASE_IMAGE} AS daily @@ -30,8 +28,4 @@ RUN apt-get update \ postgresql-client \ && rm -rf /var/lib/apt/lists/* -COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/install-php-extensions -RUN install-php-extensions bz2 \ - && rm /usr/local/bin/install-php-extensions - COPY config/php.ini /usr/local/etc/php/conf.d/ diff --git a/docs/images.md b/docs/images.md index fc6d146..b91ac05 100644 --- a/docs/images.md +++ b/docs/images.md @@ -164,7 +164,7 @@ For daily builds, `NEXTCLOUD_DAILY_URL` is required. The Dockerfile downloads th The repository Compose environment keeps `NEXTCLOUD_VERSION` as its user-facing version setting and maps it to the generic official base image. There is no second Compose stack for development images. -The PHP extension installer is consumed from its published Docker image instead of being downloaded by ad-hoc shell logic. Dependabot owns Docker and GitHub Actions updates in this repository. Renovate is deliberately restricted to custom regex-managed values that Dependabot cannot see, currently the explicit Trivy binary version used by CI. The two bots must not manage the same dependency. +The generic app image avoids adding PHP extensions already absent from the official Nextcloud runtime unless a repository-level requirement justifies them. Dependabot owns Docker and GitHub Actions updates in this repository. Renovate is deliberately restricted to custom regex-managed values that Dependabot cannot see, currently the explicit Trivy binary version used by CI. The two bots must not manage the same dependency. ## Runtime acceptance From a810e0c1851fe8511300f57ea7d363060e7b8549 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:05:18 +0000 Subject: [PATCH 10/13] fix(images): preserve LibreSign runtime requirements Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .docker/app/Dockerfile | 14 ++++++++++++++ docs/images.md | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.docker/app/Dockerfile b/.docker/app/Dockerfile index 0171472..befc6ae 100644 --- a/.docker/app/Dockerfile +++ b/.docker/app/Dockerfile @@ -1,6 +1,8 @@ ARG NEXTCLOUD_BASE_IMAGE=nextcloud:stable-fpm ARG NEXTCLOUD_SOURCE=release +FROM mlocati/php-extension-installer:2.12.0 AS php-extension-installer + FROM ${NEXTCLOUD_BASE_IMAGE} AS release FROM ${NEXTCLOUD_BASE_IMAGE} AS daily @@ -25,7 +27,19 @@ FROM ${NEXTCLOUD_SOURCE} AS runtime RUN apt-get update \ && apt-get install -y --no-install-recommends \ gzip \ + locales \ + poppler-utils \ postgresql-client \ + && sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \ + && locale-gen \ && rm -rf /var/lib/apt/lists/* +ENV LANG=en_US.UTF-8 +ENV LANGUAGE=en_US:en +ENV LC_ALL=en_US.UTF-8 + +COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/install-php-extensions +RUN install-php-extensions bz2 \ + && rm /usr/local/bin/install-php-extensions + COPY config/php.ini /usr/local/etc/php/conf.d/ diff --git a/docs/images.md b/docs/images.md index b91ac05..8dfb323 100644 --- a/docs/images.md +++ b/docs/images.md @@ -164,7 +164,7 @@ For daily builds, `NEXTCLOUD_DAILY_URL` is required. The Dockerfile downloads th The repository Compose environment keeps `NEXTCLOUD_VERSION` as its user-facing version setting and maps it to the generic official base image. There is no second Compose stack for development images. -The generic app image avoids adding PHP extensions already absent from the official Nextcloud runtime unless a repository-level requirement justifies them. Dependabot owns Docker and GitHub Actions updates in this repository. Renovate is deliberately restricted to custom regex-managed values that Dependabot cannot see, currently the explicit Trivy binary version used by CI. The two bots must not manage the same dependency. +The app image remains LibreSign-ready while being generic across Nextcloud versions. It keeps repository-level runtime requirements such as Poppler, UTF-8 locale support, and the PHP bz2 extension, but does not reinstall extensions already supplied by the official Nextcloud base image such as Imagick. Dependabot owns Docker and GitHub Actions updates in this repository. Renovate is deliberately restricted to custom regex-managed values that Dependabot cannot see, currently the explicit Trivy binary version used by CI. The two bots must not manage the same dependency. ## Runtime acceptance From e9a8300b2266b1d20e00ab29dc4bed3d0d9d37fd Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:22:37 +0000 Subject: [PATCH 11/13] style(images): keep PHP extensions one per line Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .docker/app/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.docker/app/Dockerfile b/.docker/app/Dockerfile index befc6ae..1826709 100644 --- a/.docker/app/Dockerfile +++ b/.docker/app/Dockerfile @@ -39,7 +39,8 @@ ENV LANGUAGE=en_US:en ENV LC_ALL=en_US.UTF-8 COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/install-php-extensions -RUN install-php-extensions bz2 \ +RUN install-php-extensions \ + bz2 \ && rm /usr/local/bin/install-php-extensions COPY config/php.ini /usr/local/etc/php/conf.d/ From 1bd6afc68de542086af7fcb85041ee001d5bbdc0 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:42:47 +0000 Subject: [PATCH 12/13] refactor(upgrade): remove out-of-scope database backup hooks Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .docker/app/Dockerfile | 2 - .env.example | 3 - Makefile | 5 +- README.md | 39 -------- .../01-run-post-upgrade-commands.sh | 30 ------ .../pre-upgrade/01-check-disk-and-dump-db.sh | 72 -------------- docker-compose-garages3.yml | 3 - docker-compose.yml | 3 - docs/README_ptBR.md | 39 -------- tests/test-hooks.sh | 95 ------------------- 10 files changed, 1 insertion(+), 290 deletions(-) delete mode 100755 app-hooks/post-upgrade/01-run-post-upgrade-commands.sh delete mode 100755 app-hooks/pre-upgrade/01-check-disk-and-dump-db.sh delete mode 100644 tests/test-hooks.sh diff --git a/.docker/app/Dockerfile b/.docker/app/Dockerfile index 1826709..3a94750 100644 --- a/.docker/app/Dockerfile +++ b/.docker/app/Dockerfile @@ -26,10 +26,8 @@ FROM ${NEXTCLOUD_SOURCE} AS runtime RUN apt-get update \ && apt-get install -y --no-install-recommends \ - gzip \ locales \ poppler-utils \ - postgresql-client \ && sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \ && locale-gen \ && rm -rf /var/lib/apt/lists/* diff --git a/.env.example b/.env.example index 8a588cb..fc4375d 100644 --- a/.env.example +++ b/.env.example @@ -8,9 +8,6 @@ LETSENCRYPT_EMAIL= TZ= POSTGRES_PASSWORD= -NEXTCLOUD_BACKUP_DIR=/backups -NEXTCLOUD_UPGRADE_MIN_FREE_MB=2048 - NEXTCLOUD_ADMIN_USER= NEXTCLOUD_ADMIN_PASSWORD= diff --git a/Makefile b/Makefile index 879d763..62dae15 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ COMPOSE ?= docker compose GARAGES3_COMPOSE_FILE ?= docker-compose-garages3.yml APP_TEST_IMAGE ?= nextcloud-app:acceptance -.PHONY: up-garages3 down-garages3 bootstrap-garages3 garage-status-garages3 start-garages3 wait-nextcloud-garages3 setup-garages3 test-hooks test-scan-images test-ncdd test-app-image test-current-app-image scan-images +.PHONY: up-garages3 down-garages3 bootstrap-garages3 garage-status-garages3 start-garages3 wait-nextcloud-garages3 setup-garages3 test-scan-images test-ncdd test-app-image test-current-app-image scan-images up-garages3: $(COMPOSE) -f $(GARAGES3_COMPOSE_FILE) up -d garage @@ -27,9 +27,6 @@ setup-garages3: $(MAKE) start-garages3 $(MAKE) wait-nextcloud-garages3 -test-hooks: - bash tests/test-hooks.sh - test-scan-images: bash tests/test-scan-images.sh diff --git a/README.md b/README.md index d32956b..aeebc5e 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ Languages avaliable: [pt-BR](docs/README_ptBR.md) - [After setup](#after-setup) - [Custom setup](#custom-setup) - [Customize docker-compose content](#customize-docker-compose-content) - - [Nextcloud upgrade hooks](#nextcloud-upgrade-hooks) - [PHP](#php) - [Run Nextcloud](#run-nextcloud) - [Use a specific version of Nextcloud](#use-a-specific-version-of-nextcloud) @@ -128,44 +127,6 @@ You can do this using environments and creating a file called `docker-compose.ov The main compose files now include a `redis` service by default. This keeps the stack self-contained for Nextcloud installations that already use Redis in `config.php` and avoids depending on a host-specific external network. -### Nextcloud upgrade hooks - -This repository mounts the official Nextcloud Docker hook directories so you can extend install and upgrade flows without touching the image entrypoint. - -The `app` service uses these mounts: - -```yaml -services: - app: - volumes: - - ./volumes/nextcloud:/var/www/html - - ./backups:/backups - - ./app-hooks/pre-installation:/docker-entrypoint-hooks.d/pre-installation - - ./app-hooks/post-installation:/docker-entrypoint-hooks.d/post-installation - - ./app-hooks/pre-upgrade:/docker-entrypoint-hooks.d/pre-upgrade - - ./app-hooks/post-upgrade:/docker-entrypoint-hooks.d/post-upgrade - - ./app-hooks/before-starting:/docker-entrypoint-hooks.d/before-starting -``` - -The upgrade hooks behave like this: - -- `pre-upgrade`: turns maintenance mode on -- `pre-upgrade`: saves the active app list to `/backups/app_list.old` -- `pre-upgrade`: checks free disk space on the Nextcloud volume and the backup volume -- `pre-upgrade`: creates a compressed PostgreSQL dump at `/backups/nextcloud-db.sql.gz`, replacing the previous dump -- `post-upgrade`: saves the new app list to `/backups/app_list.new` and prints a diff when possible -- `post-upgrade`: runs the extra `occ` commands needed after a major upgrade -- `post-upgrade`: turns maintenance mode off at the end - -The following variables control the safety check and backup location: - -- `NEXTCLOUD_BACKUP_DIR`, defaulting to `/backups` -- `NEXTCLOUD_UPGRADE_MIN_FREE_MB`, defaulting to `2048` - -Both upgrade hooks use `NEXTCLOUD_BACKUP_DIR` for the app list files and the database dump. - -This repository includes the `./backups` directory so Docker does not create it as a root-owned host path on a fresh checkout. It must still be writable by `www-data` inside the container. The recommended host-side ownership is `www-data:www-data` with mode `0755`. - ### Garage S3 primary storage Use `docker-compose-garages3.yml` when you want Nextcloud to store files in a Garage S3 bucket instead of the local `data/` directory. diff --git a/app-hooks/post-upgrade/01-run-post-upgrade-commands.sh b/app-hooks/post-upgrade/01-run-post-upgrade-commands.sh deleted file mode 100755 index 0437868..0000000 --- a/app-hooks/post-upgrade/01-run-post-upgrade-commands.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -backup_dir=${NEXTCLOUD_BACKUP_DIR:-/backups} - -cleanup() { - php occ maintenance:mode --off >/dev/null 2>&1 || true -} - -trap cleanup EXIT - -run_occ() { - echo "Running: php occ $*" - php occ "$@" -} - -echo "Running post-upgrade Nextcloud commands" -php occ app:list > "$backup_dir/app_list.new" -if [ -f "$backup_dir/app_list.old" ]; then - echo "Comparing app lists" - diff -u "$backup_dir/app_list.old" "$backup_dir/app_list.new" || true -fi -run_occ db:add-missing-columns -run_occ db:add-missing-indices -run_occ db:add-missing-primary-keys -run_occ maintenance:repair --include-expensive -run_occ config:system:set maintenance_window_start --type=integer --value=1 -run_occ app:update --all -echo "Post-upgrade commands completed successfully" diff --git a/app-hooks/pre-upgrade/01-check-disk-and-dump-db.sh b/app-hooks/pre-upgrade/01-check-disk-and-dump-db.sh deleted file mode 100755 index cc4d47a..0000000 --- a/app-hooks/pre-upgrade/01-check-disk-and-dump-db.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -nextcloud_dir=${NEXTCLOUD_DIR:-/var/www/html} -backup_dir=${NEXTCLOUD_BACKUP_DIR:-/backups} -min_free_mb=${NEXTCLOUD_UPGRADE_MIN_FREE_MB:-2048} -db_host=${POSTGRES_HOST:-postgres} -db_name=${POSTGRES_DB:-nextcloud} -db_user=${POSTGRES_USER:-nextcloud} -db_password=${POSTGRES_PASSWORD:-} -backup_file="${backup_dir}/nextcloud-db.sql.gz" -backup_tmp_file="${backup_file}.tmp" -app_list_file="${backup_dir}/app_list.old" -maintenance_enabled=0 - -cleanup() { - if [ "$maintenance_enabled" -eq 1 ]; then - php occ maintenance:mode --off >/dev/null 2>&1 || true - fi - - rm -f "$backup_tmp_file" -} - -trap cleanup EXIT - -run_occ() { - echo "Running: php occ $*" - php occ "$@" -} - -check_free_space() { - local path=$1 - local label=$2 - local available_mb - - available_mb=$(df -Pm "$path" | awk 'NR==2 { print $4 }') - - if [ "$available_mb" -lt "$min_free_mb" ]; then - echo "Not enough disk space on ${label}: ${available_mb} MB available, ${min_free_mb} MB required" - exit 1 - fi - - echo "${label} has ${available_mb} MB free" -} - -echo "Running pre-upgrade safety checks" -mkdir -p "$backup_dir" - -run_occ maintenance:mode --on -maintenance_enabled=1 -php occ app:list > "$app_list_file" -echo "Saved active apps list to ${app_list_file}" - -check_free_space "$nextcloud_dir" "Nextcloud volume" -check_free_space "$backup_dir" "Backup volume" - -if ! command -v pg_dump >/dev/null 2>&1; then - echo "pg_dump is not available in the container image" - exit 1 -fi - -if [ -z "$db_password" ]; then - echo "POSTGRES_PASSWORD is empty, refusing to create a database dump" - exit 1 -fi - -echo "Creating PostgreSQL dump at ${backup_file}" -PGPASSWORD="$db_password" pg_dump -h "$db_host" -U "$db_user" "$db_name" | gzip -9 > "$backup_tmp_file" -mv "$backup_tmp_file" "$backup_file" -rm -f "$backup_tmp_file" -echo "Database dump completed successfully" diff --git a/docker-compose-garages3.yml b/docker-compose-garages3.yml index 6b73c9b..331b443 100644 --- a/docker-compose-garages3.yml +++ b/docker-compose-garages3.yml @@ -41,11 +41,8 @@ services: restart: unless-stopped volumes: - ./volumes/nextcloud:/var/www/html - - ./backups:/backups - ./app-hooks/pre-installation:/docker-entrypoint-hooks.d/pre-installation - ./app-hooks/post-installation:/docker-entrypoint-hooks.d/post-installation - - ./app-hooks/pre-upgrade:/docker-entrypoint-hooks.d/pre-upgrade - - ./app-hooks/post-upgrade:/docker-entrypoint-hooks.d/post-upgrade - ./app-hooks/before-starting:/docker-entrypoint-hooks.d/before-starting - ./.docker/garages3.config.php:/var/www/html/config/garages3.config.php:ro environment: diff --git a/docker-compose.yml b/docker-compose.yml index b9c2385..3e4c68b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,11 +19,8 @@ services: NEXTCLOUD_BASE_IMAGE: nextcloud:${NEXTCLOUD_VERSION:-stable-fpm} volumes: - ./volumes/nextcloud:/var/www/html - - ./volumes/backups:/backups - ./app-hooks/pre-installation:/docker-entrypoint-hooks.d/pre-installation - ./app-hooks/post-installation:/docker-entrypoint-hooks.d/post-installation - - ./app-hooks/pre-upgrade:/docker-entrypoint-hooks.d/pre-upgrade - - ./app-hooks/post-upgrade:/docker-entrypoint-hooks.d/post-upgrade - ./app-hooks/before-starting:/docker-entrypoint-hooks.d/before-starting restart: unless-stopped environment: diff --git a/docs/README_ptBR.md b/docs/README_ptBR.md index 5ade48a..1e013f8 100644 --- a/docs/README_ptBR.md +++ b/docs/README_ptBR.md @@ -6,7 +6,6 @@ - [Após a configuração](#após-a-configuração) - [Configuração personalizada](#configuração-personalizada) - [Personalize o conteúdo do docker-compose](#personalize-o-conteúdo-do-docker-compose) - - [Hooks de upgrade do Nextcloud](#hooks-de-upgrade-do-nextcloud) - [PHP](#php) - [Execute o Nextcloud](#execute-o-nextcloud) - [Use uma versão específica do Nextcloud](#use-uma-versão-específica-do-nextcloud) @@ -83,44 +82,6 @@ Você pode fazer isso usando variáveis de ambiente e criando um arquivo chamado Os arquivos principais de compose agora incluem o serviço `redis` por padrão. Isso deixa o stack autocontido para instalações do Nextcloud que já usam Redis no `config.php` e evita depender de uma rede externa específica do host. -### Hooks de upgrade do Nextcloud - -Este repositório monta os diretórios oficiais de hooks do Nextcloud Docker para permitir extensões do fluxo de instalação e upgrade sem alterar o entrypoint da imagem. - -O serviço `app` usa estes mounts: - -```yaml -services: - app: - volumes: - - ./volumes/nextcloud:/var/www/html - - ./backups:/backups - - ./app-hooks/pre-installation:/docker-entrypoint-hooks.d/pre-installation - - ./app-hooks/post-installation:/docker-entrypoint-hooks.d/post-installation - - ./app-hooks/pre-upgrade:/docker-entrypoint-hooks.d/pre-upgrade - - ./app-hooks/post-upgrade:/docker-entrypoint-hooks.d/post-upgrade - - ./app-hooks/before-starting:/docker-entrypoint-hooks.d/before-starting -``` - -Os hooks de upgrade funcionam assim: - -- `pre-upgrade`: ativa o modo de manutenção -- `pre-upgrade`: salva a lista de apps ativos em `/backups/app_list.old` -- `pre-upgrade`: verifica o espaço livre no volume do Nextcloud e no volume de backup -- `pre-upgrade`: cria um dump compactado do PostgreSQL em `/backups/nextcloud-db.sql.gz`, substituindo o dump anterior -- `post-upgrade`: salva a nova lista de apps em `/backups/app_list.new` e mostra o diff quando possível -- `post-upgrade`: executa os comandos `occ` extras necessários após um upgrade maior -- `post-upgrade`: desativa o modo de manutenção ao final - -As variáveis abaixo controlam a checagem e o diretório de backup: - -- `NEXTCLOUD_BACKUP_DIR`, com padrão `/backups` -- `NEXTCLOUD_UPGRADE_MIN_FREE_MB`, com padrão `2048` - -Os dois hooks de upgrade usam `NEXTCLOUD_BACKUP_DIR` para os arquivos da lista de apps e para o dump do banco. - -Este repositório já inclui o diretório `./backups`, então o Docker não cria um caminho root-owned em um checkout novo. Ele ainda precisa ser gravável pelo `www-data` dentro do container. O recomendado é usar `www-data:www-data` com permissão `0755`. - ### Storage primário Garage S3 Use `docker-compose-garages3.yml` quando quiser que o Nextcloud grave os arquivos em um bucket Garage S3 em vez do diretório local `data/`. diff --git a/tests/test-hooks.sh b/tests/test-hooks.sh deleted file mode 100644 index 7c543f4..0000000 --- a/tests/test-hooks.sh +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) -tmp_root=$(mktemp -d) -trap 'rm -rf "$tmp_root"' EXIT - -bin_dir="$tmp_root/bin" -work_dir="$tmp_root/work" -backup_dir="$tmp_root/backups" -nextcloud_dir="$tmp_root/nextcloud" -log_file="$tmp_root/php.log" -dump_output="$tmp_root/pg_dump.out" - -mkdir -p "$bin_dir" "$work_dir" "$backup_dir" "$nextcloud_dir" - -cat > "$bin_dir/php" <<'EOF' -#!/usr/bin/env bash -set -euo pipefail - -log_file=${HOOK_TEST_LOG_FILE:?} - -printf 'php %s\n' "$*" >> "$log_file" - -case "${1:-}" in - occ) - shift - case "${1:-}" in - maintenance:mode) - exit 0 - ;; - app:list) - printf 'app1\napp2\n' - exit 0 - ;; - db:add-missing-columns|db:add-missing-indices|db:add-missing-primary-keys|maintenance:repair|config:system:set|app:update) - exit 0 - ;; - *) - printf 'unexpected occ command: %s\n' "$*" >&2 - exit 1 - ;; - esac - ;; - *) - printf 'unexpected php invocation: %s\n' "$*" >&2 - exit 1 - ;; -esac -EOF - -cat > "$bin_dir/pg_dump" <<'EOF' -#!/usr/bin/env bash -set -euo pipefail - -printf '%s\n' "CREATE TABLE test();" -EOF - -chmod +x "$bin_dir/php" "$bin_dir/pg_dump" - -export PATH="$bin_dir:$PATH" -export HOOK_TEST_LOG_FILE="$log_file" -export NEXTCLOUD_DIR="$nextcloud_dir" -export NEXTCLOUD_BACKUP_DIR="$backup_dir" -export NEXTCLOUD_UPGRADE_MIN_FREE_MB=1 -export POSTGRES_PASSWORD="secret" - -cp "$repo_root/app-hooks/pre-upgrade/01-check-disk-and-dump-db.sh" "$work_dir/" -cp "$repo_root/app-hooks/post-upgrade/01-run-post-upgrade-commands.sh" "$work_dir/" - -pushd "$work_dir" >/dev/null -bash ./01-check-disk-and-dump-db.sh -popd >/dev/null - -test -f "$backup_dir/nextcloud-db.sql.gz" -test ! -f "$backup_dir/nextcloud-db.sql.gz.tmp" -gzip -dc "$backup_dir/nextcloud-db.sql.gz" > "$dump_output" -grep -q "CREATE TABLE test();" "$dump_output" - -grep -q "php occ maintenance:mode --on" "$log_file" -grep -q "php occ maintenance:mode --off" "$log_file" -grep -q "php occ app:list" "$log_file" - -: > "$log_file" - -pushd "$work_dir" >/dev/null -HOOK_TEST_LOG_FILE="$log_file" bash ./01-run-post-upgrade-commands.sh -popd >/dev/null - -test -f "$backup_dir/app_list.new" -grep -q "php occ db:add-missing-columns" "$log_file" -grep -q "php occ maintenance:mode --off" "$log_file" - -echo "hook tests passed" From 9628d777dc36970d1ce284995788ca5280f08004 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:44:09 +0000 Subject: [PATCH 13/13] fix(compose): use generic app image args for Garage Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- docker-compose-garages3.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose-garages3.yml b/docker-compose-garages3.yml index 331b443..8a26f92 100644 --- a/docker-compose-garages3.yml +++ b/docker-compose-garages3.yml @@ -37,7 +37,7 @@ services: build: context: .docker/app args: - NEXTCLOUD_VERSION: ${NEXTCLOUD_VERSION:-stable-fpm} + NEXTCLOUD_BASE_IMAGE: nextcloud:${NEXTCLOUD_VERSION:-stable-fpm} restart: unless-stopped volumes: - ./volumes/nextcloud:/var/www/html @@ -103,7 +103,7 @@ services: build: context: .docker/app args: - NEXTCLOUD_VERSION: ${NEXTCLOUD_VERSION:-stable-fpm} + NEXTCLOUD_BASE_IMAGE: nextcloud:${NEXTCLOUD_VERSION:-stable-fpm} restart: unless-stopped environment: - TZ