diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md
index 66681d2e..aca2e718 100644
--- a/.github/ISSUE_TEMPLATE/Bug_report.md
+++ b/.github/ISSUE_TEMPLATE/Bug_report.md
@@ -6,9 +6,10 @@ labels: 0. Needs triage
@@ -29,4 +30,10 @@ labels: 0. Needs triage
#### Docker run command or docker-compose file that you used
-#### Other valuable info
+#### Output of `sudo docker logs nextcloud-aio-mastercontainer`
+
+#### Output of `sudo docker inspect nextcloud-aio-mastercontainer`
+
+#### Output of `sudo docker ps -a`
+
+#### Other valuable info
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index bbeee846..72ae238a 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -3,15 +3,12 @@ contact_links:
- name: 📘 Documentation on Nextcloud AIO
url: https://github.com/nextcloud/all-in-one#faq
about: Please read the docs first before submitting any report or request!
- - name: ⛑️ General questions and support
+ - name: ⛑️ Questions and support
url: https://help.nextcloud.com/tag/aio
- about: For general questions, support and help
+ about: For questions, support and help
- name: 💡 Suggest a new feature or discuss one
url: https://github.com/nextcloud/all-in-one/discussions/categories/ideas
about: For new feature requests and discussion of existing ones
- - name: ❓ Questions about Nextcloud AIO
- url: https://github.com/nextcloud/all-in-one/discussions/categories/questions
- about: For questions specifically about AIO
- name: 💼 Nextcloud Enterprise
url: https://portal.nextcloud.com/
about: If you are a Nextcloud Enterprise customer, or need Professional support, so it can be resolved directly by our dedicated engineers more quickly
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 0caaabfb..7fe1067e 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -10,6 +10,8 @@ updates:
labels:
- 3. to review
- dependencies
+ cooldown:
+ default-days: 7
- package-ecosystem: composer
directory: "/php/"
schedule:
@@ -55,6 +57,6 @@ updates:
- dependency-name: "postgres"
update-types: ["version-update:semver-major"]
- dependency-name: "redis"
- update-types: ["version-update:semver-major", "version-update:semver-minor"]
+ update-types: ["version-update:semver-major"]
- dependency-name: "elasticsearch"
update-types: ["version-update:semver-major"]
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index 51548e24..2bd4823a 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -12,9 +12,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6.0.1
- name: Check spelling
- uses: codespell-project/actions-codespell@406322ec52dd7b488e48c1c4b82e2a8b3a1bf630 # v2
+ uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2
with:
check_filenames: true
check_hidden: true
diff --git a/.github/workflows/collabora.yml b/.github/workflows/collabora.yml
new file mode 100644
index 00000000..8e464925
--- /dev/null
+++ b/.github/workflows/collabora.yml
@@ -0,0 +1,29 @@
+name: collabora-update
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: '00 12 * * *'
+
+jobs:
+ collabora-update:
+ name: update collabora
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6.0.1
+ - name: Run collabora-profile-update
+ run: |
+ rm -f php/cool-seccomp-profile.json
+ wget https://raw.githubusercontent.com/CollaboraOnline/online/refs/heads/main/docker/cool-seccomp-profile.json
+ mv cool-seccomp-profile.json php/
+
+ - name: Create Pull Request
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
+ with:
+ commit-message: collabora-seccomp-update automated change
+ signoff: true
+ title: collabora seccomp update
+ body: Automated collabora seccomp profile update
+ labels: dependencies, 3. to review
+ milestone: next
+ branch: collabora-seccomp-update
diff --git a/.github/workflows/community-containers.yml b/.github/workflows/community-containers.yml
index 2df5173d..7446677f 100644
--- a/.github/workflows/community-containers.yml
+++ b/.github/workflows/community-containers.yml
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6.0.1
- name: Validate structure
run: |
CONTAINERS="$(find ./community-containers -mindepth 1 -maxdepth 1 -type d)"
diff --git a/.github/workflows/dependency-updates.yml b/.github/workflows/dependency-updates.yml
index a7b0c5ff..1b448139 100644
--- a/.github/workflows/dependency-updates.yml
+++ b/.github/workflows/dependency-updates.yml
@@ -10,8 +10,8 @@ jobs:
name: Run dependency update script
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - uses: shivammathur/setup-php@0f7f1d08e3e32076e51cae65eb0b0c871405b16e # v2
+ - uses: actions/checkout@v6.0.1
+ - uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with:
php-version: 8.4
extensions: apcu
@@ -44,7 +44,7 @@ jobs:
)"
sed -i "s|pecl install APCu.*\;|pecl install APCu-$apcu_version\;|" ./Containers/mastercontainer/Dockerfile
- name: Create Pull Request
- uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with:
commit-message: php dependency updates
signoff: true
diff --git a/.github/workflows/docker-lint.yml b/.github/workflows/docker-lint.yml
index b1a2cd87..917df1d6 100644
--- a/.github/workflows/docker-lint.yml
+++ b/.github/workflows/docker-lint.yml
@@ -25,7 +25,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v6.0.1
- name: Install hadolint
run: |
diff --git a/.github/workflows/helm-release.yml b/.github/workflows/helm-release.yml
index 50b161ea..a4f441c2 100644
--- a/.github/workflows/helm-release.yml
+++ b/.github/workflows/helm-release.yml
@@ -13,10 +13,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v6.0.1
- name: Turnstyle
- uses: softprops/turnstyle@807f6009e7cee5c2c9faa41ccef03a8bb24b06ab # v2
+ uses: softprops/turnstyle@e565d2d86403c5d23533937e95980570545e5586 # v2
with:
continue-after-seconds: 180
env:
@@ -32,7 +32,7 @@ jobs:
# See https://github.com/helm/chart-releaser-action/issues/6
- name: Set up Helm
- uses: azure/setup-helm@b9e51907a09c216f16ebe8536097933489208112 # v4
+ uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
with:
version: v3.6.3
diff --git a/.github/workflows/imaginary-update.yml b/.github/workflows/imaginary-update.yml
index 707a4d7d..060b376e 100644
--- a/.github/workflows/imaginary-update.yml
+++ b/.github/workflows/imaginary-update.yml
@@ -10,7 +10,7 @@ jobs:
name: update to latest imaginary commit on master branch
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6.0.1
- name: Run imaginary-update
run: |
# Imaginary
@@ -22,7 +22,7 @@ jobs:
sed -i "s|^ENV IMAGINARY_HASH.*$|ENV IMAGINARY_HASH=$imaginary_version|" ./Containers/imaginary/Dockerfile
- name: Create Pull Request
- uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with:
commit-message: imaginary-update automated change
signoff: true
diff --git a/.github/workflows/json-validator.yml b/.github/workflows/json-validator.yml
index 3db0032d..4cbd28ed 100644
--- a/.github/workflows/json-validator.yml
+++ b/.github/workflows/json-validator.yml
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6.0.1
- name: Validate Json
run: |
sudo apt-get update
diff --git a/.github/workflows/lint-helm.yml b/.github/workflows/lint-helm.yml
index 476c1925..7beec865 100644
--- a/.github/workflows/lint-helm.yml
+++ b/.github/workflows/lint-helm.yml
@@ -11,12 +11,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v6.0.1
with:
fetch-depth: 0
- name: Install Helm
- uses: azure/setup-helm@b9e51907a09c216f16ebe8536097933489208112 # v4
+ uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
with:
version: v3.11.1
diff --git a/.github/workflows/lint-php.yml b/.github/workflows/lint-php.yml
index 005af782..0c5e2c74 100644
--- a/.github/workflows/lint-php.yml
+++ b/.github/workflows/lint-php.yml
@@ -2,6 +2,9 @@
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
+#
+# SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: MIT
name: Lint php
@@ -33,10 +36,12 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5.0.1
+ with:
+ persist-credentials: false
- name: Set up php ${{ matrix.php-versions }}
- uses: shivammathur/setup-php@0f7f1d08e3e32076e51cae65eb0b0c871405b16e # v2
+ uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2.36.0
with:
php-version: ${{ matrix.php-versions }}
coverage: none
diff --git a/.github/workflows/lint-yaml.yml b/.github/workflows/lint-yaml.yml
new file mode 100644
index 00000000..3bb1d33f
--- /dev/null
+++ b/.github/workflows/lint-yaml.yml
@@ -0,0 +1,42 @@
+# This workflow is provided via the organization template repository
+#
+# https://github.com/nextcloud/.github
+# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
+#
+# SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: MIT
+
+name: Lint YAML
+
+on:
+ pull_request:
+ paths:
+ - '**.yml'
+
+permissions:
+ contents: read
+
+jobs:
+ yaml-lint:
+ runs-on: ubuntu-latest
+
+ name: yaml
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
+ with:
+ persist-credentials: false
+
+ - name: GitHub action templates lint
+ uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c # v3.1.1
+ with:
+ file_or_dir: .github/workflows
+ config_data: |
+ line-length: warning
+
+ - name: Install the latest version of uv
+ uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
+
+ - name: Check GitHub actions
+ run: uvx zizmor --min-severity medium .github/workflows/*.yml
diff --git a/.github/workflows/lock-threads.yml b/.github/workflows/lock-threads.yml
index be8273d5..bda40ee2 100644
--- a/.github/workflows/lock-threads.yml
+++ b/.github/workflows/lock-threads.yml
@@ -14,7 +14,7 @@ jobs:
action:
runs-on: ubuntu-latest
steps:
- - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5
+ - uses: dessant/lock-threads@7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7 # v5
with:
issue-inactive-days: '14'
process-only: 'issues'
diff --git a/.github/workflows/nextcloud-update.yml b/.github/workflows/nextcloud-update.yml
index 96ecef69..7fe5bbf9 100644
--- a/.github/workflows/nextcloud-update.yml
+++ b/.github/workflows/nextcloud-update.yml
@@ -11,7 +11,7 @@ jobs:
name: Run nextcloud-update script
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6.0.1
- name: Run nextcloud-update script
run: |
# Inspired by https://github.com/nextcloud/docker/blob/master/update.sh
@@ -79,7 +79,7 @@ jobs:
fi
- name: Create Pull Request
- uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with:
commit-message: nextcloud-update automated change
signoff: true
diff --git a/.github/workflows/php-deprecation-detector.yml b/.github/workflows/php-deprecation-detector.yml
index 2bfe200e..c8638683 100644
--- a/.github/workflows/php-deprecation-detector.yml
+++ b/.github/workflows/php-deprecation-detector.yml
@@ -16,9 +16,9 @@ jobs:
name: PHP Deprecation Detector
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6.0.1
- name: Set up php
- uses: shivammathur/setup-php@0f7f1d08e3e32076e51cae65eb0b0c871405b16e # v2
+ uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with:
php-version: 8.4
extensions: apcu
diff --git a/.github/workflows/playwright-on-push.yml b/.github/workflows/playwright-on-push.yml
new file mode 100644
index 00000000..af8dec02
--- /dev/null
+++ b/.github/workflows/playwright-on-push.yml
@@ -0,0 +1,123 @@
+name: Playwright Tests on push
+
+on:
+ pull_request:
+ paths:
+ - 'php/**'
+ push:
+ branches:
+ - main
+ paths:
+ - 'php/**'
+
+concurrency:
+ group: playwright-${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+env:
+ BASE_URL: https://localhost:8080
+
+jobs:
+ test:
+ timeout-minutes: 60
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v6.0.1
+
+ - uses: actions/setup-node@v6
+ with:
+ node-version: lts/*
+
+ - name: Install dependencies
+ run: cd php/tests && npm ci
+
+ - name: Install Playwright Browsers
+ run: cd php/tests && npx playwright install --with-deps chromium
+
+ - name: Set up php 8.4
+ uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2.36.0
+ with:
+ extensions: apcu
+ php-version: 8.4
+ coverage: none
+ ini-file: development
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Adjust some things and fix permissions
+ run: |
+ cd php
+ rm -r ./data
+ rm -r ./session
+ composer install --no-dev
+ composer clear-cache
+ sudo chmod 777 -R ./
+
+ - name: Start fresh development server
+ run: |
+ docker rm --force nextcloud-aio-{mastercontainer,apache,notify-push,nextcloud,redis,database,domaincheck,whiteboard,imaginary,talk,collabora,borgbackup} || true
+ docker volume rm nextcloud_aio_{mastercontainer,apache,database,database_dump,nextcloud,nextcloud_data,redis,backup_cache,elasticsearch} || true
+ docker pull ghcr.io/nextcloud-releases/all-in-one:develop
+ docker run \
+ -d \
+ --init \
+ --name nextcloud-aio-mastercontainer \
+ --restart always \
+ --publish 8080:8080 \
+ --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
+ --volume ./php:/var/www/docker-aio/php \
+ --volume /var/run/docker.sock:/var/run/docker.sock:ro \
+ --env SKIP_DOMAIN_VALIDATION=true \
+ --env APACHE_PORT=11000 \
+ ghcr.io/nextcloud-releases/all-in-one:develop
+ echo Waiting for 10 seconds for the development container to start ...
+ sleep 10
+
+ - name: Run Playwright tests for initial setup
+ run: |
+ cd php/tests
+ export DEBUG=pw:api
+ if ! npx playwright test tests/initial-setup.spec.js; then
+ docker logs nextcloud-aio-mastercontainer
+ docker logs nextcloud-aio-borgbackup
+ exit 1
+ fi
+
+ - name: Start fresh development server
+ run: |
+ docker rm --force nextcloud-aio-{mastercontainer,apache,notify-push,nextcloud,redis,database,domaincheck,whiteboard,imaginary,talk,collabora,borgbackup} || true
+ docker volume rm nextcloud_aio_{mastercontainer,apache,database,database_dump,nextcloud,nextcloud_data,redis,backup_cache,elasticsearch} || true
+ docker run \
+ -d \
+ --init \
+ --name nextcloud-aio-mastercontainer \
+ --restart always \
+ --publish 8080:8080 \
+ --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
+ --volume ./php:/var/www/docker-aio/php \
+ --volume /var/run/docker.sock:/var/run/docker.sock:ro \
+ --env SKIP_DOMAIN_VALIDATION=false \
+ --env APACHE_PORT=11000 \
+ ghcr.io/nextcloud-releases/all-in-one:develop
+ echo Waiting for 10 seconds for the development container to start ...
+ sleep 10
+
+ - name: Run Playwright tests for backup restore
+ run: |
+ cd php/tests
+ export DEBUG=pw:api
+ if ! npx playwright test tests/restore-instance.spec.js; then
+ docker logs nextcloud-aio-mastercontainer
+ docker logs nextcloud-aio-borgbackup
+ exit 1
+ fi
+
+ - uses: actions/upload-artifact@v6
+ if: ${{ !cancelled() }}
+ with:
+ name: playwright-report
+ path: php/tests/playwright-report/
+ retention-days: 14
+ overwrite: true
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright-on-workflow-dispatch.yml
similarity index 80%
rename from .github/workflows/playwright.yml
rename to .github/workflows/playwright-on-workflow-dispatch.yml
index 67653783..252a6510 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright-on-workflow-dispatch.yml
@@ -13,9 +13,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6.0.1
- - uses: actions/setup-node@v4
+ - uses: actions/setup-node@v6
with:
node-version: lts/*
@@ -45,7 +45,14 @@ jobs:
sleep 10
- name: Run Playwright tests for initial setup
- run: cd php/tests && DEBUG=pw:api npx playwright test tests/initial-setup.spec.js
+ run: |
+ cd php/tests
+ export DEBUG=pw:api
+ if ! npx playwright test tests/initial-setup.spec.js; then
+ docker logs nextcloud-aio-mastercontainer
+ docker logs nextcloud-aio-borgbackup
+ exit 1
+ fi
- name: Start fresh development server
run: |
@@ -66,9 +73,16 @@ jobs:
sleep 10
- name: Run Playwright tests for backup restore
- run: cd php/tests && DEBUG=pw:api npx playwright test tests/restore-instance.spec.js
+ run: |
+ cd php/tests
+ export DEBUG=pw:api
+ if ! npx playwright test tests/restore-instance.spec.js; then
+ docker logs nextcloud-aio-mastercontainer
+ docker logs nextcloud-aio-borgbackup
+ exit 1
+ fi
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@v6
if: ${{ !cancelled() }}
with:
name: playwright-report
diff --git a/.github/workflows/psalm-update-baseline.yml b/.github/workflows/psalm-update-baseline.yml
index 304f9393..1bd47ac4 100644
--- a/.github/workflows/psalm-update-baseline.yml
+++ b/.github/workflows/psalm-update-baseline.yml
@@ -10,10 +10,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6.0.1
- name: Set up php
- uses: shivammathur/setup-php@0f7f1d08e3e32076e51cae65eb0b0c871405b16e # v2
+ uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with:
php-version: 8.4
extensions: apcu
@@ -30,7 +30,7 @@ jobs:
continue-on-error: true
- name: Create Pull Request
- uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
commit-message: Update psalm baseline
diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml
index 4e168ab7..bdae585e 100644
--- a/.github/workflows/psalm.yml
+++ b/.github/workflows/psalm.yml
@@ -2,6 +2,9 @@
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
+#
+# SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: MIT
name: Static analysis
@@ -19,6 +22,9 @@ concurrency:
group: psalm-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
+permissions:
+ contents: read
+
jobs:
static-analysis:
runs-on: ubuntu-latest
@@ -26,15 +32,19 @@ jobs:
name: static-psalm-analysis
steps:
- name: Checkout
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5.0.1
+ with:
+ persist-credentials: false
- name: Set up php
- uses: shivammathur/setup-php@0f7f1d08e3e32076e51cae65eb0b0c871405b16e # v2
+ uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2.36.0
with:
php-version: 8.4
extensions: apcu
coverage: none
ini-file: development
+ # Temporary workaround for missing pcntl_* in PHP 8.3
+ ini-values: disable_functions=
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml
index d474d95f..86954033 100644
--- a/.github/workflows/shellcheck.yml
+++ b/.github/workflows/shellcheck.yml
@@ -15,7 +15,7 @@ jobs:
name: Check Shell
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6.0.1
- name: Run Shellcheck
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0
with:
diff --git a/.github/workflows/talk.yml b/.github/workflows/talk.yml
index 1b541dd4..f28ad9f2 100644
--- a/.github/workflows/talk.yml
+++ b/.github/workflows/talk.yml
@@ -10,7 +10,7 @@ jobs:
name: update talk
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6.0.1
- name: Run talk-container-update
run: |
# Recording
@@ -45,7 +45,7 @@ jobs:
sed -i "s|^ARG JANUS_VERSION=.*$|ARG JANUS_VERSION=$janus_version|" ./Containers/talk/Dockerfile
- name: Create Pull Request
- uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with:
commit-message: talk-update automated change
signoff: true
diff --git a/.github/workflows/twig-lint.yml b/.github/workflows/twig-lint.yml
index 2c40b1ce..7e9b5cdc 100644
--- a/.github/workflows/twig-lint.yml
+++ b/.github/workflows/twig-lint.yml
@@ -24,10 +24,10 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v6.0.1
- name: Set up php ${{ matrix.php-versions }}
- uses: shivammathur/setup-php@0f7f1d08e3e32076e51cae65eb0b0c871405b16e # v2
+ uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with:
php-version: 8.4
extensions: apcu
diff --git a/.github/workflows/update-copyright.yml b/.github/workflows/update-copyright.yml
index fa00f9b1..f7960ead 100644
--- a/.github/workflows/update-copyright.yml
+++ b/.github/workflows/update-copyright.yml
@@ -8,4 +8,4 @@ jobs:
name: update copyright
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6.0.1
diff --git a/.github/workflows/update-helm.yml b/.github/workflows/update-helm.yml
index 9b261a78..ee8e4669 100644
--- a/.github/workflows/update-helm.yml
+++ b/.github/workflows/update-helm.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6.0.1
- name: update helm chart
run: |
set -x
@@ -23,7 +23,7 @@ jobs:
sudo bash nextcloud-aio-helm-chart/update-helm.sh "$DOCKER_TAG"
fi
- name: Create Pull Request
- uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with:
commit-message: Helm Chart updates
signoff: true
diff --git a/.github/workflows/update-yaml.yml b/.github/workflows/update-yaml.yml
index dca81879..ba92fd50 100644
--- a/.github/workflows/update-yaml.yml
+++ b/.github/workflows/update-yaml.yml
@@ -11,12 +11,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6.0.1
- name: update yaml files
run: |
sudo bash manual-install/update-yaml.sh
- name: Create Pull Request
- uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with:
commit-message: Yaml updates
signoff: true
diff --git a/.github/workflows/watchtower-update.yml b/.github/workflows/watchtower-update.yml
new file mode 100644
index 00000000..be929285
--- /dev/null
+++ b/.github/workflows/watchtower-update.yml
@@ -0,0 +1,37 @@
+name: watchtower-update
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: '00 12 * * *'
+
+jobs:
+ watchtower-update:
+ name: update watchtower
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6.0.1
+ - name: Run watchtower-container-update
+ run: |
+ # Watchtower
+ watchtower_version="$(
+ git ls-remote https://github.com/nicholas-fedor/watchtower v* \
+ | cut -d/ -f3 \
+ | sort -V \
+ | grep -E "^v[0-9\.]+$" \
+ | tail -1
+ )"
+ watchtower_commit_hash="$(git ls-remote https://github.com/nicholas-fedor/watchtower $watchtower_version | sed 's/refs.*//')"
+ sed -i "s|^ENV WATCHTOWER_COMMIT_HASH.*$|ENV WATCHTOWER_COMMIT_HASH=$watchtower_commit_hash|" ./Containers/watchtower/Dockerfile
+ sed -i "s|\$WATCHTOWER_COMMIT_HASH.*$|\$WATCHTOWER_COMMIT_HASH # $watchtower_version|" ./Containers/watchtower/Dockerfile
+
+ - name: Create Pull Request
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
+ with:
+ commit-message: watchtower-update automated change
+ signoff: true
+ title: watchtower container update
+ body: Automated watchtower container update
+ labels: dependencies, 3. to review
+ milestone: next
+ branch: watchtower-container-update
diff --git a/Containers/alpine/Dockerfile b/Containers/alpine/Dockerfile
index 8d180272..718c5510 100644
--- a/Containers/alpine/Dockerfile
+++ b/Containers/alpine/Dockerfile
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
-FROM alpine:3.21.3
+FROM alpine:3.23.2
RUN set -ex; \
apk upgrade --no-cache -a
diff --git a/Containers/apache/Caddyfile b/Containers/apache/Caddyfile
index 64fb5f93..4b92d807 100644
--- a/Containers/apache/Caddyfile
+++ b/Containers/apache/Caddyfile
@@ -15,6 +15,7 @@
}
https://{$ADDITIONAL_TRUSTED_DOMAIN}:443,
+http://{$APACHE_HOST}:23973, # For Collabora callback and WOPI requests, see containers.json
{$PROTOCOL}://{$NC_DOMAIN}:{$APACHE_PORT} {
header -Server
header -X-Powered-By
diff --git a/Containers/apache/Dockerfile b/Containers/apache/Dockerfile
index 615aeca4..9ccadfb8 100644
--- a/Containers/apache/Dockerfile
+++ b/Containers/apache/Dockerfile
@@ -1,8 +1,8 @@
# syntax=docker/dockerfile:latest
-FROM caddy:2.10.0-alpine AS caddy
+FROM caddy:2.10.2-alpine AS caddy
# From https://github.com/docker-library/httpd/blob/master/2.4/alpine/Dockerfile
-FROM httpd:2.4.63-alpine3.21
+FROM httpd:2.4.66-alpine3.23
COPY --from=caddy /usr/bin/caddy /usr/bin/caddy
@@ -88,4 +88,5 @@ CMD ["/usr/bin/supervisord", "-c", "/supervisord.conf"]
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/apache/start.sh b/Containers/apache/start.sh
index 9d69eb47..02a2f2ad 100644
--- a/Containers/apache/start.sh
+++ b/Containers/apache/start.sh
@@ -46,7 +46,9 @@ echo "$CADDYFILE" > /tmp/Caddyfile
# Change the trusted_proxies in case of reverse proxies
if [ "$APACHE_PORT" != '443' ]; then
- CADDYFILE="$(sed 's|# trusted_proxies placeholder|trusted_proxies static private_ranges|' /tmp/Caddyfile)"
+ # Here the 100.64.0.0/10 range gets added which is the CGNAT range used by Tailscale nodes
+ # See https://github.com/nextcloud/all-in-one/pull/6703 for reference
+ CADDYFILE="$(sed 's|# trusted_proxies placeholder|trusted_proxies static private_ranges 100.64.0.0/10|' /tmp/Caddyfile)"
else
CADDYFILE="$(sed "s|# trusted_proxies placeholder|trusted_proxies static $IPv4_ADDRESS|" /tmp/Caddyfile)"
fi
@@ -64,6 +66,11 @@ caddy fmt --overwrite /tmp/Caddyfile
# Add caddy path
mkdir -p /mnt/data/caddy/
+# Fix caddy startup
+if [ -d "/mnt/data/caddy/locks" ]; then
+ rm -rf /mnt/data/caddy/locks/*
+fi
+
# Fix apache startup
rm -f /usr/local/apache2/logs/httpd.pid
diff --git a/Containers/borgbackup/Dockerfile b/Containers/borgbackup/Dockerfile
index 70d2ea11..97d6198b 100644
--- a/Containers/borgbackup/Dockerfile
+++ b/Containers/borgbackup/Dockerfile
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
-FROM alpine:3.21.3
+FROM alpine:3.23.2
RUN set -ex; \
\
@@ -24,5 +24,6 @@ ENTRYPOINT ["/start.sh"]
USER root
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
ENV BORG_RETENTION_POLICY="--keep-within=7d --keep-weekly=4 --keep-monthly=6"
diff --git a/Containers/borgbackup/backupscript.sh b/Containers/borgbackup/backupscript.sh
index 602ec586..b7b96147 100644
--- a/Containers/borgbackup/backupscript.sh
+++ b/Containers/borgbackup/backupscript.sh
@@ -138,11 +138,6 @@ if [ "$BORG_MODE" = backup ]; then
NEW_REPOSITORY=1
if ! borg init --debug --encryption=repokey-blake2; then
echo "Could not initialize borg repository."
- if [ -z "$BORG_REMOTE_REPO" ]; then
- # Originally we checked for presence of the config file instead of calling `borg info`. Likely `borg info`
- # will error on a partially initialized repo, so this line is probably no longer necessary
- rm -f "$BORG_BACKUP_DIRECTORY/config"
- fi
exit 1
fi
@@ -199,7 +194,7 @@ if [ "$BORG_MODE" = backup ]; then
if [ -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/.noaiobackup" ]; then
BORG_EXCLUDE+=(--exclude "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/")
BORG_INCLUDE+=(--pattern="+/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/.noaiobackup")
- echo "⚠️⚠️⚠️ '.noaiobackup' file was found in Nextclouds data directory. Excluding the data directory from backup!"
+ echo "⚠️⚠️⚠️ '.noaiobackup' file was found in Nextcloud's data directory. Excluding the data directory from backup!"
# Exclude preview folder if .noaiobackup file was found
elif [ -f /nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/appdata_*/preview/.noaiobackup ]; then
BORG_EXCLUDE+=(--exclude "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/appdata_*/preview/")
@@ -344,7 +339,7 @@ if [ "$BORG_MODE" = restore ]; then
ADDITIONAL_RSYNC_EXCLUDES=(--exclude "nextcloud_aio_nextcloud_data/**")
ADDITIONAL_BORG_EXCLUDES=(--exclude "sh:nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/**")
ADDITIONAL_FIND_EXCLUDES=(-o -regex 'nextcloud_aio_volumes/nextcloud_aio_nextcloud_data\(/.*\)?')
- echo "⚠️⚠️⚠️ '.noaiobackup' file was found in Nextclouds data directory. Excluding the data directory from restore!"
+ echo "⚠️⚠️⚠️ '.noaiobackup' file was found in Nextcloud's data directory. Excluding the data directory from restore!"
echo "You might run into problems due to this afterwards as potentially this makes the directory go out of sync with the database."
echo "You might be able to fix this by running 'occ files:scan --all' and 'occ maintenance:repair' and 'occ files:scan-app-data' after the restore."
echo "See https://github.com/nextcloud/all-in-one#how-to-run-occ-commands"
@@ -617,3 +612,12 @@ if [ "$BORG_MODE" = test ]; then
fi
fi
fi
+
+if [ "$BORG_MODE" = list ]; then
+ echo "Updating backup list..."
+ if ! borg info > /dev/null; then
+ echo "Could not update the backup list."
+ exit 1
+ fi
+ # The update gets done automatically in the wrapper start.sh script.
+fi
diff --git a/Containers/borgbackup/start.sh b/Containers/borgbackup/start.sh
index 9da0d840..bb7a8a6a 100644
--- a/Containers/borgbackup/start.sh
+++ b/Containers/borgbackup/start.sh
@@ -32,8 +32,8 @@ else
fi
# Validate BORG_MODE
-if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != restore ] && [ "$BORG_MODE" != check ] && [ "$BORG_MODE" != "check-repair" ] && [ "$BORG_MODE" != test ]; then
- echo "No correct BORG_MODE mode applied. Valid are 'backup', 'check', 'restore' and 'test'."
+if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != restore ] && [ "$BORG_MODE" != check ] && [ "$BORG_MODE" != "check-repair" ] && [ "$BORG_MODE" != "test" ] && [ "$BORG_MODE" != "list" ]; then
+ echo "No correct BORG_MODE mode applied. Valid are 'backup', 'check', 'restore', 'test' and 'list'."
exit 1
fi
diff --git a/Containers/clamav/Dockerfile b/Containers/clamav/Dockerfile
index 2b7bd30b..e81fb06e 100644
--- a/Containers/clamav/Dockerfile
+++ b/Containers/clamav/Dockerfile
@@ -1,27 +1,38 @@
# syntax=docker/dockerfile:latest
-FROM alpine:3.21.3
+FROM alpine:3.23.2
RUN set -ex; \
apk upgrade --no-cache -a; \
- apk add --no-cache tzdata clamav supervisor bash; \
- mkdir -p /run/clamav /var/log/supervisord /var/run/supervisord; \
- chmod 777 -R /run/clamav /var/log/clamav /var/log/supervisord /var/run/supervisord; \
+ apk add --no-cache tzdata clamav clamav-milter supervisor bash; \
+ mkdir -p /tmp /var/lib/clamav /run/clamav /var/log/supervisord /var/run/supervisord; \
+ chmod 777 -R /tmp /run/clamav /var/log/clamav /var/log/supervisord /var/run/supervisord; \
+ chown -R 100:100 /var/lib/clamav; \
sed -i "s|#\?MaxDirectoryRecursion.*|MaxDirectoryRecursion 30|g" /etc/clamav/clamd.conf; \
- sed -i "s|#\?MaxFileSize.*|MaxFileSize 2G|g" /etc/clamav/clamd.conf; \
- sed -i "s|#\?PCREMaxFileSize.*|PCREMaxFileSize aio-placeholder|g" /etc/clamav/clamd.conf; \
- sed -i "s|#\?StreamMaxLength.*|StreamMaxLength aio-placeholder|g" /etc/clamav/clamd.conf; \
+ sed -i "s|#\?MaxScanSize.*|MaxScanSize 2000M|g" /etc/clamav/clamd.conf; \
+ sed -i "s|#\?MaxFileSize.*|MaxFileSize 2000M|g" /etc/clamav/clamd.conf; \
+ sed -i "s|#\?PCREMaxFileSize.*|PCREMaxFileSize 2000M|g" /etc/clamav/clamd.conf; \
+# StreamMaxLength must be synced with av_stream_max_length inside the Nextcloud files_antivirus plugin
+ sed -i "s|#\?StreamMaxLength.*|StreamMaxLength 2000M|g" /etc/clamav/clamd.conf; \
sed -i "s|#\?TCPSocket|TCPSocket|g" /etc/clamav/clamd.conf; \
sed -i "s|^LocalSocket .*|LocalSocket /tmp/clamd.sock|g" /etc/clamav/clamd.conf; \
- freshclam --foreground --stdout
+ sed -i "s|Example| |g" /etc/clamav/clamav-milter.conf; \
+ sed -i "s|#\?MilterSocket inet:7357|MilterSocket inet:7357|g" /etc/clamav/clamav-milter.conf; \
+ sed -i "s|#\?ClamdSocket unix:/run/clamav/clamd.sock|ClamdSocket unix:/tmp/clamd.sock|g" /etc/clamav/clamav-milter.conf; \
+ sed -i "s|#\?OnInfected Quarantine|OnInfected Reject|g" /etc/clamav/clamav-milter.conf; \
+ sed -i "s|#\?AddHeader Replace|AddHeader Add|g" /etc/clamav/clamav-milter.conf; \
+ sed -i "s|#\?Foreground yes|Foreground yes|g" /etc/clamav/clamav-milter.conf
COPY --chmod=775 start.sh /start.sh
COPY --chmod=775 healthcheck.sh /healthcheck.sh
COPY --chmod=664 supervisord.conf /supervisord.conf
USER 100
+RUN set -ex; \
+ freshclam --foreground --stdout
VOLUME /var/lib/clamav
ENTRYPOINT ["/start.sh"]
CMD ["/usr/bin/supervisord", "-c", "/supervisord.conf"]
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
HEALTHCHECK --start-period=60s --retries=9 CMD /healthcheck.sh
diff --git a/Containers/clamav/start.sh b/Containers/clamav/start.sh
index fa10d0e5..609120c1 100644
--- a/Containers/clamav/start.sh
+++ b/Containers/clamav/start.sh
@@ -1,6 +1,7 @@
#!/bin/bash
-sed "s|aio-placeholder|$MAX_SIZE|" /etc/clamav/clamd.conf > /tmp/clamd.conf
+# Print out clamav version for compliance reasons
+clamscan --version
echo "Clamav started"
diff --git a/Containers/clamav/supervisord.conf b/Containers/clamav/supervisord.conf
index 8f53856a..1895ceb6 100644
--- a/Containers/clamav/supervisord.conf
+++ b/Containers/clamav/supervisord.conf
@@ -13,11 +13,18 @@ stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
-command=freshclam --foreground --stdout --daemon --daemon-notify=/tmp/clamd.conf
+command=freshclam --foreground --stdout --daemon --daemon-notify=/etc/clamav/clamd.conf
[program:clamd]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
-command=clamd --foreground --config-file=/tmp/clamd.conf
+command=clamd --foreground --config-file=/etc/clamav/clamd.conf
+
+[program:milter]
+stdout_logfile=/dev/stdout
+stdout_logfile_maxbytes=0
+stderr_logfile=/dev/stderr
+stderr_logfile_maxbytes=0
+command=clamav-milter --config-file=/etc/clamav/clamav-milter.conf
\ No newline at end of file
diff --git a/Containers/collabora-online/Dockerfile b/Containers/collabora-online/Dockerfile
new file mode 100644
index 00000000..ec8b63f0
--- /dev/null
+++ b/Containers/collabora-online/Dockerfile
@@ -0,0 +1,16 @@
+# syntax=docker/dockerfile:latest
+# From https://gitlab.collabora.com/collabora-online/docker
+# hadolint ignore=DL3007
+FROM registry.gitlab.collabora.com/collabora-online/docker:latest
+
+USER root
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --chmod=775 healthcheck.sh /healthcheck.sh
+
+USER 1001
+
+HEALTHCHECK --start-period=60s --retries=9 CMD /healthcheck.sh
+LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
+ org.label-schema.vendor="Nextcloud"
diff --git a/Containers/collabora-online/healthcheck.sh b/Containers/collabora-online/healthcheck.sh
new file mode 100644
index 00000000..45e9278b
--- /dev/null
+++ b/Containers/collabora-online/healthcheck.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Unfortunately, no curl and no nc is installed in the container
+# and packages can also not be added as the package list is broken.
+# So always exiting 0 for now.
+# nc http://127.0.0.1:9980 || exit 1
+exit 0
diff --git a/Containers/collabora/Dockerfile b/Containers/collabora/Dockerfile
index 5fd88186..976360cb 100644
--- a/Containers/collabora/Dockerfile
+++ b/Containers/collabora/Dockerfile
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest
# From a file located probably somewhere here: https://github.com/CollaboraOnline/online/blob/master/docker/from-packages/Dockerfile
-FROM collabora/code:25.04.3.1.1
+FROM collabora/code:25.04.8.1.1
USER root
ARG DEBIAN_FRONTEND=noninteractive
@@ -11,4 +11,5 @@ USER 1001
HEALTHCHECK --start-period=60s --retries=9 CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/docker-socket-proxy/Dockerfile b/Containers/docker-socket-proxy/Dockerfile
index bcc7ac71..62590f6f 100644
--- a/Containers/docker-socket-proxy/Dockerfile
+++ b/Containers/docker-socket-proxy/Dockerfile
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
-FROM haproxy:3.2.2-alpine
+FROM haproxy:3.3.1-alpine
# hadolint ignore=DL3002
USER root
@@ -19,4 +19,5 @@ COPY --chmod=664 haproxy.cfg /haproxy.cfg
ENTRYPOINT ["/start.sh"]
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/domaincheck/Dockerfile b/Containers/domaincheck/Dockerfile
index 9b248e39..8122f315 100644
--- a/Containers/domaincheck/Dockerfile
+++ b/Containers/domaincheck/Dockerfile
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
-FROM alpine:3.21.3
+FROM alpine:3.23.2
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache bash lighttpd netcat-openbsd; \
@@ -18,4 +18,5 @@ ENTRYPOINT ["/start.sh"]
HEALTHCHECK CMD nc -z 127.0.0.1 $APACHE_PORT || exit 1
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/fulltextsearch/Dockerfile b/Containers/fulltextsearch/Dockerfile
index ae7eee63..ff1e923f 100644
--- a/Containers/fulltextsearch/Dockerfile
+++ b/Containers/fulltextsearch/Dockerfile
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest
# Probably from here https://github.com/elastic/elasticsearch/blob/main/distribution/docker/src/docker/Dockerfile
-FROM elasticsearch:8.18.2
+FROM elasticsearch:8.19.10
USER root
@@ -22,5 +22,6 @@ USER 1000:0
HEALTHCHECK --interval=10s --timeout=5s --start-period=1m --retries=5 CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
ENV ES_JAVA_OPTS="-Xms512M -Xmx512M"
diff --git a/Containers/imaginary/Dockerfile b/Containers/imaginary/Dockerfile
index 08cabd2c..650c4c67 100644
--- a/Containers/imaginary/Dockerfile
+++ b/Containers/imaginary/Dockerfile
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:latest
-FROM golang:1.24.4-alpine3.21 AS go
+FROM golang:1.25.6-alpine3.23 AS go
-ENV IMAGINARY_HASH=1d4e251cfcd58ea66f8361f8721d7b8cc85002a3
+ENV IMAGINARY_HASH=6a274b488759a896aff02f52afee6e50b5e3a3ee
RUN set -ex; \
apk upgrade --no-cache -a; \
@@ -14,7 +14,7 @@ RUN set -ex; \
build-base; \
go install github.com/h2non/imaginary@"$IMAGINARY_HASH";
-FROM alpine:3.21.3
+FROM alpine:3.23.2
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache \
@@ -43,4 +43,5 @@ ENTRYPOINT ["/start.sh"]
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/mastercontainer/Dockerfile b/Containers/mastercontainer/Dockerfile
index e5764d4c..2fea59d1 100644
--- a/Containers/mastercontainer/Dockerfile
+++ b/Containers/mastercontainer/Dockerfile
@@ -1,23 +1,30 @@
# syntax=docker/dockerfile:latest
# Docker CLI is a requirement
-FROM docker:28.3.0-cli AS docker
+FROM docker:29.1.5-cli AS docker
# Caddy is a requirement
-FROM caddy:2.10.0-alpine AS caddy
+FROM caddy:2.10.2-alpine AS caddy
-# From https://github.com/docker-library/php/blob/master/8.4/alpine3.21/fpm/Dockerfile
-FROM php:8.4.8-fpm-alpine3.21
-
-ARG AIO_GIT_URL="https://github.com/nextcloud-releases/all-in-one.git"
-ARG AIO_GIT_BRANCH="main"
+# From https://github.com/docker-library/php/blob/master/8.4/alpine3.23/fpm/Dockerfile
+FROM php:8.4.17-fpm-alpine3.23
EXPOSE 80
EXPOSE 8080
EXPOSE 8443
+# Overwrite home variable for subservices
+ENV HOME=/var/www
+
COPY --from=caddy /usr/bin/caddy /usr/bin/caddy
COPY --from=docker /usr/local/bin/docker /usr/local/bin/docker
+COPY community-containers /var/www/docker-aio/community-containers
+COPY php /var/www/docker-aio/php
+COPY --chmod=775 Containers/mastercontainer/*.sh /
+COPY --chmod=664 Containers/mastercontainer/Caddyfile /Caddyfile
+COPY --chmod=664 Containers/mastercontainer/supervisord.conf /supervisord.conf
+COPY Containers/mastercontainer/mastercontainer.conf /etc/apache2/sites-available/mastercontainer.conf
+
WORKDIR /var/www/docker-aio
# hadolint ignore=SC2086,DL3047,DL3003,DL3004
@@ -45,7 +52,7 @@ RUN set -ex; \
apk add --no-cache --virtual .build-deps \
autoconf \
build-base; \
- pecl install APCu-5.1.24; \
+ pecl install APCu-5.1.28; \
docker-php-ext-enable apcu; \
rm -r /tmp/pear; \
runDeps="$( \
@@ -67,13 +74,11 @@ RUN set -ex; \
wget https://getcomposer.org/installer -O - | php -- --install-dir=/usr/local/bin --filename=composer; \
chmod +x /usr/local/bin/composer; \
cd /var/www/docker-aio; \
- git clone "$AIO_GIT_URL" --depth 1 --single-branch --branch "$AIO_GIT_BRANCH" .; \
- find ./ -maxdepth 1 -mindepth 1 -not -path ./php -not -path ./community-containers -exec rm -r {} \; ; \
rm -r ./php/tests; \
chown www-data:www-data -R /var/www/docker-aio; \
cd php; \
- sudo -u www-data composer install --no-dev; \
- sudo -u www-data composer clear-cache; \
+ sudo -E -u www-data composer install --no-dev; \
+ sudo -E -u www-data composer clear-cache; \
cd ..; \
rm -f /usr/local/bin/composer; \
chmod -R 770 /var/www/docker-aio; \
@@ -120,12 +125,10 @@ RUN set -ex; \
mkdir /var/log/supervisord; \
mkdir /var/run/supervisord;
-COPY --chmod=775 *.sh /
-COPY --chmod=664 Caddyfile /Caddyfile
-COPY --chmod=664 supervisord.conf /supervisord.conf
-COPY mastercontainer.conf /etc/apache2/sites-available/mastercontainer.conf
-
-LABEL org.label-schema.vendor="Nextcloud"
+# hadolint ignore=DL3048
+LABEL org.label-schema.vendor="Nextcloud" \
+ wud.watch="false" \
+ com.docker.compose.project="nextcloud-aio"
# hadolint ignore=DL3002
USER root
diff --git a/Containers/mastercontainer/README.md b/Containers/mastercontainer/README.md
new file mode 100644
index 00000000..de6b535d
--- /dev/null
+++ b/Containers/mastercontainer/README.md
@@ -0,0 +1,69 @@
+# Nextcloud All-in-One `mastercontainer`
+
+This folder contains the OCI/Docker container definition, along with associated resources and
+configuration files, for building the `mastercontainer` as part of the Nextcloud All-in-One
+project. This container hosts [the Nextcloud AIO interface](
+https://github.com/nextcloud/all-in-one/tree/main/php)[^app], and a dedicated PHP environment
+for it (which is completely independent of the Nextcloud Server).
+
+## Overview
+
+The mastercontainer acts as the central orchestration service for the deployment and management
+of all other containers in the Nextcloud All-in-One stack. It hosts:
+
+- A dedicated PHP SAPI/backend (php-fpm) for AIO itself (not Nextcloud Server)
+- An Apache service for accessing the AIO interface via a self-signed HTTPS VirtualHost on 8080/tcp
+- A Caddy reverse proxy service enabling HTTPS access to the AIO frontend on port 8443/tcp.
+ - Caddy will automatically issue a Let's Encrypt issued certificate if port 80 and 8443
+ is open/forwarded and a domain pointer is in place; then, simply open the Nextcloud AIO interface using the
+ domain (`https://your-domain-that-points-to-this-server.tld:8443`). The Let's Encrypt certificate request will
+ use an [ACME HTTP-01](https://letsencrypt.org/docs/challenge-types/#http-01-challenge) challenge.
+- Miscellaneous support services specific to AIO (backup management, health checks, etc.)
+
+## Key Responsibilities
+
+- Orchestrates the deployment and lifecycle of all Nextcloud service containers
+- Handles initial setup and container configuration
+- Coordinates image updates
+- Monitors general system health
+
+It triggers the initial installation and ensures the smooth operation of the Nextcloud
+All-in-One stack.
+
+## Contents
+
+- **Dockerfile**: Instructions for building the mastercontainer image.
+- **Entrypoint script**: The `start.sh` script is used for container initialization and runtime
+ configuration before starting supervisord.
+- [**Nextcloud All-in-One Controller App**](https://github.com/nextcloud/all-in-one/tree/main/php): The
+ core AIO orchestrator that handles configuration and settings for the containers.
+- **Supervisor**: The `supervisord.conf` file defines the long-running services hosted within
+ the container (php-fpm, cron, etc.)
+
+## Usage
+
+This container should be used as the trigger image when deploying the Nextcloud All-in-One
+stack in a Docker or other OCI-compliant container environment. For detailed deployment
+instructions, refer to the [project documentation](
+https://github.com/nextcloud/all-in-one).
+
+## Related Resources
+
+- [Main Repository](https://github.com/nextcloud/all-in-one)
+- [Documentation](https://github.com/nextcloud/all-in-one#readme)
+
+## Contributing
+
+Contributions are welcome! Please follow the Nextcloud project's guidelines and submit pull
+requests or issues via the main repository.
+
+## License
+
+This folder and its contents are licensed under the
+[GNU AGPLv3](https://www.gnu.org/licenses/agpl-3.0.html), in line with the rest of Nextcloud
+All-in-One.
+
+[^app]: The Nextcloud All-in-One interface allows users to install, configure, and
+manage their Nextcloud instance and related containers via a secure web interface and API.
+It automates and simplifies complex tasks such as container orchestration, backups, updates,
+and service management for users deploying Nextcloud in Docker environments.
diff --git a/Containers/mastercontainer/cron.sh b/Containers/mastercontainer/cron.sh
index fc8c4081..67af80e7 100644
--- a/Containers/mastercontainer/cron.sh
+++ b/Containers/mastercontainer/cron.sh
@@ -45,29 +45,29 @@ while true; do
# Check for updates and send notification if yes on saturdays
if [ "$(date +%u)" = 6 ]; then
- sudo -u www-data php /var/www/docker-aio/php/src/Cron/UpdateNotification.php
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/UpdateNotification.php
fi
# Check if AIO is outdated
- sudo -u www-data php /var/www/docker-aio/php/src/Cron/OutdatedNotification.php
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/OutdatedNotification.php
# Remove sessions older than 24h
find "/mnt/docker-aio-config/session/" -mindepth 1 -mmin +1440 -delete
# Remove nextcloud-aio-domaincheck container
- if sudo -u www-data docker ps --format "{{.Names}}" --filter "status=exited" | grep -q "^nextcloud-aio-domaincheck$"; then
- sudo -u www-data docker container remove nextcloud-aio-domaincheck
+ if sudo -E -u www-data docker ps --format "{{.Names}}" --filter "status=exited" | grep -q "^nextcloud-aio-domaincheck$"; then
+ sudo -E -u www-data docker container remove nextcloud-aio-domaincheck
fi
# Remove dangling images
- sudo -u www-data docker image prune --force
+ sudo -E -u www-data docker image prune --filter "label=org.label-schema.vendor=Nextcloud" --force
# Check for available free space
- sudo -u www-data php /var/www/docker-aio/php/src/Cron/CheckFreeDiskSpace.php
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/CheckFreeDiskSpace.php
# Remove mastercontainer from default bridge network
- if sudo -u www-data docker inspect nextcloud-aio-mastercontainer --format "{{.NetworkSettings.Networks}}" | grep -q "bridge"; then
- sudo -u www-data docker network disconnect bridge nextcloud-aio-mastercontainer
+ if sudo -E -u www-data docker inspect nextcloud-aio-mastercontainer --format "{{.NetworkSettings.Networks}}" | grep -q "bridge"; then
+ sudo -E -u www-data docker network disconnect bridge nextcloud-aio-mastercontainer
fi
# Wait 60s so that the whole loop will not be executed again
diff --git a/Containers/mastercontainer/daily-backup.sh b/Containers/mastercontainer/daily-backup.sh
index c68835ea..d11f3e85 100644
--- a/Containers/mastercontainer/daily-backup.sh
+++ b/Containers/mastercontainer/daily-backup.sh
@@ -20,11 +20,11 @@ fi
if [ "$LOCK_FILE_PRESENT" = 0 ] || ! [ -f "/mnt/docker-aio-config/data/daily_backup_running" ]; then
find "/mnt/docker-aio-config/session/" -mindepth 1 -delete
fi
-sudo -u www-data touch "/mnt/docker-aio-config/data/daily_backup_running"
+sudo -E -u www-data touch "/mnt/docker-aio-config/data/daily_backup_running"
# Check if apache is running/stopped, watchtower is stopped and backupcontainer is stopped
-APACHE_PORT="$(docker inspect nextcloud-aio-apache --format "{{.Config.Env}}" | grep -o 'APACHE_PORT=[0-9]\+' | grep -o '[0-9]\+' | head -1)"
-if [ -z "$APACHE_PORT" ]; then
+LOCAL_APACHE_PORT="$(docker inspect nextcloud-aio-apache --format "{{.Config.Env}}" | grep -o 'APACHE_PORT=[0-9]\+' | grep -o '[0-9]\+' | head -1)"
+if [ -z "$LOCAL_APACHE_PORT" ]; then
echo "APACHE_PORT is not set which is not expected..."
else
# Connect mastercontainer to nextcloud-aio network to make sure that nextcloud-aio-apache is reachable
@@ -32,7 +32,7 @@ else
docker network connect nextcloud-aio nextcloud-aio-mastercontainer &>/dev/null
# Wait for apache to start
- while docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-apache$" && ! nc -z nextcloud-aio-apache "$APACHE_PORT"; do
+ while docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-apache$" && ! nc -z nextcloud-aio-apache "$LOCAL_APACHE_PORT"; do
echo "Waiting for apache to become available"
sleep 30
done
@@ -50,7 +50,7 @@ done
if [ "$AUTOMATIC_UPDATES" = 1 ]; then
echo "Starting mastercontainer update..."
echo "(The script might get exited due to that. In order to update all the other containers correctly, you need to run this script with the same settings a second time.)"
- sudo -u www-data php /var/www/docker-aio/php/src/Cron/UpdateMastercontainer.php
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/UpdateMastercontainer.php
fi
# Wait for watchtower to stop
@@ -64,17 +64,23 @@ if [ "$AUTOMATIC_UPDATES" = 1 ]; then
done
fi
+# Update container images to reduce downtime later on
+if [ "$AUTOMATIC_UPDATES" = 1 ]; then
+ echo "Updating container images..."
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/PullContainerImages.php
+fi
+
# Stop containers if required
# shellcheck disable=SC2235
if [ "$CHECK_BACKUP" != 1 ] && ([ "$DAILY_BACKUP" != 1 ] || [ "$STOP_CONTAINERS" = 1 ]); then
echo "Stopping containers..."
- sudo -u www-data php /var/www/docker-aio/php/src/Cron/StopContainers.php
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/StopContainers.php
fi
# Execute the backup itself and some related tasks (also stops the containers)
if [ "$DAILY_BACKUP" = 1 ]; then
echo "Creating daily backup..."
- sudo -u www-data php /var/www/docker-aio/php/src/Cron/CreateBackup.php
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/CreateBackup.php
if ! docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-borgbackup$"; then
echo "Something seems to be wrong: the borg container should be started at this step."
fi
@@ -87,17 +93,17 @@ fi
# Execute backup check
if [ "$CHECK_BACKUP" = 1 ]; then
echo "Starting backup check..."
- sudo -u www-data php /var/www/docker-aio/php/src/Cron/CheckBackup.php
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/CheckBackup.php
fi
# Start and/or update containers
if [ "$AUTOMATIC_UPDATES" = 1 ]; then
echo "Starting and updating containers..."
- sudo -u www-data php /var/www/docker-aio/php/src/Cron/StartAndUpdateContainers.php
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/StartAndUpdateContainers.php
else
if [ "$START_CONTAINERS" = 1 ]; then
echo "Starting containers without updating them..."
- sudo -u www-data php /var/www/docker-aio/php/src/Cron/StartContainers.php
+ sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/StartContainers.php
fi
fi
diff --git a/Containers/mastercontainer/mastercontainer.conf b/Containers/mastercontainer/mastercontainer.conf
index 6a7d37dd..7d294694 100644
--- a/Containers/mastercontainer/mastercontainer.conf
+++ b/Containers/mastercontainer/mastercontainer.conf
@@ -1,5 +1,5 @@
-Listen 8000
-Listen 8080
+Listen 127.0.0.1:8000
+Listen 8080 https
# Deny access to .ht files
@@ -7,8 +7,8 @@ Listen 8080
# Http host
-
- ServerName localhost
+
+ ServerName 127.0.0.1
# Add error log
CustomLog /proc/self/fd/1 proxy
diff --git a/Containers/mastercontainer/start.sh b/Containers/mastercontainer/start.sh
index 9b948776..ad1734f1 100644
--- a/Containers/mastercontainer/start.sh
+++ b/Containers/mastercontainer/start.sh
@@ -33,17 +33,25 @@ if [ "$*" != "" ]; then
fi
# Check if socket is available and readable
-if ! [ -a "/var/run/docker.sock" ]; then
+if ! [ -e "/var/run/docker.sock" ]; then
print_red "Docker socket is not available. Cannot continue."
echo "Please make sure to mount the docker socket into /var/run/docker.sock inside the container!"
echo "If you did this by purpose because you don't want the container to have access to the docker socket, see https://github.com/nextcloud/all-in-one/tree/main/manual-install."
+ echo "And https://github.com/nextcloud/all-in-one/blob/main/manual-install/latest.yml"
exit 1
elif ! mountpoint -q "/mnt/docker-aio-config"; then
print_red "/mnt/docker-aio-config is not a mountpoint. Cannot proceed!"
echo "Please make sure to mount the nextcloud_aio_mastercontainer docker volume into /mnt/docker-aio-config inside the container!"
echo "If you are on TrueNas SCALE, see https://github.com/nextcloud/all-in-one#can-i-run-aio-on-truenas-scale"
exit 1
-elif ! sudo -u www-data test -r /var/run/docker.sock; then
+elif mountpoint -q /var/www/docker-aio/php/containers.json; then
+ print_red "/var/www/docker-aio/php/containers.json is a mountpoint. Cannot proceed!"
+ echo "This is a not-supported customization of the mastercontainer!"
+ echo "Please remove this bind-mount from the mastercontainer."
+ echo "If you need to customize things, feel free to use https://github.com/nextcloud/all-in-one/tree/main/manual-install"
+ echo "See https://github.com/nextcloud/all-in-one/blob/main/manual-install/latest.yml"
+ exit 1
+elif ! sudo -E -u www-data test -r /var/run/docker.sock; then
echo "Trying to fix docker.sock permissions internally..."
DOCKER_GROUP=$(stat -c '%G' /var/run/docker.sock)
DOCKER_GROUP_ID=$(stat -c '%g' /var/run/docker.sock)
@@ -61,28 +69,68 @@ elif ! sudo -u www-data test -r /var/run/docker.sock; then
groupadd -g "$DOCKER_GROUP_ID" docker
usermod -aG docker www-data
fi
- if ! sudo -u www-data test -r /var/run/docker.sock; then
+ if ! sudo -E -u www-data test -r /var/run/docker.sock; then
print_red "Docker socket is not readable by the www-data user. Cannot continue."
exit 1
fi
fi
-# Check if api version is supported
-if ! sudo -u www-data docker info &>/dev/null; then
- print_red "Cannot connect to the docker socket. Cannot proceed."
- echo "Did you maybe remove group read permissions for the docker socket? AIO needs them in order to access the docker socket."
- echo "If SELinux is enabled on your host, see https://github.com/nextcloud/all-in-one#are-there-known-problems-when-selinux-is-enabled"
- echo "If you are on TrueNas SCALE, see https://github.com/nextcloud/all-in-one#can-i-run-aio-on-truenas-scale"
- exit 1
-fi
+# Get default docker api version
API_VERSION_FILE="$(find ./ -name DockerActionManager.php | head -1)"
API_VERSION="$(grep -oP 'const string API_VERSION.*\;' "$API_VERSION_FILE" | grep -oP '[0-9]+.[0-9]+' | head -1)"
+if [ -z "$API_VERSION" ]; then
+ print_red "Could not get API_VERSION. Something is wrong!"
+ exit 1
+fi
+
+# Check if DOCKER_API_VERSION is set globally
+if [ -n "$DOCKER_API_VERSION" ]; then
+ if ! echo "$DOCKER_API_VERSION" | grep -q '^[0-9].[0-9]\+$'; then
+ print_red "You've set DOCKER_API_VERSION but not to an allowed value.
+The string must be a version number like e.g. '1.44'.
+It is set to '$DOCKER_API_VERSION'."
+ exit 1
+ fi
+ print_red "DOCKER_API_VERSION was found to be set to '$DOCKER_API_VERSION'."
+ print_red "Please note that only v$API_VERSION is officially supported and tested by the maintainers of Nextcloud AIO."
+ print_red "So you run on your own risk and things might break without warning."
+else
+ # Export docker api version to use it everywhere
+ export DOCKER_API_VERSION="$API_VERSION"
+fi
+
+# Set a fallback docker api version. Needed for api version check.
+# The check will not work otherwise on old docker versions
+FALLBACK_DOCKER_API_VERSION="1.41"
+
+# Check if docker info can be used
+if ! sudo -E -u www-data docker info &>/dev/null; then
+ if ! sudo -E -u www-data DOCKER_API_VERSION="$FALLBACK_DOCKER_API_VERSION" docker info &>/dev/null; then
+ print_red "Cannot connect to the docker socket. Cannot proceed."
+ echo "Did you maybe remove group read permissions for the docker socket? AIO needs them in order to access the docker socket."
+ echo "If SELinux is enabled on your host, see https://github.com/nextcloud/all-in-one#are-there-known-problems-when-selinux-is-enabled"
+ echo "If you are on TrueNas SCALE, see https://github.com/nextcloud/all-in-one#can-i-run-aio-on-truenas-scale"
+ echo "On macOS, see https://github.com/nextcloud/all-in-one#how-to-run-aio-on-macos"
+ echo "Another possibility might be that Docker api v$API_VERSION is not supported by your docker daemon."
+ echo "In that case, you should report this to https://github.com/nextcloud/all-in-one/issues"
+ echo ""
+ exit 1
+ fi
+fi
+
+# Docker api version check
# shellcheck disable=SC2001
-API_VERSION_NUMB="$(echo "$API_VERSION" | sed 's/\.//')"
-LOCAL_API_VERSION_NUMB="$(sudo -u www-data docker version | grep -i "api version" | grep -oP '[0-9]+.[0-9]+' | head -1 | sed 's/\.//')"
+API_VERSION_NUMB="$(echo "$DOCKER_API_VERSION" | sed 's/\.//')"
+LOCAL_API_VERSION_NUMB="$(sudo -E -u www-data docker version | grep -i "api version" | grep -oP '[0-9]+.[0-9]+' | head -1 | sed 's/\.//')"
+if [ -z "$LOCAL_API_VERSION_NUMB" ]; then
+ LOCAL_API_VERSION_NUMB="$(sudo -E -u www-data DOCKER_API_VERSION="$FALLBACK_DOCKER_API_VERSION" docker version | grep -i "api version" | grep -oP '[0-9]+.[0-9]+' | head -1 | sed 's/\.//')"
+fi
if [ -n "$LOCAL_API_VERSION_NUMB" ] && [ -n "$API_VERSION_NUMB" ]; then
if ! [ "$LOCAL_API_VERSION_NUMB" -ge "$API_VERSION_NUMB" ]; then
- print_red "Docker API v$API_VERSION is not supported by your docker engine. Cannot proceed. Please upgrade your docker engine if you want to run Nextcloud AIO!"
+ print_red "Docker API v$DOCKER_API_VERSION is not supported by your docker engine. Cannot proceed. Please upgrade your docker engine if you want to run Nextcloud AIO!"
+ echo "Alternatively, set the DOCKER_API_VERSION environmental variable to a compatible version."
+ echo "However please note that only v$API_VERSION is officially supported and tested by the maintainers of Nextcloud AIO."
+ echo "See https://github.com/nextcloud/all-in-one#how-to-adjust-the-internally-used-docker-api-version"
exit 1
fi
else
@@ -91,7 +139,7 @@ else
fi
# Check Storage drivers
-STORAGE_DRIVER="$(sudo -u www-data docker info | grep "Storage Driver")"
+STORAGE_DRIVER="$(sudo -E -u www-data docker info | grep "Storage Driver")"
# Check if vfs is used: https://github.com/nextcloud/all-in-one/discussions/1467
if echo "$STORAGE_DRIVER" | grep -q vfs; then
echo "$STORAGE_DRIVER"
@@ -102,23 +150,23 @@ elif echo "$STORAGE_DRIVER" | grep -q fuse-overlayfs; then
fi
# Check if snap install
-if sudo -u www-data docker info | grep "Docker Root Dir" | grep "/var/snap/docker/"; then
+if sudo -E -u www-data docker info | grep "Docker Root Dir" | grep "/var/snap/docker/"; then
print_red "Warning: It looks like your installation uses docker installed via snap."
print_red "This comes with some limitations and is disrecommended by the docker maintainers."
print_red "See for example https://github.com/nextcloud/all-in-one/discussions/4890#discussioncomment-10386752"
fi
# Check if startup command was executed correctly
-if ! sudo -u www-data docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-mastercontainer$"; then
+if ! sudo -E -u www-data docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-mastercontainer$"; then
print_red "It seems like you did not give the mastercontainer the correct name? (The 'nextcloud-aio-mastercontainer' container was not found.)
Using a different name is not supported since mastercontainer updates will not work in that case!
If you are on docker swarm and try to run AIO, see https://github.com/nextcloud/all-in-one#can-i-run-this-with-docker-swarm"
exit 1
-elif ! sudo -u www-data docker volume ls --format "{{.Name}}" | grep -q "^nextcloud_aio_mastercontainer$"; then
+elif ! sudo -E -u www-data docker volume ls --format "{{.Name}}" | grep -q "^nextcloud_aio_mastercontainer$"; then
print_red "It seems like you did not give the mastercontainer volume the correct name? (The 'nextcloud_aio_mastercontainer' volume was not found.)
Using a different name is not supported since the built-in backup solution will not work in that case!"
exit 1
-elif ! sudo -u www-data docker inspect nextcloud-aio-mastercontainer | grep -q "nextcloud_aio_mastercontainer"; then
+elif ! sudo -E -u www-data docker inspect nextcloud-aio-mastercontainer | grep -q "nextcloud_aio_mastercontainer"; then
print_red "It seems like you did not attach the 'nextcloud_aio_mastercontainer' volume to the mastercontainer?
This is not supported since the built-in backup solution will not work in that case!"
exit 1
@@ -269,6 +317,7 @@ if ! curl --no-progress-meter https://ghcr.io/v2/ >/dev/null; then
echo "Most likely is something blocking access to it."
echo "You should be able to fix this by following https://dockerlabs.collabnix.com/intermediate/networking/Configuring_DNS.html"
echo "Another solution is using https://github.com/nextcloud/all-in-one/tree/main/manual-install"
+ echo "See https://github.com/nextcloud/all-in-one/blob/main/manual-install/latest.yml"
exit 1
fi
@@ -279,6 +328,13 @@ if [ -n "$TZ" ]; then
# Disable exit since it seems to be by default set on unraid and we dont want to break these instances
# exit 1
fi
+# Check that http proxy or no_proxy variable is not set which AIO does not support
+if [ -n "$HTTP_PROXY" ] || [ -n "$http_proxy" ] || [ -n "$HTTPS_PROXY" ] || [ -n "$https_proxy" ] || [ -n "$NO_PROXY" ] || [ -n "$no_proxy" ]; then
+ print_red "The environmental variable HTTP_PROXY, http_proxy, HTTPS_PROXY, https_proxy, NO_PROXY or no_proxy has been set which is not supported by AIO."
+ echo "If you need this, then you should use https://github.com/nextcloud/all-in-one/tree/main/manual-install"
+ echo "See https://github.com/nextcloud/all-in-one/blob/main/manual-install/latest.yml"
+ exit 1
+fi
if mountpoint -q /etc/localtime; then
print_red "/etc/localtime has been mounted into the container which is not allowed because AIO only supports running in the default Etc/UTC timezone!"
echo "The correct timezone can be set in the AIO interface later on!"
@@ -359,6 +415,11 @@ export TZ=Etc/UTC
# Fix apache startup
rm -f /var/run/apache2/httpd.pid
+# Fix caddy startup
+if [ -d "/mnt/docker-aio-config/caddy/locks" ]; then
+ rm -rf /mnt/docker-aio-config/caddy/locks/*
+fi
+
# Fix the Caddyfile format
caddy fmt --overwrite /Caddyfile
diff --git a/Containers/nextcloud/Dockerfile b/Containers/nextcloud/Dockerfile
index da201e06..c6d9bf7e 100644
--- a/Containers/nextcloud/Dockerfile
+++ b/Containers/nextcloud/Dockerfile
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
-FROM php:8.3.22-fpm-alpine3.21
+FROM php:8.3.30-fpm-alpine3.23
ENV PHP_MEMORY_LIMIT=512M
ENV PHP_UPLOAD_LIMIT=16G
@@ -8,16 +8,20 @@ ENV SOURCE_LOCATION=/usr/src/nextcloud
ENV REDIS_DB_INDEX=0
# AIO settings start # Do not remove or change this line!
-ENV NEXTCLOUD_VERSION=31.0.6
+ENV NEXTCLOUD_VERSION=32.0.5
ENV AIO_TOKEN=123456
ENV AIO_URL=localhost
# AIO settings end # Do not remove or change this line!
-COPY --chmod=775 *.sh /
-COPY --chmod=774 upgrade.exclude /upgrade.exclude
-COPY config/*.php /
-COPY supervisord.conf /supervisord.conf
-COPY root.motd /root.motd
+COPY --chmod=775 Containers/nextcloud/*.sh /
+COPY --chmod=774 Containers/nextcloud/upgrade.exclude /upgrade.exclude
+COPY Containers/nextcloud/config/*.php /
+COPY Containers/nextcloud/supervisord.conf /supervisord.conf
+
+# AIO cloning start # Do not remove or change this line!
+COPY app /usr/src/nextcloud/apps/nextcloud-aio
+COPY Containers/nextcloud/root.motd /root.motd
+# AIO cloning end # Do not remove or change this line!
VOLUME /mnt/ncdata
VOLUME /var/www/html
@@ -79,16 +83,17 @@ RUN set -ex; \
\
# pecl will claim success even if one install fails, so we need to perform each install separately
pecl install -o igbinary-3.2.16; \
- pecl install APCu-5.1.24; \
- pecl install -D 'enable-memcached-igbinary="yes"' memcached-3.3.0; \
- pecl install -oD 'enable-redis-igbinary="yes" enable-redis-zstd="yes" enable-redis-lz4="yes"' redis-6.2.0; \
- pecl install -o imagick-3.8.0; \
+ pecl install APCu-5.1.28; \
+ pecl install -D 'enable-memcached-igbinary="yes"' memcached-3.4.0; \
+ pecl install -oD 'enable-redis-igbinary="yes" enable-redis-zstd="yes" enable-redis-lz4="yes"' redis-6.3.0; \
+ pecl install -o imagick-3.8.1; \
\
docker-php-ext-enable \
igbinary \
apcu \
memcached \
redis \
+ imagick \
; \
rm -r /tmp/pear; \
\
@@ -107,7 +112,7 @@ RUN set -ex; \
} >> /usr/local/etc/php/conf.d/docker-php-ext-igbinary.ini; \
\
# set recommended PHP.ini settings
-# see https://docs.nextcloud.com/server/stable/admin_manual/configuration_server/server_tuning.html#enable-php-opcache
+# see https://docs.nextcloud.com/server/stable/admin_manual/installation/server_tuning.html#enable-php-opcache and below
{ \
echo 'opcache.max_accelerated_files=10000'; \
echo 'opcache.memory_consumption=256'; \
@@ -128,13 +133,13 @@ RUN set -ex; \
echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \
echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \
echo 'max_execution_time=${PHP_MAX_TIME}'; \
- echo 'max_input_time=${PHP_MAX_TIME}'; \
+ echo 'max_input_time=-1'; \
echo 'default_socket_timeout=${PHP_MAX_TIME}'; \
} > /usr/local/etc/php/conf.d/nextcloud.ini; \
\
{ \
echo 'session.save_handler = redis'; \
- echo 'session.save_path = "tcp://${REDIS_HOST}:6379?database=${REDIS_DB_INDEX}${REDIS_USER_AUTH}&auth[]=${REDIS_HOST_PASSWORD}"'; \
+ echo 'session.save_path = "tcp://${REDIS_HOST}:${REDIS_PORT}?database=${REDIS_DB_INDEX}${REDIS_USER_AUTH}&auth[]=${REDIS_HOST_PASSWORD}"'; \
echo 'redis.session.locking_enabled = 1'; \
echo 'redis.session.lock_retries = -1'; \
echo 'redis.session.lock_wait_time = 10000'; \
@@ -152,7 +157,7 @@ RUN set -ex; \
; \
\
curl -fsSL -o nextcloud.tar.bz2 \
- "https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2"; \
+ "https://github.com/nextcloud-releases/server/releases/download/v${NEXTCLOUD_VERSION}/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2"; \
curl -fsSL -o nextcloud.tar.bz2.asc \
"https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2.asc"; \
export GNUPGHOME="$(mktemp -d)"; \
@@ -226,7 +231,6 @@ RUN set -ex; \
sudo \
grep \
nodejs \
- libreoffice \
bind-tools \
imagemagick \
imagemagick-svg \
@@ -242,20 +246,13 @@ RUN set -ex; \
sed -i 's/^pm.max_children =.*/pm.max_children = 5000/' /usr/local/etc/php-fpm.d/www.conf; \
sed -i 's|access.log = /proc/self/fd/2|access.log = /proc/self/fd/1|' /usr/local/etc/php-fpm.d/docker.conf; \
\
-# AIO cloning start # Do not remove or change this line!
- rm -rf /tmp/nextcloud-aio && \
- mkdir -p /tmp/nextcloud-aio && \
- cd /tmp/nextcloud-aio && \
- git clone https://github.com/nextcloud-releases/all-in-one.git --depth 1 .; \
- mkdir -p /usr/src/nextcloud/apps/nextcloud-aio; \
- cp -r ./app/* /usr/src/nextcloud/apps/nextcloud-aio/; \
- echo "[ -n \"\$TERM\" ] && cat /root.motd" >> /root/.bashrc; \
-# AIO cloning end # Do not remove or change this line!
+ echo "[ -n \"\$TERM\" ] && [ -f /root.motd ] && cat /root.motd" >> /root/.bashrc; \
\
chown www-data:root -R /usr/src && \
chmod 777 -R /usr/local/etc/php/conf.d && \
chmod 777 -R /usr/local/etc/php-fpm.d && \
chmod -R 777 /tmp; \
+ chmod -R 777 /etc/openldap; \
\
mkdir -p /nc-updater; \
chmod -R 777 /nc-updater
@@ -267,4 +264,5 @@ CMD ["/usr/bin/supervisord", "-c", "/supervisord.conf"]
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/nextcloud/README.md b/Containers/nextcloud/README.md
new file mode 100644
index 00000000..574afd03
--- /dev/null
+++ b/Containers/nextcloud/README.md
@@ -0,0 +1,35 @@
+# Nextcloud All-in-One ``nextcloud`` Container
+
+This folder contains the OCI/Docker container definition, along with associated resources and configuration files, for building the `nextcloud` container as part of the [Nextcloud All-in-One](https://github.com/nextcloud/all-in-one) project. This container hosts PHP and the Nextcloud Server application.
+
+## Overview
+
+The Nextcloud container provides the core Nextcloud application environment, including the necessary dependencies and configuration for seamless integration into the All-in-One stack. The container hosts:
+
+- The PHP SAPI/backend (php-fpm)
+- Nextcloud background jobs and scheduled tasks, which are handled via cron
+- Miscellaneous minor support services specific to AIO's Nextcloud deployment (health and exec)
+
+## Contents
+
+- **Dockerfile**: Instructions for building the Nextcloud container image.
+- **Entrypoint script**: The `start.sh` script is used for container initialization and runtime configuration before starting supervisord.
+- **Nextcloud configuration files**: Specific to running in a containerized setting and/or within AIO.
+- **Supervisor**: The `supervisord.conf` file defines the long-running services hosted within the container (php-fpm, cron, etc.).
+
+## Usage
+
+This container is intended to be used as part of the All-in-One deployment and is not meant to be used on its own. Among other requirements, it needs a web server container (which AIO provides in a dedicated Apache container). It is designed to be orchestrated by the [All-in-One mastercontainer](https://github.com/nextcloud/all-in-one/tree/main/Containers/mastercontainer) or used within an [AIO Manual Installation](https://github.com/nextcloud/all-in-one/tree/main/manual-install) or [AIO Helm chart](https://github.com/nextcloud/all-in-one/tree/main/nextcloud-aio-helm-chart).
+
+## Documentation
+
+- [Nextcloud All-in-One Documentation](https://github.com/nextcloud/all-in-one#readme)
+- [Nextcloud Documentation](https://docs.nextcloud.com/)
+
+## Contributing
+
+Contributions are welcome! Please follow the Nextcloud project's guidelines and submit pull requests or issues via the main repository.
+
+## License
+
+This folder and its contents are licensed under the [GNU AGPLv3](https://www.gnu.org/licenses/agpl-3.0.html), in line with the rest of Nextcloud All-in-One.
diff --git a/Containers/nextcloud/config/apps.config.php b/Containers/nextcloud/config/apps.config.php
index c890e787..99bf5e40 100644
--- a/Containers/nextcloud/config/apps.config.php
+++ b/Containers/nextcloud/config/apps.config.php
@@ -16,3 +16,6 @@ $CONFIG = array (
if (getenv('APPS_ALLOWLIST')) {
$CONFIG['appsallowlist'] = explode(" ", getenv('APPS_ALLOWLIST'));
}
+if (getenv('NEXTCLOUD_APP_STORE_URL')) {
+ $CONFIG['appstoreurl'] = getenv('NEXTCLOUD_APP_STORE_URL');
+}
diff --git a/Containers/nextcloud/config/certificates-bundle.config.php b/Containers/nextcloud/config/certificates-bundle.config.php
new file mode 100644
index 00000000..cc05b06a
--- /dev/null
+++ b/Containers/nextcloud/config/certificates-bundle.config.php
@@ -0,0 +1,5 @@
+ array(
+ 'mode' => 'verify-ca',
+ 'rootcert' => '/var/www/html/data/certificates/ca-bundle.crt',
+ ),
+ );
+}
+if (getenv('NEXTCLOUD_TRUSTED_CERTIFICATES_MYSQL')) {
+ $CONFIG = array(
+ 'dbdriveroptions' => array(
+ PDO::MYSQL_ATTR_SSL_CA => '/var/www/html/data/certificates/ca-bundle.crt',
+ ),
+ );
+}
+
diff --git a/Containers/nextcloud/config/redis.config.php b/Containers/nextcloud/config/redis.config.php
index 80848974..b59fe4ea 100644
--- a/Containers/nextcloud/config/redis.config.php
+++ b/Containers/nextcloud/config/redis.config.php
@@ -9,10 +9,8 @@ if (getenv('REDIS_HOST')) {
),
);
- if (getenv('REDIS_HOST_PORT')) {
- $CONFIG['redis']['port'] = (int) getenv('REDIS_HOST_PORT');
- } elseif (getenv('REDIS_HOST')[0] != '/') {
- $CONFIG['redis']['port'] = 6379;
+ if (getenv('REDIS_PORT')) {
+ $CONFIG['redis']['port'] = (int) getenv('REDIS_PORT');
}
if (getenv('REDIS_DB_INDEX')) {
diff --git a/Containers/nextcloud/config/s3.config.php b/Containers/nextcloud/config/s3.config.php
index cd08f7fc..6ea06697 100644
--- a/Containers/nextcloud/config/s3.config.php
+++ b/Containers/nextcloud/config/s3.config.php
@@ -4,10 +4,13 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) {
$use_path = getenv('OBJECTSTORE_S3_USEPATH_STYLE');
$use_legacyauth = getenv('OBJECTSTORE_S3_LEGACYAUTH');
$autocreate = getenv('OBJECTSTORE_S3_AUTOCREATE');
+ $multibucket = getenv('OBJECTSTORE_S3_MULTIBUCKET');
$CONFIG = array(
'objectstore' => array(
'class' => '\OC\Files\ObjectStore\S3',
'arguments' => array(
+ 'multibucket' => $multibucket === 'true',
+ 'num_buckets' => (int)getenv('OBJECTSTORE_S3_NUM_BUCKETS') ?: 64,
'bucket' => getenv('OBJECTSTORE_S3_BUCKET'),
'key' => getenv('OBJECTSTORE_S3_KEY') ?: '',
'secret' => getenv('OBJECTSTORE_S3_SECRET') ?: '',
@@ -16,12 +19,13 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) {
'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,
+ 'autocreate' => strtolower($autocreate) !== 'false',
+ 'use_ssl' => strtolower($use_ssl) !== 'false',
// required for some non Amazon S3 implementations
- 'use_path_style' => $use_path == true && strtolower($use_path) !== 'false',
+ 'use_path_style' => strtolower($use_path) === 'true',
// required for older protocol versions
- 'legacy_auth' => $use_legacyauth == true && strtolower($use_legacyauth) !== 'false'
+ 'legacy_auth' => strtolower($use_legacyauth) === 'true',
+ 'use_nextcloud_bundle' => 1,
)
)
);
diff --git a/Containers/nextcloud/config/smtp.config.php b/Containers/nextcloud/config/smtp.config.php
index 40cfdf94..b57f9b68 100644
--- a/Containers/nextcloud/config/smtp.config.php
+++ b/Containers/nextcloud/config/smtp.config.php
@@ -18,3 +18,14 @@ if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN'))
$CONFIG['mail_smtppassword'] = '';
}
}
+
+if (getenv('NEXTCLOUD_TRUSTED_CERTIFICATES_MAILER')) {
+ $CONFIG = array(
+ 'mail_smtpstreamoptions' => array(
+ 'ssl' => array(
+ 'verify_peer_name' => false,
+ 'cafile' => '/var/www/html/data/certificates/ca-bundle.crt',
+ )
+ )
+ );
+}
diff --git a/Containers/nextcloud/entrypoint.sh b/Containers/nextcloud/entrypoint.sh
index 4b6df98f..5f47a0f4 100644
--- a/Containers/nextcloud/entrypoint.sh
+++ b/Containers/nextcloud/entrypoint.sh
@@ -20,36 +20,97 @@ run_upgrade_if_needed_due_to_app_update() {
fi
}
+# Create cert bundle
+if env | grep -q NEXTCLOUD_TRUSTED_CERTIFICATES_; then
+
+ # Enable debug mode
+ set -x
+
+ # Default vars
+ CERTIFICATES_ROOT_DIR="/var/www/html/data/certificates"
+ CERTIFICATE_BUNDLE="/var/www/html/data/certificates/ca-bundle.crt"
+
+ # Remove old root certs and recreate them with current ones
+ rm -rf "$CERTIFICATES_ROOT_DIR"
+ mkdir -p "$CERTIFICATES_ROOT_DIR"
+
+ # Retrieve default root cert bundle
+ if ! [ -f "$SOURCE_LOCATION/resources/config/ca-bundle.crt" ]; then
+ echo "Root ca-bundle not found. Only concattening configured NEXTCLOUD_TRUSTED_CERTIFICATES files!"
+ # Recreate cert file
+ touch "$CERTIFICATE_BUNDLE"
+ else
+ # Write default bundle to the target ca file
+ cat "$SOURCE_LOCATION/resources/config/ca-bundle.crt" > "$CERTIFICATE_BUNDLE"
+ fi
+
+ # Iterate through certs
+ TRUSTED_CERTIFICATES="$(env | grep NEXTCLOUD_TRUSTED_CERTIFICATES_ | grep -oP '^[A-Z_a-z0-9]+')"
+ mapfile -t TRUSTED_CERTIFICATES <<< "$TRUSTED_CERTIFICATES"
+ for certificate in "${TRUSTED_CERTIFICATES[@]}"; do
+
+ # Create new line
+ echo "" >> "$CERTIFICATE_BUNDLE"
+
+ # Check if variable is an actual cert
+ if echo "${!certificate}" | grep -q "BEGIN CERTIFICATE" && echo "${!certificate}" | grep -q "END CERTIFICATE"; then
+ # Write out cert to bundle
+ echo "${!certificate}" >> "$CERTIFICATE_BUNDLE"
+ fi
+
+ # Create file in cert dir for extra logic in other places
+ if ! [ -f "$CERTIFICATES_ROOT_DIR/$CERTIFICATE_NAME" ]; then
+ touch "$CERTIFICATES_ROOT_DIR/$CERTIFICATE_NAME"
+ fi
+
+ done
+
+ # Backwards compatibility with older instances
+ if [ -f "/var/www/html/config/postgres.config.php" ]; then
+ sed -i "s|/var/www/html/data/certificates/POSTGRES|/var/www/html/data/certificates/ca-bundle.crt|" /var/www/html/config/postgres.config.php
+ sed -i "s|/var/www/html/data/certificates/MYSQL|/var/www/html/data/certificates/ca-bundle.crt|" /var/www/html/config/postgres.config.php
+ fi
+
+ # Print out bundle one last time
+ cat "$CERTIFICATE_BUNDLE"
+
+ # Disable debug mode
+ set +x
+fi
+
# Adjust DATABASE_TYPE to by Nextcloud supported value
if [ "$DATABASE_TYPE" = postgres ]; then
export DATABASE_TYPE=pgsql
fi
-# Only start container if redis is accessible
+# Only start container if Redis is accessible
# shellcheck disable=SC2153
-while ! nc -z "$REDIS_HOST" "6379"; do
- echo "Waiting for redis to start..."
+while ! nc -z "$REDIS_HOST" "$REDIS_PORT"; do
+ echo "Waiting for Redis to start..."
sleep 5
done
# Check permissions in ncdata
-touch "$NEXTCLOUD_DATA_DIR/this-is-a-test-file"
-if ! [ -f "$NEXTCLOUD_DATA_DIR/this-is-a-test-file" ]; then
- echo "The www-data user doesn't seem to have access rights in the datadir.
-Most likely are the files located on a drive that does not follow linux permissions.
-Please adjust the permissions like mentioned below.
-The found permissions are:
-$(stat -c "%u:%g %a" "$NEXTCLOUD_DATA_DIR")
-(userID:groupID permissions)
-but they should be:
-33:0 750
-(userID:groupID permissions)
-Also make sure that the parent directories on the host of the directory that you've chosen as datadir are publicly readable with e.g. 'sudo chmod +r /mnt' (adjust the command accordingly to your case) and the same for all subdirectories.
-Additionally, if you want to use a Fuse-mount as datadir, set 'allow_other' as additional mount option.
-For SMB/CIFS mounts as datadir, see https://github.com/nextcloud/all-in-one#can-i-use-a-cifssmb-share-as-nextclouds-datadir"
+test_file="$NEXTCLOUD_DATA_DIR/this-is-a-test-file"
+touch "$test_file"
+if ! [ -f "$test_file" ]; then
+ echo "The www-data user does not appear to have access rights to the data directory."
+ echo "It is possible that the files are on a filesystem that does not support standard Linux permissions,"
+ echo "or the permissions simply need to be adjusted. Please change the permissions as described below."
+ echo "Current permissions are:"
+ stat -c "%u:%g %a" "$NEXTCLOUD_DATA_DIR"
+ echo "(userID:groupID permissions)"
+ echo "They should be:"
+ echo "33:0 750"
+ echo "(userID:groupID permissions)"
+ echo "Also, ensure that all parent directories on the host of your chosen data directory are publicly readable."
+ echo "For example: sudo chmod +r /mnt (adjust this command as needed)."
+ echo "If you want to use a FUSE mount as the data directory, add 'allow_other' as an additional mount option."
+ echo "For SMB/CIFS mounts as the data directory, see:"
+ echo " https://github.com/nextcloud/all-in-one#can-i-use-a-cifssmb-share-as-nextclouds-datadir"
exit 1
fi
-rm "$NEXTCLOUD_DATA_DIR/this-is-a-test-file"
+rm -f "$test_file"
if [ -f /var/www/html/version.php ]; then
# shellcheck disable=SC2016
@@ -71,26 +132,31 @@ fi
# Don't start the container if Nextcloud is not compatible with the PHP version
if [ -f "/var/www/html/lib/versioncheck.php" ] && ! php /var/www/html/lib/versioncheck.php; then
- echo "It seems like your installed Nextcloud is not compatible with the by the container provided PHP version."
- echo "This most likely happened because you tried to restore an old Nextcloud version from backup that is not compatible with the PHP version that comes with the container."
- echo "Please try to restore a more recent backup which contains a Nextcloud version that is compatible with the PHP version that comes with the container."
- echo "If you do not have a more recent backup, feel free to have a look at this documentation: https://github.com/nextcloud/all-in-one/blob/main/manual-upgrade.md"
+ echo "Your installed Nextcloud version is not compatible with the PHP version provided by this image."
+ echo "This typically occurs when you restore an older Nextcloud backup that does not support the"
+ echo "PHP version included in this image."
+ echo "Please restore a more recent backup that includes a compatible Nextcloud version."
+ echo "If you do not have a more recent backup, refer to the manual upgrade documentation:"
+ echo " https://github.com/nextcloud/all-in-one/blob/main/manual-upgrade.md"
exit 1
fi
# Do not start the container if the last update failed
if [ -f "$NEXTCLOUD_DATA_DIR/update.failed" ]; then
echo "The last Nextcloud update failed."
- echo "Please restore from backup and try again!"
- echo "If you do not have a backup in place, you can simply delete the update.failed file in the datadir which will allow the container to start again."
+ echo "Please restore from a backup and try again."
+ echo "If you do not have a backup, you can delete the update.failed file in the data directory"
+ echo "to allow the container to start again."
exit 1
fi
# Do not start the container if the install failed
if [ -f "$NEXTCLOUD_DATA_DIR/install.failed" ]; then
echo "The initial Nextcloud installation failed."
- echo "Please reset AIO properly and try again. For further clues what went wrong, check the logs above."
- echo "See https://github.com/nextcloud/all-in-one#how-to-properly-reset-the-instance"
+ echo "For more information about what went wrong, check the logs above."
+ echo "Please reset AIO properly and try again."
+ echo "See:"
+ echo " https://github.com/nextcloud/all-in-one#how-to-properly-reset-the-instance"
exit 1
fi
@@ -143,7 +209,7 @@ if ! [ -f "$NEXTCLOUD_DATA_DIR/skip.update" ]; then
if [ "$installed_version" != "0.0.0.0" ]; then
# Check connection to appstore start # Do not remove or change this line!
while true; do
- echo -e "Checking connection to appstore"
+ echo -e "Checking connection to the app store..."
APPSTORE_URL="https://apps.nextcloud.com/api/v1"
if grep -q appstoreurl /var/www/html/config/config.php; then
set -x
@@ -154,10 +220,10 @@ if ! [ -f "$NEXTCLOUD_DATA_DIR/skip.update" ]; then
CURL_STATUS="$(curl -LI "$APPSTORE_URL"/apps.json -o /dev/null -w '%{http_code}\n' -s)"
if [[ "$CURL_STATUS" = "200" ]]
then
- echo "Appstore is reachable"
+ echo "App store is reachable."
break
else
- echo "Curl didn't produce a 200 status, is appstore reachable?"
+ echo "Curl did not return a 200 status. Is the app store reachable?"
sleep 5
fi
done
@@ -167,21 +233,21 @@ if ! [ -f "$NEXTCLOUD_DATA_DIR/skip.update" ]; then
php /var/www/html/occ maintenance:mode --off
- echo "Getting and backing up the status of apps for later, this might take a while..."
+ echo "Getting and backing up the status of apps for later; this might take a while..."
NC_APPS="$(find /var/www/html/custom_apps/ -type d -maxdepth 1 -mindepth 1 | sed 's|/var/www/html/custom_apps/||g')"
if [ -z "$NC_APPS" ]; then
- echo "No apps detected, aborting export of app status..."
+ echo "No apps detected. Aborting export of app status..."
APPSTORAGE="no-export-done"
else
mapfile -t NC_APPS_ARRAY <<< "$NC_APPS"
declare -Ag APPSTORAGE
- echo "Disabling apps before the update in order to make the update procedure more safe. This can take a while..."
+ echo "Disabling apps before the update to make the update procedure safer. This can take a while..."
for app in "${NC_APPS_ARRAY[@]}"; do
if APPSTORAGE[$app]="$(php /var/www/html/occ config:app:get "$app" enabled)"; then
php /var/www/html/occ app:disable "$app"
else
APPSTORAGE[$app]=""
- echo "Not disabling $app because the occ command to get the enabled state was failing."
+ echo "Not disabling $app because the occ command to get its enabled state failed."
fi
done
fi
@@ -195,19 +261,61 @@ if ! [ -f "$NEXTCLOUD_DATA_DIR/skip.update" ]; then
run_upgrade_if_needed_due_to_app_update
fi
- echo "Initializing nextcloud $image_version ..."
- rsync -rlD --delete --exclude-from=/upgrade.exclude "$SOURCE_LOCATION/" /var/www/html/
+ echo "Initializing Nextcloud $image_version ..."
+ # Copy over initial data from Nextcloud archive
+ rsync -rlD --delete \
+ --exclude-from=/upgrade.exclude \
+ "$SOURCE_LOCATION/" \
+ /var/www/html/
+
+ # Copy custom_apps from Nextcloud archive
+ if ! directory_empty "$SOURCE_LOCATION/custom_apps"; then
+ set -x
+ for app in "$SOURCE_LOCATION/custom_apps"/*; do
+ app_id="$(basename "$app")"
+ mkdir -p "/var/www/html/custom_apps/$app_id"
+ rsync -rlD --delete \
+ --include "/$app_id/" \
+ --exclude '/*' \
+ "$SOURCE_LOCATION/custom_apps/" \
+ /var/www/html/custom_apps/
+ done
+ set +x
+ fi
+
+ # Copy these from Nextcloud archive if they don't exist yet (i.e. new install)
for dir in config data custom_apps themes; do
if [ ! -d "/var/www/html/$dir" ] || directory_empty "/var/www/html/$dir"; then
- rsync -rlD --include "/$dir/" --exclude '/*' "$SOURCE_LOCATION/" /var/www/html/
+ rsync -rlD \
+ --include "/$dir/" \
+ --exclude '/*' \
+ "$SOURCE_LOCATION/" \
+ /var/www/html/
fi
done
- rsync -rlD --delete --include '/config/' --exclude '/*' --exclude '/config/CAN_INSTALL' --exclude '/config/config.sample.php' --exclude '/config/config.php' "$SOURCE_LOCATION/" /var/www/html/
- rsync -rlD --include '/version.php' --exclude '/*' "$SOURCE_LOCATION/" /var/www/html/
+
+ rsync -rlD --delete \
+ --include '/config/' \
+ --exclude '/*' \
+ --exclude '/config/CAN_INSTALL' \
+ --exclude '/config/config.sample.php' \
+ --exclude '/config/config.php' \
+ "$SOURCE_LOCATION/" \
+ /var/www/html/
+
+ rsync -rlD \
+ --include '/version.php' \
+ --exclude '/*' \
+ "$SOURCE_LOCATION/" \
+ /var/www/html/
+
echo "Initializing finished"
- #install
+ ################
+ # Fresh Install
+ ################
+
if [ "$installed_version" = "0.0.0.0" ]; then
echo "New Nextcloud instance."
@@ -221,21 +329,31 @@ if ! [ -f "$NEXTCLOUD_DATA_DIR/skip.update" ]; then
INSTALL_OPTIONS+=(--data-dir "$NEXTCLOUD_DATA_DIR")
fi
- # We do our own permission check so the permission check is not needed
- cat << DATADIR_PERMISSION_CONF > /var/www/html/config/datadir.permission.config.php
+ # Skip the default permission check (we do our own)
+ cat > /var/www/html/config/datadir.permission.config.php <<'EOF'
false
-);
-DATADIR_PERMISSION_CONF
+ $CONFIG = array (
+ 'check_data_directory_permissions' => false
+ );
+EOF
echo "Installing with $DATABASE_TYPE database"
# Set a default value for POSTGRES_PORT
if [ -z "$POSTGRES_PORT" ]; then
- POSTGRES_PORT=5432
+ POSTGRES_PORT=5432
fi
- INSTALL_OPTIONS+=(--database "$DATABASE_TYPE" --database-name "$POSTGRES_DB" --database-user "$POSTGRES_USER" --database-pass "$POSTGRES_PASSWORD" --database-host "$POSTGRES_HOST" --database-port "$POSTGRES_PORT")
+ # Add database options to INSTALL_OPTIONS
+ # shellcheck disable=SC2153
+ INSTALL_OPTIONS+=(
+ --database "$DATABASE_TYPE"
+ --database-name "$POSTGRES_DB"
+ --database-user "$POSTGRES_USER"
+ --database-pass "$POSTGRES_PASSWORD"
+ --database-host "$POSTGRES_HOST"
+ --database-port "$POSTGRES_PORT"
+ )
+
echo "Starting Nextcloud installation..."
if ! php /var/www/html/occ maintenance:install "${INSTALL_OPTIONS[@]}"; then
echo "Installation of Nextcloud failed!"
@@ -257,7 +375,7 @@ DATADIR_PERMISSION_CONF
if [ "$try" -ge "$max_retries" ]; then
echo "Installation of Nextcloud failed!"
- echo "Install errors: $(cat /var/www/html/data/nextcloud.log)"
+ echo "Installation errors: $(cat /var/www/html/data/nextcloud.log)"
touch "$NEXTCLOUD_DATA_DIR/install.failed"
exit 1
fi
@@ -293,10 +411,12 @@ DATADIR_PERMISSION_CONF
installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
INSTALLED_MAJOR="${installed_version%%.*}"
IMAGE_MAJOR="${image_version%%.*}"
+ # If a valid upgrade path, trigger the Nextcloud built-in Updater
if ! [ "$INSTALLED_MAJOR" -gt "$IMAGE_MAJOR" ]; then
php /var/www/html/updater/updater.phar --no-interaction --no-backup
if ! php /var/www/html/occ -V || php /var/www/html/occ status | grep maintenance | grep -q 'true'; then
echo "Installation of Nextcloud failed!"
+ # TODO: Add a hint here about what to do / where to look / updater.log?
touch "$NEXTCLOUD_DATA_DIR/install.failed"
exit 1
fi
@@ -355,7 +475,7 @@ DATADIR_PERMISSION_CONF
read -ra STARTUP_APPS_ARRAY <<< "$STARTUP_APPS"
for app in "${STARTUP_APPS_ARRAY[@]}"; do
if ! echo "$app" | grep -q '^-'; then
- if [ -z "$(find /var/www/html/apps -type d -maxdepth 1 -mindepth 1 -name "$app" )" ]; then
+ if [ -z "$(find /var/www/html/apps /var/www/html/custom_apps -type d -maxdepth 1 -mindepth 1 -name "$app" )" ]; then
# If not shipped, install and enable the app
php /var/www/html/occ app:install "$app"
else
@@ -373,11 +493,11 @@ DATADIR_PERMISSION_CONF
#upgrade
else
touch "$NEXTCLOUD_DATA_DIR/update.failed"
- echo "Upgrading nextcloud from $installed_version to $image_version..."
+ echo "Upgrading Nextcloud from $installed_version to $image_version..."
php /var/www/html/occ config:system:delete integrity.check.disabled
if ! php /var/www/html/occ upgrade || ! php /var/www/html/occ -V; then
echo "Upgrade failed. Please restore from backup."
- bash /notify.sh "Nextcloud update to $image_version failed!" "Please restore from backup!"
+ bash /notify.sh "Nextcloud update to $image_version failed!" "Please restore from backup."
exit 1
fi
@@ -385,7 +505,7 @@ DATADIR_PERMISSION_CONF
installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
rm "$NEXTCLOUD_DATA_DIR/update.failed"
- bash /notify.sh "Nextcloud update to $image_version successful!" "Feel free to inspect the Nextcloud container logs for more info."
+ bash /notify.sh "Nextcloud update to $image_version successful!" "You may inspect the Nextcloud container logs for more information."
php /var/www/html/occ app:update --all
@@ -393,7 +513,7 @@ DATADIR_PERMISSION_CONF
# Restore app status
if [ "${APPSTORAGE[0]}" != "no-export-done" ]; then
- echo "Restoring the status of apps. This can take a while..."
+ echo "Restoring app statuses. This may take a while..."
for app in "${!APPSTORAGE[@]}"; do
if [ -n "${APPSTORAGE[$app]}" ]; then
if [ "${APPSTORAGE[$app]}" != "no" ]; then
@@ -405,13 +525,13 @@ DATADIR_PERMISSION_CONF
php /var/www/html/occ maintenance:mode --off
fi
run_upgrade_if_needed_due_to_app_update
- echo "The $app app could not get enabled. Probably because it is not compatible with the new Nextcloud version."
+ echo "The $app app could not be re-enabled, probably because it is not compatible with the new Nextcloud version."
if [ "$app" = apporder ]; then
CUSTOM_HINT="The apporder app was deprecated. A possible replacement is the side_menu app, aka 'Custom menu'."
else
- CUSTOM_HINT="Most likely because it is not compatible with the new Nextcloud version."
+ CUSTOM_HINT="Most likely, it is not compatible with the new Nextcloud version."
fi
- bash /notify.sh "Could not enable the $app app after the Nextcloud update!" "$CUSTOM_HINT Feel free to look at the Nextcloud update logs and force-enable the app again from the app-store UI."
+ bash /notify.sh "Could not re-enable the $app app after the Nextcloud update!" "$CUSTOM_HINT Feel free to review the Nextcloud update logs and force-enable the app again if you wish."
continue
fi
# Only restore the group settings, if the app was enabled (and is thus compatible with the new NC version)
@@ -433,7 +553,7 @@ DATADIR_PERMISSION_CONF
php /var/www/html/occ config:app:set updatenotification notify_groups --value="[]"
# Apply optimization
- echo "Doing some optimizations..."
+ echo "Performing some optimizations..."
if [ "$NEXTCLOUD_SKIP_DATABASE_OPTIMIZATION" != yes ]; then
php /var/www/html/occ maintenance:repair --include-expensive
php /var/www/html/occ db:add-missing-indices
@@ -464,10 +584,10 @@ if [ -z "$OBJECTSTORE_S3_BUCKET" ] && [ -z "$OBJECTSTORE_SWIFT_URL" ]; then
# Check if appdata is present
# If not, something broke (e.g. changing ncdatadir after aio was first started)
if [ -z "$(find "$NEXTCLOUD_DATA_DIR/" -maxdepth 1 -mindepth 1 -type d -name "appdata_*")" ]; then
- echo "Appdata is not present. Did you maybe change the datadir after the initial Nextcloud installation? This is not supported!"
+ echo "Appdata is not present. Did you change the datadir after the initial Nextcloud installation? This is not supported!"
echo "See https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir"
- echo "If you adjusted the datadir to be located on an external drive, make sure that the drive is still mounted!"
- echo "In the datadir was found:"
+ echo "If you moved the datadir to an external drive, make sure that the drive is still mounted."
+ echo "The following was found in the datadir:"
ls -la "$NEXTCLOUD_DATA_DIR/"
exit 1
fi
@@ -641,7 +761,7 @@ if [ "$COLLABORA_ENABLED" = 'yes' ]; then
fi
fi
else
- echo "Warning: No ipv4-address found for $COLLABORA_HOST."
+ echo "Warning: No IPv4 address found for $COLLABORA_HOST."
fi
if [ -n "$COLLABORA_IPv6_ADDRESS" ]; then
if ! echo "$COLLABORA_ALLOW_LIST" | grep -q "$COLLABORA_IPv6_ADDRESS"; then
@@ -652,10 +772,10 @@ if [ "$COLLABORA_ENABLED" = 'yes' ]; then
fi
fi
else
- echo "No ipv6-address found for $COLLABORA_HOST."
+ echo "No IPv6 address found for $COLLABORA_HOST."
fi
if [ -n "$COLLABORA_ALLOW_LIST" ]; then
- PRIVATE_IP_RANGES='127.0.0.1/8,192.168.0.0/16,172.16.0.0/12,10.0.0.0/8,fd00::/8,::1'
+ PRIVATE_IP_RANGES='127.0.0.0/8,192.168.0.0/16,172.16.0.0/12,10.0.0.0/8,100.64.0.0/10,fd00::/8,::1/128'
if ! echo "$COLLABORA_ALLOW_LIST" | grep -q "$PRIVATE_IP_RANGES"; then
COLLABORA_ALLOW_LIST+=",$PRIVATE_IP_RANGES"
fi
@@ -666,7 +786,7 @@ if [ "$COLLABORA_ENABLED" = 'yes' ]; then
fi
php /var/www/html/occ config:app:set richdocuments wopi_allowlist --value="$COLLABORA_ALLOW_LIST"
else
- echo "Warning: wopi_allowlist is empty which should not be the case!"
+ echo "Warning: wopi_allowlist is empty; this should not be the case!"
fi
else
if [ "$REMOVE_DISABLED_APPS" = yes ] && [ -d "/var/www/html/custom_apps/richdocuments" ]; then
@@ -676,32 +796,52 @@ fi
# OnlyOffice
if [ "$ONLYOFFICE_ENABLED" = 'yes' ]; then
+ # Determine OnlyOffice port based on host pattern
if echo "$ONLYOFFICE_HOST" | grep -q "nextcloud-.*-onlyoffice"; then
ONLYOFFICE_PORT=80
else
ONLYOFFICE_PORT=443
fi
- while ! nc -z "$ONLYOFFICE_HOST" "$ONLYOFFICE_PORT"; do
- echo "waiting for OnlyOffice to become available..."
+
+ count=0
+ while ! nc -z "$ONLYOFFICE_HOST" "$ONLYOFFICE_PORT" && [ "$count" -lt 90 ]; do
+ echo "Waiting for OnlyOffice to become available..."
+ count=$((count+5))
sleep 5
done
- if ! [ -d "/var/www/html/custom_apps/onlyoffice" ]; then
- php /var/www/html/occ app:install onlyoffice
- elif [ "$(php /var/www/html/occ config:app:get onlyoffice enabled)" != "yes" ]; then
- php /var/www/html/occ app:enable onlyoffice
- elif [ "$SKIP_UPDATE" != 1 ]; then
- php /var/www/html/occ app:update onlyoffice
+ if [ "$count" -ge 90 ]; then
+ bash /notify.sh "Onlyoffice did not start in time!" "Skipping initialization and disabling onlyoffice app."
+ php /var/www/html/occ app:disable onlyoffice
+ else
+ # Install or enable OnlyOffice app as needed
+ if ! [ -d "/var/www/html/custom_apps/onlyoffice" ]; then
+ php /var/www/html/occ app:install onlyoffice
+ elif [ "$(php /var/www/html/occ config:app:get onlyoffice enabled)" != "yes" ]; then
+ php /var/www/html/occ app:enable onlyoffice
+ elif [ "$SKIP_UPDATE" != 1 ]; then
+ php /var/www/html/occ app:update onlyoffice
+ fi
+
+ # Set OnlyOffice configuration
+ php /var/www/html/occ config:system:set onlyoffice editors_check_interval --value="0" --type=integer
+ php /var/www/html/occ config:system:set onlyoffice jwt_secret --value="$ONLYOFFICE_SECRET"
+ php /var/www/html/occ config:app:set onlyoffice jwt_secret --value="$ONLYOFFICE_SECRET"
+ php /var/www/html/occ config:system:set onlyoffice jwt_header --value="AuthorizationJwt"
+
+ # Adjust the OnlyOffice host if using internal pattern
+ if echo "$ONLYOFFICE_HOST" | grep -q "nextcloud-.*-onlyoffice"; then
+ ONLYOFFICE_HOST="$NC_DOMAIN/onlyoffice"
+ export ONLYOFFICE_HOST
+ fi
+
+ php /var/www/html/occ config:app:set onlyoffice DocumentServerUrl --value="https://$ONLYOFFICE_HOST"
fi
- php /var/www/html/occ config:system:set onlyoffice jwt_secret --value="$ONLYOFFICE_SECRET"
- php /var/www/html/occ config:app:set onlyoffice jwt_secret --value="$ONLYOFFICE_SECRET"
- php /var/www/html/occ config:system:set onlyoffice jwt_header --value="AuthorizationJwt"
- if echo "$ONLYOFFICE_HOST" | grep -q "nextcloud-.*-onlyoffice"; then
- ONLYOFFICE_HOST="$NC_DOMAIN/onlyoffice"
- export ONLYOFFICE_HOST
- fi
- php /var/www/html/occ config:app:set onlyoffice DocumentServerUrl --value="https://$ONLYOFFICE_HOST"
else
- if [ "$REMOVE_DISABLED_APPS" = yes ] && [ -d "/var/www/html/custom_apps/onlyoffice" ] && [ -n "$ONLYOFFICE_SECRET" ] && [ "$(php /var/www/html/occ config:system:get onlyoffice jwt_secret)" = "$ONLYOFFICE_SECRET" ]; then
+ # Remove OnlyOffice app if disabled and removal is requested
+ if [ "$REMOVE_DISABLED_APPS" = yes ] && \
+ [ -d "/var/www/html/custom_apps/onlyoffice" ] && \
+ [ -n "$ONLYOFFICE_SECRET" ] && \
+ [ "$(php /var/www/html/occ config:system:get onlyoffice jwt_secret)" = "$ONLYOFFICE_SECRET" ]; then
php /var/www/html/occ app:remove onlyoffice
fi
fi
@@ -747,14 +887,16 @@ fi
if [ -d "/var/www/html/custom_apps/spreed" ]; then
if [ "$TALK_RECORDING_ENABLED" = 'yes' ]; then
while ! nc -z "$TALK_RECORDING_HOST" 1234; do
- echo "waiting for Talk Recording to become available..."
+ echo "Waiting for Talk Recording to become available..."
sleep 5
done
# TODO: migrate to occ command if that becomes available
RECORDING_SERVERS_STRING="{\"servers\":[{\"server\":\"http://$TALK_RECORDING_HOST:1234/\",\"verify\":true}],\"secret\":\"$RECORDING_SECRET\"}"
php /var/www/html/occ config:app:set spreed recording_servers --value="$RECORDING_SERVERS_STRING"
else
- php /var/www/html/occ config:app:delete spreed recording_servers
+ if [ "$REMOVE_DISABLED_APPS" = yes ]; then
+ php /var/www/html/occ config:app:delete spreed recording_servers
+ fi
fi
fi
@@ -762,12 +904,12 @@ fi
if [ "$CLAMAV_ENABLED" = 'yes' ]; then
count=0
while ! nc -z "$CLAMAV_HOST" 3310 && [ "$count" -lt 90 ]; do
- echo "waiting for clamav to become available..."
+ echo "Waiting for ClamAV to become available..."
count=$((count+5))
sleep 5
done
if [ "$count" -ge 90 ]; then
- echo "Clamav did not start in time. Skipping initialization and disabling files_antivirus app."
+ bash /notify.sh "ClamAV did not start in time!" "Skipping initialization and disabling files_antivirus app."
php /var/www/html/occ app:disable files_antivirus
else
if ! [ -d "/var/www/html/custom_apps/files_antivirus" ]; then
@@ -780,9 +922,13 @@ if [ "$CLAMAV_ENABLED" = 'yes' ]; then
php /var/www/html/occ config:app:set files_antivirus av_mode --value="daemon"
php /var/www/html/occ config:app:set files_antivirus av_port --value="3310"
php /var/www/html/occ config:app:set files_antivirus av_host --value="$CLAMAV_HOST"
- php /var/www/html/occ config:app:set files_antivirus av_stream_max_length --value="$CLAMAV_MAX_SIZE"
- php /var/www/html/occ config:app:set files_antivirus av_max_file_size --value="$CLAMAV_MAX_SIZE"
+ # av_stream_max_length must be synced with StreamMaxLength inside clamav
+ php /var/www/html/occ config:app:set files_antivirus av_stream_max_length --value="2147483648"
+ php /var/www/html/occ config:app:set files_antivirus av_max_file_size --value="-1"
php /var/www/html/occ config:app:set files_antivirus av_infected_action --value="only_log"
+ if [ -n "$CLAMAV_BLOCKLISTED_DIRECTORIES" ]; then
+ php /var/www/html/occ config:app:set files_antivirus av_blocklisted_directories --value="$CLAMAV_BLOCKLISTED_DIRECTORIES"
+ fi
fi
else
if [ "$REMOVE_DISABLED_APPS" = yes ] && [ -d "/var/www/html/custom_apps/files_antivirus" ]; then
@@ -809,45 +955,57 @@ fi
# Fulltextsearch
if [ "$FULLTEXTSEARCH_ENABLED" = 'yes' ]; then
- while ! nc -z "$FULLTEXTSEARCH_HOST" 9200; do
- echo "waiting for Fulltextsearch to become available..."
+ count=0
+ while ! nc -z "$FULLTEXTSEARCH_HOST" "$FULLTEXTSEARCH_PORT" && [ "$count" -lt 90 ]; do
+ echo "Waiting for Fulltextsearch to become available..."
+ count=$((count+5))
sleep 5
done
- if ! [ -d "/var/www/html/custom_apps/fulltextsearch" ]; then
- php /var/www/html/occ app:install fulltextsearch
- elif [ "$(php /var/www/html/occ config:app:get fulltextsearch enabled)" != "yes" ]; then
- php /var/www/html/occ app:enable fulltextsearch
- elif [ "$SKIP_UPDATE" != 1 ]; then
- php /var/www/html/occ app:update fulltextsearch
- fi
- if ! [ -d "/var/www/html/custom_apps/fulltextsearch_elasticsearch" ]; then
- php /var/www/html/occ app:install fulltextsearch_elasticsearch
- elif [ "$(php /var/www/html/occ config:app:get fulltextsearch_elasticsearch enabled)" != "yes" ]; then
- php /var/www/html/occ app:enable fulltextsearch_elasticsearch
- elif [ "$SKIP_UPDATE" != 1 ]; then
- php /var/www/html/occ app:update fulltextsearch_elasticsearch
- fi
- if ! [ -d "/var/www/html/custom_apps/files_fulltextsearch" ]; then
- php /var/www/html/occ app:install files_fulltextsearch
- elif [ "$(php /var/www/html/occ config:app:get files_fulltextsearch enabled)" != "yes" ]; then
- php /var/www/html/occ app:enable files_fulltextsearch
- elif [ "$SKIP_UPDATE" != 1 ]; then
- php /var/www/html/occ app:update files_fulltextsearch
- fi
- php /var/www/html/occ fulltextsearch:configure '{"search_platform":"OCA\\FullTextSearch_Elasticsearch\\Platform\\ElasticSearchPlatform"}'
- php /var/www/html/occ fulltextsearch_elasticsearch:configure "{\"elastic_host\":\"http://elastic:$FULLTEXTSEARCH_PASSWORD@$FULLTEXTSEARCH_HOST:9200\",\"elastic_index\":\"nextcloud-aio\"}"
- php /var/www/html/occ files_fulltextsearch:configure "{\"files_pdf\":\"1\",\"files_office\":\"1\"}"
+ if [ "$count" -ge 90 ]; then
+ echo "Fulltextsearch did not start in time. Skipping initialization and disabling fulltextsearch apps."
+ php /var/www/html/occ app:disable fulltextsearch
+ php /var/www/html/occ app:disable fulltextsearch_elasticsearch
+ php /var/www/html/occ app:disable files_fulltextsearch
+ else
+ if [ -z "$FULLTEXTSEARCH_PROTOCOL" ]; then
+ FULLTEXTSEARCH_PROTOCOL="http"
+ fi
+ if ! [ -d "/var/www/html/custom_apps/fulltextsearch" ]; then
+ php /var/www/html/occ app:install fulltextsearch
+ elif [ "$(php /var/www/html/occ config:app:get fulltextsearch enabled)" != "yes" ]; then
+ php /var/www/html/occ app:enable fulltextsearch
+ elif [ "$SKIP_UPDATE" != 1 ]; then
+ php /var/www/html/occ app:update fulltextsearch
+ fi
+ if ! [ -d "/var/www/html/custom_apps/fulltextsearch_elasticsearch" ]; then
+ php /var/www/html/occ app:install fulltextsearch_elasticsearch
+ elif [ "$(php /var/www/html/occ config:app:get fulltextsearch_elasticsearch enabled)" != "yes" ]; then
+ php /var/www/html/occ app:enable fulltextsearch_elasticsearch
+ elif [ "$SKIP_UPDATE" != 1 ]; then
+ php /var/www/html/occ app:update fulltextsearch_elasticsearch
+ fi
+ if ! [ -d "/var/www/html/custom_apps/files_fulltextsearch" ]; then
+ php /var/www/html/occ app:install files_fulltextsearch
+ elif [ "$(php /var/www/html/occ config:app:get files_fulltextsearch enabled)" != "yes" ]; then
+ php /var/www/html/occ app:enable files_fulltextsearch
+ elif [ "$SKIP_UPDATE" != 1 ]; then
+ php /var/www/html/occ app:update files_fulltextsearch
+ fi
+ php /var/www/html/occ fulltextsearch:configure '{"search_platform":"OCA\\FullTextSearch_Elasticsearch\\Platform\\ElasticSearchPlatform"}'
+ php /var/www/html/occ fulltextsearch_elasticsearch:configure "{\"elastic_host\":\"$FULLTEXTSEARCH_PROTOCOL://$FULLTEXTSEARCH_USER:$FULLTEXTSEARCH_PASSWORD@$FULLTEXTSEARCH_HOST:$FULLTEXTSEARCH_PORT\",\"elastic_index\":\"$FULLTEXTSEARCH_INDEX\"}"
+ php /var/www/html/occ files_fulltextsearch:configure "{\"files_pdf\":true,\"files_office\":true}"
- # Do the index
- if ! [ -f "$NEXTCLOUD_DATA_DIR/fts-index.done" ]; then
- echo "Waiting 10s before activating FTS..."
- sleep 10
- echo "Activating fulltextsearch..."
- if php /var/www/html/occ fulltextsearch:test && php /var/www/html/occ fulltextsearch:index "{\"errors\": \"reset\"}" --no-readline; then
- touch "$NEXTCLOUD_DATA_DIR/fts-index.done"
- else
- echo "Fulltextsearch failed. Could not index."
- echo "Feel free to follow https://github.com/nextcloud/all-in-one/discussions/1709 if you want to skip the indexing in the future."
+ # Do the index
+ if ! [ -f "$NEXTCLOUD_DATA_DIR/fts-index.done" ]; then
+ echo "Waiting 10 seconds before activating fulltextsearch..."
+ sleep 10
+ echo "Activating fulltextsearch..."
+ if php /var/www/html/occ fulltextsearch:test && php /var/www/html/occ fulltextsearch:index "{\"errors\": \"reset\"}" --no-readline; then
+ touch "$NEXTCLOUD_DATA_DIR/fts-index.done"
+ else
+ echo "Fulltextsearch failed. Could not index."
+ echo "If you want to skip indexing in the future, see https://github.com/nextcloud/all-in-one/discussions/1709"
+ fi
fi
fi
else
diff --git a/Containers/nextcloud/run-exec-commands.sh b/Containers/nextcloud/run-exec-commands.sh
index 9ef6ba69..e8066881 100644
--- a/Containers/nextcloud/run-exec-commands.sh
+++ b/Containers/nextcloud/run-exec-commands.sh
@@ -19,11 +19,6 @@ else
echo "Activating Collabora config..."
php /var/www/html/occ richdocuments:activate-config
fi
- # OnlyOffice must work also if using manual-install
- if [ "$ONLYOFFICE_ENABLED" = yes ]; then
- echo "Activating OnlyOffice config..."
- php /var/www/html/occ onlyoffice:documentserver --check
- fi
fi
signal_handler() {
diff --git a/Containers/nextcloud/start.sh b/Containers/nextcloud/start.sh
index 37aa4d98..a5f38534 100644
--- a/Containers/nextcloud/start.sh
+++ b/Containers/nextcloud/start.sh
@@ -8,7 +8,7 @@ fi
# Only start container if database is accessible
# POSTGRES_HOST must be set in the containers env vars and POSTGRES_PORT has a default above
# shellcheck disable=SC2153
-while ! sudo -u www-data nc -z "$POSTGRES_HOST" "$POSTGRES_PORT"; do
+while ! sudo -E -u www-data nc -z "$POSTGRES_HOST" "$POSTGRES_PORT"; do
echo "Waiting for database to start..."
sleep 5
done
@@ -25,7 +25,7 @@ fi
# Fix false database connection on old instances
if [ -f "/var/www/html/config/config.php" ]; then
sleep 2
- while ! sudo -u www-data psql -d "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB" -c "select now()"; do
+ while ! sudo -E -u www-data psql -d "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB" -c "select now()"; do
echo "Waiting for the database to start..."
sleep 5
done
@@ -56,12 +56,12 @@ fi
set +x
# Check datadir permissions
-sudo -u www-data touch "$NEXTCLOUD_DATA_DIR/this-is-a-test-file" &>/dev/null
+sudo -E -u www-data touch "$NEXTCLOUD_DATA_DIR/this-is-a-test-file" &>/dev/null
if ! [ -f "$NEXTCLOUD_DATA_DIR/this-is-a-test-file" ]; then
chown -R www-data:root "$NEXTCLOUD_DATA_DIR"
chmod 750 -R "$NEXTCLOUD_DATA_DIR"
fi
-sudo -u www-data rm -f "$NEXTCLOUD_DATA_DIR/this-is-a-test-file"
+sudo -E -u www-data rm -f "$NEXTCLOUD_DATA_DIR/this-is-a-test-file"
# Install additional dependencies
if [ -n "$ADDITIONAL_APKS" ]; then
@@ -86,13 +86,15 @@ fi
# Install additional php extensions
if [ -n "$ADDITIONAL_PHP_EXTENSIONS" ]; then
if ! [ -f "/additional-php-extensions-are-installed" ]; then
+ # Allow to disable imagick without having to enable it each time
+ if ! echo "$ADDITIONAL_PHP_EXTENSIONS" | grep -q imagick; then
+ # Remove the ini file as there is no docker-php-ext-disable script available
+ rm /usr/local/etc/php/conf.d/docker-php-ext-imagick.ini
+ fi
read -ra ADDITIONAL_PHP_EXTENSIONS_ARRAY <<< "$ADDITIONAL_PHP_EXTENSIONS"
for app in "${ADDITIONAL_PHP_EXTENSIONS_ARRAY[@]}"; do
if [ "$app" = imagick ]; then
- echo "Enabling Imagick..."
- if ! docker-php-ext-enable imagick >/dev/null; then
- echo "Could not install PHP extension imagick!"
- fi
+ # imagick is already enabled by default, so does not need to be enabled anymore.
continue
fi
# shellcheck disable=SC2086
diff --git a/Containers/notify-push/Dockerfile b/Containers/notify-push/Dockerfile
index 18cbc0c4..425115c4 100644
--- a/Containers/notify-push/Dockerfile
+++ b/Containers/notify-push/Dockerfile
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
-FROM alpine:3.21.3
+FROM alpine:3.23.2
COPY --chmod=775 start.sh /start.sh
COPY --chmod=775 healthcheck.sh /healthcheck.sh
@@ -11,6 +11,7 @@ RUN set -ex; \
netcat-openbsd \
tzdata \
bash \
+ jq \
openssl; \
# Give root a random password
echo "root:$(openssl rand -base64 12)" | chpasswd; \
@@ -22,4 +23,5 @@ ENTRYPOINT ["/start.sh"]
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/notify-push/start.sh b/Containers/notify-push/start.sh
index e1bbf974..26d74333 100644
--- a/Containers/notify-push/start.sh
+++ b/Containers/notify-push/start.sh
@@ -52,6 +52,10 @@ fi
if [ -z "$REDIS_DB_INDEX" ]; then
REDIS_DB_INDEX=0
fi
+# Set a default value for REDIS_PORT
+if [ -z "$REDIS_PORT" ]; then
+ REDIS_PORT=6379
+fi
# Set a default for db type
if [ -z "$DATABASE_TYPE" ]; then
DATABASE_TYPE=postgres
@@ -66,9 +70,21 @@ if [ "$POSTGRES_USER" = nextcloud ]; then
export POSTGRES_USER
fi
+# URL-encode passwords
+POSTGRES_PASSWORD="$(jq -rn --arg v "$POSTGRES_PASSWORD" '$v|@uri')"
+REDIS_HOST_PASSWORD="$(jq -rn --arg v "$REDIS_HOST_PASSWORD" '$v|@uri')"
+
+# Postgres root cert
+if [ -f "/nextcloud/data/certificates/POSTGRES" ]; then
+ CERT_OPTIONS="?sslmode=verify-ca&sslrootcert=/nextcloud/data/certificates/ca-bundle.crt"
+# Mysql root cert
+elif [ -f "/nextcloud/data/certificates/MYSQL" ]; then
+ CERT_OPTIONS="?sslmode=verify-ca&ssl-ca=/nextcloud/data/certificates/ca-bundle.crt"
+fi
+
# Set sensitive values as env
-export DATABASE_URL="$DATABASE_TYPE://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB"
-export REDIS_URL="redis://$REDIS_USER:$REDIS_HOST_PASSWORD@$REDIS_HOST/$REDIS_DB_INDEX"
+export DATABASE_URL="$DATABASE_TYPE://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB$CERT_OPTIONS"
+export REDIS_URL="redis://$REDIS_USER:$REDIS_HOST_PASSWORD@$REDIS_HOST:$REDIS_PORT/$REDIS_DB_INDEX"
# Run it
/nextcloud/custom_apps/notify_push/bin/"$CPU_ARCH"/notify_push \
diff --git a/Containers/onlyoffice/Dockerfile b/Containers/onlyoffice/Dockerfile
index 97587907..13b4d456 100644
--- a/Containers/onlyoffice/Dockerfile
+++ b/Containers/onlyoffice/Dockerfile
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest
# From https://github.com/ONLYOFFICE/Docker-DocumentServer/blob/master/Dockerfile
-FROM onlyoffice/documentserver:8.3.3.1
+FROM onlyoffice/documentserver:9.2.1.1
# USER root is probably used
@@ -8,4 +8,5 @@ COPY --chmod=775 healthcheck.sh /healthcheck.sh
HEALTHCHECK --start-period=60s --retries=9 CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/postgresql/Dockerfile b/Containers/postgresql/Dockerfile
index 36394b05..56090f26 100644
--- a/Containers/postgresql/Dockerfile
+++ b/Containers/postgresql/Dockerfile
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest
-# From https://github.com/docker-library/postgres/blob/master/17/alpine3.21/Dockerfile
-FROM postgres:17.5-alpine
+# From https://github.com/docker-library/postgres/blob/master/17/alpine3.23/Dockerfile
+FROM postgres:17.7-alpine
COPY --chmod=775 start.sh /start.sh
COPY --chmod=775 healthcheck.sh /healthcheck.sh
@@ -44,4 +44,5 @@ ENTRYPOINT ["/start.sh"]
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/postgresql/start.sh b/Containers/postgresql/start.sh
index dbb74196..551bb10e 100644
--- a/Containers/postgresql/start.sh
+++ b/Containers/postgresql/start.sh
@@ -128,7 +128,9 @@ EOSQL
fi
# Shut down the database to be able to start it again
- pg_ctl stop -m fast
+ # The smart mode disallows new connections, then waits for all existing clients to disconnect and any online backup to finish
+ # Wait for 1800s to make sure that a checkpoint is completed successfully
+ pg_ctl stop -m smart -t 1800
# Change database port back to default
export PGPORT=5432
diff --git a/Containers/redis/Dockerfile b/Containers/redis/Dockerfile
index 92f2b17c..cc9181ad 100644
--- a/Containers/redis/Dockerfile
+++ b/Containers/redis/Dockerfile
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest
-# From https://github.com/docker-library/redis/blob/master/7.2/alpine/Dockerfile
-FROM redis:7.2.9-alpine
+# From https://github.com/redis/docker-library-redis/blob/release/8.2/alpine/Dockerfile
+FROM redis:8.2.3-alpine
COPY --chmod=775 start.sh /start.sh
@@ -21,4 +21,5 @@ ENTRYPOINT ["/start.sh"]
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/talk-recording/Dockerfile b/Containers/talk-recording/Dockerfile
index 634a5de3..8df5b89e 100644
--- a/Containers/talk-recording/Dockerfile
+++ b/Containers/talk-recording/Dockerfile
@@ -1,10 +1,10 @@
# syntax=docker/dockerfile:latest
-FROM python:3.13.5-alpine3.21
+FROM python:3.14.2-alpine3.23
COPY --chmod=775 start.sh /start.sh
COPY --chmod=775 healthcheck.sh /healthcheck.sh
-ENV RECORDING_VERSION=v0.1
+ENV RECORDING_VERSION=v0.2.1
ENV ALLOW_ALL=false
ENV HPB_PROTOCOL=https
ENV NC_PROTOCOL=https
@@ -58,4 +58,5 @@ CMD ["python", "-m", "nextcloud.talk.recording", "--config", "/conf/recording.co
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/talk-recording/recording.conf b/Containers/talk-recording/recording.conf
index 99515528..cc8bd495 100644
--- a/Containers/talk-recording/recording.conf
+++ b/Containers/talk-recording/recording.conf
@@ -1,3 +1,5 @@
+# SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: AGPL-3.0-or-later
[logs]
# Log level based on numeric values of Python logging levels:
# - Critical: 50
@@ -12,6 +14,11 @@
# IP and port to listen on for HTTP requests.
#listen = 127.0.0.1:8000
+[app]
+# Comma separated list of trusted proxies (IPs or CIDR networks) that may set
+# the "X-Forwarded-For" header.
+#trustedproxies =
+
[backend]
# Allow any hostname as backend endpoint. This is extremely insecure and should
# only be used during development.
@@ -100,6 +107,18 @@
# ffmpeg. The options given here fully override the default global options.
#common = ffmpeg -loglevel level+warning -n
+# The (additional) options given to ffmpeg for the audio input. The options
+# given here extend the default options for the audio input, although they do
+# not override them.
+# Default options: '-f pulse -i {AUDIO_SOURCE}'
+#inputaudio =
+
+# The (additional) options given to ffmpeg for the video input. The options
+# given here extend the default options for the video input, although they do
+# not override them.
+# Default options: '-f x11grab -draw_mouse 0 -video_size {WIDTH}x{HEIGHT} -i {VIDEO_SOURCE}'
+#inputvideo =
+
# The options given to ffmpeg to encode the audio output. The options given here
# fully override the default options for the audio output.
#outputaudio = -c:a libopus
@@ -120,4 +139,31 @@
# will use Google Chrome, or Chromium if Google Chrome is not installed.
# Allowed values: firefox, chrome
# Defaults to firefox
-# browser = firefox
+#browser = firefox
+
+# Path to the Selenium driver to use for recordings.
+# If set the driver must match the browser being used (for example,
+# "/usr/bin/geckodriver" for "firefox"). If no driver is explicitly set Selenium
+# Manager will try to find the right one in $PATH, downloading it as a fallback.
+# Note that Selenium Manager does not work in some architectures (for example,
+# Linux on arm64/aarch64), so in those architectures the driver must be
+# explicitly set.
+#driverPath =
+
+# Path to the browser executable to use for recordings.
+# If set the executable must match the browser being used (for example,
+# "/usr/bin/firefox-esr" for "firefox"). If no executable is explicitly set
+# Selenium Manager will try to find the right one in $PATH. Depending on the
+# installed Selenium version if the executable is not found Selenium Manager may
+# also download the browser as a fallback.
+# Note that Selenium Manager does not work in some architectures (for example,
+# Linux on arm64/aarch64); in those architectures the Selenium driver will try
+# to find the executable, but the executable may need to be explicitly set if
+# not found by the driver.
+#browserPath =
+
+[stats]
+# Comma-separated list of IP addresses (or CIDR networks) that are allowed to
+# access the stats endpoint.
+# Leave commented to only allow access from "127.0.0.1".
+#allowed_ips =
diff --git a/Containers/talk-recording/start.sh b/Containers/talk-recording/start.sh
index a03eed04..b49e5e9c 100644
--- a/Containers/talk-recording/start.sh
+++ b/Containers/talk-recording/start.sh
@@ -59,6 +59,8 @@ extensionvideo = .webm
[recording]
browser = firefox
+driverPath = /usr/bin/geckodriver
+browserPath = /usr/bin/firefox
RECORDING_CONF
exec "$@"
diff --git a/Containers/talk/Dockerfile b/Containers/talk/Dockerfile
index 67bb7e61..fb78f943 100644
--- a/Containers/talk/Dockerfile
+++ b/Containers/talk/Dockerfile
@@ -1,10 +1,10 @@
# syntax=docker/dockerfile:latest
-FROM nats:2.11.6-scratch AS nats
-FROM eturnal/eturnal:1.12.1 AS eturnal
-FROM strukturag/nextcloud-spreed-signaling:2.0.3 AS signaling
-FROM alpine:3.21.3 AS janus
+FROM nats:2.12.3-scratch AS nats
+FROM eturnal/eturnal:1.12.2-alpine AS eturnal
+FROM strukturag/nextcloud-spreed-signaling:2.0.4 AS signaling
+FROM alpine:3.23.2 AS janus
-ARG JANUS_VERSION=v1.3.1
+ARG JANUS_VERSION=v1.3.3
WORKDIR /src
RUN set -ex; \
apk upgrade --no-cache -a; \
@@ -35,7 +35,7 @@ RUN set -ex; \
make configs; \
rename -v ".jcfg.sample" ".jcfg" /usr/local/etc/janus/*.jcfg.sample
-FROM alpine:3.21.3
+FROM alpine:3.23.2
ENV ETURNAL_ETC_DIR="/conf"
ENV SKIP_CERT_VERIFY=false
COPY --from=janus --chmod=777 --chown=1000:1000 /usr/local /usr/local
@@ -107,4 +107,5 @@ CMD ["supervisord", "-c", "/supervisord.conf"]
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/talk/server.conf.in b/Containers/talk/server.conf.in
index 85630d5a..8f437e30 100644
--- a/Containers/talk/server.conf.in
+++ b/Containers/talk/server.conf.in
@@ -84,7 +84,8 @@ internalsecret = the-shared-secret-for-internal-clients
# For backend type "etcd":
# Key prefix of backend entries. All keys below will be watched and assumed to
# contain a JSON document with the following entries:
-# - "url": Url of the Nextcloud instance.
+# - "urls": List of urls of the Nextcloud instance.
+# - "url": Url of the Nextcloud instance (deprecated).
# - "secret": Shared secret for requests from and to the backend servers.
#
# Additional optional entries:
@@ -93,8 +94,8 @@ internalsecret = the-shared-secret-for-internal-clients
# - "sessionlimit": Number of sessions that are allowed to connect.
#
# Example:
-# "/signaling/backend/one" -> {"url": "https://nextcloud.domain1.invalid", ...}
-# "/signaling/backend/two" -> {"url": "https://domain2.invalid/nextcloud", ...}
+# "/signaling/backend/one" -> {"urls": ["https://nextcloud.domain1.invalid"], ...}
+# "/signaling/backend/two" -> {"urls": ["https://domain2.invalid/nextcloud"], ...}
#backendprefix = /signaling/backend
# Allow any hostname as backend endpoint. This is extremely insecure and should
@@ -122,8 +123,8 @@ connectionsperhost = 8
# Backend configurations as defined in the "[backend]" section above. The
# section names must match the ids used in "backends" above.
#[backend-id]
-# URL of the Nextcloud instance
-#url = https://cloud.domain.invalid
+# Comma-separated list of urls of the Nextcloud instance
+#urls = https://cloud.domain.invalid
# Shared secret for requests from and to the backend servers. Leave empty to use
# the common shared secret from above.
@@ -143,8 +144,8 @@ connectionsperhost = 8
#maxscreenbitrate = 2097152
#[another-backend]
-# URL of the Nextcloud instance
-#url = https://cloud.otherdomain.invalid
+# Comma-separated list of urls of the Nextcloud instance
+#urls = https://cloud.otherdomain.invalid
# Shared secret for requests from and to the backend servers. Leave empty to use
# the common shared secret from above.
@@ -179,6 +180,13 @@ connectionsperhost = 8
# proxy server that is used.
#maxscreenbitrate = 2097152
+# List of IP addresses / subnets that are allowed to be used by clients in
+# candidates. The allowed list has preference over the blocked list below.
+#allowedcandidates = 10.0.0.0/8
+
+# List of IP addresses / subnets to filter from candidates received by clients.
+#blockedcandidates = 1.2.3.0/24
+
# For type "proxy": timeout in seconds for requests to the proxy server.
#proxytimeout = 2
diff --git a/Containers/talk/start.sh b/Containers/talk/start.sh
index b07f5bc9..f89949f3 100644
--- a/Containers/talk/start.sh
+++ b/Containers/talk/start.sh
@@ -98,7 +98,7 @@ connectionsperhost = 8
skipverify = ${SKIP_CERT_VERIFY}
[backend-1]
-url = https://${NC_DOMAIN}
+urls = https://${NC_DOMAIN}
secret = ${SIGNALING_SECRET}
maxstreambitrate = ${TALK_MAX_STREAM_BITRATE}
maxscreenbitrate = ${TALK_MAX_SCREEN_BITRATE}
diff --git a/Containers/watchtower/Dockerfile b/Containers/watchtower/Dockerfile
index 76cfd60f..83bccc07 100644
--- a/Containers/watchtower/Dockerfile
+++ b/Containers/watchtower/Dockerfile
@@ -1,13 +1,21 @@
# syntax=docker/dockerfile:latest
-FROM ghcr.io/nicholas-fedor/watchtower:1.11.5 AS watchtower
+FROM golang:1.25.6-alpine3.23 AS go
-FROM alpine:3.21.3
+ENV WATCHTOWER_COMMIT_HASH=f522ce27e1fbe4618da54833025a95be62aa838a
+
+RUN set -ex; \
+ apk upgrade --no-cache -a; \
+ apk add --no-cache \
+ build-base; \
+ go install github.com/nicholas-fedor/watchtower@$WATCHTOWER_COMMIT_HASH # v1.14.0
+
+FROM alpine:3.23.2
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache bash ca-certificates tzdata
-COPY --from=watchtower /watchtower /watchtower
+COPY --from=go /go/bin/watchtower /watchtower
COPY --chmod=775 start.sh /start.sh
@@ -16,4 +24,5 @@ USER root
ENTRYPOINT ["/start.sh"]
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/watchtower/start.sh b/Containers/watchtower/start.sh
index bec4d3a2..cf16e7a4 100644
--- a/Containers/watchtower/start.sh
+++ b/Containers/watchtower/start.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# Check if socket is available and readable
-if ! [ -a "/var/run/docker.sock" ]; then
+if ! [ -e "/var/run/docker.sock" ]; then
echo "Docker socket is not available. Cannot continue."
exit 1
elif ! test -r /var/run/docker.sock; then
diff --git a/Containers/whiteboard/Dockerfile b/Containers/whiteboard/Dockerfile
index bbf0cc6e..3a3c5542 100644
--- a/Containers/whiteboard/Dockerfile
+++ b/Containers/whiteboard/Dockerfile
@@ -1,12 +1,16 @@
# syntax=docker/dockerfile:latest
# Probably from this file: https://github.com/nextcloud/whiteboard/blob/main/Dockerfile
-FROM ghcr.io/nextcloud-releases/whiteboard:v1.1.2
+FROM ghcr.io/nextcloud-releases/whiteboard:v1.5.3
USER root
RUN set -ex; \
- apk upgrade --no-cache -a; \
- apk add --no-cache bash; \
- chmod 777 -R /tmp
+ apk add --no-cache bash jq; \
+ chmod 777 -R /tmp; \
+ if [ -f /usr/lib/chromium/chrome_crashpad_handler ] && [ ! -f /usr/lib/chromium/chrome_crashpad_handler.real ]; then \
+ mv /usr/lib/chromium/chrome_crashpad_handler /usr/lib/chromium/chrome_crashpad_handler.real; \
+ printf '%s\n' '#!/bin/sh' "exec /usr/lib/chromium/chrome_crashpad_handler.real --no-periodic-tasks --database=\"\${CRASHPAD_DATABASE:-/tmp/chrome-crashpad}\" \"\$@\"" >/usr/lib/chromium/chrome_crashpad_handler; \
+ chmod +x /usr/lib/chromium/chrome_crashpad_handler; \
+ fi
USER 65534
COPY --chmod=775 start.sh /start.sh
@@ -19,4 +23,5 @@ WORKDIR /tmp
ENTRYPOINT ["/start.sh"]
LABEL com.centurylinklabs.watchtower.enable="false" \
+ wud.watch="false" \
org.label-schema.vendor="Nextcloud"
diff --git a/Containers/whiteboard/healthcheck.sh b/Containers/whiteboard/healthcheck.sh
index 4f53988a..5909db82 100644
--- a/Containers/whiteboard/healthcheck.sh
+++ b/Containers/whiteboard/healthcheck.sh
@@ -1,4 +1,4 @@
#!/bin/bash
-nc -z "$REDIS_HOST" 6379 || exit 0
+nc -z "$REDIS_HOST" "$REDIS_PORT" || exit 0
nc -z 127.0.0.1 3002 || exit 1
diff --git a/Containers/whiteboard/start.sh b/Containers/whiteboard/start.sh
index 962df9b9..e0babd7f 100644
--- a/Containers/whiteboard/start.sh
+++ b/Containers/whiteboard/start.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# Only start container if nextcloud is accessible
-while ! nc -z "$REDIS_HOST" 6379; do
+while ! nc -z "$REDIS_HOST" "$REDIS_PORT"; do
echo "Waiting for redis to start..."
sleep 5
done
@@ -11,7 +11,10 @@ if [ -z "$REDIS_DB_INDEX" ]; then
REDIS_DB_INDEX=0
fi
-export REDIS_URL="redis://$REDIS_USER:$REDIS_HOST_PASSWORD@$REDIS_HOST/$REDIS_DB_INDEX"
+# URL-encode password
+REDIS_HOST_PASSWORD="$(jq -rn --arg v "$REDIS_HOST_PASSWORD" '$v|@uri')"
+
+export REDIS_URL="redis://$REDIS_USER:$REDIS_HOST_PASSWORD@$REDIS_HOST:$REDIS_PORT/$REDIS_DB_INDEX"
# Run it
exec npm --prefix /app run server:start
diff --git a/app/appinfo/info.xml b/app/appinfo/info.xml
index 8b911c10..832d3ccd 100644
--- a/app/appinfo/info.xml
+++ b/app/appinfo/info.xml
@@ -13,7 +13,7 @@
monitoring
https://github.com/nextcloud/all-in-one/issues
-
+
diff --git a/community-containers/borgbackup-viewer/readme.md b/community-containers/borgbackup-viewer/readme.md
index dc3d5806..ddd11be7 100644
--- a/community-containers/borgbackup-viewer/readme.md
+++ b/community-containers/borgbackup-viewer/readme.md
@@ -5,7 +5,7 @@ This container allows to view the local borg repository in a web session. It als
- After adding and starting the container, you need to visit `https://ip.address.of.this.server:5801` in order to log in with the user `nextcloud` and the password that you can see next to the container in the AIO interface. (The web page uses a self-signed certificate, so you need to accept the warning).
- Then, you should see a terminal. There type in `borg mount /mnt/borgbackup/borg /tmp/borg` to mount the backup archive at `/tmp/borg` inside the container. Afterwards type in `nautilus /tmp/borg` which will show a file explorer and allows you to see all the files. You can then copy files and folders back to their initial mountpoints inside `/nextcloud_aio_volumes/`, `/host_mounts/` and `/docker_volumes/`. ⚠️ Be very carefully while doing that as can break your instance!
- After you are done with the operation, click on the terminal in the background and press `[CTRL]+[c]` multiple times to close any open application. Then run `umount /tmp/borg` to unmount the mountpoint correctly.
-- You can also delete specific archives by running `borg list`, delete a specific archive e.g. via `borg delete --stats --progress "::20220223_174237-nextcloud-aio"` and compact the archives via `borg compact`. After doing so, make sure to update the backup archives list in the AIO interface! You can do so by clicking on the `Check backup integrity` button or `Create backup` button.
+- You can also delete specific archives by running `borg list`, delete a specific archive e.g. via `borg delete --stats --progress "::20220223_174237-nextcloud-aio"` and compact the archives via `borg compact`. After doing so, make sure to update the backup archives list in the AIO interface! You can do so by clicking on the `Update backup list` button in the `Update backup list` section inside the `Backup and restore` section.
- ⚠️ After you are done doing your operations, remove the container for better security again from the stack: https://github.com/nextcloud/all-in-one/tree/main/community-containers#how-to-remove-containers-from-aios-stack
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
diff --git a/community-containers/caddy/caddy.json b/community-containers/caddy/caddy.json
index d5f72cb8..e27df683 100644
--- a/community-containers/caddy/caddy.json
+++ b/community-containers/caddy/caddy.json
@@ -5,7 +5,7 @@
"display_name": "Caddy with geoblocking",
"documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/caddy",
"image": "ghcr.io/szaimen/aio-caddy",
- "image_tag": "v2",
+ "image_tag": "v4",
"internal_port": "443",
"restart": "unless-stopped",
"ports": [
@@ -13,17 +13,14 @@
"ip_binding": "",
"port_number": "443",
"protocol": "tcp"
- },
- {
- "ip_binding": "",
- "port_number": "443",
- "protocol": "udp"
}
],
"environment": [
"TZ=%TIMEZONE%",
"NC_DOMAIN=%NC_DOMAIN%",
- "APACHE_PORT=%APACHE_PORT%"
+ "APACHE_PORT=%APACHE_PORT%",
+ "APACHE_IP_BINDING=%APACHE_IP_BINDING%",
+ "NEXTCLOUD_EXPORTER_CADDY_PASSWORD=%NEXTCLOUD_EXPORTER_CADDY_PASSWORD%"
],
"volumes": [
{
@@ -37,9 +34,14 @@
"writeable": false
}
],
+ "secrets": [
+ "NEXTCLOUD_EXPORTER_CADDY_PASSWORD"
+ ],
"aio_variables": [
"apache_ip_binding=@INTERNAL",
- "apache_port=11000"
+ "apache_port=11000",
+ "turn_domain=%NC_DOMAIN%",
+ "talk_port=443"
],
"nextcloud_exec_commands": [
"mkdir '/mnt/ncdata/admin/files/nextcloud-aio-caddy'",
diff --git a/community-containers/caddy/readme.md b/community-containers/caddy/readme.md
index edb157b6..f552c3f0 100644
--- a/community-containers/caddy/readme.md
+++ b/community-containers/caddy/readme.md
@@ -1,19 +1,24 @@
## Caddy with geoblocking
-This container bundles caddy and auto-configures it for you. It also covers [vaultwarden](https://github.com/nextcloud/all-in-one/tree/main/community-containers/vaultwarden) by listening on `bw.$NC_DOMAIN`, if installed. It also covers [stalwart](https://github.com/nextcloud/all-in-one/tree/main/community-containers/stalwart) by listening on `mail.$NC_DOMAIN`, if installed. It also covers [jellyfin](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyfin) by listening on `media.$NC_DOMAIN`, if installed. It also covers [lldap](https://github.com/nextcloud/all-in-one/tree/main/community-containers/lldap) by listening on `ldap.$NC_DOMAIN`, if installed. It also covers [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb) by listening on `tables.$NC_DOMAIN`, if installed. It also covers [jellyseerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr) by listening on `requests.$NC_DOMAIN`, if installed.
+This container bundles caddy and auto-configures it for you. It also covers [vaultwarden](https://github.com/nextcloud/all-in-one/tree/main/community-containers/vaultwarden) by listening on `bw.$NC_DOMAIN`, if installed. It also covers [stalwart](https://github.com/nextcloud/all-in-one/tree/main/community-containers/stalwart) by listening on `mail.$NC_DOMAIN`, if installed. It also covers [jellyfin](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyfin) by listening on `media.$NC_DOMAIN`, if installed. It also covers [lldap](https://github.com/nextcloud/all-in-one/tree/main/community-containers/lldap) by listening on `ldap.$NC_DOMAIN`, if installed. It also covers [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb) by listening on `tables.$NC_DOMAIN`, if installed. It also covers [jellyseerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr) by listening on `requests.$NC_DOMAIN`, if installed. It also covers [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter) by listening on `metrics.$NC_DOMAIN`, if installed.
### Notes
- This container is incompatible with the [npmplus](https://github.com/nextcloud/all-in-one/tree/main/community-containers/npmplus) community container. So make sure that you do not enable both at the same time!
-- Make sure that no other service is using port 443 on your host as otherwise the containers will fail to start. You can check this with `sudo netstat -tulpn | grep 443` before installing AIO.
+- Make sure that no other service is using port 443/tcp on your host as otherwise the containers will fail to start. You can check this with `sudo netstat -tulpn | grep 443` before installing AIO.
+- Starting with AIO v12, the Talk port that was usually exposed on port 3478 is now set to port 443 udp and tcp and reachable via `your-nc-domain.com`. For the changes to become activated, you need to go to `https://your-nc-domain.com/settings/admin/talk` and delete all turn and stun servers. Then restart the containers and the new config should become active.
+- Starting with AIO v12, you can also limit vaultwarden, stalwart and lldap to certain ip-addresses. You can do so by creating a `allowed-IPs-vaultwarden.txt`, `allowed-IPs-stalwart.txt`, or `allowed-IPs-lldap.txt` file in the `nextcloud-aio-caddy` directory of your admin user and adding the ip-addresses in these files.
+- The container also supports the proxy protocol inside caddy. That means that you can run a supported web server in front of port 443/tcp and use the proxy protocol. You can enable this by configuring the `APACHE_IP_BINDING` environmental variable for the mastercontainer and set it to an ip-address from which the protocol shall be accepted. ⚠️ Note that the initial domain validation will not work correctly if you want to use the proxy protocol. So make sure to skip the domain validation in that case. See the [documentation](https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation).
- If you want to use this with [vaultwarden](https://github.com/nextcloud/all-in-one/tree/main/community-containers/vaultwarden), make sure that you point `bw.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for vaultwarden.
- If you want to use this with [stalwart](https://github.com/nextcloud/all-in-one/tree/main/community-containers/stalwart), make sure that you point `mail.your-nc-domain.com` to your server using an A, AAAA or CNAME record so that caddy can get a certificate automatically for stalwart.
- If you want to use this with [jellyfin](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyfin), make sure that you point `media.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for jellyfin.
- If you want to use this with [lldap](https://github.com/nextcloud/all-in-one/tree/main/community-containers/lldap), make sure that you point `ldap.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for lldap.
- If you want to use this with [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb), make sure that you point `tables.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for nocodb.
- If you want to use this with [jellyseerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr), make sure that you point `requests.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for jellyseerr.
+- If you want to use this with [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter), make sure that you point `metrics.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for nextcloud-exporter.
- If you want to use this with [local AI with vulkan support](https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai-vulkan), make sure that you point `ai.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for local AI.
- After the container was started the first time, you should see a new `nextcloud-aio-caddy` folder and inside there an `allowed-countries.txt` file when you open the files app with the default `admin` user. In there you can adjust the allowed country codes for caddy by adding them to the first line, e.g. `IT FR` would allow access from italy and france. Private ip-ranges are always allowed. Additionally, in order to activate this config, you need to get an account at https://dev.maxmind.com/geoip/geolite2-free-geolocation-data and download the `GeoLite2-Country.mmdb` and upload it with this exact name into the `nextcloud-aio-caddy` folder. Afterwards restart all containers from the AIO interface and your new config should be active!
- You can add your own Caddy configurations in `/data/caddy-imports/` inside the Caddy container (`sudo docker exec -it nextcloud-aio-caddy bash`). These will be imported on container startup. **Please note:** If you do not have CLI access to the server, you can now run docker commands via a web session by using this community container: https://github.com/nextcloud/all-in-one/tree/main/community-containers/container-management
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
+- If you want to remove the container again and revert back to the default, you need to disable the container via the AIO-interface and follow https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#8-removing-the-reverse-proxy
### Repository
https://github.com/szaimen/aio-caddy
diff --git a/community-containers/calcardbackup/readme.md b/community-containers/calcardbackup/readme.md
index 0bb04a3b..42a218b4 100644
--- a/community-containers/calcardbackup/readme.md
+++ b/community-containers/calcardbackup/readme.md
@@ -2,7 +2,7 @@
This container packages calcardbackup which is a tool that exports calendars and addressbooks from Nextcloud to .ics and .vcf files and saves them to a compressed file.
### Notes
-- Backups will be created at 00:00 CEST every day. Make sure that this does not conflict with the configured daily backups inside AIO.
+- Backups will be created at 00:00 UTC every day. Make sure that this does not conflict with the configured daily backups inside AIO.
- All the exports will be included in AIOs backup solution
- You can find the exports in the nextcloud_aio_calcardbackup volume
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
diff --git a/community-containers/facerecognition/facerecognition.json b/community-containers/facerecognition/facerecognition.json
index 4078bada..d97d5c08 100644
--- a/community-containers/facerecognition/facerecognition.json
+++ b/community-containers/facerecognition/facerecognition.json
@@ -10,18 +10,21 @@
"restart": "unless-stopped",
"environment": [
"TZ=%TIMEZONE%",
- "API_KEY=some-super-secret-api-key",
+ "API_KEY=%FACERECOGNITION_API_KEY%",
"FACE_MODEL=3"
],
"aio_variables": [
"nextcloud_memory_limit=2048M"
],
+ "secrets": [
+ "FACERECOGNITION_API_KEY"
+ ],
"enable_nvidia_gpu": false,
"nextcloud_exec_commands": [
"php /var/www/html/occ app:install facerecognition",
"php /var/www/html/occ app:enable facerecognition",
"php /var/www/html/occ config:system:set facerecognition.external_model_url --value nextcloud-aio-facerecognition:5000",
- "php /var/www/html/occ config:system:set facerecognition.external_model_api_key --value some-super-secret-api-key",
+ "php /var/www/html/occ config:system:set facerecognition.external_model_api_key --value %FACERECOGNITION_API_KEY%",
"php /var/www/html/occ face:setup -m 5",
"php /var/www/html/occ face:setup -M 1G",
"php /var/www/html/occ config:app:set facerecognition analysis_image_area --value 4320000",
diff --git a/community-containers/languagetool/languagetool.json b/community-containers/languagetool/languagetool.json
new file mode 100644
index 00000000..03eb6b39
--- /dev/null
+++ b/community-containers/languagetool/languagetool.json
@@ -0,0 +1,16 @@
+{
+ "aio_services_v1": [
+ {
+ "container_name": "nextcloud-aio-languagetool",
+ "display_name": "LanguageTool for Collabora",
+ "documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/languagetool",
+ "image": "erikvl87/languagetool",
+ "image_tag": "latest",
+ "internal_port": "8010",
+ "restart": "unless-stopped",
+ "environment": [
+ "TZ=%TIMEZONE%"
+ ]
+ }
+ ]
+}
diff --git a/community-containers/languagetool/readme.md b/community-containers/languagetool/readme.md
new file mode 100644
index 00000000..4c2ca98c
--- /dev/null
+++ b/community-containers/languagetool/readme.md
@@ -0,0 +1,13 @@
+## LanguageTool for Collabora
+This container bundles a LanguageTool for Collabora which adds spell checking functionality to Collabora.
+
+### Notes
+- Make sure to have collabora enabled via the AIO interface
+- After adding this container via the AIO Interface, while all containers are still stopped, you need to scroll down to the `Additional Collabora options` section and enter `--o:languagetool.enabled=true --o:languagetool.base_url=http://nextcloud-aio-languagetool:8010/v2`.
+- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
+
+### Repository
+https://github.com/Erikvl87/docker-languagetool
+
+### Maintainer
+https://github.com/szaimen
diff --git a/community-containers/lldap/lldap.json b/community-containers/lldap/lldap.json
index 8f7fba88..32f8e7ec 100644
--- a/community-containers/lldap/lldap.json
+++ b/community-containers/lldap/lldap.json
@@ -27,7 +27,7 @@
"LLDAP_JWT_SECRET",
"LLDAP_LDAP_USER_PASS"
],
- "ui_secret": "LLDAP_JWT_SECRET",
+ "ui_secret": "LLDAP_LDAP_USER_PASS",
"volumes": [
{
"source": "nextcloud_aio_lldap",
diff --git a/community-containers/lldap/readme.md b/community-containers/lldap/readme.md
index ce4636bc..586aea9e 100644
--- a/community-containers/lldap/readme.md
+++ b/community-containers/lldap/readme.md
@@ -18,10 +18,7 @@ Functionality with this configuration:
> For simplicity, this configuration is done via the command line (don't worry, it's very simple).
-First, you need to retrieve the LLDAP admin password, this will be used later on. Which you need to type in or copy and paste:
-```bash
-sudo docker inspect nextcloud-aio-lldap | grep LLDAP_LDAP_USER_PASS
-```
+First, you need to retrieve the LLDAP admin password that you can see next to the container in the AIO interface. There you can configure smtp first and then invite users via mail.
Now go into the Nextcloud container:
**Please note:** If you do not have CLI access to the server, you can now run docker commands via a web session by using this community container: https://github.com/nextcloud/all-in-one/tree/main/community-containers/container-management. This script below can be run from inside the container-management container via `bash /lldap.sh`.
diff --git a/community-containers/makemkv/readme.md b/community-containers/makemkv/readme.md
index ed9ce040..e78510ee 100644
--- a/community-containers/makemkv/readme.md
+++ b/community-containers/makemkv/readme.md
@@ -5,7 +5,7 @@ This container bundles MakeMKV and auto-configures it for you.
- This container should only be run in home networks
- ⚠️ This container mounts all devices from the host inside the container in order to be able to access the external DVD/Blu-ray drives which is a security issue. However no better solution was found for the time being.
- This container only works on Linux and not on Docker-Desktop.
-- This container requires the [`NEXTCLOUD_MOUNT` variable in AIO to be set](https://github.com/nextcloud/all-in-one?tab=readme-ov-file#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host). Otherwise the output will not be saved correctly..
+- This container requires the [`NEXTCLOUD_MOUNT` variable in AIO to be set](https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host). Otherwise the output will not be saved correctly..
- After adding and starting the container, you need to visit `https://internal.ip.of.server:5802` in order to log in with the `makemkv` user and the password that you can see next to the container in the AIO interface. (The web page uses a self-signed certificate, so you need to accept the warning).
- After the first login, you can adjust the `/output` directory in the MakeMKV settings to a subdirectory of the root of your chosen `NEXTCLOUD_MOUNT`. (by default `NEXTCLOUD_MOUNT` is mounted to `/output` inside the container. Thus all data is written to the root of it)
- The configured `NEXTCLOUD_DATADIR` is getting mounted to `/storage` inside the container.
diff --git a/community-containers/minio/minio.json b/community-containers/minio/minio.json
new file mode 100644
index 00000000..50613202
--- /dev/null
+++ b/community-containers/minio/minio.json
@@ -0,0 +1,41 @@
+{
+ "aio_services_v1": [
+ {
+ "container_name": "nextcloud-aio-minio",
+ "image_tag": "v2",
+ "display_name": "Minio S3 Storage",
+ "documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/minio",
+ "image": "ghcr.io/szaimen/aio-minio",
+ "internal_port": "9000",
+ "environment": [
+ "MINIO_ROOT_USER=nextcloud",
+ "MINIO_ROOT_PASSWORD=%MINIO_ROOT_PASSWORD%"
+ ],
+ "secrets": [
+ "MINIO_ROOT_PASSWORD"
+ ],
+ "volumes": [
+ {
+ "source": "nextcloud_aio_minio",
+ "destination": "/data",
+ "writeable": true
+ }
+ ],
+ "backup_volumes": [
+ "nextcloud_aio_minio"
+ ],
+ "nextcloud_exec_commands": [
+ "php /var/www/html/occ config:system:set objectstore class --value 'OC\\Files\\ObjectStore\\S3'",
+ "php /var/www/html/occ config:system:set objectstore arguments autocreate --value true --type bool",
+ "php /var/www/html/occ config:system:set objectstore arguments use_path_style --value true --type bool",
+ "php /var/www/html/occ config:system:set objectstore arguments use_ssl --value false --type bool",
+ "php /var/www/html/occ config:system:set objectstore arguments region --value ''",
+ "php /var/www/html/occ config:system:set objectstore arguments bucket --value nextcloud",
+ "php /var/www/html/occ config:system:set objectstore arguments key --value nextcloud",
+ "php /var/www/html/occ config:system:set objectstore arguments secret --value %MINIO_ROOT_PASSWORD%",
+ "php /var/www/html/occ config:system:set objectstore arguments port --value 9000",
+ "php /var/www/html/occ config:system:set objectstore arguments hostname --value nextcloud-aio-minio"
+ ]
+ }
+ ]
+}
diff --git a/community-containers/minio/readme.md b/community-containers/minio/readme.md
new file mode 100644
index 00000000..be41d5bd
--- /dev/null
+++ b/community-containers/minio/readme.md
@@ -0,0 +1,18 @@
+## Minio
+This container bundles minio s3 storage and auto-configures it for you.
+
+>[!WARNING]
+> Enabling this container will remove access to all the files formerly written to the data directory.
+> So only enable this on a clean instance directly after installing AIO.
+> All additional users that are added via Nextcloud afterwards are going to work correctly.
+> Also, after enabling and using it, make sure to not disable the container as you cannot migrate from s3 to local storage anymore and s3 is a critical part of your infrastructure from then on.
+
+### Notes
+- The data of Minio will be automatically included in AIOs backup solution!
+- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
+
+### Repository
+https://github.com/szaimen/aio-minio
+
+### Maintainer
+https://github.com/szaimen
diff --git a/community-containers/nextcloud-exporter/nextcloud-exporter.json b/community-containers/nextcloud-exporter/nextcloud-exporter.json
new file mode 100644
index 00000000..e5bf74b8
--- /dev/null
+++ b/community-containers/nextcloud-exporter/nextcloud-exporter.json
@@ -0,0 +1,35 @@
+{
+ "aio_services_v1": [
+ {
+ "container_name": "nextcloud-aio-nextcloud-exporter",
+ "display_name": "Prometheus Nextcloud Exporter",
+ "documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter",
+ "image": "ghcr.io/xperimental/nextcloud-exporter",
+ "image_tag": "0.9.0",
+ "internal_port": "9205",
+ "restart": "unless-stopped",
+ "ports": [
+ {
+ "ip_binding": "127.0.0.1",
+ "port_number": "9205",
+ "protocol": "tcp"
+ }
+ ],
+ "environment": [
+ "TZ=%TIMEZONE%",
+ "NEXTCLOUD_SERVER=https://%NC_DOMAIN%",
+ "NEXTCLOUD_AUTH_TOKEN=%NEXTCLOUD_EXPORTER_TOKEN%",
+ "NEXTCLOUD_LISTEN_ADDRESS=0.0.0.0:9205",
+ "NEXTCLOUD_TIMEOUT=5s"
+ ],
+ "ui_secret": "NEXTCLOUD_EXPORTER_CADDY_PASSWORD",
+ "secrets": [
+ "NEXTCLOUD_EXPORTER_TOKEN",
+ "NEXTCLOUD_EXPORTER_CADDY_PASSWORD"
+ ],
+ "nextcloud_exec_commands": [
+ "php /var/www/html/occ config:app:set serverinfo token --value %NEXTCLOUD_EXPORTER_TOKEN%"
+ ]
+ }
+ ]
+}
diff --git a/community-containers/nextcloud-exporter/readme.md b/community-containers/nextcloud-exporter/readme.md
new file mode 100644
index 00000000..3efa6257
--- /dev/null
+++ b/community-containers/nextcloud-exporter/readme.md
@@ -0,0 +1,72 @@
+## Prometheus Nextcloud Exporter
+
+A Prometheus exporter that collects metrics from your Nextcloud instance for monitoring and alerting.
+
+### How to install
+
+See the [Community Containers documentation](https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers) for instructions on how to install this in your Nextcloud All-in-One setup.
+
+### Security & Access
+
+**Important:** This container is configured to bind only to `127.0.0.1` (localhost) for security reasons. Prometheus exporters typically don't include authentication, so direct network exposure is not recommended.
+
+#### Access Options
+
+1. **With Caddy Container (Recommended)**: If you also install the [Caddy community container](https://github.com/nextcloud/all-in-one/tree/main/community-containers/caddy), it will automatically configure secure HTTPS access to your metrics with authentication at `metrics.your-domain.com`
+
+ **Getting Authentication Credentials**:
+ - **Username**: Always `metrics`
+ - **Password**: After deploying the nextcloud-exporter container, the automatically generated password will be displayed in the AIO interface. Look for it in the container section below the container name "Prometheus Nextcloud Exporter".
+
+2. **Custom Reverse Proxy**: Set up your own reverse proxy (nginx, Apache, etc.) to provide HTTPS and authentication. See configuration guides:
+ - [NGINX Authentication](https://nginx.org/en/docs/http/ngx_http_auth_basic_module.html) + [Reverse Proxy](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/)
+ - [Apache Authentication](https://httpd.apache.org/docs/2.4/howto/auth.html) + [Reverse Proxy](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html)
+ - [Traefik BasicAuth](https://doc.traefik.io/traefik/middlewares/http/basicauth/)
+ - [Prometheus Security Best Practices](https://prometheus.io/docs/operating/security/)
+
+3. **Direct Local Access**: Access metrics directly from the server at `http://127.0.0.1:9205/metrics` (no authentication)
+
+### What it monitors
+- User activity (active users hourly, daily)
+- File counts and storage usage
+- System health and database size
+- App statistics and update availability
+- Nextcloud performance metrics
+
+### Prometheus Configuration
+
+For **local server access** (if Prometheus runs on the same server):
+```yaml
+scrape_configs:
+ - job_name: 'nextcloud'
+ scrape_interval: 90s
+ static_configs:
+ - targets: ['127.0.0.1:9205']
+ metrics_path: /metrics
+ scheme: http
+```
+
+For **Caddy integration** (secure external access):
+```yaml
+scrape_configs:
+ - job_name: 'nextcloud'
+ scrape_interval: 90s
+ static_configs:
+ - targets: ['metrics.your-domain.com']
+ metrics_path: /
+ scheme: https
+ basic_auth:
+ username: 'metrics'
+ password: 'your-generated-password'
+```
+
+### Visualization
+
+Compatible with Grafana for creating monitoring dashboards:
+- Pre-built dashboard available: [Grafana Dashboard #20716](https://grafana.com/grafana/dashboards/20716-nextcloud/)
+
+### Repository
+https://github.com/xperimental/nextcloud-exporter
+
+### Maintainer
+https://github.com/grotax
diff --git a/community-containers/notifications/notifications.json b/community-containers/notifications/notifications.json
new file mode 100644
index 00000000..5d886ec9
--- /dev/null
+++ b/community-containers/notifications/notifications.json
@@ -0,0 +1,23 @@
+{
+ "aio_services_v1": [
+ {
+ "container_name": "nextcloud-aio-notifications",
+ "display_name": "Notifications",
+ "documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/notifications",
+ "image": "ghcr.io/szaimen/aio-notifications",
+ "image_tag": "v1",
+ "internal_port": "10000",
+ "restart": "unless-stopped",
+ "volumes": [
+ {
+ "source": "%WATCHTOWER_DOCKER_SOCKET_PATH%",
+ "destination": "/var/run/docker.sock",
+ "writeable": false
+ }
+ ],
+ "environment": [
+ "TZ=%TIMEZONE%"
+ ]
+ }
+ ]
+}
diff --git a/community-containers/notifications/readme.md b/community-containers/notifications/readme.md
new file mode 100644
index 00000000..78ec49b6
--- /dev/null
+++ b/community-containers/notifications/readme.md
@@ -0,0 +1,12 @@
+## Notifications
+This container allows other AIO community containers to send admin notifications to Nextcloud users.
+
+### Notes
+- It needs to be enabled for the [scrutiny container](https://github.com/nextcloud/all-in-one/tree/main/community-containers/scrutiny) for example to make use of admin notifications that are sent if a smartctl failure was found.
+- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
+
+### Repository
+https://github.com/szaimen/aio-notifications
+
+### Maintainer
+https://github.com/szaimen
diff --git a/community-containers/scrutiny/readme.md b/community-containers/scrutiny/readme.md
index dc972d44..3bb728f7 100644
--- a/community-containers/scrutiny/readme.md
+++ b/community-containers/scrutiny/readme.md
@@ -6,7 +6,7 @@ This container bundles Scrutiny which is a frontend for SMART stats and auto-con
- ⚠️ This container mounts all devices from the host inside the container in order to be able to access the drives and smartctl stats which is a security issue. However no better solution was found for the time being.
- This container only works on Linux and not on Docker-Desktop.
- After adding and starting the container, you need to visit `http://internal.ip.of.server:8000` which will show the dashboard for your drives.
-- It currently does not support sending notifications as no good solution was found yet that makes this possible. See https://github.com/szaimen/aio-scrutiny/issues/3
+- It supports sending notifications in case of a smartctl failure if you enable the notifications community container: https://github.com/nextcloud/all-in-one/tree/main/community-containers/notifications
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
### Repository
diff --git a/community-containers/scrutiny/scrutiny.json b/community-containers/scrutiny/scrutiny.json
index 4b368291..b367e497 100644
--- a/community-containers/scrutiny/scrutiny.json
+++ b/community-containers/scrutiny/scrutiny.json
@@ -5,7 +5,7 @@
"display_name": "Scrutiny",
"documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/scrutiny",
"image": "ghcr.io/szaimen/aio-scrutiny",
- "image_tag": "v1",
+ "image_tag": "v2",
"internal_port": "8000",
"init": false,
"restart": "unless-stopped",
diff --git a/community-containers/smbserver/readme.md b/community-containers/smbserver/readme.md
index 9886f4b2..20d90c9f 100644
--- a/community-containers/smbserver/readme.md
+++ b/community-containers/smbserver/readme.md
@@ -3,7 +3,6 @@ This container bundles an SMB-server and allows to configure it via a graphical
### Notes
- This container should only be run in home networks
-- This container currently only works on amd64. See https://github.com/szaimen/aio-smbserver/issues/3
- After adding and starting the container, you need to visit `https://internal.ip.of.server:5803` in order to log in with the `smbserver` user and the password that you can see next to the container in the AIO interface. (The web page uses a self-signed certificate, so you need to accept the warning). Then type in `bash /smbserver.sh` and you will see a graphical UI for configuring the smb-server interactively.
- The config data of SMB-server will be automatically included in AIOs backup solution!
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
diff --git a/community-containers/stalwart/stalwart.json b/community-containers/stalwart/stalwart.json
index e2061688..b9a48091 100644
--- a/community-containers/stalwart/stalwart.json
+++ b/community-containers/stalwart/stalwart.json
@@ -48,7 +48,8 @@
"environment": [
"TZ=%TIMEZONE%",
"NC_DOMAIN=%NC_DOMAIN%",
- "STALWART_USER_PASS=%STALWART_USER_PASS%"
+ "STALWART_USER_PASS=%STALWART_USER_PASS%",
+ "CLAMAV_ENABLED=%CLAMAV_ENABLED%"
],
"secrets": [
"STALWART_USER_PASS"
diff --git a/compose.yaml b/compose.yaml
index 93a6b7af..c18d92d3 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -1,17 +1,20 @@
+name: nextcloud-aio # Add the container to the same compose project like all the sibling containers are added to automatically.
services:
nextcloud-aio-mastercontainer:
- image: ghcr.io/nextcloud-releases/all-in-one:latest
- init: true
- restart: always
+ image: ghcr.io/nextcloud-releases/all-in-one:latest # This is the container image used. You can switch to ghcr.io/nextcloud-releases/all-in-one:beta if you want to help testing new releases. See https://github.com/nextcloud/all-in-one#how-to-switch-the-channel
+ init: true # This setting makes sure that signals from main process inside the container are correctly forwarded to children. See https://docs.docker.com/reference/compose-file/services/#init
+ restart: always # This makes sure that the container starts always together with the host OS. See https://docs.docker.com/reference/compose-file/services/#restart
container_name: nextcloud-aio-mastercontainer # This line is not allowed to be changed as otherwise AIO will not work correctly
volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config # This line is not allowed to be changed as otherwise the built-in backup solution will not work
- /var/run/docker.sock:/var/run/docker.sock:ro # May be changed on macOS, Windows or docker rootless. See the applicable documentation. If adjusting, don't forget to also set 'WATCHTOWER_DOCKER_SOCKET_PATH'!
- network_mode: bridge # add to the same network as docker run would do
+ network_mode: bridge # This adds the container to the same network as docker run would do. Comment this line and uncomment the line below and the networks section at the end of the file if you want to define a custom MTU size for the docker network
+ # networks: ["nextcloud-aio"]
ports:
- 80:80 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
- - 8080:8080
+ - 8080:8080 # This is the AIO interface, served via https and self-signed certificate. See https://github.com/nextcloud/all-in-one#explanation-of-used-ports
- 8443:8443 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
+ # security_opt: ["label:disable"] # Is needed when using SELinux. See https://github.com/nextcloud/all-in-one#are-there-known-problems-when-selinux-is-enabled
# environment: # Is needed when using any of the options below
# AIO_DISABLE_BACKUP_SECTION: false # Setting this to true allows to hide the backup section in the AIO interface. See https://github.com/nextcloud/all-in-one#how-to-disable-the-backup-section
# APACHE_PORT: 11000 # Is needed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
@@ -19,6 +22,7 @@ services:
# APACHE_ADDITIONAL_NETWORK: frontend_net # (Optional) Connect the apache container to an additional docker network. Needed when behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) running in a different docker network on same server. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
# BORG_RETENTION_POLICY: --keep-within=7d --keep-weekly=4 --keep-monthly=6 # Allows to adjust borgs retention policy. See https://github.com/nextcloud/all-in-one#how-to-adjust-borgs-retention-policy
# COLLABORA_SECCOMP_DISABLED: false # Setting this to true allows to disable Collabora's Seccomp feature. See https://github.com/nextcloud/all-in-one#how-to-disable-collaboras-seccomp-feature
+ # DOCKER_API_VERSION: 1.44 # You can adjust the internally used docker api version with this variable. ⚠️⚠️⚠️ Warning: please note that only the default api version (unset this variable) is supported and tested by the maintainers of Nextcloud AIO. So use this on your own risk and things might break without warning. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-internally-used-docker-api-version
# FULLTEXTSEARCH_JAVA_OPTIONS: "-Xms1024M -Xmx1024M" # Allows to adjust the fulltextsearch java options. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-fulltextsearch-java-options
# NEXTCLOUD_DATADIR: /mnt/ncdata # Allows to set the host directory for Nextcloud's datadir. ⚠️⚠️⚠️ Warning: do not set or adjust this value after the initial Nextcloud installation is done! See https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir
# NEXTCLOUD_MOUNT: /mnt/ # Allows the Nextcloud container to access the chosen directory on the host. See https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host
@@ -32,13 +36,12 @@ services:
# NEXTCLOUD_ENABLE_DRI_DEVICE: true # This allows to enable the /dev/dri device for containers that profit from it. ⚠️⚠️⚠️ Warning: this only works if the '/dev/dri' device is present on the host! If it should not exist on your host, don't set this to true as otherwise the Nextcloud container will fail to start! See https://github.com/nextcloud/all-in-one#how-to-enable-hardware-acceleration-for-nextcloud
# NEXTCLOUD_ENABLE_NVIDIA_GPU: true # This allows to enable the NVIDIA runtime and GPU access for containers that profit from it. ⚠️⚠️⚠️ Warning: this only works if an NVIDIA gpu is installed on the server. See https://github.com/nextcloud/all-in-one#how-to-enable-hardware-acceleration-for-nextcloud.
# NEXTCLOUD_KEEP_DISABLED_APPS: false # Setting this to true will keep Nextcloud apps that are disabled in the AIO interface and not uninstall them if they should be installed. See https://github.com/nextcloud/all-in-one#how-to-keep-disabled-apps
- # SKIP_DOMAIN_VALIDATION: false # This should only be set to true if things are correctly configured. See https://github.com/nextcloud/all-in-one?tab=readme-ov-file#how-to-skip-the-domain-validation
+ # SKIP_DOMAIN_VALIDATION: false # This should only be set to true if things are correctly configured. See https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation
# TALK_PORT: 3478 # This allows to adjust the port that the talk container is using which is exposed on the host. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-talk-port
# WATCHTOWER_DOCKER_SOCKET_PATH: /var/run/docker.sock # Needs to be specified if the docker socket on the host is not located in the default '/var/run/docker.sock'. Otherwise mastercontainer updates will fail. For macos it needs to be '/var/run/docker.sock'
- # security_opt: ["label:disable"] # Is needed when using SELinux
# # Optional: Caddy reverse proxy. See https://github.com/nextcloud/all-in-one/discussions/575
-# # Alternatively, use Tailscale if you don't have a domain yet. See https://github.com/nextcloud/all-in-one/discussions/5439
+# # Alternatively, use Tailscale if you don't have a domain yet. See https://github.com/nextcloud/all-in-one/discussions/6817
# # Hint: You need to uncomment APACHE_PORT: 11000 above, adjust cloud.example.com to your domain and uncomment the necessary docker volumes at the bottom of this file in order to make it work
# # You can find further examples here: https://github.com/nextcloud/all-in-one/discussions/588
# caddy:
@@ -69,3 +72,10 @@ volumes: # If you want to store the data on a different drive, see https://githu
# caddy_config:
# caddy_data:
# caddy_sites:
+
+# # Adjust the MTU size of the docker network. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-mtu-size-of-the-docker-network
+# networks:
+# nextcloud-aio:
+# name: nextcloud-aio
+# driver_opts:
+# com.docker.network.driver.mtu: 1440
diff --git a/develop.md b/develop.md
index abf52208..457b3a76 100644
--- a/develop.md
+++ b/develop.md
@@ -26,7 +26,7 @@ Simply use https://github.com/nextcloud/all-in-one/issues/6198 as template.
Go to https://github.com/nextcloud-releases/all-in-one/actions/workflows/repo-sync.yml and run the workflow that will first sync the repo and then build new container that automatically get published to `develop` and `develop-arm64`.
## How to test things correctly?
-Before testing, make sure that at least the amd64 containers are built successfully by checking the last workflow here: https://github.com/nextcloud-releases/all-in-one/actions/workflows/build_images.yml.
+Before testing, make sure that at least the amd64 containers are built successfully by checking the last workflow here: https://github.com/nextcloud-releases/all-in-one/actions/workflows/build_images.yml.
There is a testing-VM available for the maintainer of AIO that allows for some final testing before releasing new version. See [this](https://cloud.nextcloud.com/apps/collectives/Nextcloud%20Handbook/Technical/AIO%20testing%20VM?fileId=6350152) for details.
@@ -48,12 +48,25 @@ This is documented here: https://github.com/nextcloud-releases/all-in-one/tree/m
## How to connect to the database?
Simply run `sudo docker exec -it nextcloud-aio-database psql -U oc_nextcloud nextcloud_database` and you should be in.
-## How to locally build and test changes to mastercontainer?
-1. Push changes to your own git fork and branch.
-1. Use below commands to build mastercontainer image for a custom git url and branch:
+## How to locally build and test changes to mastercontainer
+1. Ensure you are on the developer channel per the instructions above.
+1. Use the commands below from the project root to build the mastercontainer image:
```
-cd Containers/mastercontainer
-docker buildx build -t ghcr.io/nextcloud-releases/all-in-one:latest --build-arg AIO_GIT_URL="https://github.com/my-fork-repo/all-in-one.git" --build-arg AIO_GIT_BRANCH="my-feature-branch" --load .
+docker buildx build --file Containers/mastercontainer/Dockerfile --tag ghcr.io/nextcloud-releases/all-in-one:develop --load .
```
1. Start a container with above built image.
1. Since the hash of a locally built image doesn't match the latest release mastercontainer, it prompts for a mandatory update. To temporarily bypass the update suffix `?bypass_mastercontainer_update` to the URL. Eg: `https://localhost:8080/containers?bypass_mastercontainer_update`
+
+## How to locally build and test changes to other containers using the bypass_container_update param
+1. Ensure you are on the developer channel per the instructions above.
+1. Use the commands below from the project root to build the container image:
+```
+# For the "nextcloud" container
+docker buildx build --file Containers/nextcloud/Dockerfile --tag ghcr.io/nextcloud-releases/aio-nextcloud:develop --load .
+
+# For all other containers
+docker buildx build --file Containers/{container}/Dockerfile --tag ghcr.io/nextcloud-releases/aio-{container}:develop --load Containers/{container}
+```
+1. Stop the containers using the AIO interface.
+1. Reload the AIO interface with the param `bypass_container_update` to avoid overwriting your local changes, e.g. `https://localhost:8080/containers?bypass_container_update`.
+1. Click "Start and update containers" and test your changes. Containers will not be updated, despite the button text.
diff --git a/local-instance.md b/local-instance.md
index 4633bc08..8abbddb6 100644
--- a/local-instance.md
+++ b/local-instance.md
@@ -9,7 +9,7 @@ It is possible due to several reasons that you do not want or cannot open Nextcl
- [5. Buy a certificate and use that](#5-buy-a-certificate-and-use-that)
## 1. Tailscale
-This is the recommended way. For a reverse proxy example guide for Tailscale, see this guide by @flll: https://github.com/nextcloud/all-in-one/discussions/5439
+This is the recommended way. For a reverse proxy example guide for Tailscale, see this guide by [@Perseus333](https://github.com/Perseus333): https://github.com/nextcloud/all-in-one/discussions/6817
## 2. The normal way
The normal way is the following:
@@ -22,10 +22,11 @@ The normal way is the following:
**Hint:** You may have a look at [this video](https://youtu.be/zk-y2wVkY4c) for a more complete but possibly outdated example.
## 3. Use the ACME DNS-challenge
-You can alternatively use the ACME DNS-challenge to get a valid certificate for Nextcloud. Here is described how to set it up: https://github.com/nextcloud/all-in-one#how-to-get-nextcloud-running-using-the-acme-dns-challenge
+You can alternatively use the ACME DNS-challenge to get a valid certificate for Nextcloud. Here is described how to set it up using an external caddy reverse proxy: https://github.com/nextcloud/all-in-one#how-to-get-nextcloud-running-using-the-acme-dns-challenge
## 4. Use Cloudflare
If you do not have any control over the network, you may think about using Cloudflare Tunnel to get a valid certificate for your Nextcloud. However it will be opened to the public internet then. See https://github.com/nextcloud/all-in-one#how-to-run-nextcloud-behind-a-cloudflare-tunnel how to set this up.
## 5. Buy a certificate and use that
If none of the above ways work for you, you may simply buy a certificate from an issuer for your domain. You then download the certificate onto your server, configure AIO in [reverse proxy mode](./reverse-proxy.md) and use the certificate for your domain in your reverse proxy config.
+
diff --git a/manual-install/latest.yml b/manual-install/latest.yml
index 04ac9193..e9362ccc 100644
--- a/manual-install/latest.yml
+++ b/manual-install/latest.yml
@@ -10,15 +10,15 @@ services:
nextcloud-aio-talk:
condition: service_started
required: false
- nextcloud-aio-nextcloud:
- condition: service_started
- required: false
nextcloud-aio-notify-push:
condition: service_started
required: false
nextcloud-aio-whiteboard:
condition: service_started
required: false
+ nextcloud-aio-nextcloud:
+ condition: service_started
+ required: false
image: ghcr.io/nextcloud-releases/aio-apache:latest
user: "33"
init: true
@@ -135,6 +135,7 @@ services:
- POSTGRES_DB=nextcloud_database
- POSTGRES_USER=nextcloud
- REDIS_HOST=nextcloud-aio-redis
+ - REDIS_PORT=6379
- REDIS_HOST_PASSWORD=${REDIS_PASSWORD}
- APACHE_HOST=nextcloud-aio-apache
- APACHE_PORT
@@ -160,11 +161,14 @@ services:
- TALK_PORT
- IMAGINARY_ENABLED
- IMAGINARY_HOST=nextcloud-aio-imaginary
- - CLAMAV_MAX_SIZE=${APACHE_MAX_SIZE}
- PHP_UPLOAD_LIMIT=${NEXTCLOUD_UPLOAD_LIMIT}
- PHP_MEMORY_LIMIT=${NEXTCLOUD_MEMORY_LIMIT}
- FULLTEXTSEARCH_ENABLED
- FULLTEXTSEARCH_HOST=nextcloud-aio-fulltextsearch
+ - FULLTEXTSEARCH_PROTOCOL=http
+ - FULLTEXTSEARCH_PORT=9200
+ - FULLTEXTSEARCH_USER=elastic
+ - FULLTEXTSEARCH_INDEX=nextcloud-aio
- PHP_MAX_TIME=${NEXTCLOUD_MAX_TIME}
- TRUSTED_CACERTS_DIR=${NEXTCLOUD_TRUSTED_CACERTS_DIR}
- STARTUP_APPS=${NEXTCLOUD_STARTUP_APPS}
@@ -204,6 +208,7 @@ services:
- NEXTCLOUD_HOST=nextcloud-aio-nextcloud
- TZ=${TIMEZONE}
- REDIS_HOST=nextcloud-aio-redis
+ - REDIS_PORT=6379
- REDIS_HOST_PASSWORD=${REDIS_PASSWORD}
- POSTGRES_HOST=nextcloud-aio-database
- POSTGRES_PORT=5432
@@ -252,8 +257,8 @@ services:
expose:
- "9980"
environment:
- - aliasgroup1=https://${NC_DOMAIN}:443
- - extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:mount_jail_tree=false --o:logging.level=warning --o:home_mode.enable=true --o:remote_font_config.url=https://${NC_DOMAIN}/apps/richdocuments/settings/fonts.json --o:net.post_allow.host[0]=.+
+ - aliasgroup1=https://${NC_DOMAIN}:443,http://nextcloud-aio-apache:23973
+ - extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:logging.disable_server_audit=true --o:logging.level=warning --o:logging.level_startup=warning --o:welcome.enable=false --o:remote_font_config.url=https://${NC_DOMAIN}/apps/richdocuments/settings/fonts.json --o:net.post_allow.host[0]=.+
- dictionaries=${COLLABORA_DICTIONARIES}
- TZ=${TIMEZONE}
- server_name=${NC_DOMAIN}
@@ -264,6 +269,8 @@ services:
cap_add:
- MKNOD
- SYS_ADMIN
+ - SYS_CHROOT
+ - FOWNER
- CHOWN
cap_drop:
- NET_RAW
@@ -434,10 +441,10 @@ services:
environment:
- TZ=${TIMEZONE}
- ES_JAVA_OPTS=${FULLTEXTSEARCH_JAVA_OPTIONS}
- - bootstrap.memory_lock=true
+ - bootstrap.memory_lock=false
- cluster.name=nextcloud-aio
- discovery.type=single-node
- - logger.org.elasticsearch.discovery=WARN
+ - logger.level=WARN
- http.port=9200
- xpack.license.self_generated.type=basic
- xpack.security.enabled=false
@@ -471,6 +478,7 @@ services:
- JWT_SECRET_KEY=${WHITEBOARD_SECRET}
- STORAGE_STRATEGY=redis
- REDIS_HOST=nextcloud-aio-redis
+ - REDIS_PORT=6379
- REDIS_HOST_PASSWORD=${REDIS_PASSWORD}
- BACKUP_DIR=/tmp
restart: unless-stopped
diff --git a/manual-install/readme.md b/manual-install/readme.md
index 874a5b4b..ea2c2978 100644
--- a/manual-install/readme.md
+++ b/manual-install/readme.md
@@ -6,7 +6,7 @@ You can run the containers that are build for AIO with docker-compose. This come
- You can run it without a container having access to the docker socket
- You can modify all values on your own
- You can run the containers with docker swarm
-- You can run this in environments where access to docker.io is not possible. See [this issue](https://github.com/nextcloud/all-in-one/discussions/5268).
+- You can run this in environments where access to ghcr.io is not possible. See [this issue](https://github.com/nextcloud/all-in-one/discussions/5268).
### Disadvantages
- You lose the AIO interface
diff --git a/manual-install/update-yaml.sh b/manual-install/update-yaml.sh
index 70d14b4e..af746aee 100644
--- a/manual-install/update-yaml.sh
+++ b/manual-install/update-yaml.sh
@@ -46,6 +46,7 @@ sed -i '/AIO_TOKEN/d' containers.yml
sed -i '/AIO_URL/d' containers.yml
sed -i '/DOCKER_SOCKET_PROXY_ENABLED/d' containers.yml
sed -i '/ADDITIONAL_TRUSTED_PROXY/d' containers.yml
+sed -i '/TURN_DOMAIN/d' containers.yml
TCP="$(grep -oP '[%A-Z0-9_]+/tcp' containers.yml | sort -u)"
mapfile -t TCP <<< "$TCP"
diff --git a/manual-upgrade.md b/manual-upgrade.md
index 84c742e5..fbc07d3e 100644
--- a/manual-upgrade.md
+++ b/manual-upgrade.md
@@ -108,7 +108,7 @@ However, if you are unsure check the ghcr.io (https://github.com/nextcloud-relea
Once you see no more activities in the logs or a message like ```NOTICE: ready to handle connections```, we've done it!
-#### Now you can handle everything through the AIO admin interface and stop and restart the containers normally.
+#### Now you can handle everything through the AIO interface and stop and restart the containers normally.
---
diff --git a/nextcloud-aio-helm-chart/Chart.yaml b/nextcloud-aio-helm-chart/Chart.yaml
index 9b9ef61e..6288a381 100755
--- a/nextcloud-aio-helm-chart/Chart.yaml
+++ b/nextcloud-aio-helm-chart/Chart.yaml
@@ -1,6 +1,6 @@
name: nextcloud-aio-helm-chart
description: A generated Helm Chart for Nextcloud AIO from Skippbox Kompose
-version: 11.2.1
+version: 12.5.0
apiVersion: v2
keywords:
- latest
diff --git a/nextcloud-aio-helm-chart/readme.md b/nextcloud-aio-helm-chart/readme.md
index edf6c779..cb31e601 100755
--- a/nextcloud-aio-helm-chart/readme.md
+++ b/nextcloud-aio-helm-chart/readme.md
@@ -1,7 +1,7 @@
# Nextcloud AIO Helm-chart
> [!NOTE]
-> For an enterprise-ready and scalable deployment method based on Helm Charts (also available for Podman), please [contact Nextcloud GmbH](https://nextcloud.com/enterprise/).
+> For an enterprise-ready and scalable deployment method based on Helm Charts (also available for Podman and OpenShift), please [contact Nextcloud GmbH](https://nextcloud.com/enterprise/).
> [!IMPORTANT]
> This Helm-Chart is not intended to be used with Ingress as it handles TLS itself via the built-in apache container and exposes a Loadbalancer port itself on the Cluster. See the [apache service](https://github.com/nextcloud/all-in-one/blob/main/nextcloud-aio-helm-chart/templates/nextcloud-aio-apache-service.yaml). However if the Cluster is used behind NAT, you can adjust `APACHE_PORT` to a different one than 443 and do the TLS offloading on an external Reverse Proxy that forwards the traffic to the configured port via http. If you really need the Ingress feature, please [contact Nextcloud GmbH](https://nextcloud.com/enterprise/) as we offer an enterprise-ready and scalable deployment method based on Helm Charts that also allows Ingress to be used.
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-apache-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-apache-deployment.yaml
index 5751c7bf..e540791c 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-apache-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-apache-deployment.yaml
@@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-apache
name: nextcloud-aio-apache
@@ -17,7 +17,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-apache
spec:
@@ -61,7 +61,7 @@ spec:
value: "{{ .Values.TIMEZONE }}"
- name: WHITEBOARD_HOST
value: nextcloud-aio-whiteboard
- image: ghcr.io/nextcloud-releases/aio-apache:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-apache:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-apache-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-apache-service.yaml
index f496a3f8..98e33a4d 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-apache-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-apache-service.yaml
@@ -2,7 +2,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-apache
name: nextcloud-aio-apache
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-clamav-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-clamav-deployment.yaml
index 6d2678f8..57ec7739 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-clamav-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-clamav-deployment.yaml
@@ -3,7 +3,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-clamav
name: nextcloud-aio-clamav
@@ -18,7 +18,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-clamav
spec:
@@ -36,7 +36,7 @@ spec:
{{- end }}
initContainers:
- name: init-subpath
- image: ghcr.io/nextcloud-releases/aio-alpine:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command:
- mkdir
- "-p"
@@ -59,7 +59,7 @@ spec:
value: "{{ .Values.NEXTCLOUD_UPLOAD_LIMIT }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- image: ghcr.io/nextcloud-releases/aio-clamav:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-clamav:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-clamav-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-clamav-service.yaml
index 67a05650..8b236093 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-clamav-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-clamav-service.yaml
@@ -3,7 +3,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-clamav
name: nextcloud-aio-clamav
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-collabora-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-collabora-deployment.yaml
index ce2417e4..cd4e1368 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-collabora-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-collabora-deployment.yaml
@@ -3,7 +3,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-collabora
name: nextcloud-aio-collabora
@@ -16,7 +16,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-collabora
spec:
@@ -28,14 +28,18 @@ spec:
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- name: aliasgroup1
- value: https://{{ .Values.NC_DOMAIN }}:443
+ value: https://{{ .Values.NC_DOMAIN }}:443,http://nextcloud-aio-apache:23973
- name: dictionaries
value: "{{ .Values.COLLABORA_DICTIONARIES }}"
- name: extra_params
- value: --o:ssl.enable=false --o:ssl.termination=true --o:mount_jail_tree=false --o:logging.level=warning --o:home_mode.enable=true --o:remote_font_config.url=https://{{ .Values.NC_DOMAIN }}/apps/richdocuments/settings/fonts.json --o:net.post_allow.host[0]=.+
+ value: --o:ssl.enable=false --o:ssl.termination=true --o:logging.disable_server_audit=true --o:logging.level=warning --o:logging.level_startup=warning --o:welcome.enable=false --o:remote_font_config.url=https://{{ .Values.NC_DOMAIN }}/apps/richdocuments/settings/fonts.json --o:net.post_allow.host[0]=.+
- name: server_name
value: "{{ .Values.NC_DOMAIN }}"
- image: ghcr.io/nextcloud-releases/aio-collabora:20250701_092737
+ {{- if contains "--o:support_key=" (join " " (.Values.ADDITIONAL_COLLABORA_OPTIONS | default list)) }}
+ image: ghcr.io/nextcloud-releases/aio-collabora-online:20260122_105751
+ {{- else }}
+ image: ghcr.io/nextcloud-releases/aio-collabora:20260122_105751
+ {{- end }}
readinessProbe:
exec:
command:
@@ -61,5 +65,7 @@ spec:
add:
- MKNOD
- CAP_SYS_ADMIN
+ - SYS_CHROOT
+ - FOWNER
- CHOWN
{{- end }}
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-collabora-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-collabora-service.yaml
index 081a8131..5c81ef3e 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-collabora-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-collabora-service.yaml
@@ -3,7 +3,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-collabora
name: nextcloud-aio-collabora
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-database-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-database-deployment.yaml
index 450868ed..be6a9c90 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-database-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-database-deployment.yaml
@@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-database
name: nextcloud-aio-database
@@ -17,7 +17,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-database
spec:
@@ -35,7 +35,7 @@ spec:
{{- end }}
initContainers:
- name: init-subpath
- image: ghcr.io/nextcloud-releases/aio-alpine:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command:
- mkdir
- "-p"
@@ -64,7 +64,7 @@ spec:
value: nextcloud
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- image: ghcr.io/nextcloud-releases/aio-postgresql:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-postgresql:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-database-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-database-service.yaml
index e0abad63..45fdce3a 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-database-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-database-service.yaml
@@ -2,7 +2,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-database
name: nextcloud-aio-database
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-fulltextsearch-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-fulltextsearch-deployment.yaml
index 53180a99..bed60a0c 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-fulltextsearch-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-fulltextsearch-deployment.yaml
@@ -3,7 +3,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-fulltextsearch
name: nextcloud-aio-fulltextsearch
@@ -18,13 +18,13 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-fulltextsearch
spec:
initContainers:
- name: init-volumes
- image: ghcr.io/nextcloud-releases/aio-alpine:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command:
- chmod
- "777"
@@ -41,20 +41,20 @@ spec:
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- name: bootstrap.memory_lock
- value: "true"
+ value: "false"
- name: cluster.name
value: nextcloud-aio
- name: discovery.type
value: single-node
- name: http.port
value: "9200"
- - name: logger.org.elasticsearch.discovery
+ - name: logger.level
value: WARN
- name: xpack.license.self_generated.type
value: basic
- name: xpack.security.enabled
value: "false"
- image: ghcr.io/nextcloud-releases/aio-fulltextsearch:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-fulltextsearch:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-fulltextsearch-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-fulltextsearch-service.yaml
index 29dc4871..efe474b3 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-fulltextsearch-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-fulltextsearch-service.yaml
@@ -3,7 +3,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-fulltextsearch
name: nextcloud-aio-fulltextsearch
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-imaginary-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-imaginary-deployment.yaml
index a452962e..af15d4b3 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-imaginary-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-imaginary-deployment.yaml
@@ -3,7 +3,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-imaginary
name: nextcloud-aio-imaginary
@@ -16,7 +16,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-imaginary
spec:
@@ -38,7 +38,7 @@ spec:
value: "{{ .Values.IMAGINARY_SECRET }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- image: ghcr.io/nextcloud-releases/aio-imaginary:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-imaginary:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-imaginary-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-imaginary-service.yaml
index 28bc08be..44a57006 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-imaginary-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-imaginary-service.yaml
@@ -3,7 +3,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-imaginary
name: nextcloud-aio-imaginary
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-nextcloud-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-nextcloud-deployment.yaml
index 688ac9b4..8b6e8211 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-nextcloud-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-nextcloud-deployment.yaml
@@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-nextcloud
name: nextcloud-aio-nextcloud
@@ -17,7 +17,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-nextcloud
spec:
@@ -38,7 +38,7 @@ spec:
# AIO settings start # Do not remove or change this line!
initContainers:
- name: init-volumes
- image: ghcr.io/nextcloud-releases/aio-alpine:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command:
- chmod
- "777"
@@ -100,8 +100,6 @@ spec:
value: "{{ .Values.CLAMAV_ENABLED }}"
- name: CLAMAV_HOST
value: nextcloud-aio-clamav
- - name: CLAMAV_MAX_SIZE
- value: "{{ .Values.APACHE_MAX_SIZE }}"
- name: COLLABORA_ENABLED
value: "{{ .Values.COLLABORA_ENABLED }}"
- name: COLLABORA_HOST
@@ -110,8 +108,16 @@ spec:
value: "{{ .Values.FULLTEXTSEARCH_ENABLED }}"
- name: FULLTEXTSEARCH_HOST
value: nextcloud-aio-fulltextsearch
+ - name: FULLTEXTSEARCH_INDEX
+ value: nextcloud-aio
- name: FULLTEXTSEARCH_PASSWORD
value: "{{ .Values.FULLTEXTSEARCH_PASSWORD }}"
+ - name: FULLTEXTSEARCH_PORT
+ value: "9200"
+ - name: FULLTEXTSEARCH_PROTOCOL
+ value: http
+ - name: FULLTEXTSEARCH_USER
+ value: elastic
- name: IMAGINARY_ENABLED
value: "{{ .Values.IMAGINARY_ENABLED }}"
- name: IMAGINARY_HOST
@@ -156,6 +162,8 @@ spec:
value: nextcloud-aio-redis
- name: REDIS_HOST_PASSWORD
value: "{{ .Values.REDIS_PASSWORD }}"
+ - name: REDIS_PORT
+ value: "6379"
- name: REMOVE_DISABLED_APPS
value: "{{ .Values.REMOVE_DISABLED_APPS }}"
- name: SIGNALING_SECRET
@@ -182,7 +190,7 @@ spec:
value: "{{ .Values.WHITEBOARD_ENABLED }}"
- name: WHITEBOARD_SECRET
value: "{{ .Values.WHITEBOARD_SECRET }}"
- image: ghcr.io/nextcloud-releases/aio-nextcloud:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-nextcloud:20260122_105751
{{- if eq (.Values.RPSS_ENABLED | default "no") "yes" }} # AIO-config - do not change this comment!
securityContext:
# The items below only work in container context
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-nextcloud-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-nextcloud-service.yaml
index 6394b6fc..08ab70f2 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-nextcloud-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-nextcloud-service.yaml
@@ -2,7 +2,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-nextcloud
name: nextcloud-aio-nextcloud
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-notify-push-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-notify-push-deployment.yaml
index 480e046f..c8e30d05 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-notify-push-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-notify-push-deployment.yaml
@@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-notify-push
name: nextcloud-aio-notify-push
@@ -17,7 +17,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-notify-push
spec:
@@ -53,9 +53,11 @@ spec:
value: nextcloud-aio-redis
- name: REDIS_HOST_PASSWORD
value: "{{ .Values.REDIS_PASSWORD }}"
+ - name: REDIS_PORT
+ value: "6379"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- image: ghcr.io/nextcloud-releases/aio-notify-push:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-notify-push:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-notify-push-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-notify-push-service.yaml
index 58bc411b..986d98d4 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-notify-push-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-notify-push-service.yaml
@@ -2,7 +2,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-notify-push
name: nextcloud-aio-notify-push
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-onlyoffice-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-onlyoffice-deployment.yaml
index 0b79be44..2bb79f19 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-onlyoffice-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-onlyoffice-deployment.yaml
@@ -3,7 +3,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-onlyoffice
name: nextcloud-aio-onlyoffice
@@ -18,13 +18,13 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-onlyoffice
spec:
initContainers:
- name: init-volumes
- image: ghcr.io/nextcloud-releases/aio-alpine:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command:
- chmod
- "777"
@@ -42,7 +42,7 @@ spec:
value: "{{ .Values.ONLYOFFICE_SECRET }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- image: ghcr.io/nextcloud-releases/aio-onlyoffice:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-onlyoffice:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-onlyoffice-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-onlyoffice-service.yaml
index 08ea4965..5fc10b85 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-onlyoffice-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-onlyoffice-service.yaml
@@ -3,7 +3,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-onlyoffice
name: nextcloud-aio-onlyoffice
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-redis-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-redis-deployment.yaml
index 4120a5f5..28335e64 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-redis-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-redis-deployment.yaml
@@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-redis
name: nextcloud-aio-redis
@@ -17,7 +17,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-redis
spec:
@@ -39,7 +39,7 @@ spec:
value: "{{ .Values.REDIS_PASSWORD }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- image: ghcr.io/nextcloud-releases/aio-redis:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-redis:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-redis-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-redis-service.yaml
index 3deae463..a6a9a0a5 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-redis-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-redis-service.yaml
@@ -2,7 +2,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-redis
name: nextcloud-aio-redis
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-deployment.yaml
index 4424d662..679dd66e 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-deployment.yaml
@@ -3,7 +3,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-talk
name: nextcloud-aio-talk
@@ -16,7 +16,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-talk
spec:
@@ -52,7 +52,7 @@ spec:
value: "{{ .Values.TURN_SECRET }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- image: ghcr.io/nextcloud-releases/aio-talk:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-talk:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-recording-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-recording-deployment.yaml
index e121f2e6..8e631656 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-recording-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-recording-deployment.yaml
@@ -3,7 +3,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-talk-recording
name: nextcloud-aio-talk-recording
@@ -18,7 +18,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-talk-recording
spec:
@@ -44,7 +44,7 @@ spec:
value: "{{ .Values.RECORDING_SECRET }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- image: ghcr.io/nextcloud-releases/aio-talk-recording:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-talk-recording:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-recording-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-recording-service.yaml
index 9fe10d57..87fe0355 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-recording-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-recording-service.yaml
@@ -3,7 +3,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-talk-recording
name: nextcloud-aio-talk-recording
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-service.yaml
index 1b7f1a05..65388792 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-talk-service.yaml
@@ -4,7 +4,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-talk
name: nextcloud-aio-talk-public
@@ -12,7 +12,6 @@ metadata:
spec:
ipFamilyPolicy: PreferDualStack
type: LoadBalancer
- externalTrafficPolicy: Local
ports:
- name: "{{ .Values.TALK_PORT }}"
port: {{ .Values.TALK_PORT }}
@@ -28,7 +27,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-talk
name: nextcloud-aio-talk
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-whiteboard-deployment.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-whiteboard-deployment.yaml
index e3734f10..5788cfa0 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-whiteboard-deployment.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-whiteboard-deployment.yaml
@@ -3,7 +3,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-whiteboard
name: nextcloud-aio-whiteboard
@@ -16,7 +16,7 @@ spec:
template:
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-whiteboard
spec:
@@ -44,11 +44,13 @@ spec:
value: nextcloud-aio-redis
- name: REDIS_HOST_PASSWORD
value: "{{ .Values.REDIS_PASSWORD }}"
+ - name: REDIS_PORT
+ value: "6379"
- name: STORAGE_STRATEGY
value: redis
- name: TZ
value: "{{ .Values.TIMEZONE }}"
- image: ghcr.io/nextcloud-releases/aio-whiteboard:20250701_092737
+ image: ghcr.io/nextcloud-releases/aio-whiteboard:20260122_105751
readinessProbe:
exec:
command:
diff --git a/nextcloud-aio-helm-chart/templates/nextcloud-aio-whiteboard-service.yaml b/nextcloud-aio-helm-chart/templates/nextcloud-aio-whiteboard-service.yaml
index 29232bee..299f1ec3 100755
--- a/nextcloud-aio-helm-chart/templates/nextcloud-aio-whiteboard-service.yaml
+++ b/nextcloud-aio-helm-chart/templates/nextcloud-aio-whiteboard-service.yaml
@@ -3,7 +3,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- kompose.version: 1.36.0 (ae2a39403)
+ kompose.version: 1.38.0 (a8f5d1cbd)
labels:
io.kompose.service: nextcloud-aio-whiteboard
name: nextcloud-aio-whiteboard
diff --git a/nextcloud-aio-helm-chart/update-helm.sh b/nextcloud-aio-helm-chart/update-helm.sh
index d3a84a9c..9e5aba86 100755
--- a/nextcloud-aio-helm-chart/update-helm.sh
+++ b/nextcloud-aio-helm-chart/update-helm.sh
@@ -27,7 +27,7 @@ cp latest.yml latest.yml.backup
# Additional config
# shellcheck disable=SC1083
-sed -i -E '/^( *- )(NET_RAW|SYS_NICE|MKNOD|SYS_ADMIN|CHOWN)$/!s/( *- )([A-Z_]+)$/\1\2=${\2}/' latest.yml
+sed -i -E '/^( *- )(NET_RAW|SYS_NICE|MKNOD|SYS_ADMIN|CHOWN|SYS_CHROOT|FOWNER|MAC_OVERRIDE|BLOCK_SUSPEND|AUDIT_READ)$/!s/( *- )([A-Z_]+)$/\1\2=${\2}/' latest.yml
cp sample.conf /tmp/
sed -i 's|^|export |' /tmp/sample.conf
# shellcheck disable=SC1091
@@ -252,7 +252,7 @@ find ./ -name '*talk-service.yaml' -exec grep -v '{{ .Values.TALK.*}}\|protocol:
# shellcheck disable=SC1083
find ./ -name '*talk-service.yaml' -exec mv /tmp/talk-service.copy \{} \;
# shellcheck disable=SC1083
-find ./ -name '*service.yaml' -exec sed -i "/type: LoadBalancer/a\ \ externalTrafficPolicy: Local" \{} \;
+find ./ -name '*apache-service.yaml' -exec sed -i "/type: LoadBalancer/a\ \ externalTrafficPolicy: Local" \{} \;
# shellcheck disable=SC1083
find ./ -name '*service.yaml' -exec sed -i "/^spec:/a\ \ ipFamilyPolicy: PreferDualStack" \{} \;
# shellcheck disable=SC1083
@@ -343,6 +343,21 @@ EOL
# shellcheck disable=SC1083
find ./ -name '*talk-deployment.yaml' -exec sed -i "/^.*\- env:/r /tmp/additional-talk.config" \{} \;
+# Additional collabora config
+# shellcheck disable=SC1083
+find ./ -name '*collabora-deployment.yaml' -exec sed -i "s/image: ghcr.io.*/IMAGE_PLACEHOLDER/" \{} \;
+cat << EOL > /tmp/additional-collabora.config
+ {{- if contains "--o:support_key=" (join " " (.Values.ADDITIONAL_COLLABORA_OPTIONS | default list)) }}
+ image: ghcr.io/nextcloud-releases/aio-collabora-online:$DOCKER_TAG
+ {{- else }}
+ image: ghcr.io/nextcloud-releases/aio-collabora:$DOCKER_TAG
+ {{- end }}
+EOL
+# shellcheck disable=SC1083
+find ./ -name '*collabora-deployment.yaml' -exec sed -i "/IMAGE_PLACEHOLDER/r /tmp/additional-collabora.config" \{} \;
+# shellcheck disable=SC1083
+find ./ -name '*collabora-deployment.yaml' -exec sed -i "/IMAGE_PLACEHOLDER/d" \{} \;
+
cat << EOL > templates/nextcloud-aio-networkpolicy.yaml
{{- if eq .Values.NETWORK_POLICY_ENABLED "yes" }}
# https://github.com/ahmetb/kubernetes-network-policy-recipes/blob/master/04-deny-traffic-from-other-namespaces.md
@@ -392,7 +407,7 @@ rm latest.yml
mv latest.yml.backup latest.yml
# Get version of AIO
-AIO_VERSION="$(grep 'Nextcloud AIO ' ../php/templates/containers.twig | grep -oP '[0-9]+.[0-9]+.[0-9]+')"
+AIO_VERSION="$(grep 'Nextcloud AIO ' ../php/templates/includes/aio-version.twig | grep -oP '[0-9]+.[0-9]+.[0-9]+')"
sed -i "s|^version:.*|version: $AIO_VERSION|" ../helm-chart/Chart.yaml
# Conversion of sample.conf
@@ -410,8 +425,8 @@ sed -i 's|17179869184|"17179869184"|' /tmp/sample.conf
# shellcheck disable=SC2129
echo "" >> /tmp/sample.conf
# shellcheck disable=SC2129
-echo 'STORAGE_CLASS: # By setting this, you can adjust the storage class for your volumes. This should be a fast storage like SSD backed storage!' >> /tmp/sample.conf
-echo 'STORAGE_CLASS_DATA: # Allows to set a dedicated storage class for the Nextcloud data volume. This can be a bit slower storage than the one above. ⚠️ Warning: only set this for new installations, not existing ones!' >> /tmp/sample.conf
+echo 'STORAGE_CLASS: # By setting this, you can adjust the storage class for your volumes. This should be a fast storage like SSD backed storage! This storage class must provide RWX and RWO volumes (ReadWriteMany and ReadWriteOnce).' >> /tmp/sample.conf
+echo 'STORAGE_CLASS_DATA: # Allows to set a dedicated storage class for the Nextcloud data volume. This can be a bit slower storage than the one above. This storage class must provide RWX volumes (ReadWriteMany). ⚠️ Warning: only set this for new installations, not existing ones!' >> /tmp/sample.conf
for variable in "${VOLUME_VARIABLE[@]}"; do
echo "$variable: 1Gi # You can change the size of the $(echo "$variable" | sed 's|_STORAGE_SIZE||;s|_|-|g' | tr '[:upper:]' '[:lower:]') volume that default to 1Gi with this value" >> /tmp/sample.conf
done
diff --git a/nextcloud-aio-helm-chart/values.yaml b/nextcloud-aio-helm-chart/values.yaml
index 10603a7c..25fb2c92 100755
--- a/nextcloud-aio-helm-chart/values.yaml
+++ b/nextcloud-aio-helm-chart/values.yaml
@@ -38,8 +38,8 @@ REMOVE_DISABLED_APPS: yes # Setting this to no keep Nextcloud apps that a
TALK_PORT: 3478 # This allows to adjust the port that the talk container is using. It should be set to something higher than 1024! Otherwise it might not work!
UPDATE_NEXTCLOUD_APPS: no # When setting to yes (with quotes), it will automatically update all installed Nextcloud apps upon container startup on saturdays.
-STORAGE_CLASS: # By setting this, you can adjust the storage class for your volumes. This should be a fast storage like SSD backed storage!
-STORAGE_CLASS_DATA: # Allows to set a dedicated storage class for the Nextcloud data volume. This can be a bit slower storage than the one above. ⚠️ Warning: only set this for new installations, not existing ones!
+STORAGE_CLASS: # By setting this, you can adjust the storage class for your volumes. This should be a fast storage like SSD backed storage! This storage class must provide RWX and RWO volumes (ReadWriteMany and ReadWriteOnce).
+STORAGE_CLASS_DATA: # Allows to set a dedicated storage class for the Nextcloud data volume. This can be a bit slower storage than the one above. This storage class must provide RWX volumes (ReadWriteMany). ⚠️ Warning: only set this for new installations, not existing ones!
APACHE_STORAGE_SIZE: 1Gi # You can change the size of the apache volume that default to 1Gi with this value
CLAMAV_STORAGE_SIZE: 1Gi # You can change the size of the clamav volume that default to 1Gi with this value
DATABASE_STORAGE_SIZE: 1Gi # You can change the size of the database volume that default to 1Gi with this value
diff --git a/php/composer.lock b/php/composer.lock
index 73b56a53..75e53dfe 100644
--- a/php/composer.lock
+++ b/php/composer.lock
@@ -8,22 +8,22 @@
"packages": [
{
"name": "guzzlehttp/guzzle",
- "version": "7.9.3",
+ "version": "7.10.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
+ "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
- "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
+ "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"shasum": ""
},
"require": {
"ext-json": "*",
- "guzzlehttp/promises": "^1.5.3 || ^2.0.3",
- "guzzlehttp/psr7": "^2.7.0",
+ "guzzlehttp/promises": "^2.3",
+ "guzzlehttp/psr7": "^2.8",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
@@ -114,7 +114,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
- "source": "https://github.com/guzzle/guzzle/tree/7.9.3"
+ "source": "https://github.com/guzzle/guzzle/tree/7.10.0"
},
"funding": [
{
@@ -130,20 +130,20 @@
"type": "tidelift"
}
],
- "time": "2025-03-27T13:37:11+00:00"
+ "time": "2025-08-23T22:36:01+00:00"
},
{
"name": "guzzlehttp/promises",
- "version": "2.2.0",
+ "version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
- "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
+ "reference": "481557b130ef3790cf82b713667b43030dc9c957"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
- "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
+ "reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": ""
},
"require": {
@@ -151,7 +151,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
- "phpunit/phpunit": "^8.5.39 || ^9.6.20"
+ "phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"type": "library",
"extra": {
@@ -197,7 +197,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
- "source": "https://github.com/guzzle/promises/tree/2.2.0"
+ "source": "https://github.com/guzzle/promises/tree/2.3.0"
},
"funding": [
{
@@ -213,20 +213,20 @@
"type": "tidelift"
}
],
- "time": "2025-03-27T13:27:01+00:00"
+ "time": "2025-08-22T14:34:08+00:00"
},
{
"name": "guzzlehttp/psr7",
- "version": "2.7.1",
+ "version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
+ "reference": "21dc724a0583619cd1652f673303492272778051"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
- "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
+ "reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": ""
},
"require": {
@@ -242,7 +242,7 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0",
- "phpunit/phpunit": "^8.5.39 || ^9.6.20"
+ "phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@@ -313,7 +313,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
- "source": "https://github.com/guzzle/psr7/tree/2.7.1"
+ "source": "https://github.com/guzzle/psr7/tree/2.8.0"
},
"funding": [
{
@@ -329,20 +329,20 @@
"type": "tidelift"
}
],
- "time": "2025-03-27T12:30:47+00:00"
+ "time": "2025-08-23T21:21:41+00:00"
},
{
"name": "http-interop/http-factory-guzzle",
- "version": "1.2.0",
+ "version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/http-interop/http-factory-guzzle.git",
- "reference": "8f06e92b95405216b237521cc64c804dd44c4a81"
+ "reference": "c2c859ceb05c3f42e710b60555f4c35b6a4a3995"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/http-interop/http-factory-guzzle/zipball/8f06e92b95405216b237521cc64c804dd44c4a81",
- "reference": "8f06e92b95405216b237521cc64c804dd44c4a81",
+ "url": "https://api.github.com/repos/http-interop/http-factory-guzzle/zipball/c2c859ceb05c3f42e710b60555f4c35b6a4a3995",
+ "reference": "c2c859ceb05c3f42e710b60555f4c35b6a4a3995",
"shasum": ""
},
"require": {
@@ -385,22 +385,22 @@
],
"support": {
"issues": "https://github.com/http-interop/http-factory-guzzle/issues",
- "source": "https://github.com/http-interop/http-factory-guzzle/tree/1.2.0"
+ "source": "https://github.com/http-interop/http-factory-guzzle/tree/1.2.1"
},
- "time": "2021-07-21T13:50:14+00:00"
+ "time": "2025-12-15T11:28:16+00:00"
},
{
"name": "laravel/serializable-closure",
- "version": "v2.0.4",
+ "version": "v2.0.8",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
- "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841"
+ "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841",
- "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841",
+ "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/7581a4407012f5f53365e11bafc520fd7f36bc9b",
+ "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b",
"shasum": ""
},
"require": {
@@ -409,7 +409,7 @@
"require-dev": {
"illuminate/support": "^10.0|^11.0|^12.0",
"nesbot/carbon": "^2.67|^3.0",
- "pestphp/pest": "^2.36|^3.0",
+ "pestphp/pest": "^2.36|^3.0|^4.0",
"phpstan/phpstan": "^2.0",
"symfony/var-dumper": "^6.2.0|^7.0.0"
},
@@ -448,7 +448,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
- "time": "2025-03-19T13:51:03+00:00"
+ "time": "2026-01-08T16:22:46+00:00"
},
{
"name": "nikic/fast-route",
@@ -502,16 +502,16 @@
},
{
"name": "php-di/invoker",
- "version": "2.3.6",
+ "version": "2.3.7",
"source": {
"type": "git",
"url": "https://github.com/PHP-DI/Invoker.git",
- "reference": "59f15608528d8a8838d69b422a919fd6b16aa576"
+ "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/59f15608528d8a8838d69b422a919fd6b16aa576",
- "reference": "59f15608528d8a8838d69b422a919fd6b16aa576",
+ "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/3c1ddfdef181431fbc4be83378f6d036d59e81e1",
+ "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1",
"shasum": ""
},
"require": {
@@ -521,7 +521,7 @@
"require-dev": {
"athletic/athletic": "~0.1.8",
"mnapoli/hard-mode": "~0.3.0",
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^9.0 || ^10 || ^11 || ^12"
},
"type": "library",
"autoload": {
@@ -545,7 +545,7 @@
],
"support": {
"issues": "https://github.com/PHP-DI/Invoker/issues",
- "source": "https://github.com/PHP-DI/Invoker/tree/2.3.6"
+ "source": "https://github.com/PHP-DI/Invoker/tree/2.3.7"
},
"funding": [
{
@@ -553,20 +553,20 @@
"type": "github"
}
],
- "time": "2025-01-17T12:49:27+00:00"
+ "time": "2025-08-30T10:22:22+00:00"
},
{
"name": "php-di/php-di",
- "version": "7.0.11",
+ "version": "7.1.1",
"source": {
"type": "git",
"url": "https://github.com/PHP-DI/PHP-DI.git",
- "reference": "32f111a6d214564520a57831d397263e8946c1d2"
+ "reference": "f88054cc052e40dbe7b383c8817c19442d480352"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/32f111a6d214564520a57831d397263e8946c1d2",
- "reference": "32f111a6d214564520a57831d397263e8946c1d2",
+ "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/f88054cc052e40dbe7b383c8817c19442d480352",
+ "reference": "f88054cc052e40dbe7b383c8817c19442d480352",
"shasum": ""
},
"require": {
@@ -614,7 +614,7 @@
],
"support": {
"issues": "https://github.com/PHP-DI/PHP-DI/issues",
- "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.11"
+ "source": "https://github.com/PHP-DI/PHP-DI/tree/7.1.1"
},
"funding": [
{
@@ -626,7 +626,7 @@
"type": "tidelift"
}
],
- "time": "2025-06-03T07:45:57+00:00"
+ "time": "2025-08-16T11:10:48+00:00"
},
{
"name": "php-di/slim-bridge",
@@ -1092,16 +1092,16 @@
},
{
"name": "slim/csrf",
- "version": "1.5.0",
+ "version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim-Csrf.git",
- "reference": "179cbcf40ee1d246d4906aefed42d3e62066974b"
+ "reference": "a476a61e38451e138c400f6b4ca96037f3c2dd39"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/slimphp/Slim-Csrf/zipball/179cbcf40ee1d246d4906aefed42d3e62066974b",
- "reference": "179cbcf40ee1d246d4906aefed42d3e62066974b",
+ "url": "https://api.github.com/repos/slimphp/Slim-Csrf/zipball/a476a61e38451e138c400f6b4ca96037f3c2dd39",
+ "reference": "a476a61e38451e138c400f6b4ca96037f3c2dd39",
"shasum": ""
},
"require": {
@@ -1112,8 +1112,6 @@
"psr/http-server-middleware": "^1.0"
},
"require-dev": {
- "phpspec/prophecy": "^1.19",
- "phpspec/prophecy-phpunit": "^2.2",
"phpunit/phpunit": "^9.6",
"squizlabs/php_codesniffer": "^3.10"
},
@@ -1144,28 +1142,28 @@
],
"support": {
"issues": "https://github.com/slimphp/Slim-Csrf/issues",
- "source": "https://github.com/slimphp/Slim-Csrf/tree/1.5.0"
+ "source": "https://github.com/slimphp/Slim-Csrf/tree/1.5.1"
},
- "time": "2024-06-08T16:37:18+00:00"
+ "time": "2025-11-02T14:58:28+00:00"
},
{
"name": "slim/slim",
- "version": "4.14.0",
+ "version": "4.15.1",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
- "reference": "5943393b88716eb9e82c4161caa956af63423913"
+ "reference": "887893516557506f254d950425ce7f5387a26970"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/slimphp/Slim/zipball/5943393b88716eb9e82c4161caa956af63423913",
- "reference": "5943393b88716eb9e82c4161caa956af63423913",
+ "url": "https://api.github.com/repos/slimphp/Slim/zipball/887893516557506f254d950425ce7f5387a26970",
+ "reference": "887893516557506f254d950425ce7f5387a26970",
"shasum": ""
},
"require": {
"ext-json": "*",
"nikic/fast-route": "^1.3",
- "php": "^7.4 || ^8.0",
+ "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"psr/container": "^1.0 || ^2.0",
"psr/http-factory": "^1.1",
"psr/http-message": "^1.1 || ^2.0",
@@ -1174,7 +1172,7 @@
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"require-dev": {
- "adriansuter/php-autoload-override": "^1.4",
+ "adriansuter/php-autoload-override": "^1.4 || ^2",
"ext-simplexml": "*",
"guzzlehttp/psr7": "^2.6",
"httpsoft/http-message": "^1.1",
@@ -1184,12 +1182,12 @@
"nyholm/psr7-server": "^1.1",
"phpspec/prophecy": "^1.19",
"phpspec/prophecy-phpunit": "^2.1",
- "phpstan/phpstan": "^1.11",
- "phpunit/phpunit": "^9.6",
+ "phpstan/phpstan": "^1 || ^2",
+ "phpunit/phpunit": "^9.6 || ^10 || ^11 || ^12",
"slim/http": "^1.3",
"slim/psr7": "^1.6",
"squizlabs/php_codesniffer": "^3.10",
- "vimeo/psalm": "^5.24"
+ "vimeo/psalm": "^5 || ^6"
},
"suggest": {
"ext-simplexml": "Needed to support XML format in BodyParsingMiddleware",
@@ -1216,17 +1214,17 @@
{
"name": "Andrew Smith",
"email": "a.smith@silentworks.co.uk",
- "homepage": "http://silentworks.co.uk"
+ "homepage": "https://silentworks.co.uk"
},
{
"name": "Rob Allen",
"email": "rob@akrabat.com",
- "homepage": "http://akrabat.com"
+ "homepage": "https://akrabat.com"
},
{
"name": "Pierre Berube",
"email": "pierre@lgse.com",
- "homepage": "http://www.lgse.com"
+ "homepage": "https://www.lgse.com"
},
{
"name": "Gabriel Manricks",
@@ -1262,7 +1260,7 @@
"type": "tidelift"
}
],
- "time": "2024-06-13T08:54:48+00:00"
+ "time": "2025-11-21T12:23:44+00:00"
},
{
"name": "slim/twig-view",
@@ -1398,7 +1396,7 @@
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
@@ -1457,7 +1455,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
},
"funding": [
{
@@ -1468,6 +1466,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -1477,7 +1479,7 @@
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
@@ -1538,7 +1540,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
@@ -1549,6 +1551,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -1558,7 +1564,7 @@
},
{
"name": "symfony/polyfill-php81",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
@@ -1614,7 +1620,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0"
},
"funding": [
{
@@ -1625,6 +1631,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -1634,16 +1644,16 @@
},
{
"name": "twig/twig",
- "version": "v3.21.1",
+ "version": "v3.22.2",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
- "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d"
+ "reference": "946ddeafa3c9f4ce279d1f34051af041db0e16f2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d",
- "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/946ddeafa3c9f4ce279d1f34051af041db0e16f2",
+ "reference": "946ddeafa3c9f4ce279d1f34051af041db0e16f2",
"shasum": ""
},
"require": {
@@ -1697,7 +1707,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
- "source": "https://github.com/twigphp/Twig/tree/v3.21.1"
+ "source": "https://github.com/twigphp/Twig/tree/v3.22.2"
},
"funding": [
{
@@ -1709,22 +1719,22 @@
"type": "tidelift"
}
],
- "time": "2025-05-03T07:21:55+00:00"
+ "time": "2025-12-14T11:28:47+00:00"
}
],
"packages-dev": [
{
"name": "amphp/amp",
- "version": "v3.1.0",
+ "version": "v3.1.1",
"source": {
"type": "git",
"url": "https://github.com/amphp/amp.git",
- "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9"
+ "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/amp/zipball/7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9",
- "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9",
+ "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f",
+ "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f",
"shasum": ""
},
"require": {
@@ -1784,7 +1794,7 @@
],
"support": {
"issues": "https://github.com/amphp/amp/issues",
- "source": "https://github.com/amphp/amp/tree/v3.1.0"
+ "source": "https://github.com/amphp/amp/tree/v3.1.1"
},
"funding": [
{
@@ -1792,7 +1802,7 @@
"type": "github"
}
],
- "time": "2025-01-26T16:07:39+00:00"
+ "time": "2025-08-27T21:42:00+00:00"
},
{
"name": "amphp/byte-stream",
@@ -2025,16 +2035,16 @@
},
{
"name": "amphp/parallel",
- "version": "v2.3.1",
+ "version": "v2.3.3",
"source": {
"type": "git",
"url": "https://github.com/amphp/parallel.git",
- "reference": "5113111de02796a782f5d90767455e7391cca190"
+ "reference": "296b521137a54d3a02425b464e5aee4c93db2c60"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/parallel/zipball/5113111de02796a782f5d90767455e7391cca190",
- "reference": "5113111de02796a782f5d90767455e7391cca190",
+ "url": "https://api.github.com/repos/amphp/parallel/zipball/296b521137a54d3a02425b464e5aee4c93db2c60",
+ "reference": "296b521137a54d3a02425b464e5aee4c93db2c60",
"shasum": ""
},
"require": {
@@ -2097,7 +2107,7 @@
],
"support": {
"issues": "https://github.com/amphp/parallel/issues",
- "source": "https://github.com/amphp/parallel/tree/v2.3.1"
+ "source": "https://github.com/amphp/parallel/tree/v2.3.3"
},
"funding": [
{
@@ -2105,7 +2115,7 @@
"type": "github"
}
],
- "time": "2024-12-21T01:56:09+00:00"
+ "time": "2025-11-15T06:23:42+00:00"
},
{
"name": "amphp/parser",
@@ -2602,16 +2612,16 @@
},
{
"name": "composer/semver",
- "version": "3.4.3",
+ "version": "3.4.4",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
- "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12"
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
- "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
+ "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
"shasum": ""
},
"require": {
@@ -2663,7 +2673,7 @@
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
- "source": "https://github.com/composer/semver/tree/3.4.3"
+ "source": "https://github.com/composer/semver/tree/3.4.4"
},
"funding": [
{
@@ -2673,13 +2683,9 @@
{
"url": "https://github.com/composer",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
}
],
- "time": "2024-09-19T14:15:21+00:00"
+ "time": "2025-08-20T19:15:30+00:00"
},
{
"name": "composer/xdebug-handler",
@@ -2749,22 +2755,22 @@
},
{
"name": "danog/advanced-json-rpc",
- "version": "v3.2.2",
+ "version": "v3.2.3",
"source": {
"type": "git",
"url": "https://github.com/danog/php-advanced-json-rpc.git",
- "reference": "aadb1c4068a88c3d0530cfe324b067920661efcb"
+ "reference": "ae703ea7b4811797a10590b6078de05b3b33dd91"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/danog/php-advanced-json-rpc/zipball/aadb1c4068a88c3d0530cfe324b067920661efcb",
- "reference": "aadb1c4068a88c3d0530cfe324b067920661efcb",
+ "url": "https://api.github.com/repos/danog/php-advanced-json-rpc/zipball/ae703ea7b4811797a10590b6078de05b3b33dd91",
+ "reference": "ae703ea7b4811797a10590b6078de05b3b33dd91",
"shasum": ""
},
"require": {
"netresearch/jsonmapper": "^5",
"php": ">=8.1",
- "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0"
+ "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0 || ^6"
},
"replace": {
"felixfbecker/php-advanced-json-rpc": "^3"
@@ -2795,9 +2801,9 @@
"description": "A more advanced JSONRPC implementation",
"support": {
"issues": "https://github.com/danog/php-advanced-json-rpc/issues",
- "source": "https://github.com/danog/php-advanced-json-rpc/tree/v3.2.2"
+ "source": "https://github.com/danog/php-advanced-json-rpc/tree/v3.2.3"
},
- "time": "2025-02-14T10:55:15+00:00"
+ "time": "2026-01-12T21:07:10+00:00"
},
{
"name": "daverandom/libdns",
@@ -2986,16 +2992,16 @@
},
{
"name": "fidry/cpu-core-counter",
- "version": "1.2.0",
+ "version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/theofidry/cpu-core-counter.git",
- "reference": "8520451a140d3f46ac33042715115e290cf5785f"
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f",
- "reference": "8520451a140d3f46ac33042715115e290cf5785f",
+ "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678",
"shasum": ""
},
"require": {
@@ -3005,10 +3011,10 @@
"fidry/makefile": "^0.2.0",
"fidry/php-cs-fixer-config": "^1.1.2",
"phpstan/extension-installer": "^1.2.0",
- "phpstan/phpstan": "^1.9.2",
- "phpstan/phpstan-deprecation-rules": "^1.0.0",
- "phpstan/phpstan-phpunit": "^1.2.2",
- "phpstan/phpstan-strict-rules": "^1.4.4",
+ "phpstan/phpstan": "^2.0",
+ "phpstan/phpstan-deprecation-rules": "^2.0.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^8.5.31 || ^9.5.26",
"webmozarts/strict-phpunit": "^7.5"
},
@@ -3035,7 +3041,7 @@
],
"support": {
"issues": "https://github.com/theofidry/cpu-core-counter/issues",
- "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0"
+ "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0"
},
"funding": [
{
@@ -3043,7 +3049,7 @@
"type": "github"
}
],
- "time": "2024-08-06T10:04:20+00:00"
+ "time": "2025-08-14T07:29:31+00:00"
},
{
"name": "kelunik/certificate",
@@ -3105,33 +3111,38 @@
},
{
"name": "league/uri",
- "version": "7.5.1",
+ "version": "7.8.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri.git",
- "reference": "81fb5145d2644324614cc532b28efd0215bda430"
+ "reference": "4436c6ec8d458e4244448b069cc572d088230b76"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430",
- "reference": "81fb5145d2644324614cc532b28efd0215bda430",
+ "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76",
+ "reference": "4436c6ec8d458e4244448b069cc572d088230b76",
"shasum": ""
},
"require": {
- "league/uri-interfaces": "^7.5",
- "php": "^8.1"
+ "league/uri-interfaces": "^7.8",
+ "php": "^8.1",
+ "psr/http-factory": "^1"
},
"conflict": {
"league/uri-schemes": "^1.0"
},
"suggest": {
"ext-bcmath": "to improve IPV4 host parsing",
+ "ext-dom": "to convert the URI into an HTML anchor tag",
"ext-fileinfo": "to create Data URI from file contennts",
"ext-gmp": "to improve IPV4 host parsing",
"ext-intl": "to handle IDN host with the best performance",
- "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain",
- "league/uri-components": "Needed to easily manipulate URI objects components",
+ "ext-uri": "to use the PHP native URI class",
+ "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain",
+ "league/uri-components": "to provide additional tools to manipulate URI objects components",
+ "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP",
"php-64bit": "to improve IPV4 host parsing",
+ "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification",
"symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
},
"type": "library",
@@ -3159,6 +3170,7 @@
"description": "URI manipulation library",
"homepage": "https://uri.thephpleague.com",
"keywords": [
+ "URN",
"data-uri",
"file-uri",
"ftp",
@@ -3171,9 +3183,11 @@
"psr-7",
"query-string",
"querystring",
+ "rfc2141",
"rfc3986",
"rfc3987",
"rfc6570",
+ "rfc8141",
"uri",
"uri-template",
"url",
@@ -3183,7 +3197,7 @@
"docs": "https://uri.thephpleague.com",
"forum": "https://thephpleague.slack.com",
"issues": "https://github.com/thephpleague/uri-src/issues",
- "source": "https://github.com/thephpleague/uri/tree/7.5.1"
+ "source": "https://github.com/thephpleague/uri/tree/7.8.0"
},
"funding": [
{
@@ -3191,26 +3205,25 @@
"type": "github"
}
],
- "time": "2024-12-08T08:40:02+00:00"
+ "time": "2026-01-14T17:24:56+00:00"
},
{
"name": "league/uri-interfaces",
- "version": "7.5.0",
+ "version": "7.8.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri-interfaces.git",
- "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742"
+ "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742",
- "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742",
+ "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4",
+ "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4",
"shasum": ""
},
"require": {
"ext-filter": "*",
"php": "^8.1",
- "psr/http-factory": "^1",
"psr/http-message": "^1.1 || ^2.0"
},
"suggest": {
@@ -3218,6 +3231,7 @@
"ext-gmp": "to improve IPV4 host parsing",
"ext-intl": "to handle IDN host with the best performance",
"php-64bit": "to improve IPV4 host parsing",
+ "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification",
"symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
},
"type": "library",
@@ -3242,7 +3256,7 @@
"homepage": "https://nyamsprod.com"
}
],
- "description": "Common interfaces and classes for URI representation and interaction",
+ "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI",
"homepage": "https://uri.thephpleague.com",
"keywords": [
"data-uri",
@@ -3267,7 +3281,7 @@
"docs": "https://uri.thephpleague.com",
"forum": "https://thephpleague.slack.com",
"issues": "https://github.com/thephpleague/uri-src/issues",
- "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0"
+ "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0"
},
"funding": [
{
@@ -3275,7 +3289,7 @@
"type": "github"
}
],
- "time": "2024-12-08T08:18:47+00:00"
+ "time": "2026-01-15T06:54:53+00:00"
},
{
"name": "netresearch/jsonmapper",
@@ -3330,16 +3344,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v5.5.0",
+ "version": "v5.7.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
- "reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"shasum": ""
},
"require": {
@@ -3358,7 +3372,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.x-dev"
}
},
"autoload": {
@@ -3382,9 +3396,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
},
- "time": "2025-05-31T08:24:38+00:00"
+ "time": "2025-12-06T11:56:16+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@@ -3441,16 +3455,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
- "version": "5.6.2",
+ "version": "6.0.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62"
+ "reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62",
- "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2f5cbed597cb261d1ea458f3da3a9ad32e670b1e",
+ "reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e",
"shasum": ""
},
"require": {
@@ -3458,9 +3472,9 @@
"ext-filter": "*",
"php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.2",
- "phpdocumentor/type-resolver": "^1.7",
- "phpstan/phpdoc-parser": "^1.7|^2.0",
- "webmozart/assert": "^1.9.1"
+ "phpdocumentor/type-resolver": "^2.0",
+ "phpstan/phpdoc-parser": "^2.0",
+ "webmozart/assert": "^1.9.1 || ^2"
},
"require-dev": {
"mockery/mockery": "~1.3.5 || ~1.6.0",
@@ -3469,7 +3483,8 @@
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-webmozart-assert": "^1.2",
"phpunit/phpunit": "^9.5",
- "psalm/phar": "^5.26"
+ "psalm/phar": "^5.26",
+ "shipmonk/dead-code-detector": "^0.5.1"
},
"type": "library",
"extra": {
@@ -3499,44 +3514,44 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
- "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2"
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.1"
},
- "time": "2025-04-13T19:20:35+00:00"
+ "time": "2026-01-20T15:30:42+00:00"
},
{
"name": "phpdocumentor/type-resolver",
- "version": "1.10.0",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
+ "reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/327a05bbee54120d4786a0dc67aad30226ad4cf9",
+ "reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.0",
- "php": "^7.3 || ^8.0",
+ "php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.0",
- "phpstan/phpdoc-parser": "^1.18|^2.0"
+ "phpstan/phpdoc-parser": "^2.0"
},
"require-dev": {
"ext-tokenizer": "*",
"phpbench/phpbench": "^1.2",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.8",
- "phpstan/phpstan-phpunit": "^1.1",
+ "phpstan/extension-installer": "^1.4",
+ "phpstan/phpstan": "^2.1",
+ "phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
- "rector/rector": "^0.13.9",
- "vimeo/psalm": "^4.25"
+ "psalm/phar": "^4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-1.x": "1.x-dev",
+ "dev-2.x": "2.x-dev"
}
},
"autoload": {
@@ -3557,22 +3572,22 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/2.0.0"
},
- "time": "2024-11-09T15:12:26+00:00"
+ "time": "2026-01-06T21:53:42+00:00"
},
{
"name": "phpstan/phpdoc-parser",
- "version": "2.1.0",
+ "version": "2.3.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68"
+ "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
- "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/16dbf9937da8d4528ceb2145c9c7c0bd29e26374",
+ "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374",
"shasum": ""
},
"require": {
@@ -3604,22 +3619,22 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/2.1.0"
+ "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.1"
},
- "time": "2025-02-19T13:28:12+00:00"
+ "time": "2026-01-12T11:33:04+00:00"
},
{
"name": "revolt/event-loop",
- "version": "v1.0.7",
+ "version": "v1.0.8",
"source": {
"type": "git",
"url": "https://github.com/revoltphp/event-loop.git",
- "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3"
+ "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3",
- "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3",
+ "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/b6fc06dce8e9b523c9946138fa5e62181934f91c",
+ "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c",
"shasum": ""
},
"require": {
@@ -3676,9 +3691,9 @@
],
"support": {
"issues": "https://github.com/revoltphp/event-loop/issues",
- "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7"
+ "source": "https://github.com/revoltphp/event-loop/tree/v1.0.8"
},
- "time": "2025-01-25T19:27:39+00:00"
+ "time": "2025-08-27T21:33:23+00:00"
},
{
"name": "sebastian/diff",
@@ -3749,16 +3764,16 @@
},
{
"name": "spatie/array-to-xml",
- "version": "3.4.0",
+ "version": "3.4.4",
"source": {
"type": "git",
"url": "https://github.com/spatie/array-to-xml.git",
- "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67"
+ "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67",
- "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67",
+ "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/88b2f3852a922dd73177a68938f8eb2ec70c7224",
+ "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224",
"shasum": ""
},
"require": {
@@ -3801,7 +3816,7 @@
"xml"
],
"support": {
- "source": "https://github.com/spatie/array-to-xml/tree/3.4.0"
+ "source": "https://github.com/spatie/array-to-xml/tree/3.4.4"
},
"funding": [
{
@@ -3813,7 +3828,7 @@
"type": "github"
}
],
- "time": "2024-12-16T12:45:15+00:00"
+ "time": "2025-12-15T09:00:41+00:00"
},
{
"name": "sserbin/twig-linter",
@@ -3875,16 +3890,16 @@
},
{
"name": "symfony/console",
- "version": "v6.4.23",
+ "version": "v6.4.31",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "9056771b8eca08d026cd3280deeec3cfd99c4d93"
+ "reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/9056771b8eca08d026cd3280deeec3cfd99c4d93",
- "reference": "9056771b8eca08d026cd3280deeec3cfd99c4d93",
+ "url": "https://api.github.com/repos/symfony/console/zipball/f9f8a889f54c264f9abac3fc0f7a371ffca51997",
+ "reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997",
"shasum": ""
},
"require": {
@@ -3949,7 +3964,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v6.4.23"
+ "source": "https://github.com/symfony/console/tree/v6.4.31"
},
"funding": [
{
@@ -3960,34 +3975,38 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-06-27T19:37:22+00:00"
+ "time": "2025-12-22T08:30:34+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v7.3.0",
+ "version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb"
+ "reference": "d937d400b980523dc9ee946bb69972b5e619058d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
- "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d",
+ "reference": "d937d400b980523dc9ee946bb69972b5e619058d",
"shasum": ""
},
"require": {
- "php": ">=8.2",
+ "php": ">=8.4",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8"
},
"require-dev": {
- "symfony/process": "^6.4|^7.0"
+ "symfony/process": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -4015,7 +4034,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v7.3.0"
+ "source": "https://github.com/symfony/filesystem/tree/v8.0.1"
},
"funding": [
{
@@ -4026,25 +4045,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-10-25T15:15:23+00:00"
+ "time": "2025-12-01T09:13:36+00:00"
},
{
"name": "symfony/finder",
- "version": "v6.4.17",
+ "version": "v6.4.31",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7"
+ "reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7",
- "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/5547f2e1f0ca8e2e7abe490156b62da778cfbe2b",
+ "reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b",
"shasum": ""
},
"require": {
@@ -4079,7 +4102,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v6.4.17"
+ "source": "https://github.com/symfony/finder/tree/v6.4.31"
},
"funding": [
{
@@ -4090,25 +4113,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-12-29T13:51:37+00:00"
+ "time": "2025-12-11T14:52:17+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
"shasum": ""
},
"require": {
@@ -4157,7 +4184,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
},
"funding": [
{
@@ -4168,16 +4195,20 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2025-06-27T09:58:17+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@@ -4238,7 +4269,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
},
"funding": [
{
@@ -4249,6 +4280,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -4258,16 +4293,16 @@
},
{
"name": "symfony/polyfill-php84",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php84.git",
- "reference": "000df7860439609837bbe28670b0be15783b7fbf"
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/000df7860439609837bbe28670b0be15783b7fbf",
- "reference": "000df7860439609837bbe28670b0be15783b7fbf",
+ "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191",
"shasum": ""
},
"require": {
@@ -4314,7 +4349,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php84/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0"
},
"funding": [
{
@@ -4325,25 +4360,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-02-20T12:04:08+00:00"
+ "time": "2025-06-24T13:30:11+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.6.0",
+ "version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
"shasum": ""
},
"require": {
@@ -4397,7 +4436,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
},
"funding": [
{
@@ -4408,31 +4447,36 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-25T09:37:31+00:00"
+ "time": "2025-07-15T11:30:57+00:00"
},
{
"name": "symfony/string",
- "version": "v7.3.0",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125"
+ "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125",
- "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125",
+ "url": "https://api.github.com/repos/symfony/string/zipball/d50e862cb0a0e0886f73ca1f31b865efbb795003",
+ "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003",
"shasum": ""
},
"require": {
"php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3.0",
"symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-intl-grapheme": "~1.0",
+ "symfony/polyfill-intl-grapheme": "~1.33",
"symfony/polyfill-intl-normalizer": "~1.0",
"symfony/polyfill-mbstring": "~1.0"
},
@@ -4440,12 +4484,11 @@
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/emoji": "^7.1",
- "symfony/error-handler": "^6.4|^7.0",
- "symfony/http-client": "^6.4|^7.0",
- "symfony/intl": "^6.4|^7.0",
+ "symfony/emoji": "^7.1|^8.0",
+ "symfony/http-client": "^6.4|^7.0|^8.0",
+ "symfony/intl": "^6.4|^7.0|^8.0",
"symfony/translation-contracts": "^2.5|^3.0",
- "symfony/var-exporter": "^6.4|^7.0"
+ "symfony/var-exporter": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -4484,7 +4527,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.3.0"
+ "source": "https://github.com/symfony/string/tree/v7.4.0"
},
"funding": [
{
@@ -4495,25 +4538,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-20T20:19:01+00:00"
+ "time": "2025-11-27T13:27:24+00:00"
},
{
"name": "vimeo/psalm",
- "version": "6.12.0",
+ "version": "6.14.3",
"source": {
"type": "git",
"url": "https://github.com/vimeo/psalm.git",
- "reference": "cf420941d061a57050b6c468ef2c778faf40aee2"
+ "reference": "d0b040a91f280f071c1abcb1b77ce3822058725a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/vimeo/psalm/zipball/cf420941d061a57050b6c468ef2c778faf40aee2",
- "reference": "cf420941d061a57050b6c468ef2c778faf40aee2",
+ "url": "https://api.github.com/repos/vimeo/psalm/zipball/d0b040a91f280f071c1abcb1b77ce3822058725a",
+ "reference": "d0b040a91f280f071c1abcb1b77ce3822058725a",
"shasum": ""
},
"require": {
@@ -4536,11 +4583,11 @@
"fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0",
"netresearch/jsonmapper": "^5.0",
"nikic/php-parser": "^5.0.0",
- "php": "~8.1.31 || ~8.2.27 || ~8.3.16 || ~8.4.3",
+ "php": "~8.1.31 || ~8.2.27 || ~8.3.16 || ~8.4.3 || ~8.5.0",
"sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0",
"spatie/array-to-xml": "^2.17.0 || ^3.0",
- "symfony/console": "^6.0 || ^7.0",
- "symfony/filesystem": "~6.3.12 || ~6.4.3 || ^7.0.3",
+ "symfony/console": "^6.0 || ^7.0 || ^8.0",
+ "symfony/filesystem": "~6.3.12 || ~6.4.3 || ^7.0.3 || ^8.0",
"symfony/polyfill-php84": "^1.31.0"
},
"provide": {
@@ -4562,7 +4609,7 @@
"psalm/plugin-phpunit": "^0.19",
"slevomat/coding-standard": "^8.4",
"squizlabs/php_codesniffer": "^3.6",
- "symfony/process": "^6.0 || ^7.0"
+ "symfony/process": "^6.0 || ^7.0 || ^8.0"
},
"suggest": {
"ext-curl": "In order to send data to shepherd",
@@ -4618,7 +4665,7 @@
"issues": "https://github.com/vimeo/psalm/issues",
"source": "https://github.com/vimeo/psalm"
},
- "time": "2025-05-28T12:52:06+00:00"
+ "time": "2025-12-23T15:36:48+00:00"
},
{
"name": "wapmorgan/php-deprecation-detector",
@@ -4689,33 +4736,33 @@
},
{
"name": "webmozart/assert",
- "version": "1.11.0",
+ "version": "2.1.2",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
- "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
+ "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
- "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
+ "url": "https://api.github.com/repos/webmozarts/assert/zipball/ce6a2f100c404b2d32a1dd1270f9b59ad4f57649",
+ "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649",
"shasum": ""
},
"require": {
"ext-ctype": "*",
- "php": "^7.2 || ^8.0"
+ "ext-date": "*",
+ "ext-filter": "*",
+ "php": "^8.2"
},
- "conflict": {
- "phpstan/phpstan": "<0.12.20",
- "vimeo/psalm": "<4.6.1 || 4.6.2"
- },
- "require-dev": {
- "phpunit/phpunit": "^8.5.13"
+ "suggest": {
+ "ext-intl": "",
+ "ext-simplexml": "",
+ "ext-spl": ""
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.10-dev"
+ "dev-feature/2-0": "2.0-dev"
}
},
"autoload": {
@@ -4731,6 +4778,10 @@
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
+ },
+ {
+ "name": "Woody Gilk",
+ "email": "woody.gilk@gmail.com"
}
],
"description": "Assertions to validate method input/output with nice error messages.",
@@ -4741,9 +4792,9 @@
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
- "source": "https://github.com/webmozarts/assert/tree/1.11.0"
+ "source": "https://github.com/webmozarts/assert/tree/2.1.2"
},
- "time": "2022-06-03T18:03:27+00:00"
+ "time": "2026-01-13T14:02:24+00:00"
}
],
"aliases": [],
@@ -4762,5 +4813,5 @@
"ext-apcu": "*"
},
"platform-dev": {},
- "plugin-api-version": "2.6.0"
+ "plugin-api-version": "2.9.0"
}
diff --git a/php/containers-schema.json b/php/containers-schema.json
index cd746ebf..5ed57e34 100644
--- a/php/containers-schema.json
+++ b/php/containers-schema.json
@@ -81,7 +81,7 @@
"properties": {
"ip_binding": {
"type": "string",
- "pattern": "^(%[A-Z_]+%)?$"
+ "pattern": "^((%[A-Z_]+%)|127\\.0\\.0\\.1)?$"
},
"port_number": {
"type": "string",
diff --git a/php/containers.json b/php/containers.json
index 38fdb09a..8c507f91 100644
--- a/php/containers.json
+++ b/php/containers.json
@@ -8,9 +8,9 @@
"nextcloud-aio-onlyoffice",
"nextcloud-aio-collabora",
"nextcloud-aio-talk",
- "nextcloud-aio-nextcloud",
"nextcloud-aio-notify-push",
- "nextcloud-aio-whiteboard"
+ "nextcloud-aio-whiteboard",
+ "nextcloud-aio-nextcloud"
],
"display_name": "Apache",
"image": "ghcr.io/nextcloud-releases/aio-apache",
@@ -204,6 +204,7 @@
"POSTGRES_DB=nextcloud_database",
"POSTGRES_USER=nextcloud",
"REDIS_HOST=nextcloud-aio-redis",
+ "REDIS_PORT=6379",
"REDIS_HOST_PASSWORD=%REDIS_PASSWORD%",
"APACHE_HOST=nextcloud-aio-apache",
"APACHE_PORT=%APACHE_PORT%",
@@ -229,13 +230,17 @@
"UPDATE_NEXTCLOUD_APPS=%UPDATE_NEXTCLOUD_APPS%",
"TZ=%TIMEZONE%",
"TALK_PORT=%TALK_PORT%",
+ "TURN_DOMAIN=%TURN_DOMAIN%",
"IMAGINARY_ENABLED=%IMAGINARY_ENABLED%",
"IMAGINARY_HOST=nextcloud-aio-imaginary",
- "CLAMAV_MAX_SIZE=%APACHE_MAX_SIZE%",
"PHP_UPLOAD_LIMIT=%NEXTCLOUD_UPLOAD_LIMIT%",
"PHP_MEMORY_LIMIT=%NEXTCLOUD_MEMORY_LIMIT%",
"FULLTEXTSEARCH_ENABLED=%FULLTEXTSEARCH_ENABLED%",
"FULLTEXTSEARCH_HOST=nextcloud-aio-fulltextsearch",
+ "FULLTEXTSEARCH_PROTOCOL=http",
+ "FULLTEXTSEARCH_PORT=9200",
+ "FULLTEXTSEARCH_USER=elastic",
+ "FULLTEXTSEARCH_INDEX=nextcloud-aio",
"PHP_MAX_TIME=%NEXTCLOUD_MAX_TIME%",
"TRUSTED_CACERTS_DIR=%NEXTCLOUD_TRUSTED_CACERTS_DIR%",
"STARTUP_APPS=%NEXTCLOUD_STARTUP_APPS%",
@@ -302,6 +307,7 @@
"NEXTCLOUD_HOST=nextcloud-aio-nextcloud",
"TZ=%TIMEZONE%",
"REDIS_HOST=nextcloud-aio-redis",
+ "REDIS_PORT=6379",
"REDIS_HOST_PASSWORD=%REDIS_PASSWORD%",
"POSTGRES_HOST=nextcloud-aio-database",
"POSTGRES_PORT=5432",
@@ -376,8 +382,8 @@
],
"internal_port": "9980",
"environment": [
- "aliasgroup1=https://%NC_DOMAIN%:443",
- "extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:mount_jail_tree=false --o:logging.level=warning --o:home_mode.enable=true %COLLABORA_SECCOMP_POLICY% --o:remote_font_config.url=https://%NC_DOMAIN%/apps/richdocuments/settings/fonts.json --o:net.post_allow.host[0]=.+",
+ "aliasgroup1=https://%NC_DOMAIN%:443,http://nextcloud-aio-apache:23973",
+ "extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:logging.disable_server_audit=true --o:logging.level=warning --o:logging.level_startup=warning --o:welcome.enable=false %COLLABORA_SECCOMP_POLICY% --o:remote_font_config.url=https://%NC_DOMAIN%/apps/richdocuments/settings/fonts.json --o:net.post_allow.host[0]=.+",
"dictionaries=%COLLABORA_DICTIONARIES%",
"TZ=%TIMEZONE%",
"server_name=%NC_DOMAIN%",
@@ -386,7 +392,7 @@
"restart": "unless-stopped",
"nextcloud_exec_commands": [
"echo 'Activating Collabora config...'",
- "php /var/www/html/occ richdocuments:activate-config"
+ "php /var/www/html/occ richdocuments:activate-config --wopi-url='http://nextcloud-aio-apache:23973' --callback-url='http://nextcloud-aio-apache:23973'"
],
"profiles": [
"collabora"
@@ -394,6 +400,8 @@
"cap_add": [
"MKNOD",
"SYS_ADMIN",
+ "SYS_CHROOT",
+ "FOWNER",
"CHOWN"
],
"cap_drop": [
@@ -715,10 +723,6 @@
"ONLYOFFICE_SECRET"
],
"restart": "unless-stopped",
- "nextcloud_exec_commands": [
- "echo 'Activating OnlyOffice config...'",
- "php /var/www/html/occ onlyoffice:documentserver --check"
- ],
"profiles": [
"onlyoffice"
],
@@ -789,10 +793,10 @@
"environment": [
"TZ=%TIMEZONE%",
"ES_JAVA_OPTS=%FULLTEXTSEARCH_JAVA_OPTIONS%",
- "bootstrap.memory_lock=true",
+ "bootstrap.memory_lock=false",
"cluster.name=nextcloud-aio",
"discovery.type=single-node",
- "logger.org.elasticsearch.discovery=WARN",
+ "logger.level=WARN",
"http.port=9200",
"xpack.license.self_generated.type=basic",
"xpack.security.enabled=false",
@@ -870,6 +874,7 @@
"JWT_SECRET_KEY=%WHITEBOARD_SECRET%",
"STORAGE_STRATEGY=redis",
"REDIS_HOST=nextcloud-aio-redis",
+ "REDIS_PORT=6379",
"REDIS_HOST_PASSWORD=%REDIS_PASSWORD%",
"BACKUP_DIR=/tmp"
],
diff --git a/php/cool-seccomp-profile.json b/php/cool-seccomp-profile.json
new file mode 100644
index 00000000..ed2320ca
--- /dev/null
+++ b/php/cool-seccomp-profile.json
@@ -0,0 +1,844 @@
+{
+ "defaultAction": "SCMP_ACT_ERRNO",
+ "defaultErrnoRet": 1,
+ "archMap": [
+ {
+ "architecture": "SCMP_ARCH_X86_64",
+ "subArchitectures": [
+ "SCMP_ARCH_X86",
+ "SCMP_ARCH_X32"
+ ]
+ },
+ {
+ "architecture": "SCMP_ARCH_AARCH64",
+ "subArchitectures": [
+ "SCMP_ARCH_ARM"
+ ]
+ },
+ {
+ "architecture": "SCMP_ARCH_MIPS64",
+ "subArchitectures": [
+ "SCMP_ARCH_MIPS",
+ "SCMP_ARCH_MIPS64N32"
+ ]
+ },
+ {
+ "architecture": "SCMP_ARCH_MIPS64N32",
+ "subArchitectures": [
+ "SCMP_ARCH_MIPS",
+ "SCMP_ARCH_MIPS64"
+ ]
+ },
+ {
+ "architecture": "SCMP_ARCH_MIPSEL64",
+ "subArchitectures": [
+ "SCMP_ARCH_MIPSEL",
+ "SCMP_ARCH_MIPSEL64N32"
+ ]
+ },
+ {
+ "architecture": "SCMP_ARCH_MIPSEL64N32",
+ "subArchitectures": [
+ "SCMP_ARCH_MIPSEL",
+ "SCMP_ARCH_MIPSEL64"
+ ]
+ },
+ {
+ "architecture": "SCMP_ARCH_S390X",
+ "subArchitectures": [
+ "SCMP_ARCH_S390"
+ ]
+ },
+ {
+ "architecture": "SCMP_ARCH_RISCV64",
+ "subArchitectures": null
+ }
+ ],
+ "syscalls": [
+ {
+ "names": [
+ "unshare",
+ "mount",
+ "setns",
+ "clone",
+ "chroot",
+ "umount2"
+ ],
+ "action": "SCMP_ACT_ALLOW"
+ },
+ {
+ "names": [
+ "accept",
+ "accept4",
+ "access",
+ "adjtimex",
+ "alarm",
+ "bind",
+ "brk",
+ "cachestat",
+ "capget",
+ "capset",
+ "chdir",
+ "chmod",
+ "chown",
+ "chown32",
+ "clock_adjtime",
+ "clock_adjtime64",
+ "clock_getres",
+ "clock_getres_time64",
+ "clock_gettime",
+ "clock_gettime64",
+ "clock_nanosleep",
+ "clock_nanosleep_time64",
+ "close",
+ "close_range",
+ "connect",
+ "copy_file_range",
+ "creat",
+ "dup",
+ "dup2",
+ "dup3",
+ "epoll_create",
+ "epoll_create1",
+ "epoll_ctl",
+ "epoll_ctl_old",
+ "epoll_pwait",
+ "epoll_pwait2",
+ "epoll_wait",
+ "epoll_wait_old",
+ "eventfd",
+ "eventfd2",
+ "execve",
+ "execveat",
+ "exit",
+ "exit_group",
+ "faccessat",
+ "faccessat2",
+ "fadvise64",
+ "fadvise64_64",
+ "fallocate",
+ "fanotify_mark",
+ "fchdir",
+ "fchmod",
+ "fchmodat",
+ "fchmodat2",
+ "fchown",
+ "fchown32",
+ "fchownat",
+ "fcntl",
+ "fcntl64",
+ "fdatasync",
+ "fgetxattr",
+ "flistxattr",
+ "flock",
+ "fork",
+ "fremovexattr",
+ "fsetxattr",
+ "fstat",
+ "fstat64",
+ "fstatat64",
+ "fstatfs",
+ "fstatfs64",
+ "fsync",
+ "ftruncate",
+ "ftruncate64",
+ "futex",
+ "futex_requeue",
+ "futex_time64",
+ "futex_wait",
+ "futex_waitv",
+ "futex_wake",
+ "futimesat",
+ "getcpu",
+ "getcwd",
+ "getdents",
+ "getdents64",
+ "getegid",
+ "getegid32",
+ "geteuid",
+ "geteuid32",
+ "getgid",
+ "getgid32",
+ "getgroups",
+ "getgroups32",
+ "getitimer",
+ "getpeername",
+ "getpgid",
+ "getpgrp",
+ "getpid",
+ "getppid",
+ "getpriority",
+ "getrandom",
+ "getresgid",
+ "getresgid32",
+ "getresuid",
+ "getresuid32",
+ "getrlimit",
+ "get_robust_list",
+ "getrusage",
+ "getsid",
+ "getsockname",
+ "getsockopt",
+ "get_thread_area",
+ "gettid",
+ "gettimeofday",
+ "getuid",
+ "getuid32",
+ "getxattr",
+ "inotify_add_watch",
+ "inotify_init",
+ "inotify_init1",
+ "inotify_rm_watch",
+ "io_cancel",
+ "ioctl",
+ "io_destroy",
+ "io_getevents",
+ "io_pgetevents",
+ "io_pgetevents_time64",
+ "ioprio_get",
+ "ioprio_set",
+ "io_setup",
+ "io_submit",
+ "ipc",
+ "kill",
+ "landlock_add_rule",
+ "landlock_create_ruleset",
+ "landlock_restrict_self",
+ "lchown",
+ "lchown32",
+ "lgetxattr",
+ "link",
+ "linkat",
+ "listen",
+ "listxattr",
+ "llistxattr",
+ "_llseek",
+ "lremovexattr",
+ "lseek",
+ "lsetxattr",
+ "lstat",
+ "lstat64",
+ "madvise",
+ "map_shadow_stack",
+ "membarrier",
+ "memfd_create",
+ "memfd_secret",
+ "mincore",
+ "mkdir",
+ "mkdirat",
+ "mknod",
+ "mknodat",
+ "mlock",
+ "mlock2",
+ "mlockall",
+ "mmap",
+ "mmap2",
+ "mprotect",
+ "mq_getsetattr",
+ "mq_notify",
+ "mq_open",
+ "mq_timedreceive",
+ "mq_timedreceive_time64",
+ "mq_timedsend",
+ "mq_timedsend_time64",
+ "mq_unlink",
+ "mremap",
+ "msgctl",
+ "msgget",
+ "msgrcv",
+ "msgsnd",
+ "msync",
+ "munlock",
+ "munlockall",
+ "munmap",
+ "name_to_handle_at",
+ "nanosleep",
+ "newfstatat",
+ "_newselect",
+ "open",
+ "openat",
+ "openat2",
+ "pause",
+ "pidfd_open",
+ "pidfd_send_signal",
+ "pipe",
+ "pipe2",
+ "pkey_alloc",
+ "pkey_free",
+ "pkey_mprotect",
+ "poll",
+ "ppoll",
+ "ppoll_time64",
+ "prctl",
+ "pread64",
+ "preadv",
+ "preadv2",
+ "prlimit64",
+ "process_mrelease",
+ "pselect6",
+ "pselect6_time64",
+ "pwrite64",
+ "pwritev",
+ "pwritev2",
+ "read",
+ "readahead",
+ "readlink",
+ "readlinkat",
+ "readv",
+ "recv",
+ "recvfrom",
+ "recvmmsg",
+ "recvmmsg_time64",
+ "recvmsg",
+ "remap_file_pages",
+ "removexattr",
+ "rename",
+ "renameat",
+ "renameat2",
+ "restart_syscall",
+ "rmdir",
+ "rseq",
+ "rt_sigaction",
+ "rt_sigpending",
+ "rt_sigprocmask",
+ "rt_sigqueueinfo",
+ "rt_sigreturn",
+ "rt_sigsuspend",
+ "rt_sigtimedwait",
+ "rt_sigtimedwait_time64",
+ "rt_tgsigqueueinfo",
+ "sched_getaffinity",
+ "sched_getattr",
+ "sched_getparam",
+ "sched_get_priority_max",
+ "sched_get_priority_min",
+ "sched_getscheduler",
+ "sched_rr_get_interval",
+ "sched_rr_get_interval_time64",
+ "sched_setaffinity",
+ "sched_setattr",
+ "sched_setparam",
+ "sched_setscheduler",
+ "sched_yield",
+ "seccomp",
+ "select",
+ "semctl",
+ "semget",
+ "semop",
+ "semtimedop",
+ "semtimedop_time64",
+ "send",
+ "sendfile",
+ "sendfile64",
+ "sendmmsg",
+ "sendmsg",
+ "sendto",
+ "setfsgid",
+ "setfsgid32",
+ "setfsuid",
+ "setfsuid32",
+ "setgid",
+ "setgid32",
+ "setgroups",
+ "setgroups32",
+ "setitimer",
+ "setpgid",
+ "setpriority",
+ "setregid",
+ "setregid32",
+ "setresgid",
+ "setresgid32",
+ "setresuid",
+ "setresuid32",
+ "setreuid",
+ "setreuid32",
+ "setrlimit",
+ "set_robust_list",
+ "setsid",
+ "setsockopt",
+ "set_thread_area",
+ "set_tid_address",
+ "setuid",
+ "setuid32",
+ "setxattr",
+ "shmat",
+ "shmctl",
+ "shmdt",
+ "shmget",
+ "shutdown",
+ "sigaltstack",
+ "signalfd",
+ "signalfd4",
+ "sigprocmask",
+ "sigreturn",
+ "socketcall",
+ "socketpair",
+ "splice",
+ "stat",
+ "stat64",
+ "statfs",
+ "statfs64",
+ "statx",
+ "symlink",
+ "symlinkat",
+ "sync",
+ "sync_file_range",
+ "syncfs",
+ "sysinfo",
+ "tee",
+ "tgkill",
+ "time",
+ "timer_create",
+ "timer_delete",
+ "timer_getoverrun",
+ "timer_gettime",
+ "timer_gettime64",
+ "timer_settime",
+ "timer_settime64",
+ "timerfd_create",
+ "timerfd_gettime",
+ "timerfd_gettime64",
+ "timerfd_settime",
+ "timerfd_settime64",
+ "times",
+ "tkill",
+ "truncate",
+ "truncate64",
+ "ugetrlimit",
+ "umask",
+ "uname",
+ "unlink",
+ "unlinkat",
+ "utime",
+ "utimensat",
+ "utimensat_time64",
+ "utimes",
+ "vfork",
+ "vmsplice",
+ "wait4",
+ "waitid",
+ "waitpid",
+ "write",
+ "writev"
+ ],
+ "action": "SCMP_ACT_ALLOW"
+ },
+ {
+ "names": [
+ "process_vm_readv",
+ "process_vm_writev",
+ "ptrace"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "minKernel": "4.8"
+ }
+ },
+ {
+ "names": [
+ "socket"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 0,
+ "value": 40,
+ "op": "SCMP_CMP_NE"
+ }
+ ]
+ },
+ {
+ "names": [
+ "personality"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 0,
+ "value": 0,
+ "op": "SCMP_CMP_EQ"
+ }
+ ]
+ },
+ {
+ "names": [
+ "personality"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 0,
+ "value": 8,
+ "op": "SCMP_CMP_EQ"
+ }
+ ]
+ },
+ {
+ "names": [
+ "personality"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 0,
+ "value": 131072,
+ "op": "SCMP_CMP_EQ"
+ }
+ ]
+ },
+ {
+ "names": [
+ "personality"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 0,
+ "value": 131080,
+ "op": "SCMP_CMP_EQ"
+ }
+ ]
+ },
+ {
+ "names": [
+ "personality"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 0,
+ "value": 4294967295,
+ "op": "SCMP_CMP_EQ"
+ }
+ ]
+ },
+ {
+ "names": [
+ "sync_file_range2",
+ "swapcontext"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "arches": [
+ "ppc64le"
+ ]
+ }
+ },
+ {
+ "names": [
+ "arm_fadvise64_64",
+ "arm_sync_file_range",
+ "sync_file_range2",
+ "breakpoint",
+ "cacheflush",
+ "set_tls"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "arches": [
+ "arm",
+ "arm64"
+ ]
+ }
+ },
+ {
+ "names": [
+ "arch_prctl"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "arches": [
+ "amd64",
+ "x32"
+ ]
+ }
+ },
+ {
+ "names": [
+ "modify_ldt"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "arches": [
+ "amd64",
+ "x32",
+ "x86"
+ ]
+ }
+ },
+ {
+ "names": [
+ "s390_pci_mmio_read",
+ "s390_pci_mmio_write",
+ "s390_runtime_instr"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "arches": [
+ "s390",
+ "s390x"
+ ]
+ }
+ },
+ {
+ "names": [
+ "riscv_flush_icache"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "arches": [
+ "riscv64"
+ ]
+ }
+ },
+ {
+ "names": [
+ "open_by_handle_at"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_DAC_READ_SEARCH"
+ ]
+ }
+ },
+ {
+ "names": [
+ "bpf",
+ "clone",
+ "clone3",
+ "fanotify_init",
+ "fsconfig",
+ "fsmount",
+ "fsopen",
+ "fspick",
+ "lookup_dcookie",
+ "mount",
+ "mount_setattr",
+ "move_mount",
+ "open_tree",
+ "perf_event_open",
+ "quotactl",
+ "quotactl_fd",
+ "setdomainname",
+ "sethostname",
+ "setns",
+ "syslog",
+ "umount",
+ "umount2",
+ "unshare"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_ADMIN"
+ ]
+ }
+ },
+ {
+ "names": [
+ "clone"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 0,
+ "value": 2114060288,
+ "op": "SCMP_CMP_MASKED_EQ"
+ }
+ ],
+ "excludes": {
+ "caps": [
+ "CAP_SYS_ADMIN"
+ ],
+ "arches": [
+ "s390",
+ "s390x"
+ ]
+ }
+ },
+ {
+ "names": [
+ "clone"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 1,
+ "value": 2114060288,
+ "op": "SCMP_CMP_MASKED_EQ"
+ }
+ ],
+ "comment": "s390 parameter ordering for clone is different",
+ "includes": {
+ "arches": [
+ "s390",
+ "s390x"
+ ]
+ },
+ "excludes": {
+ "caps": [
+ "CAP_SYS_ADMIN"
+ ]
+ }
+ },
+ {
+ "names": [
+ "clone3"
+ ],
+ "action": "SCMP_ACT_ERRNO",
+ "errnoRet": 38,
+ "excludes": {
+ "caps": [
+ "CAP_SYS_ADMIN"
+ ]
+ }
+ },
+ {
+ "names": [
+ "reboot"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_BOOT"
+ ]
+ }
+ },
+ {
+ "names": [
+ "chroot"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_CHROOT"
+ ]
+ }
+ },
+ {
+ "names": [
+ "delete_module",
+ "init_module",
+ "finit_module"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_MODULE"
+ ]
+ }
+ },
+ {
+ "names": [
+ "acct"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_PACCT"
+ ]
+ }
+ },
+ {
+ "names": [
+ "kcmp",
+ "pidfd_getfd",
+ "process_madvise",
+ "process_vm_readv",
+ "process_vm_writev",
+ "ptrace"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_PTRACE"
+ ]
+ }
+ },
+ {
+ "names": [
+ "iopl",
+ "ioperm"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_RAWIO"
+ ]
+ }
+ },
+ {
+ "names": [
+ "settimeofday",
+ "stime",
+ "clock_settime",
+ "clock_settime64"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_TIME"
+ ]
+ }
+ },
+ {
+ "names": [
+ "vhangup"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_TTY_CONFIG"
+ ]
+ }
+ },
+ {
+ "names": [
+ "get_mempolicy",
+ "mbind",
+ "set_mempolicy",
+ "set_mempolicy_home_node"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYS_NICE"
+ ]
+ }
+ },
+ {
+ "names": [
+ "syslog"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_SYSLOG"
+ ]
+ }
+ },
+ {
+ "names": [
+ "bpf"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_BPF"
+ ]
+ }
+ },
+ {
+ "names": [
+ "perf_event_open"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "includes": {
+ "caps": [
+ "CAP_PERFMON"
+ ]
+ }
+ }
+ ]
+}
diff --git a/php/psalm-baseline.xml b/php/psalm-baseline.xml
index c2056b48..a9b7140d 100644
--- a/php/psalm-baseline.xml
+++ b/php/psalm-baseline.xml
@@ -1,64 +1,2 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/php/public/base_path.js b/php/public/base_path.js
new file mode 100644
index 00000000..a55ed943
--- /dev/null
+++ b/php/public/base_path.js
@@ -0,0 +1,7 @@
+document.addEventListener("DOMContentLoaded", function() {
+ basePath = document.getElementById("base_path")
+ if (basePath) {
+ // Remove '/containers' from the end of the path, to get the base path only
+ basePath.value = window.location.pathname.slice(0, -11);
+ }
+});
\ No newline at end of file
diff --git a/php/public/img/jenna-kim-the-globe-dark.webp b/php/public/img/jenna-kim-the-globe-dark.webp
deleted file mode 100644
index bd3b0daf..00000000
Binary files a/php/public/img/jenna-kim-the-globe-dark.webp and /dev/null differ
diff --git a/php/public/img/jenna-kim-the-globe.webp b/php/public/img/jenna-kim-the-globe.webp
deleted file mode 100644
index 909a8761..00000000
Binary files a/php/public/img/jenna-kim-the-globe.webp and /dev/null differ
diff --git a/php/public/img/jo-myoung-hee-fluid-dark.webp b/php/public/img/jo-myoung-hee-fluid-dark.webp
new file mode 100644
index 00000000..314048f9
Binary files /dev/null and b/php/public/img/jo-myoung-hee-fluid-dark.webp differ
diff --git a/php/public/img/jo-myoung-hee-fluid.webp b/php/public/img/jo-myoung-hee-fluid.webp
new file mode 100644
index 00000000..1e9f4aad
Binary files /dev/null and b/php/public/img/jo-myoung-hee-fluid.webp differ
diff --git a/php/public/index.php b/php/public/index.php
index 712f1463..b57f65a5 100644
--- a/php/public/index.php
+++ b/php/public/index.php
@@ -60,6 +60,7 @@ $app->get('/api/docker/getwatchtower', AIO\Controller\DockerController::class .
$app->post('/api/docker/start', AIO\Controller\DockerController::class . ':StartContainer');
$app->post('/api/docker/backup', AIO\Controller\DockerController::class . ':StartBackupContainerBackup');
$app->post('/api/docker/backup-check', AIO\Controller\DockerController::class . ':StartBackupContainerCheck');
+$app->post('/api/docker/backup-list', AIO\Controller\DockerController::class . ':StartBackupContainerList');
$app->post('/api/docker/backup-check-repair', AIO\Controller\DockerController::class . ':StartBackupContainerCheckRepair');
$app->post('/api/docker/backup-test', AIO\Controller\DockerController::class . ':StartBackupContainerTest');
$app->post('/api/docker/restore', AIO\Controller\DockerController::class . ':StartBackupContainerRestore');
@@ -76,16 +77,18 @@ $app->get('/containers', function (Request $request, Response $response, array $
$view->addExtension(new \AIO\Twig\ClassExtension());
/** @var \AIO\Data\ConfigurationManager $configurationManager */
$configurationManager = $container->get(\AIO\Data\ConfigurationManager::class);
- /** @var \AIO\Docker\DockerActionManager $dockerActionManger */
- $dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
+ /** @var \AIO\Docker\DockerActionManager $dockerActionManager */
+ $dockerActionManager = $container->get(\AIO\Docker\DockerActionManager::class);
/** @var \AIO\Controller\DockerController $dockerController */
$dockerController = $container->get(\AIO\Controller\DockerController::class);
- $dockerActionManger->ConnectMasterContainerToNetwork();
+ $dockerActionManager->ConnectMasterContainerToNetwork();
$dockerController->StartDomaincheckContainer();
// Check if bypass_mastercontainer_update is provided on the URL, a special developer mode to bypass a mastercontainer update and use local image.
$params = $request->getQueryParams();
$bypass_mastercontainer_update = isset($params['bypass_mastercontainer_update']);
+ $bypass_container_update = isset($params['bypass_container_update']);
+ $skip_domain_validation = isset($params['skip_domain_validation']);
return $view->render($response, 'containers.twig', [
'domain' => $configurationManager->GetDomain(),
@@ -96,17 +99,17 @@ $app->get('/containers', function (Request $request, Response $response, array $
'nextcloud_password' => $configurationManager->GetAndGenerateSecret('NEXTCLOUD_PASSWORD'),
'containers' => (new \AIO\ContainerDefinitionFetcher($container->get(\AIO\Data\ConfigurationManager::class), $container))->FetchDefinition(),
'borgbackup_password' => $configurationManager->GetAndGenerateSecret('BORGBACKUP_PASSWORD'),
- 'is_mastercontainer_update_available' => ( $bypass_mastercontainer_update ? false : $dockerActionManger->IsMastercontainerUpdateAvailable() ),
+ 'is_mastercontainer_update_available' => ( $bypass_mastercontainer_update ? false : $dockerActionManager->IsMastercontainerUpdateAvailable() ),
'has_backup_run_once' => $configurationManager->hasBackupRunOnce(),
- 'is_backup_container_running' => $dockerActionManger->isBackupContainerRunning(),
- 'backup_exit_code' => $dockerActionManger->GetBackupcontainerExitCode(),
+ 'is_backup_container_running' => $dockerActionManager->isBackupContainerRunning(),
+ 'backup_exit_code' => $dockerActionManager->GetBackupcontainerExitCode(),
'is_instance_restore_attempt' => $configurationManager->isInstanceRestoreAttempt(),
- 'borg_backup_mode' => $configurationManager->GetBorgBackupMode(),
+ 'borg_backup_mode' => $configurationManager->GetBackupMode(),
'was_start_button_clicked' => $configurationManager->wasStartButtonClicked(),
- 'has_update_available' => $dockerActionManger->isAnyUpdateAvailable(),
+ 'has_update_available' => $dockerActionManager->isAnyUpdateAvailable(),
'last_backup_time' => $configurationManager->GetLastBackupTime(),
'backup_times' => $configurationManager->GetBackupTimes(),
- 'current_channel' => $dockerActionManger->GetCurrentChannel(),
+ 'current_channel' => $dockerActionManager->GetCurrentChannel(),
'is_clamav_enabled' => $configurationManager->isClamavEnabled(),
'is_onlyoffice_enabled' => $configurationManager->isOnlyofficeEnabled(),
'is_collabora_enabled' => $configurationManager->isCollaboraEnabled(),
@@ -115,7 +118,7 @@ $app->get('/containers', function (Request $request, Response $response, array $
'daily_backup_time' => $configurationManager->GetDailyBackupTime(),
'is_daily_backup_running' => $configurationManager->isDailyBackupRunning(),
'timezone' => $configurationManager->GetTimezone(),
- 'skip_domain_validation' => $configurationManager->shouldDomainValidationBeSkipped(),
+ 'skip_domain_validation' => $configurationManager->shouldDomainValidationBeSkipped($skip_domain_validation),
'talk_port' => $configurationManager->GetTalkPort(),
'collabora_dictionaries' => $configurationManager->GetCollaboraDictionaries(),
'collabora_additional_options' => $configurationManager->GetAdditionalCollaboraOptions(),
@@ -136,14 +139,15 @@ $app->get('/containers', function (Request $request, Response $response, array $
'is_whiteboard_enabled' => $configurationManager->isWhiteboardEnabled(),
'community_containers' => $configurationManager->listAvailableCommunityContainers(),
'community_containers_enabled' => $configurationManager->GetEnabledCommunityContainers(),
+ 'bypass_container_update' => $bypass_container_update,
]);
})->setName('profile');
$app->get('/login', function (Request $request, Response $response, array $args) use ($container) {
$view = Twig::fromRequest($request);
- /** @var \AIO\Docker\DockerActionManager $dockerActionManger */
- $dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
+ /** @var \AIO\Docker\DockerActionManager $dockerActionManager */
+ $dockerActionManager = $container->get(\AIO\Docker\DockerActionManager::class);
return $view->render($response, 'login.twig', [
- 'is_login_allowed' => $dockerActionManger->isLoginAllowed(),
+ 'is_login_allowed' => $dockerActionManager->isLoginAllowed(),
]);
});
$app->get('/setup', function (Request $request, Response $response, array $args) use ($container) {
@@ -176,17 +180,17 @@ $app->get('/', function (\Psr\Http\Message\RequestInterface $request, Response $
$setup = $container->get(\AIO\Data\Setup::class);
if($setup->CanBeInstalled()) {
return $response
- ->withHeader('Location', '/setup')
+ ->withHeader('Location', 'setup')
->withStatus(302);
}
if($authManager->IsAuthenticated()) {
return $response
- ->withHeader('Location', '/containers')
+ ->withHeader('Location', 'containers')
->withStatus(302);
} else {
return $response
- ->withHeader('Location', '/login')
+ ->withHeader('Location', 'login')
->withStatus(302);
}
});
diff --git a/php/public/style.css b/php/public/style.css
index 107463b5..b4d5f8a5 100644
--- a/php/public/style.css
+++ b/php/public/style.css
@@ -220,7 +220,7 @@ svg:not(:has(use)) .fallback-text {
}
.login > .monospace {
- font-family: monospace;
+ font-family: monospace, monospace, system-ui, -apple-system, 'Segoe UI', Roboto, Oxygen-Sans, Cantarell, Ubuntu, 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-size: 17px;
}
@@ -251,7 +251,7 @@ svg:not(:has(use)) .fallback-text {
min-width: 100vw;
position: fixed;
width: 100vw;
- background-image: url("img/jenna-kim-the-globe.webp");
+ background-image: url("img/jo-myoung-hee-fluid.webp");
background-position: center;
background-repeat: no-repeat;
background-size: cover;
@@ -260,7 +260,7 @@ svg:not(:has(use)) .fallback-text {
}
html[data-theme="dark"] .wrapper {
- background-image: url("img/jenna-kim-the-globe-dark.webp");
+ background-image: url("img/jo-myoung-hee-fluid-dark.webp");
}
form {
diff --git a/php/src/Container/Container.php b/php/src/Container/Container.php
index 77858283..6e5d2b54 100644
--- a/php/src/Container/Container.php
+++ b/php/src/Container/Container.php
@@ -5,127 +5,56 @@ namespace AIO\Container;
use AIO\Data\ConfigurationManager;
use AIO\Docker\DockerActionManager;
use AIO\ContainerDefinitionFetcher;
+use JsonException;
readonly class Container {
public function __construct(
- private string $identifier,
- private string $displayName,
- private string $containerName,
- private string $restartPolicy,
- private int $maxShutdownTime,
- private ContainerPorts $ports,
- private string $internalPorts,
- private ContainerVolumes $volumes,
- private ContainerEnvironmentVariables $containerEnvironmentVariables,
+ public string $identifier,
+ public string $displayName,
+ public string $containerName,
+ public string $restartPolicy,
+ public int $maxShutdownTime,
+ public ContainerPorts $ports,
+ public string $internalPorts,
+ public ContainerVolumes $volumes,
+ public ContainerEnvironmentVariables $containerEnvironmentVariables,
/** @var string[] */
- private array $dependsOn,
- /** @var string[] */
- private array $secrets,
+ public array $dependsOn,
private string $uiSecret,
/** @var string[] */
- private array $devices,
- private bool $enableNvidiaGpu,
+ public array $devices,
+ public bool $enableNvidiaGpu,
/** @var string[] */
- private array $capAdd,
- private int $shmSize,
- private bool $apparmorUnconfined,
+ public array $capAdd,
+ public int $shmSize,
+ public bool $apparmorUnconfined,
/** @var string[] */
- private array $backupVolumes,
- private array $nextcloudExecCommands,
- private bool $readOnlyRootFs,
- private array $tmpfs,
- private bool $init,
- private string $imageTag,
- private AioVariables $aioVariables,
- private string $documentation,
+ public array $backupVolumes,
+ public array $nextcloudExecCommands,
+ public bool $readOnlyRootFs,
+ public array $tmpfs,
+ public bool $init,
+ public string $imageTag,
+ public AioVariables $aioVariables,
+ public string $documentation,
private DockerActionManager $dockerActionManager
) {
}
- public function GetIdentifier() : string {
- return $this->identifier;
- }
-
- public function GetDisplayName() : string {
- return $this->displayName;
- }
-
- public function GetContainerName() : string {
- return $this->containerName;
- }
-
- public function GetRestartPolicy() : string {
- return $this->restartPolicy;
- }
-
- public function GetImageTag() : string {
- return $this->imageTag;
- }
-
- public function GetReadOnlySetting() : bool {
- return $this->readOnlyRootFs;
- }
-
- public function GetInit() : bool {
- return $this->init;
- }
-
- public function GetShmSize() : int {
- return $this->shmSize;
- }
-
- public function isApparmorUnconfined() : bool {
- return $this->apparmorUnconfined;
- }
-
- public function GetMaxShutdownTime() : int {
- return $this->maxShutdownTime;
- }
-
- public function GetSecrets() : array {
- return $this->secrets;
- }
-
public function GetUiSecret() : string {
return $this->dockerActionManager->GetAndGenerateSecretWrapper($this->uiSecret);
}
- public function GetTmpfs() : array {
- return $this->tmpfs;
- }
-
- public function GetDevices() : array {
- return $this->devices;
- }
-
- public function isNvidiaGpuEnabled() : bool {
- return $this->enableNvidiaGpu;
- }
-
- public function GetCapAdds() : array {
- return $this->capAdd;
- }
-
- public function GetBackupVolumes() : array {
- return $this->backupVolumes;
- }
-
- public function GetPorts() : ContainerPorts {
- return $this->ports;
- }
-
- public function GetInternalPort() : string {
- return $this->internalPorts;
- }
-
- public function GetVolumes() : ContainerVolumes {
- return $this->volumes;
- }
-
+ /**
+ * @throws JsonException
+ */
public function GetRunningState() : ContainerState {
return $this->dockerActionManager->GetContainerRunningState($this);
}
+ /**
+ * @throws JsonException
+ */
public function GetRestartingState() : ContainerState {
return $this->dockerActionManager->GetContainerRestartingState($this);
}
@@ -137,27 +66,4 @@ readonly class Container {
public function GetStartingState() : ContainerState {
return $this->dockerActionManager->GetContainerStartingState($this);
}
-
- /**
- * @return string[]
- */
- public function GetDependsOn() : array {
- return $this->dependsOn;
- }
-
- public function GetNextcloudExecCommands() : array {
- return $this->nextcloudExecCommands;
- }
-
- public function GetEnvironmentVariables() : ContainerEnvironmentVariables {
- return $this->containerEnvironmentVariables;
- }
-
- public function GetAioVariables() : AioVariables {
- return $this->aioVariables;
- }
-
- public function GetDocumentation() : string {
- return $this->documentation;
- }
}
diff --git a/php/src/ContainerDefinitionFetcher.php b/php/src/ContainerDefinitionFetcher.php
index 6809650c..d7498047 100644
--- a/php/src/ContainerDefinitionFetcher.php
+++ b/php/src/ContainerDefinitionFetcher.php
@@ -25,7 +25,7 @@ readonly class ContainerDefinitionFetcher {
$containers = $this->FetchDefinition();
foreach ($containers as $container) {
- if ($container->GetIdentifier() === $id) {
+ if ($container->identifier === $id) {
return $container;
}
}
@@ -38,13 +38,13 @@ readonly class ContainerDefinitionFetcher {
*/
private function GetDefinition(): array
{
- $data = json_decode(file_get_contents(__DIR__ . '/../containers.json'), true);
+ $data = json_decode((string)file_get_contents(DataConst::GetContainersDefinitionPath()), true, 512, JSON_THROW_ON_ERROR);
$additionalContainerNames = [];
foreach ($this->configurationManager->GetEnabledCommunityContainers() as $communityContainer) {
if ($communityContainer !== '') {
$path = DataConst::GetCommunityContainersDirectory() . '/' . $communityContainer . '/' . $communityContainer . '.json';
- $additionalData = json_decode(file_get_contents($path), true);
+ $additionalData = json_decode((string)file_get_contents($path), true, 512, JSON_THROW_ON_ERROR);
$data = array_merge_recursive($data, $additionalData);
if (isset($additionalData['aio_services_v1'][0]['display_name']) && $additionalData['aio_services_v1'][0]['display_name'] !== '') {
// Store container_name of community containers in variable for later
@@ -67,6 +67,9 @@ readonly class ContainerDefinitionFetcher {
if (!$this->configurationManager->isCollaboraEnabled()) {
continue;
}
+ if ($this->configurationManager->isCollaboraSubscriptionEnabled()) {
+ $entry['image'] = 'ghcr.io/nextcloud-releases/aio-collabora-online';
+ }
} elseif ($entry['container_name'] === 'nextcloud-aio-talk') {
if (!$this->configurationManager->isTalkEnabled()) {
continue;
@@ -239,9 +242,12 @@ readonly class ContainerDefinitionFetcher {
$internalPort = $entry['internal_port'];
}
- $secrets = [];
if (isset($entry['secrets'])) {
- $secrets = $entry['secrets'];
+ // All secrets are registered with the configuration when they
+ // are discovered so they can be later generated at time-of-use.
+ foreach ($entry['secrets'] as $secret) {
+ $this->configurationManager->RegisterSecret($secret);
+ }
}
$uiSecret = '';
@@ -320,7 +326,6 @@ readonly class ContainerDefinitionFetcher {
$volumes,
$variables,
$dependsOn,
- $secrets,
$uiSecret,
$devices,
$enableNvidiaGpu,
diff --git a/php/src/Controller/ConfigurationController.php b/php/src/Controller/ConfigurationController.php
index ed3be505..45586f9c 100644
--- a/php/src/Controller/ConfigurationController.php
+++ b/php/src/Controller/ConfigurationController.php
@@ -19,7 +19,8 @@ readonly class ConfigurationController {
try {
if (isset($request->getParsedBody()['domain'])) {
$domain = $request->getParsedBody()['domain'] ?? '';
- $this->configurationManager->SetDomain($domain);
+ $skipDomainValidation = isset($request->getParsedBody()['skip_domain_validation']);
+ $this->configurationManager->SetDomain($domain, $skipDomainValidation);
}
if (isset($request->getParsedBody()['current-master-password']) || isset($request->getParsedBody()['new-master-password'])) {
@@ -158,10 +159,10 @@ readonly class ConfigurationController {
}
if (isset($request->getParsedBody()['delete_borg_backup_location_vars'])) {
- $this->configurationManager->DeleteBorgBackupLocationVars();
+ $this->configurationManager->DeleteBorgBackupLocationItems();
}
- return $response->withStatus(201)->withHeader('Location', '/');
+ return $response->withStatus(201)->withHeader('Location', '.');
} catch (InvalidSettingConfigurationException $ex) {
$response->getBody()->write($ex->getMessage());
return $response->withStatus(422);
diff --git a/php/src/Controller/DockerController.php b/php/src/Controller/DockerController.php
index 13e8bdda..a924e61f 100644
--- a/php/src/Controller/DockerController.php
+++ b/php/src/Controller/DockerController.php
@@ -22,7 +22,8 @@ readonly class DockerController {
private function PerformRecursiveContainerStart(string $id, bool $pullImage = true) : void {
$container = $this->containerDefinitionFetcher->GetContainerById($id);
- foreach($container->GetDependsOn() as $dependency) {
+ // Start all dependencies first and then itself
+ foreach($container->dependsOn as $dependency) {
$this->PerformRecursiveContainerStart($dependency, $pullImage);
}
@@ -33,33 +34,32 @@ readonly class DockerController {
return;
}
- // Skip database image pull if the last shutdown was not clean
- if ($id === 'nextcloud-aio-database') {
- if ($this->dockerActionManager->GetDatabasecontainerExitCode() > 0) {
- $pullImage = false;
- error_log('Not pulling the latest database image because the container was not correctly shut down.');
- }
- }
-
- // Check if registry is reachable in order to make sure that we do not try to pull an image if it is down
- // and try to mitigate issues that are arising due to that
- if ($pullImage) {
- if (!$this->dockerActionManager->isRegistryReachable($container)) {
- $pullImage = false;
- error_log('Not pulling the ' . $container->GetContainerName() . ' image for the ' . $container->GetIdentifier() . ' container because the registry does not seem to be reachable.');
- }
- }
-
$this->dockerActionManager->DeleteContainer($container);
$this->dockerActionManager->CreateVolumes($container);
- if ($pullImage) {
- $this->dockerActionManager->PullImage($container);
- }
+ $this->dockerActionManager->PullImage($container, $pullImage);
$this->dockerActionManager->CreateContainer($container);
$this->dockerActionManager->StartContainer($container);
$this->dockerActionManager->ConnectContainerToNetwork($container);
}
+ private function PerformRecursiveImagePull(string $id) : void {
+ $container = $this->containerDefinitionFetcher->GetContainerById($id);
+
+ // Pull all dependencies first and then itself
+ foreach($container->dependsOn as $dependency) {
+ $this->PerformRecursiveImagePull($dependency);
+ }
+
+ $this->dockerActionManager->PullImage($container, true);
+ }
+
+ public function PullAllContainerImages(): void {
+
+ $id = self::TOP_CONTAINER;
+
+ $this->PerformRecursiveImagePull($id);
+ }
+
public function GetLogs(Request $request, Response $response, array $args) : Response
{
$requestParams = $request->getQueryParams();
@@ -83,17 +83,16 @@ readonly class DockerController {
}
public function StartBackupContainerBackup(Request $request, Response $response, array $args) : Response {
- $this->startBackup();
- return $response->withStatus(201)->withHeader('Location', '/');
+ $forceStopNextcloud = true;
+ $this->startBackup($forceStopNextcloud);
+ return $response->withStatus(201)->withHeader('Location', '.');
}
- public function startBackup() : void {
- $config = $this->configurationManager->GetConfig();
- $config['backup-mode'] = 'backup';
- $this->configurationManager->WriteConfig($config);
+ public function startBackup(bool $forceStopNextcloud = false) : void {
+ $this->configurationManager->SetBackupMode('backup');
$id = self::TOP_CONTAINER;
- $this->PerformRecursiveContainerStop($id);
+ $this->PerformRecursiveContainerStop($id, $forceStopNextcloud);
$id = 'nextcloud-aio-borgbackup';
$this->PerformRecursiveContainerStart($id);
@@ -101,21 +100,31 @@ readonly class DockerController {
public function StartBackupContainerCheck(Request $request, Response $response, array $args) : Response {
$this->checkBackup();
- return $response->withStatus(201)->withHeader('Location', '/');
+ return $response->withStatus(201)->withHeader('Location', '.');
+ }
+
+ public function StartBackupContainerList(Request $request, Response $response, array $args) : Response {
+ $this->listBackup();
+ return $response->withStatus(201)->withHeader('Location', '.');
}
public function checkBackup() : void {
- $config = $this->configurationManager->GetConfig();
- $config['backup-mode'] = 'check';
- $this->configurationManager->WriteConfig($config);
+ $this->configurationManager->SetBackupMode('check');
+
+ $id = 'nextcloud-aio-borgbackup';
+ $this->PerformRecursiveContainerStart($id);
+ }
+
+ private function listBackup() : void {
+ $this->configurationManager->SetBackupMode('list');
$id = 'nextcloud-aio-borgbackup';
$this->PerformRecursiveContainerStart($id);
}
public function StartBackupContainerRestore(Request $request, Response $response, array $args) : Response {
+ $this->configurationManager->SetBackupMode('restore');
$config = $this->configurationManager->GetConfig();
- $config['backup-mode'] = 'restore';
$config['selected-restore-time'] = $request->getParsedBody()['selected_restore_time'] ?? '';
if (isset($request->getParsedBody()['restore-exclude-previews'])) {
$config['restore-exclude-previews'] = 1;
@@ -125,33 +134,30 @@ readonly class DockerController {
$this->configurationManager->WriteConfig($config);
$id = self::TOP_CONTAINER;
- $this->PerformRecursiveContainerStop($id);
+ $forceStopNextcloud = true;
+ $this->PerformRecursiveContainerStop($id, $forceStopNextcloud);
$id = 'nextcloud-aio-borgbackup';
$this->PerformRecursiveContainerStart($id);
- return $response->withStatus(201)->withHeader('Location', '/');
+ return $response->withStatus(201)->withHeader('Location', '.');
}
public function StartBackupContainerCheckRepair(Request $request, Response $response, array $args) : Response {
- $config = $this->configurationManager->GetConfig();
- $config['backup-mode'] = 'check-repair';
- $this->configurationManager->WriteConfig($config);
+ $this->configurationManager->SetBackupMode('check-repair');
$id = 'nextcloud-aio-borgbackup';
$this->PerformRecursiveContainerStart($id);
// Restore to backup check which is needed to make the UI logic work correctly
- $config = $this->configurationManager->GetConfig();
- $config['backup-mode'] = 'check';
- $this->configurationManager->WriteConfig($config);
+ $this->configurationManager->SetBackupMode('check');
- return $response->withStatus(201)->withHeader('Location', '/');
+ return $response->withStatus(201)->withHeader('Location', '.');
}
public function StartBackupContainerTest(Request $request, Response $response, array $args) : Response {
+ $this->configurationManager->SetBackupMode('test');
$config = $this->configurationManager->GetConfig();
- $config['backup-mode'] = 'test';
$config['instance_restore_attempt'] = 0;
$this->configurationManager->WriteConfig($config);
@@ -161,7 +167,7 @@ readonly class DockerController {
$id = 'nextcloud-aio-borgbackup';
$this->PerformRecursiveContainerStart($id);
- return $response->withStatus(201)->withHeader('Location', '/');
+ return $response->withStatus(201)->withHeader('Location', '.');
}
public function StartContainer(Request $request, Response $response, array $args) : Response
@@ -169,34 +175,41 @@ readonly class DockerController {
$uri = $request->getUri();
$host = $uri->getHost();
$port = $uri->getPort();
+ $path = $request->getParsedBody()['base_path'] ?? '';
if ($port === 8000) {
error_log('The AIO_URL-port was discovered to be 8000 which is not expected. It is now set to 443.');
$port = 443;
}
if (isset($request->getParsedBody()['install_latest_major'])) {
- $installLatestMajor = 31;
+ $installLatestMajor = 32;
} else {
$installLatestMajor = "";
}
$config = $this->configurationManager->GetConfig();
// set AIO_URL
- $config['AIO_URL'] = $host . ':' . $port;
+ $config['AIO_URL'] = $host . ':' . (string)$port . $path;
// set wasStartButtonClicked
$config['wasStartButtonClicked'] = 1;
// set install_latest_major
$config['install_latest_major'] = $installLatestMajor;
$this->configurationManager->WriteConfig($config);
+ // Do not pull container images in case 'bypass_container_update' is set via url params
+ // Needed for local testing
+ $pullImage = !isset($request->getParsedBody()['bypass_container_update']);
+ if ($pullImage === false) {
+ error_log('WARNING: Not pulling container images. Instead, using local ones.');
+ }
// Start container
- $this->startTopContainer(true);
+ $this->startTopContainer($pullImage);
// Clear apcu cache in order to check if container updates are available
// Temporarily disabled as it leads much faster to docker rate limits
// apcu_clear_cache();
- return $response->withStatus(201)->withHeader('Location', '/');
+ return $response->withStatus(201)->withHeader('Location', '.');
}
public function startTopContainer(bool $pullImage) : void {
@@ -215,7 +228,7 @@ readonly class DockerController {
public function StartWatchtowerContainer(Request $request, Response $response, array $args) : Response {
$this->startWatchtower();
- return $response->withStatus(201)->withHeader('Location', '/');
+ return $response->withStatus(201)->withHeader('Location', '.');
}
public function startWatchtower() : void {
@@ -224,24 +237,36 @@ readonly class DockerController {
$this->PerformRecursiveContainerStart($id);
}
- private function PerformRecursiveContainerStop(string $id) : void
+ private function PerformRecursiveContainerStop(string $id, bool $forceStopNextcloud = false) : void
{
$container = $this->containerDefinitionFetcher->GetContainerById($id);
- foreach($container->GetDependsOn() as $dependency) {
- $this->PerformRecursiveContainerStop($dependency);
+
+ // This is a hack but no better solution was found for the meantime
+ // Stop Collabora first to make sure it force-saves
+ // See https://github.com/nextcloud/richdocuments/issues/3799
+ if ($id === self::TOP_CONTAINER && $this->configurationManager->isCollaboraEnabled()) {
+ $this->PerformRecursiveContainerStop('nextcloud-aio-collabora');
}
- // Disconnecting is not needed. This also allows to start the containers manually via docker-cli
- //$this->dockerActionManager->DisconnectContainerFromNetwork($container);
- $this->dockerActionManager->StopContainer($container);
+ // Stop itself first and then all the dependencies
+ if ($id !== 'nextcloud-aio-nextcloud') {
+ $this->dockerActionManager->StopContainer($container);
+ } else {
+ // We want to stop the Nextcloud container after 10s and not wait for the configured stop_grace_period
+ $this->dockerActionManager->StopContainer($container, $forceStopNextcloud);
+ }
+ foreach($container->dependsOn as $dependency) {
+ $this->PerformRecursiveContainerStop($dependency, $forceStopNextcloud);
+ }
}
public function StopContainer(Request $request, Response $response, array $args) : Response
{
$id = self::TOP_CONTAINER;
- $this->PerformRecursiveContainerStop($id);
+ $forceStopNextcloud = true;
+ $this->PerformRecursiveContainerStop($id, $forceStopNextcloud);
- return $response->withStatus(201)->withHeader('Location', '/');
+ return $response->withStatus(201)->withHeader('Location', '.');
}
public function stopTopContainer() : void {
diff --git a/php/src/Controller/LoginController.php b/php/src/Controller/LoginController.php
index 196e7138..412ff9df 100644
--- a/php/src/Controller/LoginController.php
+++ b/php/src/Controller/LoginController.php
@@ -19,33 +19,33 @@ readonly class LoginController {
public function TryLogin(Request $request, Response $response, array $args) : Response {
if (!$this->dockerActionManager->isLoginAllowed()) {
$response->getBody()->write("The login is blocked since Nextcloud is running.");
- return $response->withHeader('Location', '/')->withStatus(422);
+ return $response->withHeader('Location', '.')->withStatus(422);
}
$password = $request->getParsedBody()['password'] ?? '';
if($this->authManager->CheckCredentials($password)) {
$this->authManager->SetAuthState(true);
- return $response->withHeader('Location', '/')->withStatus(201);
+ return $response->withHeader('Location', '.')->withStatus(201);
}
$response->getBody()->write("The password is incorrect.");
- return $response->withHeader('Location', '/')->withStatus(422);
+ return $response->withHeader('Location', '.')->withStatus(422);
}
public function GetTryLogin(Request $request, Response $response, array $args) : Response {
$token = $request->getQueryParams()['token'] ?? '';
if($this->authManager->CheckToken($token)) {
$this->authManager->SetAuthState(true);
- return $response->withHeader('Location', '/')->withStatus(302);
+ return $response->withHeader('Location', '../..')->withStatus(302);
}
- return $response->withHeader('Location', '/')->withStatus(302);
+ return $response->withHeader('Location', '../..')->withStatus(302);
}
public function Logout(Request $request, Response $response, array $args) : Response
{
$this->authManager->SetAuthState(false);
return $response
- ->withHeader('Location', '/')
+ ->withHeader('Location', '../..')
->withStatus(302);
}
}
diff --git a/php/src/Cron/BackupNotification.php b/php/src/Cron/BackupNotification.php
index 17da93b2..6fbab65f 100644
--- a/php/src/Cron/BackupNotification.php
+++ b/php/src/Cron/BackupNotification.php
@@ -1,33 +1,33 @@
-get(\AIO\Docker\DockerActionManager::class);
-/** @var \AIO\ContainerDefinitionFetcher $containerDefinitionFetcher */
-$containerDefinitionFetcher = $container->get(\AIO\ContainerDefinitionFetcher::class);
-
-$id = 'nextcloud-aio-nextcloud';
-$nextcloudContainer = $containerDefinitionFetcher->GetContainerById($id);
-
-$backupExitCode = $dockerActionManger->GetBackupcontainerExitCode();
-
-if ($backupExitCode === 0) {
- if (getenv('SEND_SUCCESS_NOTIFICATIONS') === "0") {
- error_log("Daily backup successful! Only logging successful backup and not sending backup notification since that has been disabled! You can get further info by looking at the backup logs in the AIO interface.");
- } else {
- $dockerActionManger->sendNotification($nextcloudContainer, 'Daily backup successful!', 'You can get further info by looking at the backup logs in the AIO interface.');
- }
-}
-
-if ($backupExitCode > 0) {
- $dockerActionManger->sendNotification($nextcloudContainer, 'Daily backup failed!', 'You can get further info by looking at the backup logs in the AIO interface.');
-}
+get(\AIO\Docker\DockerActionManager::class);
+/** @var \AIO\ContainerDefinitionFetcher $containerDefinitionFetcher */
+$containerDefinitionFetcher = $container->get(\AIO\ContainerDefinitionFetcher::class);
+
+$id = 'nextcloud-aio-nextcloud';
+$nextcloudContainer = $containerDefinitionFetcher->GetContainerById($id);
+
+$backupExitCode = $dockerActionManager->GetBackupcontainerExitCode();
+
+if ($backupExitCode === 0) {
+ if (getenv('SEND_SUCCESS_NOTIFICATIONS') === "0") {
+ error_log("Daily backup successful! Only logging successful backup and not sending backup notification since that has been disabled! You can get further info by looking at the backup logs in the AIO interface.");
+ } else {
+ $dockerActionManager->sendNotification($nextcloudContainer, 'Daily backup successful!', 'You can get further info by looking at the backup logs in the AIO interface.');
+ }
+}
+
+if ($backupExitCode > 0) {
+ $dockerActionManager->sendNotification($nextcloudContainer, 'Daily backup failed!', 'You can get further info by looking at the backup logs in the AIO interface.');
+}
diff --git a/php/src/Cron/CheckFreeDiskSpace.php b/php/src/Cron/CheckFreeDiskSpace.php
index b462195e..1b5d2d64 100644
--- a/php/src/Cron/CheckFreeDiskSpace.php
+++ b/php/src/Cron/CheckFreeDiskSpace.php
@@ -11,8 +11,8 @@ require __DIR__ . '/../../vendor/autoload.php';
$container = \AIO\DependencyInjection::GetContainer();
-/** @var \AIO\Docker\DockerActionManager $dockerActionManger */
-$dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
+/** @var \AIO\Docker\DockerActionManager $dockerActionManager */
+$dockerActionManager = $container->get(\AIO\Docker\DockerActionManager::class);
/** @var \AIO\ContainerDefinitionFetcher $containerDefinitionFetcher */
$containerDefinitionFetcher = $container->get(\AIO\ContainerDefinitionFetcher::class);
@@ -22,5 +22,5 @@ $nextcloudContainer = $containerDefinitionFetcher->GetContainerById($id);
$df = disk_free_space(DataConst::GetDataDirectory());
if ($df !== false && (int)$df < 1024 * 1024 * 1024 * 5) {
error_log("The drive that hosts the mastercontainer volume has less than 5 GB free space. Container updates and backups might not succeed due to that!");
- $dockerActionManger->sendNotification($nextcloudContainer, 'Low on space!', 'The drive that hosts the mastercontainer volume has less than 5 GB free space. Container updates and backups might not succeed due to that!');
+ $dockerActionManager->sendNotification($nextcloudContainer, 'Low on space!', 'The drive that hosts the mastercontainer volume has less than 5 GB free space. Container updates and backups might not succeed due to that!');
}
diff --git a/php/src/Cron/OutdatedNotification.php b/php/src/Cron/OutdatedNotification.php
index e652ba3a..628f0924 100644
--- a/php/src/Cron/OutdatedNotification.php
+++ b/php/src/Cron/OutdatedNotification.php
@@ -10,17 +10,17 @@ require __DIR__ . '/../../vendor/autoload.php';
$container = \AIO\DependencyInjection::GetContainer();
-/** @var \AIO\Docker\DockerActionManager $dockerActionManger */
-$dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
+/** @var \AIO\Docker\DockerActionManager $dockerActionManager */
+$dockerActionManager = $container->get(\AIO\Docker\DockerActionManager::class);
/** @var \AIO\ContainerDefinitionFetcher $containerDefinitionFetcher */
$containerDefinitionFetcher = $container->get(\AIO\ContainerDefinitionFetcher::class);
$id = 'nextcloud-aio-nextcloud';
$nextcloudContainer = $containerDefinitionFetcher->GetContainerById($id);
-$isNextcloudImageOutdated = $dockerActionManger->isNextcloudImageOutdated();
+$isNextcloudImageOutdated = $dockerActionManager->isNextcloudImageOutdated();
if ($isNextcloudImageOutdated === true) {
- $dockerActionManger->sendNotification($nextcloudContainer, 'AIO is outdated!', 'Please open the AIO interface or ask an administrator to update it. If you do not want to do it manually each time, you can enable the daily backup feature from the AIO interface which automatically updates all containers.', '/notify-all.sh');
+ $dockerActionManager->sendNotification($nextcloudContainer, 'AIO is outdated!', 'Please open the AIO interface or ask an administrator to update it. If you do not want to do it manually each time, you can enable the daily backup feature from the AIO interface which automatically updates all containers.', '/notify-all.sh');
}
diff --git a/php/src/Cron/PullContainerImages.php b/php/src/Cron/PullContainerImages.php
new file mode 100644
index 00000000..43c87d28
--- /dev/null
+++ b/php/src/Cron/PullContainerImages.php
@@ -0,0 +1,20 @@
+get(\AIO\Controller\DockerController::class);
+
+// Pull all containers
+$dockerController->PullAllContainerImages();
diff --git a/php/src/Cron/UpdateNotification.php b/php/src/Cron/UpdateNotification.php
index e1d57f6a..2c12e2f4 100644
--- a/php/src/Cron/UpdateNotification.php
+++ b/php/src/Cron/UpdateNotification.php
@@ -10,21 +10,21 @@ require __DIR__ . '/../../vendor/autoload.php';
$container = \AIO\DependencyInjection::GetContainer();
-/** @var \AIO\Docker\DockerActionManager $dockerActionManger */
-$dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
+/** @var \AIO\Docker\DockerActionManager $dockerActionManager */
+$dockerActionManager = $container->get(\AIO\Docker\DockerActionManager::class);
/** @var \AIO\ContainerDefinitionFetcher $containerDefinitionFetcher */
$containerDefinitionFetcher = $container->get(\AIO\ContainerDefinitionFetcher::class);
$id = 'nextcloud-aio-nextcloud';
$nextcloudContainer = $containerDefinitionFetcher->GetContainerById($id);
-$isMastercontainerUpdateAvailable = $dockerActionManger->IsMastercontainerUpdateAvailable();
-$isAnyUpdateAvailable = $dockerActionManger->isAnyUpdateAvailable();
+$isMastercontainerUpdateAvailable = $dockerActionManager->IsMastercontainerUpdateAvailable();
+$isAnyUpdateAvailable = $dockerActionManager->isAnyUpdateAvailable();
if ($isMastercontainerUpdateAvailable === true) {
- $dockerActionManger->sendNotification($nextcloudContainer, 'Mastercontainer update available!', 'Please open your AIO interface to update it. If you do not want to do it manually each time, you can enable the daily backup feature from the AIO interface which also automatically updates the mastercontainer.');
+ $dockerActionManager->sendNotification($nextcloudContainer, 'Mastercontainer update available!', 'Please open your AIO interface to update it. If you do not want to do it manually each time, you can enable the daily backup feature from the AIO interface which also automatically updates the mastercontainer.');
}
if ($isAnyUpdateAvailable === true) {
- $dockerActionManger->sendNotification($nextcloudContainer, 'Container updates available!', 'Please open your AIO interface to update them. If you do not want to do it manually each time, you can enable the daily backup feature from the AIO interface which also automatically updates your containers and your Nextcloud apps.');
+ $dockerActionManager->sendNotification($nextcloudContainer, 'Container updates available!', 'Please open your AIO interface to update them. If you do not want to do it manually each time, you can enable the daily backup feature from the AIO interface which also automatically updates your containers and your Nextcloud apps.');
}
diff --git a/php/src/Data/ConfigurationManager.php b/php/src/Data/ConfigurationManager.php
index bfc59f7c..320bc477 100644
--- a/php/src/Data/ConfigurationManager.php
+++ b/php/src/Data/ConfigurationManager.php
@@ -7,11 +7,13 @@ use AIO\Controller\DockerController;
class ConfigurationManager
{
+ private array $secrets = [];
+
public function GetConfig() : array
{
if(file_exists(DataConst::GetConfigFile()))
{
- $configContent = file_get_contents(DataConst::GetConfigFile());
+ $configContent = (string)file_get_contents(DataConst::GetConfigFile());
return json_decode($configContent, true, 512, JSON_THROW_ON_ERROR);
}
@@ -50,13 +52,15 @@ class ConfigurationManager
return $config['secrets'][$secretId];
}
- public function GetSecret(string $secretId) : string {
- $config = $this->GetConfig();
- if(!isset($config['secrets'][$secretId])) {
- $config['secrets'][$secretId] = "";
+ public function GetRegisteredSecret(string $secretId) : string {
+ if ($this->secrets[$secretId]) {
+ return $this->GetAndGenerateSecret($secretId);
}
+ throw new \Exception("The secret " . $secretId . " was not registered. Please check if it is defined in secrets of containers.json.");
+ }
- return $config['secrets'][$secretId];
+ public function RegisterSecret(string $secretId) : void {
+ $this->secrets[$secretId] = true;
}
private function DoubleSafeBackupSecret(string $borgBackupPassword) : void {
@@ -76,10 +80,7 @@ class ConfigurationManager
return '';
}
- $content = file_get_contents(DataConst::GetBackupArchivesList());
- if ($content === '') {
- return '';
- }
+ $content = (string)file_get_contents(DataConst::GetBackupArchivesList());
$lastBackupLines = explode("\n", $content);
$lastBackupLine = "";
@@ -104,10 +105,7 @@ class ConfigurationManager
return [];
}
- $content = file_get_contents(DataConst::GetBackupArchivesList());
- if ($content === '') {
- return [];
- }
+ $content = (string)file_get_contents(DataConst::GetBackupArchivesList());
$backupLines = explode("\n", $content);
$backupTimes = [];
@@ -211,7 +209,7 @@ class ConfigurationManager
public function SetFulltextsearchEnabledState(int $value) : void {
// Elasticsearch does not work on kernels without seccomp anymore. See https://github.com/nextcloud/all-in-one/discussions/5768
- if ($this->GetCollaboraSeccompDisabledState() === 'true') {
+ if ($this->isSeccompDisabled()) {
$value = 0;
}
@@ -282,11 +280,6 @@ class ConfigurationManager
$value = 0;
}
- // Currently only works on x64. See https://github.com/nextcloud/nextcloud-talk-recording/issues/17
- if (!$this->isx64Platform()) {
- $value = 0;
- }
-
$config = $this->GetConfig();
$config['isTalkRecordingEnabled'] = $value;
$this->WriteConfig($config);
@@ -295,7 +288,7 @@ class ConfigurationManager
/**
* @throws InvalidSettingConfigurationException
*/
- public function SetDomain(string $domain) : void {
+ public function SetDomain(string $domain, bool $skipDomainValidation) : void {
// Validate that at least one dot is contained
if (!str_contains($domain, '.')) {
throw new InvalidSettingConfigurationException("Domain must contain at least one dot!");
@@ -322,8 +315,9 @@ class ConfigurationManager
}
// Skip domain validation if opted in to do so
- if (!$this->shouldDomainValidationBeSkipped()) {
-
+ if ($this->shouldDomainValidationBeSkipped($skipDomainValidation)) {
+ error_log('Skipping domain validation');
+ } else {
$dnsRecordIP = gethostbyname($domain);
if ($dnsRecordIP === $domain) {
$dnsRecordIP = '';
@@ -357,7 +351,7 @@ class ConfigurationManager
if ($connection) {
fclose($connection);
} else {
- throw new InvalidSettingConfigurationException("The domain is not reachable on Port 443 from within this container. Have you opened port 443/tcp in your router/firewall? If yes is the problem most likely that the router or firewall forbids local access to your domain. You can work around that by setting up a local DNS-server.");
+ throw new InvalidSettingConfigurationException("The domain is not reachable on Port 443 from within this container. Have you opened port 443/tcp in your router/firewall? If yes is the problem most likely that the router or firewall forbids local access to your domain. Or in other words: NAT loopback (Hairpinning) does not seem to work in your network. You can work around that by setting up a local DNS server and utilizing Split-Brain-DNS and configuring the daemon.json file of your docker daemon to use the local DNS server.");
}
// Get Instance ID
@@ -372,6 +366,9 @@ class ConfigurationManager
// Check if response is correct
$ch = curl_init();
+ if ($ch === false) {
+ throw new InvalidSettingConfigurationException('Could not init curl! Please check the logs!');
+ }
$testUrl = $protocol . $domain . ':443';
curl_setopt($ch, CURLOPT_URL, $testUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@@ -389,7 +386,7 @@ class ConfigurationManager
if ($port === '443') {
$notice .= " If you should be using Cloudflare, make sure to disable the Cloudflare Proxy feature as it might block the domain validation. Same for any other firewall or service that blocks unencrypted access on port 443.";
} else {
- error_log('Please follow https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#6-how-to-debug-things in order to debug things!');
+ error_log('Please follow https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#how-to-debug in order to debug things!');
}
throw new InvalidSettingConfigurationException($notice);
}
@@ -429,6 +426,12 @@ class ConfigurationManager
return $config['backup-mode'];
}
+ public function SetBackupMode(string $mode) : void {
+ $config = $this->GetConfig();
+ $config['backup-mode'] = $mode;
+ $this->WriteConfig($config);
+ }
+
public function GetSelectedRestoreTime() : string {
$config = $this->GetConfig();
if(!isset($config['selected-restore-time'])) {
@@ -509,11 +512,19 @@ class ConfigurationManager
}
}
- public function DeleteBorgBackupLocationVars() : void {
+ public function DeleteBorgBackupLocationItems() : void {
+ // Delete the variables
$config = $this->GetConfig();
$config['borg_backup_host_location'] = '';
$config['borg_remote_repo'] = '';
$this->WriteConfig($config);
+
+ // Also delete the borg config file to be able to start over
+ if (file_exists(DataConst::GetBackupKeyFile())) {
+ if (unlink(DataConst::GetBackupKeyFile())) {
+ error_log('borg.config file deleted to be able to start over.');
+ }
+ }
}
/**
@@ -576,6 +587,15 @@ class ConfigurationManager
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
}
+ public function GetTurnDomain() : string {
+ $config = $this->GetConfig();
+ if(!isset($config['turn_domain'])) {
+ $config['turn_domain'] = '';
+ }
+
+ return $config['turn_domain'];
+ }
+
/**
* @throws InvalidSettingConfigurationException
*/
@@ -637,7 +657,7 @@ class ConfigurationManager
return "";
}
- return trim(file_get_contents(DataConst::GetBackupPublicKey()));
+ return trim((string)file_get_contents(DataConst::GetBackupPublicKey()));
}
public function GetBorgRestorePassword() : string {
@@ -661,15 +681,6 @@ class ConfigurationManager
return false;
}
- public function GetBorgBackupMode() : string {
- $config = $this->GetConfig();
- if(!isset($config['backup-mode'])) {
- $config['backup-mode'] = '';
- }
-
- return $config['backup-mode'];
- }
-
public function GetNextcloudMount() : string {
$envVariableName = 'NEXTCLOUD_MOUNT';
$configName = 'nextcloud_mount';
@@ -754,7 +765,7 @@ class ConfigurationManager
public function GetCollaboraSeccompPolicy() : string {
$defaultString = '--o:security.seccomp=';
- if ($this->GetCollaboraSeccompDisabledState() !== 'true') {
+ if (!$this->isSeccompDisabled()) {
return $defaultString . 'true';
}
return $defaultString . 'false';
@@ -767,6 +778,13 @@ class ConfigurationManager
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
}
+ public function isSeccompDisabled() : bool {
+ if ($this->GetCollaboraSeccompDisabledState() === 'true') {
+ return true;
+ }
+ return false;
+ }
+
/**
* @throws InvalidSettingConfigurationException
*/
@@ -796,7 +814,7 @@ class ConfigurationManager
if (!file_exists(DataConst::GetDailyBackupTimeFile())) {
return '';
}
- $dailyBackupFile = file_get_contents(DataConst::GetDailyBackupTimeFile());
+ $dailyBackupFile = (string)file_get_contents(DataConst::GetDailyBackupTimeFile());
$dailyBackupFileArray = explode("\n", $dailyBackupFile);
return $dailyBackupFileArray[0];
}
@@ -805,7 +823,7 @@ class ConfigurationManager
if (!file_exists(DataConst::GetDailyBackupTimeFile())) {
return false;
}
- $dailyBackupFile = file_get_contents(DataConst::GetDailyBackupTimeFile());
+ $dailyBackupFile = (string)file_get_contents(DataConst::GetDailyBackupTimeFile());
$dailyBackupFileArray = explode("\n", $dailyBackupFile);
if (isset($dailyBackupFileArray[1]) && $dailyBackupFileArray[1] === 'automaticUpdatesAreNotEnabled') {
return false;
@@ -856,8 +874,7 @@ class ConfigurationManager
if (!file_exists(DataConst::GetAdditionalBackupDirectoriesFile())) {
return '';
}
- $additionalBackupDirectories = file_get_contents(DataConst::GetAdditionalBackupDirectoriesFile());
- return $additionalBackupDirectories;
+ return (string)file_get_contents(DataConst::GetAdditionalBackupDirectoriesFile());
}
public function GetAdditionalBackupDirectoriesArray() : array {
@@ -906,8 +923,8 @@ class ConfigurationManager
$this->WriteConfig($config);
}
- public function shouldDomainValidationBeSkipped() : bool {
- if (getenv('SKIP_DOMAIN_VALIDATION') === 'true') {
+ public function shouldDomainValidationBeSkipped(bool $skipDomainValidation) : bool {
+ if ($skipDomainValidation || getenv('SKIP_DOMAIN_VALIDATION') === 'true') {
return true;
}
return false;
@@ -979,6 +996,13 @@ class ConfigurationManager
return $config['collabora_additional_options'];
}
+ public function isCollaboraSubscriptionEnabled() : bool {
+ if (str_contains($this->GetAdditionalCollaboraOptions(), '--o:support_key=')) {
+ return true;
+ }
+ return false;
+ }
+
public function DeleteAdditionalCollaboraOptions() : void {
$config = $this->GetConfig();
$config['collabora_additional_options'] = '';
@@ -1041,7 +1065,7 @@ class ConfigurationManager
apcu_add($filePath, $fileContents);
}
}
- $json = is_string($fileContents) ? json_decode($fileContents, true) : false;
+ $json = is_string($fileContents) ? json_decode($fileContents, true, 512, JSON_THROW_ON_ERROR) : false;
if(is_array($json) && is_array($json['aio_services_v1'])) {
foreach ($json['aio_services_v1'] as $service) {
$documentation = is_string($service['documentation']) ? $service['documentation'] : '';
diff --git a/php/src/Data/DataConst.php b/php/src/Data/DataConst.php
index 4f697325..9111a98a 100644
--- a/php/src/Data/DataConst.php
+++ b/php/src/Data/DataConst.php
@@ -8,7 +8,7 @@ class DataConst {
return '/mnt/docker-aio-config/data/';
}
- return realpath(__DIR__ . '/../../data/');
+ return (string)realpath(__DIR__ . '/../../data/');
}
public static function GetSessionDirectory() : string {
@@ -16,7 +16,7 @@ class DataConst {
return '/mnt/docker-aio-config/session/';
}
- return realpath(__DIR__ . '/../../session/');
+ return (string)realpath(__DIR__ . '/../../session/');
}
public static function GetConfigFile() : string {
@@ -56,6 +56,14 @@ class DataConst {
}
public static function GetCommunityContainersDirectory() : string {
- return realpath(__DIR__ . '/../../../community-containers/');
+ return (string)realpath(__DIR__ . '/../../../community-containers/');
+ }
+
+ public static function GetCollaboraSeccompProfilePath() : string {
+ return (string)realpath(__DIR__ . '/../../cool-seccomp-profile.json');
+ }
+
+ public static function GetContainersDefinitionPath() : string {
+ return (string)realpath(__DIR__ . '/../../containers.json');
}
}
diff --git a/php/src/Docker/DockerActionManager.php b/php/src/Docker/DockerActionManager.php
index b3560968..fb3701a4 100644
--- a/php/src/Docker/DockerActionManager.php
+++ b/php/src/Docker/DockerActionManager.php
@@ -7,12 +7,13 @@ use AIO\Container\ContainerState;
use AIO\Container\VersionState;
use AIO\ContainerDefinitionFetcher;
use AIO\Data\ConfigurationManager;
+use AIO\Data\DataConst;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use http\Env\Response;
readonly class DockerActionManager {
- private const string API_VERSION = 'v1.41';
+ private const string API_VERSION = 'v1.44';
private Client $guzzleClient;
public function __construct(
@@ -25,19 +26,25 @@ readonly class DockerActionManager {
}
private function BuildApiUrl(string $url): string {
- return sprintf('http://127.0.0.1/%s/%s', self::API_VERSION, $url);
+ $apiVersion = getenv('DOCKER_API_VERSION');
+ if ($apiVersion === false || empty($apiVersion)) {
+ $apiVersion = self::API_VERSION;
+ } else {
+ $apiVersion = 'v'. $apiVersion;
+ }
+ return sprintf('http://127.0.0.1/%s/%s', $apiVersion, $url);
}
private function BuildImageName(Container $container): string {
- $tag = $container->GetImageTag();
+ $tag = $container->imageTag;
if ($tag === '%AIO_CHANNEL%') {
$tag = $this->GetCurrentChannel();
}
- return $container->GetContainerName() . ':' . $tag;
+ return $container->containerName . ':' . $tag;
}
public function GetContainerRunningState(Container $container): ContainerState {
- $url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
+ $url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->identifier)));
try {
$response = $this->guzzleClient->get($url);
} catch (RequestException $e) {
@@ -47,7 +54,7 @@ readonly class DockerActionManager {
throw $e;
}
- $responseBody = json_decode((string)$response->getBody(), true);
+ $responseBody = json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
if ($responseBody['State']['Running'] === true) {
return ContainerState::Running;
@@ -57,7 +64,7 @@ readonly class DockerActionManager {
}
public function GetContainerRestartingState(Container $container): ContainerState {
- $url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
+ $url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->identifier)));
try {
$response = $this->guzzleClient->get($url);
} catch (RequestException $e) {
@@ -67,7 +74,7 @@ readonly class DockerActionManager {
throw $e;
}
- $responseBody = json_decode((string)$response->getBody(), true);
+ $responseBody = json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
if ($responseBody['State']['Restarting'] === true) {
return ContainerState::Restarting;
@@ -77,16 +84,16 @@ readonly class DockerActionManager {
}
public function GetContainerUpdateState(Container $container): VersionState {
- $tag = $container->GetImageTag();
+ $tag = $container->imageTag;
if ($tag === '%AIO_CHANNEL%') {
$tag = $this->GetCurrentChannel();
}
- $runningDigests = $this->GetRepoDigestsOfContainer($container->GetIdentifier());
+ $runningDigests = $this->GetRepoDigestsOfContainer($container->identifier);
if ($runningDigests === null) {
return VersionState::Different;
}
- $remoteDigest = $this->GetLatestDigestOfTag($container->GetContainerName(), $tag);
+ $remoteDigest = $this->GetLatestDigestOfTag($container->containerName, $tag);
if ($remoteDigest === null) {
return VersionState::Equal;
}
@@ -105,8 +112,8 @@ readonly class DockerActionManager {
return $runningState;
}
- $containerName = $container->GetIdentifier();
- $internalPort = $container->GetInternalPort();
+ $containerName = $container->identifier;
+ $internalPort = $container->internalPorts;
if ($internalPort === '%APACHE_PORT%') {
$internalPort = $this->configurationManager->GetApachePort();
} elseif ($internalPort === '%TALK_PORT%') {
@@ -127,7 +134,7 @@ readonly class DockerActionManager {
}
public function DeleteContainer(Container $container): void {
- $url = $this->BuildApiUrl(sprintf('containers/%s?v=true', urlencode($container->GetIdentifier())));
+ $url = $this->BuildApiUrl(sprintf('containers/%s?v=true', urlencode($container->identifier)));
try {
$this->guzzleClient->delete($url);
} catch (RequestException $e) {
@@ -148,28 +155,28 @@ readonly class DockerActionManager {
$response = "";
$separator = "\r\n";
$line = strtok($responseBody, $separator);
- $response = substr($line, 8) . $separator;
+ $response = substr((string)$line, 8) . $separator;
while ($line !== false) {
$line = strtok($separator);
- $response .= substr($line, 8) . $separator;
+ $response .= substr((string)$line, 8) . $separator;
}
return $response;
}
public function StartContainer(Container $container): void {
- $url = $this->BuildApiUrl(sprintf('containers/%s/start', urlencode($container->GetIdentifier())));
+ $url = $this->BuildApiUrl(sprintf('containers/%s/start', urlencode($container->identifier)));
try {
$this->guzzleClient->post($url);
} catch (RequestException $e) {
- throw new \Exception("Could not start container " . $container->GetIdentifier() . ": " . $e->getResponse()?->getBody()->getContents());
+ throw new \Exception("Could not start container " . $container->identifier . ": " . $e->getResponse()?->getBody()->getContents());
}
}
public function CreateVolumes(Container $container): void {
$url = $this->BuildApiUrl('volumes/create');
- foreach ($container->GetVolumes()->GetVolumes() as $volume) {
+ foreach ($container->volumes->GetVolumes() as $volume) {
$forbiddenChars = [
'/',
];
@@ -195,9 +202,9 @@ readonly class DockerActionManager {
public function CreateContainer(Container $container): void {
$volumes = [];
- foreach ($container->GetVolumes()->GetVolumes() as $volume) {
+ foreach ($container->volumes->GetVolumes() as $volume) {
// // NEXTCLOUD_MOUNT gets added via bind-mount later on
- // if ($container->GetIdentifier() === 'nextcloud-aio-nextcloud') {
+ // if ($container->identifier === 'nextcloud-aio-nextcloud') {
// if ($volume->name === $this->configurationManager->GetNextcloudMount()) {
// continue;
// }
@@ -221,210 +228,36 @@ readonly class DockerActionManager {
$requestBody['HostConfig']['Binds'] = $volumes;
}
- foreach ($container->GetSecrets() as $secret) {
- $this->configurationManager->GetAndGenerateSecret($secret);
- }
-
- $aioVariables = $container->GetAioVariables()->GetVariables();
+ $aioVariables = $container->aioVariables->GetVariables();
foreach ($aioVariables as $variable) {
$config = $this->configurationManager->GetConfig();
+ $variable = $this->replaceEnvPlaceholders($variable);
$variableArray = explode('=', $variable);
$config[$variableArray[0]] = $variableArray[1];
$this->configurationManager->WriteConfig($config);
sleep(1);
}
- $envs = $container->GetEnvironmentVariables()->GetVariables();
+ $envs = $container->containerEnvironmentVariables->GetVariables();
// Special thing for the nextcloud container
- if ($container->GetIdentifier() === 'nextcloud-aio-nextcloud') {
+ if ($container->identifier === 'nextcloud-aio-nextcloud') {
$envs[] = $this->GetAllNextcloudExecCommands();
}
foreach ($envs as $key => $env) {
- // TODO: This whole block below is a hack and needs to get reworked in order to support multiple substitutions per line by default for all envs
- if (str_starts_with($env, 'extra_params=')) {
- $env = str_replace('%COLLABORA_SECCOMP_POLICY%', $this->configurationManager->GetCollaboraSeccompPolicy(), $env);
- $env = str_replace('%NC_DOMAIN%', $this->configurationManager->GetDomain(), $env);
- $envs[$key] = $env;
- continue;
- }
-
- // Original implementation
- $patterns = ['/%(.*)%/'];
-
- if (preg_match($patterns[0], $env, $out) === 1) {
- $replacements = array();
-
- if ($out[1] === 'NC_DOMAIN') {
- $replacements[1] = $this->configurationManager->GetDomain();
- } elseif ($out[1] === 'NC_BASE_DN') {
- $replacements[1] = $this->configurationManager->GetBaseDN();
- } elseif ($out[1] === 'AIO_TOKEN') {
- $replacements[1] = $this->configurationManager->GetToken();
- } elseif ($out[1] === 'BORGBACKUP_REMOTE_REPO') {
- $replacements[1] = $this->configurationManager->GetBorgRemoteRepo();
- } elseif ($out[1] === 'BORGBACKUP_MODE') {
- $replacements[1] = $this->configurationManager->GetBackupMode();
- } elseif ($out[1] === 'AIO_URL') {
- $replacements[1] = $this->configurationManager->GetAIOURL();
- } elseif ($out[1] === 'SELECTED_RESTORE_TIME') {
- $replacements[1] = $this->configurationManager->GetSelectedRestoreTime();
- } elseif ($out[1] === 'RESTORE_EXCLUDE_PREVIEWS') {
- $replacements[1] = $this->configurationManager->GetRestoreExcludePreviews();
- } elseif ($out[1] === 'APACHE_PORT') {
- $replacements[1] = $this->configurationManager->GetApachePort();
- } elseif ($out[1] === 'TALK_PORT') {
- $replacements[1] = $this->configurationManager->GetTalkPort();
- } elseif ($out[1] === 'NEXTCLOUD_MOUNT') {
- $replacements[1] = $this->configurationManager->GetNextcloudMount();
- } elseif ($out[1] === 'BACKUP_RESTORE_PASSWORD') {
- $replacements[1] = $this->configurationManager->GetBorgRestorePassword();
- } elseif ($out[1] === 'CLAMAV_ENABLED') {
- if ($this->configurationManager->isClamavEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'TALK_RECORDING_ENABLED') {
- if ($this->configurationManager->isTalkRecordingEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'ONLYOFFICE_ENABLED') {
- if ($this->configurationManager->isOnlyofficeEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'COLLABORA_ENABLED') {
- if ($this->configurationManager->isCollaboraEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'TALK_ENABLED') {
- if ($this->configurationManager->isTalkEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'UPDATE_NEXTCLOUD_APPS') {
- if ($this->configurationManager->isDailyBackupRunning() && $this->configurationManager->areAutomaticUpdatesEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'TIMEZONE') {
- if ($this->configurationManager->GetTimezone() === '') {
- $replacements[1] = 'Etc/UTC';
- } else {
- $replacements[1] = $this->configurationManager->GetTimezone();
- }
- } elseif ($out[1] === 'COLLABORA_DICTIONARIES') {
- if ($this->configurationManager->GetCollaboraDictionaries() === '') {
- $replacements[1] = 'de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru';
- } else {
- $replacements[1] = $this->configurationManager->GetCollaboraDictionaries();
- }
- } elseif ($out[1] === 'IMAGINARY_ENABLED') {
- if ($this->configurationManager->isImaginaryEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'FULLTEXTSEARCH_ENABLED') {
- if ($this->configurationManager->isFulltextsearchEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'DOCKER_SOCKET_PROXY_ENABLED') {
- if ($this->configurationManager->isDockerSocketProxyEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'NEXTCLOUD_UPLOAD_LIMIT') {
- $replacements[1] = $this->configurationManager->GetNextcloudUploadLimit();
- } elseif ($out[1] === 'NEXTCLOUD_MEMORY_LIMIT') {
- $replacements[1] = $this->configurationManager->GetNextcloudMemoryLimit();
- } elseif ($out[1] === 'NEXTCLOUD_MAX_TIME') {
- $replacements[1] = $this->configurationManager->GetNextcloudMaxTime();
- } elseif ($out[1] === 'BORG_RETENTION_POLICY') {
- $replacements[1] = $this->configurationManager->GetBorgRetentionPolicy();
- } elseif ($out[1] === 'FULLTEXTSEARCH_JAVA_OPTIONS') {
- $replacements[1] = $this->configurationManager->GetFulltextsearchJavaOptions();
- } elseif ($out[1] === 'NEXTCLOUD_TRUSTED_CACERTS_DIR') {
- $replacements[1] = $this->configurationManager->GetTrustedCacertsDir();
- } elseif ($out[1] === 'ADDITIONAL_DIRECTORIES_BACKUP') {
- if ($this->configurationManager->GetAdditionalBackupDirectoriesString() !== '') {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'BORGBACKUP_HOST_LOCATION') {
- $replacements[1] = $this->configurationManager->GetBorgBackupHostLocation();
- } elseif ($out[1] === 'APACHE_MAX_SIZE') {
- $replacements[1] = $this->configurationManager->GetApacheMaxSize();
- } elseif ($out[1] === 'COLLABORA_SECCOMP_POLICY') {
- $replacements[1] = $this->configurationManager->GetCollaboraSeccompPolicy();
- } elseif ($out[1] === 'NEXTCLOUD_STARTUP_APPS') {
- $replacements[1] = $this->configurationManager->GetNextcloudStartupApps();
- } elseif ($out[1] === 'NEXTCLOUD_ADDITIONAL_APKS') {
- $replacements[1] = $this->configurationManager->GetNextcloudAdditionalApks();
- } elseif ($out[1] === 'NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS') {
- $replacements[1] = $this->configurationManager->GetNextcloudAdditionalPhpExtensions();
- } elseif ($out[1] === 'INSTALL_LATEST_MAJOR') {
- if ($this->configurationManager->shouldLatestMajorGetInstalled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } elseif ($out[1] === 'REMOVE_DISABLED_APPS') {
- if ($this->configurationManager->shouldDisabledAppsGetRemoved()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- // Allow to get local ip-address of database container which allows to talk to it even in host mode (the container that requires this needs to be started first then)
- } elseif ($out[1] === 'AIO_DATABASE_HOST') {
- $replacements[1] = gethostbyname('nextcloud-aio-database');
- // Allow to get local ip-address of caddy container and add it to trusted proxies automatically
- } elseif ($out[1] === 'CADDY_IP_ADDRESS') {
- $replacements[1] = '';
- $communityContainers = $this->configurationManager->GetEnabledCommunityContainers();
- if (in_array('caddy', $communityContainers, true)) {
- $replacements[1] = gethostbyname('nextcloud-aio-caddy');
- }
- } elseif ($out[1] === 'WHITEBOARD_ENABLED') {
- if ($this->configurationManager->isWhiteboardEnabled()) {
- $replacements[1] = 'yes';
- } else {
- $replacements[1] = '';
- }
- } else {
- $secret = $this->configurationManager->GetSecret($out[1]);
- if ($secret === "") {
- throw new \Exception("The secret " . $out[1] . " is empty. Cannot substitute its value. Please check if it is defined in secrets of containers.json.");
- }
- $replacements[1] = $secret;
- }
-
- $envs[$key] = preg_replace($patterns, $replacements, $env);
- }
+ $envs[$key] = $this->replaceEnvPlaceholders($env);
}
if (count($envs) > 0) {
$requestBody['Env'] = $envs;
}
- $requestBody['HostConfig']['RestartPolicy']['Name'] = $container->GetRestartPolicy();
+ $requestBody['HostConfig']['RestartPolicy']['Name'] = $container->restartPolicy;
- $requestBody['HostConfig']['ReadonlyRootfs'] = $container->GetReadOnlySetting();
+ $requestBody['HostConfig']['ReadonlyRootfs'] = $container->readOnlyRootFs;
$exposedPorts = [];
- if ($container->GetInternalPort() !== 'host') {
- foreach ($container->GetPorts()->GetPorts() as $value) {
+ if ($container->internalPorts !== 'host') {
+ foreach ($container->ports->GetPorts() as $value) {
$port = $value->port;
$protocol = $value->protocol;
if ($port === '%APACHE_PORT%') {
@@ -446,7 +279,7 @@ readonly class DockerActionManager {
if (count($exposedPorts) > 0) {
$requestBody['ExposedPorts'] = $exposedPorts;
- foreach ($container->GetPorts()->GetPorts() as $value) {
+ foreach ($container->ports->GetPorts() as $value) {
$port = $value->port;
$protocol = $value->protocol;
if ($port === '%APACHE_PORT%') {
@@ -457,6 +290,10 @@ readonly class DockerActionManager {
}
} else if ($port === '%TALK_PORT%') {
$port = $this->configurationManager->GetTalkPort();
+ // Skip publishing talk tcp port if it is set to 443
+ if ($port === '443' && $protocol === 'tcp') {
+ continue;
+ }
}
$ipBinding = $value->ipBinding;
if ($ipBinding === '%APACHE_IP_BINDING%') {
@@ -477,7 +314,7 @@ readonly class DockerActionManager {
}
$devices = [];
- foreach ($container->GetDevices() as $device) {
+ foreach ($container->devices as $device) {
if ($device === '/dev/dri' && !$this->configurationManager->isDriDeviceEnabled()) {
continue;
}
@@ -488,7 +325,7 @@ readonly class DockerActionManager {
$requestBody['HostConfig']['Devices'] = $devices;
}
- if ($container->isNvidiaGpuEnabled() && $this->configurationManager->isNvidiaGpuEnabled()) {
+ if ($container->enableNvidiaGpu && $this->configurationManager->isNvidiaGpuEnabled()) {
$requestBody['HostConfig']['Runtime'] = 'nvidia';
$requestBody['HostConfig']['DeviceRequests'] = [
[
@@ -499,13 +336,13 @@ readonly class DockerActionManager {
];
}
- $shmSize = $container->GetShmSize();
+ $shmSize = $container->shmSize;
if ($shmSize > 0) {
$requestBody['HostConfig']['ShmSize'] = $shmSize;
}
$tmpfs = [];
- foreach ($container->GetTmpfs() as $tmp) {
+ foreach ($container->tmpfs as $tmp) {
$mode = "";
if (str_contains($tmp, ':')) {
$mode = explode(':', $tmp)[1];
@@ -517,9 +354,14 @@ readonly class DockerActionManager {
$requestBody['HostConfig']['Tmpfs'] = $tmpfs;
}
- $requestBody['HostConfig']['Init'] = $container->GetInit();
+ $requestBody['HostConfig']['Init'] = $container->init;
- $capAdds = $container->GetCapAdds();
+ $maxShutDownTime = $container->maxShutdownTime;
+ if ($maxShutDownTime > 0) {
+ $requestBody['StopTimeout'] = $maxShutDownTime;
+ }
+
+ $capAdds = $container->capAdd;
if (count($capAdds) > 0) {
$requestBody['HostConfig']['CapAdd'] = $capAdds;
}
@@ -531,14 +373,14 @@ readonly class DockerActionManager {
// Disable SELinux for AIO containers so that it does not break them
$requestBody['HostConfig']['SecurityOpt'] = ["label:disable"];
- if ($container->isApparmorUnconfined()) {
+ if ($container->apparmorUnconfined) {
$requestBody['HostConfig']['SecurityOpt'] = ["apparmor:unconfined", "label:disable"];
}
$mounts = [];
// Special things for the backup container which should not be exposed in the containers.json
- if (str_starts_with($container->GetIdentifier(), 'nextcloud-aio-borgbackup')) {
+ if (str_starts_with($container->identifier, 'nextcloud-aio-borgbackup')) {
// Additional backup directories
foreach ($this->getAllBackupVolumes() as $additionalBackupVolumes) {
if ($additionalBackupVolumes !== '') {
@@ -547,7 +389,7 @@ readonly class DockerActionManager {
}
// Make volumes read only in case of borgbackup container. The viewer makes them writeable
- $isReadOnly = $container->GetIdentifier() === 'nextcloud-aio-borgbackup';
+ $isReadOnly = $container->identifier === 'nextcloud-aio-borgbackup';
foreach ($this->configurationManager->GetAdditionalBackupDirectoriesArray() as $additionalBackupDirectories) {
if ($additionalBackupDirectories !== '') {
@@ -558,23 +400,33 @@ readonly class DockerActionManager {
}
}
}
- // Special things for the talk container which should not be exposed in the containers.json
- } elseif ($container->GetIdentifier() === 'nextcloud-aio-talk') {
- // This is needed due to a bug in libwebsockets which cannot handle unlimited ulimits
+
+ // Special things for the talk container which should not be exposed in the containers.json
+ } elseif ($container->identifier === 'nextcloud-aio-talk') {
+ // This is needed due to a bug in libwebsockets used in Janus which cannot handle unlimited ulimits
$requestBody['HostConfig']['Ulimits'] = [["Name" => "nofile", "Hard" => 200000, "Soft" => 200000]];
// // Special things for the nextcloud container which should not be exposed in the containers.json
- // } elseif ($container->GetIdentifier() === 'nextcloud-aio-nextcloud') {
- // foreach ($container->GetVolumes()->GetVolumes() as $volume) {
+ // } elseif ($container->identifier === 'nextcloud-aio-nextcloud') {
+ // foreach ($container->volumes->GetVolumes() as $volume) {
// if ($volume->name !== $this->configurationManager->GetNextcloudMount()) {
// continue;
// }
// $mounts[] = ["Type" => "bind", "Source" => $volume->name, "Target" => $volume->mountPoint, "ReadOnly" => !$volume->isWritable, "BindOptions" => [ "Propagation" => "rshared"]];
// }
- // Special things for the caddy community container
- } elseif ($container->GetIdentifier() === 'nextcloud-aio-caddy') {
+
+ // Special things for the caddy community container
+ } elseif ($container->identifier === 'nextcloud-aio-caddy') {
$requestBody['HostConfig']['ExtraHosts'] = ['host.docker.internal:host-gateway'];
- // Special things for the collabora container which should not be exposed in the containers.json
- } elseif ($container->GetIdentifier() === 'nextcloud-aio-collabora') {
+
+ // Special things for the collabora container which should not be exposed in the containers.json
+ } elseif ($container->identifier === 'nextcloud-aio-collabora') {
+ if (!$this->configurationManager->isSeccompDisabled()) {
+ // Load reference seccomp profile for collabora
+ $seccompProfile = (string)file_get_contents(DataConst::GetCollaboraSeccompProfilePath());
+ $requestBody['HostConfig']['SecurityOpt'] = ["label:disable", "seccomp=$seccompProfile"];
+ }
+
+ // Additional Collabora options
if ($this->configurationManager->GetAdditionalCollaboraOptions() !== '') {
$requestBody['Cmd'] = [$this->configurationManager->GetAdditionalCollaboraOptions()];
}
@@ -585,12 +437,14 @@ readonly class DockerActionManager {
}
// All AIO-managed containers should not be updated externally via watchtower but gracefully by AIO's backup and update feature.
- $requestBody['Labels'] = ["com.centurylinklabs.watchtower.enable" => "false", "org.label-schema.vendor" => "Nextcloud"];
+ // Also DIUN should not send update notifications. See https://crazymax.dev/diun/providers/docker/#docker-labels
+ // Additionally set a default org.label-schema.vendor and com.docker.compose.project
+ $requestBody['Labels'] = ["com.centurylinklabs.watchtower.enable" => "false", "wud.watch" => "false", "diun.enable" => "false", "org.label-schema.vendor" => "Nextcloud", "com.docker.compose.project" => "nextcloud-aio"];
// Containers should have a fixed host name. See https://github.com/nextcloud/all-in-one/discussions/6589
- $requestBody['Hostname'] = $container->GetIdentifier();
+ $requestBody['Hostname'] = $container->identifier;
- $url = $this->BuildApiUrl('containers/create?name=' . $container->GetIdentifier());
+ $url = $this->BuildApiUrl('containers/create?name=' . $container->identifier);
try {
$this->guzzleClient->request(
'POST',
@@ -600,18 +454,18 @@ readonly class DockerActionManager {
]
);
} catch (RequestException $e) {
- throw new \Exception("Could not create container " . $container->GetIdentifier() . ": " . $e->getResponse()?->getBody()->getContents());
+ throw new \Exception("Could not create container " . $container->identifier . ": " . $e->getResponse()?->getBody()->getContents());
}
}
public function isRegistryReachable(Container $container): bool {
- $tag = $container->GetImageTag();
+ $tag = $container->imageTag;
if ($tag === '%AIO_CHANNEL%') {
$tag = $this->GetCurrentChannel();
}
- $remoteDigest = $this->GetLatestDigestOfTag($container->GetContainerName(), $tag);
+ $remoteDigest = $this->GetLatestDigestOfTag($container->containerName, $tag);
if ($remoteDigest === null) {
return false;
@@ -620,7 +474,30 @@ readonly class DockerActionManager {
}
}
- public function PullImage(Container $container): void {
+ public function PullImage(Container $container, bool $pullImage = true): void {
+
+ // Skip database image pull if the last shutdown was not clean
+ if ($container->identifier === 'nextcloud-aio-database') {
+ if ($this->GetDatabasecontainerExitCode() > 0) {
+ $pullImage = false;
+ error_log('Not pulling the latest database image because the container was not correctly shut down.');
+ }
+ }
+
+ // Check if registry is reachable in order to make sure that we do not try to pull an image if it is down
+ // and try to mitigate issues that are arising due to that
+ if ($pullImage) {
+ if (!$this->isRegistryReachable($container)) {
+ $pullImage = false;
+ error_log('Not pulling the ' . $container->containerName . ' image for the ' . $container->identifier . ' container because the registry does not seem to be reachable.');
+ }
+ }
+
+ // Do not continue if $pullImage is false
+ if (!$pullImage) {
+ return;
+ }
+
$imageName = $this->BuildImageName($container);
$encodedImageName = urlencode($imageName);
$url = $this->BuildApiUrl(sprintf('images/create?fromImage=%s', $encodedImageName));
@@ -631,18 +508,104 @@ readonly class DockerActionManager {
} catch (\Throwable $e) {
$imageIsThere = false;
}
- try {
- $this->guzzleClient->post($url);
- } catch (RequestException $e) {
- $message = "Could not pull image " . $imageName . ": " . $e->getResponse()?->getBody()->getContents();
- if ($imageIsThere === false) {
- throw new \Exception($message);
- } else {
- error_log($message);
+
+ $maxRetries = 3;
+ for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
+ try {
+ $this->guzzleClient->post($url);
+ break;
+ } catch (RequestException $e) {
+ $message = "Could not pull image " . $imageName . " (attempt $attempt/$maxRetries): " . $e->getResponse()?->getBody()->getContents();
+ if ($attempt === $maxRetries) {
+ if ($imageIsThere === false) {
+ throw new \Exception($message);
+ } else {
+ error_log($message);
+ }
+ } else {
+ error_log($message . ' Retrying...');
+ sleep(1);
+ }
}
}
}
+ // Replaces placeholders in $envValue with their values.
+ // E.g. "%NC_DOMAIN%:%APACHE_PORT" becomes "my.nextcloud.com:11000"
+ private function replaceEnvPlaceholders(string $envValue): string {
+ // $pattern breaks down as:
+ // % - matches a literal percent sign
+ // ([^%]+) - capture group that matches one or more characters that are NOT percent signs
+ // % - matches the closing percent sign
+ //
+ // Assumes literal percent signs are always matched and there is no
+ // escaping.
+ $pattern = '/%([^%]+)%/';
+ $matchCount = preg_match_all($pattern, $envValue, $matches);
+
+ if ($matchCount === 0) {
+ return $envValue;
+ }
+
+ $placeholders = $matches[0]; // ["%PLACEHOLDER1%", "%PLACEHOLDER2%", ...]
+ $placeholderNames = $matches[1]; // ["PLACEHOLDER1", "PLACEHOLDER2", ...]
+ $placeholderPatterns = array_map(static fn(string $p) => '/' . preg_quote($p) . '/', $placeholders); // ["/%PLACEHOLDER1%/", ...]
+ $placeholderValues = array_map($this->getPlaceholderValue(...), $placeholderNames); // ["val1", "val2"]
+ // Guaranteed to be non-null because we found the placeholders in the preg_match_all.
+ return (string) preg_replace($placeholderPatterns, $placeholderValues, $envValue);
+ }
+
+ private function getPlaceholderValue(string $placeholder) : string {
+ return match ($placeholder) {
+ 'NC_DOMAIN' => $this->configurationManager->GetDomain(),
+ 'NC_BASE_DN' => $this->configurationManager->GetBaseDN(),
+ 'AIO_TOKEN' => $this->configurationManager->GetToken(),
+ 'BORGBACKUP_REMOTE_REPO' => $this->configurationManager->GetBorgRemoteRepo(),
+ 'BORGBACKUP_MODE' => $this->configurationManager->GetBackupMode(),
+ 'AIO_URL' => $this->configurationManager->GetAIOURL(),
+ 'SELECTED_RESTORE_TIME' => $this->configurationManager->GetSelectedRestoreTime(),
+ 'RESTORE_EXCLUDE_PREVIEWS' => $this->configurationManager->GetRestoreExcludePreviews(),
+ 'APACHE_PORT' => $this->configurationManager->GetApachePort(),
+ 'APACHE_IP_BINDING' => $this->configurationManager->GetApacheIPBinding(),
+ 'TALK_PORT' => $this->configurationManager->GetTalkPort(),
+ 'TURN_DOMAIN' => $this->configurationManager->GetTurnDomain(),
+ 'NEXTCLOUD_MOUNT' => $this->configurationManager->GetNextcloudMount(),
+ 'BACKUP_RESTORE_PASSWORD' => $this->configurationManager->GetBorgRestorePassword(),
+ 'CLAMAV_ENABLED' => $this->configurationManager->isClamavEnabled() ? 'yes' : '',
+ 'TALK_RECORDING_ENABLED' => $this->configurationManager->isTalkRecordingEnabled() ? 'yes' : '',
+ 'ONLYOFFICE_ENABLED' => $this->configurationManager->isOnlyofficeEnabled() ? 'yes' : '',
+ 'COLLABORA_ENABLED' => $this->configurationManager->isCollaboraEnabled() ? 'yes' : '',
+ 'TALK_ENABLED' => $this->configurationManager->isTalkEnabled() ? 'yes' : '',
+ 'UPDATE_NEXTCLOUD_APPS' => ($this->configurationManager->isDailyBackupRunning() && $this->configurationManager->areAutomaticUpdatesEnabled()) ? 'yes' : '',
+ 'TIMEZONE' => $this->configurationManager->GetTimezone() === '' ? 'Etc/UTC' : $this->configurationManager->GetTimezone(),
+ 'COLLABORA_DICTIONARIES' => $this->configurationManager->GetCollaboraDictionaries() === '' ? 'de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru' : $this->configurationManager->GetCollaboraDictionaries(),
+ 'IMAGINARY_ENABLED' => $this->configurationManager->isImaginaryEnabled() ? 'yes' : '',
+ 'FULLTEXTSEARCH_ENABLED' => $this->configurationManager->isFulltextsearchEnabled() ? 'yes' : '',
+ 'DOCKER_SOCKET_PROXY_ENABLED' => $this->configurationManager->isDockerSocketProxyEnabled() ? 'yes' : '',
+ 'NEXTCLOUD_UPLOAD_LIMIT' => $this->configurationManager->GetNextcloudUploadLimit(),
+ 'NEXTCLOUD_MEMORY_LIMIT' => $this->configurationManager->GetNextcloudMemoryLimit(),
+ 'NEXTCLOUD_MAX_TIME' => $this->configurationManager->GetNextcloudMaxTime(),
+ 'BORG_RETENTION_POLICY' => $this->configurationManager->GetBorgRetentionPolicy(),
+ 'FULLTEXTSEARCH_JAVA_OPTIONS' => $this->configurationManager->GetFulltextsearchJavaOptions(),
+ 'NEXTCLOUD_TRUSTED_CACERTS_DIR' => $this->configurationManager->GetTrustedCacertsDir(),
+ 'ADDITIONAL_DIRECTORIES_BACKUP' => $this->configurationManager->GetAdditionalBackupDirectoriesString() !== '' ? 'yes' : '',
+ 'BORGBACKUP_HOST_LOCATION' => $this->configurationManager->GetBorgBackupHostLocation(),
+ 'APACHE_MAX_SIZE' => (string)($this->configurationManager->GetApacheMaxSize()),
+ 'COLLABORA_SECCOMP_POLICY' => $this->configurationManager->GetCollaboraSeccompPolicy(),
+ 'NEXTCLOUD_STARTUP_APPS' => $this->configurationManager->GetNextcloudStartupApps(),
+ 'NEXTCLOUD_ADDITIONAL_APKS' => $this->configurationManager->GetNextcloudAdditionalApks(),
+ 'NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS' => $this->configurationManager->GetNextcloudAdditionalPhpExtensions(),
+ 'INSTALL_LATEST_MAJOR' => $this->configurationManager->shouldLatestMajorGetInstalled() ? 'yes' : '',
+ 'REMOVE_DISABLED_APPS' => $this->configurationManager->shouldDisabledAppsGetRemoved() ? 'yes' : '',
+ // Allow to get local ip-address of database container which allows to talk to it even in host mode (the container that requires this needs to be started first then)
+ 'AIO_DATABASE_HOST' => gethostbyname('nextcloud-aio-database'),
+ // Allow to get local ip-address of caddy container and add it to trusted proxies automatically
+ 'CADDY_IP_ADDRESS' => in_array('caddy', $this->configurationManager->GetEnabledCommunityContainers(), true) ? gethostbyname('nextcloud-aio-caddy') : '',
+ 'WHITEBOARD_ENABLED' => $this->configurationManager->isWhiteboardEnabled() ? 'yes' : '',
+ default => $this->configurationManager->GetRegisteredSecret($placeholder),
+ };
+ }
+
private function isContainerUpdateAvailable(string $id): string {
$container = $this->containerDefinitionFetcher->GetContainerById($id);
@@ -650,7 +613,7 @@ readonly class DockerActionManager {
if ($container->GetUpdateState() === VersionState::Different) {
$updateAvailable = '1';
}
- foreach ($container->GetDependsOn() as $dependency) {
+ foreach ($container->dependsOn as $dependency) {
$updateAvailable .= $this->isContainerUpdateAvailable($dependency);
}
return $updateAvailable;
@@ -674,10 +637,10 @@ readonly class DockerActionManager {
$container = $this->containerDefinitionFetcher->GetContainerById($id);
$backupVolumes = '';
- foreach ($container->GetBackupVolumes() as $backupVolume) {
+ foreach ($container->backupVolumes as $backupVolume) {
$backupVolumes .= $backupVolume . ' ';
}
- foreach ($container->GetDependsOn() as $dependency) {
+ foreach ($container->dependsOn as $dependency) {
$backupVolumes .= $this->getBackupVolumes($dependency);
}
return $backupVolumes;
@@ -693,10 +656,10 @@ readonly class DockerActionManager {
$container = $this->containerDefinitionFetcher->GetContainerById($id);
$nextcloudExecCommands = '';
- foreach ($container->GetNextcloudExecCommands() as $execCommand) {
+ foreach ($container->nextcloudExecCommands as $execCommand) {
$nextcloudExecCommands .= $execCommand . PHP_EOL;
}
- foreach ($container->GetDependsOn() as $dependency) {
+ foreach ($container->dependsOn as $dependency) {
$nextcloudExecCommands .= $this->GetNextcloudExecCommands($dependency);
}
return $nextcloudExecCommands;
@@ -710,11 +673,11 @@ readonly class DockerActionManager {
private function GetRepoDigestsOfContainer(string $containerName): ?array {
try {
$containerUrl = $this->BuildApiUrl(sprintf('containers/%s/json', $containerName));
- $containerOutput = json_decode($this->guzzleClient->get($containerUrl)->getBody()->getContents(), true);
+ $containerOutput = json_decode($this->guzzleClient->get($containerUrl)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
$imageName = $containerOutput['Image'];
$imageUrl = $this->BuildApiUrl(sprintf('images/%s/json', $imageName));
- $imageOutput = json_decode($this->guzzleClient->get($imageUrl)->getBody()->getContents(), true);
+ $imageOutput = json_decode($this->guzzleClient->get($imageUrl)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
if (!isset($imageOutput['RepoDigests'])) {
error_log('RepoDigests is not set of container ' . $containerName);
@@ -758,7 +721,7 @@ readonly class DockerActionManager {
$containerName = 'nextcloud-aio-mastercontainer';
$url = $this->BuildApiUrl(sprintf('containers/%s/json', $containerName));
try {
- $output = json_decode($this->guzzleClient->get($url)->getBody()->getContents(), true);
+ $output = json_decode($this->guzzleClient->get($url)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
$imageNameArray = explode(':', $output['Config']['Image']);
if (count($imageNameArray) === 2) {
$imageName = $imageNameArray[0];
@@ -785,7 +748,7 @@ readonly class DockerActionManager {
$containerName = 'nextcloud-aio-mastercontainer';
$url = $this->BuildApiUrl(sprintf('containers/%s/json', $containerName));
try {
- $output = json_decode($this->guzzleClient->get($url)->getBody()->getContents(), true);
+ $output = json_decode($this->guzzleClient->get($url)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
$tagArray = explode(':', $output['Config']['Image']);
if (count($tagArray) === 2) {
$tag = $tagArray[1];
@@ -828,7 +791,7 @@ readonly class DockerActionManager {
public function sendNotification(Container $container, string $subject, string $message, string $file = '/notify.sh'): void {
if ($this->GetContainerStartingState($container) === ContainerState::Running) {
- $containerName = $container->GetIdentifier();
+ $containerName = $container->identifier;
// schedule the exec
$url = $this->BuildApiUrl(sprintf('containers/%s/exec', urlencode($containerName)));
@@ -849,7 +812,9 @@ readonly class DockerActionManager {
],
]
)->getBody()->getContents(),
- true
+ true,
+ 512,
+ JSON_THROW_ON_ERROR,
);
$id = $response['Id'];
@@ -951,20 +916,25 @@ readonly class DockerActionManager {
// Add a secondary alias for domaincheck container, to keep it as similar to actual apache controller as possible.
// If a reverse-proxy is relying on container name as hostname this allows it to operate as usual and still validate the domain
// The domaincheck container and apache container are never supposed to be active at the same time because they use the same APACHE_PORT anyway, so this doesn't add any new constraints.
- $alias = ($container->GetIdentifier() === 'nextcloud-aio-domaincheck') ? 'nextcloud-aio-apache' : '';
+ $alias = ($container->identifier === 'nextcloud-aio-domaincheck') ? 'nextcloud-aio-apache' : '';
- $this->ConnectContainerIdToNetwork($container->GetIdentifier(), $container->GetInternalPort(), alias: $alias);
+ $this->ConnectContainerIdToNetwork($container->identifier, $container->internalPorts, alias: $alias);
- if ($container->GetIdentifier() === 'nextcloud-aio-apache' || $container->GetIdentifier() === 'nextcloud-aio-domaincheck') {
+ if ($container->identifier === 'nextcloud-aio-apache' || $container->identifier === 'nextcloud-aio-domaincheck') {
$apacheAdditionalNetwork = $this->configurationManager->GetApacheAdditionalNetwork();
if ($apacheAdditionalNetwork !== '') {
- $this->ConnectContainerIdToNetwork($container->GetIdentifier(), $container->GetInternalPort(), $apacheAdditionalNetwork, false, $alias);
+ $this->ConnectContainerIdToNetwork($container->identifier, $container->internalPorts, $apacheAdditionalNetwork, false, $alias);
}
}
}
- public function StopContainer(Container $container): void {
- $url = $this->BuildApiUrl(sprintf('containers/%s/stop?t=%s', urlencode($container->GetIdentifier()), $container->GetMaxShutdownTime()));
+ public function StopContainer(Container $container, bool $forceStopContainer = false): void {
+ if ($forceStopContainer) {
+ $maxShutDownTime = 10;
+ } else {
+ $maxShutDownTime = $container->maxShutdownTime;
+ }
+ $url = $this->BuildApiUrl(sprintf('containers/%s/stop?t=%s', urlencode($container->identifier), $maxShutDownTime));
try {
$this->guzzleClient->post($url);
} catch (RequestException $e) {
@@ -986,7 +956,7 @@ readonly class DockerActionManager {
throw $e;
}
- $responseBody = json_decode((string)$response->getBody(), true);
+ $responseBody = json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
$exitCode = $responseBody['State']['ExitCode'];
if (is_int($exitCode)) {
@@ -1008,7 +978,7 @@ readonly class DockerActionManager {
throw $e;
}
- $responseBody = json_decode((string)$response->getBody(), true);
+ $responseBody = json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
$exitCode = $responseBody['State']['ExitCode'];
if (is_int($exitCode)) {
@@ -1040,7 +1010,7 @@ readonly class DockerActionManager {
$imageName = $imageName . ':' . $this->GetCurrentChannel();
try {
$imageUrl = $this->BuildApiUrl(sprintf('images/%s/json', $imageName));
- $imageOutput = json_decode($this->guzzleClient->get($imageUrl)->getBody()->getContents(), true);
+ $imageOutput = json_decode($this->guzzleClient->get($imageUrl)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
if (!isset($imageOutput['Created'])) {
error_log('Created is not set of image ' . $imageName);
diff --git a/php/src/Docker/DockerHubManager.php b/php/src/Docker/DockerHubManager.php
index 9bf4ad29..256d592e 100644
--- a/php/src/Docker/DockerHubManager.php
+++ b/php/src/Docker/DockerHubManager.php
@@ -30,7 +30,7 @@ readonly class DockerHubManager {
'https://auth.docker.io/token?service=registry.docker.io&scope=repository:' . $name . ':pull'
);
$body = $authTokenRequest->getBody()->getContents();
- $decodedBody = json_decode($body, true);
+ $decodedBody = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
if(isset($decodedBody['token'])) {
$authToken = $decodedBody['token'];
$manifestRequest = $this->guzzleClient->request(
diff --git a/php/src/Docker/GitHubContainerRegistryManager.php b/php/src/Docker/GitHubContainerRegistryManager.php
index d885ae09..eeecfb28 100644
--- a/php/src/Docker/GitHubContainerRegistryManager.php
+++ b/php/src/Docker/GitHubContainerRegistryManager.php
@@ -31,7 +31,7 @@ readonly class GitHubContainerRegistryManager
'https://ghcr.io/token?scope=repository:' . $name . ':pull'
);
$body = $authTokenRequest->getBody()->getContents();
- $decodedBody = json_decode($body, true);
+ $decodedBody = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
if (isset($decodedBody['token'])) {
$authToken = $decodedBody['token'];
$manifestRequest = $this->guzzleClient->request(
diff --git a/php/src/Middleware/AuthMiddleware.php b/php/src/Middleware/AuthMiddleware.php
index f8d44857..724f1776 100644
--- a/php/src/Middleware/AuthMiddleware.php
+++ b/php/src/Middleware/AuthMiddleware.php
@@ -27,7 +27,24 @@ readonly class AuthMiddleware {
if(!in_array($request->getUri()->getPath(), $publicRoutes)) {
if(!$this->authManager->IsAuthenticated()) {
$status = 302;
- $headers = ['Location' => '/'];
+
+ // Check the url of the request: split the string by '/' and count the number of elements
+ // Note that the path that gets to this middleware is not aware of any base path managed by a reverse proxy, so if the url is 'https://example.com/AIO/somepage', the path will be 'https://mastercontainer/somepage'
+ if (count(explode('/', $request->getUri()->getPath())) < 2) {
+ // If there are less than 2 elements it means we are somewhere in the root folder (no '/', so no subfolder), so we redirect to the same folder level to offload the redirection to the appropriate page to 'index.php' (specifically, once in the root level the login page will be loaded since we are not authenticated)
+ $location = '.';
+ } else {
+ // If there are 2 or more elements it means we are in a subfolder, so we need to go back to the root folder
+ // In the best case we need to go back by 1 level only
+ $location = '..';
+ // In the worst case we need to go back by n levels, where n is the number of elements - 2 (the first element is not a folder, the second element is already accounted for by the initial '..')
+ for ($i = 1; $i < count(explode('/', $request->getUri()->getPath())) - 2; $i++) {
+ // For each extra level we need to go back by another level
+ $location = $location . '/..';
+ }
+ }
+
+ $headers = ['Location' => $location];
$response = new Response($status, $headers);
return $response;
}
diff --git a/php/src/Twig/ClassExtension.php b/php/src/Twig/ClassExtension.php
index ff5ffe44..7f478994 100644
--- a/php/src/Twig/ClassExtension.php
+++ b/php/src/Twig/ClassExtension.php
@@ -7,6 +7,7 @@ use Twig\TwigFunction;
class ClassExtension extends TwigExtension
{
+ #[\Override]
public function getFunctions() : array
{
return array(
diff --git a/php/src/Twig/CsrfExtension.php b/php/src/Twig/CsrfExtension.php
index feac9c72..51334864 100644
--- a/php/src/Twig/CsrfExtension.php
+++ b/php/src/Twig/CsrfExtension.php
@@ -12,6 +12,7 @@ class CsrfExtension extends AbstractExtension implements GlobalsInterface {
) {
}
+ #[\Override]
public function getGlobals() : array
{
// CSRF token name and value
diff --git a/php/templates/already-installed.twig b/php/templates/already-installed.twig
index fa18f988..e16e6792 100644
--- a/php/templates/already-installed.twig
+++ b/php/templates/already-installed.twig
@@ -3,11 +3,11 @@
{% block body %}
{% endblock %}
diff --git a/php/templates/components/container-state.twig b/php/templates/components/container-state.twig
index 4cf5dd4e..07580e66 100644
--- a/php/templates/components/container-state.twig
+++ b/php/templates/components/container-state.twig
@@ -3,24 +3,24 @@
{% if c.GetStartingState().value == 'starting' %}
- {{ c.GetDisplayName() }}
- (Starting )
+ {{ c.displayName }}
+ (Starting )
{% elseif c.GetRunningState().value == 'running' %}
- {{ c.GetDisplayName() }}
- (Running )
+ {{ c.displayName }}
+ (Running )
{% else %}
- {{ c.GetDisplayName() }}
- (Stopped )
+ {{ c.displayName }}
+ (Stopped )
{% endif %}
- {% if c.GetDocumentation() != '' %}
- (docs )
+ {% if c.documentation != '' %}
+ (docs )
{% endif %}
{% if c.GetUiSecret() != '' %}
- Show password for {{ c.GetDisplayName() }}
+ Show password for {{ c.displayName }}
{% endif %}
diff --git a/php/templates/containers.twig b/php/templates/containers.twig
index 6d50efd4..2f722768 100644
--- a/php/templates/containers.twig
+++ b/php/templates/containers.twig
@@ -6,9 +6,9 @@
- {% if is_onlyoffice_enabled == true %}
OnlyOffice
- {% endif %}
In order to get the correct dictionaries in Collabora, you may configure the dictionaries below:
-
+
@@ -171,7 +169,7 @@
You need to make sure that the dictionaries that you enter are valid. An example is de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru .
{% else %}
The dictionaries for Collabora are currently set to {{ collabora_dictionaries }} . You can reset them again by clicking on the button below.
-
+
@@ -184,7 +182,7 @@
{% if collabora_additional_options == "" %}
You can configure additional options for collabora below.
(This can be used for configuring the net.content_security_policy and more. Make sure to submit the value!)
-
+
@@ -193,7 +191,7 @@
You need to make sure that the options that you enter are valid. An example is --o:net.content_security_policy=frame-ancestors *.example.com:*; .
{% else %}
The additioinal options for Collabora are currently set to {{ collabora_additional_options }} . You can reset them again by clicking on the button below.
-
+
diff --git a/php/templates/layout.twig b/php/templates/layout.twig
index 6ed264c2..4d842e3d 100644
--- a/php/templates/layout.twig
+++ b/php/templates/layout.twig
@@ -1,8 +1,8 @@
AIO
-
-
+
+
diff --git a/php/templates/login.twig b/php/templates/login.twig
index cf5cc0c3..1c5420c2 100644
--- a/php/templates/login.twig
+++ b/php/templates/login.twig
@@ -3,14 +3,14 @@
{% block body %}
-
-
+
+
Nextcloud Logo
Nextcloud AIO Login
{% if is_login_allowed == true %}
Log in using your Nextcloud AIO passphrase:
-
+
diff --git a/php/templates/setup.twig b/php/templates/setup.twig
index f1d4d1dc..7cc9227a 100644
--- a/php/templates/setup.twig
+++ b/php/templates/setup.twig
@@ -3,14 +3,14 @@
{% block body %}
-
-
+
+
Nextcloud Logo
All-in-One setup
The official Nextcloud installation method. Nextcloud All-in-One provides easy deployment and maintenance with most features included in this one Nextcloud instance.
⚠️ Please note down the passphrase to access the AIO interface and don't lose it!
Passphrase {{ password }}
-
Open Nextcloud AIO login ↗
+
Open Nextcloud AIO login ↗
{% endblock %}
diff --git a/php/tests/package-lock.json b/php/tests/package-lock.json
index ea2b4296..7d7d3383 100644
--- a/php/tests/package-lock.json
+++ b/php/tests/package-lock.json
@@ -7,20 +7,19 @@
"": {
"name": "e2e",
"version": "1.0.0",
- "license": "ISC",
+ "license": "AGPL-3.0-or-later",
"devDependencies": {
- "@playwright/test": "^1.51.1",
- "@types/node": "^22.13.10"
+ "@playwright/test": "^1.56.1"
}
},
"node_modules/@playwright/test": {
- "version": "1.51.1",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.51.1.tgz",
- "integrity": "sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
+ "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright": "1.51.1"
+ "playwright": "1.56.1"
},
"bin": {
"playwright": "cli.js"
@@ -29,16 +28,6 @@
"node": ">=18"
}
},
- "node_modules/@types/node": {
- "version": "22.13.10",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
- "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
@@ -55,13 +44,13 @@
}
},
"node_modules/playwright": {
- "version": "1.51.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.51.1.tgz",
- "integrity": "sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
+ "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.51.1"
+ "playwright-core": "1.56.1"
},
"bin": {
"playwright": "cli.js"
@@ -74,9 +63,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.51.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.1.tgz",
- "integrity": "sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
+ "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -85,13 +74,6 @@
"engines": {
"node": ">=18"
}
- },
- "node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
}
}
}
diff --git a/php/tests/package.json b/php/tests/package.json
index ebfa99ec..95aae5a8 100644
--- a/php/tests/package.json
+++ b/php/tests/package.json
@@ -3,6 +3,6 @@
"version": "1.0.0",
"license": "AGPL-3.0-or-later",
"devDependencies": {
- "@playwright/test": "^1.51.1"
+ "@playwright/test": "^1.56.1"
}
}
diff --git a/php/tests/tests/initial-setup.spec.js b/php/tests/tests/initial-setup.spec.js
index ca8bc077..c88cd8e3 100644
--- a/php/tests/tests/initial-setup.spec.js
+++ b/php/tests/tests/initial-setup.spec.js
@@ -60,8 +60,8 @@ test('Initial setup', async ({ page: setupPage }) => {
// Start containers and wait for starting message
await containersPage.getByRole('button', { name: 'Download and start containers' }).click();
- await expect(containersPage.getByRole('main')).toContainText('Containers are currently starting.', { timeout: 3 * 60 * 1000 });
- await expect(containersPage.getByRole('link', { name: 'Open your Nextcloud ↗' })).toBeVisible({ timeout: 2 * 60 * 1000 });
+ await expect(containersPage.getByRole('main')).toContainText('Containers are currently starting.', { timeout: 5 * 60 * 1000 });
+ await expect(containersPage.getByRole('link', { name: 'Open your Nextcloud ↗' })).toBeVisible({ timeout: 3 * 60 * 1000 });
await expect(containersPage.getByRole('link', { name: 'Open your Nextcloud ↗' })).toHaveAttribute('href', 'https://example.com');
// Extract initial nextcloud password
diff --git a/php/tests/tests/restore-instance.spec.js b/php/tests/tests/restore-instance.spec.js
index 217218e5..e93cf340 100644
--- a/php/tests/tests/restore-instance.spec.js
+++ b/php/tests/tests/restore-instance.spec.js
@@ -28,7 +28,7 @@ test('Restore instance', async ({ page: setupPage }) => {
await containersPage.locator('#domain').click();
await containersPage.locator('#domain').fill('example.com');
await containersPage.getByRole('button', { name: 'Submit domain' }).click();
- await expect(containersPage.locator('body')).toContainText('Domain does not point to this server or the reverse proxy is not configured correctly.');
+ await expect(containersPage.locator('body')).toContainText('Domain does not point to this server or the reverse proxy is not configured correctly.', { timeout: 15 * 1000 });
// Reject invalid backup location
await containersPage.locator('#borg_restore_host_location').click();
@@ -59,6 +59,10 @@ test('Restore instance', async ({ page: setupPage }) => {
// Check integrity and restore backup
await containersPage.getByRole('button', { name: 'Check backup integrity' }).click();
await expect(containersPage.getByRole('main')).toContainText('Last check successful!', { timeout: 5 * 60 * 1000 });
+ containersPage.once('dialog', dialog => {
+ console.log(`Dialog message: ${dialog.message()}`)
+ dialog.accept()
+ });
await containersPage.getByRole('button', { name: 'Restore selected backup' }).click();
await expect(containersPage.getByRole('main')).toContainText('Backup container is currently running:', { timeout: 1 * 60 * 1000 });
diff --git a/readme.md b/readme.md
index 9338ea4a..66059954 100644
--- a/readme.md
+++ b/readme.md
@@ -1,4 +1,8 @@
# Nextcloud All-in-One
+
+> [!NOTE]
+> Nextcloud AIO is actively looking for contributors. See [the forum post](https://help.nextcloud.com/t/nextcloud-aio-is-looking-for-contributors/205234).
+
The official Nextcloud installation method. Nextcloud AIO provides easy deployment and maintenance with most features included in this one Nextcloud instance.
Included are:
@@ -28,7 +32,7 @@ Included are:
- A+ security in Nextcloud security scan
- Ready to be used behind existing [Reverse proxies](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md)
- Can be used behind [Cloudflare Tunnel](https://github.com/nextcloud/all-in-one#how-to-run-nextcloud-behind-a-cloudflare-tunnel)
-- Can be used via [Tailscale](https://github.com/nextcloud/all-in-one/discussions/5439)
+- Can be used via [Tailscale](https://github.com/nextcloud/all-in-one/discussions/6817)
- Ready for big file uploads up to 10 GB on public links, [adjustable](https://github.com/nextcloud/all-in-one#how-to-adjust-the-upload-limit-for-nextcloud) (logged in users can upload much bigger files using the webinterface or the mobile/desktop clients since chunking is used in that case)
- PHP and web server timeouts set to 3600s, [adjustable](https://github.com/nextcloud/all-in-one#how-to-adjust-the-max-execution-time-for-nextcloud) (important for big file uploads)
- Defaults to a max of 512 MB RAM per PHP process, [adjustable](https://github.com/nextcloud/all-in-one#how-to-adjust-the-php-memory-limit-for-nextcloud)
@@ -42,13 +46,14 @@ Included are:
- By default confined (good for security) but can [allow access to additional storages](https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host) in order to enable the usage of the local external storage feature
- Possibility included to [adjust default installed Nextcloud apps](https://github.com/nextcloud/all-in-one#how-to-change-the-nextcloud-apps-that-are-installed-on-the-first-startup)
- Nextcloud installation is not read only - that means you can apply patches if you should need them (instead of having to wait for the next release for them getting applied)
-- `ffmpeg`, `smbclient`, `libreoffice` and `nodejs` are included by default
+- `ffmpeg`, `smbclient` and `nodejs` are included by default
- Possibility included to [permanently add additional OS packages into the Nextcloud container](https://github.com/nextcloud/all-in-one#how-to-change-the-nextcloud-apps-that-are-installed-on-the-first-startup) without having to build your own Docker image
- Possibility included to [permanently add additional PHP extensions into the Nextcloud container](https://github.com/nextcloud/all-in-one#how-to-add-php-extensions-permanently-to-the-nextcloud-container) without having to build your own Docker image
- Possibility included to [pass the needed device for hardware transcoding](https://github.com/nextcloud/all-in-one#how-to-enable-hardware-acceleration-for-nextcloud) to the Nextcloud container
- Possibility included to [store all docker related files on a separate drive](https://github.com/nextcloud/all-in-one#how-to-store-the-filesinstallation-on-a-separate-drive)
- [LDAP can be used as user backend for Nextcloud](https://github.com/nextcloud/all-in-one/tree/main#ldap)
-- Migration from any former Nextcloud installation to AIO is possible. See [this documentation](https://github.com/nextcloud/all-in-one/blob/main/migration.md)
+- Migration from any former Nextcloud installation to AIO is possible. See [this documentation](https://github.com/nextcloud/all-in-one/blob/main/migration.md).
+- Migration in the other direction (e.g. from AIO to a VM-based installation) is also possible.
- [Fail2Ban can be added](https://github.com/nextcloud/all-in-one#fail2ban)
- [phpMyAdmin, Adminer or pgAdmin can be added](https://github.com/nextcloud/all-in-one#phpmyadmin-adminer-or-pgadmin)
- [Mail server can be added](https://github.com/nextcloud/all-in-one#mail-server)
@@ -81,66 +86,100 @@ Included are:
|  |  |
## How to use this?
->[!WARNING]
-> You should first make sure that you are not using docker installed via snap. You can check this by running `sudo docker info | grep "Docker Root Dir" | grep "/var/snap/docker/"`. If the output should contain the mentioned string `/var/snap/docker/`, you should first uninstall docker snap via `sudo snap remove docker` and then follow the instructions below. ⚠️ Attention: only run the command if this is a clean new docker installation and you are not running any service already using this.
-> [!NOTE]
-> The following instructions are meant for installations without a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) already being in place. If you want to run AIO behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), see the [reverse proxy documentation](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md). Also, the instructions below are especially meant for Linux. For macOS see [this](#how-to-run-aio-on-macos), for Windows see [this](#how-to-run-aio-on-windows) and for Synology see [this](#how-to-run-aio-on-synology-dsm).
+The steps below are written for Linux. For platform-specific guidance see:
+- macOS: [How to run AIO on macOS](#how-to-run-aio-on-macos)
+- Windows: [How to run AIO on Windows](#how-to-run-aio-on-windows)
+- Synology DSM: [How to run AIO on Synology DSM](#how-to-run-aio-on-synology-dsm)
+- TrueNAS SCALE: [Can I run AIO on TrueNAS SCALE?](#can-i-run-aio-on-truenas-scale)
-1. Install Docker on your Linux installation by following the official documentation: https://docs.docker.com/engine/install/#supported-platforms.
->[!WARNING]
-> You could use the convenience script below to install docker. However we recommend to not blindly download and execute scripts as sudo. But if you feel like it, you can of course use it. See below:
+> [!IMPORTANT]
+> These instructions assume there is no existing web server or reverse proxy (for example Apache, Nginx, Caddy, or Cloudflare Tunnel) that you intend to place in front of AIO. If you plan to run AIO behind an existing web server or reverse proxy, follow the AIO reverse proxy documentation: [Reverse proxy docs](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md)
-
- Using the convenience script
+You're encouraged to skim the attached [FAQ](#faq). While we've tried to make things straightforward, Nextcloud is a large and flexible platform. Reading the FAQ will save you time, particularly if edge cases come up.
+
+> [!TIP]
+> Don't worry about getting everything perfect on the first try — test deployments are cheap and disposable.
+
+1. Install Docker on your Linux host by following the official documentation: [Docker install — supported platforms](https://docs.docker.com/engine/install/#supported-platforms)
+
+> [!WARNING]
+> Snap-based Docker installations are not supported. Make sure you are not using a snap-based Docker installation (generally only applicable to Ubuntu). To check, run:
+> ```sh
+> sudo docker info | grep "Docker Root Dir" | grep "/var/snap/docker/"
+> ```
+> If you see the following output:
+> ```
+> /var/snap/docker/
+> ```
+> you should migrate to a standard Docker installation and remove the snap-based package before proceeding: [Install Docker on Ubuntu](https://docs.docker.com/engine/install/ubuntu/).
+>
+> ⚠️ To avoid losing data or interrupting services, only remove the Docker snap after you are certain you're not running any existing containers in it.
+>
+> Consult the official Docker documentation or other guides for instructions on migrating existing containers. Once you are certain it's safe, remove the snap-based Docker installation with:
+> ```sh
+> sudo snap remove docker
+> ```
+
+2. If you need IPv6 support, enable it by following: [Docker IPv6 support for AIO](https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md)
+
+3. AIO uses a special `mastercontainer` to orchestrate the various pieces of the Nextcloud stack. To start AIO, launch the `mastercontainer` with the command below:
```sh
-curl -fsSL https://get.docker.com | sudo sh
+# For Linux and without a web server or reverse proxy already in place:
+sudo docker run \
+ --init \
+ --sig-proxy=false \
+ --name nextcloud-aio-mastercontainer \
+ --restart always \
+ --publish 80:80 \
+ --publish 8080:8080 \
+ --publish 8443:8443 \
+ --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
+ --volume /var/run/docker.sock:/var/run/docker.sock:ro \
+ ghcr.io/nextcloud-releases/all-in-one:latest
```
+
+ Explanation of the command
+
+ - `sudo docker run` — starts a new Docker container. Omit `sudo` if your user is in the `docker` group.
+ - `--init` — runs an init process inside the container to handle zombie processes.
+ - `--sig-proxy=false` — prevents Ctrl+C in the attached terminal from stopping the container.
+ - `--name nextcloud-aio-mastercontainer` — the container name. Do not change this name; mastercontainer updates rely on it.
+ - `--restart always` — ensures the container restarts automatically with the Docker daemon.
+ - `--publish 80:80` — publishes container port 80 on host port 80 (used for ACME http-challenge when obtaining certificates). Not required if you run AIO behind a reverse proxy.
+ - `--publish 8080:8080` — publishes the AIO interface (self-signed certificate) on host port 8080. You may map a different host port if 8080 is in use (e.g. `--publish 8081:8080`).
+ - `--publish 8443:8443` — publishes the AIO interface with a valid certificate on host port 8443 (requires ports 80 and 8443 to be reachable and a domain pointing to your server). Not required if you run AIO behind a reverse proxy.
+ - `--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config` — stores mastercontainer configuration in the named Docker volume. Do not change this volume name; built-in backups depend on it.
+ - `--volume /var/run/docker.sock:/var/run/docker.sock:ro` — mounts the Docker socket (read-only) so the mastercontainer can manage other containers. On Windows/macOS or when using rootless Docker, this path may need adjustment; see the platform-specific docs. If you change the socket path, also set `WATCHTOWER_DOCKER_SOCKET_PATH` accordingly. If you prefer not to expose the socket, see the manual-install documentation: [Manual install without docker socket access](https://github.com/nextcloud/all-in-one/tree/main/manual-install)
+ - `ghcr.io/nextcloud-releases/all-in-one:latest` — the mastercontainer image.
+
+ Additional options can be set with environment variables (for example `--env NEXTCLOUD_DATADIR="/mnt/ncdata"` to change Nextcloud's datadir on first startup). See the Customization section and example compose file: [compose.yaml](https://github.com/nextcloud/all-in-one/blob/main/compose.yaml) for more options.
-2. If you need ipv6 support, you should enable it by following https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md.
-3. Run the command below in order to start the container on Linux and without a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) already in place:
- ```
- # For Linux and without a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) already in place:
- sudo docker run \
- --init \
- --sig-proxy=false \
- --name nextcloud-aio-mastercontainer \
- --restart always \
- --publish 80:80 \
- --publish 8080:8080 \
- --publish 8443:8443 \
- --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
- --volume /var/run/docker.sock:/var/run/docker.sock:ro \
- ghcr.io/nextcloud-releases/all-in-one:latest
- ```
-
- Explanation of the command
+> [!TIP]
+> If you want Nextcloud’s data directory in a different location than the default Docker volume, see "How to change the default location of Nextcloud's Datadir" in this README: [How to change the default location of Nextcloud's Datadir](#how-to-change-the-default-location-of-nextclouds-datadir)
- - `sudo docker run` This command spins up a new docker container. Docker commands can optionally be used without `sudo` if the user is added to the docker group (this is not the same as docker rootless, see FAQ below).
- - `--init` This option makes sure that no zombie-processes are created, ever. See [the Docker documentation](https://docs.docker.com/reference/cli/docker/container/run/#init).
- - `--sig-proxy=false` This option allows to exit the container shell that gets attached automatically when using `docker run` by using `[CTRL] + [C]` without shutting down the container.
- - `--name nextcloud-aio-mastercontainer` This is the name of the container. This line is not allowed to be changed, since mastercontainer updates would fail.
- - `--restart always` This is the "restart policy". `always` means that the container should always get started with the Docker daemon. See the Docker documentation for further detail about restart policies: https://docs.docker.com/config/containers/start-containers-automatically/
- - `--publish 80:80` This means that port 80 of the container should get published on the host using port 80. It is used for getting valid certificates for the AIO interface if you want to use port 8443. It is not needed if you run AIO behind a web server or reverse proxy and can get removed in that case as you can simply use port 8080 for the AIO interface then.
- - `--publish 8080:8080` This means that port 8080 of the container should get published on the host using port 8080. This port is used for the AIO interface and uses a self-signed certificate by default. You can also use a different host port if port 8080 is already used on your host, for example `--publish 8081:8080` (only the first port can be changed for the host, the second port is for the container and must remain at 8080).
- - `--publish 8443:8443` This means that port 8443 of the container should get published on the host using port 8443. If you publish port 80 and 8443 to the public internet, you can access the AIO interface via this port with a valid certificate. It is not needed if you run AIO behind a web server or reverse proxy and can get removed in that case as you can simply use port 8080 for the AIO interface then.
- - `--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config` This means that the files that are created by the mastercontainer will be stored in a docker volume that is called `nextcloud_aio_mastercontainer`. This line is not allowed to be changed, since built-in backups would fail later on.
- - `--volume /var/run/docker.sock:/var/run/docker.sock:ro` The docker socket is mounted into the container which is used for spinning up all the other containers and for further features. It needs to be adjusted on Windows/macOS and on docker rootless. See the applicable documentation on this. If adjusting, don't forget to also set `WATCHTOWER_DOCKER_SOCKET_PATH`! If you dislike this, see https://github.com/nextcloud/all-in-one/tree/main/manual-install.
- - `ghcr.io/nextcloud-releases/all-in-one:latest` This is the docker container image that is used.
- - Further options can be set using environment variables, for example `--env NEXTCLOUD_DATADIR="/mnt/ncdata"` (This is an example for Linux. See [this](https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir) for other OS' and for an explanation of what this value does. This specific one needs to be specified upon the first startup if you want to change it to a specific path instead of the default Docker volume). To see explanations and examples for further variables (like changing the location of Nextcloud's datadir or mounting some locations as external storage into the Nextcloud container), read through this readme and look at the docker-compose file: https://github.com/nextcloud/all-in-one/blob/main/compose.yaml
-
+> [!NOTE]
+> For production usage (and ease of upgrades and changes), we suggest using the example [Compose file](https://github.com/nextcloud/all-in-one/blob/main/compose.yaml) rather than `docker run`.
- Note: You may be interested in adjusting Nextcloud’s datadir to store the files in a different location than the default docker volume. See [this documentation](https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir) on how to do it.
+4. After the initial startup, open the Nextcloud AIO interface on port 8080 of this server **by IP address**, for example:
+```txt
+https://192.168.5.5:8080
+```
-4. After the initial startup, you should be able to open the Nextcloud AIO Interface now on port 8080 of this server.
-E.g. `https://ip.address.of.this.server:8080`
-⚠️ **Important:** do always use an ip-address if you access this port and not a domain as HSTS might block access to it later! (It is also expected that this port uses a self-signed certificate due to security concerns which you need to accept in your browser)
-If your firewall/router has port 80 and 8443 open/forwarded and you point a domain to your server, you can get a valid certificate automatically by opening the Nextcloud AIO Interface via:
-`https://your-domain-that-points-to-this-server.tld:8443`
-5. Please do not forget to open port `3478/TCP` and `3478/UDP` in your firewall/router for the Talk container!
+> [!CAUTION]
+> Use an IP address (not a domain) when accessing the AIO interface on port 8080. Accessing via a domain may work temporarily but is likely to break later due to HSTS.
+
+Port 8080 uses a self-signed certificate that you must accept in your browser.
+
+It is also possible to obtain a valid certificate automatically if your firewall/router forwards ports 80 and 8443 and you point a domain to your server. In that case, access the AIO interface using the dedicated port for this purpose (8443), for example:
+```txt
+https://your-domain-that-points-to-this-server.tld:8443
+```
+
+5. If you enable Nextcloud Talk, open port `3478/TCP` and `3478/UDP` in your firewall/router for the Talk (TURN) container.
# FAQ
- [TOC](#faq)
@@ -167,6 +206,7 @@ If your firewall/router has port 80 and 8443 open/forwarded and you point a doma
- [How to skip the domain validation?](#how-to-skip-the-domain-validation)
- [How to resolve firewall problems with Fedora Linux, RHEL OS, CentOS, SUSE Linux and others?](#how-to-resolve-firewall-problems-with-fedora-linux-rhel-os-centos-suse-linux-and-others)
- [What can I do to fix the internal or reserved ip-address error?](#what-can-i-do-to-fix-the-internal-or-reserved-ip-address-error)
+ - [How to adjust the MTU size of the docker network](#how-to-adjust-the-mtu-size-of-the-docker-network)
- [Infrastructure](#infrastructure)
- [Which CPU architectures are supported?](#which-cpu-architectures-are-supported)
- [Disrecommended VPS providers](#disrecommended-vps-providers)
@@ -174,8 +214,10 @@ If your firewall/router has port 80 and 8443 open/forwarded and you point a doma
- [Note on storage options](#note-on-storage-options)
- [Are there known problems when SELinux is enabled?](#are-there-known-problems-when-selinux-is-enabled)
- [Customization](#customization)
+ - [How to adjust the internally used docker api version?](#how-to-adjust-the-internally-used-docker-api-version)
- [How to change the default location of Nextcloud's Datadir?](#how-to-change-the-default-location-of-nextclouds-datadir)
- [How to store the files/installation on a separate drive?](#how-to-store-the-filesinstallation-on-a-separate-drive)
+ - [How to limit the resource usage of AIO?](#how-to-limit-the-resource-usage-of-aio)
- [How to allow the Nextcloud container to access directories on the host?](#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host)
- [How to adjust the Talk port?](#how-to-adjust-the-talk-port)
- [How to adjust the upload limit for Nextcloud?](#how-to-adjust-the-upload-limit-for-nextcloud)
@@ -277,7 +319,7 @@ Only those (if you access the Mastercontainer Interface internally via port 8080
- `3478/TCP` and `3478/UDP`: will be used by the Turnserver inside the Talk container and needs to be open/forwarded in your firewall/router
### Notes on Cloudflare (proxy/tunnel)
-Since Cloudflare Proxy/Tunnel comes with a lot of limitations which are listed below, it is rather recommended to switch to [Tailscale](https://github.com/nextcloud/all-in-one/discussions/5439) if possible.
+Since Cloudflare Proxy/Tunnel comes with a lot of limitations which are listed below, it is rather recommended to switch to [Tailscale](https://github.com/nextcloud/all-in-one/discussions/6817) if possible.
- Cloudflare Proxy and Cloudflare Tunnel both require Cloudflare to perform TLS termination on their side and thus decrypt all the traffic on their infrastructure. This is a privacy concern and you will need to look for other solutions if it's unacceptable for you.
- Using Cloudflare Tunnel might potentially slow down Nextcloud since local access via the configured domain is not possible because TLS termination is in that case offloaded to Cloudflare's infrastructure. There is no way to disable this behavior in Cloudflare Tunnel.
- It is known that the domain validation may not work correctly behind Cloudflare since Cloudflare might block the validation attempt. You can simply skip it in that case by following: https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation
@@ -295,31 +337,31 @@ Since Cloudflare Proxy/Tunnel comes with a lot of limitations which are listed b
Although it does not seems like it is the case but from AIO perspective a Cloudflare Tunnel works like a reverse proxy. So please follow the [reverse proxy documentation](./reverse-proxy.md) where is documented how to make it run behind a Cloudflare Tunnel. However please see the [caveats](https://github.com/nextcloud/all-in-one#notes-on-cloudflare-proxytunnel) before proceeding.
### How to run Nextcloud via Tailscale?
-For a reverse proxy example guide for Tailscale, see this guide by @flll: https://github.com/nextcloud/all-in-one/discussions/5439
+For a reverse proxy example guide for Tailscale, see this guide by [@Perseus333](https://github.com/Perseus333): https://github.com/nextcloud/all-in-one/discussions/6817
### How to get Nextcloud running using the ACME DNS-challenge?
-You can install AIO in reverse proxy mode where is also documented how to get it running using the ACME DNS-challenge for getting a valid certificate for AIO. See the [reverse proxy documentation](./reverse-proxy.md). (Meant is the `Caddy with ACME DNS-challenge` section). Also see https://github.com/dani-garcia/vaultwarden/wiki/Running-a-private-vaultwarden-instance-with-Let%27s-Encrypt-certs#getting-a-custom-caddy-build for additional docs on this topic.
+You can install AIO behind an external reverse proxy where is also documented how to get it running using the ACME DNS-challenge for getting a valid certificate for AIO. See the [reverse proxy documentation](./reverse-proxy.md). (Meant is the `Caddy with ACME DNS-challenge` section). Also see https://github.com/dani-garcia/vaultwarden/wiki/Running-a-private-vaultwarden-instance-with-Let%27s-Encrypt-certs#getting-a-custom-caddy-build for additional docs on this topic.
### How to run Nextcloud locally? No domain wanted, or wanting intranet access within your LAN.
If you do not want to open Nextcloud to the public internet, you may have a look at the following documentation on how to set it up locally: [local-instance.md](./local-instance.md), but keep in mind you're still required to have https working properly.
### Can I use an ip-address for Nextcloud instead of a domain?
-No and it will not be added. If you only want to run it locally, you may have a look at the following documentation: [local-instance.md](./local-instance.md). Recommended is to use [Tailscale](https://github.com/nextcloud/all-in-one/discussions/5439).
+No and it will not be added. If you only want to run it locally, you may have a look at the following documentation: [local-instance.md](./local-instance.md). Recommended is to use [Tailscale](https://github.com/nextcloud/all-in-one/discussions/6817).
### Can I run AIO offline or in an airgapped system?
No. This is not possible and will not be added due to multiple reasons: update checks, app installs via app-store, downloading additional docker images on demand and more.
### Are self-signed certificates supported for Nextcloud?
-No and they will not be. If you want to run it locally, without opening Nextcloud to the public internet, please have a look at the [local instance documentation](./local-instance.md). Recommended is to use [Tailscale](https://github.com/nextcloud/all-in-one/discussions/5439).
+No and they will not be. If you want to run it locally, without opening Nextcloud to the public internet, please have a look at the [local instance documentation](./local-instance.md). Recommended is to use [Tailscale](https://github.com/nextcloud/all-in-one/discussions/6817).
### Can I use AIO with multiple domains?
No and it will not be added. However you can use [this feature](https://github.com/nextcloud/all-in-one/blob/main/multiple-instances.md) in order to create multiple AIO instances, one for each domain.
### Are other ports than the default 443 for Nextcloud supported?
-No and they will not be. If port 443 and/or 80 is blocked for you, you may use [Tailscale](https://github.com/nextcloud/all-in-one/discussions/5439) if you want to publish it online. If you already run a different service on port 443, please use a dedicated domain for Nextcloud and set it up correctly by following the [reverse proxy documentation](./reverse-proxy.md). However in all cases the Nextcloud interface will redirect you to port 443.
+No and they will not be. If port 443 and/or 80 is blocked for you, you may use [Tailscale](https://github.com/nextcloud/all-in-one/discussions/6817) if you want to publish it online. If you already run a different service on port 443, please use a dedicated domain for Nextcloud and set it up correctly by following the [reverse proxy documentation](./reverse-proxy.md). However in all cases the Nextcloud interface will redirect you to port 443.
### Can I run Nextcloud in a subdirectory on my domain?
-No and it will not be added. Please use a dedicated (sub-)domain for Nextcloud and set it up correctly by following the [reverse proxy documentation](./reverse-proxy.md). Alternatively, you may use [Tailscale](https://github.com/nextcloud/all-in-one/discussions/5439) if you want to publish it online.
+No and it will not be added. Please use a dedicated (sub-)domain for Nextcloud and set it up correctly by following the [reverse proxy documentation](./reverse-proxy.md). Alternatively, you may use [Tailscale](https://github.com/nextcloud/all-in-one/discussions/6817) if you want to publish it online.
### How can I access Nextcloud locally?
Please note that local access is not possible if you are running AIO behind Cloudflare Tunnel since TLS proxying is in that case offloaded to Cloudflares infrastructure. You can fix this by setting up your own reverse proxy that handles TLS proxying locally and will make the steps below work.
@@ -336,6 +378,8 @@ Apart from that there is now a community container that can be added to the AIO
### How to skip the domain validation?
If you are completely sure that you've configured everything correctly and are not able to pass the domain validation, you may skip the domain validation by adding `--env SKIP_DOMAIN_VALIDATION=true` to the docker run command of the mastercontainer (but before the last line `ghcr.io/nextcloud-releases/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used).
+Alternatively, if the container is already running, reload the AIO interface with the param `skip_domain_validation` to skip the domain validation on the fly: e.g. `https://ip.address.of.the.server:8080/containers?skip_domain_validation`.
+
### How to resolve firewall problems with Fedora Linux, RHEL OS, CentOS, SUSE Linux and others?
It is known that Linux distros that use [firewalld](https://firewalld.org) as their firewall daemon have problems with docker networks. In case the containers are not able to communicate with each other, you may change your firewalld to use the iptables backend by running:
```
@@ -349,6 +393,15 @@ See https://dev.to/ozorest/fedora-32-how-to-solve-docker-internal-network-issue-
### What can I do to fix the internal or reserved ip-address error?
If you get an error during the domain validation which states that your ip-address is an internal or reserved ip-address, you can fix this by first making sure that your domain indeed has the correct public ip-address that points to the server and then adding `--add-host yourdomain.com:` to the docker run command of the mastercontainer (but before the last line `ghcr.io/nextcloud-releases/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used) which will allow the domain validation to work correctly. And so that you know: even if the `A` record of your domain should change over time, this is no problem since the mastercontainer will not make any attempt to access the chosen domain after the initial domain validation.
+### How to adjust the MTU size of the docker network
+You can adjust the MTU size of the docker network by creating it beforehand with the custom MTU:
+```
+docker network create --driver bridge --opt com.docker.network.driver.mtu=1440 nextcloud-aio
+```
+When you open the AIO interface for the first time after you execute the `docker run` command, it will automatically connect to the `nextcloud-aio` network with the custom MTU. Keep in mind that if you previously started the mastercontainer without creating the network with the extra options, you will need to remove the old `nextcloud-aio` network and recreate it with the new configuration.
+
+If you want to use docker compose, you can check out the comments in the `compose.yaml` file for more details.
+
## Infrastructure
### Which CPU architectures are supported?
@@ -376,6 +429,9 @@ Yes. If SELinux is enabled, you might need to add the `--security-opt label:disa
## Customization
+### How to adjust the internally used docker api version?
+If you run an outdated or too new docker version, you might run into problems with the by AIO internally used docker api version. To fix this, you can specify the api version manually. You can do so by adding `--env DOCKER_API_VERSION=1.44` to the docker run command of the mastercontainer (but before the last line `ghcr.io/nextcloud-releases/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used). This variable excepts a string based on the pattern `[0-9].[0-9]+`, so e.g. `1.44`. ⚠️ However please note that only the default api version (unset this variable) is supported and tested by the maintainers of Nextcloud AIO. So use this on your own risk and things might break without warning.
+
### How to change the default location of Nextcloud's Datadir?
> [!WARNING]
> Do not set or adjust this value after the initial Nextcloud installation is done! If you still want to do it afterwards, see [this](https://github.com/nextcloud/all-in-one/discussions/890#discussioncomment-3089903) on how to do it.
@@ -405,11 +461,14 @@ You can move the whole docker library and all its files including all Nextcloud
1. Stop all the containers from the AIO Interface.
2. Go to your terminal and delete the Collabora container (`docker rm nextcloud-aio-collabora`) AND the Collabora image (`docker image rm nextcloud/aio-collabora`).
-3. You might also want to prune your Docker (`docker system prune`) (no data will be lost).
+3. You might also want to prune your Docker (`docker system prune -a`) (no data will be lost).
4. Restart your containers from the AIO Interface.
This should solve the problem.
+### How to limit the resource usage of AIO?
+In some cases, you might want to limit the overall resource usage of AIO. You can do so by following [this documentation](https://github.com/nextcloud/all-in-one/discussions/7273). Another possibility is to use the [manual installation](./manual-install/).
+
### How to allow the Nextcloud container to access directories on the host?
By default, the Nextcloud container is confined and cannot access directories on the host OS. You might want to change this when you are planning to use local external storage in Nextcloud to store some files outside the data directory and can do so by adding the environmental variable `NEXTCLOUD_MOUNT` to the docker run command of the mastercontainer (but before the last line `ghcr.io/nextcloud-releases/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used). Allowed values for that variable are strings that start with `/` and are not equal to `/`.
@@ -445,7 +504,7 @@ You might want to adjust the Nextcloud apps that are installed upon the first st
### How to add OS packages permanently to the Nextcloud container?
Some Nextcloud apps require additional external dependencies that must be bundled within Nextcloud container in order to work correctly. As we cannot put each and every dependency for all apps into the container - as this would make the project quickly unmaintainable - there is an official way in which you can add additional dependencies into the Nextcloud container. However note that doing this is disrecommended since we do not test Nextcloud apps that require external dependencies.
-You can do so by adding `--env NEXTCLOUD_ADDITIONAL_APKS="imagemagick dependency2 dependency3"` to the docker run command of the mastercontainer (but before the last line `ghcr.io/nextcloud-releases/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used) and customize the value to your fitting. It must be a string with small letters a-z, digits 0-9, spaces, dots and hyphens or '_'. You can find available packages here: https://pkgs.alpinelinux.org/packages?branch=v3.21. By default `imagemagick` is added. If you want to keep it, you need to specify it as well.
+You can do so by adding `--env NEXTCLOUD_ADDITIONAL_APKS="imagemagick dependency2 dependency3"` to the docker run command of the mastercontainer (but before the last line `ghcr.io/nextcloud-releases/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used) and customize the value to your fitting. It must be a string with small letters a-z, digits 0-9, spaces, dots and hyphens or '_'. You can find available packages here: https://pkgs.alpinelinux.org/packages?branch=v3.23. By default `imagemagick` is added. If you want to keep it, you need to specify it as well.
### How to add PHP extensions permanently to the Nextcloud container?
Some Nextcloud apps require additional php extensions that must be bundled within Nextcloud container in order to work correctly. As we cannot put each and every dependency for all apps into the container - as this would make the project quickly unmaintainable - there is an official way in which you can add additional php extensions into the Nextcloud container. However note that doing this is disrecommended since we do not test Nextcloud apps that require additional php extensions.
@@ -509,7 +568,11 @@ The Fulltextsearch Java options are by default set to `-Xms512M -Xmx512M` which
## Guides
### How to run AIO on macOS?
-On macOS, there is only one thing different in comparison to Linux: instead of using `--volume /var/run/docker.sock:/var/run/docker.sock:ro`, you need to use `--volume /var/run/docker.sock.raw:/var/run/docker.sock:ro` to run it after you installed [Docker Desktop](https://www.docker.com/products/docker-desktop/) (and don't forget to [enable ipv6](https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md) if you should need that). Apart from that it should work and behave the same like on Linux.
+
+> [!NOTE]
+> On macOS, it is recommended to use OrbStack instead of Docker Desktop which has much better compatibility with docker for Linux compared to Docker Desktop. See https://orbstack.dev/
+
+Generally, on macOS, there is only one thing different for the docker run command in comparison to Linux: instead of using `--volume /var/run/docker.sock:/var/run/docker.sock:ro`, you need to use `--volume /var/run/docker.sock.raw:/var/run/docker.sock:ro` to run it after you installed [Docker Desktop](https://www.docker.com/products/docker-desktop/) (and don't forget to [enable ipv6](https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md) if you should need that). Apart from that it should work and behave the same like on Linux.
Also, you may be interested in adjusting Nextcloud's Datadir to store the files on the host system. See [this documentation](https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir) on how to do it.
@@ -536,7 +599,7 @@ Also, you may be interested in adjusting Nextcloud's Datadir to store the files
> Almost all commands in this project's documentation use `sudo docker ...`. Since `sudo` is not available on Windows, you simply remove `sudo` from the commands and they should work.
### How to run AIO on Synology DSM
-On Synology, there are two things different in comparison to Linux: instead of using `--volume /var/run/docker.sock:/var/run/docker.sock:ro`, you need to use `--volume /volume1/docker/docker.sock:/var/run/docker.sock:ro` to run it. You also need to add `--env WATCHTOWER_DOCKER_SOCKET_PATH="/volume1/docker/docker.sock"`to the docker run command of the mastercontainer (but before the last line `ghcr.io/nextcloud-releases/all-in-one:latest`). Apart from that it should work and behave the same like on Linux. Obviously the Synology Docker GUI will not work with that so you will need to either use SSH or create a user-defined script task in the task scheduler as the user 'root' in order to run the command.
+On Synology, there are two things different in comparison to Linux: instead of using `--volume /var/run/docker.sock:/var/run/docker.sock:ro`, you need to use `--volume /volume1/docker/docker.sock:/var/run/docker.sock:ro` to run it. You also need to add `--env WATCHTOWER_DOCKER_SOCKET_PATH="/volume1/docker/docker.sock"`to the docker run command of the mastercontainer (but before the last line `ghcr.io/nextcloud-releases/all-in-one:latest`). Additionally, you likely need to adjust the internally used api version. See [this documentation](#how-to-adjust-the-internally-used-docker-api-version). Apart from that it should work and behave the same like on Linux. Obviously the Synology Docker GUI will not work with that so you will need to either use SSH or create a user-defined script task in the task scheduler as the user 'root' in order to run the command.
> [!NOTE]
> It is possible that the docker socket on your Synology is located in `/var/run/docker.sock` like the default on Linux. Then you can just use the Linux command without having to change anything - you will notice this when you try to start the container and it says that the bind mount failed. E.g. `docker: Error response from daemon: Bind mount failed: '/volume1/docker/docker.sock' does not exists.`
@@ -582,7 +645,7 @@ See [multiple-instances.md](./multiple-instances.md) for some documentation on t
Nextcloud features a built-in bruteforce protection which may get triggered and will block an ip-address or disable a user. You can unblock an ip-address by running `sudo docker exec --user www-data -it nextcloud-aio-nextcloud php occ security:bruteforce:reset ` and enable a disabled user by running `sudo docker exec --user www-data -it nextcloud-aio-nextcloud php occ user:enable `. See https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ_command.html#security for further information. **Please note:** If you do not have CLI access to the server, you can now run docker commands via a web session by using this community container: https://github.com/nextcloud/all-in-one/tree/main/community-containers/container-management
### How to switch the channel?
-You can switch to a different channel like e.g. the beta channel or from the beta channel back to the latest channel by stopping the mastercontainer, removing it (no data will be lost) and recreating the container using the same command that you used initially to create the mastercontainer. You simply need to change the last line `ghcr.io/nextcloud-releases/all-in-one:latest` to `ghcr.io/nextcloud-releases/all-in-one:beta` and vice versa.
+You can switch to a different channel like e.g. the beta channel or from the beta channel back to the latest channel by stopping the mastercontainer, removing it (no data will be lost) and recreating the container using the same command that you used initially to create the mastercontainer. You simply need to change the last line `ghcr.io/nextcloud-releases/all-in-one:latest` to `ghcr.io/nextcloud-releases/all-in-one:beta` and vice versa. ⚠️ In some rare occurrences, you might need to run `docker pull ghcr.io/nextcloud-releases/all-in-one:latest` or `docker pull ghcr.io/nextcloud-releases/all-in-one:beta` first before being able to use the image.
### How to update the containers?
If we push new containers to `latest`, you will see in the AIO interface below the `containers` section that new container updates were found. In this case, just press `Stop containers` and `Start and update containers` in order to update the containers. The mastercontainer has its own update procedure though. See below. And don't forget to back up the current state of your instance using the built-in backup solution before starting the containers again! Otherwise you won't be able to restore your instance easily if something should break during the update.
@@ -911,7 +974,7 @@ sudo borg compact
```
After doing so, make sure to update the backup archives list in the AIO interface!
-You can do so by clicking on the `Check backup integrity` button or `Create backup` button.
+You can do so by clicking on the `Update backup list` button in the `Update backup list` section inside the `Backup and restore` section.
---
@@ -1034,7 +1097,7 @@ You can do so by running the `/daily-backup.sh` script that is stored in the mas
- `AUTOMATIC_UPDATES` if set to `1`, it will automatically stop the containers, update them and start them including the mastercontainer. If the mastercontainer gets updated, this script's execution will stop as soon as the mastercontainer gets stopped. You can then wait until it is started again and run the script with this flag again in order to update all containers correctly afterwards.
- `DAILY_BACKUP` if set to `1`, it will automatically stop the containers and create a backup. If you want to start them again afterwards, you may have a look at the `START_CONTAINERS` option.
- `STOP_CONTAINERS` if set to `1`, it will automatically stop the containers at the start of the script. Implied by `DAILY_BACKUP=1`.
-- `START_CONTAINERS` if set to `1`, it will automatically start the containers at the end of the script, without updating them. Implied by `DAILY_BACKUP=1`.
+- `START_CONTAINERS` if set to `1`, it will automatically start the containers at the end of the script, without updating them. Implied by `AUTOMATIC_UPDATES=1`.
- `CHECK_BACKUP` if set to `1`, it will start the integrity check of all borg backups made by AIO. Note that the backup check is non blocking so containers can be kept running while the check lasts. That means you can't pass `DAILY_BACKUP=1` at the same time. The output of the check can be found in the logs of the container `nextcloud-aio-borgbackup`.
One example to do a backup would be `sudo docker exec -it --env DAILY_BACKUP=1 nextcloud-aio-mastercontainer /daily-backup.sh`, which you can run via a cronjob or put it in a script.
@@ -1090,3 +1153,11 @@ AIO ships its own update notifications implementation. It checks if container up
### Huge docker logs
If you should run into issues with huge docker logs, you can adjust the log size by following https://docs.docker.com/config/containers/logging/local/#usage. However for the included AIO containers, this should usually not be needed because almost all of them have the log level set to warn so they should not produce many logs.
+
+
+
+Badges
+
+[](https://deepwiki.com/nextcloud/all-in-one)
+
+
diff --git a/reverse-proxy.md b/reverse-proxy.md
index 84aad3d1..bdeb3244 100644
--- a/reverse-proxy.md
+++ b/reverse-proxy.md
@@ -1,79 +1,156 @@
-# Reverse Proxy Documentation
-
-> [!NOTE]
-> Please note that AIO comes secured with TLS out-of-the-box. So you don't need to necessarily set up your own reverse proxy if you only want to run Nextcloud AIO which is much easier. See [the normal readme](https://github.com/nextcloud/all-in-one?tab=readme-ov-file#how-to-use-this) in that case. However if port 443 should already be used because you already run a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), you need to follow this reverse proxy documentation to set up Nextcloud AIO.
-
-> [!TIP]
-> If you don't have a domain yet, [Tailscale is recommended](https://github.com/nextcloud/all-in-one/discussions/5439). If you don't have a reverse proxy yet, [Caddy is recommended](https://github.com/nextcloud/all-in-one/discussions/575).
+# Using a reverse proxy or secure tunnel to access Nextcloud AIO
## Introduction
-In order to run Nextcloud behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), you need to:
-1. add a specific config to your web server or reverse proxy. [See the documentation below.](#1-configure-the-reverse-proxy)
-2. specify the port that AIO's integrated Apache container shall use via the environmental variable `APACHE_PORT` (that runs inside its own container and published this port on the host) and adjust the `docker run` command of AIO. [See the documentation below.](#2-use-this-startup-command).
-3. Open the AIO interface at port `8080` and type in and validate your domain. [See the documentation below.](#4-open-the-aio-interface)
-Here one example with all reverse proxy settings for Linux:
-```
-sudo docker run \
---init \
---sig-proxy=false \
---name nextcloud-aio-mastercontainer \
---restart always \
---publish 8080:8080 \
---env APACHE_PORT=11000 \
---env APACHE_IP_BINDING=0.0.0.0 \
---env APACHE_ADDITIONAL_NETWORK="" \
---env SKIP_DOMAIN_VALIDATION=false \
---volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
---volume /var/run/docker.sock:/var/run/docker.sock:ro \
-ghcr.io/nextcloud-releases/all-in-one:latest
-```
+This guide explains how to connect to Nextcloud AIO securely via HTTPS (TLS) using a reverse proxy or a secure tunneling platform. It covers several potential scenarios:
-
+- **Integrated**: AIO's built-in reverse proxy with automatic HTTPS
+- **External**: An external reverse proxy (such as Caddy or Nginx or Cloudflare Proxy)
+- **Secure tunnel**: Tunneling services for private network access or public access without port forwarding (such as Tailscale Serve or Cloudflare Tunnel)
-Explanation of the command
+## Choosing Your Approach
-- `sudo docker run` This command spins up a new docker container. Docker commands can optionally be used without `sudo` if the user is added to the docker group (this is not the same as docker rootless, see FAQ in the normal readme).
-- `--init` This option makes sure that no zombie-processes are created, ever. See [the Docker documentation](https://docs.docker.com/reference/cli/docker/container/run/#init).
-- `--sig-proxy=false` This option allows to exit the container shell that gets attached automatically when using `docker run` by using `[CTRL] + [C]` without shutting down the container.
-- `--name nextcloud-aio-mastercontainer` This is the name of the container. This line is not allowed to be changed, since mastercontainer updates would fail.
-- `--restart always` This is the "restart policy". `always` means that the container should always get started with the Docker daemon. See the Docker documentation for further detail about restart policies: https://docs.docker.com/config/containers/start-containers-automatically/
-- `--publish 8080:8080` This means that port 8080 of the container should get published on the host using port 8080. This port is used for the AIO interface and uses a self-signed certificate by default. You can also use a different host port if port 8080 is already used on your host, for example `--publish 8081:8080` (only the first port can be changed for the host, the second port is for the container and must remain at 8080).
-- `--env APACHE_PORT=11000` This is the port that is published on the host that runs Docker and Nextcloud AIO at which the reverse proxy should point at.
-- `--env APACHE_IP_BINDING=0.0.0.0` This can be modified to allow access to the published port on the host only from certain ip-addresses. [See this documentation](#3-limit-the-access-to-the-apache-container)
-- `--env APACHE_ADDITIONAL_NETWORK=""` This can be used to put the sibling apache container that is created by AIO into a specified network - useful if your reverse proxy runs as a container on the same host. [See this documentation](#adapting-the-sample-web-server-configurations-below)
-- `--env SKIP_DOMAIN_VALIDATION=false` This can be set to `true` if the domain validation does not work and you are sure that you configured everything correctly after you followed [the debug documentation](#6-how-to-debug-things).
-- `--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config` This means that the files that are created by the mastercontainer will be stored in a docker volume that is called `nextcloud_aio_mastercontainer`. This line is not allowed to be changed, since built-in backups would fail later on.
-- `--volume /var/run/docker.sock:/var/run/docker.sock:ro` The docker socket is mounted into the container which is used for spinning up all the other containers and for further features. It needs to be adjusted on Windows/macOS and on docker rootless. See the applicable documentation on this. If adjusting, don't forget to also set `WATCHTOWER_DOCKER_SOCKET_PATH`! If you dislike this, see https://github.com/nextcloud/all-in-one/tree/main/manual-install.
-- `ghcr.io/nextcloud-releases/all-in-one:latest` This is the docker container image that is used.
-- Further options can be set using environment variables, for example `--env NEXTCLOUD_DATADIR="/mnt/ncdata"` (This is an example for Linux. See [this](https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir) for other OS' and for an explanation of what this value does. This specific one needs to be specified upon the first startup if you want to change it to a specific path instead of the default Docker volume). To see explanations and examples for further variables (like changing the location of Nextcloud's datadir or mounting some locations as external storage into the Nextcloud container), read through this readme and look at the docker-compose file: https://github.com/nextcloud/all-in-one/blob/main/compose.yaml
-
-
-
-> [!Note]
-> If you run into troubles, see [the debug section](#6-how-to-debug-things).
-
----
-
-> [!IMPORTANT]
-> If you need HTTPS between Nextcloud and the reverse proxy because it is running on a different server in the same network, simply add another reverse proxy to the chain that runs on the same server like AIO and takes care of HTTPS proxying (most likely via self-signed certificates). Another option would be to create a VPN between the server that runs AIO and the server that runs the reverse proxy which takes care of encrypting the connection.
+> [!TIP]
+> If AIO's internal reverse proxy meets your needs, you may not need to set up your own reverse proxy. See the next section to assess whether this is the case.
> [!NOTE]
-> Since the Apache container gets created by the mastercontainer, there is **NO** way to provide custom docker labels or custom environmental variables for the Apache container. So please do not attempt to do this because it will fail!
+> If your goal is to use AIO purely locally, refer to the [Local instance documentation](https://github.com/nextcloud/all-in-one/blob/main/local-instance.md). Local instance setups don't require domain validation.
-## Content
+### When to use each approach
-The process to run Nextcloud behind a reverse proxy consists of at least steps 1, 2 and 4:
-1. **Configure the reverse proxy! See [point 1](#1-configure-the-reverse-proxy)**
-1. **Use this startup command! See [point 2](#2-use-this-startup-command)**
-1. Optional: if the reverse proxy is installed on the same host and in the host network, you should limit the apache container to only listen on localhost. See [point 3](#3-limit-the-access-to-the-apache-container)
-1. **Open the AIO interface. See [point 4](#4-open-the-aio-interface)**
-1. Optional: get a valid certificate for the AIO interface! See [point 5](#5-optional-get-a-valid-certificate-for-the-aio-interface)
-1. Optional: how to debug things? See [point 6](#6-how-to-debug-things)
+| Approach | Best for | Requirements | Inbound Ports Required |
+|----------|----------|--------------|---------------|
+| **Integrated** | Simple setups, single service on port 443 | Public IP, dedicated port 443 | Yes (443) |
+| **External Reverse Proxy** (including Cloudflare Proxy) | Multiple services, existing web server, or users wanting DDoS protection | Existing reverse proxy, willingness to set one up, or Cloudflare account | Yes (443) |
+| **Cloudflare Tunnel** | No port forwarding possible/desired, public access | Cloudflare account | No |
+| **Tailscale Serve** | Private access (tailnet only) | Tailscale account | No |
+| **Tailscale Funnel** | Public access via Tailscale | Tailscale account | No |
-## 1. Configure the reverse proxy
+## Implementation Details
+
+### Integrated: Using AIO's internal reverse proxy with built-in HTTPS support
+
+Nextcloud AIO is secured with TLS (HTTPS) out of the box via its internal reverse proxy. The integrated HTTPS support works well if your goal is to make AIO accessible from the public Internet and to ensure all traffic is encrypted with HTTPS.
+
+Requirements:
+- A public IP address that is reachable from the Internet (it does **not** need to be static, but it must not be behind carrier-grade NAT, which some ISPs use to share IP addresses among multiple customers).
+- Port `443/tcp` on that IP must be available for AIO's exclusive use, and it must be opened/forwarded on your internet-facing firewall/router to the AIO host.[^talkPort]
+
+**If AIO's integrated HTTPS support and internal reverse proxy meet your requirements, you do not need to proceed further. Follow the [standard Nextcloud AIO instructions](https://github.com/nextcloud/all-in-one#how-to-use-this).**
+
+### External: Using AIO with an external reverse proxy (e.g., *Caddy, Nginx, Cloudflare Proxy*)
+
+**When you use an external reverse proxy, you disable AIO's built-in HTTPS support** because your reverse proxy will handle HTTPS/TLS certificates and encryption instead. This approach is necessary when:
+- Port 443 is already in use by another service
+- You want to run multiple web services on the same IP address
+- You already have an existing reverse proxy infrastructure
+
+A reverse proxy (or a web server acting as a reverse proxy) enables multiple web applications to share the same IP address and/or port (for example `443/tcp`) by directing traffic based on each application's hostname (often called "virtual hosts"). Incoming requests reach the reverse proxy and are then forwarded to the appropriate internal IP address, port, or container based on the requested hostname.
+
+**Types of external reverse proxies:**
+- **Self-hosted** (Caddy, Nginx, Apache, Traefik, HAProxy, etc.) - You manage the reverse proxy on your own server or separate server
+- **Cloudflare Proxy** (orange-clouded DNS) - Cloudflare provides the reverse proxy at their edge network with DDoS protection and CDN benefits. This is distinct from Cloudflare Tunnel, though Tunnel can optionally use these proxy features when publishing routes.
+
+Most notably, an external reverse proxy allows you to:
+- share one external IP address among multiple hostnames/web applications, and
+- use a different internal port than the externally used port.
+
+Using an existing external reverse proxy is required in particular if port `443/tcp` on your public IP is already in use by another web application or by an existing web server/reverse proxy (for example Caddy or Nginx).
+
+> [!NOTE]
+> Cloudflare **Tunnel** and Cloudflare **Proxy** are different approaches:
+> - **Cloudflare Tunnel** doesn't require opening any inbound ports on your firewall.
+> - **Cloudflare Proxy** still requires port 443 exposed on your server.
+
+> [!TIP]
+> Examples of web servers or reverse proxies you might already be running include Apache, Caddy, Nginx, Traefik, and HAProxy — but only if they are bound to port `443/tcp` on the IP address you plan to associate with AIO.
+
+> [!NOTE]
+> An external reverse proxy can also facilitate other routing approaches, but Nextcloud AIO only supports having its own dedicated hostname (e.g., `cloud.example.com`). You cannot run it in a subfolder like `example.com/nextcloud/`.[^shared]
+
+### Secure tunnel: Using AIO with a secure tunneling service (*Tailscale, Cloudflare*)
+
+Cloudflare and Tailscale offer secure tunneling services that let you access your Nextcloud without opening ports on your firewall.
+
+#### Private network access
+
+For Nextcloud AIO, you can use:
+- **Cloudflare Tunnel (`cloudflared`)** - Secure outbound-only tunnels that don't require exposing ports
+- **Tailscale Serve** - Expose services privately on your Tailscale network (tailnet only)
+
+Both options provide private network access to your Nextcloud AIO instance.
+
+#### Public Internet access (without port forwarding)
+
+To make your Nextcloud AIO instance accessible from the public Internet (not just your private network), you can use:
+- **Cloudflare Tunnel** with public routes enabled (which combines Cloudflare Tunnel with Cloudflare's proxy features)
+- **Tailscale Funnel** - Expose services to the public Internet via Tailscale's infrastructure
+
+**Comparison of Cloudflare and Tailscale options:**
+
+| Feature | Access Scope | Inbound Ports Required | Use Case |
+|---------|--------------|----------------|----------|
+| **Cloudflare Tunnel** | Public Internet | None | Public access without port forwarding |
+| **Tailscale Serve** | Your Tailscale network only | None | Private access for you and invited users |
+| **Tailscale Funnel** | Public Internet | None | Public access through Tailscale |
+
+> [!TIP]
+> Because of how [Cloudflare's Tunnel/Proxy operate](https://github.com/nextcloud/all-in-one/tree/main#notes-on-cloudflare-proxytunnel), we recommend using Tailscale with Nextcloud when possible. Tailscale typically offers better performance and fewer trade-offs/limitations for Nextcloud.
+>
+> **For private/personal use**: [Tailscale Serve](https://tailscale.com/kb/1312/serve) is ideal - it keeps your Nextcloud completely private to your tailnet.
+>
+> **For public access without port forwarding**: Use [Tailscale Funnel](https://tailscale.com/kb/1223/funnel).
+
+## Configuration and Deployment
+
+> [!NOTE]
+> These instructions assume you already have a domain name pointing to your server's public IP address. If you don't have a domain yet, see the recommendations below.
+
+### Quick overview
+
+To run Nextcloud AIO behind an external reverse proxy or secure tunneling/proxying service (instead of using AIO's integrated reverse proxy), the basic process is:
+
+1. Configure your web server or reverse proxy with the specific settings for AIO.
+2. Specify the port that AIO's integrated Apache container will use.
+3. Open the AIO interface and validate your domain.
+
+The sections below provide detailed instructions for each step.
+
+> [!TIP]
+> If you don't have a domain yet, we recommend using [an approach using Tailscale](https://github.com/nextcloud/all-in-one/discussions/6817). If you don't have an external reverse proxy yet, we recommend [Caddy](https://github.com/nextcloud/all-in-one/discussions/575).
+
+### Step-by-Step Instructions
+
+The process to run Nextcloud AIO behind a reverse proxy has three required steps and three optional steps:
+
+**Required steps:**
+1. **Configure** your web server or reverse proxy with the specific settings for AIO. See ["Configuring your reverse proxy"](#1-configure-the-reverse-proxy) below.
+2. **Specify** the port that AIO's integrated Apache container will use via the environment variable `APACHE_PORT`, and update the `docker run` command or your Compose file accordingly. See ["Use this startup command"](#2-use-this-startup-command) below.
+ - *Optional*: Limit the access to the Apache container. See ["Limit the access to the Apache container"](#3-limit-the-access-to-the-apache-container).
+3. **Open** the AIO interface at port `8080`, enter your domain, and validate it. See ["Open the AIO interface"](#4-open-the-aio-interface) below.
+
+**Optional steps:**
+
+4. Configure additional settings if your reverse proxy uses an IP address to connect to AIO. See ["Configure AIO for IP-based reverse proxies"](#5-optional-configure-aio-for-reverse-proxies-that-connect-to-nextcloud-using-an-ip-address-and-not-localhost-nor-127001).
+5. Get a valid certificate for the AIO interface. See ["Get a valid certificate for the AIO interface"](#6-optional-get-a-valid-certificate-for-the-aio-interface).
+6. Debug things if needed. See ["How to debug things"](#7-how-to-debug-things).
+
+> [!NOTE]
+> If you run into troubles, see [the debug section](#7-how-to-debug-things).
+
+> [!IMPORTANT]
+> If you need HTTPS between Nextcloud and the reverse proxy (because the reverse proxy runs on a different server), you have two options:
+>
+> 1. **Add a local reverse proxy**: Install another reverse proxy on the same server as AIO to handle HTTPS (typically with self-signed certificates)
+> 2. **Use a VPN**: Create a VPN tunnel between the AIO server and the reverse proxy server to encrypt the connection
+
+> [!NOTE]
+> Since the Apache container gets created by the mastercontainer, there is **NO** way to provide custom Docker labels or custom environmental variables for the Apache container. So please do not attempt to do this because it will fail!
+
+### 1. Configure the reverse proxy
+
+#### Adapting the sample web server configurations below
-### Adapting the sample web server configurations below
1. Replace `` with the domain on which you want to run Nextcloud.
1. Adjust the port `11000` to match your chosen `APACHE_PORT`.
1. Adjust `localhost` or `127.0.0.1` to point to the Nextcloud server IP or domain depending on where the reverse proxy is running. See the following options.
@@ -107,7 +184,7 @@ The process to run Nextcloud behind a reverse proxy consists of at least steps 1
-### Apache
+##### Apache
@@ -187,7 +264,7 @@ To make the config work you can run the following command:
-### Caddy (recommended)
+##### Caddy (recommended)
@@ -210,7 +287,7 @@ The Caddyfile is a text file called `Caddyfile` (no extension) which – if you
-### Caddy with ACME DNS-challenge
+##### Caddy with ACME DNS-challenge
@@ -238,7 +315,7 @@ You can get AIO running using the ACME DNS-challenge. Here is how to do it.
-### OpenLiteSpeed
+##### OpenLiteSpeed
@@ -248,7 +325,7 @@ You can find the OpenLiteSpeed reverse proxy guide by @MorrowShore here: https:/
-### Citrix ADC VPX / Citrix Netscaler
+##### Citrix ADC VPX / Citrix Netscaler
@@ -258,7 +335,7 @@ For a reverse proxy example guide for Citrix ADC VPX / Citrix Netscaler, see thi
-### Cloudflare Tunnel
+##### Cloudflare Tunnel
@@ -277,7 +354,7 @@ Although it does not seem like it is the case but from AIO perspective a Cloudfl
-### HaProxy
+##### HAProxy
@@ -374,7 +451,7 @@ backend Nextcloud
-### Nginx, Freenginx, Openresty, Angie
+##### Nginx, Freenginx, Openresty, Angie
@@ -473,7 +550,7 @@ server {
-### NPMplus (Fork of Nginx-Proxy-Manager - NPM)
+##### NPMplus (Fork of Nginx-Proxy-Manager - NPM)
@@ -487,24 +564,19 @@ Note: this will cause that a non root user can bind privileged ports.
Second, see these screenshots for a working config:
-
+
-
+
-
+
-
+
-
-
-`proxy_set_header Accept-Encoding $http_accept_encoding;`
-
-⚠️ **Please note:** Nextcloud will complain that X-XXS-Protection is set to the wrong value, this is intended by NPMplus.
⚠️ **Please note:** look into [this](#adapting-the-sample-web-server-configurations-below) to adapt the above example configuration.
-### Nginx-Proxy-Manager - NPM
+##### Nginx-Proxy-Manager - NPM
@@ -537,13 +609,15 @@ Also change `@` to a mail address of yours.
-### Nginx-Proxy
+##### Nginx-Proxy
click here to expand
-Unfortunately, it is not possible to configure Nginx-proxy in a way that works because it completely relies on environmental variables of the docker containers itself. Providing these variables does not work as stated above.
+This section refers to the dedicated project named `nginx-proxy`. See its [GitHub repo](https://github.com/nginx-proxy/nginx-proxy). If you should be looking for Nginx, see the `Nginx, Freenginx, Openresty, Angie` section in this docu.
+
+Unfortunately, it is not possible to configure `nginx-proxy` in a way that works because it completely relies on environmental variables of the docker containers itself. Providing these variables does not work as stated above.
If you really want to use AIO, we recommend you to switch to caddy. It is simply amazing!
@@ -551,7 +625,7 @@ Apart from that, there is a [manual-install](https://github.com/nextcloud/all-in
-### Node.js with Express
+##### Node.js with Express
@@ -638,7 +712,7 @@ httpServer.on('upgrade', (req, socket, head) => {
-### Synology Reverse Proxy
+##### Synology Reverse Proxy
@@ -656,7 +730,27 @@ See these screenshots for a working config:
-### Traefik 2
+##### Tailscale (Serve)
+
+
+
+Click here to expand
+
+Tailscale can be used to provide private access to your Nextcloud AIO instance without opening ports on your firewall. With **Tailscale Serve**, your Nextcloud is accessible only to devices on your Tailscale network (tailnet) via a secure HTTPS domain.
+
+For a detailed setup guide using Tailscale Serve with Nextcloud AIO, see this guide by [@Perseus333](https://github.com/Perseus333): https://github.com/nextcloud/all-in-one/discussions/6817
+
+The guide covers:
+- Setting up system-wide (non-containerized) Tailscale as a reverse proxy
+- Configuring Nextcloud AIO to work with Tailscale Serve
+- Using Tailscale's MagicDNS to provide automatic HTTPS certificates
+- Private access via your tailnet (e.g., `yourserver.tail0a12b3.ts.net`)
+
+⚠️ **Please note:** This guide covers **Tailscale Serve** for private tailnet access. If you need public Internet access, consider using **Tailscale Funnel**.
+
+
+
+##### Traefik 2
@@ -678,6 +772,9 @@ The examples below define the dynamic configuration in YAML files. If you rather
entryPoints:
https:
address: ":443" # Create an entrypoint called "https" that uses port 443
+ transport:
+ respondingTimeouts:
+ readTimeout: 24h # Allows uploads > 100MB; prevents connection reset due to chunking (public upload-only links)
# If you want to enable HTTP/3 support, uncomment the line below
# http3: {}
@@ -745,7 +842,7 @@ The examples below define the dynamic configuration in YAML files. If you rather
-### Traefik 3
+##### Traefik 3
@@ -765,6 +862,15 @@ The examples below define the dynamic configuration in YAML files. If you rather
entryPoints:
https:
address: ":443" # Create an entrypoint called "https" that uses port 443
+ transport:
+ respondingTimeouts:
+ readTimeout: 24h # Allows uploads > 100MB; prevents connection reset due to chunking (public upload-only links)
+ http:
+ # Required for Nextcloud to correctly handle encoded URL characters (%2F, %3F and %25 in this case) in newer Traefik versions (v3.6.4+).
+ encodedCharacters:
+ allowEncodedSlash: true
+ allowEncodedQuestionMark: true
+ allowEncodedPercent: true
# If you want to enable HTTP/3 support, uncomment the line below
# http3: {}
@@ -828,7 +934,7 @@ The examples below define the dynamic configuration in YAML files. If you rather
-### IIS with ARR and URL Rewrite
+##### IIS with ARR and URL Rewrite
@@ -898,18 +1004,7 @@ Add the following `web.config` file to the root of the site you created as the r
-### Tailscale
-
-
-
-click here to expand
-
-For a reverse proxy example guide for Tailscale, see this guide by @flll: https://github.com/nextcloud/all-in-one/discussions/5439
-
-
-
-
-### Others
+##### Others
@@ -919,7 +1014,7 @@ Config examples for other reverse proxies are currently not documented. Pull req
-## 2. Use this startup command
+### 2. Use this startup command
After adjusting your reverse proxy config, use the following command to start AIO:
@@ -942,6 +1037,27 @@ sudo docker run \
ghcr.io/nextcloud-releases/all-in-one:latest
```
+
+
+Explanation of the command
+
+- `sudo docker run` This command spins up a new docker container. Docker commands can optionally be used without `sudo` if the user is added to the docker group (this is not the same as docker rootless, see FAQ in the normal readme).
+- `--init` This option makes sure that no zombie-processes are created, ever. See [the Docker documentation](https://docs.docker.com/reference/cli/docker/container/run/#init).
+- `--sig-proxy=false` This option allows to exit the container shell that gets attached automatically when using `docker run` by using `[CTRL] + [C]` without shutting down the container.
+- `--name nextcloud-aio-mastercontainer` This is the name of the container. This line is not allowed to be changed, since mastercontainer updates would fail.
+- `--restart always` This is the "restart policy". `always` means that the container should always get started with the Docker daemon. See the Docker documentation for further detail about restart policies: https://docs.docker.com/config/containers/start-containers-automatically/
+- `--publish 8080:8080` This means that port 8080 of the container should get published on the host using port 8080. This port is used for the AIO interface and uses a self-signed certificate by default. You can also use a different host port if port 8080 is already used on your host, for example `--publish 8081:8080` (only the first port can be changed for the host, the second port is for the container and must remain at 8080).
+- `--env APACHE_PORT=11000` This is the port that is published on the host that runs Docker and Nextcloud AIO at which the reverse proxy should point at.
+- `--env APACHE_IP_BINDING=0.0.0.0` This can be modified to allow access to the published port on the host only from certain ip-addresses. [See this documentation](#3-limit-the-access-to-the-apache-container)
+- `--env APACHE_ADDITIONAL_NETWORK=""` This can be used to put the sibling apache container that is created by AIO into a specified network - useful if your reverse proxy runs as a container on the same host. [See this documentation](#adapting-the-sample-web-server-configurations-below)
+- `--env SKIP_DOMAIN_VALIDATION=false` This can be set to `true` if the domain validation does not work and you are sure that you configured everything correctly after you followed [the debug documentation](#7-how-to-debug-things). Also see [this documentation](https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation).
+- `--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config` This means that the files that are created by the mastercontainer will be stored in a docker volume that is called `nextcloud_aio_mastercontainer`. This line is not allowed to be changed, since built-in backups would fail later on.
+- `--volume /var/run/docker.sock:/var/run/docker.sock:ro` The docker socket is mounted into the container which is used for spinning up all the other containers and for further features. It needs to be adjusted on Windows/macOS and on docker rootless. See the applicable documentation on this. If adjusting, don't forget to also set `WATCHTOWER_DOCKER_SOCKET_PATH`! If you dislike this, see https://github.com/nextcloud/all-in-one/tree/main/manual-install.
+- `ghcr.io/nextcloud-releases/all-in-one:latest` This is the docker container image that is used.
+- Further options can be set using environment variables, for example `--env NEXTCLOUD_DATADIR="/mnt/ncdata"` (This is an example for Linux. See [this](https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir) for other OS' and for an explanation of what this value does. This specific one needs to be specified upon the first startup if you want to change it to a specific path instead of the default Docker volume). To see explanations and examples for further variables (like changing the location of Nextcloud's datadir or mounting some locations as external storage into the Nextcloud container), read through this readme and look at the docker-compose file: https://github.com/nextcloud/all-in-one/blob/main/compose.yaml
+
+
+
Note: you may be interested in adjusting Nextcloud’s datadir to store the files in a different location than the default docker volume. See [this documentation](https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir) on how to do it.
You should also think about limiting the Apache container to listen only on localhost in case the reverse proxy is running on the same host and in the host network, by providing an additional environmental variable to this docker run command. See [point 3](#3-limit-the-access-to-the-apache-container).
@@ -980,17 +1096,38 @@ On Synology DSM see https://github.com/nextcloud/all-in-one#how-to-run-aio-on-sy
Simply translate the docker run command into a docker-compose file. You can have a look at [this file](https://github.com/nextcloud/all-in-one/blob/main/compose.yaml) for some inspiration but you will need to modify it either way. You can find further examples here: https://github.com/nextcloud/all-in-one/discussions/588
-## 3. Limit the access to the Apache container
+### 3. Limit the access to the Apache container
Use this environment variable during the initial startup of the mastercontainer to make the apache container only listen on localhost: `--env APACHE_IP_BINDING=127.0.0.1`. **Attention:** This is only recommended to be set if you use `localhost` in your reverse proxy config to connect to your AIO instance. If you use an ip-address instead of localhost, you should set it to `0.0.0.0`.
-## 4. Open the AIO interface
+### 4. Open the AIO interface
After starting AIO, you should be able to access the AIO Interface via `https://ip.address.of.the.host:8080` and type in and validate the domain that you have configured.
⚠️ **Important:** do always use an ip-address if you access this port and not a domain as HSTS might block access to it later! (It is also expected that this port uses a self-signed certificate due to security concerns which you need to accept in your browser)
Enter your domain in the AIO interface that you've used in the reverse proxy config and you should be done. Please do not forget to open/forward port `3478/TCP` and `3478/UDP` in your firewall/router for the Talk container!
-## 5. Optional: get a valid certificate for the AIO interface
+### 5. Optional: Configure AIO for reverse proxies that connect to nextcloud using an ip-address and not localhost nor 127.0.0.1
+If your reverse proxy connects to nextcloud using an ip-address and not localhost or 127.0.0.1* you must make the following configuration changes
+
+*: The IP address it uses to connect to AIO is not in a private IP range such as these: `127.0.0.0/8,192.168.0.0/16,172.16.0.0/12,10.0.0.0/8,100.64.0.0/10,fd00::/8,::1/128`
+
+#### Nextcloud trusted proxies
+Add the IP it uses connect to AIO to the Nextcloud trusted_proxies like this:
+
+```
+sudo docker exec --user www-data -it nextcloud-aio-nextcloud php occ config:system:set trusted_proxies 2 --value=ip.address.of.proxy
+```
+
+#### Collabora WOPI allow list
+If your reverse proxy connects to Nextcloud with an IP address that is different from the one for your domain* and you are using the Collabora server then you must also add the IP to the WOPI request allow list via `Administration Settings > Administration > Office > Allow list for WOPI requests`.
+
+*: For example, the reverse proxy has a public globally routable IP and connects to your AIO instance via Tailscale with an IP in the `100.64.0.0/10` range, or you are using a Cloudflare tunnel ([cloudflare notes](https://github.com/nextcloud/all-in-one#notes-on-cloudflare-proxytunnel): You must add all [Cloudflare IP-Ranges](https://www.cloudflare.com/ips/) to the WOPI allowlist.)
+
+#### External reverse proxies connecting via VPN (e.g. Tailscale)
+
+If your reverse proxy is outside your LAN and connecting via VPN such as Tailscale, you may want to set `APACHE_IP_BINDING=AIO.VPN.host.IP` to ensure only traffic coming from the VPN can connect.
+
+### 6. Optional: get a valid certificate for the AIO interface
If you want to also access your AIO interface publicly with a valid certificate, you can add e.g. the following config to your Caddyfile:
@@ -1007,7 +1144,10 @@ https://:8443 {
Afterwards should the AIO interface be accessible via `https://ip.address.of.the.host:8443`. You can alternatively change the domain to a different subdomain by using `https://:443` instead of `https://:8443` in the Caddyfile and use that to access the AIO interface.
-## 6. How to debug things?
+### 7. How to debug things?
+
+
+
If something does not work, follow the steps below:
1. Make sure to exactly follow the whole reverse proxy documentation step-for-step from top to bottom!
@@ -1023,4 +1163,31 @@ If something does not work, follow the steps below:
1. Check if you have a public IPv4- and public IPv6-address. If you only have a public IPv6-address (e.g. due to DS-Lite), make sure to enable IPv6 in Docker and your whole networking infrastructure (e.g. also by adding an AAAA DNS-entry to your domain)!
1. [Enable Hairpin NAT in your router](https://github.com/nextcloud/all-in-one/discussions/5849) or [set up a local DNS server and add a custom dns-record](https://github.com/nextcloud/all-in-one#how-can-i-access-nextcloud-locally) that allows the server to reach itself locally
1. Try to configure everything from scratch - if it still does not work by following https://github.com/nextcloud/all-in-one#how-to-properly-reset-the-instance.
-1. As last resort, you may disable the domain validation by adding `--env SKIP_DOMAIN_VALIDATION=true` to the docker run command. But only use this if you are completely sure that you've correctly configured everything!
+1. As last resort, you may disable the domain validation by adding `--env SKIP_DOMAIN_VALIDATION=true` to the docker run command. But only use this if you are completely sure that you've correctly configured everything! Also see [this documentation](https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation).
+
+### 8. Removing the reverse proxy
+
+If you, at some point, want to remove the reverse proxy, here are some general steps:
+1. Stop all running containers in the AIO Interface.
+2. Stop and remove the mastercontainer.
+ ```
+ sudo docker stop nextcloud-aio-mastercontainer
+ sudo docker rm nextcloud-aio-mastercontainer
+ ```
+3. Remove the software and configuration file that you used for the reverse proxy (see section 1).
+4. Restart the mastercontainer with the [docker run command from the main readme](https://github.com/nextcloud/all-in-one#how-to-use-this) but add the two options:
+ ```
+ --env APACHE_IP_BINDING=0.0.0.0 \
+ --env APACHE_PORT=443 \
+ ```
+ Do this *before* the last line of the run command!
+
+ *The first command ensures that the Apache container is listening on all available network interfaces and the second command configures it to listen to port 443.*
+5. Restart all other containers in the AIO interface.
+
+---
+
+## Footnotes:
+
+[^talkPort]: Ports 3478/TCP and 3478/UDP are also required if using Nextcloud Talk (but they're less likely to conflict with existing services).
+[^shared]: Other Nextcloud Server deployment methods (but not AIO) can be deployed behind shared hostnames and accessed via subfolder-based URLs. For example, this is supported with Bare Metal (Archive) and the micro-services Docker image, among others. Note that pure subfolder deployments are less and less required these days, with the broad support for virtual host based access (including at the reverse proxy level), which easily facilitates port IP address and external port sharing.
diff --git a/tests/QA/060-environmental-variables.md b/tests/QA/060-environmental-variables.md
index 818ecf7c..b984c0e3 100644
--- a/tests/QA/060-environmental-variables.md
+++ b/tests/QA/060-environmental-variables.md
@@ -6,6 +6,7 @@
- [ ] When starting the mastercontainer with `--env TALK_PORT=3479` on a clean instance, the talk container should use this port later on. Using a value here that is not a port will not allow the mastercontainer to start correctly. Also it should stop if apache_port and talk_port are set to the same value.
- [ ] Make also sure that reverse proxies work by following https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#reverse-proxy-documentation and following [001-initial-setup.md](./001-initial-setup.md) and [002-new-instance.md](./002-new-instance.md)
- [ ] When starting the mastercontainer with `--env SKIP_DOMAIN_VALIDATION=true` on a clean instance, it should skip the domain verification. So it should accept any domain that you type in then.
+- [ ] When starting the mastercontainer with `--env DOCKER_API_VERSION=1.44` it should use the mentioned docker API version internally for all requests
- [ ] When starting the mastercontainer with `--env NEXTCLOUD_DATADIR="/mnt/testdata"` it should map that location from `/mnt/testdata` to `/mnt/ncdata` inside the Nextcloud container. Not having adjusted the permissions correctly before starting the Nextcloud container the first time will not allow the Nextcloud container to start correctly. See https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir for allowed values.
- [ ] When starting the mastercontainer with `--env NEXTCLOUD_MOUNT="/mnt/"` it should map `/mnt/` to `/mnt/` inside the Nextcloud container. See https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host for allowed values.
- [ ] When starting the mastercontainer with `--env NEXTCLOUD_UPLOAD_LIMIT=11G` it should change Nextclouds upload limit to 11G. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-upload-limit-for-nextcloud for allowed values.
diff --git a/zizmor.yml b/zizmor.yml
new file mode 100644
index 00000000..a991eaa5
--- /dev/null
+++ b/zizmor.yml
@@ -0,0 +1,10 @@
+rules:
+ excessive-permissions:
+ disable: true
+ dangerous-triggers:
+ ignore:
+ - build_images.yml
+ unpinned-uses:
+ config:
+ policies:
+ actions/*: ref-pin