Showing preview only (1,432K chars total). Download the full file or copy to clipboard to get everything.
Repository: nextcloud/all-in-one
Branch: main
Commit: 35dd0a2c0084
Files: 361
Total size: 1.3 MB
Directory structure:
gitextract_32moa423/
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── Bug_report.md
│ │ ├── Feature_request.md
│ │ └── config.yml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ ├── release.yml
│ └── workflows/
│ ├── codespell.yml
│ ├── collabora.yml
│ ├── community-containers.yml
│ ├── dependency-updates.yml
│ ├── docker-lint.yml
│ ├── fail-on-prerelease.yml
│ ├── helm-release.yml
│ ├── imaginary-update.yml
│ ├── json-validator.yml
│ ├── lint-helm.yml
│ ├── lint-php.yml
│ ├── lint-yaml.yml
│ ├── lock-threads.yml
│ ├── nextcloud-update.yml
│ ├── php-deprecation-detector.yml
│ ├── playwright-on-push.yml
│ ├── playwright-on-workflow-dispatch.yml
│ ├── psalm-update-baseline.yml
│ ├── psalm.yml
│ ├── shellcheck.yml
│ ├── talk.yml
│ ├── twig-lint.yml
│ ├── update-copyright.yml
│ ├── update-helm.yml
│ ├── update-yaml.yml
│ └── watchtower-update.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── Containers/
│ ├── alpine/
│ │ └── Dockerfile
│ ├── apache/
│ │ ├── Caddyfile
│ │ ├── Dockerfile
│ │ ├── healthcheck.sh
│ │ ├── nextcloud.conf
│ │ ├── start.sh
│ │ └── supervisord.conf
│ ├── borgbackup/
│ │ ├── Dockerfile
│ │ ├── backupscript.sh
│ │ ├── borg_excludes
│ │ └── start.sh
│ ├── clamav/
│ │ ├── Dockerfile
│ │ ├── healthcheck.sh
│ │ ├── start.sh
│ │ └── supervisord.conf
│ ├── collabora/
│ │ ├── Dockerfile
│ │ └── healthcheck.sh
│ ├── collabora-online/
│ │ ├── Dockerfile
│ │ └── healthcheck.sh
│ ├── docker-socket-proxy/
│ │ ├── Dockerfile
│ │ ├── haproxy.cfg
│ │ ├── healthcheck.sh
│ │ └── start.sh
│ ├── domaincheck/
│ │ ├── Dockerfile
│ │ ├── lighttpd.conf
│ │ └── start.sh
│ ├── fulltextsearch/
│ │ ├── Dockerfile
│ │ └── healthcheck.sh
│ ├── imaginary/
│ │ ├── Dockerfile
│ │ ├── healthcheck.sh
│ │ └── start.sh
│ ├── mastercontainer/
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── acme.Caddyfile
│ │ ├── backup-time-file-watcher.sh
│ │ ├── cron.sh
│ │ ├── daily-backup.sh
│ │ ├── healthcheck.sh
│ │ ├── internal.Caddyfile
│ │ ├── session-deduplicator.sh
│ │ ├── start.sh
│ │ └── supervisord.conf
│ ├── nextcloud/
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── config/
│ │ │ ├── aio.config.php
│ │ │ ├── apcu.config.php
│ │ │ ├── apps.config.php
│ │ │ ├── certificates-bundle.config.php
│ │ │ ├── postgres.config.php
│ │ │ ├── proxy.config.php
│ │ │ ├── redis.config.php
│ │ │ ├── reverse-proxy.config.php
│ │ │ ├── s3.config.php
│ │ │ ├── smtp.config.php
│ │ │ └── swift.config.php
│ │ ├── cron.sh
│ │ ├── entrypoint.sh
│ │ ├── healthcheck.sh
│ │ ├── notify-all.sh
│ │ ├── notify.sh
│ │ ├── root.motd
│ │ ├── run-exec-commands.sh
│ │ ├── start.sh
│ │ ├── supervisord.conf
│ │ └── upgrade.exclude
│ ├── notify-push/
│ │ ├── Dockerfile
│ │ ├── healthcheck.sh
│ │ └── start.sh
│ ├── onlyoffice/
│ │ ├── Dockerfile
│ │ └── healthcheck.sh
│ ├── postgresql/
│ │ ├── Dockerfile
│ │ ├── healthcheck.sh
│ │ ├── init-user-db.sh
│ │ └── start.sh
│ ├── redis/
│ │ ├── Dockerfile
│ │ ├── healthcheck.sh
│ │ └── start.sh
│ ├── talk/
│ │ ├── Dockerfile
│ │ ├── healthcheck.sh
│ │ ├── server.conf.in
│ │ ├── start.sh
│ │ └── supervisord.conf
│ ├── talk-recording/
│ │ ├── Dockerfile
│ │ ├── healthcheck.sh
│ │ ├── recording.conf
│ │ └── start.sh
│ ├── watchtower/
│ │ ├── Dockerfile
│ │ └── start.sh
│ └── whiteboard/
│ ├── Dockerfile
│ ├── healthcheck.sh
│ └── start.sh
├── LICENSE
├── app/
│ ├── .editorconfig
│ ├── appinfo/
│ │ └── info.xml
│ ├── composer/
│ │ ├── autoload.php
│ │ ├── composer/
│ │ │ ├── ClassLoader.php
│ │ │ ├── InstalledVersions.php
│ │ │ ├── LICENSE
│ │ │ ├── autoload_classmap.php
│ │ │ ├── autoload_namespaces.php
│ │ │ ├── autoload_psr4.php
│ │ │ ├── autoload_real.php
│ │ │ ├── autoload_static.php
│ │ │ ├── installed.json
│ │ │ └── installed.php
│ │ └── composer.json
│ ├── lib/
│ │ └── Settings/
│ │ └── Admin.php
│ ├── readme.md
│ └── templates/
│ └── admin.php
├── community-containers/
│ ├── borgbackup-viewer/
│ │ ├── borgbackup-viewer.json
│ │ └── readme.md
│ ├── caddy/
│ │ ├── caddy.json
│ │ └── readme.md
│ ├── calcardbackup/
│ │ ├── calcardbackup.json
│ │ └── readme.md
│ ├── container-management/
│ │ ├── container-management.json
│ │ └── readme.md
│ ├── dlna/
│ │ ├── dlna.json
│ │ └── readme.md
│ ├── facerecognition/
│ │ ├── facerecognition.json
│ │ └── readme.md
│ ├── fail2ban/
│ │ ├── fail2ban.json
│ │ └── readme.md
│ ├── glances/
│ │ ├── glances.json
│ │ └── readme.md
│ ├── helloworld/
│ │ ├── helloworld.json
│ │ └── readme.md
│ ├── jellyfin/
│ │ ├── jellyfin.json
│ │ └── readme.md
│ ├── jellyseerr/
│ │ ├── jellyseerr.json
│ │ └── readme.md
│ ├── languagetool/
│ │ ├── languagetool.json
│ │ └── readme.md
│ ├── libretranslate/
│ │ ├── libretranslate.json
│ │ └── readme.md
│ ├── lldap/
│ │ ├── lldap.json
│ │ └── readme.md
│ ├── local-ai/
│ │ ├── local-ai.json
│ │ └── readme.md
│ ├── makemkv/
│ │ ├── makemkv.json
│ │ └── readme.md
│ ├── memories/
│ │ ├── memories.json
│ │ └── readme.md
│ ├── minio/
│ │ ├── minio.json
│ │ └── readme.md
│ ├── nextcloud-exporter/
│ │ ├── nextcloud-exporter.json
│ │ └── readme.md
│ ├── nocodb/
│ │ ├── nocodb.json
│ │ └── readme.md
│ ├── notifications/
│ │ ├── notifications.json
│ │ └── readme.md
│ ├── npmplus/
│ │ ├── npmplus.json
│ │ └── readme.md
│ ├── pi-hole/
│ │ ├── pi-hole.json
│ │ └── readme.md
│ ├── plex/
│ │ ├── plex.json
│ │ └── readme.md
│ ├── readme.md
│ ├── scrutiny/
│ │ ├── readme.md
│ │ └── scrutiny.json
│ ├── smbserver/
│ │ ├── readme.md
│ │ └── smbserver.json
│ ├── stalwart/
│ │ ├── readme.md
│ │ └── stalwart.json
│ └── vaultwarden/
│ ├── readme.md
│ └── vaultwarden.json
├── compose.yaml
├── develop.md
├── docker-ipv6-support.md
├── docker-rootless.md
├── local-instance.md
├── manual-install/
│ ├── latest.yml
│ ├── readme.md
│ ├── sample.conf
│ └── update-yaml.sh
├── manual-upgrade.md
├── migration.md
├── multiple-instances.md
├── nextcloud-aio-helm-chart/
│ ├── Chart.yaml
│ ├── readme.md
│ ├── templates/
│ │ ├── nextcloud-aio-apache-deployment.yaml
│ │ ├── nextcloud-aio-apache-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-apache-service.yaml
│ │ ├── nextcloud-aio-clamav-deployment.yaml
│ │ ├── nextcloud-aio-clamav-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-clamav-service.yaml
│ │ ├── nextcloud-aio-collabora-deployment.yaml
│ │ ├── nextcloud-aio-collabora-service.yaml
│ │ ├── nextcloud-aio-database-deployment.yaml
│ │ ├── nextcloud-aio-database-dump-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-database-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-database-service.yaml
│ │ ├── nextcloud-aio-elasticsearch-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-fulltextsearch-deployment.yaml
│ │ ├── nextcloud-aio-fulltextsearch-service.yaml
│ │ ├── nextcloud-aio-imaginary-deployment.yaml
│ │ ├── nextcloud-aio-imaginary-service.yaml
│ │ ├── nextcloud-aio-namespace-namespace.yaml
│ │ ├── nextcloud-aio-networkpolicy.yaml
│ │ ├── nextcloud-aio-nextcloud-data-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-nextcloud-deployment.yaml
│ │ ├── nextcloud-aio-nextcloud-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-nextcloud-service.yaml
│ │ ├── nextcloud-aio-nextcloud-trusted-cacerts-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-notify-push-deployment.yaml
│ │ ├── nextcloud-aio-notify-push-service.yaml
│ │ ├── nextcloud-aio-onlyoffice-deployment.yaml
│ │ ├── nextcloud-aio-onlyoffice-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-onlyoffice-service.yaml
│ │ ├── nextcloud-aio-redis-deployment.yaml
│ │ ├── nextcloud-aio-redis-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-redis-service.yaml
│ │ ├── nextcloud-aio-talk-deployment.yaml
│ │ ├── nextcloud-aio-talk-recording-deployment.yaml
│ │ ├── nextcloud-aio-talk-recording-persistentvolumeclaim.yaml
│ │ ├── nextcloud-aio-talk-recording-service.yaml
│ │ ├── nextcloud-aio-talk-service.yaml
│ │ ├── nextcloud-aio-whiteboard-deployment.yaml
│ │ └── nextcloud-aio-whiteboard-service.yaml
│ ├── update-helm.sh
│ └── values.yaml
├── php/
│ ├── README.md
│ ├── composer.json
│ ├── containers-schema.json
│ ├── containers.json
│ ├── cool-seccomp-profile.json
│ ├── data/
│ │ └── .gitkeep
│ ├── domain-validator.php
│ ├── get-configurable-aio-variables.sh
│ ├── psalm-baseline.xml
│ ├── psalm.xml
│ ├── public/
│ │ ├── automatic_reload.js
│ │ ├── base_path.js
│ │ ├── before-unload.js
│ │ ├── containers-form-submit.js
│ │ ├── disable-clamav.js
│ │ ├── disable-collabora.js
│ │ ├── disable-docker-socket-proxy.js
│ │ ├── disable-fulltextsearch.js
│ │ ├── disable-harp.js
│ │ ├── disable-imaginary.js
│ │ ├── disable-onlyoffice.js
│ │ ├── disable-talk-recording.js
│ │ ├── disable-talk.js
│ │ ├── disable-whiteboard.js
│ │ ├── forms.js
│ │ ├── index.php
│ │ ├── log-view.js
│ │ ├── robots.txt
│ │ ├── second-tab-warning.js
│ │ ├── style.css
│ │ ├── timezone.js
│ │ └── toggle-dark-mode.js
│ ├── session/
│ │ └── .gitkeep
│ ├── src/
│ │ ├── Auth/
│ │ │ ├── AuthManager.php
│ │ │ └── PasswordGenerator.php
│ │ ├── Container/
│ │ │ ├── AioVariables.php
│ │ │ ├── Container.php
│ │ │ ├── ContainerEnvironmentVariables.php
│ │ │ ├── ContainerPort.php
│ │ │ ├── ContainerPorts.php
│ │ │ ├── ContainerState.php
│ │ │ ├── ContainerVolume.php
│ │ │ ├── ContainerVolumes.php
│ │ │ └── VersionState.php
│ │ ├── ContainerDefinitionFetcher.php
│ │ ├── Controller/
│ │ │ ├── ConfigurationController.php
│ │ │ ├── DockerController.php
│ │ │ └── LoginController.php
│ │ ├── Cron/
│ │ │ ├── BackupNotification.php
│ │ │ ├── CheckBackup.php
│ │ │ ├── CheckFreeDiskSpace.php
│ │ │ ├── CreateBackup.php
│ │ │ ├── OutdatedNotification.php
│ │ │ ├── PullContainerImages.php
│ │ │ ├── StartAndUpdateContainers.php
│ │ │ ├── StartContainers.php
│ │ │ ├── StopContainers.php
│ │ │ ├── UpdateMastercontainer.php
│ │ │ └── UpdateNotification.php
│ │ ├── Data/
│ │ │ ├── ConfigurationManager.php
│ │ │ ├── DataConst.php
│ │ │ ├── InvalidSettingConfigurationException.php
│ │ │ └── Setup.php
│ │ ├── DependencyInjection.php
│ │ ├── Docker/
│ │ │ ├── DockerActionManager.php
│ │ │ ├── DockerHubManager.php
│ │ │ └── GitHubContainerRegistryManager.php
│ │ ├── Middleware/
│ │ │ └── AuthMiddleware.php
│ │ └── Twig/
│ │ ├── ClassExtension.php
│ │ └── CsrfExtension.php
│ ├── templates/
│ │ ├── already-installed.twig
│ │ ├── components/
│ │ │ └── container-state.twig
│ │ ├── containers.twig
│ │ ├── includes/
│ │ │ ├── aio-config.twig
│ │ │ ├── aio-version.twig
│ │ │ ├── backup-dirs.twig
│ │ │ ├── community-containers.twig
│ │ │ └── optional-containers.twig
│ │ ├── layout.twig
│ │ ├── log.twig
│ │ ├── login.twig
│ │ └── setup.twig
│ └── tests/
│ ├── .gitignore
│ ├── package.json
│ ├── playwright.config.js
│ └── tests/
│ ├── initial-setup.spec.js
│ └── restore-instance.spec.js
├── readme.md
├── reverse-proxy.md
├── tests/
│ └── QA/
│ ├── 001-initial-setup.md
│ ├── 002-new-instance.md
│ ├── 003-automatic-login.md
│ ├── 004-initial-backup.md
│ ├── 010-restore-instance.md
│ ├── 020-backup-and-restore.md
│ ├── 030-aio-password-change.md
│ ├── 040-login-behavior.md
│ ├── 050-optional-addons.md
│ ├── 055-community-containers.md
│ ├── 060-environmental-variables.md
│ ├── 070-timezone-change.md
│ ├── 080-daily-backup-script.md
│ ├── assets/
│ │ └── backup-archive/
│ │ └── readme.md
│ └── readme.md
└── zizmor.yml
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
* text=auto
================================================
FILE: .github/ISSUE_TEMPLATE/Bug_report.md
================================================
---
name: 🐛 Bug report - no questions and no support!
about: Help us improving by reporting a bug - this category is not for questions and also not for support! Please use one of the options below for questions and support
labels: 0. Needs triage
---
<!---
- Before submitting a bug report, please read through the documentation available at https://github.com/nextcloud/all-in-one#faq
- Additional documentation is available here: https://github.com/nextcloud/all-in-one/discussions/categories/wiki
- You should also read through existing questions and their answer here: https://github.com/nextcloud/all-in-one/discussions/categories/questions
- Additional threads can be found here: https://help.nextcloud.com/tag/aio
- Existing feature requests are listed here: https://github.com/nextcloud/all-in-one/discussions/categories/ideas
--->
<!--- Please fill out the whole template below -->
### Steps to reproduce
1.
2.
3.
### Expected behavior <!--- Tell us what should happen -->
### Actual behavior <!--- Tell us what happens instead -->
### Other information
#### Host OS <!--- (the host OS on which you are trying to install AIO on) -->
#### Output of `sudo docker info`
#### Docker run command or docker-compose file that you used
#### 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 <!--- (like additional logs, screenshots & Co.) -->
================================================
FILE: .github/ISSUE_TEMPLATE/Feature_request.md
================================================
---
name: 📖 Existing feature/documentation enhancement
about: Suggest an enhancement of an existing feature/documentation - for other types, please use the feature request option below
labels: 0. Needs triage
---
<!--- Please fill out the whole template below -->
### Is your feature request related to a problem? Please describe.
<!--- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
### Describe the solution you'd like
<!--- A clear and concise description of what you want to happen. -->
### Describe alternatives you've considered
<!--- A clear and concise description of any alternative solutions or features you've considered. -->
### Additional context
<!--- Add any other context or screenshots about the feature request below. -->
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
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: ⛑️ Questions and support
url: https://help.nextcloud.com/tag/aio
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: 💼 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
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: ".github/workflows"
schedule:
interval: "daily"
time: "12:00"
open-pull-requests-limit: 10
rebase-strategy: "disabled"
labels:
- 3. to review
- dependencies
cooldown:
default-days: 7
- package-ecosystem: composer
directory: "/php/"
schedule:
interval: "daily"
time: "12:00"
open-pull-requests-limit: 10
rebase-strategy: "auto"
labels:
- 3. to review
- dependencies
- package-ecosystem: "docker"
directories:
- "/Containers/alpine"
- "/Containers/apache"
- "/Containers/borgbackup"
- "/Containers/clamav"
- "/Containers/collabora"
- "/Containers/docker-socket-proxy"
- "/Containers/domaincheck"
- "/Containers/fulltextsearch"
- "/Containers/imaginary"
- "/Containers/mastercontainer"
- "/Containers/nextcloud"
- "/Containers/notify-push"
- "/Containers/onlyoffice"
- "/Containers/postgresql"
- "/Containers/redis"
- "/Containers/talk"
- "/Containers/talk-recording"
- "/Containers/watchtower"
- "/Containers/whiteboard"
schedule:
interval: "daily"
time: "04:00"
open-pull-requests-limit: 10
rebase-strategy: "disabled"
labels:
- 3. to review
- dependencies
ignore:
- dependency-name: "php"
update-types: ["version-update:semver-major", "version-update:semver-minor"]
- dependency-name: "postgres"
update-types: ["version-update:semver-major"]
- dependency-name: "redis"
update-types: ["version-update:semver-major"]
- dependency-name: "elasticsearch"
update-types: ["version-update:semver-major"]
================================================
FILE: .github/pull_request_template.md
================================================
<!--
- 🚨 SECURITY INFO
-
- Before sending a pull request that fixes a security issue please report it via our HackerOne page (https://hackerone.com/nextcloud) following our security policy (https://nextcloud.com/security/). This allows us to coordinate the fix and release without potentially exposing all Nextcloud servers and users in the meantime.
-->
================================================
FILE: .github/release.yml
================================================
changelog:
categories:
- title: 🏕 New features and other improvements
labels:
- enhancement
- title: 🐞 Fixed bugs
labels:
- bug
- title: 👒 Updated dependencies
labels:
- dependencies
- title: 📄 Improved documentation
labels:
- documentation
================================================
FILE: .github/workflows/codespell.yml
================================================
name: 'Codespell'
on:
pull_request:
push:
branches:
- main
jobs:
codespell:
name: Check spelling
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check spelling
uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2
with:
check_filenames: true
check_hidden: true
================================================
FILE: .github/workflows/collabora.yml
================================================
name: collabora-update
on:
workflow_dispatch:
schedule:
- cron: '00 12 * * *'
jobs:
collabora-update:
name: update collabora
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- 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@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
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
================================================
FILE: .github/workflows/community-containers.yml
================================================
name: Validate community containers
on:
pull_request:
paths:
- 'community-containers/**'
push:
branches:
- main
paths:
- 'community-containers/**'
jobs:
validator-community-containers:
name: Validate community containers
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Validate structure
run: |
CONTAINERS="$(find ./community-containers -mindepth 1 -maxdepth 1 -type d)"
mapfile -t CONTAINERS <<< "$CONTAINERS"
for container in "${CONTAINERS[@]}"; do
container="$(echo "$container" | sed 's|./community-containers/||')"
if ! [ -f ./community-containers/"$container"/"$container.json" ]; then
echo ".json file must be named like its parent folder $container"
FAIL=1
fi
if ! [ -f ./community-containers/"$container"/readme.md ]; then
echo "There must be a readme.md file in the folder!"
FAIL=1
fi
if [ -n "$FAIL" ]; then
exit 1
fi
done
================================================
FILE: .github/workflows/dependency-updates.yml
================================================
name: dependency-updates
on:
workflow_dispatch:
schedule:
- cron: '00 12 * * *'
jobs:
dependency_updates:
name: Run dependency update script
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with:
php-version: 8.5
extensions: apcu
- name: Run dependency update script
run: |
set -x
cd ./php
composer update --with-all-dependencies
# Disable dependency updates for now
# set +e
# ALL_LINES="$(composer outdated | grep -v "^$\|Direct dependencies\|Everything up to date\|Transitive dependencies")"
# set -e
# while [ -n "$ALL_LINES" ]; do
# CURRENT_LINE="$(echo "$ALL_LINES" | head -1)"
# composer require "$(echo "$CURRENT_LINE" | awk '{print $1}')" "^$(echo "$CURRENT_LINE" | awk '{print $4}')" --with-all-dependencies
# ALL_LINES="$(echo "$ALL_LINES" | sed '1d')"
# done
# echo "outdated dependencies:
# $(composer outdated)"
- name: Update apcu
run: |
# APCU
apcu_version="$(
git ls-remote --tags https://github.com/krakjoe/apcu.git \
| cut -d/ -f3 \
| grep -viE -- 'rc|b' \
| sed -E 's/^v//' \
| sort -V \
| tail -1
)"
sed -i "s|pecl install APCu.*\;|pecl install APCu-$apcu_version\;|" ./Containers/mastercontainer/Dockerfile
# CADDY_REMOTE_HOST_HASH
CADDY_REMOTE_HOST_HASH="$(
git ls-remote https://github.com/muety/caddy-remote-host master \
| cut -f1 \
| tail -1
)"
sed -i "s|^ARG CADDY_REMOTE_HOST_HASH.*$|ARG CADDY_REMOTE_HOST_HASH=$CADDY_REMOTE_HOST_HASH|" ./Containers/mastercontainer/Dockerfile
- name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: php dependency updates
signoff: true
title: PHP dependency updates
body: Automated php dependency updates since dependabot does not support grouped updates
labels: dependencies, 3. to review
milestone: next
branch: aio-dependency-update
================================================
FILE: .github/workflows/docker-lint.yml
================================================
name: Docker Lint
on:
pull_request:
paths:
- 'Containers/**'
push:
branches:
- main
paths:
- 'Containers/**'
permissions:
contents: read
concurrency:
group: docker-lint-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
docker-lint:
runs-on: ubuntu-latest
name: docker-lint
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install hadolint
run: |
sudo wget https://github.com/hadolint/hadolint/releases/latest/download/hadolint-Linux-x86_64 -O /usr/bin/hadolint
sudo chmod +x /usr/bin/hadolint
- name: run lint
run: |
DOCKERFILES="$(find ./Containers -name Dockerfile)"
mapfile -t DOCKERFILES <<< "$DOCKERFILES"
for file in "${DOCKERFILES[@]}"; do
# DL3018 warning: Pin versions in apk add. Instead of `apk add <package>` use `apk add <package>=<version>`
# DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check
hadolint "$file" --ignore DL3018 --ignore DL4006 | tee -a ./hadolint.log
done
if grep -q "DL[0-9]\+\|SC[0-9]\+" ./hadolint.log; then
exit 1
fi
================================================
FILE: .github/workflows/fail-on-prerelease.yml
================================================
name: Block if prerelease is present
on:
pull_request:
permissions:
contents: read
jobs:
check-latest-release:
runs-on: ubuntu-latest
steps:
- name: "Check latest published release isn't a prerelease"
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v6
with:
script: |
const tags = await github.rest.repos.listTags({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 1
});
if (!tags.data || tags.data.length === 0) {
core.info('No tags found for this repository; skipping prerelease check.');
return;
}
const latestTag = tags.data[0].name;
core.info(`Latest tag found: ${latestTag}`);
try {
const { data } = await github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: latestTag
});
if (data.prerelease) {
core.setFailed(`Release for tag ${latestTag} (${data.tag_name}) is a prerelease. Blocking merges to main as we need to wait for the prerelease to become stable.`);
} else {
core.info(`Release for tag ${latestTag} (${data.tag_name}) is not a prerelease.`);
}
} catch (err) {
if (err.status === 404) {
core.info(`No release found for tag ${latestTag}; skipping prerelease check.`);
} else {
throw err;
}
}
================================================
FILE: .github/workflows/helm-release.yml
================================================
name: Helm Chart Releaser
on:
push:
branches:
- main
paths:
- 'nextcloud-aio-helm-chart/**'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Turnstyle
uses: softprops/turnstyle@e565d2d86403c5d23533937e95980570545e5586 # v2
with:
continue-after-seconds: 180
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Fetch history
run: git fetch --prune --unshallow
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
# See https://github.com/helm/chart-releaser-action/issues/6
- name: Set up Helm
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
with:
version: v3.6.3
- name: Run Helm Lint
run: |
helm lint ./nextcloud-aio-helm-chart
- name: Run chart-releaser
uses: helm/chart-releaser-action@cae68fefc6b5f367a0275617c9f83181ba54714f # v1.7.0
with:
mark_as_latest: false
charts_dir: .
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
CR_RELEASE_NAME_TEMPLATE: "helm-chart-{{ .Version }}"
CR_SKIP_EXISTING: true
================================================
FILE: .github/workflows/imaginary-update.yml
================================================
name: imaginary-update
on:
workflow_dispatch:
schedule:
- cron: '00 12 * * *'
jobs:
run_update:
name: update to latest imaginary commit on master branch
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Run imaginary-update
run: |
# Imaginary
imaginary_version="$(
git ls-remote https://github.com/h2non/imaginary master \
| cut -f1 \
| tail -1
)"
sed -i "s|^ENV IMAGINARY_HASH.*$|ENV IMAGINARY_HASH=$imaginary_version|" ./Containers/imaginary/Dockerfile
- name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: imaginary-update automated change
signoff: true
title: Imaginary update
body: Automated Imaginary container update
labels: dependencies, 3. to review
milestone: next
branch: imaginary-container-update
================================================
FILE: .github/workflows/json-validator.yml
================================================
name: Json Validator
on:
pull_request:
paths:
- '**.json'
push:
branches:
- main
paths:
- '**.json'
jobs:
json-validator:
name: Json Validator
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Validate Json
run: |
sudo apt-get update
sudo apt-get install python3-venv -y --no-install-recommends
python3 -m venv venv
. venv/bin/activate
pip3 install json-spec
if ! json validate --schema-file=php/containers-schema.json --document-file=php/containers.json; then
exit 1
fi
JSON_FILES="$(find ./community-containers -name '*.json')"
mapfile -t JSON_FILES <<< "$JSON_FILES"
for file in "${JSON_FILES[@]}"; do
json validate --schema-file=php/containers-schema.json --document-file="$file" 2>&1 | tee -a ./json-validator.log
done
if grep -q "document does not validate with schema.\|invalid JSONFile" ./json-validator.log; then
exit 1
fi
================================================
FILE: .github/workflows/lint-helm.yml
================================================
name: Lint Helm Charts
on:
workflow_dispatch:
pull_request:
paths:
- 'nextcloud-aio-helm-chart/**'
jobs:
lint-helm:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Install Helm
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
with:
version: v3.11.1
- name: Lint charts
run: helm lint nextcloud-aio-helm-chart
================================================
FILE: .github/workflows/lint-php.yml
================================================
# 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 php
on:
pull_request:
paths:
- 'php/**'
push:
branches:
- main
paths:
- 'php/**'
permissions:
contents: read
concurrency:
group: lint-php-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
php-lint:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: [ "8.5" ]
name: php-lint
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2.36.0
with:
php-version: ${{ matrix.php-versions }}
coverage: none
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Lint
run: cd php && composer run lint
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: php-lint
if: always()
name: php-lint-summary
steps:
- name: Summary status
run: if ${{ needs.php-lint.result != 'success' && needs.php-lint.result != 'skipped' }}; then exit 1; fi
================================================
FILE: .github/workflows/lint-yaml.yml
================================================
# 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 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@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
- name: Check GitHub actions
run: uvx zizmor --min-severity medium .github/workflows/*.yml
================================================
FILE: .github/workflows/lock-threads.yml
================================================
name: 'Lock Threads'
on:
schedule:
- cron: '0 0 * * *'
permissions:
issues: write
concurrency:
group: lock
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7 # v5
with:
issue-inactive-days: '14'
process-only: 'issues'
================================================
FILE: .github/workflows/nextcloud-update.yml
================================================
# Inspired by https://github.com/nextcloud/docker/blob/master/.github/workflows/update-sh.yml
name: nextcloud-update
on:
workflow_dispatch:
schedule:
- cron: '00 12 * * *'
jobs:
run_update_sh:
name: Run nextcloud-update script
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Run nextcloud-update script
run: |
# Inspired by https://github.com/nextcloud/docker/blob/master/update.sh
# APCU
apcu_version="$(
git ls-remote --tags https://github.com/krakjoe/apcu.git \
| cut -d/ -f3 \
| grep -viE -- 'rc|b' \
| sed -E 's/^v//' \
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*APCu-\)[0-9.]*|\1$apcu_version|" ./Containers/nextcloud/Dockerfile
# Memcached
memcached_version="$(
git ls-remote --tags https://github.com/php-memcached-dev/php-memcached.git \
| cut -d/ -f3 \
| grep -viE -- 'rc|b' \
| sed -E 's/^[rv]//' \
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*memcached-\)[0-9.]*|\1$memcached_version|" ./Containers/nextcloud/Dockerfile
# Redis
redis_version="$(
git ls-remote --tags https://github.com/phpredis/phpredis.git \
| cut -d/ -f3 \
| grep -viE '[a-z]' \
| tr -d '^{}' \
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*redis-\)[0-9.]*|\1$redis_version|" ./Containers/nextcloud/Dockerfile
# Imagick
imagick_version="$(
git ls-remote --tags https://github.com/imagick/imagick.git \
| cut -d/ -f3 \
| grep -viE '[a-z]' \
| tr -d '^{}' \
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*imagick-\)[0-9.]*|\1$imagick_version|" ./Containers/nextcloud/Dockerfile
# Igbinary
igbinary_version="$(
git ls-remote --tags https://github.com/igbinary/igbinary.git \
| cut -d/ -f3 \
| grep -viE '[a-z]' \
| tr -d '^{}' \
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*igbinary-\)[0-9.]*|\1$igbinary_version|" ./Containers/nextcloud/Dockerfile
# Nextcloud
NC_MAJOR="$(grep "ENV NEXTCLOUD_VERSION" ./Containers/nextcloud/Dockerfile | grep -oP '[23][0-9]')"
NCVERSION=$(curl -s -m 900 https://download.nextcloud.com/server/releases/ | sed --silent 's/.*href="nextcloud-\([^"]\+\).zip.asc".*/\1/p' | grep "$NC_MAJOR" | sort --version-sort | tail -1)
if [ -n "$NCVERSION" ]; then
sed -i "s|^ENV NEXTCLOUD_VERSION.*|ENV NEXTCLOUD_VERSION=$NCVERSION|" ./Containers/nextcloud/Dockerfile
fi
- name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: nextcloud-update automated change
signoff: true
title: Nextcloud dependency update
body: Automated Nextcloud container update
labels: dependencies, 3. to review
milestone: next
branch: nextcloud-container-update
================================================
FILE: .github/workflows/php-deprecation-detector.yml
================================================
name: PHP Deprecation Detector
# See https://github.com/wapmorgan/PhpDeprecationDetector
on:
pull_request:
paths:
- 'php/**'
push:
branches:
- main
paths:
- 'php/**'
jobs:
phpdd:
name: PHP Deprecation Detector
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up php
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with:
php-version: 8.5
extensions: apcu
coverage: none
- name: Run script
run: |
set -x
cd php
composer install
composer run php-deprecation-detector | tee -i ./phpdd.log
if grep "Total issues:" ./phpdd.log; then
exit 1
fi
================================================
FILE: .github/workflows/playwright-on-push.yml
================================================
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # 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.5
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2.36.0
with:
extensions: apcu
php-version: 8.5
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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: ${{ !cancelled() }}
with:
name: playwright-report
path: php/tests/playwright-report/
retention-days: 14
overwrite: true
================================================
FILE: .github/workflows/playwright-on-workflow-dispatch.yml
================================================
name: Playwright Tests
on:
workflow_dispatch:
env:
BASE_URL: https://localhost:8080
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # 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: 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 /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 /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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: ${{ !cancelled() }}
with:
name: playwright-report
path: php/tests/playwright-report/
retention-days: 14
overwrite: true
================================================
FILE: .github/workflows/psalm-update-baseline.yml
================================================
name: Update Psalm baseline
on:
workflow_dispatch:
schedule:
- cron: '5 4 * * *'
jobs:
update-psalm-baseline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up php
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with:
php-version: 8.5
extensions: apcu
coverage: none
ini-file: development
- name: Run script
run: |
set -x
cd php
composer install
composer run psalm:update-baseline
git clean -f lib/composer
git checkout composer.json composer.lock lib/composer
continue-on-error: true
- name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update psalm baseline
committer: GitHub <noreply@github.com>
author: nextcloud-command <nextcloud-command@users.noreply.github.com>
signoff: true
branch: automated/noid/psalm-baseline-update
title: '[Automated] Update psalm-baseline.xml'
milestone: next
body: |
Auto-generated update psalm-baseline.xml with fixed psalm warnings
labels: |
3. to review, dependencies
================================================
FILE: .github/workflows/psalm.yml
================================================
# 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: 2022-2024 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: MIT
name: Static analysis
on:
pull_request:
paths:
- 'php/**'
push:
branches:
- main
paths:
- 'php/**'
concurrency:
group: psalm-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
static-analysis:
runs-on: ubuntu-latest
name: static-psalm-analysis
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up php
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2.36.0
with:
php-version: 8.5
extensions: apcu
coverage: none
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install dependencies and run psalm
run: |
set -x
cd php
composer install
composer run psalm
================================================
FILE: .github/workflows/shellcheck.yml
================================================
name: Shellcheck
on:
pull_request:
paths:
- '**.sh'
push:
branches:
- main
paths:
- '**.sh'
jobs:
shellcheck:
name: Check Shell
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Run Shellcheck
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0
with:
check_together: 'yes'
env:
SHELLCHECK_OPTS: --shell bash
================================================
FILE: .github/workflows/talk.yml
================================================
name: talk-update
on:
workflow_dispatch:
schedule:
- cron: '00 12 * * *'
jobs:
talk-update:
name: update talk
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Run talk-container-update
run: |
# Recording
recording_version="$(
git ls-remote https://github.com/nextcloud/nextcloud-talk-recording v* \
| cut -d/ -f3 \
| sort -V \
| grep -E "^v[0-9\.]+$" \
| tail -1
)"
sed -i "s|^ENV RECORDING_VERSION.*$|ENV RECORDING_VERSION=$recording_version|" ./Containers/talk-recording/Dockerfile
curl -L "https://raw.githubusercontent.com/nextcloud/nextcloud-talk-recording/$recording_version/server.conf.in" -o Containers/talk-recording/recording.conf
# Signaling
signaling_version="$(
git ls-remote https://github.com/strukturag/nextcloud-spreed-signaling v*.*.* \
| cut -d/ -f3 \
| sort -V \
| grep -E "^v[0-9]+\.[0-9]+\.[0-9]+$" \
| tail -1
)"
curl -L "https://raw.githubusercontent.com/strukturag/nextcloud-spreed-signaling/$signaling_version/server.conf.in" -o Containers/talk/server.conf.in
# Janus
janus_version="$(
git ls-remote https://github.com/meetecho/janus-gateway v1.*.* \
| cut -d/ -f3 \
| sort -V \
| grep -E "^v[0-9]+\.[0-9]+\.[0-9]+$" \
| tail -1
)"
sed -i "s|^ARG JANUS_VERSION=.*$|ARG JANUS_VERSION=$janus_version|" ./Containers/talk/Dockerfile
- name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: talk-update automated change
signoff: true
title: talk container update
body: Automated talk container update
labels: dependencies, 3. to review
milestone: next
branch: talk-container-update
================================================
FILE: .github/workflows/twig-lint.yml
================================================
name: Twig Lint
on:
pull_request:
paths:
- '**.twig'
push:
branches:
- main
paths:
- '**.twig'
permissions:
contents: read
concurrency:
group: lint-twig-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
twig-lint:
runs-on: ubuntu-latest
name: twig-lint
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with:
php-version: 8.5
extensions: apcu
coverage: none
- name: twig lint
run: |
cd php
composer install
composer run lint:twig
================================================
FILE: .github/workflows/update-copyright.yml
================================================
name: Update Copyright
on:
workflow_dispatch:
jobs:
update-copyright:
name: update copyright
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
================================================
FILE: .github/workflows/update-helm.yml
================================================
name: Update Helm Chart
on:
workflow_dispatch:
schedule:
- cron: '00 12 * * *'
jobs:
update-helm:
name: update helm chart
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: update helm chart
run: |
set -x
GHCR_TOKEN="$(curl https://ghcr.io/token?scope=repository:nextcloud-releases/nce-php-fpm-mgmt:pull | jq '.token' | sed 's|"||g')"
DOCKER_TAG="$(curl -H "Authorization: Bearer ${GHCR_TOKEN}" -L -s 'https://ghcr.io/v2/nextcloud-releases/all-in-one/tags/list?page_size=1024' | jq '.tags' | sed 's|"||g;s|[[:space:]]||g;s|,||g' | grep '^20[0-9_]\+' | grep -v latest | sort -r | head -1)"
export DOCKER_TAG
set +x
if [ -n "$DOCKER_TAG" ] && ! grep -q "aio-nextcloud:$DOCKER_TAG" ./nextcloud-aio-helm-chart/templates/nextcloud-aio-nextcloud-deployment.yaml; then
sudo bash nextcloud-aio-helm-chart/update-helm.sh "$DOCKER_TAG"
fi
- name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
commit-message: Helm Chart updates
signoff: true
title: Helm Chart updates
body: Automated Helm Chart updates for the yaml files. It can be merged if it looks good at any time which will automatically trigger a new release of the helm chart.
labels: dependencies, 3. to review
milestone: next
branch: aio-helm-update
token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/update-yaml.yml
================================================
name: Update Yaml files
on:
workflow_dispatch:
schedule:
- cron: '00 12 * * *'
jobs:
update-yaml:
name: update yaml files
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: update yaml files
run: |
sudo bash manual-install/update-yaml.sh
- name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
commit-message: Yaml updates
signoff: true
title: Yaml updates
body: Automated yaml updates for the docker-compose files. Should only be merged shortly before the next latest release.
labels: dependencies, 3. to review
milestone: next
branch: aio-yaml-update
token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/watchtower-update.yml
================================================
name: watchtower-update
on:
workflow_dispatch:
schedule:
- cron: '00 12 * * *'
jobs:
watchtower-update:
name: update watchtower
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- 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@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
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
================================================
FILE: .gitignore
================================================
.DS_Store
.idea/
*.iml
/php/data/*
/php/session/*
!/php/data/.gitkeep
!/php/session/.gitkeep
/php/vendor
/manual-install/*.conf
!/manual-install/sample.conf
/manual-install/docker-compose.yml
/manual-install/compose.yaml
/manual-install/.env
================================================
FILE: CODE_OF_CONDUCT.md
================================================
<!--
- SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
In the Nextcloud community, participants from all over the world come together to create Free Software for a free internet. This is made possible by the support, hard work and enthusiasm of thousands of people, including those who create and use Nextcloud software.
Our code of conduct offers some guidance to ensure Nextcloud participants can cooperate effectively in a positive and inspiring atmosphere, and to explain how together we can strengthen and support each other.
The Code of Conduct is shared by all contributors and users who engage with the Nextcloud team and its community services. It presents a summary of the shared values and “common sense” thinking in our community.
You can find our full code of conduct on our website: https://nextcloud.com/code-of-conduct/
Please, keep our CoC in mind when you contribute! That way, everyone can be a part of our community in a productive, positive, creative and fun way.
================================================
FILE: Containers/alpine/Dockerfile
================================================
# syntax=docker/dockerfile:latest
FROM alpine:3.23.3
RUN set -ex; \
apk upgrade --no-cache -a
LABEL org.label-schema.vendor="Nextcloud"
================================================
FILE: Containers/apache/Caddyfile
================================================
{
auto_https disable_redirects
storage file_system {
root /mnt/data/caddy
}
servers {
# trusted_proxies placeholder
}
log {
level ERROR
}
}
https://{$ADDITIONAL_TRUSTED_DOMAIN}:443,
http://{$APACHE_HOST}.nextcloud-aio:23973, # For Collabora callback and WOPI requests, see containers.json
{$PROTOCOL}://{$NC_DOMAIN}:{$APACHE_PORT} {
header -Server
header -X-Powered-By
# Collabora
route /browser/* {
reverse_proxy {$COLLABORA_HOST}:9980
}
route /hosting/* {
reverse_proxy {$COLLABORA_HOST}:9980
}
route /cool/* {
reverse_proxy {$COLLABORA_HOST}:9980
}
# Notify Push
route /push/* {
uri strip_prefix /push
reverse_proxy {$NOTIFY_PUSH_HOST}:7867
}
# Onlyoffice
route /onlyoffice/* {
uri strip_prefix /onlyoffice
reverse_proxy {$ONLYOFFICE_HOST}:80 {
header_up X-Forwarded-Host {http.request.hostport}/onlyoffice
header_up X-Forwarded-Proto https
}
}
# Talk
route /standalone-signaling/* {
uri strip_prefix /standalone-signaling
reverse_proxy {$TALK_HOST}:8081
}
# Whiteboard
route /whiteboard/* {
uri strip_prefix /whiteboard
reverse_proxy {$WHITEBOARD_HOST}:3002
}
# HaRP (ExApps)
route /exapps/* {
reverse_proxy {$HARP_HOST}:8780
}
# Nextcloud
route {
header Strict-Transport-Security max-age=31536000;
reverse_proxy 127.0.0.1:8000
}
redir /.well-known/carddav /remote.php/dav/ 301
redir /.well-known/caldav /remote.php/dav/ 301
# TLS options
tls {
issuer acme {
disable_http_challenge
}
}
}
================================================
FILE: Containers/apache/Dockerfile
================================================
# syntax=docker/dockerfile:latest
FROM caddy:2.11.2-alpine AS caddy
# From https://github.com/docker-library/httpd/blob/master/2.4/alpine/Dockerfile
FROM httpd:2.4.66-alpine3.23
COPY --from=caddy /usr/bin/caddy /usr/bin/caddy
COPY --chown=33:33 Caddyfile /Caddyfile
COPY --chmod=664 nextcloud.conf /usr/local/apache2/conf/nextcloud.conf
COPY --chmod=664 supervisord.conf /supervisord.conf
COPY --chmod=775 start.sh /start.sh
COPY --chmod=775 healthcheck.sh /healthcheck.sh
VOLUME /mnt/data
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache shadow; \
groupmod -g 33 www-data; \
usermod -u 33 -g 33 www-data; \
apk del --no-cache shadow; \
\
mkdir -p /mnt/data; \
chown -R www-data:www-data /mnt/data; \
chown -R 777 /tmp; \
\
apk add --no-cache \
bash \
supervisor \
tzdata \
ca-certificates \
openssl \
bind-tools \
netcat-openbsd; \
\
sed -i \
-e '/^Listen /d' \
-e 's/^#\(LoadModule .*mod_rewrite.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_headers.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_proxy.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_proxy_fcgi.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_setenvif.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_env.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_mime.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_dir.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_authz_core.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_alias.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_mpm_event.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_brotli.so\)/\1/' \
-e 's/\(LoadModule .*mod_mpm_worker.so\)/#\1/' \
-e 's/\(LoadModule .*mod_mpm_prefork.so\)/#\1/' \
-e 's/\(ScriptAlias \)/#\1/' \
/usr/local/apache2/conf/httpd.conf; \
echo "Include conf/nextcloud.conf" | tee -a /usr/local/apache2/conf/httpd.conf; \
echo "ServerName localhost" | tee -a /usr/local/apache2/conf/httpd.conf; \
# Sync this with max db connections and pm.max_children
# We don't actually expect so many workers but don't want to limit it artificially because people will report issues otherwise.
sed -i 's|MaxRequestWorkers.*|MaxRequestWorkers 5000|' /usr/local/apache2/conf/extra/httpd-mpm.conf; \
grep -q '<IfModule mpm_event_module>' /usr/local/apache2/conf/extra/httpd-mpm.conf; \
# ServerLimit needs to be set to MaxRequestWorkers divided by ThreadsPerChild which is set to 25 by default
sed -i '/<IfModule mpm_event_module>/a\ \ \ \ ServerLimit 200' /usr/local/apache2/conf/extra/httpd-mpm.conf; \
\
rm -rf /usr/local/apache2/conf/original /var/www; \
mkdir -p /var/www; \
chown -R www-data:www-data /var/www; \
\
mkdir /var/log/supervisord; \
mkdir /var/run/supervisord; \
chown www-data:www-data /var/run/supervisord; \
chown www-data:www-data /var/log/supervisord; \
chmod 777 /var/run/supervisord; \
chmod 777 /var/log/supervisord; \
\
chown -R www-data:www-data /usr/local/apache2; \
chmod +r -R /usr/local/apache2; \
mkdir -p /usr/local/apache2/logs; \
chmod 777 -R /home/www-data; \
chmod 777 -R /usr/local/apache2/logs; \
rm -rf /usr/local/apache2/cgi-bin/; \
\
echo "root:$(openssl rand -base64 12)" | chpasswd; \
apk --no-cache del openssl
USER 33
ENTRYPOINT ["/start.sh"]
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"
================================================
FILE: Containers/apache/healthcheck.sh
================================================
#!/bin/bash
nc -z "$NEXTCLOUD_HOST" 9000 || exit 0
nc -z 127.0.0.1 8000 || exit 1
nc -z 127.0.0.1 "$APACHE_PORT" || exit 1
================================================
FILE: Containers/apache/nextcloud.conf
================================================
Listen 8000
<VirtualHost *:8000>
ServerName localhost
# Add error log
CustomLog /proc/self/fd/1 proxy
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy
ErrorLog /proc/self/fd/2
ErrorLogFormat "[%t] [%l] [%E] [client: %{X-Forwarded-For}i] [%M] [%{User-Agent}i]"
LogLevel warn
# PHP match
<FilesMatch "\.php$">
SetHandler "proxy:fcgi://${NEXTCLOUD_HOST}:9000"
</FilesMatch>
<Proxy "fcgi://${NEXTCLOUD_HOST}:9000" flushpackets=on>
</Proxy>
# Enable Brotli compression for js, css and svg files - other plain files are compressed by Nextcloud by default
<IfModule mod_brotli.c>
AddOutputFilterByType BROTLI_COMPRESS text/javascript application/javascript application/x-javascript text/css image/svg+xml
BrotliCompressionQuality 0
</IfModule>
# Nextcloud dir
DocumentRoot /var/www/html/
<Directory /var/www/html/>
Options Indexes FollowSymLinks
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
Satisfy Any
<IfModule mod_dav.c>
Dav off
</IfModule>
</Directory>
# Deny access to .ht files
<Files ".ht*">
Require all denied
</Files>
# See https://httpd.apache.org/docs/current/en/mod/core.html#limitrequestbody
LimitRequestBody ${APACHE_MAX_SIZE}
# See https://httpd.apache.org/docs/current/mod/core.html#timeout
Timeout ${APACHE_MAX_TIME}
# See https://httpd.apache.org/docs/current/mod/mod_proxy.html#proxytimeout
ProxyTimeout ${APACHE_MAX_TIME}
# See https://httpd.apache.org/docs/trunk/mod/core.html#traceenable
TraceEnable Off
</VirtualHost>
================================================
FILE: Containers/apache/start.sh
================================================
#!/bin/bash
if [ -z "$NC_DOMAIN" ]; then
echo "NC_DOMAIN and NEXTCLOUD_HOST need to be provided. Exiting!"
exit 1
fi
# Need write access to /mnt/data
if ! [ -w /mnt/data ]; then
echo "Cannot write to /mnt/data"
exit 1
fi
# Only start container if nextcloud is accessible
while ! nc -z "$NEXTCLOUD_HOST" 9000; do
echo "Waiting for Nextcloud to start..."
sleep 5
done
# Get ipv4-address of Apache
# shellcheck disable=SC2153
IPv4_ADDRESS="$(dig "$APACHE_HOST" A +short +search | head -1)"
# Bring it in CIDR notation
# shellcheck disable=SC2001
IPv4_ADDRESS="$(echo "$IPv4_ADDRESS" | sed 's|[0-9]\+$|0/16|')"
if [ -z "$APACHE_PORT" ]; then
export APACHE_PORT="443"
fi
# Change variables in case of reverse proxies
if [ "$APACHE_PORT" != '443' ]; then
export PROTOCOL="http"
export NC_DOMAIN=""
else
export PROTOCOL="https"
fi
# Change the auto_https in case of reverse proxies
if [ "$APACHE_PORT" != '443' ]; then
CADDYFILE="$(sed 's|auto_https.*|auto_https off|' /Caddyfile)"
else
CADDYFILE="$(sed 's|auto_https.*|auto_https disable_redirects|' /Caddyfile)"
fi
echo "$CADDYFILE" > /tmp/Caddyfile
# Change the trusted_proxies in case of reverse proxies
if [ "$APACHE_PORT" != '443' ]; then
# 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
echo "$CADDYFILE" > /tmp/Caddyfile
# Remove additional domain if not given
if [ -z "$ADDITIONAL_TRUSTED_DOMAIN" ]; then
CADDYFILE="$(sed '/ADDITIONAL_TRUSTED_DOMAIN/d' /tmp/Caddyfile)"
fi
echo "$CADDYFILE" > /tmp/Caddyfile
# Fix the Caddyfile format
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
exec "$@"
================================================
FILE: Containers/apache/supervisord.conf
================================================
[supervisord]
nodaemon=true
nodaemon=true
logfile=/var/log/supervisord/supervisord.log
pidfile=/var/run/supervisord/supervisord.pid
childlogdir=/var/log/supervisord/
logfile_maxbytes=50MB
logfile_backups=10
loglevel=error
[program:apache]
# Stdout logging is disabled as otherwise the logs are spammed
stdout_logfile=NONE
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=apachectl -DFOREGROUND
[program:caddy]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=/usr/bin/caddy run --config /tmp/Caddyfile
================================================
FILE: Containers/borgbackup/Dockerfile
================================================
# syntax=docker/dockerfile:latest
FROM alpine:3.23.3
RUN set -ex; \
\
apk upgrade --no-cache -a; \
apk add --no-cache \
util-linux-misc \
bash \
borgbackup \
rsync \
fuse \
py3-llfuse \
jq \
openssh-client
VOLUME /root
COPY --chmod=770 *.sh /
COPY borg_excludes /
ENTRYPOINT ["/start.sh"]
# hadolint ignore=DL3002
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"
================================================
FILE: Containers/borgbackup/backupscript.sh
================================================
#!/bin/bash
# Functions
get_start_time(){
START_TIME=$(date +%s)
CURRENT_DATE=$(date --date @"$START_TIME" +"%Y%m%d_%H%M%S")
}
get_expiration_time() {
END_TIME=$(date +%s)
END_DATE_READABLE=$(date --date @"$END_TIME" +"%d.%m.%Y - %H:%M:%S")
DURATION=$((END_TIME-START_TIME))
DURATION_SEC=$((DURATION % 60))
DURATION_MIN=$(((DURATION / 60) % 60))
DURATION_HOUR=$((DURATION / 3600))
DURATION_READABLE=$(printf "%02d hours %02d minutes %02d seconds" $DURATION_HOUR $DURATION_MIN $DURATION_SEC)
}
# Test if all volumes aren't empty
VOLUME_DIRS="$(find /nextcloud_aio_volumes -mindepth 1 -maxdepth 1 -type d)"
mapfile -t VOLUME_DIRS <<< "$VOLUME_DIRS"
for directory in "${VOLUME_DIRS[@]}"; do
if ! mountpoint -q "$directory"; then
echo "$directory is not a mountpoint which is not allowed."
exit 1
fi
done
# Test if default volumes are there
DEFAULT_VOLUMES=(nextcloud_aio_apache nextcloud_aio_nextcloud nextcloud_aio_database nextcloud_aio_database_dump nextcloud_aio_elasticsearch nextcloud_aio_nextcloud_data nextcloud_aio_mastercontainer)
for volume in "${DEFAULT_VOLUMES[@]}"; do
if ! mountpoint -q "/nextcloud_aio_volumes/$volume"; then
echo "$volume is missing which is not intended."
exit 1
fi
done
# Check if target is mountpoint
if [ -z "$BORG_REMOTE_REPO" ] && ! mountpoint -q "$MOUNT_DIR"; then
echo "$MOUNT_DIR is not a mountpoint which is not allowed."
exit 1
fi
# Check if repo is uninitialized
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != test ] && ! borg info > /dev/null; then
if [ -n "$BORG_REMOTE_REPO" ]; then
echo "The repository is uninitialized or cannot connect to remote. Cannot perform check or restore."
else
echo "The repository is uninitialized. Cannot perform check or restore."
fi
exit 1
fi
# Do not continue if this file exists (needed for simple external blocking)
if [ -z "$BORG_REMOTE_REPO" ] && [ -f "$BORG_BACKUP_DIRECTORY/aio-lockfile" ]; then
echo "Not continuing because aio-lockfile exists – it seems like a script is externally running which is locking the backup archive."
echo "If this should not be the case, you can fix this by deleting the 'aio-lockfile' file from the backup archive directory."
exit 1
fi
# Create lockfile
if [ "$BORG_MODE" = backup ] || [ "$BORG_MODE" = restore ]; then
touch "/nextcloud_aio_volumes/nextcloud_aio_database_dump/backup-is-running"
fi
if [ -n "$BORG_REMOTE_REPO" ] && ! [ -f "$BORGBACKUP_KEY" ]; then
echo "First run, creating borg ssh key"
ssh-keygen -f "$BORGBACKUP_KEY" -N ""
echo "You should configure the remote to accept this public key"
fi
if [ -n "$BORG_REMOTE_REPO" ] && [ -f "$BORGBACKUP_KEY.pub" ]; then
echo "Your public ssh key for borgbackup is: $(cat "$BORGBACKUP_KEY.pub")"
fi
# Do the backup
if [ "$BORG_MODE" = backup ]; then
# Test if important files are present
if ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json" ]; then
echo "configuration.json not present. Cannot perform the backup!"
exit 1
elif ! grep -q '"domain"' "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json" \
|| ! grep -q '"wasStartButtonClicked"' "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json"; then
echo "It seems like the configuration.json setup was not done correctly. Something is wrong! (Most likely the provided configuration.json is invalid)"
exit 1
elif ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud/config/config.php" ]; then
echo "config.php is missing. Cannot perform backup!"
exit 1
elif ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_database_dump/database-dump.sql" ]; then
echo "database-dump is missing. Cannot perform backup!"
echo "Please check the database container logs!"
exit 1
elif ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/.ocdata" ] && ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/.ncdata" ]; then
echo "The .ncdata or .ocdata file is missing in Nextcloud datadir which means it is invalid!"
echo "Is the drive where the datadir is located on still mounted?"
exit 1
fi
# Test that default volumes are not empty
for volume in "${DEFAULT_VOLUMES[@]}"; do
if [ -z "$(ls -A "/nextcloud_aio_volumes/$volume")" ] && [ "$volume" != "nextcloud_aio_elasticsearch" ]; then
echo "/nextcloud_aio_volumes/$volume is empty which should not happen!"
exit 1
fi
done
if [ -f "/nextcloud_aio_volumes/nextcloud_aio_database_dump/export.failed" ]; then
echo "Cannot create a backup now."
echo "Reason is that the database export failed the last time."
echo "Most likely was the database container not correctly shut down via the AIO interface."
echo ""
echo "You might want to try the database export again manually by running the three commands:"
echo "sudo docker start nextcloud-aio-database"
echo "sleep 10"
echo "sudo docker stop nextcloud-aio-database -t 1800"
echo ""
echo "Afterwards try to create a backup again and it should hopefully work."
echo "If it should still fail, feel free to report this to https://github.com/nextcloud/all-in-one/issues and post the database container logs and the borgbackup container logs into the thread. Thanks!"
exit 1
fi
if [ -z "$BORG_REMOTE_REPO" ]; then
# Create backup folder
mkdir -p "$BORG_BACKUP_DIRECTORY"
fi
# Initialize the repository if can't get info from target
if ! borg info > /dev/null; then
# Don't initialize if already initialized
if [ -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config" ]; then
if [ -n "$BORG_REMOTE_REPO" ]; then
echo "Borg could not get info from the remote repo."
echo "This might be a failure to connect to the remote server. See the above borg info output for details."
else
echo "Borg could not get info from the targeted directory."
echo "This might happen if the targeted directory is located on an external drive and the drive not connected anymore. You should check this."
fi
echo "If you instead want to initialize a new backup repository, you may delete the 'borg.config' file that is stored in the mastercontainer volume manually, which will allow you to initialize a new borg repository in the chosen directory:"
echo "sudo docker exec nextcloud-aio-mastercontainer rm /mnt/docker-aio-config/data/borg.config"
exit 1
fi
echo "Initializing repository..."
NEW_REPOSITORY=1
if ! borg init --debug --encryption=repokey-blake2; then
echo "Could not initialize borg repository."
exit 1
fi
if [ -z "$BORG_REMOTE_REPO" ]; then
# borg config only works for local repos; it's up to the remote to ensure the disk isn't full
borg config :: additional_free_space 2G
# Fix too large Borg cache
# https://borgbackup.readthedocs.io/en/stable/faq.html#the-borg-cache-eats-way-too-much-disk-space-what-can-i-do
BORG_ID="$(borg config :: id)"
rm -r "/root/.cache/borg/$BORG_ID/chunks.archive.d"
touch "/root/.cache/borg/$BORG_ID/chunks.archive.d"
fi
if ! borg info > /dev/null; then
echo "Borg can't get info from the repo it created. Something is wrong."
exit 1
fi
rm -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"
if [ -n "$BORG_REMOTE_REPO" ]; then
# `borg config` does not support remote repos so instead create a dummy file and rely on the remote to avoid
# corruption of the config file (which contains the encryption key). We don't actually use the contents of
# this file anywhere, so a touch is all we need so we remember we already initialized the repo.
touch "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"
else
# Make a backup from the borg config file
if ! cp "$BORG_BACKUP_DIRECTORY/config" "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"; then
echo "Could not copy config file to second place. Cannot perform backup."
exit 1
fi
fi
echo "Repository successfully initialized."
fi
# Perform backup
echo "Performing backup..."
# Borg options
# auto,zstd compression seems to has the best ratio based on:
# https://forum.level1techs.com/t/optimal-compression-for-borg-backups/145870/6
BORG_OPTS=(-v --stats --compression "auto,zstd")
if [ "$NEW_REPOSITORY" = 1 ]; then
BORG_OPTS+=(--progress)
fi
# Exclude the nextcloud log and audit log for GDPR reasons
BORG_EXCLUDE=(--exclude "/nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/nextcloud.log*" --exclude "/nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/audit.log" --exclude "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/lost+found")
BORG_INCLUDE=()
# Exclude datadir if .noaiobackup file was found
# shellcheck disable=SC2144
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 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/")
BORG_INCLUDE+=(--pattern="+/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/appdata_*/preview/.noaiobackup")
echo "⚠️⚠️⚠️ '.noaiobackup' file was found in the preview directory. Excluding the preview directory from backup!"
fi
# Make sure that there is always a borg.config file before creating a new backup
if ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config" ]; then
echo "Did not find borg.config file in the mastercontainer volume."
echo "Cannot create a backup as this is wrong."
exit 1
fi
# Create the backup
echo "Starting the backup..."
get_start_time
if ! borg create "${BORG_OPTS[@]}" "${BORG_INCLUDE[@]}" "${BORG_EXCLUDE[@]}" "::$CURRENT_DATE-nextcloud-aio" "/nextcloud_aio_volumes/" --exclude-from /borg_excludes; then
echo "Deleting the failed backup archive..."
borg delete --stats "::$CURRENT_DATE-nextcloud-aio"
echo "Backup failed!"
echo "You might want to check the backup integrity via the AIO interface."
if [ "$NEW_REPOSITORY" = 1 ]; then
echo "Deleting borg.config file so that you can choose a different location for the backup."
rm "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"
fi
exit 1
fi
# Remove the update skip file because the backup was successful
rm -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/skip.update"
# Prune options
read -ra BORG_PRUNE_OPTS <<< "$BORG_RETENTION_POLICY"
echo "BORG_PRUNE_OPTS are ${BORG_PRUNE_OPTS[*]}"
# Prune archives
echo "Pruning the archives..."
if ! borg prune --stats --glob-archives '*_*-nextcloud-aio' "${BORG_PRUNE_OPTS[@]}"; then
echo "Failed to prune archives!"
exit 1
fi
# Compact archives
echo "Compacting the archives..."
if ! borg compact; then
echo "Failed to compact archives!"
exit 1
fi
# Back up additional directories of the host
if [ "$ADDITIONAL_DIRECTORIES_BACKUP" = 'yes' ]; then
if [ -d "/docker_volumes/" ]; then
DOCKER_VOLUME_DIRS="$(find /docker_volumes -mindepth 1 -maxdepth 1 -type d)"
mapfile -t DOCKER_VOLUME_DIRS <<< "$DOCKER_VOLUME_DIRS"
for directory in "${DOCKER_VOLUME_DIRS[@]}"; do
if [ -z "$(ls -A "$directory")" ]; then
echo "$directory is empty which is not allowed."
exit 1
fi
done
echo "Starting the backup for additional volumes..."
if ! borg create "${BORG_OPTS[@]}" "::$CURRENT_DATE-additional-docker-volumes" "/docker_volumes/"; then
echo "Deleting the failed backup archive..."
borg delete --stats "::$CURRENT_DATE-additional-docker-volumes"
echo "Backup of additional docker-volumes failed!"
exit 1
fi
echo "Pruning additional volumes..."
if ! borg prune --stats --glob-archives '*_*-additional-docker-volumes' "${BORG_PRUNE_OPTS[@]}"; then
echo "Failed to prune additional docker-volumes archives!"
exit 1
fi
echo "Compacting additional volumes..."
if ! borg compact; then
echo "Failed to compact additional docker-volume archives!"
exit 1
fi
fi
if [ -d "/host_mounts/" ]; then
EXCLUDED_DIRECTORIES=(home/*/.cache root/.cache var/cache lost+found run var/run dev tmp sys proc)
# Exclude borg backup cache
EXCLUDED_DIRECTORIES+=(var/lib/docker/volumes/nextcloud_aio_backup_cache/_data)
# Exclude target directory
if [ -n "$BORGBACKUP_HOST_LOCATION" ] && [ "$BORGBACKUP_HOST_LOCATION" != "nextcloud_aio_backupdir" ]; then
EXCLUDED_DIRECTORIES+=("$BORGBACKUP_HOST_LOCATION")
fi
for directory in "${EXCLUDED_DIRECTORIES[@]}"
do
EXCLUDE_DIRS+=(--exclude "/host_mounts/$directory/")
done
echo "Starting the backup for additional host mounts..."
if ! borg create "${BORG_OPTS[@]}" "${EXCLUDE_DIRS[@]}" "::$CURRENT_DATE-additional-host-mounts" "/host_mounts/"; then
echo "Deleting the failed backup archive..."
borg delete --stats "::$CURRENT_DATE-additional-host-mounts"
echo "Backup of additional host-mounts failed!"
exit 1
fi
echo "Pruning additional host mounts..."
if ! borg prune --stats --glob-archives '*_*-additional-host-mounts' "${BORG_PRUNE_OPTS[@]}"; then
echo "Failed to prune additional host-mount archives!"
exit 1
fi
echo "Compacting additional host mounts..."
if ! borg compact; then
echo "Failed to compact additional host-mount archives!"
exit 1
fi
fi
fi
# Inform user
get_expiration_time
echo "Backup finished successfully on $END_DATE_READABLE ($DURATION_READABLE)."
if [ -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/update.failed" ]; then
echo "However a Nextcloud update failed. So reporting that the backup failed which will skip any update attempt the next time."
echo "Please restore a backup from before the failed Nextcloud update attempt."
exit 1
fi
exit 0
fi
# Do the restore
if [ "$BORG_MODE" = restore ]; then
get_start_time
# Pick archive to restore
if [ -n "$SELECTED_RESTORE_TIME" ]; then
SELECTED_ARCHIVE="$(borg list | grep "nextcloud-aio" | grep "$SELECTED_RESTORE_TIME" | awk -F " " '{print $1}' | head -1)"
else
SELECTED_ARCHIVE="$(borg list | grep "nextcloud-aio" | awk -F " " '{print $1}' | sort -r | head -1)"
fi
echo "Restoring '$SELECTED_ARCHIVE'..."
ADDITIONAL_RSYNC_EXCLUDES=()
ADDITIONAL_BORG_EXCLUDES=()
ADDITIONAL_FIND_EXCLUDES=()
# Exclude datadir if .noaiobackup file was found
# shellcheck disable=SC2144
if [ -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/.noaiobackup" ]; then
# Keep these 3 in sync. Beware, the pattern syntax and the paths differ
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 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"
# Exclude previews from restore if selected to speed up process or exclude preview folder if .noaiobackup file was found
elif [ -n "$RESTORE_EXCLUDE_PREVIEWS" ] || [ -f /nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/appdata_*/preview/.noaiobackup ]; then
# Keep these 3 in sync. Beware, the pattern syntax and the paths differ
ADDITIONAL_RSYNC_EXCLUDES=(--exclude "nextcloud_aio_nextcloud_data/appdata_*/preview/**")
ADDITIONAL_BORG_EXCLUDES=(--exclude "sh:nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/appdata_*/preview/**")
ADDITIONAL_FIND_EXCLUDES=(-o -regex 'nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/appdata_[^/]*/preview\(/.*\)?')
echo "⚠️⚠️⚠️ Excluding previews 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-app-data preview' after the restore."
echo "See https://github.com/nextcloud/all-in-one#how-to-run-occ-commands"
fi
# Save Additional Backup dirs
if [ -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/additional_backup_directories" ]; then
ADDITIONAL_BACKUP_DIRECTORIES="$(cat /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/additional_backup_directories)"
fi
# Save daily backup time
if [ -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_time" ]; then
DAILY_BACKUPTIME="$(cat /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_time)"
fi
# Save current aio password
AIO_PASSWORD="$(jq '.password' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
# Save current backup location vars
BORG_LOCATION="$(jq '.borg_backup_host_location' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
REMOTE_REPO="$(jq '.borg_remote_repo' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
# Save current nextcloud datadir
if grep -q '"nextcloud_datadir":' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json; then
NEXTCLOUD_DATADIR="$(jq '.nextcloud_datadir' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
else
NEXTCLOUD_DATADIR='""'
fi
if [ -z "$BORG_REMOTE_REPO" ]; then
mkdir -p /tmp/borg
if ! borg mount "::$SELECTED_ARCHIVE" /tmp/borg; then
echo "Could not mount the backup!"
exit 1
fi
# Restore everything except the configuration file
#
# These exclude patterns need to be kept in sync with the borg_excludes file and the find excludes in this file,
# which use a different syntax (patterns appear in 3 places in total)
if ! rsync --stats --archive --human-readable -vv --delete \
--exclude "nextcloud_aio_apache/caddy/**" \
--exclude "nextcloud_aio_mastercontainer/caddy/**" \
--exclude "nextcloud_aio_nextcloud/data/nextcloud.log*" \
--exclude "nextcloud_aio_nextcloud/data/audit.log" \
--exclude "nextcloud_aio_mastercontainer/certs/**" \
--exclude "nextcloud_aio_mastercontainer/data/configuration.json" \
--exclude "nextcloud_aio_mastercontainer/data/daily_backup_running" \
--exclude "nextcloud_aio_mastercontainer/data/session_date_file" \
--exclude "nextcloud_aio_mastercontainer/session/**" \
--exclude "nextcloud_aio_nextcloud_data/lost+found" \
"${ADDITIONAL_RSYNC_EXCLUDES[@]}" \
/tmp/borg/nextcloud_aio_volumes/ /nextcloud_aio_volumes/; then
RESTORE_FAILED=1
echo "Something failed while restoring from backup."
fi
# Restore the configuration file
if ! rsync --archive --human-readable -vv \
/tmp/borg/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json \
/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json; then
RESTORE_FAILED=1
echo "Something failed while restoring the configuration.json."
fi
if ! umount /tmp/borg; then
echo "Failed to unmount the borg archive but should still be able to restore successfully"
fi
else
# Restore nearly everything
#
# borg mount is really slow for remote repos (did not check whether it's slow for local repos too),
# using extract to /tmp would require temporarily storing a second copy of the data.
# So instead extract directly on top of the destination with exclude patterns for the config, but
# then we do still need to delete local files which are not present in the archive.
#
# Older backups may still contain files we've since excluded, so we have to exclude on extract as well.
cd / # borg extract has no destination arg and extracts to CWD
if ! borg extract "::$SELECTED_ARCHIVE" --progress --exclude-from /borg_excludes "${ADDITIONAL_BORG_EXCLUDES[@]}" --pattern '+nextcloud_aio_volumes/**'
then
RESTORE_FAILED=1
echo "Failed to extract backup archive."
else
# Delete files/dirs present locally, but not in the backup archive, excluding conf files
# https://unix.stackexchange.com/a/759341
# This comm does not support -z, but I doubt any file names would have \n in them
#
# These find patterns need to be kept in sync with the borg_excludes file and the rsync excludes in this
# file, which use a different syntax (patterns appear in 3 places in total)
echo "Deleting local files which do not exist in the backup"
if ! find nextcloud_aio_volumes \
-not \( \
-path nextcloud_aio_volumes/nextcloud_aio_apache/caddy \
-o -path "nextcloud_aio_volumes/nextcloud_aio_apache/caddy/*" \
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/caddy \
-o -path "nextcloud_aio_volumes/nextcloud_aio_mastercontainer/caddy/*" \
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/certs \
-o -path "nextcloud_aio_volumes/nextcloud_aio_mastercontainer/certs/*" \
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/session \
-o -path "nextcloud_aio_volumes/nextcloud_aio_mastercontainer/session/*" \
-o -path "nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/nextcloud.log*" \
-o -path nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/audit.log \
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_running \
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/session_date_file \
-o -path "nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/id_borg*" \
-o -path "nextcloud_aio_nextcloud_data/lost+found" \
"${ADDITIONAL_FIND_EXCLUDES[@]}" \
\) \
| LC_ALL=C sort \
| LC_ALL=C comm -23 - \
<(borg list "::$SELECTED_ARCHIVE" --short --exclude-from /borg_excludes --pattern '+nextcloud_aio_volumes/**' | LC_ALL=C sort) \
> /tmp/local_files_not_in_backup
then
RESTORE_FAILED=1
echo "Failed to delete local files not in backup archive."
else
# More robust than e.g. xargs as I got a ~"args line too long" error while testing that, but it's slower
# https://stackoverflow.com/a/21848934
while IFS= read -r file
do rm -vrf -- "$file" || DELETE_FAILED=1
done < /tmp/local_files_not_in_backup
if [ "$DELETE_FAILED" = 1 ]; then
RESTORE_FAILED=1
echo "Failed to delete (some) local files not in backup archive."
fi
fi
fi
fi
# Set backup-mode to restore since it was a restore
CONTENTS="$(jq '."backup-mode" = "restore"' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
# Reset the backup location vars to the currently used one
CONTENTS="$(jq ".borg_backup_host_location = $BORG_LOCATION" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
CONTENTS="$(jq ".borg_remote_repo = $REMOTE_REPO" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
# Reset the AIO password to the currently used one
CONTENTS="$(jq ".password = $AIO_PASSWORD" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
# Reset the datadir to the one that was used for the restore
CONTENTS="$(jq ".nextcloud_datadir = $NEXTCLOUD_DATADIR" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
# Reset the additional backup directories
if [ -n "$ADDITIONAL_BACKUP_DIRECTORIES" ]; then
echo "$ADDITIONAL_BACKUP_DIRECTORIES" > "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/additional_backup_directories"
chown 33:0 "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/additional_backup_directories"
chmod 770 "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/additional_backup_directories"
fi
# Reset the additional backup directories
if [ -n "$DAILY_BACKUPTIME" ]; then
echo "$DAILY_BACKUPTIME" > "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_time"
chown 33:0 "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_time"
chmod 770 "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_time"
fi
if [ "$RESTORE_FAILED" = 1 ]; then
exit 1
elif ! grep -q '"domain"' "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json" \
|| ! grep -q '"wasStartButtonClicked"' "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json"; then
echo "It seems like the restore of the configuration.json was not done correctly. Something is wrong! (Most likely is the restore archive already incorrect)!"
exit 1
fi
# Inform user
get_expiration_time
echo "Restore finished successfully on $END_DATE_READABLE ($DURATION_READABLE)."
# Add file to Nextcloud container so that it skips any update the next time
touch "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/skip.update"
chmod 777 "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/skip.update"
# Add file to Nextcloud container so that it performs a fingerprint update the next time
touch "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/fingerprint.update"
chmod 777 "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/fingerprint.update"
# Add file to Netcloud container to trigger a preview scan the next time it starts
if [ -n "$RESTORE_EXCLUDE_PREVIEWS" ]; then
touch "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/trigger-preview.scan"
chmod 777 "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/trigger-preview.scan"
fi
# Delete redis cache
rm -f "/mnt/redis/dump.rdb"
fi
# Do the Backup check
if [ "$BORG_MODE" = check ]; then
get_start_time
echo "Checking the backup integrity..."
# Perform the check
if ! borg check -v --verify-data; then
echo "Some errors were found while checking the backup integrity!"
echo "Check the AIO interface for advice on how to proceed now!"
exit 1
fi
# Inform user
get_expiration_time
echo "Check finished successfully on $END_DATE_READABLE ($DURATION_READABLE)."
exit 0
fi
# Do the Backup check-repair
if [ "$BORG_MODE" = "check-repair" ]; then
get_start_time
echo "Checking the backup integrity and repairing it..."
# Perform the check-repair
if ! echo YES | borg check -v --repair; then
echo "Some errors were found while checking and repairing the backup integrity!"
exit 1
fi
# Inform user
get_expiration_time
echo "Check finished successfully on $END_DATE_READABLE ($DURATION_READABLE)."
exit 0
fi
# Do the backup test
if [ "$BORG_MODE" = test ]; then
if [ -n "$BORG_REMOTE_REPO" ]; then
if ! borg info > /dev/null; then
echo "Borg could not get info from the remote repo."
echo "See the above borg info output for details."
exit 1
fi
else
if ! [ -d "$BORG_BACKUP_DIRECTORY" ]; then
echo "No 'borg' directory in the given backup directory found!"
echo "Only the files/folders below have been found in the given directory."
ls -a "$MOUNT_DIR"
echo "Please adjust the directory so that the borg archive is positioned in a folder named 'borg' inside the given directory!"
exit 1
elif ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
echo "A 'borg' directory was found but could not find the borg archive."
echo "Only the files/folders below have been found in the borg directory."
ls -a "$BORG_BACKUP_DIRECTORY"
echo "The archive and most importantly the config file must be positioned directly in the 'borg' subfolder."
exit 1
fi
fi
if ! borg list >/dev/null; then
echo "The entered path seems to be valid but could not open the backup archive."
echo "Most likely the entered password was wrong so please adjust it accordingly!"
exit 1
else
if ! borg list | grep "nextcloud-aio"; then
echo "The backup archive does not contain a valid Nextcloud AIO backup."
echo "Most likely was the archive not created via Nextcloud AIO."
exit 1
else
echo "Everything looks fine so feel free to continue!"
exit 0
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
================================================
FILE: Containers/borgbackup/borg_excludes
================================================
# These patterns need to be kept in sync with rsync and find excludes in backupscript.sh,
# which use a different syntax (patterns appear in 3 places in total)
nextcloud_aio_volumes/nextcloud_aio_apache/caddy/
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/caddy/
nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/nextcloud.log*
nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/audit.log
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/certs/
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_running
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/session_date_file
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/session/
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/id_borg*
================================================
FILE: Containers/borgbackup/start.sh
================================================
#!/bin/bash
# Variables
export MOUNT_DIR="/mnt/borgbackup"
export BORG_BACKUP_DIRECTORY="$MOUNT_DIR/borg" # necessary even when remote to store the aio-lockfile
# Validate BORG_PASSWORD
if [ -z "$BORG_PASSWORD" ] && [ -z "$BACKUP_RESTORE_PASSWORD" ]; then
echo "Neither BORG_PASSWORD nor BACKUP_RESTORE_PASSWORD are set."
exit 1
fi
# Export defaults
if [ -n "$BACKUP_RESTORE_PASSWORD" ]; then
export BORG_PASSPHRASE="$BACKUP_RESTORE_PASSWORD"
else
export BORG_PASSPHRASE="$BORG_PASSWORD"
fi
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes
if [ -n "$BORG_REMOTE_REPO" ]; then
export BORG_REPO="$BORG_REMOTE_REPO"
# Location to create the borg ssh pub/priv key
export BORGBACKUP_KEY="/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/id_borg"
# Accept any host key the first time connecting to the remote. Strictly speaking should be provided by user but you'd
# have to be very unlucky to get MitM'ed on your first connection.
export BORG_RSH="ssh -o StrictHostKeyChecking=accept-new -i $BORGBACKUP_KEY"
else
export BORG_REPO="$BORG_BACKUP_DIRECTORY"
fi
# Validate BORG_MODE
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
export BORG_MODE
# Run the backup script
if ! bash /backupscript.sh; then
FAILED=1
fi
# Remove lockfile
rm -f "/nextcloud_aio_volumes/nextcloud_aio_database_dump/backup-is-running"
# Get a list of all available borg archives
if borg list &>/dev/null; then
borg list | grep "nextcloud-aio" | awk -F " " '{print $1","$3,$4}' > "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
else
echo "" > "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
fi
chmod +r "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
if [ -n "$FAILED" ]; then
if [ "$BORG_MODE" = backup ]; then
# Add file to Nextcloud container so that it skips any update the next time
touch "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/skip.update"
chmod 777 "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/skip.update"
fi
exit 1
fi
exec "$@"
================================================
FILE: Containers/clamav/Dockerfile
================================================
# syntax=docker/dockerfile:latest
FROM alpine:3.23.3
RUN set -ex; \
apk upgrade --no-cache -a; \
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|#\?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; \
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
================================================
FILE: Containers/clamav/healthcheck.sh
================================================
#!/bin/bash
if [ "$(echo "PING" | nc 127.0.0.1 3310)" != "PONG" ]; then
echo "ERROR: Unable to contact server"
exit 1
fi
echo "Clamd is up"
exit 0
================================================
FILE: Containers/clamav/start.sh
================================================
#!/bin/bash
# Print out clamav version for compliance reasons
clamscan --version
echo "Clamav started"
exec "$@"
================================================
FILE: Containers/clamav/supervisord.conf
================================================
[supervisord]
nodaemon=true
nodaemon=true
logfile=/var/log/supervisord/supervisord.log
pidfile=/var/run/supervisord/supervisord.pid
childlogdir=/var/log/supervisord/
logfile_maxbytes=50MB
logfile_backups=10
loglevel=error
[program:freshclam]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
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=/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
================================================
FILE: Containers/collabora/Dockerfile
================================================
# 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.9.3.1
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"
================================================
FILE: Containers/collabora/healthcheck.sh
================================================
#!/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
================================================
FILE: Containers/collabora-online/Dockerfile
================================================
# 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"
================================================
FILE: Containers/collabora-online/healthcheck.sh
================================================
#!/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
================================================
FILE: Containers/docker-socket-proxy/Dockerfile
================================================
# syntax=docker/dockerfile:latest
FROM haproxy:3.3.6-alpine
# hadolint ignore=DL3002
USER root
ENV NEXTCLOUD_HOST=nextcloud-aio-nextcloud
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache \
ca-certificates \
tzdata \
bash \
bind-tools; \
chmod -R 777 /tmp
COPY --chmod=775 *.sh /
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"
================================================
FILE: Containers/docker-socket-proxy/haproxy.cfg
================================================
# Inspiration: https://github.com/Tecnativa/docker-socket-proxy/blob/master/haproxy.cfg
global
maxconn 10
defaults
timeout connect 30s
timeout client 30s
timeout server 1800s
frontend http
mode http
bind :::2375 v4v6
http-request deny unless { src 127.0.0.1 } || { src ::1 } || { src NC_IPV4_PLACEHOLDER } || { src NC_IPV6_PLACEHOLDER }
# docker system _ping
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/_ping$ } METH_GET
# docker inspect image: GET images/%s/json
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/images/.*/json } METH_GET
# container inspect: GET containers/%s/json
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/json } METH_GET
# container inspect: GET containers/%s/logs
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/logs } METH_GET
# container start/stop: POST containers/%s/start containers/%s/stop
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/((start)|(stop)) } METH_POST
# container rm: DELETE containers/%s
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+ } METH_DELETE
# container update/exec: POST containers/%s/update containers/%s/exec
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/((update)|(exec)) } METH_POST
# container put: PUT containers/%s/archive
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/archive } METH_PUT
# run exec instance: POST exec/%s
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/exec/[a-zA-Z0-9_.-]+/start } METH_POST
# container create: POST containers/create?name=%s
# ACL to restrict container name to nc_app_[a-zA-Z0-9_.-]+
acl nc_app_container_name url_param(name) -m reg -i "^nc_app_[a-zA-Z0-9_.-]+"
# ACL to restrict the number of Mounts to 1
acl one_mount_volume req.body -m reg -i "\"Mounts\"\s*:\s*\[\s*(?:(?!\"Mounts\"\s*:\s*\[)[^}]*)}[^}]*\]"
# ACL to deny if there are any binds
acl binds_present req.body -m reg -i "\"HostConfig\"\s*:.*\"Binds\"\s*:"
# ACL to restrict the type of Mounts to volume
acl type_not_volume req.body -m reg -i "\"Mounts\"\s*:\s*\[[^\]]*(\"Type\"\s*:\s*\"(?!volume\b)\w+\"[^\]]*)+\]"
http-request deny if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/create } nc_app_container_name !one_mount_volume binds_present type_not_volume METH_POST
# ACL to restrict container creation, that it has HostConfig.Privileged(by searching for "Privileged" word in all payload)
acl no_privileged_flag req.body -m reg -i "\"Privileged\""
# ACL to allow mount volume with strict pattern for name: nc_app_[a-zA-Z0-9_.-]+_data
acl nc_app_volume_data_only req.body -m reg -i "\"Mounts\"\s*:\s*\[\s*{[^}]*\"Source\"\s*:\s*\"nc_app_[a-zA-Z0-9_.-]+_data\""
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/create } nc_app_container_name !no_privileged_flag nc_app_volume_data_only METH_POST
# end of container create
# volume create: POST volumes/create
# restrict name
acl nc_app_volume_data req.body -m reg -i "\"Name\"\s*:\s*\"nc_app_[a-zA-Z0-9_.-]+_data\""
# do not allow to use "device" word e.g., "--opt device=:/path/to/dir"
acl volume_no_device req.body -m reg -i "\"device\""
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/volumes/create } nc_app_volume_data !volume_no_device METH_POST
# volume rm: DELETE volumes/%s
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/volumes/nc_app_[a-zA-Z0-9_.-]+_data } METH_DELETE
# image pull: POST images/create?fromImage=%s
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/images/create } METH_POST
http-request deny
default_backend dockerbackend
backend dockerbackend
mode http
server dockersocket /var/run/docker.sock
================================================
FILE: Containers/docker-socket-proxy/healthcheck.sh
================================================
#!/bin/bash
nc -z "$NEXTCLOUD_HOST" 9001 || exit 0
nc -z 127.0.0.1 2375 || exit 1
================================================
FILE: Containers/docker-socket-proxy/start.sh
================================================
#!/bin/sh
# Only start container if nextcloud is accessible
while ! nc -z "$NEXTCLOUD_HOST" 9001; do
echo "Waiting for Nextcloud to start..."
sleep 5
done
set -x
IPv4_ADDRESS_NC="$(dig nextcloud-aio-nextcloud IN A +short +search | grep '^[0-9.]\+$' | sort | head -n1)"
HAPROXYFILE="$(sed "s|NC_IPV4_PLACEHOLDER|$IPv4_ADDRESS_NC|" /haproxy.cfg)"
echo "$HAPROXYFILE" > /tmp/haproxy.cfg
IPv6_ADDRESS_NC="$(dig nextcloud-aio-nextcloud AAAA +short +search | grep '^[0-9a-f:]\+$' | sort | head -n1)"
if [ -n "$IPv6_ADDRESS_NC" ]; then
HAPROXYFILE="$(sed "s|NC_IPV6_PLACEHOLDER|$IPv6_ADDRESS_NC|" /tmp/haproxy.cfg)"
else
HAPROXYFILE="$(sed "s# || { src NC_IPV6_PLACEHOLDER }##g" /tmp/haproxy.cfg)"
fi
echo "$HAPROXYFILE" > /tmp/haproxy.cfg
set +x
haproxy -f /tmp/haproxy.cfg -db
================================================
FILE: Containers/domaincheck/Dockerfile
================================================
# syntax=docker/dockerfile:latest
FROM alpine:3.23.3
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache bash lighttpd netcat-openbsd; \
adduser -S www-data -G www-data; \
rm -rf /etc/lighttpd/lighttpd.conf; \
chmod 777 -R /etc/lighttpd; \
mkdir -p /var/www/domaincheck; \
chown www-data:www-data -R /var/www; \
chmod 777 -R /var/www/domaincheck
COPY --chown=www-data:www-data lighttpd.conf /lighttpd.conf
COPY --chmod=775 start.sh /start.sh
USER www-data
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"
================================================
FILE: Containers/domaincheck/lighttpd.conf
================================================
server.document-root = "/var/www/domaincheck/"
server.port = env.APACHE_PORT
server.username = "www-data"
server.groupname = "www-data"
mimetype.assign = (
".html" => "text/html",
".txt" => "text/plain",
".jpg" => "image/jpeg",
".png" => "image/png"
)
static-file.exclude-extensions = ( ".fcgi", ".php", ".rb", "~", ".inc" )
index-file.names = ( "index.html" )
$SERVER["socket"] == "ipv6-placeholder" {
server.document-root = "/var/www/domaincheck/"
}
================================================
FILE: Containers/domaincheck/start.sh
================================================
#!/bin/bash
if [ -z "$INSTANCE_ID" ]; then
echo "You need to provide an instance id."
exit 1
fi
echo "$INSTANCE_ID" > /var/www/domaincheck/index.html
if [ -z "$APACHE_PORT" ]; then
export APACHE_PORT="443"
fi
CONF_FILE="$(sed "s|ipv6-placeholder|\[::\]:$APACHE_PORT|" /lighttpd.conf)"
echo "$CONF_FILE" > /etc/lighttpd/lighttpd.conf
# Check config file
lighttpd -tt -f /etc/lighttpd/lighttpd.conf
# Run server
lighttpd -D -f /etc/lighttpd/lighttpd.conf
exec "$@"
================================================
FILE: Containers/fulltextsearch/Dockerfile
================================================
# syntax=docker/dockerfile:latest
# Probably from here https://github.com/elastic/elasticsearch/blob/main/distribution/docker/src/docker/Dockerfile
FROM elasticsearch:8.19.13
USER root
ARG DEBIAN_FRONTEND=noninteractive
# hadolint ignore=DL3008
RUN set -ex; \
\
apt-get update; \
apt-get upgrade -y; \
apt-get install -y --no-install-recommends \
tzdata \
; \
rm -rf /var/lib/apt/lists/*;
COPY --chmod=775 healthcheck.sh /healthcheck.sh
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"
================================================
FILE: Containers/fulltextsearch/healthcheck.sh
================================================
#!/bin/bash
nc -z 127.0.0.1 9200 || exit 1
================================================
FILE: Containers/imaginary/Dockerfile
================================================
# syntax=docker/dockerfile:latest
FROM golang:1.26.1-alpine3.23 AS go
ENV IMAGINARY_HASH=6a274b488759a896aff02f52afee6e50b5e3a3ee
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache \
vips-dev \
vips-magick \
vips-heif \
vips-jxl \
vips-poppler \
build-base; \
go install github.com/h2non/imaginary@"$IMAGINARY_HASH";
FROM alpine:3.23.3
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache \
tzdata \
ca-certificates \
netcat-openbsd \
vips \
vips-magick \
vips-heif \
vips-jxl \
vips-poppler \
ttf-dejavu \
bash
COPY --from=go /go/bin/imaginary /usr/local/bin/imaginary
COPY --chmod=775 start.sh /start.sh
COPY --chmod=775 healthcheck.sh /healthcheck.sh
ENV PORT=9000
USER 65534
# https://github.com/h2non/imaginary#memory-issues
ENV MALLOC_ARENA_MAX=2
ENTRYPOINT ["/start.sh"]
HEALTHCHECK CMD /healthcheck.sh
LABEL com.centurylinklabs.watchtower.enable="false" \
wud.watch="false" \
org.label-schema.vendor="Nextcloud"
================================================
FILE: Containers/imaginary/healthcheck.sh
================================================
#!/bin/bash
nc -z 127.0.0.1 "$PORT" || exit 1
================================================
FILE: Containers/imaginary/start.sh
================================================
#!/bin/bash
echo "Imaginary has started"
if [ -z "$IMAGINARY_SECRET" ]; then
imaginary -return-size -max-allowed-resolution 222.2 "$@"
else
imaginary -return-size -max-allowed-resolution 222.2 -key "$IMAGINARY_SECRET" "$@"
fi
================================================
FILE: Containers/mastercontainer/Dockerfile
================================================
# syntax=docker/dockerfile:latest
# Docker CLI is a requirement
FROM docker:29.3.0-cli AS docker
ARG CADDY_REMOTE_HOST_HASH=b21775afa730ffb52a24ddff310c8a6d1fd37276
# Caddy is a requirement
FROM caddy:2.11.2-builder-alpine AS caddy
RUN set -ex; \
xcaddy build --with github.com/muety/caddy-remote-host@"$CADDY_REMOTE_HOST_HASH"; \
/usr/bin/caddy list-modules
# From https://github.com/docker-library/php/blob/master/8.5/alpine3.23/fpm/Dockerfile
FROM php:8.5.4-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 /
COPY --chmod=664 Containers/mastercontainer/supervisord.conf /supervisord.conf
WORKDIR /var/www/docker-aio
# hadolint ignore=SC2086,DL3047,DL3003,DL3004
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache shadow; \
groupmod -g 33 www-data; \
usermod -u 33 -g 33 www-data; \
\
apk add --no-cache \
util-linux-misc \
ca-certificates \
bash \
supervisor \
sudo \
netcat-openbsd \
curl \
grep; \
\
apk add --no-cache --virtual .build-deps \
autoconf \
build-base; \
pecl install APCu-5.1.28; \
docker-php-ext-enable apcu; \
rm -r /tmp/pear; \
runDeps="$( \
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
| tr ',' '\n' \
| sort -u \
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
)"; \
apk add --no-cache --virtual .nextcloud-aio-rundeps $runDeps; \
apk del .build-deps; \
grep -q '^pm = dynamic' /usr/local/etc/php-fpm.d/www.conf; \
sed -i 's/^pm = dynamic/pm = ondemand/' /usr/local/etc/php-fpm.d/www.conf; \
sed -i 's/^pm.max_children =.*/pm.max_children = 80/' /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; \
grep -q '^listen =' /usr/local/etc/php-fpm.d/docker.conf; \
sed -i 's|listen =.*|listen = /run/php.sock|' /usr/local/etc/php-fpm.d/docker.conf; \
echo "listen.owner = www-data" | tee -a /usr/local/etc/php-fpm.d/docker.conf; \
\
apk add --no-cache git; \
curl https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer; \
chmod +x /usr/local/bin/composer; \
cd /var/www/docker-aio; \
rm -r ./php/tests; \
chown www-data:www-data -R /var/www/docker-aio; \
cd php; \
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; \
chown -R www-data:www-data /var/www; \
rm -r php/data; \
rm -r php/session; \
\
mkdir /var/log/supervisord; \
mkdir /var/run/supervisord;
# hadolint ignore=DL3048
LABEL org.label-schema.vendor="Nextcloud" \
wud.watch="false" \
com.docker.compose.project="nextcloud-aio"
# hadolint ignore=DL3002
USER root
ENTRYPOINT ["/start.sh"]
HEALTHCHECK CMD /healthcheck.sh
================================================
FILE: Containers/mastercontainer/README.md
================================================
# 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)
- A Caddy server enabling self-signed HTTPS access to the AIO frontend on port 8080/tcp.
- A Caddy server enabling trusted 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.
================================================
FILE: Containers/mastercontainer/acme.Caddyfile
================================================
{
admin off
# auto_https will create redirects for https://{host}:8443 instead of https://{host}
# https redirects are added manually in the http://:80 block
auto_https disable_redirects
storage file_system {
root /mnt/docker-aio-config/caddy/
}
log {
level ERROR
# We need to exclude the remote-host plugin from logging as it would spam the logs
# See https://github.com/nextcloud/all-in-one/pull/7006#issuecomment-4003238239
exclude http.matchers.remote_host
}
servers {
# Only h1 is allowed as we prevent `ERR_NETWORK_CHANGED` from happening
protocols h1
}
on_demand_tls {
ask http://127.0.0.1:9876/
}
skip_install_trust
}
http://:80 {
redir https://{host}{uri} permanent
}
https://:8443 {
@denied {
path /api/auth/login /api/auth/getlogin
remote_host nextcloud-aio-nextcloud
}
abort @denied
root * /var/www/docker-aio/php/public
php_fastcgi unix//run/php.sock
file_server
tls {
on_demand
issuer acme {
disable_tlsalpn_challenge
}
}
}
================================================
FILE: Containers/mastercontainer/backup-time-file-watcher.sh
================================================
#!/bin/bash
restart_process() {
echo "Restarting cron.sh because daily backup time was set, changed or unset."
pkill cron.sh
}
file_present() {
if [ -f "/mnt/docker-aio-config/data/daily_backup_time" ]; then
if [ "$FILE_PRESENT" = 0 ]; then
restart_process
else
if [ -n "$BACKUP_TIME" ] && [ "$(head -1 "/mnt/docker-aio-config/data/daily_backup_time")" != "$BACKUP_TIME" ]; then
restart_process
fi
fi
FILE_PRESENT=1
BACKUP_TIME="$(head -1 "/mnt/docker-aio-config/data/daily_backup_time")"
else
if [ "$FILE_PRESENT" = 1 ]; then
restart_process
fi
FILE_PRESENT=0
fi
}
while true; do
file_present
sleep 2
done
================================================
FILE: Containers/mastercontainer/cron.sh
================================================
#!/bin/bash
while true; do
if [ -f "/mnt/docker-aio-config/data/daily_backup_time" ]; then
set -x
BACKUP_TIME="$(head -1 "/mnt/docker-aio-config/data/daily_backup_time")"
export BACKUP_TIME
export DAILY_BACKUP=1
if [ "$(sed -n '2p' "/mnt/docker-aio-config/data/daily_backup_time")" != 'automaticUpdatesAreNotEnabled' ]; then
export AUTOMATIC_UPDATES=1
else
export AUTOMATIC_UPDATES=0
export START_CONTAINERS=1
fi
if [ "$(sed -n '3p' "/mnt/docker-aio-config/data/daily_backup_time")" != 'successNotificationsAreNotEnabled' ]; then
export SEND_SUCCESS_NOTIFICATIONS=1
else
export SEND_SUCCESS_NOTIFICATIONS=0
fi
set +x
if [ -f "/mnt/docker-aio-config/data/daily_backup_running" ]; then
export LOCK_FILE_PRESENT=1
else
export LOCK_FILE_PRESENT=0
fi
else
export BACKUP_TIME="04:00"
export DAILY_BACKUP=0
export LOCK_FILE_PRESENT=0
fi
# Allow to continue directly if e.g. the mastercontainer was updated. Otherwise wait for the next execution
if [ "$LOCK_FILE_PRESENT" = 0 ]; then
while [ "$(date +%H:%M)" != "$BACKUP_TIME" ]; do
sleep 30
done
fi
if [ "$DAILY_BACKUP" = 1 ]; then
bash /daily-backup.sh
fi
# Make sure to delete the lock file always
rm -f "/mnt/docker-aio-config/data/daily_backup_running"
# Check for updates and send notification if yes on saturdays
if [ "$(date +%u)" = 6 ]; then
sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/UpdateNotification.php
fi
# Check if AIO is outdated
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 -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 -E -u www-data docker image prune --filter "label=org.label-schema.vendor=Nextcloud" --force
# Check for available free space
sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/CheckFreeDiskSpace.php
# Remove mastercontainer from default bridge network
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
sleep 60
done
================================================
FILE: Containers/mastercontainer/daily-backup.sh
================================================
#!/bin/bash
echo "Daily backup script has started"
# Check if initial configuration has been done, otherwise this script should do nothing.
CONFIG_FILE=/mnt/docker-aio-config/data/configuration.json
if ! [ -f "$CONFIG_FILE" ] || (! grep -q "wasStartButtonClicked.*1" "$CONFIG_FILE" && ! grep -q "wasStartButtonClicked.*true" "$CONFIG_FILE"); then
echo "Initial configuration via AIO interface not done yet. Exiting..."
exit 0
fi
# Daily backup and backup check cannot be run at the same time
if [ "$DAILY_BACKUP" = 1 ] && [ "$CHECK_BACKUP" = 1 ]; then
echo "Daily backup and backup check cannot be run at the same time. Exiting..."
exit 1
fi
# Delete all active sessions and create a lock file
# But don't kick out the user if the mastercontainer was just updated since we block the interface either way with the lock file
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 -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
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
# Prevent issues like https://github.com/nextcloud/all-in-one/discussions/5222
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 "$LOCAL_APACHE_PORT"; do
echo "Waiting for apache to become available"
sleep 30
done
fi
while docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-watchtower$"; do
echo "Waiting for watchtower to stop"
sleep 30
done
while docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-borgbackup$"; do
echo "Waiting for borgbackup to stop"
sleep 30
done
# Update the mastercontainer
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 -E -u www-data php /var/www/docker-aio/php/src/Cron/UpdateMastercontainer.php
fi
# Wait for watchtower to stop
if [ "$AUTOMATIC_UPDATES" = 1 ]; then
if ! docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-watchtower$"; then
echo "Something seems to be wrong: Watchtower should be started at this step."
fi
while docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-watchtower$"; do
echo "Waiting for watchtower to stop"
sleep 30
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 -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 -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
while docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-borgbackup$"; do
echo "Waiting for backup container to stop"
sleep 30
done
fi
# Execute backup check
if [ "$CHECK_BACKUP" = 1 ]; then
echo "Starting backup check..."
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 -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 -E -u www-data php /var/www/docker-aio/php/src/Cron/StartContainers.php
fi
fi
# Delete the lock file
rm -f "/mnt/docker-aio-config/data/daily_backup_running"
# Send backup notification
# shellcheck disable=SC2235
if [ "$DAILY_BACKUP" = 1 ] && ([ "$AUTOMATIC_UPDATES" = 1 ] || [ "$START_CONTAINERS" = 1 ]); then
# Wait for the nextcloud container to start and send if the backup was successful
if ! docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-nextcloud$"; then
echo "Something seems to be wrong: Nextcloud should be started at this step."
else
while docker ps --format "{{.Names}}" | grep -q "^nextcloud-aio-nextcloud$" && ! nc -z nextcloud-aio-nextcloud 9000; do
echo "Waiting for the Nextcloud container to start"
sleep 30
if [ "$(docker inspect nextcloud-aio-nextcloud --format "{{.State.Restarting}}")" = "true" ]; then
echo "Nextcloud container restarting. Skipping this check!"
break
fi
done
fi
echo "Sending backup notification..."
sudo -E -u www-data php /var/www/docker-aio/php/src/Cron/BackupNotification.php
fi
echo "Daily backup script has finished"
================================================
FILE: Containers/mastercontainer/healthcheck.sh
================================================
#!/bin/bash
if [ -f "/mnt/docker-aio-config/data/configuration.json" ]; then
nc -z 127.0.0.1 80 || exit 1
nc -z 127.0.0.1 8080 || exit 1
nc -z 127.0.0.1 8443 || exit 1
test -S /run/php.sock || exit 1
nc -z 127.0.0.1 9876 || exit 1
fi
================================================
FILE: Containers/mastercontainer/internal.Caddyfile
================================================
{
admin off
storage file_system {
root /mnt/docker-aio-config/caddy/
}
log {
level ERROR
# We need to exclude the remote-host plugin from logging as it would spam the logs
# See https://github.com/nextcloud/all-in-one/pull/7006#issuecomment-4003238239
exclude http.matchers.remote_host
}
servers {
# Only h1 is allowed as we prevent `ERR_NETWORK_CHANGED` from happening
protocols h1
}
skip_install_trust
}
https://:8080 {
@denied {
path /api/auth/login /api/auth/getlogin
remote_host nextcloud-aio-nextcloud
}
abort @denied
root * /var/www/docker-aio/php/public
php_fastcgi unix//run/php.sock
file_server
tls {
on_demand
issuer internal
}
}
================================================
FILE: Containers/mastercontainer/session-deduplicator.sh
================================================
#!/bin/bash
deduplicate_sessions() {
echo "Deleting duplicate sessions"
find "/mnt/docker-aio-config/session/" -mindepth 1 -exec grep -qv "$NEW_SESSION_TIME" {} \; -delete
}
compare_times() {
if [ -f "/mnt/docker-aio-config/data/session_date_file" ]; then
unset NEW_SESSION_TIME
NEW_SESSION_TIME="$(cat "/mnt/docker-aio-config/data/session_date_file")"
if [ -n "$NEW_SESSION_TIME" ] && [ -n "$OLD_SESSION_TIME" ] && [ "$NEW_SESSION_TIME" != "$OLD_SESSION_TIME" ]; then
deduplicate_sessions
fi
OLD_SESSION_TIME="$NEW_SESSION_TIME"
fi
}
while true; do
compare_times
sleep 2
done
================================================
FILE: Containers/mastercontainer/start.sh
================================================
#!/bin/bash
# Function to show text in green
print_green() {
local TEXT="$1"
printf "%b%s%b\n" "\e[0;92m" "$TEXT" "\e[0m"
}
# Function to show text in red
print_red() {
local TEXT="$1"
printf "%b%s%b\n" "\e[0;31m" "$TEXT" "\e[0m"
}
# Function to check if number was provided
check_if_number() {
case "${1}" in
''|*[!0-9]*) return 1 ;;
*) return 0 ;;
esac
}
# Check if running as root user
if [ "$EUID" != "0" ]; then
print_red "Container does not run as root user. This is not supported."
exit 1
fi
# Check that the CMD is not overwritten nor set
if [ "$*" != "" ]; then
print_red "Docker run command for AIO is incorrect as a CMD option was given which is not expected."
exit 1
fi
# Check if socket is available and readable
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 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)
# Check if a group with the same group name of /var/run/docker.socket already exists in the container
if grep -q "^$DOCKER_GROUP:" /etc/group; then
# If yes, add www-data to that group
echo "Adding internal www-data to group $DOCKER_GROUP"
usermod -aG "$DOCKER_GROUP" www-data
else
# Delete the docker group for cases when the docker socket permissions changed between restarts
groupdel docker &>/dev/null
# If the group doesn't exist, create it
echo "Creating docker group internally with id $DOCKER_GROUP_ID"
groupadd -g "$DOCKER_GROUP_ID" docker
usermod -aG docker www-data
fi
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
# 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 "$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$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
echo "LOCAL_API_VERSION_NUMB or API_VERSION_NUMB are not set correctly. Cannot check if the API version is supported."
sleep 10
fi
# Check Storage drivers
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"
print_red "Warning: It seems like the storage driver vfs is used. This will lead to problems with disk space and performance and is disrecommended!"
elif echo "$STORAGE_DRIVER" | grep -q fuse-overlayfs; then
echo "$STORAGE_DRIVER"
print_red "Warning: It seems like the storage driver fuse-overlayfs is used. Please check if you can switch to overlay2 instead."
fi
# Check if snap install
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 -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 -E -u www-data docker inspect nextcloud-aio-mastercontainer --format "{{.Config.Image}}" | grep -q '@'; then
print_red "It seems like you used a hash for the mastercontainer image tag. This is not supported!"
exit 1
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 -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
fi
# Check for other options
if [ -n "$NEXTCLOUD_DATADIR" ]; then
if [ "$NEXTCLOUD_DATADIR" = "nextcloud_aio_nextcloud_datadir" ]; then
sleep 1
elif ! echo "$NEXTCLOUD_DATADIR" | grep -q "^/" || [ "$NEXTCLOUD_DATADIR" = "/" ]; then
print_red "You've set NEXTCLOUD_DATADIR but not to an allowed value.
The string must start with '/' and must not be equal to '/'. Also allowed is 'nextcloud_aio_nextcloud_datadir'.
It is set to '$NEXTCLOUD_DATADIR'."
exit 1
fi
fi
if [ -n "$NEXTCLOUD_MOUNT" ]; then
if ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/" || [ "$NEXTCLOUD_MOUNT" = "/" ]; then
print_red "You've set NEXTCLOUD_MOUNT but not to an allowed value.
The string must start with '/' and must not be equal to '/'.
It is set to '$NEXTCLOUD_MOUNT'."
exit 1
elif [ "$NEXTCLOUD_MOUNT" = "/mnt/ncdata" ] || echo "$NEXTCLOUD_MOUNT" | grep -q "^/mnt/ncdata/"; then
print_red "'/mnt/ncdata' and '/mnt/ncdata/' are not allowed as values for NEXTCLOUD_MOUNT."
exit 1
fi
fi
if [ -n "$NEXTCLOUD_DATADIR" ] && [ -n "$NEXTCLOUD_MOUNT" ]; then
if [ "$NEXTCLOUD_DATADIR" = "$NEXTCLOUD_MOUNT" ]; then
print_red "NEXTCLOUD_DATADIR and NEXTCLOUD_MOUNT are not allowed to be equal."
exit 1
fi
fi
if [ -n "$NEXTCLOUD_UPLOAD_LIMIT" ]; then
if ! echo "$NEXTCLOUD_UPLOAD_LIMIT" | grep -q '^[0-9]\+G$'; then
print_red "You've set NEXTCLOUD_UPLOAD_LIMIT but not to an allowed value.
The string must start with a number and end with 'G'.
It is set to '$NEXTCLOUD_UPLOAD_LIMIT'."
exit 1
fi
fi
if [ -n "$NEXTCLOUD_MAX_TIME" ]; then
if ! echo "$NEXTCLOUD_MAX_TIME" | grep -q '^[0-9]\+$'; then
print_red "You've set NEXTCLOUD_MAX_TIME but not to an allowed value.
The string must be a number. E.g. '3600'.
It is set to '$NEXTCLOUD_MAX_TIME'."
exit 1
fi
fi
if [ -n "$NEXTCLOUD_MEMORY_LIMIT" ]; then
if ! echo "$NEXTCLOUD_MEMORY_LIMIT" | grep -q '^[0-9]\+M$'; then
print_red "You've set NEXTCLOUD_MEMORY_LIMIT but not to an allowed value.
The string must start with a number and end with 'M'.
It is set to '$NEXTCLOUD_MEMORY_LIMIT'."
exit 1
fi
fi
if [ -n "$APACHE_PORT" ]; then
if ! check_if_number "$APACHE_PORT"; then
print_red "You provided an Apache port but did not only use numbers.
It is set to '$APACHE_PORT'."
exit 1
elif ! [ "$APACHE_PORT" -le 65535 ] || ! [ "$APACHE_PORT" -ge 1 ]; then
print_red "The provided Apache port is invalid. It must be between 1 and 65535"
exit 1
fi
fi
if [ -n "$APACHE_IP_BINDING" ]; then
if ! echo "$APACHE_IP_BINDING" | grep -q '^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$\|^[0-9a-f:]\+$\|^@INTERNAL$'; then
print_red "You provided an ip-address for the apache container's ip-binding but it was not a valid ip-address.
It is set to '$APACHE_IP_BINDING'."
exit 1
fi
fi
if [ -n "$APACHE_ADDITIONAL_NETWORK" ]; then
if ! echo "$APACHE_ADDITIONAL_NETWORK" | grep -q "^[a-zA-Z0-9._-]\+$"; then
print_red "You've set APACHE_ADDITIONAL_NETWORK but not to an allowed value.
It needs to be a string with letters, numbers, hyphens and underscores.
It is set to '$APACHE_ADDITIONAL_NETWORK'."
exit 1
fi
fi
if [ -n "$TALK_PORT" ]; then
if ! check_if_number "$TALK_PORT"; then
print_red "You provided an Talk port but did not only use numbers.
It is set to '$TALK_PORT'."
exit 1
elif ! [ "$TALK_PORT" -le 65535 ] || ! [ "$TALK_PORT" -ge 1 ]; then
print_red "The provided Talk port is invalid. It must be between 1 and 65535"
exit 1
fi
fi
if [ -n "$APACHE_PORT" ] && [ -n "$TALK_PORT" ]; then
if [ "$APACHE_PORT" = "$TALK_PORT" ]; then
print_red "APACHE_PORT and TALK_PORT are not allowed to be equal."
exit 1
fi
fi
if [ -n "$WATCHTOWER_DOCKER_SOCKET_PATH" ]; then
if ! echo "$WATCHTOWER_DOCKER_SOCKET_PATH" | grep -q "^/" || echo "$WATCHTOWER_DOCKER_SOCKET_PATH" | grep -q "/$"; then
print_red "You've set WATCHTOWER_DOCKER_SOCKET_PATH but not to an allowed value.
The string must start with '/' and must not end with '/'.
It is set to '$WATCHTOWER_DOCKER_SOCKET_PATH'."
exit 1
fi
fi
if [ -n "$NEXTCLOUD_TRUSTED_CACERTS_DIR" ]; then
if ! echo "$NEXTCLOUD_TRUSTED_CACERTS_DIR" | grep -q "^/" || echo "$NEXTCLOUD_TRUSTED_CACERTS_DIR" | grep -q "/$"; then
print_red "You've set NEXTCLOUD_TRUSTED_CACERTS_DIR but not to an allowed value.
It should be an absolute path to a directory that starts with '/' but not end with '/'.
It is set to '$NEXTCLOUD_TRUSTED_CACERTS_DIR '."
exit 1
fi
fi
if [ -n "$NEXTCLOUD_STARTUP_APPS" ]; then
if ! echo "$NEXTCLOUD_STARTUP_APPS" | grep -q "^[a-z0-9 _-]\+$"; then
print_red "You've set NEXTCLOUD_STARTUP_APPS but not to an allowed value.
It needs to be a string. Allowed are small letters a-z, 0-9, spaces, hyphens and '_'.
It is set to '$NEXTCLOUD_STARTUP_APPS'."
exit 1
fi
fi
if [ -n "$NEXTCLOUD_ADDITIONAL_APKS" ]; then
if ! echo "$NEXTCLOUD_ADDITIONAL_APKS" | grep -q "^[a-z0-9 ._-]\+$"; then
print_red "You've set NEXTCLOUD_ADDITIONAL_APKS but not to an allowed value.
It needs to be a string. Allowed are small letters a-z, digits 0-9, spaces, hyphens, dots and '_'.
It is set to '$NEXTCLOUD_ADDITIONAL_APKS'."
exit 1
fi
fi
if [ -n "$NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS" ]; then
if ! echo "$NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS" | grep -q "^[a-z0-9 ._-]\+$"; then
print_red "You've set NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS but not to an allowed value.
It needs to be a string. Allowed are small letters a-z, digits 0-9, spaces, hyphens, dots and '_'.
It is set to '$NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS'."
exit 1
fi
fi
if [ -n "$AIO_COMMUNITY_CONTAINERS" ]; then
print_red "You've set AIO_COMMUNITY_CONTAINERS but the option was removed.
The community containers get managed via the AIO interface now."
fi
# Check if ghcr.io is reachable
# Solves issues like https://github.com/nextcloud/all-in-one/discussions/5268
if ! curl --no-progress-meter https://ghcr.io/v2/ >/dev/null; then
print_red "Could not reach https://ghcr.io."
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
# Check that no changes have been made to timezone settings since AIO only supports running in Etc/UTC timezone
if [ -n "$TZ" ]; then
print_red "The environmental variable TZ has been set which is not supported by AIO since it only supports running in the default Etc/UTC timezone!"
echo "The correct timezone can be set in the AIO interface later on!"
# 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!"
exit 1
fi
if mountpoint -q /etc/timezone; then
print_red "/etc/timezone 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!"
exit 1
fi
# Check if unsupported env are set (but don't exit as it would break many instances)
if [ -n "$APACHE_DISABLE_REWRITE_IP" ]; then
print_red "The environmental variable APACHE_DISABLE_REWRITE_IP has been set which is not supported by AIO. Please remove it!"
fi
if [ -n "$NEXTCLOUD_TRUSTED_DOMAINS" ]; then
print_red "The environmental variable NEXTCLOUD_TRUSTED_DOMAINS has been set which is not supported by AIO. Please remove it!"
fi
if [ -n "$TRUSTED_PROXIES" ]; then
print_red "The environmental variable TRUSTED_PROXIES has been set which is not supported by AIO. Please remove it!"
fi
# Add important folders
mkdir -p /mnt/docker-aio-config/data/
mkdir -p /mnt/docker-aio-config/session/
mkdir -p /mnt/docker-aio-config/caddy/
# Adjust permissions for all instances
chmod 770 -R /mnt/docker-aio-config
chmod 777 /mnt/docker-aio-config
chown www-data:www-data -R /mnt/docker-aio-config/data/
chown www-data:www-data -R /mnt/docker-aio-config/session/
chown www-data:www-data -R /mnt/docker-aio-config/caddy/
print_green "Initial startup of Nextcloud All-in-One complete!
You should be able to open the Nextcloud AIO Interface now on port 8080 of this server!
E.g. https://internal.ip.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!
If your server has port 80 and 8443 open 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"
# Set the timezone to Etc/UTC
export TZ=Etc/UTC
# Remove unused certs
rm -vrf /mnt/docker-aio-config/certs
# Remove the php socket as safeguard
rm -vf /run/php.sock
# 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 /acme.Caddyfile
caddy fmt --overwrite /internal.Caddyfile
# Fix caddy log
chmod 777 /root
# Start supervisord
exec /usr/bin/supervisord -c /supervisord.conf
================================================
FILE: Containers/mastercontainer/supervisord.conf
================================================
[supervisord]
nodaemon=true
logfile=/var/log/supervisord/supervisord.log
pidfile=/var/run/supervisord/supervisord.pid
childlogdir=/var/log/supervisord/
logfile_maxbytes=50MB
logfile_backups=10
loglevel=error
user=root
[program:php-fpm]
# Stdout logging is disabled as otherwise the logs are spammed
stdout_logfile=NONE
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=php-fpm
user=root
[program:caddy-internal]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=/usr/bin/caddy run --config /internal.Caddyfile
user=www-data
[program:caddy-acme]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=/usr/bin/caddy run --config /acme.Caddyfile
user=www-data
[program:cron]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=/cron.sh
user=root
[program:backup-time-file-watcher]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=/backup-time-file-watcher.sh
user=root
[program:session-deduplicator]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=/session-deduplicator.sh
user=root
[program:domain-validator]
# Logging is disabled as otherwise all attempts will be logged which spams the logs
stdout_logfile=NONE
stderr_logfile=NONE
command=php -S 127.0.0.1:9876 /var/www/docker-aio/php/domain-validator.php
user=www-data
================================================
FILE: Containers/nextcloud/Dockerfile
================================================
# syntax=docker/dockerfile:latest
FROM php:8.3.30-fpm-alpine3.23
ENV PHP_MEMORY_LIMIT=512M
ENV PHP_UPLOAD_LIMIT=16G
ENV PHP_MAX_TIME=3600
ENV SOURCE_LOCATION=/usr/src/nextcloud
ENV REDIS_DB_INDEX=0
# AIO settings start # Do not remove or change this line!
ENV NEXTCLOUD_VERSION=32.0.6
ENV AIO_TOKEN=123456
ENV AIO_URL=localhost
# AIO settings end # Do not remove or change this line!
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
# Custom: change id of www-data user as it needs to be the same like on old installations
# hadolint ignore=SC2086,DL3003
RUN set -ex; \
apk upgrade --no-cache -a; \
apk add --no-cache shadow; \
deluser www-data; \
addgroup -g 33 -S www-data; \
adduser -u 33 -D -S -G www-data www-data; \
\
# entrypoint.sh and cron.sh dependencies
apk add --no-cache \
rsync \
; \
# install the PHP extensions we need
# see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html
apk add --no-cache --virtual .build-deps \
$PHPIZE_DEPS \
autoconf \
freetype-dev \
gmp-dev \
icu-dev \
imagemagick-dev \
imagemagick-svg \
imagemagick-heic \
imagemagick-tiff \
libevent-dev \
libjpeg-turbo-dev \
libmcrypt-dev \
libmemcached-dev \
libpng-dev \
libwebp-dev \
libxml2-dev \
libzip-dev \
openldap-dev \
pcre-dev \
postgresql-dev \
; \
\
docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \
docker-php-ext-configure ftp --with-openssl-dir=/usr; \
docker-php-ext-configure ldap; \
docker-php-ext-install -j "$(nproc)" \
bcmath \
exif \
gd \
gmp \
intl \
ldap \
opcache \
pcntl \
pdo_pgsql \
sysvsem \
zip \
; \
\
# 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.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; \
\
runDeps="$( \
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
| tr ',' '\n' \
| sort -u \
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
)"; \
apk add --no-cache --virtual .nextcloud-phpext-rundeps $runDeps; \
apk del .build-deps; \
\
{ \
echo 'apc.serializer=igbinary'; \
echo 'session.serialize_handler=igbinary'; \
} >> /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/installation/server_tuning.html#enable-php-opcache and below
{ \
echo 'opcache.max_accelerated_files=10000'; \
echo 'opcache.memory_consumption=256'; \
echo 'opcache.interned_strings_buffer=64'; \
echo 'opcache.save_comments=1'; \
echo 'opcache.revalidate_freq=60'; \
echo 'opcache.jit=1255'; \
echo 'opcache.jit_buffer_size=8M'; \
} > /usr/local/etc/php/conf.d/opcache-recommended.ini; \
\
{ \
echo 'apc.enable_cli=1'; \
echo 'apc.shm_size=64M'; \
} >> /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini; \
\
{ \
echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \
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=-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}:${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'; \
echo 'session.gc_maxlifetime = 86400'; \
} > /usr/local/etc/php/conf.d/redis-session.ini; \
\
mkdir -p /var/www/data; \
chown -R www-data:root /var/www; \
chmod -R g=u /var/www; \
\
# Download Nextcloud archive start # Do not remove or change this line!
apk add --no-cache --virtual .fetch-deps \
bzip2 \
gnupg \
; \
\
curl -fsSL -o nextcloud.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)"; \
# gpg key from https://nextcloud.com/nextcloud.asc
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \
gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2; \
tar -xjf nextcloud.tar.bz2 -C /usr/src/; \
gpgconf --kill all; \
rm nextcloud.tar.bz2.asc nextcloud.tar.bz2; \
mkdir -p /usr/src/nextcloud/data; \
mkdir -p /usr/src/nextcloud/custom_apps; \
chmod +x /usr/src/nextcloud/occ; \
mkdir -p /usr/src/nextcloud/config; \
apk del .fetch-deps; \
# Download Nextcloud archive end # Do not remove or change this line!
mv /*.php /usr/src/nextcloud/config/; \
\
# Template from https://github.com/nextcloud/docker/blob/master/.examples/dockerfiles/full/fpm-alpine/Dockerfile
apk add --no-cache \
ffmpeg \
procps \
samba-client \
supervisor \
# libreoffice \
; \
\
apk add --no-cache --virtual .build-deps \
$PHPIZE_DEPS \
imap-dev \
krb5-dev \
openssl-dev \
samba-dev \
bzip2-dev \
libpq-dev \
; \
\
docker-php-ext-configure imap --with-kerberos --with-imap-ssl; \
docker-php-ext-install \
bz2 \
imap \
pgsql \
ftp \
; \
pecl install smbclient; \
docker-php-ext-enable smbclient; \
\
runDeps="$( \
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
| tr ',' '\n' \
| sort -u \
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
)"; \
apk add --no-cache --virtual .nextcloud-phpext-rundeps $runDeps; \
apk del .build-deps; \
\
mkdir -p \
/var/log/supervisord \
/var/run/supervisord \
; \
chmod 777 -R /var/log/supervisord; \
chmod 777 -R /var/run/supervisord; \
\
apk add --no-cache \
bash \
netcat-openbsd \
openssl \
gnupg \
git \
postgresql-client \
tzdata \
sudo \
grep \
nodejs \
bind-tools \
imagemagick \
imagemagick-svg \
imagemagick-heic \
imagemagick-tiff \
coreutils; \
\
grep -q '^pm = dynamic' /usr/local/etc/php-fpm.d/www.conf; \
sed -i 's/^pm = dynamic/pm = ondemand/' /usr/local/etc/php-fpm.d/www.conf; \
# Sync this with max db connections and MaxRequestWorkers
# We don't actually expect so many children but don't want to limit it artificially because people will report issues otherwise.
# Also children will usually be terminated again after the process is done due to the ondemand setting
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; \
\
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
# hadolint ignore=DL3002
USER root
ENTRYPOINT ["/start.sh"]
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"
================================================
FILE: Containers/nextcloud/README.md
================================================
# 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.
================================================
FILE: Containers/nextcloud/config/aio.config.php
================================================
<?php
$CONFIG = array (
'one-click-instance' => true,
'one-click-instance.user-limit' => 100,
);
================================================
FILE: Containers/nextcloud/config/apcu.config.php
================================================
<?php
$CONFIG = array (
'memcache.local' => '\OC\Memcache\APCu',
);
================================================
FILE: Containers/nextcloud/config/apps.config.php
================================================
<?php
$CONFIG = array (
'apps_paths' => array (
0 => array (
'path' => '/var/www/html/apps',
'url' => '/apps',
'writable' => false,
),
1 => array (
'path' => '/var/www/html/custom_apps',
'url' => '/custom_apps',
'writable' => true,
),
),
);
if (getenv('APPS_ALLOWLIST')) {
$CONFIG['appsallowlist'] = explode(" ", getenv('APPS_ALLOWLIST'));
}
if (getenv('NEXTCLOUD_APP_STORE_URL')) {
$CONFIG['appstoreurl'] = getenv('NEXTCLOUD_APP_STORE_URL');
}
================================================
FILE: Containers/nextcloud/config/certificates-bundle.config.php
================================================
<?php
// Check if NEXTCLOUD_TRUSTED_CERTIFICATES_ are configured
if (str_contains(implode(' ', array_keys(getenv())), 'NEXTCLOUD_TRUSTED_CERTIFICATES_')) {
$CONFIG['default_certificates_bundle_path'] = '/var/www/html/data/certificates/ca-bundle.crt';
}
================================================
FILE: Containers/nextcloud/config/postgres.config.php
================================================
<?php
if (getenv('NEXTCLOUD_TRUSTED_CERTIFICATES_POSTGRES')) {
$CONFIG = array(
'pgsql_ssl' => 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',
),
);
}
================================================
FILE: Containers/nextcloud/config/proxy.config.php
================================================
<?php
if (getenv('HTTP_PROXY')) {
$CONFIG['proxy'] = getenv('HTTP_PROXY');
}
if (getenv('HTTPS_PROXY')) {
$CONFIG['proxy'] = getenv('HTTPS_PROXY');
}
if (getenv('PROXY_USER_PASSWORD')) {
$CONFIG['proxyuserpwd'] = getenv('PROXY_USER_PASSWORD');
}
if (getenv('NO_PROXY')) {
$CONFIG['proxyexclude'] = explode(',', getenv('NO_PROXY'));
}
================================================
FILE: Containers/nextcloud/config/redis.config.php
================================================
<?php
if (getenv('REDIS_MODE') !== 'rediscluster') {
$CONFIG = array(
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
);
if (getenv('REDIS_HOST')) {
$CONFIG['redis']['host'] = (string) getenv('REDIS_HOST');
}
if (getenv('REDIS_HOST_PASSWORD')) {
$CONFIG['redis']['password'] = (string) getenv('REDIS_HOST_PASSWORD');
}
if (getenv('REDIS_PORT')) {
$CONFIG['redis']['port'] = (int) getenv('REDIS_PORT');
}
if (getenv('REDIS_DB_INDEX')) {
$CONFIG['redis']['dbindex'] = (int) getenv('REDIS_DB_INDEX');
}
if (getenv('REDIS_USER_AUTH')) {
$CONFIG['redis']['user'] = str_replace("&auth[]=", "", getenv('REDIS_USER_AUTH'));
}
if (getenv('NEXTCLOUD_TRUSTED_CERTIFICATES_REDIS')) {
$CONFIG['redis']['ssl_context']['cafile'] = '/var/www/html/data/certificates/ca-bundle.crt';
}
} else {
$CONFIG = array(
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis.cluster' => array(
'timeout' => 0.0,
'read_timeout' => 0.0,
'failover_mode' => \RedisCluster::FAILOVER_ERROR,
'seeds' => array_values(array_filter(array(
(getenv('REDIS_HOST') && getenv('REDIS_PORT')) ? (getenv('REDIS_HOST') . ':' . (string)getenv('REDIS_PORT')) : null,
(getenv('REDIS_HOST_2') && getenv('REDIS_PORT_2')) ? (getenv('REDIS_HOST_2') . ':' . (string)getenv('REDIS_PORT_2')) : null,
(getenv('REDIS_HOST_3') && getenv('REDIS_PORT_3')) ? (getenv('REDIS_HOST_3') . ':' . (string)getenv('REDIS_PORT_3')) : null,
(getenv('REDIS_HOST_4') && getenv('REDIS_PORT_4')) ? (getenv('REDIS_HOST_4') . ':' . (string)getenv('REDIS_PORT_4')) : null,
(getenv('REDIS_HOST_5') && getenv('REDIS_PORT_5')) ? (getenv('REDIS_HOST_5') . ':' . (string)getenv('REDIS_PORT_5')) : null,
(getenv('REDIS_HOST_6') && getenv('REDIS_PORT_6')) ? (getenv('REDIS_HOST_6') . ':' . (string)getenv('REDIS_PORT_6')) : null,
(getenv('REDIS_HOST_7') && getenv('REDIS_PORT_7')) ? (getenv('REDIS_HOST_7') . ':' . (string)getenv('REDIS_PORT_7')) : null,
(getenv('REDIS_HOST_8') && getenv('REDIS_PORT_8')) ? (getenv('REDIS_HOST_8') . ':' . (string)getenv('REDIS_PORT_8')) : null,
(getenv('REDIS_HOST_9') && getenv('REDIS_PORT_9')) ? (getenv('REDIS_HOST_9') . ':' . (string)getenv('REDIS_PORT_9')) : null,
))),
),
);
if (getenv('REDIS_HOST_PASSWORD')) {
$CONFIG['redis.cluster']['password'] = (string) getenv('REDIS_HOST_PASSWORD');
}
if (getenv('REDIS_USER_AUTH')) {
$CONFIG['redis.cluster']['user'] = str_replace("&auth[]=", "", getenv('REDIS_USER_AUTH'));
}
if (getenv('NEXTCLOUD_TRUSTED_CERTIFICATES_REDIS')) {
$CONFIG['redis.cluster']['ssl_context']['cafile'] = '/var/www/html/data/certificates/ca-bundle.crt';
}
}
================================================
FILE: Containers/nextcloud/config/reverse-proxy.config.php
================================================
<?php
$overwriteHost = getenv('OVERWRITEHOST');
if ($overwriteHost) {
$CONFIG['overwritehost'] = $overwriteHost;
}
$overwriteProtocol = getenv('OVERWRITEPROTOCOL');
if ($overwriteProtocol) {
$CONFIG['overwriteprotocol'] = $overwriteProtocol;
}
$overwriteWebRoot = getenv('OVERWRITEWEBROOT');
if ($overwriteWebRoot) {
$CONFIG['overwritewebroot'] = $overwriteWebRoot;
}
$overwriteCondAddr = getenv('OVERWRITECONDADDR');
if ($overwriteCondAddr) {
$CONFIG['overwritecondaddr'] = $overwriteCondAddr;
}
================================================
FILE: Containers/nextcloud/config/s3.config.php
================================================
<?php
if (getenv('OBJECTSTORE_S3_BUCKET')) {
$use_ssl = getenv('OBJECTSTORE_S3_SSL');
$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') ?: '',
'region' => getenv('OBJECTSTORE_S3_REGION') ?: '',
'hostname' => getenv('OBJECTSTORE_S3_HOST') ?: '',
'port' => getenv('OBJECTSTORE_S3_PORT') ?: '',
'storageClass' => getenv('OBJECTSTORE_S3_STORAGE_CLASS') ?: '',
'objectPrefix' => getenv("OBJECTSTORE_S3_OBJECT_PREFIX") ? getenv("OBJECTSTORE_S3_OBJECT_PREFIX") : "urn:oid:",
'autocreate' => strtolower($autocreate) !== 'false',
'use_ssl' => strtolower($use_ssl) !== 'false',
// required for some non Amazon S3 implementations
'use_path_style' => strtolower($use_path) === 'true',
// required for older protocol versions
'legacy_auth' => strtolower($use_legacyauth) === 'true',
'use_nextcloud_bundle' => 1,
)
)
);
$sse_c_key = getenv('OBJECTSTORE_S3_SSE_C_KEY');
if ($sse_c_key) {
$CONFIG['objectstore']['arguments']['sse_c_key'] = $sse_c_key;
}
$requestChecksumValidation = getenv('OBJECTSTORE_S3_REQUEST_CHECKSUM_VALIDATION');
if ($requestChecksumValidation) {
$CONFIG['objectstore']['arguments']['request_checksum_calculation'] = $requestChecksumValidation;
}
$responseChecksumValidation = getenv('OBJECTSTORE_S3_RESPONSE_CHECKSUM_VALIDATION');
if ($responseChecksumValidation) {
$CONFIG['objectstore']['arguments']['response_checksum_validation'] = $responseChecksumValidation;
}
}
================================================
FILE: Containers/nextcloud/config/smtp.config.php
================================================
<?php
if (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) {
$CONFIG = array (
'mail_smtpmode' => 'smtp',
'mail_smtphost' => getenv('SMTP_HOST'),
'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25),
'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '',
'mail_smtpauth' => getenv('SMTP_NAME') && getenv('SMTP_PASSWORD'),
'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN',
'mail_smtpname' => getenv('SMTP_NAME') ?: '',
'mail_from_address' => getenv('MAIL_FROM_ADDRESS'),
'mail_domain' => getenv('MAIL_DOMAIN'),
);
if (getenv('SMTP_PASSWORD')) {
$CONFIG['mail_smtppassword'] = getenv('SMTP_PASSWORD');
} else {
$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',
)
)
);
}
================================================
FILE: Containers/nextcloud/config/swift.config.php
================================================
<?php
if (getenv('OBJECTSTORE_SWIFT_URL')) {
$autocreate = getenv('OBJECTSTORE_SWIFT_AUTOCREATE');
$CONFIG = array(
'objectstore' => [
'class' => 'OC\\Files\\ObjectStore\\Swift',
'arguments' => [
'autocreate' => $autocreate == true && strtolower($autocreate) !== 'false',
'user' => [
'name' => getenv('OBJECTSTORE_SWIFT_USER_NAME'),
'password' => getenv('OBJECTSTORE_SWIFT_USER_PASSWORD'),
'domain' => [
'name' => (getenv('OBJECTSTORE_SWIFT_USER_DOMAIN')) ?: 'Default',
],
],
'scope' => [
'project' => [
'name' => getenv('OBJECTSTORE_SWIFT_PROJECT_NAME'),
'domain' => [
'name' => (getenv('OBJECTSTORE_SWIFT_PROJECT_DOMAIN')) ?: 'Default',
],
],
],
'serviceName' => (getenv('OBJECTSTORE_SWIFT_SERVICE_NAME')) ?: 'swift',
'region' => getenv('OBJECTSTORE_SWIFT_REGION'),
'url' => getenv('OBJECTSTORE_SWIFT_URL'),
'bucket' => getenv('OBJECTSTORE_SWIFT_CONTAINER_NAME'),
]
]
);
}
================================================
FILE: Containers/nextcloud/cron.sh
================================================
#!/bin/bash
wait_for_cron() {
set -x
while [ -n "$(pgrep -f /var/www/html/cron.php)" ]; do
echo "Waiting for cron to stop..."
sleep 5
done
echo "Cronjob successfully exited."
exit
}
trap wait_for_cron SIGINT SIGTERM
while true; do
php -f /var/www/html/cron.php &
sleep 5m &
wait $!
done
================================================
FILE: Containers/nextcloud/entrypoint.sh
================================================
#!/bin/bash
# version_greater A B returns whether A > B
version_greater() {
[ "$(printf '%s\n' "$@" | sort -t '.' -n -k1,1 -k2,2 -k3,3 -k4,4 | head -n 1)" != "$1" ]
}
# return true if specified directory is empty
directory_empty() {
[ -z "$(ls -A "$1/")" ]
}
run_upgrade_if_needed_due_to_app_update() {
if php /var/www/html/occ status | grep maintenance | grep -q true; then
php /var/www/html/occ maintenance:mode --off
fi
if php /var/www/html/occ status | grep needsDbUpgrade | grep -q true; then
php /var/www/html/occ upgrade
php /var/www/html/occ app:enable nextcloud-aio --force
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
# shellcheck disable=SC2153
while ! nc -z "$REDIS_HOST" "$REDIS_PORT"; do
echo "Waiting for Redis to start..."
sleep 5
done
# Check permissions in ncdata
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 -f "$test_file"
if [ -f /var/www/html/version.php ]; then
# shellcheck disable=SC2016
installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
else
installed_version="0.0.0.0"
fi
if [ -f "$SOURCE_LOCATION/version.php" ]; then
# shellcheck disable=SC2016
image_version="$(php -r "require '$SOURCE_LOCATION/version.php'; echo implode('.', \$OC_Version);")"
else
image_version="$installed_version"
fi
# unset admin password
if [ "$installed_version" != "0.0.0.0" ]; then
unset ADMIN_PASSWORD
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 "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 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 "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
# Skip any update if Nextcloud was just restored
if ! [ -f "$NEXTCLOUD_DATA_DIR/skip.update" ]; then
if version_greater "$image_version" "$installed_version"; then
# Check if it skips a major version
INSTALLED_MAJOR="${installed_version%%.*}"
IMAGE_MAJOR="${image_version%%.*}"
if [ "$installed_version" != "0.0.0.0" ]; then
# Write output to logfile.
exec > >(tee -i "/var/www/html/data/update.log")
exec 2>&1
fi
if [ "$installed_version" != "0.0.0.0" ] && [ "$((IMAGE_MAJOR - INSTALLED_MAJOR))" -gt 1 ]; then
# Do not skip major versions placeholder # Do not remove or change this line!
# Do not skip major versions start # Do not remove or change this line!
set -ex
NEXT_MAJOR="$((INSTALLED_MAJOR + 1))"
curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/latest-${NEXT_MAJOR}.tar.bz2"
curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/latest-${NEXT_MAJOR}.tar.bz2.asc"
GNUPGHOME="$(mktemp -d)"
export GNUPGHOME
if ! gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; then
if ! gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 28806A878AE423A28372792ED75899B9A724937A; then
curl -sSL https://nextcloud.com/nextcloud.asc | gpg --import
fi
fi
gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2
mkdir -p /usr/src/tmp
tar -xjf nextcloud.tar.bz2 -C /usr/src/tmp/
gpgconf --kill all
rm nextcloud.tar.bz2.asc nextcloud.tar.bz2
mkdir -p /usr/src/tmp/nextcloud/data
mkdir -p /usr/src/tmp/nextcloud/custom_apps
chmod +x /usr/src/tmp/nextcloud/occ
cp -r "$SOURCE_LOCATION"/config/* /usr/src/tmp/nextcloud/config/
mkdir -p /usr/src/tmp/nextcloud/apps/nextcloud-aio
cp -r "$SOURCE_LOCATION"/apps/nextcloud-aio/* /usr/src/tmp/nextcloud/apps/nextcloud-aio/
mv "$SOURCE_LOCATION" /usr/src/temp-nextcloud
mv /usr/src/tmp/nextcloud "$SOURCE_LOCATION"
rm -r /usr/src/tmp
rm -r /usr/src/temp-nextcloud
# shellcheck disable=SC2016
image_version="$(php -r "require '$SOURCE_LOCATION/version.php'; echo implode('.', \$OC_Version);")"
IMAGE_MAJOR="${image_version%%.*}"
set +ex
# Do not skip major versions end # Do not remove or change this line!
fi
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 the app store..."
APPSTORE_URL="https://apps.nextcloud.com/api/v1"
if grep -q appstoreurl /var/www/html/config/config.php; then
set -x
APPSTORE_URL="$(grep appstoreurl /var/www/html/config/config.php | grep -oP 'https://.*v[0-9]+')"
set +x
fi
# Default appstoreurl parameter in config.php defaults to 'https://apps.nextcloud.com/api/v1' so we check for the apps.json file stored in there
CURL_STATUS="$(curl -LI "$APPSTORE_URL"/apps.json -o /dev/null -w '%{http_code}\n' -s)"
if [[ "$CURL_STATUS" = "200" ]]
then
echo "App store is reachable."
break
else
echo "Curl did not return a 200 status. Is the app store reachable?"
sleep 5
fi
done
# Check connection to appstore end # Do not remove or change this line!
run_upgrade_if_needed_due_to_app_update
php /var/www/html/occ maintenance:mode --off
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..."
APPSTORAGE="no-export-done"
else
mapfile -t NC_APPS_ARRAY <<< "$NC_APPS"
declare -Ag APPSTORAGE
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 its enabled state failed."
fi
done
fi
if [ "$((IMAGE_MAJOR - INSTALLED_MAJOR))" -eq 1 ]; then
php /var/www/html/occ config:system:delete app_install_overwrite
fi
php /var/www/html/occ app:update --all
run_upgrade_if_needed_due_to_app_update
fi
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/
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/
echo "Initializing finished"
################
# Fresh Install
################
if [ "$installed_version" = "0.0.0.0" ]; then
echo "New Nextcloud instance."
# Write output to logfile.
mkdir -p /var/www/html/data
exec > >(tee -i "/var/www/html/data/install.log")
exec 2>&1
INSTALL_OPTIONS=(-n --admin-user "$ADMIN_USER" --admin-pass "$ADMIN_PASSWORD")
if [ -n "${NEXTCLOUD_DATA_DIR}" ]; then
INSTALL_OPTIONS+=(--data-dir "$NEXTCLOUD_DATA_DIR")
fi
# Skip the default permission check (we do our own)
cat > /var/www/html/config/datadir.permission.config.php <<'EOF'
<?php
$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
fi
# 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!"
touch "$NEXTCLOUD_DATA_DIR/install.failed"
exit 1
fi
# Try to force generation of appdata dir:
php /var/www/html/occ maintenance:repair
if [ -z "$OBJECTSTORE_S3_BUCKET" ] && [ -z "$OBJECTSTORE_SWIFT_URL" ]; then
max_retries=10
try=0
while [ -z "$(find "$NEXTCLOUD_DATA_DIR/" -maxdepth 1 -mindepth 1 -type d -name "appdata_*")" ] && [ "$try" -lt "$max_retries" ]; do
echo "Waiting for appdata to become available..."
try=$((try+1))
sleep 10s
done
if [ "$try" -ge "$max_retries" ]; then
echo "Installation of Nextcloud failed!"
echo "Installation errors: $(cat /var/www/html/data/nextcloud.log)"
touch "$NEXTCLOUD_DATA_DIR/install.failed"
exit 1
fi
fi
# This autoconfig is not needed anymore and should be able to be overwritten by the user
rm /var/www/html/config/datadir.permission.config.php
# unset admin password
unset ADMIN_PASSWORD
# Enable the updatenotification app but disable its UI and server update notifications
php /var/www/html/occ config:system:set updatechecker --type=bool --value=false
php /var/www/html/occ config:app:set updatenotification notify_groups --value="[]"
# AIO update to latest start # Do not remove or change this line!
if [ "$INSTALL_LATEST_MAJOR" = yes ]; then
php /var/www/html/occ config:system:set updatedirectory --value="/nc-updater"
INSTALLED_AT="$(php /var/www/html/occ config:app:get core installedat)"
if [ -n "${INSTALLED_AT}" ]; then
# Set the installdat to 00 which will allow to skip staging and install the next major directly
# shellcheck disable=SC2001
INSTALLED_AT="$(echo "${INSTALLED_AT}" | sed "s|[0-9][0-9]$|00|")"
php /var/www/html/occ config:app:set core installedat --value="${INSTALLED_AT}"
fi
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!"
touch "$NEXTCLOUD_DATA_DIR/install.failed"
exit 1
fi
# shellcheck disable=SC2016
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
# shellcheck disable=SC2016
installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
fi
php /var/www/html/occ config:system:set updatechecker --type=bool --value=true
php /var/www/html/occ app:enable nextcloud-aio --force
php /var/www/html/occ db:add-missing-columns
php /var/www/html/occ db:add-missing-primary-keys
yes | php /var/www/html/occ db:convert-filecache-bigint
fi
# AIO update to latest end # Do not remove or change this line!
# Apply log settings
echo "Applying default settings..."
mkdir -p /var/www/html/data
php /var/www/html/occ config:system:set loglevel --value="2" --type=integer
php /var/www/html/occ config:system:set log_type --value="file"
php /var/www/html/occ config:system:set logfile --value="/var/www/html/data/nextcloud.log"
php /var/www/html/occ config:system:set log_rotate_size --value="10485760" --type=integer
php /var/www/html/occ app:enable admin_audit
php /var/www/html/occ config:app:set admin_audit logfile --value="/var/www/html/data/audit.log"
php /var/www/html/occ config:system:set log.condition apps 0 --value="admin_audit"
# Apply preview settings
echo "Applying preview settings..."
php /var/www/html/occ config:system:set preview_max_x --value="2048" --type=integer
php /var/www/html/occ config:system:set preview_max_y --value="2048" --type=integer
php /var/www/html/occ config:system:set jpeg_quality --value="60" --type=integer
php /var/www/html/occ config:app:set preview jpeg_quality --value="60"
php /var/www/html/occ config:system:delete enabledPreviewProviders
php /var/www/html/occ config:system:set enabledPreviewProviders 1 --value="OC\\Preview\\Image"
php /var/www/html/occ config:system:set enabledPreviewProviders 2 --value="OC\\Preview\\MarkDown"
php /var/www/html/occ config:system:set enabledPreviewProvi
gitextract_32moa423/ ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── Bug_report.md │ │ ├── Feature_request.md │ │ └── config.yml │ ├── dependabot.yml │ ├── pull_request_template.md │ ├── release.yml │ └── workflows/ │ ├── codespell.yml │ ├── collabora.yml │ ├── community-containers.yml │ ├── dependency-updates.yml │ ├── docker-lint.yml │ ├── fail-on-prerelease.yml │ ├── helm-release.yml │ ├── imaginary-update.yml │ ├── json-validator.yml │ ├── lint-helm.yml │ ├── lint-php.yml │ ├── lint-yaml.yml │ ├── lock-threads.yml │ ├── nextcloud-update.yml │ ├── php-deprecation-detector.yml │ ├── playwright-on-push.yml │ ├── playwright-on-workflow-dispatch.yml │ ├── psalm-update-baseline.yml │ ├── psalm.yml │ ├── shellcheck.yml │ ├── talk.yml │ ├── twig-lint.yml │ ├── update-copyright.yml │ ├── update-helm.yml │ ├── update-yaml.yml │ └── watchtower-update.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── Containers/ │ ├── alpine/ │ │ └── Dockerfile │ ├── apache/ │ │ ├── Caddyfile │ │ ├── Dockerfile │ │ ├── healthcheck.sh │ │ ├── nextcloud.conf │ │ ├── start.sh │ │ └── supervisord.conf │ ├── borgbackup/ │ │ ├── Dockerfile │ │ ├── backupscript.sh │ │ ├── borg_excludes │ │ └── start.sh │ ├── clamav/ │ │ ├── Dockerfile │ │ ├── healthcheck.sh │ │ ├── start.sh │ │ └── supervisord.conf │ ├── collabora/ │ │ ├── Dockerfile │ │ └── healthcheck.sh │ ├── collabora-online/ │ │ ├── Dockerfile │ │ └── healthcheck.sh │ ├── docker-socket-proxy/ │ │ ├── Dockerfile │ │ ├── haproxy.cfg │ │ ├── healthcheck.sh │ │ └── start.sh │ ├── domaincheck/ │ │ ├── Dockerfile │ │ ├── lighttpd.conf │ │ └── start.sh │ ├── fulltextsearch/ │ │ ├── Dockerfile │ │ └── healthcheck.sh │ ├── imaginary/ │ │ ├── Dockerfile │ │ ├── healthcheck.sh │ │ └── start.sh │ ├── mastercontainer/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── acme.Caddyfile │ │ ├── backup-time-file-watcher.sh │ │ ├── cron.sh │ │ ├── daily-backup.sh │ │ ├── healthcheck.sh │ │ ├── internal.Caddyfile │ │ ├── session-deduplicator.sh │ │ ├── start.sh │ │ └── supervisord.conf │ ├── nextcloud/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── config/ │ │ │ ├── aio.config.php │ │ │ ├── apcu.config.php │ │ │ ├── apps.config.php │ │ │ ├── certificates-bundle.config.php │ │ │ ├── postgres.config.php │ │ │ ├── proxy.config.php │ │ │ ├── redis.config.php │ │ │ ├── reverse-proxy.config.php │ │ │ ├── s3.config.php │ │ │ ├── smtp.config.php │ │ │ └── swift.config.php │ │ ├── cron.sh │ │ ├── entrypoint.sh │ │ ├── healthcheck.sh │ │ ├── notify-all.sh │ │ ├── notify.sh │ │ ├── root.motd │ │ ├── run-exec-commands.sh │ │ ├── start.sh │ │ ├── supervisord.conf │ │ └── upgrade.exclude │ ├── notify-push/ │ │ ├── Dockerfile │ │ ├── healthcheck.sh │ │ └── start.sh │ ├── onlyoffice/ │ │ ├── Dockerfile │ │ └── healthcheck.sh │ ├── postgresql/ │ │ ├── Dockerfile │ │ ├── healthcheck.sh │ │ ├── init-user-db.sh │ │ └── start.sh │ ├── redis/ │ │ ├── Dockerfile │ │ ├── healthcheck.sh │ │ └── start.sh │ ├── talk/ │ │ ├── Dockerfile │ │ ├── healthcheck.sh │ │ ├── server.conf.in │ │ ├── start.sh │ │ └── supervisord.conf │ ├── talk-recording/ │ │ ├── Dockerfile │ │ ├── healthcheck.sh │ │ ├── recording.conf │ │ └── start.sh │ ├── watchtower/ │ │ ├── Dockerfile │ │ └── start.sh │ └── whiteboard/ │ ├── Dockerfile │ ├── healthcheck.sh │ └── start.sh ├── LICENSE ├── app/ │ ├── .editorconfig │ ├── appinfo/ │ │ └── info.xml │ ├── composer/ │ │ ├── autoload.php │ │ ├── composer/ │ │ │ ├── ClassLoader.php │ │ │ ├── InstalledVersions.php │ │ │ ├── LICENSE │ │ │ ├── autoload_classmap.php │ │ │ ├── autoload_namespaces.php │ │ │ ├── autoload_psr4.php │ │ │ ├── autoload_real.php │ │ │ ├── autoload_static.php │ │ │ ├── installed.json │ │ │ └── installed.php │ │ └── composer.json │ ├── lib/ │ │ └── Settings/ │ │ └── Admin.php │ ├── readme.md │ └── templates/ │ └── admin.php ├── community-containers/ │ ├── borgbackup-viewer/ │ │ ├── borgbackup-viewer.json │ │ └── readme.md │ ├── caddy/ │ │ ├── caddy.json │ │ └── readme.md │ ├── calcardbackup/ │ │ ├── calcardbackup.json │ │ └── readme.md │ ├── container-management/ │ │ ├── container-management.json │ │ └── readme.md │ ├── dlna/ │ │ ├── dlna.json │ │ └── readme.md │ ├── facerecognition/ │ │ ├── facerecognition.json │ │ └── readme.md │ ├── fail2ban/ │ │ ├── fail2ban.json │ │ └── readme.md │ ├── glances/ │ │ ├── glances.json │ │ └── readme.md │ ├── helloworld/ │ │ ├── helloworld.json │ │ └── readme.md │ ├── jellyfin/ │ │ ├── jellyfin.json │ │ └── readme.md │ ├── jellyseerr/ │ │ ├── jellyseerr.json │ │ └── readme.md │ ├── languagetool/ │ │ ├── languagetool.json │ │ └── readme.md │ ├── libretranslate/ │ │ ├── libretranslate.json │ │ └── readme.md │ ├── lldap/ │ │ ├── lldap.json │ │ └── readme.md │ ├── local-ai/ │ │ ├── local-ai.json │ │ └── readme.md │ ├── makemkv/ │ │ ├── makemkv.json │ │ └── readme.md │ ├── memories/ │ │ ├── memories.json │ │ └── readme.md │ ├── minio/ │ │ ├── minio.json │ │ └── readme.md │ ├── nextcloud-exporter/ │ │ ├── nextcloud-exporter.json │ │ └── readme.md │ ├── nocodb/ │ │ ├── nocodb.json │ │ └── readme.md │ ├── notifications/ │ │ ├── notifications.json │ │ └── readme.md │ ├── npmplus/ │ │ ├── npmplus.json │ │ └── readme.md │ ├── pi-hole/ │ │ ├── pi-hole.json │ │ └── readme.md │ ├── plex/ │ │ ├── plex.json │ │ └── readme.md │ ├── readme.md │ ├── scrutiny/ │ │ ├── readme.md │ │ └── scrutiny.json │ ├── smbserver/ │ │ ├── readme.md │ │ └── smbserver.json │ ├── stalwart/ │ │ ├── readme.md │ │ └── stalwart.json │ └── vaultwarden/ │ ├── readme.md │ └── vaultwarden.json ├── compose.yaml ├── develop.md ├── docker-ipv6-support.md ├── docker-rootless.md ├── local-instance.md ├── manual-install/ │ ├── latest.yml │ ├── readme.md │ ├── sample.conf │ └── update-yaml.sh ├── manual-upgrade.md ├── migration.md ├── multiple-instances.md ├── nextcloud-aio-helm-chart/ │ ├── Chart.yaml │ ├── readme.md │ ├── templates/ │ │ ├── nextcloud-aio-apache-deployment.yaml │ │ ├── nextcloud-aio-apache-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-apache-service.yaml │ │ ├── nextcloud-aio-clamav-deployment.yaml │ │ ├── nextcloud-aio-clamav-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-clamav-service.yaml │ │ ├── nextcloud-aio-collabora-deployment.yaml │ │ ├── nextcloud-aio-collabora-service.yaml │ │ ├── nextcloud-aio-database-deployment.yaml │ │ ├── nextcloud-aio-database-dump-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-database-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-database-service.yaml │ │ ├── nextcloud-aio-elasticsearch-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-fulltextsearch-deployment.yaml │ │ ├── nextcloud-aio-fulltextsearch-service.yaml │ │ ├── nextcloud-aio-imaginary-deployment.yaml │ │ ├── nextcloud-aio-imaginary-service.yaml │ │ ├── nextcloud-aio-namespace-namespace.yaml │ │ ├── nextcloud-aio-networkpolicy.yaml │ │ ├── nextcloud-aio-nextcloud-data-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-nextcloud-deployment.yaml │ │ ├── nextcloud-aio-nextcloud-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-nextcloud-service.yaml │ │ ├── nextcloud-aio-nextcloud-trusted-cacerts-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-notify-push-deployment.yaml │ │ ├── nextcloud-aio-notify-push-service.yaml │ │ ├── nextcloud-aio-onlyoffice-deployment.yaml │ │ ├── nextcloud-aio-onlyoffice-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-onlyoffice-service.yaml │ │ ├── nextcloud-aio-redis-deployment.yaml │ │ ├── nextcloud-aio-redis-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-redis-service.yaml │ │ ├── nextcloud-aio-talk-deployment.yaml │ │ ├── nextcloud-aio-talk-recording-deployment.yaml │ │ ├── nextcloud-aio-talk-recording-persistentvolumeclaim.yaml │ │ ├── nextcloud-aio-talk-recording-service.yaml │ │ ├── nextcloud-aio-talk-service.yaml │ │ ├── nextcloud-aio-whiteboard-deployment.yaml │ │ └── nextcloud-aio-whiteboard-service.yaml │ ├── update-helm.sh │ └── values.yaml ├── php/ │ ├── README.md │ ├── composer.json │ ├── containers-schema.json │ ├── containers.json │ ├── cool-seccomp-profile.json │ ├── data/ │ │ └── .gitkeep │ ├── domain-validator.php │ ├── get-configurable-aio-variables.sh │ ├── psalm-baseline.xml │ ├── psalm.xml │ ├── public/ │ │ ├── automatic_reload.js │ │ ├── base_path.js │ │ ├── before-unload.js │ │ ├── containers-form-submit.js │ │ ├── disable-clamav.js │ │ ├── disable-collabora.js │ │ ├── disable-docker-socket-proxy.js │ │ ├── disable-fulltextsearch.js │ │ ├── disable-harp.js │ │ ├── disable-imaginary.js │ │ ├── disable-onlyoffice.js │ │ ├── disable-talk-recording.js │ │ ├── disable-talk.js │ │ ├── disable-whiteboard.js │ │ ├── forms.js │ │ ├── index.php │ │ ├── log-view.js │ │ ├── robots.txt │ │ ├── second-tab-warning.js │ │ ├── style.css │ │ ├── timezone.js │ │ └── toggle-dark-mode.js │ ├── session/ │ │ └── .gitkeep │ ├── src/ │ │ ├── Auth/ │ │ │ ├── AuthManager.php │ │ │ └── PasswordGenerator.php │ │ ├── Container/ │ │ │ ├── AioVariables.php │ │ │ ├── Container.php │ │ │ ├── ContainerEnvironmentVariables.php │ │ │ ├── ContainerPort.php │ │ │ ├── ContainerPorts.php │ │ │ ├── ContainerState.php │ │ │ ├── ContainerVolume.php │ │ │ ├── ContainerVolumes.php │ │ │ └── VersionState.php │ │ ├── ContainerDefinitionFetcher.php │ │ ├── Controller/ │ │ │ ├── ConfigurationController.php │ │ │ ├── DockerController.php │ │ │ └── LoginController.php │ │ ├── Cron/ │ │ │ ├── BackupNotification.php │ │ │ ├── CheckBackup.php │ │ │ ├── CheckFreeDiskSpace.php │ │ │ ├── CreateBackup.php │ │ │ ├── OutdatedNotification.php │ │ │ ├── PullContainerImages.php │ │ │ ├── StartAndUpdateContainers.php │ │ │ ├── StartContainers.php │ │ │ ├── StopContainers.php │ │ │ ├── UpdateMastercontainer.php │ │ │ └── UpdateNotification.php │ │ ├── Data/ │ │ │ ├── ConfigurationManager.php │ │ │ ├── DataConst.php │ │ │ ├── InvalidSettingConfigurationException.php │ │ │ └── Setup.php │ │ ├── DependencyInjection.php │ │ ├── Docker/ │ │ │ ├── DockerActionManager.php │ │ │ ├── DockerHubManager.php │ │ │ └── GitHubContainerRegistryManager.php │ │ ├── Middleware/ │ │ │ └── AuthMiddleware.php │ │ └── Twig/ │ │ ├── ClassExtension.php │ │ └── CsrfExtension.php │ ├── templates/ │ │ ├── already-installed.twig │ │ ├── components/ │ │ │ └── container-state.twig │ │ ├── containers.twig │ │ ├── includes/ │ │ │ ├── aio-config.twig │ │ │ ├── aio-version.twig │ │ │ ├── backup-dirs.twig │ │ │ ├── community-containers.twig │ │ │ └── optional-containers.twig │ │ ├── layout.twig │ │ ├── log.twig │ │ ├── login.twig │ │ └── setup.twig │ └── tests/ │ ├── .gitignore │ ├── package.json │ ├── playwright.config.js │ └── tests/ │ ├── initial-setup.spec.js │ └── restore-instance.spec.js ├── readme.md ├── reverse-proxy.md ├── tests/ │ └── QA/ │ ├── 001-initial-setup.md │ ├── 002-new-instance.md │ ├── 003-automatic-login.md │ ├── 004-initial-backup.md │ ├── 010-restore-instance.md │ ├── 020-backup-and-restore.md │ ├── 030-aio-password-change.md │ ├── 040-login-behavior.md │ ├── 050-optional-addons.md │ ├── 055-community-containers.md │ ├── 060-environmental-variables.md │ ├── 070-timezone-change.md │ ├── 080-daily-backup-script.md │ ├── assets/ │ │ └── backup-archive/ │ │ └── readme.md │ └── readme.md └── zizmor.yml
SYMBOL INDEX (279 symbols across 33 files)
FILE: app/composer/composer/ClassLoader.php
class ClassLoader (line 43) | class ClassLoader
method __construct (line 64) | public function __construct($vendorDir = null)
method getPrefixes (line 69) | public function getPrefixes()
method getPrefixesPsr4 (line 78) | public function getPrefixesPsr4()
method getFallbackDirs (line 83) | public function getFallbackDirs()
method getFallbackDirsPsr4 (line 88) | public function getFallbackDirsPsr4()
method getClassMap (line 93) | public function getClassMap()
method addClassMap (line 101) | public function addClassMap(array $classMap)
method add (line 118) | public function add($prefix, $paths, $prepend = false)
method addPsr4 (line 165) | public function addPsr4($prefix, $paths, $prepend = false)
method set (line 210) | public function set($prefix, $paths)
method setPsr4 (line 228) | public function setPsr4($prefix, $paths)
method setUseIncludePath (line 247) | public function setUseIncludePath($useIncludePath)
method getUseIncludePath (line 258) | public function getUseIncludePath()
method setClassMapAuthoritative (line 269) | public function setClassMapAuthoritative($classMapAuthoritative)
method isClassMapAuthoritative (line 279) | public function isClassMapAuthoritative()
method setApcuPrefix (line 289) | public function setApcuPrefix($apcuPrefix)
method getApcuPrefix (line 299) | public function getApcuPrefix()
method register (line 309) | public function register($prepend = false)
method unregister (line 328) | public function unregister()
method loadClass (line 343) | public function loadClass($class)
method findFile (line 361) | public function findFile($class)
method getRegisteredLoaders (line 401) | public static function getRegisteredLoaders()
method findFileWithExtension (line 406) | private function findFileWithExtension($class, $ext)
function includeFile (line 478) | function includeFile($file)
FILE: app/composer/composer/InstalledVersions.php
class InstalledVersions (line 25) | class InstalledVersions
method getInstalledPackages (line 37) | public static function getInstalledPackages()
method getInstalledPackagesByType (line 58) | public static function getInstalledPackagesByType($type)
method isInstalled (line 82) | public static function isInstalled($packageName, $includeDevRequiremen...
method satisfies (line 105) | public static function satisfies(VersionParser $parser, $packageName, ...
method getVersionRanges (line 122) | public static function getVersionRanges($packageName)
method getVersion (line 153) | public static function getVersion($packageName)
method getPrettyVersion (line 174) | public static function getPrettyVersion($packageName)
method getReference (line 195) | public static function getReference($packageName)
method getInstallPath (line 216) | public static function getInstallPath($packageName)
method getRootPackage (line 233) | public static function getRootPackage()
method getRawData (line 247) | public static function getRawData()
method getAllRawData (line 270) | public static function getAllRawData()
method reload (line 293) | public static function reload($data)
method getInstalled (line 303) | private static function getInstalled()
FILE: app/composer/composer/autoload_real.php
class ComposerAutoloaderInitAllInOne (line 5) | class ComposerAutoloaderInitAllInOne
method loadClassLoader (line 9) | public static function loadClassLoader($class)
method getLoader (line 19) | public static function getLoader()
FILE: app/composer/composer/autoload_static.php
class ComposerStaticInitAllInOne (line 7) | class ComposerStaticInitAllInOne
method getInitializer (line 28) | public static function getInitializer(ClassLoader $loader)
FILE: app/lib/Settings/Admin.php
class Admin (line 33) | class Admin implements ISettings {
method __construct (line 41) | public function __construct(
method getForm (line 54) | public function getForm(): TemplateResponse {
method getSection (line 69) | public function getSection(): string {
method getPriority (line 80) | public function getPriority(): int {
FILE: php/public/containers-form-submit.js
function checkForOptionContainerChanges (line 50) | function checkForOptionContainerChanges() {
function checkForCommunityContainerChanges (line 88) | function checkForCommunityContainerChanges() {
function handleTalkVisibility (line 111) | function handleTalkVisibility() {
function handleDockerSocketProxyWarning (line 122) | function handleDockerSocketProxyWarning() {
function handleHarpWarning (line 131) | function handleHarpWarning() {
FILE: php/public/forms.js
function showPassword (line 3) | function showPassword(id) {
function showError (line 15) | function showError(message) {
function handleEvent (line 28) | function handleEvent(e) {
function enableSpinner (line 47) | function enableSpinner() {
function disableSpinner (line 51) | function disableSpinner() {
function initForm (line 55) | function initForm(form) {
function initForms (line 75) | function initForms() {
FILE: php/public/log-view.js
class LogViewer (line 1) | class LogViewer {
method constructor (line 17) | constructor() {
method startAutoloading (line 30) | startAutoloading() {
method stopAutoloading (line 42) | stopAutoloading() {
method isAutoloadingEnabled (line 48) | isAutoloadingEnabled() {
method getUrl (line 52) | getUrl() {
method debug (line 56) | debug(...args) {
method loadAndAppendLogData (line 63) | loadAndAppendLogData() {
method scrollToBottom (line 98) | scrollToBottom() {
method initAutoloadingControls (line 102) | initAutoloadingControls() {
FILE: php/public/toggle-dark-mode.js
function toggleTheme (line 2) | function toggleTheme() {
function setThemeToDOM (line 12) | function setThemeToDOM(value) {
function getSavedTheme (line 18) | function getSavedTheme() {
function setThemeIcon (line 23) | function setThemeIcon(theme) {
FILE: php/src/Auth/AuthManager.php
class AuthManager (line 10) | readonly class AuthManager {
method __construct (line 13) | public function __construct(
method CheckCredentials (line 18) | public function CheckCredentials(string $password) : bool {
method CheckToken (line 22) | public function CheckToken(string $token) : bool {
method SetAuthState (line 26) | public function SetAuthState(bool $isLoggedIn) : void {
method IsAuthenticated (line 44) | public function IsAuthenticated() : bool {
FILE: php/src/Auth/PasswordGenerator.php
class PasswordGenerator (line 8) | class PasswordGenerator
method GeneratePassword (line 7789) | public function GeneratePassword(int $length) : string {
FILE: php/src/Container/AioVariables.php
class AioVariables (line 6) | class AioVariables {
method AddVariable (line 10) | public function AddVariable(string $variable) : void {
method GetVariables (line 17) | public function GetVariables() : array {
FILE: php/src/Container/Container.php
class Container (line 11) | readonly class Container {
method __construct (line 12) | public function __construct(
method GetUiSecret (line 46) | public function GetUiSecret() : string {
method GetRunningState (line 53) | public function GetRunningState() : ContainerState {
method GetRestartingState (line 60) | public function GetRestartingState() : ContainerState {
method GetUpdateState (line 64) | public function GetUpdateState() : VersionState {
method GetStartingState (line 68) | public function GetStartingState() : ContainerState {
FILE: php/src/Container/ContainerEnvironmentVariables.php
class ContainerEnvironmentVariables (line 6) | class ContainerEnvironmentVariables {
method AddVariable (line 10) | public function AddVariable(string $variable) : void {
method GetVariables (line 17) | public function GetVariables() : array {
FILE: php/src/Container/ContainerPort.php
class ContainerPort (line 6) | class ContainerPort {
method __construct (line 7) | public function __construct(
FILE: php/src/Container/ContainerPorts.php
class ContainerPorts (line 6) | class ContainerPorts {
method AddPort (line 10) | public function AddPort(ContainerPort $port) : void {
method GetPorts (line 17) | public function GetPorts() : array {
FILE: php/src/Container/ContainerVolume.php
class ContainerVolume (line 6) | class ContainerVolume {
method __construct (line 7) | public function __construct(
FILE: php/src/Container/ContainerVolumes.php
class ContainerVolumes (line 6) | class ContainerVolumes {
method AddVolume (line 10) | public function AddVolume(ContainerVolume $volume) : void {
method GetVolumes (line 17) | public function GetVolumes() : array {
FILE: php/src/ContainerDefinitionFetcher.php
class ContainerDefinitionFetcher (line 17) | readonly class ContainerDefinitionFetcher {
method __construct (line 18) | public function __construct(
method GetContainerById (line 24) | public function GetContainerById(string $id): Container
method GetDefinition (line 40) | private function GetDefinition(): array
method FetchDefinition (line 362) | public function FetchDefinition(): array
FILE: php/src/Controller/ConfigurationController.php
class ConfigurationController (line 13) | readonly class ConfigurationController {
method __construct (line 14) | public function __construct(
method SetConfig (line 19) | public function SetConfig(Request $request, Response $response, array ...
FILE: php/src/Controller/DockerController.php
class DockerController (line 15) | readonly class DockerController {
method __construct (line 18) | public function __construct(
method PerformRecursiveContainerStart (line 25) | private function PerformRecursiveContainerStart(string $id, bool $pull...
method PerformRecursiveImagePull (line 48) | private function PerformRecursiveImagePull(string $id) : void {
method PullAllContainerImages (line 59) | public function PullAllContainerImages(): void {
method GetLogs (line 66) | public function GetLogs(Request $request, Response $response, array $a...
method StartBackupContainerBackup (line 89) | public function StartBackupContainerBackup(Request $request, Response ...
method startBackup (line 102) | public function startBackup(bool $forceStopNextcloud = false, ?\Closur...
method StartBackupContainerCheck (line 112) | public function StartBackupContainerCheck(Request $request, Response $...
method StartBackupContainerList (line 124) | public function StartBackupContainerList(Request $request, Response $r...
method checkBackup (line 136) | public function checkBackup(?\Closure $addToStreamingResponseBody = nu...
method listBackup (line 143) | private function listBackup(?\Closure $addToStreamingResponseBody = nu...
method StartBackupContainerRestore (line 150) | public function StartBackupContainerRestore(Request $request, Response...
method StartBackupContainerCheckRepair (line 173) | public function StartBackupContainerCheckRepair(Request $request, Resp...
method StartBackupContainerTest (line 191) | public function StartBackupContainerTest(Request $request, Response $r...
method StartContainer (line 212) | public function StartContainer(Request $request, Response $response, a...
method startTopContainer (line 260) | public function startTopContainer(bool $pullImage, ?\Closure $addToStr...
method StartWatchtowerContainer (line 271) | public function StartWatchtowerContainer(Request $request, Response $r...
method startWatchtower (line 283) | public function startWatchtower(?\Closure $addToStreamingResponseBody ...
method PerformRecursiveContainerStop (line 289) | private function PerformRecursiveContainerStop(string $id, bool $force...
method StopContainer (line 316) | public function StopContainer(Request $request, Response $response, ar...
method stopTopContainer (line 331) | public function stopTopContainer() : void {
method StartDomaincheckContainer (line 336) | public function StartDomaincheckContainer() : void
method StopDomaincheckContainer (line 372) | private function StopDomaincheckContainer() : void
method getStreamingResponseHtmlStart (line 378) | private function getStreamingResponseHtmlStart() : string {
method startStreamingResponse (line 401) | private function startStreamingResponse(Response $response) : Response {
method getAddToStreamingResponseBody (line 417) | private function getAddToStreamingResponseBody(Response $nonbufResp) :...
method finalizeStreamingResponse (line 428) | private function finalizeStreamingResponse(Response $nonbufResp) : void {
method getStreamingResponseHtmlEnd (line 432) | private function getStreamingResponseHtmlEnd() : string {
method getTimestampForDockerLogsApiSince (line 436) | private function getTimestampForDockerLogsApiSince(string $input) : st...
FILE: php/src/Controller/LoginController.php
class LoginController (line 13) | readonly class LoginController {
method __construct (line 14) | public function __construct(
method TryLogin (line 20) | public function TryLogin(Request $request, Response $response, array $...
method GetTryLogin (line 35) | public function GetTryLogin(Request $request, Response $response, arra...
method Logout (line 45) | public function Logout(Request $request, Response $response, array $ar...
FILE: php/src/Data/ConfigurationManager.php
class ConfigurationManager (line 9) | class ConfigurationManager
method getApacheMaxSize (line 227) | public function getApacheMaxSize() : int {
method getConfig (line 292) | private function getConfig() : array
method get (line 303) | private function get(string $key, mixed $fallbackValue = null) : mixed {
method set (line 307) | private function set(string $key, mixed $value) : void {
method startTransaction (line 320) | public function startTransaction() : void {
method commitTransaction (line 328) | public function commitTransaction() : void {
method getAndGenerateSecret (line 336) | public function getAndGenerateSecret(string $secretId) : string {
method getRegisteredSecret (line 354) | public function getRegisteredSecret(string $secretId) : string {
method registerSecret (line 361) | public function registerSecret(string $secretId) : void {
method doubleSafeBackupSecret (line 365) | private function doubleSafeBackupSecret(string $borgBackupPassword) : ...
method hasBackupRunOnce (line 369) | public function hasBackupRunOnce() : bool {
method getLastBackupTime (line 377) | public function getLastBackupTime() : string {
method getBackupTimes (line 402) | public function getBackupTimes() : array {
method getAioVersion (line 424) | public function getAioVersion() : string {
method isx64Platform (line 432) | private function isx64Platform() : bool {
method setDomain (line 445) | public function setDomain(string $domain, bool $skipDomainValidation) ...
method getBaseDN (line 559) | public function getBaseDN() : string {
method setBorgLocationVars (line 570) | public function setBorgLocationVars(string $location, string $repo) : ...
method validateBorgLocationVars (line 578) | private function validateBorgLocationVars(string $location, string $re...
method validateBorgRemoteRepo (line 608) | private function validateBorgRemoteRepo(string $repo) : void {
method deleteBorgBackupLocationItems (line 619) | public function deleteBorgBackupLocationItems() : void {
method setBorgRestoreLocationVarsAndPassword (line 637) | public function setBorgRestoreLocationVarsAndPassword(string $location...
method changeMasterPassword (line 655) | public function changeMasterPassword(string $currentPassword, string $...
method writeConfig (line 683) | private function writeConfig() : void {
method getEnvironmentalVariableOrConfig (line 701) | private function getEnvironmentalVariableOrConfig(string $envVariableN...
method getBorgPublicKey (line 720) | public function getBorgPublicKey() : string {
method getCollaboraSeccompPolicy (line 728) | public function getCollaboraSeccompPolicy() : string {
method setDailyBackupTime (line 739) | public function setDailyBackupTime(string $time, bool $enableAutomatic...
method getDailyBackupTime (line 761) | public function getDailyBackupTime() : string {
method areAutomaticUpdatesEnabled (line 770) | public function areAutomaticUpdatesEnabled() : bool {
method deleteDailyBackupTime (line 783) | public function deleteDailyBackupTime() : void {
method setAdditionalBackupDirectories (line 792) | public function setAdditionalBackupDirectories(string $additionalBacku...
method getAdditionalBackupDirectoriesString (line 813) | public function getAdditionalBackupDirectoriesString() : string {
method getAdditionalBackupDirectoriesArray (line 820) | public function getAdditionalBackupDirectoriesArray() : array {
method isDailyBackupRunning (line 827) | public function isDailyBackupRunning() : bool {
method validateTimezone (line 834) | private function validateTimezone(string $timezone) : void {
method deleteTimezone (line 847) | public function deleteTimezone() : void {
method shouldDomainValidationBeSkipped (line 851) | public function shouldDomainValidationBeSkipped(bool $skipDomainValida...
method getApacheAdditionalNetwork (line 858) | public function getApacheAdditionalNetwork() : string {
method getNextcloudStartupApps (line 866) | public function getNextcloudStartupApps() : string {
method validateCollaboraDictionaries (line 877) | private function validateCollaboraDictionaries(string $CollaboraDictio...
method deleteCollaboraDictionaries (line 890) | public function deleteCollaboraDictionaries() : void {
method validateCollaboraAdditionalOptions (line 897) | private function validateCollaboraAdditionalOptions(string $additional...
method isCollaboraSubscriptionEnabled (line 907) | public function isCollaboraSubscriptionEnabled() : bool {
method deleteAdditionalCollaboraOptions (line 914) | public function deleteAdditionalCollaboraOptions() : void {
method listAvailableCommunityContainers (line 918) | public function listAvailableCommunityContainers() : array {
method camelize (line 953) | private function camelize(string $input, string $delimiter = '_') : st...
method setAioVariables (line 964) | public function setAioVariables(array $input) : void {
method replaceEnvPlaceholders (line 993) | public function replaceEnvPlaceholders(string $envValue): string {
method getPlaceholderValue (line 1016) | private function getPlaceholderValue(string $placeholder) : string {
method booleanize (line 1069) | private function booleanize(mixed $value) : bool {
FILE: php/src/Data/DataConst.php
class DataConst (line 6) | class DataConst {
method GetDataDirectory (line 7) | public static function GetDataDirectory() : string {
method GetSessionDirectory (line 15) | public static function GetSessionDirectory() : string {
method GetConfigFile (line 23) | public static function GetConfigFile() : string {
method GetBackupPublicKey (line 27) | public static function GetBackupPublicKey() : string {
method GetBackupSecretFile (line 31) | public static function GetBackupSecretFile() : string {
method GetDailyBackupTimeFile (line 35) | public static function GetDailyBackupTimeFile() : string {
method GetAdditionalBackupDirectoriesFile (line 39) | public static function GetAdditionalBackupDirectoriesFile() : string {
method GetDailyBackupBlockFile (line 43) | public static function GetDailyBackupBlockFile() : string {
method GetBackupKeyFile (line 47) | public static function GetBackupKeyFile() : string {
method GetBackupArchivesList (line 51) | public static function GetBackupArchivesList() : string {
method GetSessionDateFile (line 55) | public static function GetSessionDateFile() : string {
method GetCommunityContainersDirectory (line 59) | public static function GetCommunityContainersDirectory() : string {
method GetCollaboraSeccompProfilePath (line 63) | public static function GetCollaboraSeccompProfilePath() : string {
method GetContainersDefinitionPath (line 67) | public static function GetContainersDefinitionPath() : string {
method GetAioVersionFile (line 71) | public static function GetAioVersionFile() : string {
FILE: php/src/Data/InvalidSettingConfigurationException.php
class InvalidSettingConfigurationException (line 6) | class InvalidSettingConfigurationException extends \Exception {}
FILE: php/src/Data/Setup.php
class Setup (line 8) | readonly class Setup {
method __construct (line 9) | public function __construct(
method Setup (line 15) | public function Setup() : string {
method CanBeInstalled (line 25) | public function CanBeInstalled() : bool {
FILE: php/src/DependencyInjection.php
class DependencyInjection (line 10) | class DependencyInjection
method GetContainer (line 12) | public static function GetContainer() : Container {
FILE: php/src/Docker/DockerActionManager.php
class DockerActionManager (line 16) | readonly class DockerActionManager {
method __construct (line 20) | public function __construct(
method BuildApiUrl (line 29) | private function BuildApiUrl(string $url): string {
method BuildImageName (line 39) | private function BuildImageName(Container $container): string {
method GetContainerRunningState (line 47) | public function GetContainerRunningState(Container $container): Contai...
method GetContainerRestartingState (line 67) | public function GetContainerRestartingState(Container $container): Con...
method GetContainerUpdateState (line 87) | public function GetContainerUpdateState(Container $container): Version...
method GetContainerStartingState (line 110) | public function GetContainerStartingState(Container $container): Conta...
method DeleteContainer (line 137) | public function DeleteContainer(Container $container): void {
method GetLogs (line 148) | public function GetLogs(string $id, string $since = ''): string {
method StartContainer (line 170) | public function StartContainer(Container $container, ?\Closure $addToS...
method CreateVolumes (line 182) | public function CreateVolumes(Container $container): void {
method CreateContainer (line 208) | public function CreateContainer(Container $container): void {
method isRegistryReachable (line 465) | public function isRegistryReachable(Container $container): bool {
method PullImage (line 480) | public function PullImage(Container $container, bool $pullImage = true...
method isContainerUpdateAvailable (line 538) | private function isContainerUpdateAvailable(string $id): string {
method isAnyUpdateAvailable (line 551) | public function isAnyUpdateAvailable(): bool {
method getBackupVolumes (line 565) | private function getBackupVolumes(string $id): string {
method getAllBackupVolumes (line 578) | private function getAllBackupVolumes(): array {
method GetNextcloudExecCommands (line 584) | private function GetNextcloudExecCommands(string $id): string {
method GetAllNextcloudExecCommands (line 597) | private function GetAllNextcloudExecCommands(): string {
method GetRepoDigestsOfContainer (line 602) | private function GetRepoDigestsOfContainer(string $containerName): ?ar...
method GetCurrentImageName (line 643) | private function GetCurrentImageName(): string {
method GetCurrentChannel (line 670) | public function GetCurrentChannel(): string {
method IsMastercontainerUpdateAvailable (line 697) | public function IsMastercontainerUpdateAvailable(): bool {
method sendNotification (line 720) | public function sendNotification(Container $container, string $subject...
method DisconnectContainerFromBridgeNetwork (line 766) | private function DisconnectContainerFromBridgeNetwork(string $id): void {
method ConnectContainerIdToNetwork (line 786) | private function ConnectContainerIdToNetwork(string $id, string $inter...
method ConnectMasterContainerToNetwork (line 838) | public function ConnectMasterContainerToNetwork(): void {
method ConnectContainerToNetwork (line 844) | public function ConnectContainerToNetwork(Container $container): void {
method StopContainer (line 860) | public function StopContainer(Container $container, bool $forceStopCon...
method GetBackupcontainerExitCode (line 876) | public function GetBackupcontainerExitCode(): int {
method GetDatabasecontainerExitCode (line 898) | public function GetDatabasecontainerExitCode(): int {
method isLoginAllowed (line 920) | public function isLoginAllowed(): bool {
method isBackupContainerRunning (line 929) | public function isBackupContainerRunning(): bool {
method GetCreatedTimeOfNextcloudImage (line 938) | private function GetCreatedTimeOfNextcloudImage(string $imageName): ?s...
method GetAndGenerateSecretWrapper (line 955) | public function GetAndGenerateSecretWrapper(string $secretId): string {
method isNextcloudImageOutdated (line 959) | public function isNextcloudImageOutdated(): bool {
method GetLatestDigestOfTag (line 978) | public function GetLatestDigestOfTag(string $imageName, string $tag): ...
FILE: php/src/Docker/DockerHubManager.php
class DockerHubManager (line 10) | readonly class DockerHubManager {
method __construct (line 13) | public function __construct(
method GetLatestDigestOfTag (line 18) | public function GetLatestDigestOfTag(string $name, string $tag) : ?str...
FILE: php/src/Docker/GitHubContainerRegistryManager.php
class GitHubContainerRegistryManager (line 8) | readonly class GitHubContainerRegistryManager
method __construct (line 12) | public function __construct()
method GetLatestDigestOfTag (line 17) | public function GetLatestDigestOfTag(string $name, string $tag): ?string
FILE: php/src/Middleware/AuthMiddleware.php
class AuthMiddleware (line 12) | readonly class AuthMiddleware {
method __construct (line 13) | public function __construct(
method __invoke (line 18) | public function __invoke(ServerRequestInterface $request, RequestHandl...
FILE: php/src/Twig/ClassExtension.php
class ClassExtension (line 9) | class ClassExtension extends TwigExtension
method getFunctions (line 11) | #[\Override]
method getClassName (line 19) | public function getClassName(mixed $object) : ?string
FILE: php/src/Twig/CsrfExtension.php
class CsrfExtension (line 10) | class CsrfExtension extends AbstractExtension implements GlobalsInterface {
method __construct (line 11) | public function __construct(
method getGlobals (line 16) | #[\Override]
Condensed preview — 361 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,445K chars).
[
{
"path": ".gitattributes",
"chars": 12,
"preview": "* text=auto\n"
},
{
"path": ".github/ISSUE_TEMPLATE/Bug_report.md",
"chars": 1492,
"preview": "---\nname: 🐛 Bug report - no questions and no support!\nabout: Help us improving by reporting a bug - this category is not"
},
{
"path": ".github/ISSUE_TEMPLATE/Feature_request.md",
"chars": 795,
"preview": "---\nname: 📖 Existing feature/documentation enhancement\nabout: Suggest an enhancement of an existing feature/documentatio"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 788,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: 📘 Documentation on Nextcloud AIO\n url: https://github.com/ne"
},
{
"path": ".github/dependabot.yml",
"chars": 1655,
"preview": "version: 2\nupdates:\n- package-ecosystem: \"github-actions\"\n directory: \".github/workflows\"\n schedule:\n interval: \"da"
},
{
"path": ".github/pull_request_template.md",
"chars": 361,
"preview": "<!--\n - 🚨 SECURITY INFO\n -\n - Before sending a pull request that fixes a security issue please report it via our Hack"
},
{
"path": ".github/release.yml",
"chars": 315,
"preview": "changelog:\n categories:\n - title: 🏕 New features and other improvements\n labels:\n - enhancement\n - ti"
},
{
"path": ".github/workflows/codespell.yml",
"chars": 467,
"preview": "name: 'Codespell'\n\non:\n pull_request:\n push:\n branches:\n - main\n\njobs:\n codespell:\n name: Check spelling\n "
},
{
"path": ".github/workflows/collabora.yml",
"chars": 995,
"preview": "name: collabora-update\n\non:\n workflow_dispatch:\n schedule:\n - cron: '00 12 * * *'\n\njobs:\n collabora-update:\n nam"
},
{
"path": ".github/workflows/community-containers.yml",
"chars": 1201,
"preview": "name: Validate community containers\n\non:\n pull_request:\n paths:\n - 'community-containers/**'\n push:\n branch"
},
{
"path": ".github/workflows/dependency-updates.yml",
"chars": 2386,
"preview": "name: dependency-updates\n\non:\n workflow_dispatch:\n schedule:\n - cron: '00 12 * * *'\n\njobs:\n dependency_updates:\n "
},
{
"path": ".github/workflows/docker-lint.yml",
"chars": 1453,
"preview": "name: Docker Lint\n\non:\n pull_request:\n paths:\n - 'Containers/**'\n push:\n branches:\n - main\n paths:\n"
},
{
"path": ".github/workflows/fail-on-prerelease.yml",
"chars": 1638,
"preview": "name: Block if prerelease is present\n\non:\n pull_request:\n\npermissions:\n contents: read\n\njobs:\n check-latest-release:\n"
},
{
"path": ".github/workflows/helm-release.yml",
"chars": 1392,
"preview": "\nname: Helm Chart Releaser\n\non:\n push:\n branches:\n - main\n paths:\n - 'nextcloud-aio-helm-chart/**'\n\njob"
},
{
"path": ".github/workflows/imaginary-update.yml",
"chars": 1080,
"preview": "name: imaginary-update\n\non:\n workflow_dispatch:\n schedule:\n - cron: '00 12 * * *'\n\njobs:\n run_update:\n name: upd"
},
{
"path": ".github/workflows/json-validator.yml",
"chars": 1159,
"preview": "name: Json Validator\n\non:\n pull_request:\n paths:\n - '**.json'\n push:\n branches:\n - main\n paths:\n "
},
{
"path": ".github/workflows/lint-helm.yml",
"chars": 536,
"preview": "name: Lint Helm Charts\n\non:\n workflow_dispatch:\n pull_request:\n paths:\n - 'nextcloud-aio-helm-chart/**'\n\njobs:"
},
{
"path": ".github/workflows/lint-php.yml",
"chars": 1560,
"preview": "# This workflow is provided via the organization template repository\n#\n# https://github.com/nextcloud/.github\n# https://"
},
{
"path": ".github/workflows/lint-yaml.yml",
"chars": 1130,
"preview": "# This workflow is provided via the organization template repository\n#\n# https://github.com/nextcloud/.github\n# https://"
},
{
"path": ".github/workflows/lock-threads.yml",
"chars": 340,
"preview": "name: 'Lock Threads'\n\non:\n schedule:\n - cron: '0 0 * * *'\n\npermissions:\n issues: write\n\nconcurrency:\n group: lock\n"
},
{
"path": ".github/workflows/nextcloud-update.yml",
"chars": 3372,
"preview": "# Inspired by https://github.com/nextcloud/docker/blob/master/.github/workflows/update-sh.yml\nname: nextcloud-update\n\non"
},
{
"path": ".github/workflows/php-deprecation-detector.yml",
"chars": 827,
"preview": "name: PHP Deprecation Detector\n# See https://github.com/wapmorgan/PhpDeprecationDetector\n\non:\n pull_request:\n paths:"
},
{
"path": ".github/workflows/playwright-on-push.yml",
"chars": 4303,
"preview": "name: Playwright Tests on push\n\non:\n pull_request:\n paths:\n - 'php/**'\n push:\n branches:\n - main\n p"
},
{
"path": ".github/workflows/playwright-on-workflow-dispatch.yml",
"chars": 3461,
"preview": "name: Playwright Tests\n\non:\n workflow_dispatch:\n\nenv:\n BASE_URL: https://localhost:8080\n\njobs:\n test:\n timeout-min"
},
{
"path": ".github/workflows/psalm-update-baseline.yml",
"chars": 1437,
"preview": "name: Update Psalm baseline\n\non:\n workflow_dispatch:\n schedule:\n - cron: '5 4 * * *'\n\njobs:\n update-psalm-baseline"
},
{
"path": ".github/workflows/psalm.yml",
"chars": 1294,
"preview": "# This workflow is provided via the organization template repository\n#\n# https://github.com/nextcloud/.github\n# https://"
},
{
"path": ".github/workflows/shellcheck.yml",
"chars": 493,
"preview": "name: Shellcheck\n\non:\n pull_request:\n paths:\n - '**.sh'\n push:\n branches:\n - main\n paths:\n - '"
},
{
"path": ".github/workflows/talk.yml",
"chars": 2101,
"preview": "name: talk-update\n\non:\n workflow_dispatch:\n schedule:\n - cron: '00 12 * * *'\n\njobs:\n talk-update:\n name: update "
},
{
"path": ".github/workflows/twig-lint.yml",
"chars": 790,
"preview": "name: Twig Lint\n\non:\n pull_request:\n paths:\n - '**.twig'\n push:\n branches:\n - main\n paths:\n - "
},
{
"path": ".github/workflows/update-copyright.yml",
"chars": 222,
"preview": "name: Update Copyright\n\non:\n workflow_dispatch:\n\njobs:\n update-copyright:\n name: update copyright\n runs-on: ubun"
},
{
"path": ".github/workflows/update-helm.yml",
"chars": 1616,
"preview": "name: Update Helm Chart\n\non:\n workflow_dispatch:\n schedule:\n - cron: '00 12 * * *'\n\njobs:\n update-helm:\n name: u"
},
{
"path": ".github/workflows/update-yaml.yml",
"chars": 922,
"preview": "name: Update Yaml files\r\n\r\non:\r\n workflow_dispatch:\r\n schedule:\r\n - cron: '00 12 * * *'\r\n\r\njobs:\r\n update-yaml:\r\n "
},
{
"path": ".github/workflows/watchtower-update.yml",
"chars": 1440,
"preview": "name: watchtower-update\n\non:\n workflow_dispatch:\n schedule:\n - cron: '00 12 * * *'\n\njobs:\n watchtower-update:\n n"
},
{
"path": ".gitignore",
"chars": 244,
"preview": ".DS_Store\n.idea/\n*.iml\n\n/php/data/*\n/php/session/*\n!/php/data/.gitkeep\n!/php/session/.gitkeep\n/php/vendor\n\n/manual-insta"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 1063,
"preview": "<!--\n - SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-l"
},
{
"path": "Containers/alpine/Dockerfile",
"chars": 142,
"preview": "# syntax=docker/dockerfile:latest\nFROM alpine:3.23.3\n\nRUN set -ex; \\\n apk upgrade --no-cache -a\n\nLABEL org.label-sche"
},
{
"path": "Containers/apache/Caddyfile",
"chars": 1756,
"preview": "{\n auto_https disable_redirects\n\n storage file_system {\n root /mnt/data/caddy\n }\n\n servers {\n "
},
{
"path": "Containers/apache/Dockerfile",
"chars": 3662,
"preview": "# syntax=docker/dockerfile:latest\nFROM caddy:2.11.2-alpine AS caddy\n\n# From https://github.com/docker-library/httpd/blob"
},
{
"path": "Containers/apache/healthcheck.sh",
"chars": 124,
"preview": "#!/bin/bash\n\nnc -z \"$NEXTCLOUD_HOST\" 9000 || exit 0\nnc -z 127.0.0.1 8000 || exit 1\nnc -z 127.0.0.1 \"$APACHE_PORT\" || exi"
},
{
"path": "Containers/apache/nextcloud.conf",
"chars": 1737,
"preview": "Listen 8000\n<VirtualHost *:8000>\n ServerName localhost\n\n # Add error log\n CustomLog /proc/self/fd/1 proxy\n L"
},
{
"path": "Containers/apache/start.sh",
"chars": 2165,
"preview": "#!/bin/bash\n\nif [ -z \"$NC_DOMAIN\" ]; then\n echo \"NC_DOMAIN and NEXTCLOUD_HOST need to be provided. Exiting!\"\n exit"
},
{
"path": "Containers/apache/supervisord.conf",
"chars": 661,
"preview": "[supervisord]\r\nnodaemon=true\r\nnodaemon=true\r\nlogfile=/var/log/supervisord/supervisord.log\r\npidfile=/var/run/supervisord/"
},
{
"path": "Containers/borgbackup/Dockerfile",
"chars": 601,
"preview": "# syntax=docker/dockerfile:latest\nFROM alpine:3.23.3\n\nRUN set -ex; \\\n \\\n apk upgrade --no-cache -a; \\\n apk add "
},
{
"path": "Containers/borgbackup/backupscript.sh",
"chars": 32372,
"preview": "#!/bin/bash\n\n# Functions\nget_start_time(){\n START_TIME=$(date +%s)\n CURRENT_DATE=$(date --date @\"$START_TIME\" +\"%Y"
},
{
"path": "Containers/borgbackup/borg_excludes",
"chars": 734,
"preview": "# These patterns need to be kept in sync with rsync and find excludes in backupscript.sh,\n# which use a different syntax"
},
{
"path": "Containers/borgbackup/start.sh",
"chars": 2452,
"preview": "#!/bin/bash\n\n# Variables\nexport MOUNT_DIR=\"/mnt/borgbackup\"\nexport BORG_BACKUP_DIRECTORY=\"$MOUNT_DIR/borg\" # necessary "
},
{
"path": "Containers/clamav/Dockerfile",
"chars": 2109,
"preview": "# syntax=docker/dockerfile:latest\nFROM alpine:3.23.3\n\nRUN set -ex; \\\n apk upgrade --no-cache -a; \\\n apk add --no-c"
},
{
"path": "Containers/clamav/healthcheck.sh",
"chars": 151,
"preview": "#!/bin/bash\n\nif [ \"$(echo \"PING\" | nc 127.0.0.1 3310)\" != \"PONG\" ]; then\n\techo \"ERROR: Unable to contact server\"\n\texit 1"
},
{
"path": "Containers/clamav/start.sh",
"chars": 116,
"preview": "#!/bin/bash\n\n# Print out clamav version for compliance reasons\nclamscan --version\n\necho \"Clamav started\"\n\nexec \"$@\"\n"
},
{
"path": "Containers/clamav/supervisord.conf",
"chars": 871,
"preview": "[supervisord]\nnodaemon=true\nnodaemon=true\nlogfile=/var/log/supervisord/supervisord.log\npidfile=/var/run/supervisord/supe"
},
{
"path": "Containers/collabora/Dockerfile",
"chars": 487,
"preview": "# syntax=docker/dockerfile:latest\n# From a file located probably somewhere here: https://github.com/CollaboraOnline/onli"
},
{
"path": "Containers/collabora/healthcheck.sh",
"chars": 222,
"preview": "#!/bin/bash\n\n# Unfortunately, no curl and no nc is installed in the container \n# and packages can also not be added as t"
},
{
"path": "Containers/collabora-online/Dockerfile",
"chars": 473,
"preview": "# syntax=docker/dockerfile:latest\n# From https://gitlab.collabora.com/collabora-online/docker\n# hadolint ignore=DL3007\nF"
},
{
"path": "Containers/collabora-online/healthcheck.sh",
"chars": 222,
"preview": "#!/bin/bash\n\n# Unfortunately, no curl and no nc is installed in the container \n# and packages can also not be added as t"
},
{
"path": "Containers/docker-socket-proxy/Dockerfile",
"chars": 557,
"preview": "# syntax=docker/dockerfile:latest\nFROM haproxy:3.3.6-alpine\n\n# hadolint ignore=DL3002\nUSER root\nENV NEXTCLOUD_HOST=nextc"
},
{
"path": "Containers/docker-socket-proxy/haproxy.cfg",
"chars": 4062,
"preview": "# Inspiration: https://github.com/Tecnativa/docker-socket-proxy/blob/master/haproxy.cfg\n\nglobal\n maxconn 10\n\ndefaults"
},
{
"path": "Containers/docker-socket-proxy/healthcheck.sh",
"chars": 83,
"preview": "#!/bin/bash\n\nnc -z \"$NEXTCLOUD_HOST\" 9001 || exit 0\nnc -z 127.0.0.1 2375 || exit 1\n"
},
{
"path": "Containers/docker-socket-proxy/start.sh",
"chars": 793,
"preview": "#!/bin/sh\n\n# Only start container if nextcloud is accessible\nwhile ! nc -z \"$NEXTCLOUD_HOST\" 9001; do\n echo \"Waiting "
},
{
"path": "Containers/domaincheck/Dockerfile",
"chars": 700,
"preview": "# syntax=docker/dockerfile:latest\nFROM alpine:3.23.3\nRUN set -ex; \\\n apk upgrade --no-cache -a; \\\n apk add --no-ca"
},
{
"path": "Containers/domaincheck/lighttpd.conf",
"chars": 472,
"preview": "server.document-root = \"/var/www/domaincheck/\" \n\nserver.port = env.APACHE_PORT\n\nserver.username = \"www-data\" \nserver.gro"
},
{
"path": "Containers/domaincheck/start.sh",
"chars": 482,
"preview": "#!/bin/bash\n\nif [ -z \"$INSTANCE_ID\" ]; then\n echo \"You need to provide an instance id.\"\n exit 1\nfi\n\necho \"$INSTANC"
},
{
"path": "Containers/fulltextsearch/Dockerfile",
"chars": 759,
"preview": "# syntax=docker/dockerfile:latest\r\n# Probably from here https://github.com/elastic/elasticsearch/blob/main/distribution/"
},
{
"path": "Containers/fulltextsearch/healthcheck.sh",
"chars": 44,
"preview": "#!/bin/bash\n\nnc -z 127.0.0.1 9200 || exit 1\n"
},
{
"path": "Containers/imaginary/Dockerfile",
"chars": 1152,
"preview": "# syntax=docker/dockerfile:latest\r\nFROM golang:1.26.1-alpine3.23 AS go\r\n\r\nENV IMAGINARY_HASH=6a274b488759a896aff02f52afe"
},
{
"path": "Containers/imaginary/healthcheck.sh",
"chars": 47,
"preview": "#!/bin/bash\n\nnc -z 127.0.0.1 \"$PORT\" || exit 1\n"
},
{
"path": "Containers/imaginary/start.sh",
"chars": 235,
"preview": "#!/bin/bash\n\necho \"Imaginary has started\"\nif [ -z \"$IMAGINARY_SECRET\" ]; then\n imaginary -return-size -max-allowed-re"
},
{
"path": "Containers/mastercontainer/Dockerfile",
"chars": 3431,
"preview": "# syntax=docker/dockerfile:latest\n# Docker CLI is a requirement\nFROM docker:29.3.0-cli AS docker\n\nARG CADDY_REMOTE_HOST_"
},
{
"path": "Containers/mastercontainer/README.md",
"chars": 3365,
"preview": "# Nextcloud All-in-One `mastercontainer`\n\nThis folder contains the OCI/Docker container definition, along with associate"
},
{
"path": "Containers/mastercontainer/acme.Caddyfile",
"chars": 1000,
"preview": "{\n\tadmin off\n\n\t# auto_https will create redirects for https://{host}:8443 instead of https://{host}\n\t# https redirects a"
},
{
"path": "Containers/mastercontainer/backup-time-file-watcher.sh",
"chars": 766,
"preview": "#!/bin/bash\n\nrestart_process() {\n echo \"Restarting cron.sh because daily backup time was set, changed or unset.\"\n "
},
{
"path": "Containers/mastercontainer/cron.sh",
"chars": 2827,
"preview": "#!/bin/bash\n\nwhile true; do\n if [ -f \"/mnt/docker-aio-config/data/daily_backup_time\" ]; then\n set -x\n B"
},
{
"path": "Containers/mastercontainer/daily-backup.sh",
"chars": 5804,
"preview": "#!/bin/bash\n\necho \"Daily backup script has started\"\n\n# Check if initial configuration has been done, otherwise this scri"
},
{
"path": "Containers/mastercontainer/healthcheck.sh",
"chars": 255,
"preview": "#!/bin/bash\n\nif [ -f \"/mnt/docker-aio-config/data/configuration.json\" ]; then\n nc -z 127.0.0.1 80 || exit 1\n nc -z"
},
{
"path": "Containers/mastercontainer/internal.Caddyfile",
"chars": 687,
"preview": "{\n\tadmin off\n\n\tstorage file_system {\n\t\troot /mnt/docker-aio-config/caddy/\n\t}\n\n\tlog {\n\t\tlevel ERROR\n\t\t# We need to exclud"
},
{
"path": "Containers/mastercontainer/session-deduplicator.sh",
"chars": 656,
"preview": "#!/bin/bash\n\ndeduplicate_sessions() {\n echo \"Deleting duplicate sessions\"\n find \"/mnt/docker-aio-config/session/\" "
},
{
"path": "Containers/mastercontainer/start.sh",
"chars": 19719,
"preview": "#!/bin/bash\n\n# Function to show text in green\nprint_green() {\n local TEXT=\"$1\"\n printf \"%b%s%b\\n\" \"\\e[0;92m\" \"$TEX"
},
{
"path": "Containers/mastercontainer/supervisord.conf",
"chars": 1599,
"preview": "[supervisord]\nnodaemon=true\nlogfile=/var/log/supervisord/supervisord.log\npidfile=/var/run/supervisord/supervisord.pid\nch"
},
{
"path": "Containers/nextcloud/Dockerfile",
"chars": 9118,
"preview": "# syntax=docker/dockerfile:latest\nFROM php:8.3.30-fpm-alpine3.23\n\nENV PHP_MEMORY_LIMIT=512M\nENV PHP_UPLOAD_LIMIT=16G\nENV"
},
{
"path": "Containers/nextcloud/README.md",
"chars": 2320,
"preview": "# Nextcloud All-in-One ``nextcloud`` Container\n\nThis folder contains the OCI/Docker container definition, along with ass"
},
{
"path": "Containers/nextcloud/config/aio.config.php",
"chars": 101,
"preview": "<?php\n$CONFIG = array (\n 'one-click-instance' => true,\n 'one-click-instance.user-limit' => 100,\n);\n"
},
{
"path": "Containers/nextcloud/config/apcu.config.php",
"chars": 70,
"preview": "<?php\n$CONFIG = array (\n 'memcache.local' => '\\OC\\Memcache\\APCu',\n);\n"
},
{
"path": "Containers/nextcloud/config/apps.config.php",
"chars": 583,
"preview": "<?php\n$CONFIG = array (\n 'apps_paths' => array (\n 0 => array (\n 'path' => '/var/www/html/apps',\n "
},
{
"path": "Containers/nextcloud/config/certificates-bundle.config.php",
"chars": 255,
"preview": "<?php\n// Check if NEXTCLOUD_TRUSTED_CERTIFICATES_ are configured\nif (str_contains(implode(' ', array_keys(getenv())), 'N"
},
{
"path": "Containers/nextcloud/config/postgres.config.php",
"chars": 421,
"preview": "<?php\nif (getenv('NEXTCLOUD_TRUSTED_CERTIFICATES_POSTGRES')) {\n $CONFIG = array(\n 'pgsql_ssl' => array(\n 'mode'"
},
{
"path": "Containers/nextcloud/config/proxy.config.php",
"chars": 350,
"preview": "<?php\nif (getenv('HTTP_PROXY')) {\n $CONFIG['proxy'] = getenv('HTTP_PROXY');\n}\nif (getenv('HTTPS_PROXY')) {\n $CONFI"
},
{
"path": "Containers/nextcloud/config/redis.config.php",
"chars": 2836,
"preview": "<?php\nif (getenv('REDIS_MODE') !== 'rediscluster') {\n $CONFIG = array(\n 'memcache.distributed' => '\\OC\\Memcache\\Redi"
},
{
"path": "Containers/nextcloud/config/reverse-proxy.config.php",
"chars": 508,
"preview": "<?php\n$overwriteHost = getenv('OVERWRITEHOST');\nif ($overwriteHost) {\n $CONFIG['overwritehost'] = $overwriteHost;\n}\n\n$o"
},
{
"path": "Containers/nextcloud/config/s3.config.php",
"chars": 2139,
"preview": "<?php\r\nif (getenv('OBJECTSTORE_S3_BUCKET')) {\r\n $use_ssl = getenv('OBJECTSTORE_S3_SSL');\r\n $use_path = getenv('OBJECTS"
},
{
"path": "Containers/nextcloud/config/smtp.config.php",
"chars": 1026,
"preview": "<?php\nif (getenv('SMTP_HOST') && getenv('MAIL_FROM_ADDRESS') && getenv('MAIL_DOMAIN')) {\n $CONFIG = array (\n 'mail_s"
},
{
"path": "Containers/nextcloud/config/swift.config.php",
"chars": 1134,
"preview": "<?php\r\nif (getenv('OBJECTSTORE_SWIFT_URL')) {\r\n $autocreate = getenv('OBJECTSTORE_SWIFT_AUTOCREATE');\r\n $CONFIG = ar"
},
{
"path": "Containers/nextcloud/cron.sh",
"chars": 337,
"preview": "#!/bin/bash\nwait_for_cron() {\n set -x\n while [ -n \"$(pgrep -f /var/www/html/cron.php)\" ]; do\n echo \"Waiting"
},
{
"path": "Containers/nextcloud/entrypoint.sh",
"chars": 51470,
"preview": "#!/bin/bash\n\n# version_greater A B returns whether A > B\nversion_greater() {\n [ \"$(printf '%s\\n' \"$@\" | sort -t '.' -"
},
{
"path": "Containers/nextcloud/healthcheck.sh",
"chars": 332,
"preview": "#!/bin/bash\n\n# Set a default value for POSTGRES_PORT\nif [ -z \"$POSTGRES_PORT\" ]; then\n POSTGRES_PORT=5432\nfi\n\n\n# POST"
},
{
"path": "Containers/nextcloud/notify-all.sh",
"chars": 717,
"preview": "#!/bin/bash\n\nif [[ \"$EUID\" = 0 ]]; then\n COMMAND=(sudo -E -u www-data php /var/www/html/occ)\nelse\n COMMAND=(php /v"
},
{
"path": "Containers/nextcloud/notify.sh",
"chars": 905,
"preview": "#!/bin/bash\n\nif [[ \"$EUID\" = 0 ]]; then\n COMMAND=(sudo -E -u www-data php /var/www/html/occ)\nelse\n COMMAND=(php /v"
},
{
"path": "Containers/nextcloud/root.motd",
"chars": 364,
"preview": "Warning: You have logged in into the Nextcloud container as root user.\nSee https://github.com/nextcloud/all-in-one#how-t"
},
{
"path": "Containers/nextcloud/run-exec-commands.sh",
"chars": 817,
"preview": "#!/bin/bash\n\n# Wait until the apache container is ready\nwhile ! nc -z \"$APACHE_HOST\" \"$APACHE_PORT\"; do\n echo \"Waitin"
},
{
"path": "Containers/nextcloud/start.sh",
"chars": 7844,
"preview": "#!/bin/bash\n\n# Set a default value for POSTGRES_PORT\nif [ -z \"$POSTGRES_PORT\" ]; then\n POSTGRES_PORT=5432\nfi\n\n# Only "
},
{
"path": "Containers/nextcloud/supervisord.conf",
"chars": 1298,
"preview": "# From https://github.com/nextcloud/docker/blob/master/.examples/dockerfiles/full/fpm/supervisord.conf\n[supervisord]\nnod"
},
{
"path": "Containers/nextcloud/upgrade.exclude",
"chars": 64,
"preview": "/config/\n/data/\n/custom_apps/\n/themes/\n/version.php\n/lost+found\n"
},
{
"path": "Containers/notify-push/Dockerfile",
"chars": 628,
"preview": "# syntax=docker/dockerfile:latest\nFROM alpine:3.23.3\n\nCOPY --chmod=775 start.sh /start.sh\nCOPY --chmod=775 healthcheck.s"
},
{
"path": "Containers/notify-push/healthcheck.sh",
"chars": 99,
"preview": "#!/bin/bash\n\nif ! nc -z \"$NEXTCLOUD_HOST\" 9001; then\n exit 0\nfi\n\nnc -z 127.0.0.1 7867 || exit 1\n"
},
{
"path": "Containers/notify-push/start.sh",
"chars": 1587,
"preview": "#!/bin/bash\n\nif [ -z \"$NEXTCLOUD_HOST\" ]; then\n echo \"NEXTCLOUD_HOST needs to be provided. Exiting!\"\n exit 1\nfi\n\n#"
},
{
"path": "Containers/onlyoffice/Dockerfile",
"chars": 416,
"preview": "# syntax=docker/dockerfile:latest\n# From https://github.com/ONLYOFFICE/Docker-DocumentServer/blob/master/Dockerfile\nFROM"
},
{
"path": "Containers/onlyoffice/healthcheck.sh",
"chars": 42,
"preview": "#!/bin/bash\n\nnc -z 127.0.0.1 80 || exit 1\n"
},
{
"path": "Containers/postgresql/Dockerfile",
"chars": 1438,
"preview": "# syntax=docker/dockerfile:latest\n# From https://github.com/docker-library/postgres/blob/master/17/alpine3.23/Dockerfile"
},
{
"path": "Containers/postgresql/healthcheck.sh",
"chars": 296,
"preview": "#!/bin/bash\n\ntest -f \"/mnt/data/backup-is-running\" && exit 0\n\npsql -d \"postgresql://oc_$POSTGRES_USER:$POSTGRES_PASSWORD"
},
{
"path": "Containers/postgresql/init-user-db.sh",
"chars": 475,
"preview": "#!/bin/bash\nset -ex\n\ntouch \"$DUMP_DIR/initialization.failed\"\n\npsql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" --dbna"
},
{
"path": "Containers/postgresql/start.sh",
"chars": 7820,
"preview": "#!/bin/bash\n\n# Variables\nDATADIR=\"/var/lib/postgresql/data\"\nexport DUMP_DIR=\"/mnt/data\"\nDUMP_FILE=\"$DUMP_DIR/database-du"
},
{
"path": "Containers/redis/Dockerfile",
"chars": 699,
"preview": "# syntax=docker/dockerfile:latest\n# From https://github.com/redis/docker-library-redis/blob/release/8.2/alpine/Dockerfil"
},
{
"path": "Containers/redis/healthcheck.sh",
"chars": 64,
"preview": "#!/bin/bash\n\nredis-cli -a \"$REDIS_HOST_PASSWORD\" PING || exit 1\n"
},
{
"path": "Containers/redis/start.sh",
"chars": 527,
"preview": "#!/bin/bash\n\n# Show wiki if vm.overcommit is disabled\nif [ \"$(sysctl -n vm.overcommit_memory)\" != \"1\" ]; then\n echo \""
},
{
"path": "Containers/talk/Dockerfile",
"chars": 3259,
"preview": "# syntax=docker/dockerfile:latest\nFROM nats:2.12.5-scratch AS nats\nFROM eturnal/eturnal:1.12.2-alpine AS eturnal\nFROM st"
},
{
"path": "Containers/talk/healthcheck.sh",
"chars": 173,
"preview": "#!/bin/bash\n\nnc -z 127.0.0.1 8081 || exit 1\nnc -z 127.0.0.1 8188 || exit 1\nnc -z 127.0.0.1 4222 || exit 1\nnc -z 127.0.0."
},
{
"path": "Containers/talk/server.conf.in",
"chars": 12944,
"preview": "[http]\n# IP and port to listen on for HTTP requests.\n# Comment line to disable the listener.\n#listen = 127.0.0.1:8080\n\n#"
},
{
"path": "Containers/talk/start.sh",
"chars": 3332,
"preview": "#!/bin/bash\n\n# Variables\nif [ -z \"$NC_DOMAIN\" ]; then\n echo \"You need to provide the NC_DOMAIN.\"\n exit 1\nelif [ -z"
},
{
"path": "Containers/talk/supervisord.conf",
"chars": 1047,
"preview": "[supervisord]\nnodaemon=true\nlogfile=/var/log/supervisord/supervisord.log\npidfile=/var/run/supervisord/supervisord.pid\nch"
},
{
"path": "Containers/talk-recording/Dockerfile",
"chars": 1710,
"preview": "# syntax=docker/dockerfile:latest\nFROM python:3.14.3-alpine3.23\n\nCOPY --chmod=775 start.sh /start.sh\nCOPY --chmod=775 he"
},
{
"path": "Containers/talk-recording/healthcheck.sh",
"chars": 44,
"preview": "#!/bin/bash\n\nnc -z 127.0.0.1 1234 || exit 1\n"
},
{
"path": "Containers/talk-recording/recording.conf",
"chars": 6387,
"preview": "# SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n# SPDX-License-Identifier: AGPL-3.0-or-later\n[l"
},
{
"path": "Containers/talk-recording/start.sh",
"chars": 1412,
"preview": "#!/bin/bash\n\n# Variables\nif [ -z \"$NC_DOMAIN\" ]; then\n echo \"You need to provide the NC_DOMAIN.\"\n exit 1\nelif [ -z"
},
{
"path": "Containers/watchtower/Dockerfile",
"chars": 706,
"preview": "# syntax=docker/dockerfile:latest\nFROM golang:1.26.1-alpine3.23 AS go\n\nENV WATCHTOWER_COMMIT_HASH=5a33e3c0aa3b2770c648a1"
},
{
"path": "Containers/watchtower/start.sh",
"chars": 868,
"preview": "#!/bin/bash\n\n# Check if socket is available and readable\nif ! [ -e \"/var/run/docker.sock\" ]; then\n echo \"Docker socke"
},
{
"path": "Containers/whiteboard/Dockerfile",
"chars": 1061,
"preview": "# syntax=docker/dockerfile:latest\n# Probably from this file: https://github.com/nextcloud/whiteboard/blob/main/Dockerfil"
},
{
"path": "Containers/whiteboard/healthcheck.sh",
"chars": 88,
"preview": "#!/bin/bash\n\nnc -z \"$REDIS_HOST\" \"$REDIS_PORT\" || exit 0\nnc -z 127.0.0.1 3002 || exit 1\n"
},
{
"path": "Containers/whiteboard/start.sh",
"chars": 508,
"preview": "#!/bin/bash\n\n# Only start container if nextcloud is accessible\nwhile ! nc -z \"$REDIS_HOST\" \"$REDIS_PORT\"; do\n echo \"W"
},
{
"path": "LICENSE",
"chars": 34523,
"preview": " GNU AFFERO GENERAL PUBLIC LICENSE\n Version 3, 19 November 2007\n\n Copyright (C)"
},
{
"path": "app/.editorconfig",
"chars": 269,
"preview": "# https://editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = tab\ninsert_"
},
{
"path": "app/appinfo/info.xml",
"chars": 785,
"preview": "<?xml version=\"1.0\"?>\n<info xmlns:xsi= \"http://www.w3.org/2001/XMLSchema-instance\"\n\t xsi:noNamespaceSchemaLocation=\"htt"
},
{
"path": "app/composer/autoload.php",
"chars": 154,
"preview": "<?php\n\n// autoload.php @generated by Composer\n\nrequire_once __DIR__ . '/composer/autoload_real.php';\n\nreturn ComposerAut"
},
{
"path": "app/composer/composer/ClassLoader.php",
"chars": 14389,
"preview": "<?php\n\n/*\n * This file is part of Composer.\n *\n * (c) Nils Adermann <naderman@naderman.de>\n * Jordi Boggiano <j.bogg"
},
{
"path": "app/composer/composer/InstalledVersions.php",
"chars": 13927,
"preview": "<?php\n\n/*\n * This file is part of Composer.\n *\n * (c) Nils Adermann <naderman@naderman.de>\n * Jordi Boggiano <j.bogg"
},
{
"path": "app/composer/composer/LICENSE",
"chars": 1070,
"preview": "\nCopyright (c) Nils Adermann, Jordi Boggiano\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "app/composer/composer/autoload_classmap.php",
"chars": 304,
"preview": "<?php\n\n// autoload_classmap.php @generated by Composer\n\n$vendorDir = dirname(dirname(__FILE__));\n$baseDir = $vendorDir;\n"
},
{
"path": "app/composer/composer/autoload_namespaces.php",
"chars": 140,
"preview": "<?php\n\n// autoload_namespaces.php @generated by Composer\n\n$vendorDir = dirname(dirname(__FILE__));\n$baseDir = $vendorDir"
},
{
"path": "app/composer/composer/autoload_psr4.php",
"chars": 188,
"preview": "<?php\n\n// autoload_psr4.php @generated by Composer\n\n$vendorDir = dirname(dirname(__FILE__));\n$baseDir = $vendorDir;\n\nret"
},
{
"path": "app/composer/composer/autoload_real.php",
"chars": 1440,
"preview": "<?php\n\n// autoload_real.php @generated by Composer\n\nclass ComposerAutoloaderInitAllInOne\n{\n private static $loader;\n\n"
},
{
"path": "app/composer/composer/autoload_static.php",
"chars": 1058,
"preview": "<?php\n\n// autoload_static.php @generated by Composer\n\nnamespace Composer\\Autoload;\n\nclass ComposerStaticInitAllInOne\n{\n "
},
{
"path": "app/composer/composer/installed.json",
"chars": 69,
"preview": "{\n \"packages\": [],\n \"dev\": true,\n \"dev-package-names\": []\n}\n"
},
{
"path": "app/composer/composer/installed.php",
"chars": 734,
"preview": "<?php return array(\n 'root' => array(\n 'pretty_version' => 'dev-master',\n 'version' => 'dev-master',\n "
},
{
"path": "app/composer/composer.json",
"chars": 267,
"preview": "{\n \"config\" : {\n \"vendor-dir\": \".\",\n \"optimize-autoloader\": true,\n \"classmap-authoritative\": tru"
},
{
"path": "app/lib/Settings/Admin.php",
"chars": 2286,
"preview": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * @copyright Copyright (c) 2021, Azul <azul@riseup.net>\n *\n * @author Azul <azul@r"
},
{
"path": "app/readme.md",
"chars": 262,
"preview": "## How to develop the app?\n\nPlease note that in order to check if an app is already downloaded\nNextcloud will look for a"
},
{
"path": "app/templates/admin.php",
"chars": 673,
"preview": "<?php\ndeclare(strict_types=1);\n/**\n * @copyright (c) 2021 Azul <azul@riseup.net>\n *\n * @author Azul <azul@riseup.net>\n *"
},
{
"path": "community-containers/borgbackup-viewer/borgbackup-viewer.json",
"chars": 2489,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-borgbackup-viewer\",\n \"image"
},
{
"path": "community-containers/borgbackup-viewer/readme.md",
"chars": 2106,
"preview": "## Borgbackup Viewer\nThis container allows to view the local borg repository in a web session. It also allows you to res"
},
{
"path": "community-containers/caddy/caddy.json",
"chars": 2001,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-caddy\",\n \"display_name\": \"C"
},
{
"path": "community-containers/caddy/readme.md",
"chars": 6945,
"preview": "## Caddy with geoblocking\nThis container bundles caddy and auto-configures it for you. It also covers [vaultwarden](http"
},
{
"path": "community-containers/calcardbackup/calcardbackup.json",
"chars": 1258,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-calcardbackup\",\n \"display_n"
},
{
"path": "community-containers/calcardbackup/readme.md",
"chars": 707,
"preview": "## calcardbackup \nThis container packages calcardbackup which is a tool that exports calendars and addressbooks from Ne"
},
{
"path": "community-containers/container-management/container-management.json",
"chars": 1448,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-container-management\",\n \"di"
},
{
"path": "community-containers/container-management/readme.md",
"chars": 1431,
"preview": "## Container-Management\nThis container allows to manage insides of other containers via a GUI inside a Web session by al"
},
{
"path": "community-containers/dlna/dlna.json",
"chars": 1361,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-dlna\",\n \"display_name\": \"DL"
},
{
"path": "community-containers/dlna/readme.md",
"chars": 746,
"preview": "## DLNA server\nThis container bundles DLNA server for your Nextcloud files to be accessible by the clients in your local"
},
{
"path": "community-containers/facerecognition/facerecognition.json",
"chars": 2183,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-facerecognition\",\n \"display"
},
{
"path": "community-containers/facerecognition/readme.md",
"chars": 2816,
"preview": "## Facerecognition\nThis container bundles the external model of facerecognition and auto-configures it for you.\n\n### Not"
},
{
"path": "community-containers/fail2ban/fail2ban.json",
"chars": 1371,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-fail2ban\",\n \"display_name\":"
},
{
"path": "community-containers/fail2ban/readme.md",
"chars": 1520,
"preview": "## Fail2ban\nThis container bundles fail2ban and auto-configures it for you in order to block ip-addresses automatically."
},
{
"path": "community-containers/glances/glances.json",
"chars": 1191,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-glances\",\n \"display_name\": "
},
{
"path": "community-containers/glances/readme.md",
"chars": 1030,
"preview": "## Glances\nThis container starts Glances, a web-based info-board, and auto-configures it for you.\n\n> [!CAUTION]\n> This c"
},
{
"path": "community-containers/helloworld/helloworld.json",
"chars": 406,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-helloworld\",\n \"display_name"
},
{
"path": "community-containers/helloworld/readme.md",
"chars": 179,
"preview": "## Hello World\nThis container is a template for creating a community container.\n\n### Repository\nhttps://github.com/docjy"
},
{
"path": "community-containers/jellyfin/jellyfin.json",
"chars": 1259,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-jellyfin\",\n \"display_name\":"
},
{
"path": "community-containers/jellyfin/readme.md",
"chars": 1980,
"preview": "## Jellyfin\nThis container bundles Jellyfin and auto-configures it for you.\n\n### Notes\n- This container is incompatible "
},
{
"path": "community-containers/jellyseerr/jellyseerr.json",
"chars": 1080,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-jellyseerr\",\n \"display_name"
},
{
"path": "community-containers/jellyseerr/readme.md",
"chars": 2243,
"preview": "## Seerr\nThis container bundles Seerr and auto-configures it for you.\n\n### Notes\n- **Migration from Jellyseerr**: Jellys"
},
{
"path": "community-containers/languagetool/languagetool.json",
"chars": 523,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-languagetool\",\n \"display_na"
},
{
"path": "community-containers/languagetool/readme.md",
"chars": 752,
"preview": "## LanguageTool for Nextcloud Office\nThis container bundles a LanguageTool for Nextcloud Office which adds spell checkin"
},
{
"path": "community-containers/libretranslate/libretranslate.json",
"chars": 1423,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-libretranslate\",\n \"display_"
},
{
"path": "community-containers/libretranslate/readme.md",
"chars": 1159,
"preview": "## LibreTranslate\nThis container bundles LibreTranslate and auto-configures it for you.\n\n> [!WARNING]\n> The LibreTransla"
},
{
"path": "community-containers/lldap/lldap.json",
"chars": 1270,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-lldap\",\n \"display_name\": \"Light LDAP implemen"
},
{
"path": "community-containers/lldap/readme.md",
"chars": 5529,
"preview": "## Light LDAP server\nThis container bundles LLDAP server and auto-configures your Nextcloud instance for you.\n\n### Notes"
},
{
"path": "community-containers/local-ai/local-ai.json",
"chars": 2397,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-local-ai\",\n \"display_name\":"
},
{
"path": "community-containers/local-ai/readme.md",
"chars": 912,
"preview": "## Local AI\nThis container bundles Local AI and auto-configures it for you. It support hardware acceleration with Vulkan"
},
{
"path": "community-containers/makemkv/makemkv.json",
"chars": 1911,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-makekv\",\n \"display_name\": \""
},
{
"path": "community-containers/makemkv/readme.md",
"chars": 1864,
"preview": "## MakeMKV\nThis container bundles MakeMKV and auto-configures it for you.\n\n### Notes\n- This container should only be run"
},
{
"path": "community-containers/memories/memories.json",
"chars": 1471,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-memories\",\n \"display_name\":"
},
{
"path": "community-containers/memories/readme.md",
"chars": 573,
"preview": "## Memories\nThis container bundles the hardware-transcoding container of memories and auto-configures it for you.\n\n### N"
},
{
"path": "community-containers/minio/minio.json",
"chars": 2050,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-minio\",\n \"image_tag\": \"v2\","
},
{
"path": "community-containers/minio/readme.md",
"chars": 867,
"preview": "## Minio\nThis container bundles minio s3 storage and auto-configures it for you.\n\n>[!WARNING]\n> Enabling this container "
},
{
"path": "community-containers/nextcloud-exporter/nextcloud-exporter.json",
"chars": 1331,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-nextcloud-exporter\",\n \"disp"
},
{
"path": "community-containers/nextcloud-exporter/readme.md",
"chars": 3128,
"preview": "## Prometheus Nextcloud Exporter\n\nA Prometheus exporter that collects metrics from your Nextcloud instance for monitorin"
},
{
"path": "community-containers/nocodb/nocodb.json",
"chars": 1467,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-nocodb\",\n \"display_name\": \""
},
{
"path": "community-containers/nocodb/readme.md",
"chars": 1621,
"preview": "> [!CAUTION]\n> NocoDB is licensed under a non-free license.\n> \n> And is no longer maintained.\n\n> [!NOTE]\n> This containe"
},
{
"path": "community-containers/notifications/notifications.json",
"chars": 754,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-notifications\",\n \"display_n"
},
{
"path": "community-containers/notifications/readme.md",
"chars": 592,
"preview": "## Notifications\nThis container allows other AIO community containers to send admin notifications to Nextcloud users. \n\n"
},
{
"path": "community-containers/npmplus/npmplus.json",
"chars": 997,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-npmplus\",\n \"display_name\": "
},
{
"path": "community-containers/npmplus/readme.md",
"chars": 2221,
"preview": "## NPMplus\nThis container contains a fork of the Nginx Proxy Manager, which is a WebUI for nginx. It will also automatic"
},
{
"path": "community-containers/pi-hole/pi-hole.json",
"chars": 1840,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-pihole\",\n \"display_name\": \""
},
{
"path": "community-containers/pi-hole/readme.md",
"chars": 1254,
"preview": "## Pi-hole\nThis container bundles pi-hole and auto-configures it for you.\n\n### Notes\n- You should not run this container"
},
{
"path": "community-containers/plex/plex.json",
"chars": 1302,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-plex\",\n \"display_name\": \"Pl"
},
{
"path": "community-containers/plex/readme.md",
"chars": 1154,
"preview": "## Plex\nThis container bundles Plex and auto-configures it for you.\n\n### Notes\n- This container is incompatible with the"
},
{
"path": "community-containers/readme.md",
"chars": 3062,
"preview": "# Community containers\nThis directory features containers that are built for AIO which allows to add additional function"
},
{
"path": "community-containers/scrutiny/readme.md",
"chars": 1034,
"preview": "## Scrutiny\nThis container bundles Scrutiny which is a frontend for SMART stats and auto-configures it for you.\n\n### Not"
},
{
"path": "community-containers/scrutiny/scrutiny.json",
"chars": 1805,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-scrutiny\",\n \"display_name\":"
},
{
"path": "community-containers/smbserver/readme.md",
"chars": 905,
"preview": "## SMB-server\nThis container bundles an SMB-server and allows to configure it via a graphical shell script.\n\n### Notes\n-"
},
{
"path": "community-containers/smbserver/smbserver.json",
"chars": 1956,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-smbserver\",\n \"display_name\""
},
{
"path": "community-containers/stalwart/readme.md",
"chars": 887,
"preview": "> [!CAUTION]\n> Be aware that the mail server is the most difficult service to deploy.\n> \n> Do not use this feature as a "
},
{
"path": "community-containers/stalwart/stalwart.json",
"chars": 2365,
"preview": "{\n \"aio_services_v1\": [\n {\n \"container_name\": \"nextcloud-aio-stalwart\",\n \"display_name\":"
},
{
"path": "community-containers/vaultwarden/readme.md",
"chars": 2071,
"preview": "## Vaultwarden\nThis container bundles vaultwarden and auto-configures it for you.\n\n### Notes\n- You need to configure a r"
}
]
// ... and 161 more files (download for full content)
About this extraction
This page contains the full source code of the nextcloud/all-in-one GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 361 files (1.3 MB), approximately 345.4k tokens, and a symbol index with 279 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.