mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-05-21 10:50:10 +00:00
Compare commits
197 Commits
v9.4.1
...
enh/noid/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7dfdf346a | ||
|
|
1e4f32f3cb | ||
|
|
5187ea6c35 | ||
|
|
c36ca0a4a3 | ||
|
|
56aa613dfb | ||
|
|
d674ba4f6e | ||
|
|
890bcc9434 | ||
|
|
ff19098f48 | ||
|
|
af72da74f0 | ||
|
|
cd4c294799 | ||
|
|
88026afab3 | ||
|
|
56f6934263 | ||
|
|
3a8db48322 | ||
|
|
4ce04eba4a | ||
|
|
eacca1ad5e | ||
|
|
973774a401 | ||
|
|
abcf8bfeb9 | ||
|
|
bf2f0fd65e | ||
|
|
89984e6c92 | ||
|
|
e09aacd29e | ||
|
|
2faf4f2452 | ||
|
|
6d6f50c966 | ||
|
|
2aa8aa7dda | ||
|
|
f529714a07 | ||
|
|
a2f7a221d7 | ||
|
|
b3f63e5f74 | ||
|
|
8d062f7461 | ||
|
|
5d3afccb71 | ||
|
|
f803cea6f1 | ||
|
|
3218e429ec | ||
|
|
2ed94446d7 | ||
|
|
546f11a654 | ||
|
|
9a4f132998 | ||
|
|
5d4cbeccd4 | ||
|
|
72b892088a | ||
|
|
78431692ee | ||
|
|
959f067598 | ||
|
|
1911b573d4 | ||
|
|
d84c7bf704 | ||
|
|
9e72a29726 | ||
|
|
5a910a33f0 | ||
|
|
649ac3d226 | ||
|
|
c29911f006 | ||
|
|
8b564a74c5 | ||
|
|
e6119332ee | ||
|
|
8261ce0ad9 | ||
|
|
e94525eb5f | ||
|
|
af1483a4d4 | ||
|
|
eb26e68b0c | ||
|
|
3c8a262fd7 | ||
|
|
50b56ed363 | ||
|
|
8761289d06 | ||
|
|
343db3de13 | ||
|
|
9982bb2156 | ||
|
|
8a575e96fb | ||
|
|
ab1fc6bcbc | ||
|
|
e8215a112b | ||
|
|
7a39ec46c6 | ||
|
|
281c276df0 | ||
|
|
ad93ccd476 | ||
|
|
23aa99dc8f | ||
|
|
4e11ae3d22 | ||
|
|
5204ea633f | ||
|
|
147e81c503 | ||
|
|
0800fd4458 | ||
|
|
d1125142cc | ||
|
|
a8ced69ab4 | ||
|
|
9d0b52296d | ||
|
|
06b1116402 | ||
|
|
473007f4cd | ||
|
|
142d3e8997 | ||
|
|
e2946faf02 | ||
|
|
3474801116 | ||
|
|
cf70d53c5b | ||
|
|
73ef6db4cf | ||
|
|
9f92af0259 | ||
|
|
d2e330a78f | ||
|
|
939e5fec8a | ||
|
|
26695effa2 | ||
|
|
f17a27b80c | ||
|
|
d6dd6140c3 | ||
|
|
e92cbc211b | ||
|
|
c701ae38f8 | ||
|
|
ed857db3c1 | ||
|
|
1321f875e9 | ||
|
|
2af1eaf207 | ||
|
|
4c162237bf | ||
|
|
0445b4c5f1 | ||
|
|
ba4446f565 | ||
|
|
3c74ebf347 | ||
|
|
0db3f95219 | ||
|
|
7a3bcc73c6 | ||
|
|
8e55a6f35f | ||
|
|
992608a2b0 | ||
|
|
0be1f9827b | ||
|
|
3389af0bdf | ||
|
|
fb815dd5b4 | ||
|
|
c7cd473c99 | ||
|
|
dbe3fb4472 | ||
|
|
84bbc6d936 | ||
|
|
6737c188a3 | ||
|
|
e53ffb85a4 | ||
|
|
d791161357 | ||
|
|
2251a218dd | ||
|
|
52fd6d63c7 | ||
|
|
fd1d21c364 | ||
|
|
b252bc7730 | ||
|
|
4d3d8b9158 | ||
|
|
3ba0995dd7 | ||
|
|
91faf2bd34 | ||
|
|
d62e3b70ff | ||
|
|
25ca271055 | ||
|
|
2d8b8ab542 | ||
|
|
da3d20d648 | ||
|
|
01f3813308 | ||
|
|
7e8402aeb0 | ||
|
|
7c1d337d47 | ||
|
|
43e1dbb107 | ||
|
|
3d9c51baee | ||
|
|
c2744fb788 | ||
|
|
5d6fc71a61 | ||
|
|
2f70096a52 | ||
|
|
03c900ca09 | ||
|
|
95e8a461ce | ||
|
|
841e80e3b2 | ||
|
|
b413877c6f | ||
|
|
8712b3fa17 | ||
|
|
7e9a39a074 | ||
|
|
b9c30adab4 | ||
|
|
a86c92a94a | ||
|
|
32fac05807 | ||
|
|
d7caa2a7b4 | ||
|
|
f67015732f | ||
|
|
50acbb62d8 | ||
|
|
3ccdd332a9 | ||
|
|
6587f9ff68 | ||
|
|
22aa12d875 | ||
|
|
108035c720 | ||
|
|
1792d4c2fc | ||
|
|
12e4b0d561 | ||
|
|
a67fe51bbc | ||
|
|
f37b474708 | ||
|
|
5318d66d6d | ||
|
|
b892917671 | ||
|
|
ef66df0f08 | ||
|
|
8e8f5f1a04 | ||
|
|
a41dc9f2c0 | ||
|
|
e74f52aaeb | ||
|
|
6a383ef27a | ||
|
|
52305ce9e9 | ||
|
|
db55a1c282 | ||
|
|
c63440f2ee | ||
|
|
a27a255d3d | ||
|
|
8c4eda9d75 | ||
|
|
4e24200301 | ||
|
|
2cd955a7f2 | ||
|
|
6986eccad4 | ||
|
|
c369b1f4ae | ||
|
|
bbcbf71e6b | ||
|
|
8c1f6ac4f6 | ||
|
|
151b05ec01 | ||
|
|
164d4fb997 | ||
|
|
a23026889f | ||
|
|
9cd2d7eb7b | ||
|
|
0315d4c10f | ||
|
|
30981b9afa | ||
|
|
c990d03b91 | ||
|
|
35c641265c | ||
|
|
69a3087359 | ||
|
|
bc6dfe8711 | ||
|
|
2603941d35 | ||
|
|
e058ab96ea | ||
|
|
c5cc5d1521 | ||
|
|
41e6d7cf6d | ||
|
|
c8447f2713 | ||
|
|
f1114a2b23 | ||
|
|
f9cc25bb59 | ||
|
|
63d05b6065 | ||
|
|
4cacd38be2 | ||
|
|
b31286ae11 | ||
|
|
ab1cfee353 | ||
|
|
d91c58ea28 | ||
|
|
149688803c | ||
|
|
9ad7ea1456 | ||
|
|
83fc108d9c | ||
|
|
bc084eca93 | ||
|
|
eb3a133a0c | ||
|
|
0020bb45b2 | ||
|
|
8bf7a4d57f | ||
|
|
ca8c474cea | ||
|
|
f6fd960ba0 | ||
|
|
c4e1ab64fc | ||
|
|
7879b9ea0d | ||
|
|
c9b97220d0 | ||
|
|
ed8794522d | ||
|
|
a9710944f0 | ||
|
|
b84611a5ac |
10
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: 🐛 Bug report
|
||||
about: Help us improving by reporting a bug
|
||||
labels: bug, 0. Needs triage
|
||||
labels: 0. Needs triage
|
||||
---
|
||||
|
||||
<!---
|
||||
@@ -20,11 +20,11 @@ labels: bug, 0. Needs triage
|
||||
### Actual behavior <!--- Tell us what happens instead -->
|
||||
|
||||
|
||||
### Host OS <!--- (the host OS on which you are trying to install AIO on) -->
|
||||
### Other information
|
||||
#### Host OS <!--- (the host OS on which you are trying to install AIO on) -->
|
||||
|
||||
#### Output of `sudo docker info`
|
||||
|
||||
#### Nextcloud AIO version <!--- (see Nextcloud AIO interface) -->
|
||||
|
||||
#### Current channel <!--- (see the channel name in the AIO interface) -->
|
||||
#### Docker run command or docker-compose file that you used
|
||||
|
||||
#### Other valuable info <!--- (like logs, screenshots & Co.) -->
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
@@ -1,7 +1,7 @@
|
||||
---
|
||||
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: enhancement, 0. Needs triage
|
||||
labels: 0. Needs triage
|
||||
---
|
||||
|
||||
<!--- Please fill out the whole template below -->
|
||||
|
||||
11
.github/dependabot.yml
vendored
11
.github/dependabot.yml
vendored
@@ -94,7 +94,7 @@ updates:
|
||||
time: "12:00"
|
||||
ignore:
|
||||
- dependency-name: "redis"
|
||||
update-types: ["version-update:semver-major"]
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
@@ -183,3 +183,12 @@ updates:
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/whiteboard"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
|
||||
51
.github/workflows/command-rebase.yml
vendored
51
.github/workflows/command-rebase.yml
vendored
@@ -1,51 +0,0 @@
|
||||
# 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
|
||||
|
||||
name: Rebase command
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: created
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
rebase:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: none
|
||||
|
||||
# On pull requests and if the comment starts with `/rebase`
|
||||
if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/rebase')
|
||||
|
||||
steps:
|
||||
- name: Add reaction on start
|
||||
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
|
||||
with:
|
||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
repository: ${{ github.event.repository.full_name }}
|
||||
comment-id: ${{ github.event.comment.id }}
|
||||
reaction-type: "+1"
|
||||
|
||||
- name: Checkout the latest code
|
||||
uses: actions/checkout@v4 # v3.5.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
|
||||
- name: Automatic Rebase
|
||||
uses: cirrus-actions/rebase@b87d48154a87a85666003575337e27b8cd65f691 # 1.8
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
|
||||
- name: Add reaction on failure
|
||||
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
|
||||
if: failure()
|
||||
with:
|
||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
repository: ${{ github.event.repository.full_name }}
|
||||
comment-id: ${{ github.event.comment.id }}
|
||||
reaction-type: "-1"
|
||||
2
.github/workflows/dependency-updates.yml
vendored
2
.github/workflows/dependency-updates.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
)"
|
||||
sed -i "s|pecl install APCu.*\;|pecl install APCu-$apcu_version\;|" ./Containers/mastercontainer/Dockerfile
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
commit-message: php dependency updates
|
||||
signoff: true
|
||||
|
||||
2
.github/workflows/imaginary-update.yml
vendored
2
.github/workflows/imaginary-update.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
sed -i "s|^ENV IMAGINARY_HASH.*$|ENV IMAGINARY_HASH=$imaginary_version|" ./Containers/imaginary/Dockerfile
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
commit-message: imaginary-update automated change
|
||||
signoff: true
|
||||
|
||||
2
.github/workflows/nextcloud-update.yml
vendored
2
.github/workflows/nextcloud-update.yml
vendored
@@ -79,7 +79,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
commit-message: nextcloud-update automated change
|
||||
signoff: true
|
||||
|
||||
2
.github/workflows/psalm-update-baseline.yml
vendored
2
.github/workflows/psalm-update-baseline.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
commit-message: Update psalm baseline
|
||||
|
||||
2
.github/workflows/talk.yml
vendored
2
.github/workflows/talk.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
sed -i "s|^ARG JANUS_VERSION=.*$|ARG JANUS_VERSION=$janus_version|" ./Containers/talk/Dockerfile
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
commit-message: talk-update automated change
|
||||
signoff: true
|
||||
|
||||
2
.github/workflows/update-helm.yml
vendored
2
.github/workflows/update-helm.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
sudo bash nextcloud-aio-helm-chart/update-helm.sh "$DOCKER_TAG"
|
||||
fi
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
commit-message: Helm Chart updates
|
||||
signoff: true
|
||||
|
||||
2
.github/workflows/update-yaml.yml
vendored
2
.github/workflows/update-yaml.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
run: |
|
||||
sudo bash manual-install/update-yaml.sh
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
commit-message: Yaml updates
|
||||
signoff: true
|
||||
|
||||
@@ -51,6 +51,12 @@ https://{$ADDITIONAL_TRUSTED_DOMAIN}:443,
|
||||
reverse_proxy {$TALK_HOST}:8081
|
||||
}
|
||||
|
||||
# Whiteboard
|
||||
route /whiteboard/* {
|
||||
uri strip_prefix /whiteboard
|
||||
reverse_proxy {$WHITEBOARD_HOST}:3002
|
||||
}
|
||||
|
||||
# Nextcloud
|
||||
route {
|
||||
header Strict-Transport-Security max-age=31536000;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM alpine:3.20.2
|
||||
FROM alpine:3.20.3
|
||||
|
||||
RUN set -ex; \
|
||||
\
|
||||
|
||||
@@ -71,8 +71,8 @@ if [ "$BORG_MODE" = backup ]; 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" ]; then
|
||||
echo "The .ocdata file is missing in Nextcloud datadir which means it is invalid!"
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# Probably from this file: https://github.com/Cisco-Talos/clamav-docker/blob/main/clamav/1.3/alpine/Dockerfile
|
||||
FROM clamav/clamav:1.3.1-61
|
||||
FROM clamav/clamav:1.4.1-5
|
||||
|
||||
COPY clamav.conf /clamav.conf
|
||||
COPY --chmod=775 start.script /start.script
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# From a file located probably somewhere here: https://github.com/CollaboraOnline/online/tree/master/docker
|
||||
FROM collabora/code:24.04.5.2.1
|
||||
FROM collabora/code:24.04.7.2.1
|
||||
|
||||
USER root
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM haproxy:3.0.3-alpine
|
||||
FROM haproxy:3.0.4-alpine
|
||||
|
||||
# hadolint ignore=DL3002
|
||||
USER root
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM alpine:3.20.2
|
||||
FROM alpine:3.20.3
|
||||
RUN set -ex; \
|
||||
apk upgrade --no-cache -a; \
|
||||
apk add --no-cache bash lighttpd netcat-openbsd; \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# Probably from here https://github.com/elastic/elasticsearch/blob/main/distribution/docker/src/docker/Dockerfile
|
||||
FROM elasticsearch:8.14.3
|
||||
FROM elasticsearch:8.15.1
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM golang:1.22.5-alpine3.20 AS go
|
||||
FROM golang:1.23.1-alpine3.20 AS go
|
||||
|
||||
ENV IMAGINARY_HASH=6cd9edd1d3fb151eb773c14552886e4fc8e50138
|
||||
|
||||
@@ -13,7 +13,7 @@ RUN set -ex; \
|
||||
build-base; \
|
||||
go install github.com/h2non/imaginary@"$IMAGINARY_HASH";
|
||||
|
||||
FROM alpine:3.20.2
|
||||
FROM alpine:3.20.3
|
||||
RUN set -ex; \
|
||||
apk upgrade --no-cache -a; \
|
||||
apk add --no-cache \
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# Docker CLI is a requirement
|
||||
FROM docker:27.1.1-cli AS docker
|
||||
FROM docker:27.2.1-cli AS docker
|
||||
|
||||
# Caddy is a requirement
|
||||
FROM caddy:2.8.4-alpine AS caddy
|
||||
|
||||
# From https://github.com/docker-library/php/blob/master/8.3/alpine3.20/fpm/Dockerfile
|
||||
FROM php:8.3.9-fpm-alpine3.20
|
||||
FROM php:8.3.11-fpm-alpine3.20
|
||||
|
||||
EXPOSE 80
|
||||
EXPOSE 8080
|
||||
|
||||
@@ -91,14 +91,21 @@ else
|
||||
fi
|
||||
|
||||
# Check Storage drivers
|
||||
STORAGE_DRIVER="$(docker info | grep "Storage Driver")"
|
||||
STORAGE_DRIVER="$(sudo -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"
|
||||
echo "Warning: It seems like the storage driver vfs is used. This will lead to problems with disk space and performance and is disrecommended!"
|
||||
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"
|
||||
echo "Warning: It seems like the storage driver fuse-overlayfs is used. Please check if you can switch to overlay2 instead."
|
||||
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 -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
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM php:8.2.21-fpm-alpine3.20
|
||||
FROM php:8.2.23-fpm-alpine3.20
|
||||
|
||||
ENV PHP_MEMORY_LIMIT=512M
|
||||
ENV PHP_UPLOAD_LIMIT=10G
|
||||
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=29.0.4
|
||||
ENV NEXTCLOUD_VERSION=29.0.7
|
||||
ENV AIO_TOKEN=123456
|
||||
ENV AIO_URL=localhost
|
||||
# AIO settings end # Do not remove or change this line!
|
||||
@@ -77,7 +78,7 @@ RUN set -ex; \
|
||||
; \
|
||||
\
|
||||
# pecl will claim success even if one install fails, so we need to perform each install separately
|
||||
pecl install igbinary-3.2.15; \
|
||||
pecl install igbinary-3.2.16; \
|
||||
pecl install APCu-5.1.23; \
|
||||
pecl install memcached-3.2.0 \
|
||||
--configureoptions 'enable-memcached-igbinary="yes"'; \
|
||||
@@ -131,7 +132,7 @@ RUN set -ex; \
|
||||
\
|
||||
{ \
|
||||
echo 'session.save_handler = redis'; \
|
||||
echo 'session.save_path = "tcp://${REDIS_HOST}:6379?auth=${REDIS_HOST_PASSWORD}"'; \
|
||||
echo 'session.save_path = "tcp://${REDIS_HOST}:6379/${REDIS_DB_INDEX}?auth=${REDIS_HOST_PASSWORD}"'; \
|
||||
echo 'redis.session.locking_enabled = 1'; \
|
||||
echo 'redis.session.lock_retries = -1'; \
|
||||
echo 'redis.session.lock_wait_time = 10000'; \
|
||||
|
||||
@@ -13,6 +13,6 @@ $CONFIG = array (
|
||||
),
|
||||
),
|
||||
);
|
||||
if (getenv('APPS_ALLOWLIST') !== false) {
|
||||
if (getenv('APPS_ALLOWLIST')) {
|
||||
$CONFIG['appsallowlist'] = explode(" ", getenv('APPS_ALLOWLIST'));
|
||||
}
|
||||
|
||||
13
Containers/nextcloud/config/proxy.config.php
Normal file
13
Containers/nextcloud/config/proxy.config.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?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'));
|
||||
}
|
||||
@@ -9,13 +9,13 @@ if (getenv('REDIS_HOST')) {
|
||||
),
|
||||
);
|
||||
|
||||
if (getenv('REDIS_HOST_PORT') !== false) {
|
||||
if (getenv('REDIS_HOST_PORT')) {
|
||||
$CONFIG['redis']['port'] = (int) getenv('REDIS_HOST_PORT');
|
||||
} elseif (getenv('REDIS_HOST')[0] != '/') {
|
||||
$CONFIG['redis']['port'] = 6379;
|
||||
}
|
||||
|
||||
if (getenv('REDIS_DB_INDEX') !== false) {
|
||||
if (getenv('REDIS_DB_INDEX')) {
|
||||
$CONFIG['redis']['dbindex'] = (int) getenv('REDIS_DB_INDEX');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@ directory_empty() {
|
||||
}
|
||||
|
||||
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
|
||||
# Disable integrity check temporarily until next update
|
||||
php /var/www/html/occ config:system:set integrity.check.disabled --type bool --value true
|
||||
php /var/www/html/occ upgrade
|
||||
php /var/www/html/occ app:enable nextcloud-aio --force
|
||||
fi
|
||||
@@ -99,6 +100,20 @@ if ! [ -f "$NEXTCLOUD_DATA_DIR/skip.update" ]; then
|
||||
# Write output to logfile.
|
||||
exec > >(tee -i "/var/www/html/data/update.log")
|
||||
exec 2>&1
|
||||
# Run built-in upgrader if version is below 28.0.2 to upgrade to 28.0.x first
|
||||
touch "$NEXTCLOUD_DATA_DIR/update.failed"
|
||||
if ! version_greater "$installed_version" "28.0.1.20"; then
|
||||
php /var/www/html/updater/updater.phar --no-interaction --no-backup
|
||||
if ! php /var/www/html/occ upgrade || php /var/www/html/occ status | grep maintenance | grep -q 'true'; then
|
||||
echo "Upgrade failed. Please restore from backup."
|
||||
bash /notify.sh "Nextcloud update to $image_version failed!" "Please restore from backup!"
|
||||
exit 1
|
||||
fi
|
||||
rm "$NEXTCLOUD_DATA_DIR/update.failed"
|
||||
# shellcheck disable=SC2016
|
||||
installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
|
||||
INSTALLED_MAJOR="${installed_version%%.*}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$installed_version" != "0.0.0.0" ] && [ "$((IMAGE_MAJOR - INSTALLED_MAJOR))" -gt 1 ]; then
|
||||
@@ -421,12 +436,14 @@ DATADIR_PERMISSION_CONF
|
||||
|
||||
# Apply optimization
|
||||
echo "Doing some optimizations..."
|
||||
php /var/www/html/occ maintenance:repair
|
||||
if [ "$NEXTCLOUD_SKIP_DATABASE_OPTIMIZATION" != yes ]; then
|
||||
php /var/www/html/occ maintenance:repair --include-expensive
|
||||
php /var/www/html/occ db:add-missing-indices
|
||||
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
|
||||
else
|
||||
php /var/www/html/occ maintenance:repair
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -582,6 +599,10 @@ if [ "$COLLABORA_ENABLED" = 'yes' ]; then
|
||||
COLLABORA_HOST="$NC_DOMAIN"
|
||||
fi
|
||||
set +x
|
||||
# Remove richdcoumentscode if it should be incorrectly installed
|
||||
if [ -d "/var/www/html/custom_apps/richdocumentscode" ]; then
|
||||
php /var/www/html/occ app:remove richdocumentscode
|
||||
fi
|
||||
if ! [ -d "/var/www/html/custom_apps/richdocuments" ]; then
|
||||
php /var/www/html/occ app:install richdocuments
|
||||
elif [ "$(php /var/www/html/occ config:app:get richdocuments enabled)" != "yes" ]; then
|
||||
@@ -816,19 +837,34 @@ else
|
||||
fi
|
||||
|
||||
# Docker socket proxy
|
||||
if version_greater "$installed_version" "27.1.2.0"; then
|
||||
if [ "$DOCKER_SOCKET_PROXY_ENABLED" = 'yes' ]; then
|
||||
if ! [ -d "/var/www/html/custom_apps/app_api" ]; then
|
||||
php /var/www/html/occ app:install app_api
|
||||
elif [ "$(php /var/www/html/occ config:app:get app_api enabled)" != "yes" ]; then
|
||||
php /var/www/html/occ app:enable app_api
|
||||
elif [ "$SKIP_UPDATE" != 1 ]; then
|
||||
php /var/www/html/occ app:update app_api
|
||||
fi
|
||||
else
|
||||
if [ "$REMOVE_DISABLED_APPS" = yes ] && [ -d "/var/www/html/custom_apps/app_api" ]; then
|
||||
php /var/www/html/occ app:remove app_api
|
||||
fi
|
||||
if [ "$DOCKER_SOCKET_PROXY_ENABLED" = 'yes' ]; then
|
||||
if ! [ -d "/var/www/html/custom_apps/app_api" ]; then
|
||||
php /var/www/html/occ app:install app_api
|
||||
elif [ "$(php /var/www/html/occ config:app:get app_api enabled)" != "yes" ]; then
|
||||
php /var/www/html/occ app:enable app_api
|
||||
elif [ "$SKIP_UPDATE" != 1 ]; then
|
||||
php /var/www/html/occ app:update app_api
|
||||
fi
|
||||
else
|
||||
if [ "$REMOVE_DISABLED_APPS" = yes ] && [ -d "/var/www/html/custom_apps/app_api" ]; then
|
||||
php /var/www/html/occ app:remove app_api
|
||||
fi
|
||||
fi
|
||||
|
||||
# Whiteboard app
|
||||
if [ "$WHITEBOARD_ENABLED" = 'yes' ]; then
|
||||
if ! [ -d "/var/www/html/custom_apps/whiteboard" ]; then
|
||||
php /var/www/html/occ app:install whiteboard
|
||||
elif [ "$(php /var/www/html/occ config:app:get whiteboard enabled)" != "yes" ]; then
|
||||
php /var/www/html/occ app:enable whiteboard
|
||||
elif [ "$SKIP_UPDATE" != 1 ]; then
|
||||
php /var/www/html/occ app:update whiteboard
|
||||
fi
|
||||
php /var/www/html/occ config:app:set whiteboard collabBackendUrl --value="https://$NC_DOMAIN/whiteboard"
|
||||
php /var/www/html/occ config:app:set whiteboard jwt_secret_key --value="$WHITEBOARD_SECRET"
|
||||
else
|
||||
if [ "$REMOVE_DISABLED_APPS" = yes ] && [ -d "/var/www/html/custom_apps/whiteboard" ]; then
|
||||
php /var/www/html/occ app:remove whiteboard
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM alpine:3.20.2
|
||||
FROM alpine:3.20.3
|
||||
|
||||
COPY --chmod=775 start.sh /start.sh
|
||||
COPY --chmod=775 healthcheck.sh /healthcheck.sh
|
||||
|
||||
@@ -48,9 +48,14 @@ echo "notify-push was started"
|
||||
if [ -z "$POSTGRES_PORT" ]; then
|
||||
POSTGRES_PORT=5432
|
||||
fi
|
||||
# Set a default for redis db index
|
||||
if [ -z "$REDIS_DB_INDEX" ]; then
|
||||
REDIS_DB_INDEX=0
|
||||
fi
|
||||
|
||||
# Set sensitive values as env
|
||||
export DATABASE_URL="postgres://oc_$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB"
|
||||
export REDIS_URL="redis://:$REDIS_HOST_PASSWORD@$REDIS_HOST"
|
||||
export REDIS_URL="redis://:$REDIS_HOST_PASSWORD@$REDIS_HOST/$REDIS_DB_INDEX"
|
||||
|
||||
# Run it
|
||||
/nextcloud/custom_apps/notify_push/bin/"$CPU_ARCH"/notify_push \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# From https://github.com/ONLYOFFICE/Docker-DocumentServer/blob/master/Dockerfile
|
||||
FROM onlyoffice/documentserver:8.1.1.1
|
||||
FROM onlyoffice/documentserver:8.1.3.2
|
||||
|
||||
# USER root is probably used
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# From https://github.com/docker-library/postgres/blob/master/16/alpine3.20/Dockerfile
|
||||
FROM postgres:16.3-alpine
|
||||
FROM postgres:16.4-alpine
|
||||
|
||||
COPY --chmod=775 start.sh /start.sh
|
||||
COPY --chmod=775 healthcheck.sh /healthcheck.sh
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM python:3.12.4-alpine3.20
|
||||
FROM python:3.12.6-alpine3.20
|
||||
|
||||
COPY --chmod=775 start.sh /start.sh
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM nats:2.10.18-scratch AS nats
|
||||
FROM nats:2.10.20-scratch AS nats
|
||||
FROM eturnal/eturnal:1.12.0 AS eturnal
|
||||
FROM strukturag/nextcloud-spreed-signaling:1.3.2 AS signaling
|
||||
FROM alpine:3.20.2 AS janus
|
||||
FROM strukturag/nextcloud-spreed-signaling:2.0.0 AS signaling
|
||||
FROM alpine:3.20.3 AS janus
|
||||
|
||||
ARG JANUS_VERSION=v0.14.3
|
||||
ARG JANUS_VERSION=v0.14.4
|
||||
WORKDIR /src
|
||||
RUN set -ex; \
|
||||
apk add --no-cache \
|
||||
@@ -34,7 +34,7 @@ RUN set -ex; \
|
||||
make configs; \
|
||||
rename -v ".jcfg.sample" ".jcfg" /usr/local/etc/janus/*.jcfg.sample
|
||||
|
||||
FROM alpine:3.20.2
|
||||
FROM alpine:3.20.3
|
||||
ENV ETURNAL_ETC_DIR="/conf"
|
||||
COPY --from=janus --chmod=777 --chown=1000:1000 /usr/local /usr/local
|
||||
COPY --from=eturnal --chmod=777 --chown=1000:1000 /opt/eturnal /opt/eturnal
|
||||
|
||||
@@ -55,6 +55,15 @@ blockkey = -encryption-key-
|
||||
# value as configured in the respective internal services.
|
||||
internalsecret = the-shared-secret-for-internal-clients
|
||||
|
||||
[federation]
|
||||
# If set to "true", certificate validation of federation targets will be skipped.
|
||||
# This should only be enabled during development, e.g. to work with self-signed
|
||||
# certificates.
|
||||
#skipverify = false
|
||||
|
||||
# Timeout in seconds for requests to federation targets.
|
||||
#timeout = 10
|
||||
|
||||
[backend]
|
||||
# Type of backend configuration.
|
||||
# Defaults to "static".
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
# From https://github.com/containrrr/watchtower/blob/main/dockerfiles/Dockerfile.self-contained
|
||||
FROM containrrr/watchtower:1.7.1 AS watchtower
|
||||
|
||||
FROM alpine:3.20.2
|
||||
FROM alpine:3.20.3
|
||||
|
||||
RUN apk upgrade --no-cache -a; \
|
||||
RUN set -ex; \
|
||||
apk upgrade --no-cache -a; \
|
||||
apk add --no-cache bash
|
||||
|
||||
COPY --from=watchtower /watchtower /watchtower
|
||||
|
||||
14
Containers/whiteboard/Dockerfile
Normal file
14
Containers/whiteboard/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM ghcr.io/nextcloud-releases/whiteboard:v1.0.2
|
||||
|
||||
USER root
|
||||
RUN set -ex; \
|
||||
apk upgrade --no-cache -a; \
|
||||
apk add --no-cache bash
|
||||
USER nobody
|
||||
|
||||
COPY --chmod=775 start.sh /start.sh
|
||||
|
||||
ENTRYPOINT ["/start.sh"]
|
||||
|
||||
LABEL com.centurylinklabs.watchtower.enable="false"
|
||||
17
Containers/whiteboard/start.sh
Normal file
17
Containers/whiteboard/start.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Only start container if nextcloud is accessible
|
||||
while ! nc -z "$REDIS_HOST" 6379; do
|
||||
echo "Waiting for redis to start..."
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Set a default for redis db index
|
||||
if [ -z "$REDIS_DB_INDEX" ]; then
|
||||
REDIS_DB_INDEX=0
|
||||
fi
|
||||
|
||||
export REDIS_URL="redis://:$REDIS_HOST_PASSWORD@$REDIS_HOST/$REDIS_DB_INDEX"
|
||||
|
||||
# Run it
|
||||
exec npm run server:start
|
||||
@@ -3,7 +3,6 @@ This container bundles DLNA server for your Nextcloud files to be accessible by
|
||||
|
||||
### Notes
|
||||
- This container will work only if the Nextcloud installation is in your home network, it is not suitable for installations on remote servers.
|
||||
- This is not working with Docker Desktop since it requires the `host` networking mode in docker, and it doesn't really share the host's network interfaces in this system
|
||||
- If you have a firewall like ufw configured, you might need to open at least port 9999 TCP and 1900 UDP first in order to make it work.
|
||||
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
This container bundles fail2ban and auto-configures it for you in order to block ip-addresses automatically. It also covers https://github.com/nextcloud/all-in-one/tree/main/community-containers/vaultwarden, if installed.
|
||||
|
||||
### Notes
|
||||
- This is not working on Docker Desktop since it needs `network_mode: host` in order to work correctly.
|
||||
- If you get an error like `"ip6tables v1.8.9 (legacy): can't initialize ip6tables table filter': Table does not exist (do you need to insmod?)"`, you need to enable ip6tables on your host via `sudo modprobe ip6table_filter`.
|
||||
- If you get an error like `stderr: 'iptables: No chain/target/match by that name.'` and `stderr: 'ip6tables: No chain/target/match by that name.'`, you need to follow https://github.com/szaimen/aio-fail2ban/issues/9#issuecomment-2026898790 in order to resolve this.
|
||||
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
|
||||
|
||||
@@ -3,7 +3,6 @@ This container bundles Jellyfin and auto-configures it for you.
|
||||
|
||||
### Notes
|
||||
- This container is incompatible with the [Plex](https://github.com/nextcloud/all-in-one/tree/main/community-containers/plex) community container. So make sure that you do not enable both at the same time!
|
||||
- This container does not work on Docker Desktop since it needs `network_mode: host` in order to work correctly.
|
||||
- After adding and starting the container, you can directly visit http://ip.address.of.server:8096/ and access your new Jellyfin instance!
|
||||
- This container should usually only be run in home networks as it exposes unencrypted services like DLNA by default which can be disabld via the web interface though.
|
||||
- In order to access your Jellyfin outside the local network, you have to set up your own reverse proxy. You can set up a reverse proxy following [these instructions](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md) and [Jellyfin's networking documentation](https://jellyfin.org/docs/general/networking/#running-jellyfin-behind-a-reverse-proxy), OR use the [Caddy](https://github.com/nextcloud/all-in-one/tree/main/community-containers/caddy) community container that will automatically configure `media.$NC_DOMAIN` to redirect to your Jellyfin.
|
||||
|
||||
@@ -3,7 +3,6 @@ This container contains a fork of the Nginx Proxy Manager, which is a WebUI for
|
||||
|
||||
### Notes
|
||||
- This container is incompatible with the [caddy](https://github.com/nextcloud/all-in-one/tree/main/community-containers/caddy) community container. So make sure that you do not enable both at the same time!
|
||||
- Only works on linux since it uses network mode host
|
||||
- You can ignore the NPM configuration of the reverse-proxy.md. The NPMplus fork already contains the changes of the advanced tab.
|
||||
- Make sure that no other service is using port `443 (tcp/upd)` or `81 (tcp)` on your host as otherwise the containers will fail to start. You can check this with `sudo netstat -tulpn | grep "443\|81"` before installing AIO.
|
||||
- Please change the default login data first, after you can read inside the logs that the default config for AIO is created and there are no errors.
|
||||
|
||||
@@ -4,7 +4,6 @@ This container bundles Plex and auto-configures it for you.
|
||||
### Notes
|
||||
- This container is incompatible with the [Jellyfin](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyfin) community container. So make sure that you do not enable both at the same time!
|
||||
- This is not working on arm64 since Plex does only provide x64 docker images.
|
||||
- This is not working on Docker Desktop since it needs `network_mode: host` in order to work correctly.
|
||||
- This container should usually only be run in home networks as it exposes unencrypted services like DLNA by default which can be disabld via the web interface though.
|
||||
- If you have a firewall like ufw configured, you might need to open all Plex ports in there first in order to make it work. Especially port 32400 is important!
|
||||
- After adding and starting the container, you need to visit http://ip.address.of.server:32400/manage in order to claim your server with a plex account
|
||||
|
||||
@@ -13,7 +13,7 @@ Afterwards, you might want to add additional community containers to the default
|
||||
Simply submit a PR by creating a new folder in this directory: https://github.com/nextcloud/all-in-one/tree/main/community-containers with the name of your container. It must include a json file with the same name and with correct syntax and a readme.md with additional information. You might get inspired by caddy, fail2ban, local-ai, libretranslate, plex, pi-hole or vaultwarden (subfolders in this directory). For a full-blown example of the json file, see https://github.com/nextcloud/all-in-one/blob/main/php/containers.json. The json-schema that it validates against can be found here: https://github.com/nextcloud/all-in-one/blob/main/php/containers-schema.json.
|
||||
|
||||
### Is there a list of ideas for new community containers?
|
||||
Yes, see [this list](https://github.com/nextcloud/all-in-one/discussions/categories/ideas?discussions_q=is%3Aopen+category%3AIdeas+label%3A%22help+wanted%22+sort%3Atop) for already existing ideas for new community containers. Feel free to pick one up and add it to this folder by following the instructions above.
|
||||
Yes, see [this list](https://github.com/nextcloud/all-in-one/issues/5251) for already existing ideas for new community containers. Feel free to pick one up and add it to this folder by following the instructions above.
|
||||
|
||||
## How to remove containers from AIOs stack?
|
||||
In some cases, you might want to remove some community containers from the AIO stack again. Here is how to do this.
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
> [!WARNING]
|
||||
> The Stalwart server is under development.
|
||||
> [!CAUTION]
|
||||
> Be aware that the mail server is the most difficult service to deploy.
|
||||
>
|
||||
> The stability of Stalwart services is not guaranteed.
|
||||
> Do not use this feature as a main mail server without a redundancy system and without knowledge.
|
||||
>
|
||||
> To learn or use as a secondary server enjoy it and please report bugs at [docjyj/aio-stalwart](https://github.com/docjyj/aio-stalwart/issues).
|
||||
> Do not use this feature as a main mail server or without a redundancy system and without knowledge.
|
||||
|
||||
## Stalwart mail server
|
||||
This container bundles stalwart mail server and auto-configures it for you.
|
||||
|
||||
### Notes
|
||||
- This is only intended to run on a VPS with static ip-address.
|
||||
- Check with `sudo netstat -tulpn` that no other service is using port 25, 143, 465, 587, 993 nor 4190 yet as otherwise the container will fail to start.
|
||||
- You need to configure a reverse proxy in order to run this container since stalwart needs a dedicated (sub)domain! For that, you might have a look at https://github.com/nextcloud/all-in-one/tree/main/community-containers/caddy.
|
||||
- Currently, only `mail.$NC_DOMAIN` is supported as subdomain! So if Nextcloud is using `your-domain.com`, Stalwart will use `mail.your-domain.com`.
|
||||
- The data of Stalwart will be automatically included in AIOs backup solution!
|
||||
- After adding and starting the container, you need to run `docker inspect nextcloud-aio-stalwart | grep STALWART_USER_PASS` to obtain the system administrator password (username: `admin`). With this information, you can log in to the web interface at `https://mail.your-domain.com/login`
|
||||
- See https://stalw.art/docs/install/docker/ for next steps.
|
||||
- Additionally, you might want to install and configure [snappymail](https://apps.nextcloud.com/apps/snappymail) or [mail](https://apps.nextcloud.com/apps/mail) inside Nextcloud in order to use your mail accounts for sending and retrieving mails.
|
||||
Documentation is available on the container repository.
|
||||
This documentation is regularly updated and is intended to be as simple and detailed as possible.
|
||||
Thanks for all your feedback!
|
||||
|
||||
- See https://github.com/docjyJ/aio-stalwart#getting-started for getting start with this container.
|
||||
- See https://stalw.art/docs/faq for further faq and docs on the project
|
||||
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
> [!NOTE]
|
||||
> Unless the starting script tells you, you have no action to do to update.
|
||||
|
||||
# UPGRADING
|
||||
|
||||
During a major server update, this message will be displayed:
|
||||
|
||||
> Your data is in an old format.
|
||||
>
|
||||
> Make a backup and see https://github.com/nextcloud/all-in-one/blob/main/community-containers/stalwart/upgrading.md
|
||||
>
|
||||
> To avoid any loss of data, Stalwart will not launch.
|
||||
|
||||
If there is no update, delete the `/opt/stalwart-mail/aio.lock` file from the container. Beware of data loss.
|
||||
|
||||
See https://github.com/stalwartlabs/mail-server/blob/main/UPGRADING.md
|
||||
|
||||
> [!CAUTION]
|
||||
> Before each update don't forget to make a backup.
|
||||
|
||||
## Upgrading from 0.7.x to 0.8.x
|
||||
|
||||
Before upgrading, do a backup of your data !
|
||||
|
||||
```bash
|
||||
sudo docker run --rm -v nextcloud_aio_stalwart:/opt/stalwart-mail -it --entrypoint /usr/local/bin/stalwart-mail stalwartlabs/mail-server:v0.7.3 --config /opt/stalwart-mail/etc/config.toml --export /opt/stalwart-mail/export
|
||||
sudo docker run --rm -v nextcloud_aio_stalwart:/opt/stalwart-mail -it --entrypoint /usr/local/bin/stalwart-mail stalwartlabs/mail-server:v0.8.0 --config /opt/stalwart-mail/etc/config.toml --import /opt/stalwart-mail/export
|
||||
sudo docker run --rm -v nextcloud_aio_stalwart:/opt/stalwart-mail -it --entrypoint /bin/rm alpine /opt/stalwart-mail/aio.lock
|
||||
```
|
||||
@@ -27,23 +27,23 @@ Then copy the sample.conf to default environment file, e.g. `cp sample.conf .env
|
||||
|
||||
Now copy the provided yaml file to a compose.yaml file by running `cp latest.yml compose.yaml`.
|
||||
|
||||
Now you should be ready to go with `sudo docker-compose up`.
|
||||
Now you should be ready to go with `sudo docker compose up`.
|
||||
|
||||
## Docker profiles
|
||||
The default profile of `latest.yml` only provide the minimum necessary services: nextcloud, database, redis and apache. To get optional services collabora, talk, talk-recording, clamav, imaginary or fulltextsearch use additional arguments for each of them, for example `--profile collabora`. (Note: there is no clamav image for arm64).
|
||||
The default profile of `latest.yml` only provide the minimum necessary services: nextcloud, database, redis and apache. To get optional services collabora, talk, whiteboard, talk-recording, clamav, imaginary or fulltextsearch use additional arguments for each of them, for example `--profile collabora`. (Note: there is no clamav image for arm64).
|
||||
|
||||
For a complete all-in-one with collabora use `sudo docker-compose --profile collabora --profile talk --profile talk-recording --profile clamav --profile imaginary --profile fulltextsearch up`. (Note: there is no clamav image for arm64).
|
||||
For a complete all-in-one with collabora use `sudo docker compose --profile collabora --profile talk --profile talk-recording --profile clamav --profile imaginary --profile fulltextsearch --profile whiteboard up`. (Note: there is no clamav image for arm64).
|
||||
|
||||
## How to update?
|
||||
Since the AIO containers may change in the future, it is highly recommended to strictly follow the following procedure whenever you want to upgrade your containers.
|
||||
1. If your previous copy of `sample.conf` is named `my.conf`, run `mv -vn my.conf .env` in order to rename the file to `.env`.
|
||||
1. Run `sudo docker-compose down` to stop all running containers
|
||||
1. Run `sudo docker compose down` to stop all running containers
|
||||
1. Back up all important files and folders
|
||||
1. If your compose file is still named `docker-compose.yml` rename it to `compose.yaml` by running `mv -vn docker-compose.yml compose.yaml`
|
||||
1. Run `git pull` in order to get the updated yaml files from the repository. Now bring your `compose.yaml` file up-to-date with the updated one from the repository. You can use `diff compose.yaml latest.yml` for comparing. ⚠️ **Please note**: Starting with AIO v5.1.0, ipv6 networking will be enabled by default, so make sure to either enable it first by following steps 1 and 2 of https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md and then proceed with the steps below or disable ipv6 networking by editing the compose.yaml file and removing ipv6 from the network.
|
||||
1. Also have a look at the `sample.conf` if any variable was added or renamed and add that to your conf file as well. Here may help the diff command as well.
|
||||
1. After the file update was successful, simply run `sudo docker-compose pull` to pull the new images.
|
||||
1. At the end run `sudo docker-compose up` in order to start and update the containers with the new configuration.
|
||||
1. After the file update was successful, simply run `sudo docker compose pull` to pull the new images.
|
||||
1. At the end run `sudo docker compose up` in order to start and update the containers with the new configuration.
|
||||
|
||||
## FAQ
|
||||
### Backup and restore?
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
There are basically three ways how to migrate from an already existing Nextcloud installation to Nextcloud AIO:
|
||||
|
||||
1. Migrate only the files which is the easiest way
|
||||
1. Migrate only the files which is the easiest way (this excludes all calendar data for example)
|
||||
1. Migrate the files and the database which is much more complicated (and doesn't work on former snap installations)
|
||||
1. Use the user_migration app that allows to migrate some of the user's data from a former instance to a new instance but needs to be done manually for each user
|
||||
|
||||
## Migrate only the files
|
||||
**Please note**: If you used groupfolders or encrypted your files before, you will need to restore the database, as well!
|
||||
**Please note**: If you used groupfolders or encrypted your files before, you will need to restore the database, as well! (This will also exclude all calendar data for example).
|
||||
|
||||
The procedure for migrating only the files works like this:
|
||||
1. Take a backup of your former instance (especially from your datadirectory, see `'datadirectory'` in your `config.php`)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: nextcloud-aio-helm-chart
|
||||
description: A generated Helm Chart for Nextcloud AIO from Skippbox Kompose
|
||||
version: 9.3.0
|
||||
version: 9.5.1
|
||||
apiVersion: v2
|
||||
keywords:
|
||||
- latest
|
||||
|
||||
@@ -25,11 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -66,7 +62,7 @@ spec:
|
||||
value: nextcloud-aio-talk
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-apache:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-apache:20240914_063340"
|
||||
name: nextcloud-aio-apache
|
||||
ports:
|
||||
- containerPort: {{ .Values.APACHE_PORT }}
|
||||
|
||||
@@ -26,11 +26,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
@@ -40,11 +36,7 @@ spec:
|
||||
- name: nextcloud-aio-clamav
|
||||
mountPath: /nextcloud-aio-clamav
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chown
|
||||
- 100:100
|
||||
@@ -61,7 +53,7 @@ spec:
|
||||
value: "{{ .Values.NEXTCLOUD_UPLOAD_LIMIT }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-clamav:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-clamav:20240914_063340"
|
||||
name: nextcloud-aio-clamav
|
||||
ports:
|
||||
- containerPort: 3310
|
||||
|
||||
@@ -36,7 +36,7 @@ spec:
|
||||
value: --o:ssl.enable=false --o:ssl.termination=true --o:mount_jail_tree=false --o:logging.level=warning --o:home_mode.enable=true {{ .Values.COLLABORA_SECCOMP_POLICY }} --o:remote_font_config.url=https://{{ .Values.NC_DOMAIN }}/apps/richdocuments/settings/fonts.json
|
||||
- name: server_name
|
||||
value: "{{ .Values.NC_DOMAIN }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-collabora:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-collabora:20240914_063340"
|
||||
name: nextcloud-aio-collabora
|
||||
ports:
|
||||
- containerPort: 9980
|
||||
|
||||
@@ -25,11 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
@@ -42,11 +38,7 @@ spec:
|
||||
- name: nextcloud-aio-database
|
||||
mountPath: /nextcloud-aio-database
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chown
|
||||
- 999:999
|
||||
@@ -70,7 +62,7 @@ spec:
|
||||
value: nextcloud
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-postgresql:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-postgresql:20240914_063340"
|
||||
name: nextcloud-aio-database
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
|
||||
@@ -26,11 +26,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -60,7 +56,7 @@ spec:
|
||||
value: basic
|
||||
- name: xpack.security.enabled
|
||||
value: "false"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-fulltextsearch:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-fulltextsearch:20240914_063340"
|
||||
name: nextcloud-aio-fulltextsearch
|
||||
ports:
|
||||
- containerPort: 9200
|
||||
|
||||
@@ -28,7 +28,7 @@ spec:
|
||||
value: "{{ .Values.IMAGINARY_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-imaginary:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-imaginary:20240914_063340"
|
||||
name: nextcloud-aio-imaginary
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
|
||||
@@ -25,11 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: "delete-lost-found"
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- rm
|
||||
- "-rf"
|
||||
@@ -40,11 +36,7 @@ spec:
|
||||
- name: nextcloud-aio-nextcloud
|
||||
mountPath: /nextcloud-aio-nextcloud
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -85,6 +77,8 @@ spec:
|
||||
value: "{{ .Values.SERVERINFO_TOKEN }}"
|
||||
- name: NEXTCLOUD_DEFAULT_QUOTA
|
||||
value: "{{ .Values.NEXTCLOUD_DEFAULT_QUOTA }}"
|
||||
- name: NEXTCLOUD_MAINTENANCE_WINDOW
|
||||
value: "{{ .Values.NEXTCLOUD_MAINTENANCE_WINDOW }}"
|
||||
- name: ADDITIONAL_APKS
|
||||
value: "{{ .Values.NEXTCLOUD_ADDITIONAL_APKS }}"
|
||||
- name: ADDITIONAL_PHP_EXTENSIONS
|
||||
@@ -175,7 +169,7 @@ spec:
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
- name: UPDATE_NEXTCLOUD_APPS
|
||||
value: "{{ .Values.UPDATE_NEXTCLOUD_APPS }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-nextcloud:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-nextcloud:20240914_063340"
|
||||
name: nextcloud-aio-nextcloud
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
|
||||
@@ -25,11 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -57,7 +53,7 @@ spec:
|
||||
value: nextcloud-aio-redis
|
||||
- name: REDIS_HOST_PASSWORD
|
||||
value: "{{ .Values.REDIS_PASSWORD }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-notify-push:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-notify-push:20240914_063340"
|
||||
name: nextcloud-aio-notify-push
|
||||
ports:
|
||||
- containerPort: 7867
|
||||
|
||||
@@ -26,11 +26,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -48,7 +44,7 @@ spec:
|
||||
value: "{{ .Values.ONLYOFFICE_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-onlyoffice:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-onlyoffice:20240914_063340"
|
||||
name: nextcloud-aio-onlyoffice
|
||||
ports:
|
||||
- containerPort: 80
|
||||
|
||||
@@ -25,11 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -43,7 +39,7 @@ spec:
|
||||
value: "{{ .Values.REDIS_PASSWORD }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-redis:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-redis:20240914_063340"
|
||||
name: nextcloud-aio-redis
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
|
||||
@@ -42,7 +42,7 @@ spec:
|
||||
value: "{{ .Values.TURN_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-talk:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-talk:20240914_063340"
|
||||
name: nextcloud-aio-talk
|
||||
ports:
|
||||
- containerPort: {{ .Values.TALK_PORT }}
|
||||
|
||||
@@ -32,7 +32,7 @@ spec:
|
||||
value: "{{ .Values.RECORDING_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-talk-recording:20240725_074330"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-talk-recording:20240914_063340"
|
||||
name: nextcloud-aio-talk-recording
|
||||
ports:
|
||||
- containerPort: 1234
|
||||
|
||||
@@ -59,11 +59,7 @@ find ./ -name '*networkpolicy.yaml' -exec sed -i "s|manual-install-nextcloud-aio
|
||||
cat << EOL > /tmp/initcontainers
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -72,22 +68,14 @@ EOL
|
||||
cat << EOL > /tmp/initcontainers.database
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
- /nextcloud-aio-database/data
|
||||
volumeMountsInitContainer:
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chown
|
||||
- 999:999
|
||||
@@ -97,22 +85,14 @@ EOL
|
||||
cat << EOL > /tmp/initcontainers.clamav
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
- /nextcloud-aio-clamav/data
|
||||
volumeMountsInitContainer:
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chown
|
||||
- 100:100
|
||||
@@ -122,22 +102,14 @@ EOL
|
||||
cat << EOL > /tmp/initcontainers.nextcloud
|
||||
initContainers:
|
||||
- name: "delete-lost-found"
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- rm
|
||||
- "-rf"
|
||||
- "/nextcloud-aio-nextcloud/lost+found"
|
||||
volumeMountsInitRmLostFound:
|
||||
- name: init-volumes
|
||||
{{- if or .Values.IMAGE_MIRROR_PREFIX .Values.ALPINE_IMAGE_ORG }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG}}/alpine"
|
||||
{{- else }}
|
||||
image: alpine
|
||||
{{- end }}
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -399,9 +371,9 @@ MAIL_DOMAIN: # (not set by default): Set a different domain for the emai
|
||||
TALK_MAX_STREAM_BITRATE: "1048576" # This allows to adjust the max stream bitrate of the talk hpb
|
||||
TALK_MAX_SCREEN_BITRATE: "2097152" # This allows to adjust the max stream bitrate of the talk hpb
|
||||
|
||||
IMAGE_MIRROR_PREFIX: # Setting this allows you to pull Nextcloud images through a mirror registry.
|
||||
IMAGE_MIRROR_PREFIX: # Setting this allows you to pull Nextcloud images through a mirror registry. It needs a trailing slash!
|
||||
NEXTCLOUD_IMAGE_ORG: nextcloud # Setting this allows you to change the image's org name in case a different image needs to be used e.g. for compliance reasons.
|
||||
ALPINE_IMAGE_ORG: # Setting this allows you to change the image's org name in case a different image needs to be used e.g. for compliance reasons.
|
||||
ALPINE_IMAGE_ORG: # Setting this allows you to change the image's org name in case a different image needs to be used e.g. for compliance reasons. It needs a trailing slash!
|
||||
ADDITIONAL_CONFIG
|
||||
|
||||
mv /tmp/sample.conf ../helm-chart/values.yaml
|
||||
|
||||
@@ -56,6 +56,7 @@ APPS_ALLOWLIST: # This allows to configure allowed apps that will be show
|
||||
ADDITIONAL_TRUSTED_PROXY: # Allows to add one additional ip-address to Nextcloud's trusted proxies and to the Office WOPI-allowlist automatically. Set it e.g. like this: 'your.public.ip-address'. You can also use an ip-range here.
|
||||
ADDITIONAL_TRUSTED_DOMAIN: # Allows to add one domain to Nextcloud's trusted domains and also generates a certificate automatically for it
|
||||
NEXTCLOUD_DEFAULT_QUOTA: "10 GB" # Allows to adjust the default quota that will be taken into account in Nextcloud for new users. Setting it to "unlimited" will set it to unlimited
|
||||
NEXTCLOUD_MAINTENANCE_WINDOW: # Allows to define the maintenance window for Nextcloud. See https://docs.nextcloud.com/server/stable/admin_manual/configuration_server/background_jobs_configuration.html#parameters for possible values
|
||||
SMTP_HOST: # (empty by default): The hostname of the SMTP server.
|
||||
SMTP_SECURE: # (empty by default): Set to 'ssl' to use SSL, or 'tls' to use STARTTLS.
|
||||
SMTP_PORT: # (default: '465' for SSL and '25' for non-secure connections): Optional port for the SMTP connection. Use '587' for an alternative port for STARTTLS.
|
||||
@@ -67,6 +68,6 @@ MAIL_DOMAIN: # (not set by default): Set a different domain for the emai
|
||||
TALK_MAX_STREAM_BITRATE: "1048576" # This allows to adjust the max stream bitrate of the talk hpb
|
||||
TALK_MAX_SCREEN_BITRATE: "2097152" # This allows to adjust the max stream bitrate of the talk hpb
|
||||
|
||||
IMAGE_MIRROR_PREFIX: # Setting this allows you to pull Nextcloud images through a mirror registry.
|
||||
IMAGE_MIRROR_PREFIX: # Setting this allows you to pull Nextcloud images through a mirror registry. It needs a trailing slash!
|
||||
NEXTCLOUD_IMAGE_ORG: nextcloud # Setting this allows you to change the image's org name in case a different image needs to be used e.g. for compliance reasons.
|
||||
ALPINE_IMAGE_ORG: # Setting this allows you to change the image's org name in case a different image needs to be used e.g. for compliance reasons.
|
||||
ALPINE_IMAGE_ORG: # Setting this allows you to change the image's org name in case a different image needs to be used e.g. for compliance reasons. It needs a trailing slash!
|
||||
|
||||
317
php/composer.lock
generated
317
php/composer.lock
generated
@@ -391,26 +391,27 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
"version": "v1.3.3",
|
||||
"version": "v1.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/serializable-closure.git",
|
||||
"reference": "3dbf8a8e914634c48d389c1234552666b3d43754"
|
||||
"reference": "61b87392d986dc49ad5ef64e75b1ff5fee24ef81"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754",
|
||||
"reference": "3dbf8a8e914634c48d389c1234552666b3d43754",
|
||||
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/61b87392d986dc49ad5ef64e75b1ff5fee24ef81",
|
||||
"reference": "61b87392d986dc49ad5ef64e75b1ff5fee24ef81",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nesbot/carbon": "^2.61",
|
||||
"illuminate/support": "^8.0|^9.0|^10.0|^11.0",
|
||||
"nesbot/carbon": "^2.61|^3.0",
|
||||
"pestphp/pest": "^1.21.3",
|
||||
"phpstan/phpstan": "^1.8.2",
|
||||
"symfony/var-dumper": "^5.4.11"
|
||||
"symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -447,7 +448,7 @@
|
||||
"issues": "https://github.com/laravel/serializable-closure/issues",
|
||||
"source": "https://github.com/laravel/serializable-closure"
|
||||
},
|
||||
"time": "2023-11-08T14:08:06+00:00"
|
||||
"time": "2024-08-02T07:48:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
@@ -996,16 +997,16 @@
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
|
||||
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
|
||||
"reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1040,9 +1041,9 @@
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/log/tree/3.0.0"
|
||||
"source": "https://github.com/php-fig/log/tree/3.0.2"
|
||||
},
|
||||
"time": "2021-07-14T16:46:02+00:00"
|
||||
"time": "2024-09-11T13:17:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
@@ -1396,20 +1397,20 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540"
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
|
||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
@@ -1455,7 +1456,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1471,24 +1472,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c"
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
@@ -1535,7 +1536,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1551,104 +1552,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-19T12:30:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433",
|
||||
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php80\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ion Bazan",
|
||||
"email": "ion.bazan@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
"reference": "3fb075789fb91f9ad9af537c4012d523085bd5af"
|
||||
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/3fb075789fb91f9ad9af537c4012d523085bd5af",
|
||||
"reference": "3fb075789fb91f9ad9af537c4012d523085bd5af",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
|
||||
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -1691,7 +1612,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1707,28 +1628,28 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-19T12:30:46+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.10.3",
|
||||
"version": "v3.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "67f29781ffafa520b0bbfbd8384674b42db04572"
|
||||
"reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/67f29781ffafa520b0bbfbd8384674b42db04572",
|
||||
"reference": "67f29781ffafa520b0bbfbd8384674b42db04572",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
|
||||
"reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"php": ">=8.0.2",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-ctype": "^1.8",
|
||||
"symfony/polyfill-mbstring": "^1.3",
|
||||
"symfony/polyfill-php80": "^1.22"
|
||||
"symfony/polyfill-php81": "^1.29"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/container": "^1.0|^2.0",
|
||||
@@ -1774,7 +1695,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.10.3"
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.14.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1786,7 +1707,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-16T10:04:27+00:00"
|
||||
"time": "2024-09-09T17:55:12+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@@ -2025,26 +1946,26 @@
|
||||
},
|
||||
{
|
||||
"name": "composer/pcre",
|
||||
"version": "3.2.0",
|
||||
"version": "3.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/pcre.git",
|
||||
"reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90"
|
||||
"reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
|
||||
"reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4",
|
||||
"reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan": "<1.11.8"
|
||||
"phpstan/phpstan": "<1.11.10"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.11.8",
|
||||
"phpstan/phpstan": "^1.11.10",
|
||||
"phpstan/phpstan-strict-rules": "^1.1",
|
||||
"phpunit/phpunit": "^8 || ^9"
|
||||
},
|
||||
@@ -2084,7 +2005,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/pcre/issues",
|
||||
"source": "https://github.com/composer/pcre/tree/3.2.0"
|
||||
"source": "https://github.com/composer/pcre/tree/3.3.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2100,7 +2021,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-25T09:36:02+00:00"
|
||||
"time": "2024-08-27T18:44:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
@@ -2436,16 +2357,16 @@
|
||||
},
|
||||
{
|
||||
"name": "fidry/cpu-core-counter",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theofidry/cpu-core-counter.git",
|
||||
"reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42"
|
||||
"reference": "8520451a140d3f46ac33042715115e290cf5785f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42",
|
||||
"reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42",
|
||||
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f",
|
||||
"reference": "8520451a140d3f46ac33042715115e290cf5785f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2485,7 +2406,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/theofidry/cpu-core-counter/issues",
|
||||
"source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0"
|
||||
"source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2493,20 +2414,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-02-07T09:43:46+00:00"
|
||||
"time": "2024-08-06T10:04:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
"version": "v4.4.1",
|
||||
"version": "v4.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cweiske/jsonmapper.git",
|
||||
"reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0"
|
||||
"reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0",
|
||||
"reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8e76efb98ee8b6afc54687045e1b8dba55ac76e5",
|
||||
"reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2542,22 +2463,22 @@
|
||||
"support": {
|
||||
"email": "cweiske@cweiske.de",
|
||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1"
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.5.0"
|
||||
},
|
||||
"time": "2024-01-31T06:18:54+00:00"
|
||||
"time": "2024-09-08T10:13:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.19.1",
|
||||
"version": "v4.19.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "4e1b88d21c69391150ace211e9eaf05810858d0b"
|
||||
"reference": "0ed4c8949a32986043e977dbe14776c14d644c45"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b",
|
||||
"reference": "4e1b88d21c69391150ace211e9eaf05810858d0b",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ed4c8949a32986043e977dbe14776c14d644c45",
|
||||
"reference": "0ed4c8949a32986043e977dbe14776c14d644c45",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2598,9 +2519,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.2"
|
||||
},
|
||||
"time": "2024-03-17T08:10:35+00:00"
|
||||
"time": "2024-09-17T19:36:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
@@ -2779,16 +2700,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
"version": "1.29.1",
|
||||
"version": "1.30.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||
"reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4"
|
||||
"reference": "51b95ec8670af41009e2b2b56873bad96682413e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4",
|
||||
"reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/51b95ec8670af41009e2b2b56873bad96682413e",
|
||||
"reference": "51b95ec8670af41009e2b2b56873bad96682413e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2820,9 +2741,9 @@
|
||||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1"
|
||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.30.1"
|
||||
},
|
||||
"time": "2024-05-31T08:52:43+00:00"
|
||||
"time": "2024-09-07T20:13:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
@@ -2965,12 +2886,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sserbin/twig-linter.git",
|
||||
"reference": "0b7cc4d61b6cf423ec837a0969ea5e0c8f017ddb"
|
||||
"reference": "c4cb0d08c8290d8fed541eb027bd85dba90a5914"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sserbin/twig-linter/zipball/0b7cc4d61b6cf423ec837a0969ea5e0c8f017ddb",
|
||||
"reference": "0b7cc4d61b6cf423ec837a0969ea5e0c8f017ddb",
|
||||
"url": "https://api.github.com/repos/sserbin/twig-linter/zipball/c4cb0d08c8290d8fed541eb027bd85dba90a5914",
|
||||
"reference": "c4cb0d08c8290d8fed541eb027bd85dba90a5914",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2983,7 +2904,7 @@
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7.3||^8.2|^9.5",
|
||||
"squizlabs/php_codesniffer": "^3.3",
|
||||
"vimeo/psalm": "^4.7"
|
||||
"vimeo/psalm": "^4.7 || ^5.8"
|
||||
},
|
||||
"default-branch": true,
|
||||
"bin": [
|
||||
@@ -3013,22 +2934,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sserbin/twig-linter/issues",
|
||||
"source": "https://github.com/sserbin/twig-linter/tree/3.1.0"
|
||||
"source": "https://github.com/sserbin/twig-linter/tree/3.1.1"
|
||||
},
|
||||
"time": "2022-06-29T11:06:19+00:00"
|
||||
"time": "2024-09-09T16:51:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.4.10",
|
||||
"version": "v6.4.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc"
|
||||
"reference": "42686880adaacdad1835ee8fc2a9ec5b7bd63998"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/504974cbe43d05f83b201d6498c206f16fc0cdbc",
|
||||
"reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/42686880adaacdad1835ee8fc2a9ec5b7bd63998",
|
||||
"reference": "42686880adaacdad1835ee8fc2a9ec5b7bd63998",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3093,7 +3014,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v6.4.10"
|
||||
"source": "https://github.com/symfony/console/tree/v6.4.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3109,7 +3030,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-26T12:30:32+00:00"
|
||||
"time": "2024-08-15T22:48:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
@@ -3179,16 +3100,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v6.4.10",
|
||||
"version": "v6.4.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "af29198d87112bebdd397bd7735fbd115997824c"
|
||||
"reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/af29198d87112bebdd397bd7735fbd115997824c",
|
||||
"reference": "af29198d87112bebdd397bd7735fbd115997824c",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/d7eb6daf8cd7e9ac4976e9576b32042ef7253453",
|
||||
"reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3223,7 +3144,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v6.4.10"
|
||||
"source": "https://github.com/symfony/finder/tree/v6.4.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3239,24 +3160,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-24T07:06:38+00:00"
|
||||
"time": "2024-08-13T14:27:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a"
|
||||
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a",
|
||||
"reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
|
||||
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
@@ -3301,7 +3222,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3317,24 +3238,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb"
|
||||
"reference": "3833d7255cc303546435cb650316bff708a1c75c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb",
|
||||
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
|
||||
"reference": "3833d7255cc303546435cb650316bff708a1c75c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
@@ -3382,7 +3303,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3398,7 +3319,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
@@ -3485,16 +3406,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v7.1.3",
|
||||
"version": "v7.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "ea272a882be7f20cad58d5d78c215001617b7f07"
|
||||
"reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/ea272a882be7f20cad58d5d78c215001617b7f07",
|
||||
"reference": "ea272a882be7f20cad58d5d78c215001617b7f07",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/6cd670a6d968eaeb1c77c2e76091c45c56bc367b",
|
||||
"reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3552,7 +3473,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v7.1.3"
|
||||
"source": "https://github.com/symfony/string/tree/v7.1.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3568,20 +3489,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-22T10:25:37+00:00"
|
||||
"time": "2024-08-12T09:59:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vimeo/psalm",
|
||||
"version": "5.25.0",
|
||||
"version": "5.26.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vimeo/psalm.git",
|
||||
"reference": "01a8eb06b9e9cc6cfb6a320bf9fb14331919d505"
|
||||
"reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vimeo/psalm/zipball/01a8eb06b9e9cc6cfb6a320bf9fb14331919d505",
|
||||
"reference": "01a8eb06b9e9cc6cfb6a320bf9fb14331919d505",
|
||||
"url": "https://api.github.com/repos/vimeo/psalm/zipball/d747f6500b38ac4f7dfc5edbcae6e4b637d7add0",
|
||||
"reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3602,7 +3523,7 @@
|
||||
"felixfbecker/language-server-protocol": "^1.5.2",
|
||||
"fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0",
|
||||
"netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
|
||||
"nikic/php-parser": "^4.16",
|
||||
"nikic/php-parser": "^4.17",
|
||||
"php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0",
|
||||
"sebastian/diff": "^4.0 || ^5.0 || ^6.0",
|
||||
"spatie/array-to-xml": "^2.17.0 || ^3.0",
|
||||
@@ -3678,7 +3599,7 @@
|
||||
"issues": "https://github.com/vimeo/psalm/issues",
|
||||
"source": "https://github.com/vimeo/psalm"
|
||||
},
|
||||
"time": "2024-06-16T15:08:35+00:00"
|
||||
"time": "2024-09-08T18:53:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "wapmorgan/php-deprecation-detector",
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"nextcloud-aio-collabora",
|
||||
"nextcloud-aio-talk",
|
||||
"nextcloud-aio-nextcloud",
|
||||
"nextcloud-aio-notify-push"
|
||||
"nextcloud-aio-notify-push",
|
||||
"nextcloud-aio-whiteboard"
|
||||
],
|
||||
"display_name": "Apache",
|
||||
"image": "nextcloud/aio-apache",
|
||||
@@ -37,7 +38,8 @@
|
||||
"TZ=%TIMEZONE%",
|
||||
"APACHE_MAX_SIZE=%APACHE_MAX_SIZE%",
|
||||
"APACHE_MAX_TIME=%NEXTCLOUD_MAX_TIME%",
|
||||
"NOTIFY_PUSH_HOST=nextcloud-aio-notify-push"
|
||||
"NOTIFY_PUSH_HOST=nextcloud-aio-notify-push",
|
||||
"WHITEBOARD_HOST=nextcloud-aio-whiteboard"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -148,7 +150,8 @@
|
||||
"TURN_SECRET",
|
||||
"SIGNALING_SECRET",
|
||||
"FULLTEXTSEARCH_PASSWORD",
|
||||
"IMAGINARY_SECRET"
|
||||
"IMAGINARY_SECRET",
|
||||
"WHITEBOARD_SECRET"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -224,7 +227,9 @@
|
||||
"APACHE_PORT=%APACHE_PORT%",
|
||||
"ADDITIONAL_TRUSTED_PROXY=%CADDY_IP_ADDRESS%",
|
||||
"THIS_IS_AIO=true",
|
||||
"IMAGINARY_SECRET=%IMAGINARY_SECRET%"
|
||||
"IMAGINARY_SECRET=%IMAGINARY_SECRET%",
|
||||
"WHITEBOARD_SECRET=%WHITEBOARD_SECRET%",
|
||||
"WHITEBOARD_ENABLED=%WHITEBOARD_ENABLED%"
|
||||
],
|
||||
"stop_grace_period": 600,
|
||||
"restart": "unless-stopped",
|
||||
@@ -746,6 +751,40 @@
|
||||
"cap_drop": [
|
||||
"NET_RAW"
|
||||
]
|
||||
},
|
||||
{
|
||||
"container_name": "nextcloud-aio-whiteboard",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Whiteboard",
|
||||
"image": "nextcloud/aio-whiteboard",
|
||||
"init": true,
|
||||
"expose": [
|
||||
"3002"
|
||||
],
|
||||
"internal_port": "3002",
|
||||
"environment": [
|
||||
"TZ=%TIMEZONE%",
|
||||
"NEXTCLOUD_URL=https://%NC_DOMAIN%",
|
||||
"JWT_SECRET_KEY=%WHITEBOARD_SECRET%",
|
||||
"STORAGE_STRATEGY=redis",
|
||||
"REDIS_HOST=nextcloud-aio-redis",
|
||||
"REDIS_HOST_PASSWORD=%REDIS_PASSWORD%"
|
||||
],
|
||||
"secrets": [
|
||||
"WHITEBOARD_SECRET",
|
||||
"REDIS_PASSWORD"
|
||||
],
|
||||
"restart": "unless-stopped",
|
||||
"profiles": [
|
||||
"whiteboard"
|
||||
],
|
||||
"read_only": true,
|
||||
"networks": [
|
||||
"nextcloud-aio"
|
||||
],
|
||||
"cap_drop": [
|
||||
"NET_RAW"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="5.25.0@01a8eb06b9e9cc6cfb6a320bf9fb14331919d505"/>
|
||||
<files psalm-version="5.26.1@d747f6500b38ac4f7dfc5edbcae6e4b637d7add0"/>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0"?>
|
||||
<psalm
|
||||
errorLevel="2"
|
||||
resolveFromConfigFile="true"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="https://getpsalm.org/schema/config"
|
||||
xsi:schemaLocation="https://getpsalm.org/schema/config"
|
||||
errorLevel="2"
|
||||
resolveFromConfigFile="true"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="https://getpsalm.org/schema/config"
|
||||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
||||
errorBaseline="psalm-baseline.xml"
|
||||
findUnusedBaselineEntry="true"
|
||||
findUnusedCode="false"
|
||||
findUnusedBaselineEntry="true"
|
||||
findUnusedCode="false"
|
||||
>
|
||||
<projectFiles>
|
||||
<directory name="templates"/>
|
||||
<directory name="src"/>
|
||||
<file name="public/index.php"/>
|
||||
</projectFiles>
|
||||
<projectFiles>
|
||||
<directory name="templates"/>
|
||||
<directory name="src"/>
|
||||
<file name="public/index.php"/>
|
||||
</projectFiles>
|
||||
</psalm>
|
||||
|
||||
5
php/public/disable-whiteboard.js
Normal file
5
php/public/disable-whiteboard.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Whiteboard
|
||||
let whiteboard = document.getElementById("whiteboard");
|
||||
whiteboard.disabled = true;
|
||||
});
|
||||
BIN
php/public/img/Background_Light.jpg
Normal file
BIN
php/public/img/Background_Light.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 661 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB |
@@ -125,6 +125,7 @@ $app->get('/containers', function (Request $request, Response $response, array $
|
||||
'is_dri_device_enabled' => $configurationManager->isDriDeviceEnabled(),
|
||||
'is_talk_recording_enabled' => $configurationManager->isTalkRecordingEnabled(),
|
||||
'is_docker_socket_proxy_enabled' => $configurationManager->isDockerSocketProxyEnabled(),
|
||||
'is_whiteboard_enabled' => $configurationManager->isWhiteboardEnabled(),
|
||||
]);
|
||||
})->setName('profile');
|
||||
$app->get('/login', function (Request $request, Response $response, array $args) use ($container) {
|
||||
|
||||
@@ -66,4 +66,8 @@ document.addEventListener("DOMContentLoaded", function(event) {
|
||||
dockerSocketProxy.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
// dockerSocketProxy.addEventListener('change', handleDockerSocketProxyWarning);
|
||||
}
|
||||
|
||||
// Whiteboard
|
||||
let whiteboard = document.getElementById("whiteboard");
|
||||
whiteboard.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
});
|
||||
|
||||
@@ -9,28 +9,25 @@ a {
|
||||
color: #0082c9;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 6px 16px;
|
||||
a.button,
|
||||
input[type="submit"] {
|
||||
padding: 8px 16px;
|
||||
width: auto;
|
||||
min-height: 34px;
|
||||
height: 34px;
|
||||
cursor: pointer;
|
||||
background-color:#0082c9;
|
||||
background-color: #0082c9;
|
||||
font-weight: bold;
|
||||
border-radius: 100px;
|
||||
border-radius: 8px;
|
||||
margin: 3px 3px 3px 0;
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
border: 1px solid black;
|
||||
border: .5px solid black;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button:focus {
|
||||
color:black;
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
#logout {
|
||||
margin-top: 7px;
|
||||
a.button:focus,
|
||||
input[type="submit"]:focus {
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
summary {
|
||||
@@ -88,8 +85,7 @@ div.toast {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
border-radius: 3px;
|
||||
background: none;
|
||||
background-color: white;
|
||||
background: white none;
|
||||
}
|
||||
|
||||
.login {
|
||||
@@ -100,7 +96,7 @@ div.toast {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 16px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.login > .monospace {
|
||||
@@ -108,12 +104,36 @@ div.toast {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 10px;
|
||||
margin-bottom: 15px;
|
||||
form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.login > form > input {
|
||||
input[type="text"],
|
||||
input[type="password"],
|
||||
select {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
height: 34px;
|
||||
margin-bottom: 15px;
|
||||
border-radius: 8px;
|
||||
border: .5px solid black;
|
||||
}
|
||||
|
||||
textarea {
|
||||
border-radius: 8px;
|
||||
border: .5px solid black;
|
||||
}
|
||||
|
||||
input[type="text"]:focus,
|
||||
input[type="password"]:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.login > form > input[type="password"],
|
||||
.login > form > input[type="text"],
|
||||
.login > form > input[type="submit"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -123,30 +143,30 @@ input {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.login > .button {
|
||||
.login a.button,
|
||||
.login input[type="submit"] {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
text-align: center;
|
||||
line-height: 33px;
|
||||
margin-top: 20px;
|
||||
padding: 0px;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.login-wrapper {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #0082c9;
|
||||
background-image: linear-gradient(
|
||||
40deg
|
||||
, #0082c9 0%, #30b6ff 100%);
|
||||
background-size: contain;
|
||||
background-image: url('/img/background.png'), linear-gradient(
|
||||
40deg
|
||||
, #0082c9 0%, #30b6ff 100%);
|
||||
position: relative;
|
||||
min-height: 100dvh;
|
||||
min-width: 100vw;
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
height: auto;
|
||||
background-image: url("img/Background_Light.jpg");
|
||||
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.content {
|
||||
main {
|
||||
padding: 20px;
|
||||
max-width: 100%;
|
||||
word-break: break-word;
|
||||
@@ -173,26 +193,31 @@ header {
|
||||
background-image: linear-gradient(40deg, #0082c9 0%, #30b6ff 100%);
|
||||
height: 50px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
header > form {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
#overlay {
|
||||
position: fixed; /* Sit on top of the page content */
|
||||
display: none; /* Hidden by default */
|
||||
width: 100%; /* Full width (cover the whole page) */
|
||||
height: 100%; /* Full height (cover the whole page) */
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(0,0,0,0.5); /* Black background with opacity */
|
||||
z-index: 2;
|
||||
position: fixed; /* Sit on top of the page content */
|
||||
display: none; /* Hidden by default */
|
||||
width: 100%; /* Full width (cover the whole page) */
|
||||
height: 100%; /* Full height (cover the whole page) */
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5); /* Black background with opacity */
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#overlay.loading {
|
||||
display: block;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loader {
|
||||
@@ -206,15 +231,15 @@ header {
|
||||
position: absolute;
|
||||
top: calc(50% - 60px);
|
||||
left: calc(50% - 60px);
|
||||
}
|
||||
|
||||
/* Safari */
|
||||
@-webkit-keyframes spin {
|
||||
}
|
||||
|
||||
/* Safari */
|
||||
@-webkit-keyframes spin {
|
||||
0% { -webkit-transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,25 +4,25 @@ namespace AIO\Auth;
|
||||
|
||||
use AIO\Data\ConfigurationManager;
|
||||
use AIO\Data\DataConst;
|
||||
use \DateTime;
|
||||
use AIO\Data\InvalidSettingConfigurationException;
|
||||
use DateTime;
|
||||
|
||||
class AuthManager {
|
||||
readonly class AuthManager {
|
||||
private const string SESSION_KEY = 'aio_authenticated';
|
||||
private ConfigurationManager $configurationManager;
|
||||
|
||||
public function __construct(ConfigurationManager $configurationManager) {
|
||||
$this->configurationManager = $configurationManager;
|
||||
/** @throws InvalidSettingConfigurationException */
|
||||
public function CheckCredentials(string $password): bool {
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
return hash_equals($config->GetPassword(), $password);
|
||||
}
|
||||
|
||||
public function CheckCredentials(string $password) : bool {
|
||||
return hash_equals($this->configurationManager->GetPassword(), $password);
|
||||
/** @throws InvalidSettingConfigurationException */
|
||||
public function CheckToken(string $token): bool {
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
return hash_equals($config->GetToken(), $token);
|
||||
}
|
||||
|
||||
public function CheckToken(string $token) : bool {
|
||||
return hash_equals($this->configurationManager->GetToken(), $token);
|
||||
}
|
||||
|
||||
public function SetAuthState(bool $isLoggedIn) : void {
|
||||
public function SetAuthState(bool $isLoggedIn): void {
|
||||
|
||||
if (!$this->IsAuthenticated() && $isLoggedIn === true) {
|
||||
$date = new DateTime();
|
||||
@@ -40,7 +40,7 @@ class AuthManager {
|
||||
$_SESSION[self::SESSION_KEY] = $isLoggedIn;
|
||||
}
|
||||
|
||||
public function IsAuthenticated() : bool {
|
||||
public function IsAuthenticated(): bool {
|
||||
return isset($_SESSION[self::SESSION_KEY]) && $_SESSION[self::SESSION_KEY] === true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace AIO\Auth;
|
||||
|
||||
use AIO\Data\ConfigurationManager;
|
||||
use Random\RandomException;
|
||||
|
||||
class PasswordGenerator
|
||||
{
|
||||
private array $words = [
|
||||
class PasswordGenerator {
|
||||
|
||||
private const array WORDS = [
|
||||
'abacus',
|
||||
'abdomen',
|
||||
'abdominal',
|
||||
@@ -7785,14 +7785,16 @@ class PasswordGenerator
|
||||
'zoom',
|
||||
];
|
||||
|
||||
public function GeneratePassword(int $length) : string {
|
||||
|
||||
/** @throws RandomException */
|
||||
static function GeneratePassword(int $length): string {
|
||||
$password = '';
|
||||
|
||||
for($i = 0; $i < $length; $i ++) {
|
||||
if($password !== '') {
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
if ($password !== '') {
|
||||
$password = $password . ' ';
|
||||
}
|
||||
$password = $password . $this->words[random_int(0, 7775)];
|
||||
$password = $password . PasswordGenerator::WORDS[random_int(0, 7775)];
|
||||
}
|
||||
|
||||
return $password;
|
||||
|
||||
@@ -16,15 +16,12 @@ use AIO\Docker\DockerActionManager;
|
||||
|
||||
class ContainerDefinitionFetcher
|
||||
{
|
||||
private ConfigurationManager $configurationManager;
|
||||
private \DI\Container $container;
|
||||
|
||||
public function __construct(
|
||||
ConfigurationManager $configurationManager,
|
||||
\DI\Container $container
|
||||
)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
@@ -47,9 +44,10 @@ class ContainerDefinitionFetcher
|
||||
private function GetDefinition(): array
|
||||
{
|
||||
$data = json_decode(file_get_contents(__DIR__ . '/../containers.json'), true);
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
|
||||
$additionalContainerNames = [];
|
||||
foreach ($this->configurationManager->GetEnabledCommunityContainers() as $communityContainer) {
|
||||
foreach ($config->aioCommunityContainers as $communityContainer) {
|
||||
if ($communityContainer !== '') {
|
||||
$path = DataConst::GetCommunityContainersDirectory() . '/' . $communityContainer . '/' . $communityContainer . '.json';
|
||||
$additionalData = json_decode(file_get_contents($path), true);
|
||||
@@ -64,42 +62,46 @@ class ContainerDefinitionFetcher
|
||||
$containers = [];
|
||||
foreach ($data['aio_services_v1'] as $entry) {
|
||||
if ($entry['container_name'] === 'nextcloud-aio-clamav') {
|
||||
if (!$this->configurationManager->isClamavEnabled()) {
|
||||
if (!$config->isClamavEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-onlyoffice') {
|
||||
if (!$this->configurationManager->isOnlyofficeEnabled()) {
|
||||
if (!$config->isOnlyofficeEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-collabora') {
|
||||
if (!$this->configurationManager->isCollaboraEnabled()) {
|
||||
if (!$config->isCollaboraEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-talk') {
|
||||
if (!$this->configurationManager->isTalkEnabled()) {
|
||||
if (!$config->talkEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-talk-recording') {
|
||||
if (!$this->configurationManager->isTalkRecordingEnabled()) {
|
||||
if (!$config->isTalkRecordingEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-imaginary') {
|
||||
if (!$this->configurationManager->isImaginaryEnabled()) {
|
||||
if (!$config->imaginaryEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-fulltextsearch') {
|
||||
if (!$this->configurationManager->isFulltextsearchEnabled()) {
|
||||
if (!$config->fulltextsearchEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-docker-socket-proxy') {
|
||||
if (!$this->configurationManager->isDockerSocketProxyEnabled()) {
|
||||
if (!$config->dockerSocketProxyEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-whiteboard') {
|
||||
if (!$config->whiteboardEnabled) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$ports = new ContainerPorts();
|
||||
if (isset($entry['ports'])) {
|
||||
foreach ($entry['ports'] as $value) {
|
||||
foreach ($entry['ports'] as $value) {
|
||||
$ports->AddPort(
|
||||
new ContainerPort(
|
||||
$value['port_number'],
|
||||
@@ -114,34 +116,34 @@ class ContainerDefinitionFetcher
|
||||
if (isset($entry['volumes'])) {
|
||||
foreach ($entry['volumes'] as $value) {
|
||||
if($value['source'] === '%BORGBACKUP_HOST_LOCATION%') {
|
||||
$value['source'] = $this->configurationManager->GetBorgBackupHostLocation();
|
||||
$value['source'] = $config->getBorgLocation();
|
||||
if($value['source'] === '') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if($value['source'] === '%NEXTCLOUD_MOUNT%') {
|
||||
$value['source'] = $this->configurationManager->GetNextcloudMount();
|
||||
$value['source'] = $config->nextcloudMount;
|
||||
if($value['source'] === '') {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value['source'] === '%NEXTCLOUD_DATADIR%') {
|
||||
$value['source'] = $this->configurationManager->GetNextcloudDatadirMount();
|
||||
$value['source'] = $config->nextcloudDatadir;
|
||||
if ($value['source'] === '') {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value['source'] === '%WATCHTOWER_DOCKER_SOCKET_PATH%') {
|
||||
$value['source'] = $this->configurationManager->GetDockerSocketPath();
|
||||
$value['source'] = $config->dockerSocketPath;
|
||||
if($value['source'] === '') {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value['source'] === '%NEXTCLOUD_TRUSTED_CACERTS_DIR%') {
|
||||
$value['source'] = $this->configurationManager->GetTrustedCacertsDir();
|
||||
$value['source'] = $config->trustedCacertsDir;
|
||||
if($value['source'] === '') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($value['destination'] === '%NEXTCLOUD_MOUNT%') {
|
||||
$value['destination'] = $this->configurationManager->GetNextcloudMount();
|
||||
$value['destination'] = $config->nextcloudMount;
|
||||
if($value['destination'] === '') {
|
||||
continue;
|
||||
}
|
||||
@@ -169,42 +171,46 @@ class ContainerDefinitionFetcher
|
||||
}
|
||||
foreach ($valueDependsOn as $value) {
|
||||
if ($value === 'nextcloud-aio-clamav') {
|
||||
if (!$this->configurationManager->isClamavEnabled()) {
|
||||
if (!$config->isClamavEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-onlyoffice') {
|
||||
if (!$this->configurationManager->isOnlyofficeEnabled()) {
|
||||
if (!$config->isOnlyofficeEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-collabora') {
|
||||
if (!$this->configurationManager->isCollaboraEnabled()) {
|
||||
if (!$config->isCollaboraEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-talk') {
|
||||
if (!$this->configurationManager->isTalkEnabled()) {
|
||||
if (!$config->talkEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-talk-recording') {
|
||||
if (!$this->configurationManager->isTalkRecordingEnabled()) {
|
||||
if (!$config->isTalkRecordingEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-imaginary') {
|
||||
if (!$this->configurationManager->isImaginaryEnabled()) {
|
||||
if (!$config->imaginaryEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-fulltextsearch') {
|
||||
if (!$this->configurationManager->isFulltextsearchEnabled()) {
|
||||
if (!$config->fulltextsearchEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-docker-socket-proxy') {
|
||||
if (!$this->configurationManager->isDockerSocketProxyEnabled()) {
|
||||
if (!$config->dockerSocketProxyEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-whiteboard') {
|
||||
if (!$config->whiteboardEnabled) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$dependsOn[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$variables = new ContainerEnvironmentVariables();
|
||||
if (isset($entry['environment'])) {
|
||||
foreach ($entry['environment'] as $value) {
|
||||
|
||||
@@ -2,137 +2,76 @@
|
||||
|
||||
namespace AIO\Controller;
|
||||
|
||||
use AIO\ContainerDefinitionFetcher;
|
||||
use AIO\Data\ConfigurationManager;
|
||||
use AIO\Data\InvalidSettingConfigurationException;
|
||||
use AIO\Docker\DockerActionManager;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
class ConfigurationController
|
||||
{
|
||||
private ConfigurationManager $configurationManager;
|
||||
|
||||
public function __construct(
|
||||
ConfigurationManager $configurationManager
|
||||
) {
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
public function SetConfig(Request $request, Response $response, array $args) : Response {
|
||||
readonly class ConfigurationController {
|
||||
public function SetConfig(Request $request, Response $response, array $args): Response {
|
||||
try {
|
||||
if (isset($request->getParsedBody()['domain'])) {
|
||||
$domain = $request->getParsedBody()['domain'] ?? '';
|
||||
$this->configurationManager->SetDomain($domain);
|
||||
}
|
||||
$body = $request->getParsedBody();
|
||||
if (is_array($body)) {
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
|
||||
if (isset($request->getParsedBody()['current-master-password']) || isset($request->getParsedBody()['new-master-password'])) {
|
||||
$currentMasterPassword = $request->getParsedBody()['current-master-password'] ?? '';
|
||||
$newMasterPassword = $request->getParsedBody()['new-master-password'] ?? '';
|
||||
$this->configurationManager->ChangeMasterPassword($currentMasterPassword, $newMasterPassword);
|
||||
}
|
||||
if (is_string($body['domain']))
|
||||
$config->setDomain($body['domain']);
|
||||
|
||||
if (isset($request->getParsedBody()['borg_backup_host_location'])) {
|
||||
$location = $request->getParsedBody()['borg_backup_host_location'] ?? '';
|
||||
$this->configurationManager->SetBorgBackupHostLocation($location);
|
||||
}
|
||||
$currentMasterPassword = is_string($body['current-master-password']) ? $body['current-master-password'] : null;
|
||||
$newMasterPassword = is_string($body['new-master-password']) ? $body['new-master-password'] : null;
|
||||
if ($currentMasterPassword !== null || $newMasterPassword !== null)
|
||||
$config->changeMasterPassword($currentMasterPassword ?? '', $newMasterPassword ?? '');
|
||||
|
||||
if (isset($request->getParsedBody()['borg_restore_host_location']) || isset($request->getParsedBody()['borg_restore_password'])) {
|
||||
$restoreLocation = $request->getParsedBody()['borg_restore_host_location'] ?? '';
|
||||
$borgPassword = $request->getParsedBody()['borg_restore_password'] ?? '';
|
||||
$this->configurationManager->SetBorgRestoreHostLocationAndPassword($restoreLocation, $borgPassword);
|
||||
}
|
||||
if (is_string($body['borg_backup_host_location']))
|
||||
$config->setBorgLocation($body['borg_backup_host_location']);
|
||||
|
||||
if (isset($request->getParsedBody()['daily_backup_time'])) {
|
||||
if (isset($request->getParsedBody()['automatic_updates'])) {
|
||||
$enableAutomaticUpdates = true;
|
||||
} else {
|
||||
$enableAutomaticUpdates = false;
|
||||
$borgRestoreHostLocation = is_string($body['borg_restore_host_location']) ? $body['borg_restore_host_location'] : null;
|
||||
$borgRestorePassword = is_string($body['borg_restore_password']) ? $body['borg_restore_password'] : null;
|
||||
if ($borgRestoreHostLocation !== null || $borgRestorePassword !== null)
|
||||
$config->setBorgRestoreLocationAndPassword($borgRestoreHostLocation ?? '', $borgRestorePassword ?? '');
|
||||
|
||||
if (is_string($body['daily_backup_time']))
|
||||
ConfigurationManager::SetDailyBackupTime(
|
||||
$body['daily_backup_time'],
|
||||
isset($body['automatic_updates']),
|
||||
isset($body['success_notification']));
|
||||
|
||||
if (isset($body['delete_daily_backup_time']))
|
||||
$config->deleteTimezone();
|
||||
|
||||
if (is_string($body['additional_backup_directories']))
|
||||
ConfigurationManager::SetAdditionalBackupDirectories($body['additional_backup_directories']);
|
||||
|
||||
if (isset($body['delete_timezone']))
|
||||
$config->DeleteTimezone();
|
||||
|
||||
if (is_string($body['timezone']))
|
||||
$config->SetTimezone($body['timezone']);
|
||||
|
||||
if (isset($body['options-form'])) {
|
||||
if (isset($body['collabora']) && isset($body['onlyoffice']))
|
||||
throw new InvalidSettingConfigurationException("Collabora and Onlyoffice are not allowed to be enabled at the same time!");
|
||||
$config->enableClamav(isset($body['clamav']));
|
||||
$config->enableOnlyoffice(isset($body['onlyoffice']));
|
||||
$config->enableCollabora(isset($body['collabora']));
|
||||
$config->talkEnabled = isset($body['talk']);
|
||||
$config->enableTalkRecording(isset($body['talk-recording']));
|
||||
$config->imaginaryEnabled = isset($body['imaginary']);
|
||||
$config->fulltextsearchEnabled = isset($body['fulltextsearch']);
|
||||
$config->dockerSocketProxyEnabled = isset($body['docker-socket-proxy']);
|
||||
$config->whiteboardEnabled = isset($body['whiteboard']);
|
||||
}
|
||||
if (isset($request->getParsedBody()['success_notification'])) {
|
||||
$successNotification = true;
|
||||
} else {
|
||||
$successNotification = false;
|
||||
}
|
||||
$dailyBackupTime = $request->getParsedBody()['daily_backup_time'] ?? '';
|
||||
$this->configurationManager->SetDailyBackupTime($dailyBackupTime, $enableAutomaticUpdates, $successNotification);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['delete_daily_backup_time'])) {
|
||||
$this->configurationManager->DeleteDailyBackupTime();
|
||||
}
|
||||
if (isset($body['delete_collabora_dictionaries']))
|
||||
$config->DeleteCollaboraDictionaries();
|
||||
|
||||
if (isset($request->getParsedBody()['additional_backup_directories'])) {
|
||||
$additionalBackupDirectories = $request->getParsedBody()['additional_backup_directories'] ?? '';
|
||||
$this->configurationManager->SetAdditionalBackupDirectories($additionalBackupDirectories);
|
||||
}
|
||||
if (is_string($body['collabora_dictionaries']))
|
||||
$config->SetCollaboraDictionaries($body['collabora_dictionaries']);
|
||||
|
||||
if (isset($request->getParsedBody()['delete_timezone'])) {
|
||||
$this->configurationManager->DeleteTimezone();
|
||||
}
|
||||
if (isset($body['delete_borg_backup_host_location']))
|
||||
$config->deleteBorgLocation();
|
||||
|
||||
if (isset($request->getParsedBody()['timezone'])) {
|
||||
$timezone = $request->getParsedBody()['timezone'] ?? '';
|
||||
$this->configurationManager->SetTimezone($timezone);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['options-form'])) {
|
||||
if (isset($request->getParsedBody()['collabora']) && isset($request->getParsedBody()['onlyoffice'])) {
|
||||
throw new InvalidSettingConfigurationException("Collabora and Onlyoffice are not allowed to be enabled at the same time!");
|
||||
}
|
||||
if (isset($request->getParsedBody()['clamav'])) {
|
||||
$this->configurationManager->SetClamavEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetClamavEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['onlyoffice'])) {
|
||||
$this->configurationManager->SetOnlyofficeEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetOnlyofficeEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['collabora'])) {
|
||||
$this->configurationManager->SetCollaboraEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetCollaboraEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['talk'])) {
|
||||
$this->configurationManager->SetTalkEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetTalkEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['talk-recording'])) {
|
||||
$this->configurationManager->SetTalkRecordingEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetTalkRecordingEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['imaginary'])) {
|
||||
$this->configurationManager->SetImaginaryEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetImaginaryEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['fulltextsearch'])) {
|
||||
$this->configurationManager->SetFulltextsearchEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetFulltextsearchEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['docker-socket-proxy'])) {
|
||||
$this->configurationManager->SetDockerSocketProxyEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetDockerSocketProxyEnabledState(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['delete_collabora_dictionaries'])) {
|
||||
$this->configurationManager->DeleteCollaboraDictionaries();
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['collabora_dictionaries'])) {
|
||||
$collaboraDictionaries = $request->getParsedBody()['collabora_dictionaries'] ?? '';
|
||||
$this->configurationManager->SetCollaboraDictionaries($collaboraDictionaries);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['delete_borg_backup_host_location'])) {
|
||||
$this->configurationManager->DeleteBorgBackupHostLocation();
|
||||
ConfigurationManager::storeConfigFile($config);
|
||||
}
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '/');
|
||||
|
||||
@@ -14,16 +14,13 @@ class DockerController
|
||||
private DockerActionManager $dockerActionManager;
|
||||
private ContainerDefinitionFetcher $containerDefinitionFetcher;
|
||||
private const string TOP_CONTAINER = 'nextcloud-aio-apache';
|
||||
private ConfigurationManager $configurationManager;
|
||||
|
||||
public function __construct(
|
||||
DockerActionManager $dockerActionManager,
|
||||
ContainerDefinitionFetcher $containerDefinitionFetcher,
|
||||
ConfigurationManager $configurationManager
|
||||
) {
|
||||
$this->dockerActionManager = $dockerActionManager;
|
||||
$this->containerDefinitionFetcher = $containerDefinitionFetcher;
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
private function PerformRecursiveContainerStart(string $id, bool $pullImage = true) : void {
|
||||
@@ -48,7 +45,7 @@ class DockerController
|
||||
}
|
||||
}
|
||||
|
||||
// Check if docker hub is reachable in order to make sure that we do not try to pull an image if it is down
|
||||
// Check if docker hub is reachable in order to make sure that we do not try to pull an image if it is down
|
||||
// and try to mitigate issues that are arising due to that
|
||||
if ($pullImage) {
|
||||
if (!$this->dockerActionManager->isDockerHubReachable($container)) {
|
||||
@@ -91,9 +88,9 @@ class DockerController
|
||||
}
|
||||
|
||||
public function startBackup() : void {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'backup';
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
$config->setBackupMode('backup');
|
||||
ConfigurationManager::storeConfigFile($config);
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
$this->PerformRecursiveContainerStop($id);
|
||||
@@ -108,19 +105,19 @@ class DockerController
|
||||
}
|
||||
|
||||
public function checkBackup() : void {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'check';
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
$config->setBackupMode('check');
|
||||
ConfigurationManager::storeConfigFile($config);
|
||||
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
}
|
||||
|
||||
public function StartBackupContainerRestore(Request $request, Response $response, array $args) : Response {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'restore';
|
||||
$config['selected-restore-time'] = $request->getParsedBody()['selected_restore_time'] ?? '';
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
$config->setBackupMode('restore');
|
||||
$config->setSelectedRestoreTime($request->getParsedBody()['selected_restore_time'] ?? '');
|
||||
ConfigurationManager::storeConfigFile($config);
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
$this->PerformRecursiveContainerStop($id);
|
||||
@@ -132,26 +129,26 @@ class DockerController
|
||||
}
|
||||
|
||||
public function StartBackupContainerCheckRepair(Request $request, Response $response, array $args) : Response {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'check-repair';
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
$config->setBackupMode('check-repair');
|
||||
ConfigurationManager::storeConfigFile($config);
|
||||
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
|
||||
// Restore to backup check which is needed to make the UI logic work correctly
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'check';
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
$config->setBackupMode('check');
|
||||
ConfigurationManager::storeConfigFile($config);
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '/');
|
||||
}
|
||||
|
||||
public function StartBackupContainerTest(Request $request, Response $response, array $args) : Response {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'test';
|
||||
$config['instance_restore_attempt'] = 0;
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
$config->setBackupMode('test');
|
||||
$config->instanceRestoreAttempt = 0;
|
||||
ConfigurationManager::storeConfigFile($config);
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
$this->PerformRecursiveContainerStop($id);
|
||||
@@ -173,19 +170,16 @@ class DockerController
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['install_latest_major'])) {
|
||||
$installLatestMajor = 29;
|
||||
$installLatestMajor = 30;
|
||||
} else {
|
||||
$installLatestMajor = "";
|
||||
$installLatestMajor = 0;
|
||||
}
|
||||
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
// set AIO_URL
|
||||
$config['AIO_URL'] = $host . ':' . $port;
|
||||
// set wasStartButtonClicked
|
||||
$config['wasStartButtonClicked'] = 1;
|
||||
// set install_latest_major
|
||||
$config['install_latest_major'] = $installLatestMajor;
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
$config->aioUrl = $host . ':' . $port;
|
||||
$config->wasStartButtonClicked = true;
|
||||
$config->installLatestMajor = $installLatestMajor;
|
||||
ConfigurationManager::storeConfigFile($config);
|
||||
|
||||
// Start container
|
||||
$this->startTopContainer(true);
|
||||
@@ -198,10 +192,9 @@ class DockerController
|
||||
}
|
||||
|
||||
public function startTopContainer(bool $pullImage) : void {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
// set AIO_TOKEN
|
||||
$config['AIO_TOKEN'] = bin2hex(random_bytes(24));
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
$config->setToken(bin2hex(random_bytes(24)));
|
||||
ConfigurationManager::storeConfigFile($config);
|
||||
|
||||
// Stop domaincheck since apache would not be able to start otherwise
|
||||
$this->StopDomaincheckContainer();
|
||||
@@ -250,7 +243,8 @@ class DockerController
|
||||
public function StartDomaincheckContainer() : void
|
||||
{
|
||||
# Don't start if domain is already set
|
||||
if ($this->configurationManager->GetDomain() !== '' || $this->configurationManager->wasStartButtonClicked()) {
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
if ($config->getDomain() !== '' || $config->wasStartButtonClicked) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
620
php/src/Data/ConfigFile.php
Normal file
620
php/src/Data/ConfigFile.php
Normal file
@@ -0,0 +1,620 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Data;
|
||||
|
||||
use JsonException;
|
||||
use JsonSerializable;
|
||||
|
||||
|
||||
function _bool(array $json, int|string $key): bool {
|
||||
return $json[$key] === true || $json[$key] === 1 || $json[$key] === 'true';
|
||||
}
|
||||
|
||||
function _env_bool(string $envKey, array $json, int|string $key): bool {
|
||||
$envVar = getenv($envKey);
|
||||
if (is_string($envVar)) return $envVar === 'true' || $envVar === '1';
|
||||
return $json[$key] === true || $json[$key] === 1 || $json[$key] === 'true' || $json[$key] === '1';
|
||||
}
|
||||
|
||||
/** @throws JsonException */
|
||||
function _string(array $json, int|string $key, string $default = ''): string {
|
||||
if (!isset($json[$key])) return $default;
|
||||
if (is_string($json[$key])) return $json[$key];
|
||||
throw new JsonException("Invalid JSON type for key '$key': expected 'string' got '" . gettype($json[$key]) . "'");
|
||||
}
|
||||
|
||||
/** @throws JsonException */
|
||||
function _env_string(string $envKey, array $json, int|string $key, string $default = ''): string {
|
||||
$envVar = getenv($envKey);
|
||||
if (is_string($envVar)) return $envVar;
|
||||
return _string($json, $key, $default);
|
||||
}
|
||||
|
||||
/** @throws JsonException */
|
||||
function _int(array $json, int|string $key, int $default = 0): int {
|
||||
if (!isset($json[$key])) return $default;
|
||||
if (is_numeric($json[$key])) return intval($json[$key]);
|
||||
throw new JsonException("Invalid JSON type for key '$key': expected 'int' got '" . gettype($json[$key]) . "'");
|
||||
}
|
||||
|
||||
/** @throws JsonException */
|
||||
function _env_int(string $envKey, array $json, int|string $key, int $default = 0): int {
|
||||
$envVar = getenv($envKey);
|
||||
if (is_numeric($envVar)) return intval($envVar);
|
||||
return _int($json, $key, $default);
|
||||
}
|
||||
|
||||
/** @throws JsonException */
|
||||
function _object(mixed $data): array {
|
||||
if (!isset($data)) return [];
|
||||
if (is_array($data)) return $data;
|
||||
if (is_object($data)) return (array)$data;
|
||||
throw new JsonException("Invalid JSON type: expected 'array' or 'object' got '" . gettype($data) . "'");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @psalm-suppress MixedReturnTypeCoercion
|
||||
* @return array<string, string>
|
||||
* @throws JsonException
|
||||
*/
|
||||
function _map_str_str(array $json, int|string $key): array {
|
||||
return array_filter(_object($json[$key]), fn($k, $v) => is_string($k) && is_string($v), ARRAY_FILTER_USE_BOTH);
|
||||
}
|
||||
|
||||
|
||||
class ConfigFile implements JsonSerializable {
|
||||
//////////////////////
|
||||
/// Object Methods ///
|
||||
//////////////////////
|
||||
readonly bool $x64Platform;
|
||||
private bool $clamav, $talkRecording, $onlyoffice, $collabora;
|
||||
|
||||
// Bool keys
|
||||
const string KEY_CLAMAV = 'isClamavEnabled';
|
||||
const string KEY_DOCKER_SOCKET_PROXY = 'isDockerSocketProxyEnabled';
|
||||
const string KEY_WHITEBOARD = 'isWhiteboardEnabled';
|
||||
const string KEY_IMAGINARY = 'isImaginaryEnabled';
|
||||
const string KEY_FULLTEXTSEARCH = 'isFulltextsearchEnabled';
|
||||
const string KEY_ONLYOFFICE = 'isOnlyofficeEnabled';
|
||||
const string KEY_COLLABORA = 'isCollaboraEnabled';
|
||||
const string KEY_TALK = 'isTalkEnabled';
|
||||
const string KEY_TALK_RECORDING = 'isTalkRecordingEnabled';
|
||||
const string KEY_START_BUTTON_CLICKED = 'wasStartButtonClicked';
|
||||
const string KEY_INSTALL_LATEST_MAJOR = 'shouldLatestMajorGetInstalled';
|
||||
// Readonly keys
|
||||
const string KEY_APACHE_PORT = 'apache_port';
|
||||
const string KEY_TALK_PORT = 'talk_port';
|
||||
const string KEY_NEXTCLOUD_MOUNT = 'nextcloud_mount';
|
||||
const string KEY_NEXTCLOUD_DATADIR = 'nextcloud_datadir';
|
||||
const string KEY_NEXTCLOUD_UPLOAD_LIMIT = 'nextcloud_upload_limit';
|
||||
const string KEY_NEXTCLOUD_MEMORY_LIMIT = 'nextcloud_memory_limit';
|
||||
const string KEY_NEXTCLOUD_MAX_TIME = 'nextcloud_max_time';
|
||||
const string KEY_BORG_RETENTION_POLICY = 'borg_retention_policy';
|
||||
const string KEY_DOCKER_SOCKET_PATH = 'docker_socket_path';
|
||||
const string KEY_TRUSTED_CACERTS_DIR = 'trusted_cacerts_dir';
|
||||
const string KEY_NEXTCLOUD_ADDITIONAL_APKS = 'nextcloud_additional_apks';
|
||||
const string KEY_NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS = 'nextcloud_additional_php_extensions';
|
||||
const string KEY_APACHE_IP_BINDING = 'apache_ip_binding';
|
||||
const string KEY_AIO_DISABLE_BACKUP_SECTION = 'aio_disable_backup_section';
|
||||
const string KEY_AIO_COMMUNITY_CONTAINERS = 'aio_community_containers';
|
||||
const string KEY_NEXTCLOUD_ENABLE_DRI_DEVICE = 'nextcloud_enable_dri_device';
|
||||
const string KEY_COLLABORA_SECCOMP_DISABLED = 'collabora_seccomp_disabled';
|
||||
const string KEY_NEXTCLOUD_KEEP_DISABLED_APPS = 'nextcloud_keep_disabled_apps';
|
||||
// String keys
|
||||
const string KEY_INSTANCE_RESTORE_ATTEMPT = 'instance_restore_attempt';
|
||||
const string KEY_BORG_LOCATION = 'borg_backup_host_location';
|
||||
const string KEY_BORG_PASSWORD = 'borg_restore_password';
|
||||
const string KEY_BACKUP_MODE = 'backup-mode';
|
||||
const string KEY_SELECTED_RESTORE_TIME = 'selected-restore-time';
|
||||
// Other keys
|
||||
const string KEY_PASSWORD = 'password';
|
||||
const string KEY_TOKEN = 'AIO_TOKEN';
|
||||
const string KEY_DOMAIN = 'domain';
|
||||
const string KEY_AIO_URL = 'AIO_URL';
|
||||
const string KEY_TIMEZONE = 'timezone';
|
||||
const string KEY_COLLABORA_DICTIONARIES = 'collabora_dictionaries';
|
||||
const string KEY_SECRETS = 'secrets';
|
||||
|
||||
|
||||
private function __construct(
|
||||
// Bool data
|
||||
bool $clamavEnabled,
|
||||
public bool $dockerSocketProxyEnabled,
|
||||
public bool $whiteboardEnabled,
|
||||
public bool $imaginaryEnabled,
|
||||
public bool $fulltextsearchEnabled,
|
||||
bool $onlyofficeEnabled,
|
||||
bool $collaboraEnabled,
|
||||
public bool $talkEnabled,
|
||||
bool $talkRecordingEnabled,
|
||||
public bool $wasStartButtonClicked,
|
||||
// Readonly data
|
||||
public int $apachePort,
|
||||
public int $talkPort,
|
||||
public string $nextcloudMount,
|
||||
public string $nextcloudDatadir,
|
||||
public string $nextcloudUploadLimit,
|
||||
public string $nextcloudMemoryLimit,
|
||||
public string $nextcloudMaxTime,
|
||||
public string $borgRetentionPolicy,
|
||||
public string $dockerSocketPath,
|
||||
public string $trustedCacertsDir,
|
||||
public string $nextcloudAdditionalApks,
|
||||
public string $nextcloudAdditionalPhpExtensions,
|
||||
public string $apacheIpBinding,
|
||||
public bool $aioDisableBackupSection,
|
||||
public bool $nextcloudEnableDriDevice,
|
||||
public bool $nextcloudKeepDisabledApps,
|
||||
private bool $collaboraSeccompDisabled,
|
||||
/** @var list<string> $aioCommunityContainers */
|
||||
public array $aioCommunityContainers,
|
||||
|
||||
// Backup data
|
||||
public int $instanceRestoreAttempt,
|
||||
private string $borgLocation,
|
||||
private string $borgPassword,
|
||||
private string $backupMode,
|
||||
private string $selectedRestoreTime,
|
||||
// Other data
|
||||
public int $installLatestMajor,
|
||||
private string $password,
|
||||
private string $token,
|
||||
private string $domain,
|
||||
public string $aioUrl,
|
||||
private string $timezone,
|
||||
private string $collaboraDictionaries,
|
||||
/** @var array<string, string> $secrets */
|
||||
private array $secrets = [],
|
||||
) {
|
||||
$this->x64Platform = php_uname('m') === 'x86_64';
|
||||
$this->clamav = $clamavEnabled && $this->x64Platform;
|
||||
$this->talkRecording = $talkRecordingEnabled && $this->talkEnabled;
|
||||
$this->collabora = $collaboraEnabled;
|
||||
$this->onlyoffice = $onlyofficeEnabled && !$this->collabora;
|
||||
}
|
||||
|
||||
/** @throws InvalidSettingConfigurationException */
|
||||
static function parse(mixed $data): self {
|
||||
try {
|
||||
$json = _object($data);
|
||||
return new self(
|
||||
// Bool data
|
||||
clamavEnabled: _bool($json, self::KEY_CLAMAV),
|
||||
dockerSocketProxyEnabled: _bool($json, self::KEY_DOCKER_SOCKET_PROXY),
|
||||
whiteboardEnabled: _bool($json, self::KEY_WHITEBOARD),
|
||||
imaginaryEnabled: _bool($json, self::KEY_IMAGINARY),
|
||||
fulltextsearchEnabled: _bool($json, self::KEY_FULLTEXTSEARCH),
|
||||
onlyofficeEnabled: _bool($json, self::KEY_ONLYOFFICE),
|
||||
collaboraEnabled: _bool($json, self::KEY_COLLABORA),
|
||||
talkEnabled: _bool($json, self::KEY_TALK),
|
||||
talkRecordingEnabled: _bool($json, self::KEY_TALK_RECORDING),
|
||||
wasStartButtonClicked: _bool($json, self::KEY_START_BUTTON_CLICKED),
|
||||
// Readonly data
|
||||
apachePort: _env_int('APACHE_PORT', $json, self::KEY_APACHE_PORT, 443),
|
||||
talkPort: _env_int('TALK_PORT', $json, self::KEY_TALK_PORT, 3478),
|
||||
nextcloudMount: _env_string('NEXTCLOUD_MOUNT', $json, self::KEY_NEXTCLOUD_MOUNT),
|
||||
nextcloudDatadir: _env_string('NEXTCLOUD_DATADIR', $json, self::KEY_NEXTCLOUD_DATADIR, 'nextcloud_aio_nextcloud_data'),
|
||||
nextcloudUploadLimit: _env_string('NEXTCLOUD_UPLOAD_LIMIT', $json, self::KEY_NEXTCLOUD_UPLOAD_LIMIT, '10G'),
|
||||
nextcloudMemoryLimit: _env_string('NEXTCLOUD_MEMORY_LIMIT', $json, self::KEY_NEXTCLOUD_MEMORY_LIMIT, '512M'),
|
||||
nextcloudMaxTime: _env_string('NEXTCLOUD_MAX_TIME', $json, self::KEY_NEXTCLOUD_MAX_TIME, '3600'),
|
||||
borgRetentionPolicy: _env_string('BORG_RETENTION_POLICY', $json, self::KEY_BORG_RETENTION_POLICY, '--keep-within=7d --keep-weekly=4 --keep-monthly=6'),
|
||||
dockerSocketPath: _env_string('DOCKER_SOCKET_PATH', $json, self::KEY_DOCKER_SOCKET_PATH, '/var/run/docker.sock'),
|
||||
trustedCacertsDir: _env_string('TRUSTED_CACERTS_DIR', $json, self::KEY_TRUSTED_CACERTS_DIR),
|
||||
nextcloudAdditionalApks: _env_string('NEXTCLOUD_ADDITIONAL_APKS', $json, self::KEY_NEXTCLOUD_ADDITIONAL_APKS, 'imagemagick'),
|
||||
nextcloudAdditionalPhpExtensions: _env_string('NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS', $json, self::KEY_NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS, 'imagick'),
|
||||
apacheIpBinding: _env_string('APACHE_IP_BINDING', $json, self::KEY_APACHE_IP_BINDING),
|
||||
aioDisableBackupSection: _env_bool('AIO_DISABLE_BACKUP_SECTION', $json, self::KEY_AIO_DISABLE_BACKUP_SECTION),
|
||||
nextcloudEnableDriDevice: _env_bool('NEXTCLOUD_ENABLE_DRI_DEVICE', $json, self::KEY_NEXTCLOUD_ENABLE_DRI_DEVICE),
|
||||
nextcloudKeepDisabledApps: _env_bool('NEXTCLOUD_KEEP_DISABLED_APPS', $json, self::KEY_NEXTCLOUD_KEEP_DISABLED_APPS),
|
||||
collaboraSeccompDisabled: _env_bool('COLLABORA_SECCOMP_DISABLED', $json, self::KEY_COLLABORA_SECCOMP_DISABLED),
|
||||
aioCommunityContainers: _env_string('AIO_COMMUNITY_CONTAINERS', $json, self::KEY_AIO_COMMUNITY_CONTAINERS),
|
||||
// Backup data
|
||||
instanceRestoreAttempt: _int($json, self::KEY_INSTANCE_RESTORE_ATTEMPT),
|
||||
borgLocation: _string($json, self::KEY_BORG_LOCATION),
|
||||
borgPassword: _string($json, self::KEY_BORG_PASSWORD),
|
||||
backupMode: _string($json, self::KEY_BACKUP_MODE),
|
||||
selectedRestoreTime: _string($json, self::KEY_SELECTED_RESTORE_TIME),
|
||||
// Other data
|
||||
installLatestMajor: _int($json, self::KEY_INSTALL_LATEST_MAJOR),
|
||||
password: _string($json, self::KEY_PASSWORD),
|
||||
token: _string($json, self::KEY_TOKEN),
|
||||
domain: _string($json, self::KEY_DOMAIN),
|
||||
aioUrl: _string($json, self::KEY_AIO_URL),
|
||||
timezone: _string($json, self::KEY_TIMEZONE),
|
||||
collaboraDictionaries: _string($json, self::KEY_COLLABORA_DICTIONARIES),
|
||||
secrets: _map_str_str($json, self::KEY_SECRETS),
|
||||
);
|
||||
|
||||
} catch (JsonException $e) {
|
||||
throw new InvalidSettingConfigurationException('Failed to parse JSON data', previous: $e);
|
||||
}
|
||||
}
|
||||
|
||||
static function blank(string $password): self {
|
||||
return new self(
|
||||
// Bool data
|
||||
clamavEnabled: false,
|
||||
dockerSocketProxyEnabled: false,
|
||||
whiteboardEnabled: false,
|
||||
imaginaryEnabled: false,
|
||||
fulltextsearchEnabled: false,
|
||||
onlyofficeEnabled: false,
|
||||
collaboraEnabled: false,
|
||||
talkEnabled: false,
|
||||
talkRecordingEnabled: false,
|
||||
wasStartButtonClicked: false,
|
||||
// Readonly data
|
||||
apachePort: 0,
|
||||
talkPort: 0,
|
||||
nextcloudMount: '',
|
||||
nextcloudDatadir: '',
|
||||
nextcloudUploadLimit: '',
|
||||
nextcloudMemoryLimit: '',
|
||||
nextcloudMaxTime: '',
|
||||
borgRetentionPolicy: '',
|
||||
dockerSocketPath: '',
|
||||
trustedCacertsDir: '',
|
||||
nextcloudAdditionalApks: '',
|
||||
nextcloudAdditionalPhpExtensions: '',
|
||||
apacheIpBinding: '',
|
||||
aioDisableBackupSection: false,
|
||||
nextcloudEnableDriDevice: false,
|
||||
nextcloudKeepDisabledApps: false,
|
||||
collaboraSeccompDisabled: false,
|
||||
aioCommunityContainers: [],
|
||||
// Backup data
|
||||
instanceRestoreAttempt: 0,
|
||||
borgLocation: '',
|
||||
borgPassword: '',
|
||||
backupMode: '',
|
||||
selectedRestoreTime: '',
|
||||
// Other data
|
||||
installLatestMajor: 0,
|
||||
password: $password,
|
||||
token: '',
|
||||
domain: '',
|
||||
aioUrl: '',
|
||||
timezone: '',
|
||||
collaboraDictionaries: '',
|
||||
secrets: [],
|
||||
);
|
||||
}
|
||||
|
||||
function jsonSerialize(): array {
|
||||
$json = [];
|
||||
// Bool data
|
||||
if ($this->clamav) $json[self::KEY_CLAMAV] = true;
|
||||
if ($this->dockerSocketProxyEnabled) $json[self::KEY_DOCKER_SOCKET_PROXY] = true;
|
||||
if ($this->whiteboardEnabled) $json[self::KEY_WHITEBOARD] = true;
|
||||
if ($this->imaginaryEnabled) $json[self::KEY_IMAGINARY] = true;
|
||||
if ($this->fulltextsearchEnabled) $json[self::KEY_FULLTEXTSEARCH] = true;
|
||||
if ($this->onlyoffice) $json[self::KEY_ONLYOFFICE] = true;
|
||||
if ($this->collabora) $json[self::KEY_COLLABORA] = true;
|
||||
if ($this->talkEnabled) $json[self::KEY_TALK] = true;
|
||||
if ($this->talkRecording) $json[self::KEY_TALK_RECORDING] = true;
|
||||
if ($this->wasStartButtonClicked) $json[self::KEY_START_BUTTON_CLICKED] = true;
|
||||
// Backup data
|
||||
if (!empty($this->instanceRestoreAttempt)) $json[self::KEY_INSTANCE_RESTORE_ATTEMPT] = $this->instanceRestoreAttempt;
|
||||
if (!empty($this->borgLocation)) $json[self::KEY_BORG_LOCATION] = $this->borgLocation;
|
||||
if (!empty($this->borgPassword)) $json[self::KEY_BORG_PASSWORD] = $this->borgPassword;
|
||||
if (!empty($this->backupMode)) $json[self::KEY_BACKUP_MODE] = $this->backupMode;
|
||||
if (!empty($this->selectedRestoreTime)) $json[self::KEY_SELECTED_RESTORE_TIME] = $this->selectedRestoreTime;
|
||||
// Other data
|
||||
if (!empty($this->password)) $json[self::KEY_PASSWORD] = $this->password;
|
||||
if (!empty($this->token)) $json[self::KEY_TOKEN] = $this->token;
|
||||
if (!empty($this->domain)) $json[self::KEY_DOMAIN] = $this->domain;
|
||||
if (!empty($this->aioUrl)) $json[self::KEY_AIO_URL] = $this->aioUrl;
|
||||
if (!empty($this->timezone)) $json[self::KEY_TIMEZONE] = $this->timezone;
|
||||
if (!empty($this->collaboraDictionaries)) $json[self::KEY_COLLABORA_DICTIONARIES] = $this->collaboraDictionaries;
|
||||
if (!empty($this->secrets)) $json[self::KEY_SECRETS] = $this->secrets;
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
function overwrite(string $key, string $value): void {
|
||||
switch ($key) {
|
||||
case self::KEY_APACHE_IP_BINDING:
|
||||
$this->apacheIpBinding = $value;
|
||||
break;
|
||||
case self::KEY_APACHE_PORT:
|
||||
if (is_numeric($value)) $this->apachePort = intval($value);
|
||||
break;
|
||||
case self::KEY_NEXTCLOUD_MEMORY_LIMIT:
|
||||
$this->nextcloudMemoryLimit = $value;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
}
|
||||
/////////////////////////
|
||||
/// Bool data Methods ///
|
||||
/////////////////////////
|
||||
function isClamavEnabled(): bool {
|
||||
return $this->clamav;
|
||||
}
|
||||
|
||||
function enableClamav(bool $clamav): void {
|
||||
if ($this->x64Platform) $this->clamav = $clamav;
|
||||
}
|
||||
|
||||
function isCollaboraEnabled(): bool {
|
||||
return $this->collabora;
|
||||
}
|
||||
|
||||
function enableCollabora(bool $collabora): void {
|
||||
$this->collabora = $collabora;
|
||||
$this->onlyoffice = false;
|
||||
}
|
||||
|
||||
function isOnlyofficeEnabled(): bool {
|
||||
return $this->onlyoffice;
|
||||
}
|
||||
|
||||
function enableOnlyoffice(bool $onlyoffice): void {
|
||||
if ($this->collabora)
|
||||
$this->onlyoffice = $onlyoffice;
|
||||
}
|
||||
|
||||
function isTalkRecordingEnabled(): bool {
|
||||
return $this->talkRecording;
|
||||
}
|
||||
|
||||
function enableTalkRecording(bool $talkRecording): void {
|
||||
if ($this->talkEnabled)
|
||||
$this->talkRecording = $talkRecording;
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
/// Readonly data Methods ///
|
||||
/////////////////////////////
|
||||
function getCollaboraSeccompPolicy(): string {
|
||||
return $this->collaboraSeccompDisabled
|
||||
? '--o:security.seccomp=false'
|
||||
: '--o:security.seccomp=true';
|
||||
}
|
||||
|
||||
function getApacheMaxSize(): int {
|
||||
return intval(rtrim($this->nextcloudUploadLimit, 'G')) * 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
/// Backup data Methods ///
|
||||
///////////////////////////
|
||||
function getBorgLocation(): string {
|
||||
return $this->borgLocation;
|
||||
}
|
||||
|
||||
/** @throws InvalidSettingConfigurationException */
|
||||
function setBorgLocation(string $location): void {
|
||||
if ($location !== 'nextcloud_aio_backupdir' && (!str_starts_with($location, '/') || str_ends_with($location, '/')))
|
||||
throw new InvalidSettingConfigurationException("The path must start with '/', and must not end with '/'!");
|
||||
$this->borgLocation = $location;
|
||||
}
|
||||
|
||||
function deleteBorgLocation(): void {
|
||||
$this->borgLocation = '';
|
||||
}
|
||||
|
||||
function getBorgPassword(): string {
|
||||
return $this->borgPassword;
|
||||
}
|
||||
|
||||
/** @throws InvalidSettingConfigurationException */
|
||||
function setBorgRestoreLocationAndPassword(string $location, string $password): void {
|
||||
if ($password === '')
|
||||
throw new InvalidSettingConfigurationException("Please enter the password!");
|
||||
$this->setBorgLocation($location);
|
||||
$this->password = $password;
|
||||
$this->instanceRestoreAttempt = 1;
|
||||
}
|
||||
|
||||
function getBackupMode(): string {
|
||||
return $this->backupMode;
|
||||
}
|
||||
|
||||
function setBackupMode(string $backupMode): void {
|
||||
$this->backupMode = $backupMode;
|
||||
}
|
||||
|
||||
function getSelectedRestoreTime(): string {
|
||||
return $this->selectedRestoreTime;
|
||||
}
|
||||
|
||||
function setSelectedRestoreTime(string $selectedRestoreTime): void {
|
||||
$this->selectedRestoreTime = $selectedRestoreTime;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
/// Other data Methods //
|
||||
/////////////////////////
|
||||
function getPassword(): string {
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
/** @throws InvalidSettingConfigurationException */
|
||||
function changeMasterPassword(string $currentPassword, string $newPassword): void {
|
||||
if ($currentPassword === '')
|
||||
throw new InvalidSettingConfigurationException("Please enter your current password.");
|
||||
if ($currentPassword !== $this->password)
|
||||
throw new InvalidSettingConfigurationException("The entered current password is not correct.");
|
||||
if ($newPassword === '')
|
||||
throw new InvalidSettingConfigurationException("Please enter a new password.");
|
||||
if (strlen($newPassword) < 24)
|
||||
throw new InvalidSettingConfigurationException("New passwords must be >= 24 digits.");
|
||||
if (!preg_match("#^[a-zA-Z0-9 ]+$#", $newPassword))
|
||||
throw new InvalidSettingConfigurationException('Not allowed characters in the new password.');
|
||||
|
||||
$this->password = $newPassword;
|
||||
}
|
||||
|
||||
function getToken(): string {
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
function setToken(string $token): void {
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
function getDomain(): string {
|
||||
return $this->domain;
|
||||
}
|
||||
|
||||
/* @throws InvalidSettingConfigurationException */
|
||||
function setDomain(string $domain): void {
|
||||
// Validate that at least one dot is contained
|
||||
if (!str_contains($domain, '.')) {
|
||||
throw new InvalidSettingConfigurationException("Domain must contain at least one dot!");
|
||||
}
|
||||
|
||||
// Validate that no slashes are contained
|
||||
if (str_contains($domain, '/')) {
|
||||
throw new InvalidSettingConfigurationException("Domain must not contain slashes!");
|
||||
}
|
||||
|
||||
// Validate that no colons are contained
|
||||
if (str_contains($domain, ':')) {
|
||||
throw new InvalidSettingConfigurationException("Domain must not contain colons!");
|
||||
}
|
||||
|
||||
// Validate domain
|
||||
if (filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) === false) {
|
||||
throw new InvalidSettingConfigurationException("Domain is not a valid domain!");
|
||||
}
|
||||
|
||||
// Validate that it is not an IP-address
|
||||
if (filter_var($domain, FILTER_VALIDATE_IP)) {
|
||||
throw new InvalidSettingConfigurationException("Please enter a domain and not an IP-address!");
|
||||
}
|
||||
// TODO
|
||||
//
|
||||
// // Skip domain validation if opted in to do so
|
||||
// if (!$this->shouldDomainValidationBeSkipped()) {
|
||||
//
|
||||
// $dnsRecordIP = gethostbyname($domain);
|
||||
// if ($dnsRecordIP === $domain) {
|
||||
// $dnsRecordIP = '';
|
||||
// }
|
||||
//
|
||||
// if (empty($dnsRecordIP)) {
|
||||
// $record = dns_get_record($domain, DNS_AAAA);
|
||||
// if (isset($record[0]['ipv6']) && !empty($record[0]['ipv6'])) {
|
||||
// $dnsRecordIP = $record[0]['ipv6'];
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Validate IP
|
||||
// if (!filter_var($dnsRecordIP, FILTER_VALIDATE_IP)) {
|
||||
// throw new InvalidSettingConfigurationException("DNS config is not set for this domain or the domain is not a valid domain! (It was found to be set to '" . $dnsRecordIP . "')");
|
||||
// }
|
||||
//
|
||||
// // Get the apache port
|
||||
// $port = $this->GetApachePort();
|
||||
//
|
||||
// if (!filter_var($dnsRecordIP, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
// if ($port === '443') {
|
||||
// throw new InvalidSettingConfigurationException("It seems like the ip-address of the domain is set to an internal or reserved ip-address. This is not supported. (It was found to be set to '" . $dnsRecordIP . "'). Please set it to a public ip-address so that the domain validation can work!");
|
||||
// } else {
|
||||
// error_log("It seems like the ip-address of " . $domain . " is set to an internal or reserved ip-address. (It was found to be set to '" . $dnsRecordIP . "')");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Check if port 443 is open
|
||||
// $connection = @fsockopen($domain, 443, $errno, $errstr, 10);
|
||||
// if ($connection) {
|
||||
// fclose($connection);
|
||||
// } else {
|
||||
// throw new InvalidSettingConfigurationException("The domain is not reachable on Port 443 from within this container. Have you opened port 443/tcp in your router/firewall? If yes is the problem most likely that the router or firewall forbids local access to your domain. You can work around that by setting up a local DNS-server.");
|
||||
// }
|
||||
//
|
||||
// // Get Instance ID
|
||||
// $instanceID = $this->GetAndGenerateSecret('INSTANCE_ID');
|
||||
//
|
||||
// // set protocol
|
||||
// if ($port !== '443') {
|
||||
// $protocol = 'https://';
|
||||
// } else {
|
||||
// $protocol = 'http://';
|
||||
// }
|
||||
//
|
||||
// // Check if response is correct
|
||||
// $ch = curl_init();
|
||||
// $testUrl = $protocol . $domain . ':443';
|
||||
// curl_setopt($ch, CURLOPT_URL, $testUrl);
|
||||
// curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
// curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||
// curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
// $response = (string)curl_exec($ch);
|
||||
// # Get rid of trailing \n
|
||||
// $response = str_replace("\n", "", $response);
|
||||
//
|
||||
// if ($response !== $instanceID) {
|
||||
// error_log('The response of the connection attempt to "' . $testUrl . '" was: ' . $response);
|
||||
// error_log('Expected was: ' . $instanceID);
|
||||
// error_log('The error message was: ' . curl_error($ch));
|
||||
// $notice = "Domain does not point to this server or the reverse proxy is not configured correctly. See the mastercontainer logs for more details. ('sudo docker logs -f nextcloud-aio-mastercontainer')";
|
||||
// if ($port === '443') {
|
||||
// $notice .= " If you should be using Cloudflare, make sure to disable the Cloudflare Proxy feature as it might block the domain validation. Same for any other firewall or service that blocks unencrypted access on port 443.";
|
||||
// } else {
|
||||
// error_log('Please follow https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#6-how-to-debug-things in order to debug things!');
|
||||
// }
|
||||
// throw new InvalidSettingConfigurationException($notice);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Write domain
|
||||
$this->domain = $domain;
|
||||
// Reset the borg restore password when setting the domain
|
||||
$this->borgPassword = '';
|
||||
}
|
||||
|
||||
function getBaseDN(): string {
|
||||
$domain = $this->getDomain();
|
||||
if ($domain === "") {
|
||||
return "";
|
||||
}
|
||||
return 'dc=' . implode(',dc=', explode('.', $domain));
|
||||
}
|
||||
|
||||
function getTimezone(): string {
|
||||
return $this->timezone;
|
||||
}
|
||||
|
||||
/* @throws InvalidSettingConfigurationException */
|
||||
function setTimezone(string $timezone): void {
|
||||
if ($timezone === "")
|
||||
throw new InvalidSettingConfigurationException("The timezone must not be empty!");
|
||||
if (!preg_match("#^[a-zA-Z0-9_\-/+]+$#", $timezone))
|
||||
throw new InvalidSettingConfigurationException("The entered timezone does not seem to be a valid timezone!");
|
||||
$this->timezone = $timezone;
|
||||
}
|
||||
|
||||
function deleteTimezone(): void {
|
||||
$this->timezone = '';
|
||||
}
|
||||
|
||||
function getCollaboraDictionaries(): string {
|
||||
return $this->collaboraDictionaries;
|
||||
}
|
||||
|
||||
/** @throws InvalidSettingConfigurationException */
|
||||
function setCollaboraDictionaries(string $collaboraDictionaries): void {
|
||||
if ($collaboraDictionaries === "")
|
||||
throw new InvalidSettingConfigurationException("The dictionaries must not be empty!");
|
||||
if (!preg_match("#^[a-zA-Z_ ]+$#", $collaboraDictionaries))
|
||||
throw new InvalidSettingConfigurationException("The entered dictionaries do not seem to be a valid!");
|
||||
$this->collaboraDictionaries = $collaboraDictionaries;
|
||||
}
|
||||
|
||||
function deleteCollaboraDictionaries(): void {
|
||||
$this->collaboraDictionaries = '';
|
||||
}
|
||||
|
||||
function getSecret(string $key): ?string {
|
||||
return $this->secrets[$key] ?? null;
|
||||
}
|
||||
|
||||
function setSecret(string $key, string $data): void {
|
||||
$this->secrets[$key] = $data;
|
||||
}
|
||||
}
|
||||
@@ -4,76 +4,50 @@ namespace AIO\Data;
|
||||
|
||||
use AIO\Auth\PasswordGenerator;
|
||||
use AIO\Controller\DockerController;
|
||||
use JsonException;
|
||||
use Random\RandomException;
|
||||
|
||||
class ConfigurationManager
|
||||
{
|
||||
public function GetConfig() : array
|
||||
{
|
||||
if(file_exists(DataConst::GetConfigFile()))
|
||||
{
|
||||
$configContent = file_get_contents(DataConst::GetConfigFile());
|
||||
return json_decode($configContent, true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
return [];
|
||||
readonly class ConfigurationManager {
|
||||
/* @throws InvalidSettingConfigurationException */
|
||||
static function loadConfigFile(): ConfigFile {
|
||||
return ConfigFile::parse(file_get_contents(DataConst::GetConfigFile()));
|
||||
}
|
||||
|
||||
public function GetPassword() : string {
|
||||
return $this->GetConfig()['password'];
|
||||
}
|
||||
|
||||
public function GetToken() : string {
|
||||
return $this->GetConfig()['AIO_TOKEN'];
|
||||
}
|
||||
|
||||
public function SetPassword(string $password) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['password'] = $password;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function GetAndGenerateSecret(string $secretId) : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['secrets'][$secretId])) {
|
||||
$config['secrets'][$secretId] = bin2hex(random_bytes(24));
|
||||
$this->WriteConfig($config);
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
* @throws RandomException
|
||||
*/
|
||||
static function GetAndGenerateSecret(string $secretId): string {
|
||||
$config = self::loadConfigFile();
|
||||
$secret = $config->getSecret($secretId);
|
||||
if ($secret === null) {
|
||||
$secret = bin2hex(random_bytes(24));
|
||||
$config->setSecret($secretId, $secret);
|
||||
self::storeConfigFile($config);
|
||||
}
|
||||
|
||||
if ($secretId === 'BORGBACKUP_PASSWORD' && !file_exists(DataConst::GetBackupSecretFile())) {
|
||||
$this->DoubleSafeBackupSecret($config['secrets'][$secretId]);
|
||||
self::DoubleSafeBackupSecret($secret);
|
||||
}
|
||||
|
||||
return $config['secrets'][$secretId];
|
||||
return $secret;
|
||||
}
|
||||
|
||||
public function GetSecret(string $secretId) : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['secrets'][$secretId])) {
|
||||
$config['secrets'][$secretId] = "";
|
||||
}
|
||||
|
||||
return $config['secrets'][$secretId];
|
||||
}
|
||||
|
||||
private function DoubleSafeBackupSecret(string $borgBackupPassword) : void {
|
||||
private static function DoubleSafeBackupSecret(string $borgBackupPassword): void {
|
||||
file_put_contents(DataConst::GetBackupSecretFile(), $borgBackupPassword);
|
||||
}
|
||||
|
||||
public function hasBackupRunOnce() : bool {
|
||||
if (!file_exists(DataConst::GetBackupKeyFile())) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
public function hasBackupRunOnce(): bool {
|
||||
return file_exists(DataConst::GetBackupKeyFile());
|
||||
}
|
||||
|
||||
public function GetLastBackupTime() : string {
|
||||
public function GetLastBackupTime(): string {
|
||||
if (!file_exists(DataConst::GetBackupArchivesList())) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
$content = file_get_contents(DataConst::GetBackupArchivesList());
|
||||
if ($content === '') {
|
||||
if ($content === '' || $content === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -91,15 +65,15 @@ class ConfigurationManager
|
||||
if ($lastBackupTime === "") {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
return $lastBackupTime;
|
||||
}
|
||||
|
||||
public function GetBackupTimes() : array {
|
||||
public function GetBackupTimes(): array {
|
||||
if (!file_exists(DataConst::GetBackupArchivesList())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
$content = file_get_contents(DataConst::GetBackupArchivesList());
|
||||
if ($content === '') {
|
||||
return [];
|
||||
@@ -107,428 +81,30 @@ class ConfigurationManager
|
||||
|
||||
$backupLines = explode("\n", $content);
|
||||
$backupTimes = [];
|
||||
foreach($backupLines as $lines) {
|
||||
foreach ($backupLines as $lines) {
|
||||
if ($lines !== "") {
|
||||
$backupTimesTemp = explode(',', $lines);
|
||||
$backupTimes[] = $backupTimesTemp[1];
|
||||
$backupTimes[] = $backupTimesTemp[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the array to list newest backup first
|
||||
$backupTimes = array_reverse($backupTimes);
|
||||
|
||||
return $backupTimes;
|
||||
}
|
||||
|
||||
public function wasStartButtonClicked() : bool {
|
||||
if (isset($this->GetConfig()['wasStartButtonClicked'])) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function isx64Platform() : bool {
|
||||
if (php_uname('m') === 'x86_64') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function isClamavEnabled() : bool {
|
||||
if (!$this->isx64Platform()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isClamavEnabled']) && $config['isClamavEnabled'] === 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function isDockerSocketProxyEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isDockerSocketProxyEnabled']) && $config['isDockerSocketProxyEnabled'] === 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetDockerSocketProxyEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isDockerSocketProxyEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function SetClamavEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isClamavEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function isImaginaryEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isImaginaryEnabled']) && $config['isImaginaryEnabled'] === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetImaginaryEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isImaginaryEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function isFulltextsearchEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isFulltextsearchEnabled']) && $config['isFulltextsearchEnabled'] === 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetFulltextsearchEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isFulltextsearchEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function isOnlyofficeEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isOnlyofficeEnabled']) && $config['isOnlyofficeEnabled'] === 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetOnlyofficeEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isOnlyofficeEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function isCollaboraEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isCollaboraEnabled']) && $config['isCollaboraEnabled'] === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetCollaboraEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isCollaboraEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function isTalkEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isTalkEnabled']) && $config['isTalkEnabled'] === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetTalkEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isTalkEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function isTalkRecordingEnabled() : bool {
|
||||
if (!$this->isTalkEnabled()) {
|
||||
return false;
|
||||
}
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isTalkRecordingEnabled']) && $config['isTalkRecordingEnabled'] === 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetTalkRecordingEnabledState(int $value) : void {
|
||||
if (!$this->isTalkEnabled()) {
|
||||
$value = 0;
|
||||
}
|
||||
$config = $this->GetConfig();
|
||||
$config['isTalkRecordingEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
return array_reverse($backupTimes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetDomain(string $domain) : void {
|
||||
// Validate that at least one dot is contained
|
||||
if (!str_contains($domain, '.')) {
|
||||
throw new InvalidSettingConfigurationException("Domain must contain at least one dot!");
|
||||
}
|
||||
|
||||
// Validate that no slashes are contained
|
||||
if (str_contains($domain, '/')) {
|
||||
throw new InvalidSettingConfigurationException("Domain must not contain slashes!");
|
||||
}
|
||||
|
||||
// Validate that no colons are contained
|
||||
if (str_contains($domain, ':')) {
|
||||
throw new InvalidSettingConfigurationException("Domain must not contain colons!");
|
||||
}
|
||||
|
||||
// Validate domain
|
||||
if (filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) === false) {
|
||||
throw new InvalidSettingConfigurationException("Domain is not a valid domain!");
|
||||
}
|
||||
|
||||
// Validate that it is not an IP-address
|
||||
if(filter_var($domain, FILTER_VALIDATE_IP)) {
|
||||
throw new InvalidSettingConfigurationException("Please enter a domain and not an IP-address!");
|
||||
}
|
||||
|
||||
// Skip domain validation if opted in to do so
|
||||
if (!$this->shouldDomainValidationBeSkipped()) {
|
||||
|
||||
$dnsRecordIP = gethostbyname($domain);
|
||||
if ($dnsRecordIP === $domain) {
|
||||
$dnsRecordIP = '';
|
||||
}
|
||||
|
||||
if (empty($dnsRecordIP)) {
|
||||
$record = dns_get_record($domain, DNS_AAAA);
|
||||
if (isset($record[0]['ipv6']) && !empty($record[0]['ipv6'])) {
|
||||
$dnsRecordIP = $record[0]['ipv6'];
|
||||
}
|
||||
}
|
||||
|
||||
// Validate IP
|
||||
if (!filter_var($dnsRecordIP, FILTER_VALIDATE_IP)) {
|
||||
throw new InvalidSettingConfigurationException("DNS config is not set for this domain or the domain is not a valid domain! (It was found to be set to '" . $dnsRecordIP . "')");
|
||||
}
|
||||
|
||||
// Get the apache port
|
||||
$port = $this->GetApachePort();
|
||||
|
||||
if (!filter_var($dnsRecordIP, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
if ($port === '443') {
|
||||
throw new InvalidSettingConfigurationException("It seems like the ip-address of the domain is set to an internal or reserved ip-address. This is not supported. (It was found to be set to '" . $dnsRecordIP . "'). Please set it to a public ip-address so that the domain validation can work!");
|
||||
} else {
|
||||
error_log("It seems like the ip-address of " . $domain . " is set to an internal or reserved ip-address. (It was found to be set to '" . $dnsRecordIP . "')");
|
||||
}
|
||||
}
|
||||
|
||||
// Check if port 443 is open
|
||||
$connection = @fsockopen($domain, 443, $errno, $errstr, 10);
|
||||
if ($connection) {
|
||||
fclose($connection);
|
||||
} else {
|
||||
throw new InvalidSettingConfigurationException("The domain is not reachable on Port 443 from within this container. Have you opened port 443/tcp in your router/firewall? If yes is the problem most likely that the router or firewall forbids local access to your domain. You can work around that by setting up a local DNS-server.");
|
||||
}
|
||||
|
||||
// Get Instance ID
|
||||
$instanceID = $this->GetAndGenerateSecret('INSTANCE_ID');
|
||||
|
||||
// set protocol
|
||||
if ($port !== '443') {
|
||||
$protocol = 'https://';
|
||||
} else {
|
||||
$protocol = 'http://';
|
||||
}
|
||||
|
||||
// Check if response is correct
|
||||
$ch = curl_init();
|
||||
$testUrl = $protocol . $domain . ':443';
|
||||
curl_setopt($ch, CURLOPT_URL, $testUrl);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
$response = (string)curl_exec($ch);
|
||||
# Get rid of trailing \n
|
||||
$response = str_replace("\n", "", $response);
|
||||
|
||||
if ($response !== $instanceID) {
|
||||
error_log('The response of the connection attempt to "' . $testUrl . '" was: ' . $response);
|
||||
error_log('Expected was: ' . $instanceID);
|
||||
error_log('The error message was: ' . curl_error($ch));
|
||||
$notice = "Domain does not point to this server or the reverse proxy is not configured correctly. See the mastercontainer logs for more details. ('sudo docker logs -f nextcloud-aio-mastercontainer')";
|
||||
if ($port === '443') {
|
||||
$notice .= " If you should be using Cloudflare, make sure to disable the Cloudflare Proxy feature as it might block the domain validation. Same for any other firewall or service that blocks unencrypted access on port 443.";
|
||||
} else {
|
||||
error_log('Please follow https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#6-how-to-debug-things in order to debug things!');
|
||||
}
|
||||
throw new InvalidSettingConfigurationException($notice);
|
||||
}
|
||||
}
|
||||
|
||||
// Write domain
|
||||
$config = $this->GetConfig();
|
||||
$config['domain'] = $domain;
|
||||
// Reset the borg restore password when setting the domain
|
||||
$config['borg_restore_password'] = '';
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function GetDomain() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['domain'])) {
|
||||
$config['domain'] = '';
|
||||
}
|
||||
|
||||
return $config['domain'];
|
||||
}
|
||||
|
||||
public function GetBaseDN() : string {
|
||||
$domain = $this->GetDomain();
|
||||
if ($domain === "") {
|
||||
return "";
|
||||
}
|
||||
return 'dc=' . implode(',dc=', explode('.', $domain));
|
||||
}
|
||||
|
||||
public function GetBackupMode() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['backup-mode'])) {
|
||||
$config['backup-mode'] = '';
|
||||
}
|
||||
|
||||
return $config['backup-mode'];
|
||||
}
|
||||
|
||||
public function GetSelectedRestoreTime() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['selected-restore-time'])) {
|
||||
$config['selected-restore-time'] = '';
|
||||
}
|
||||
|
||||
return $config['selected-restore-time'];
|
||||
}
|
||||
|
||||
public function GetAIOURL() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['AIO_URL'])) {
|
||||
$config['AIO_URL'] = '';
|
||||
}
|
||||
|
||||
return $config['AIO_URL'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetBorgBackupHostLocation(string $location) : void {
|
||||
$isValidPath = false;
|
||||
if (str_starts_with($location, '/') && !str_ends_with($location, '/')) {
|
||||
$isValidPath = true;
|
||||
} elseif ($location === 'nextcloud_aio_backupdir') {
|
||||
$isValidPath = true;
|
||||
}
|
||||
|
||||
if (!$isValidPath) {
|
||||
throw new InvalidSettingConfigurationException("The path must start with '/', and must not end with '/'!");
|
||||
}
|
||||
|
||||
|
||||
$config = $this->GetConfig();
|
||||
$config['borg_backup_host_location'] = $location;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function DeleteBorgBackupHostLocation() : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['borg_backup_host_location'] = '';
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetBorgRestoreHostLocationAndPassword(string $location, string $password) : void {
|
||||
if ($location === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter a path!");
|
||||
}
|
||||
|
||||
$isValidPath = false;
|
||||
if (str_starts_with($location, '/') && !str_ends_with($location, '/')) {
|
||||
$isValidPath = true;
|
||||
} elseif ($location === 'nextcloud_aio_backupdir') {
|
||||
$isValidPath = true;
|
||||
}
|
||||
|
||||
if (!$isValidPath) {
|
||||
throw new InvalidSettingConfigurationException("The path must start with '/', and must not end with '/'!");
|
||||
}
|
||||
|
||||
if ($password === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter the password!");
|
||||
}
|
||||
|
||||
$config = $this->GetConfig();
|
||||
$config['borg_backup_host_location'] = $location;
|
||||
$config['borg_restore_password'] = $password;
|
||||
$config['instance_restore_attempt'] = 1;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function ChangeMasterPassword(string $currentPassword, string $newPassword) : void {
|
||||
if ($currentPassword === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter your current password.");
|
||||
}
|
||||
|
||||
if ($currentPassword !== $this->GetPassword()) {
|
||||
throw new InvalidSettingConfigurationException("The entered current password is not correct.");
|
||||
}
|
||||
|
||||
if ($newPassword === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter a new password.");
|
||||
}
|
||||
|
||||
if (strlen($newPassword) < 24) {
|
||||
throw new InvalidSettingConfigurationException("New passwords must be >= 24 digits.");
|
||||
}
|
||||
|
||||
if (!preg_match("#^[a-zA-Z0-9 ]+$#", $newPassword)) {
|
||||
throw new InvalidSettingConfigurationException('Not allowed characters in the new password.');
|
||||
}
|
||||
|
||||
// All checks pass so set the password
|
||||
$this->SetPassword($newPassword);
|
||||
}
|
||||
|
||||
public function GetApachePort() : string {
|
||||
$envVariableName = 'APACHE_PORT';
|
||||
$configName = 'apache_port';
|
||||
$defaultValue = '443';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetTalkPort() : string {
|
||||
$envVariableName = 'TALK_PORT';
|
||||
$configName = 'talk_port';
|
||||
$defaultValue = '3478';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function WriteConfig(array $config) : void {
|
||||
if(!is_dir(DataConst::GetDataDirectory())) {
|
||||
public static function storeConfigFile(ConfigFile $config): void {
|
||||
if (!is_dir(DataConst::GetDataDirectory())) {
|
||||
throw new InvalidSettingConfigurationException(DataConst::GetDataDirectory() . " does not exist! Something was set up falsely!");
|
||||
}
|
||||
$df = disk_free_space(DataConst::GetDataDirectory());
|
||||
$content = json_encode($config, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR);
|
||||
try {
|
||||
$content = json_encode($config, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
throw new InvalidSettingConfigurationException('Failed to encode JSON data', previous: $e);
|
||||
}
|
||||
$size = strlen($content) + 10240;
|
||||
if ($df !== false && (int)$df < $size) {
|
||||
throw new InvalidSettingConfigurationException(DataConst::GetDataDirectory() . " does not have enough space for writing the config file! Not writing it back!");
|
||||
@@ -536,161 +112,11 @@ class ConfigurationManager
|
||||
file_put_contents(DataConst::GetConfigFile(), $content);
|
||||
}
|
||||
|
||||
private function GetEnvironmentalVariableOrConfig(string $envVariableName, string $configName, string $defaultValue) : string {
|
||||
$envVariableOutput = getenv($envVariableName);
|
||||
if ($envVariableOutput === false) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config[$configName]) || $config[$configName] === '') {
|
||||
$config[$configName] = $defaultValue;
|
||||
}
|
||||
return $config[$configName];
|
||||
}
|
||||
if(file_exists(DataConst::GetConfigFile())) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config[$configName])) {
|
||||
$config[$configName] = '';
|
||||
}
|
||||
if ($envVariableOutput !== $config[$configName]) {
|
||||
$config[$configName] = $envVariableOutput;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
}
|
||||
return $envVariableOutput;
|
||||
}
|
||||
|
||||
public function GetBorgBackupHostLocation() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['borg_backup_host_location'])) {
|
||||
$config['borg_backup_host_location'] = '';
|
||||
}
|
||||
|
||||
return $config['borg_backup_host_location'];
|
||||
}
|
||||
|
||||
public function GetBorgRestorePassword() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['borg_restore_password'])) {
|
||||
$config['borg_restore_password'] = '';
|
||||
}
|
||||
|
||||
return $config['borg_restore_password'];
|
||||
}
|
||||
|
||||
public function isInstanceRestoreAttempt() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['instance_restore_attempt'])) {
|
||||
$config['instance_restore_attempt'] = '';
|
||||
}
|
||||
|
||||
if ($config['instance_restore_attempt'] === 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetBorgBackupMode() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['backup-mode'])) {
|
||||
$config['backup-mode'] = '';
|
||||
}
|
||||
|
||||
return $config['backup-mode'];
|
||||
}
|
||||
|
||||
public function GetNextcloudMount() : string {
|
||||
$envVariableName = 'NEXTCLOUD_MOUNT';
|
||||
$configName = 'nextcloud_mount';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetNextcloudDatadirMount() : string {
|
||||
$envVariableName = 'NEXTCLOUD_DATADIR';
|
||||
$configName = 'nextcloud_datadir';
|
||||
$defaultValue = 'nextcloud_aio_nextcloud_data';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetNextcloudUploadLimit() : string {
|
||||
$envVariableName = 'NEXTCLOUD_UPLOAD_LIMIT';
|
||||
$configName = 'nextcloud_upload_limit';
|
||||
$defaultValue = '10G';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetNextcloudMemoryLimit() : string {
|
||||
$envVariableName = 'NEXTCLOUD_MEMORY_LIMIT';
|
||||
$configName = 'nextcloud_memory_limit';
|
||||
$defaultValue = '512M';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetApacheMaxSize() : int {
|
||||
$uploadLimit = (int)rtrim($this->GetNextcloudUploadLimit(), 'G');
|
||||
return $uploadLimit * 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
public function GetNextcloudMaxTime() : string {
|
||||
$envVariableName = 'NEXTCLOUD_MAX_TIME';
|
||||
$configName = 'nextcloud_max_time';
|
||||
$defaultValue = '3600';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetBorgRetentionPolicy() : string {
|
||||
$envVariableName = 'BORG_RETENTION_POLICY';
|
||||
$configName = 'borg_retention_policy';
|
||||
$defaultValue = '--keep-within=7d --keep-weekly=4 --keep-monthly=6';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetDockerSocketPath() : string {
|
||||
$envVariableName = 'WATCHTOWER_DOCKER_SOCKET_PATH';
|
||||
$configName = 'docker_socket_path';
|
||||
$defaultValue = '/var/run/docker.sock';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetTrustedCacertsDir() : string {
|
||||
$envVariableName = 'NEXTCLOUD_TRUSTED_CACERTS_DIR';
|
||||
$configName = 'trusted_cacerts_dir';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetNextcloudAdditionalApks() : string {
|
||||
$envVariableName = 'NEXTCLOUD_ADDITIONAL_APKS';
|
||||
$configName = 'nextcloud_additional_apks';
|
||||
$defaultValue = 'imagemagick';
|
||||
return trim($this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue));
|
||||
}
|
||||
|
||||
public function GetNextcloudAdditionalPhpExtensions() : string {
|
||||
$envVariableName = 'NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS';
|
||||
$configName = 'nextcloud_additional_php_extensions';
|
||||
$defaultValue = 'imagick';
|
||||
return trim($this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue));
|
||||
}
|
||||
|
||||
public function GetCollaboraSeccompPolicy() : string {
|
||||
$defaultString = '--o:security.seccomp=';
|
||||
if ($this->GetCollaboraSeccompDisabledState() !== 'true') {
|
||||
return $defaultString . 'true';
|
||||
}
|
||||
return $defaultString . 'false';
|
||||
}
|
||||
|
||||
private function GetCollaboraSeccompDisabledState() : string {
|
||||
$envVariableName = 'COLLABORA_SECCOMP_DISABLED';
|
||||
$configName = 'collabora_seccomp_disabled';
|
||||
$defaultValue = 'false';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetDailyBackupTime(string $time, bool $enableAutomaticUpdates, bool $successNotification) : void {
|
||||
public static function SetDailyBackupTime(string $time, bool $enableAutomaticUpdates, bool $successNotification): void {
|
||||
if ($time === "") {
|
||||
throw new InvalidSettingConfigurationException("The daily backup time must not be empty!");
|
||||
}
|
||||
@@ -698,7 +124,7 @@ class ConfigurationManager
|
||||
if (!preg_match("#^[0-1][0-9]:[0-5][0-9]$#", $time) && !preg_match("#^2[0-3]:[0-5][0-9]$#", $time)) {
|
||||
throw new InvalidSettingConfigurationException("You did not enter a correct time! One correct example is '04:00'!");
|
||||
}
|
||||
|
||||
|
||||
if ($enableAutomaticUpdates === false) {
|
||||
$time .= PHP_EOL . 'automaticUpdatesAreNotEnabled';
|
||||
} else {
|
||||
@@ -712,7 +138,7 @@ class ConfigurationManager
|
||||
file_put_contents(DataConst::GetDailyBackupTimeFile(), $time);
|
||||
}
|
||||
|
||||
public function GetDailyBackupTime() : string {
|
||||
public function GetDailyBackupTime(): string {
|
||||
if (!file_exists(DataConst::GetDailyBackupTimeFile())) {
|
||||
return '';
|
||||
}
|
||||
@@ -721,7 +147,7 @@ class ConfigurationManager
|
||||
return $dailyBackupFileArray[0];
|
||||
}
|
||||
|
||||
public function areAutomaticUpdatesEnabled() : bool {
|
||||
static function areAutomaticUpdatesEnabled(): bool {
|
||||
if (!file_exists(DataConst::GetDailyBackupTimeFile())) {
|
||||
return false;
|
||||
}
|
||||
@@ -734,19 +160,17 @@ class ConfigurationManager
|
||||
}
|
||||
}
|
||||
|
||||
public function DeleteDailyBackupTime() : void {
|
||||
public function DeleteDailyBackupTime(): void {
|
||||
if (file_exists(DataConst::GetDailyBackupTimeFile())) {
|
||||
unlink(DataConst::GetDailyBackupTimeFile());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetAdditionalBackupDirectories(string $additionalBackupDirectories) : void {
|
||||
/** @throws InvalidSettingConfigurationException */
|
||||
public static function SetAdditionalBackupDirectories(string $additionalBackupDirectories): void {
|
||||
$additionalBackupDirectoriesArray = explode("\n", $additionalBackupDirectories);
|
||||
$validDirectories = '';
|
||||
foreach($additionalBackupDirectoriesArray as $entry) {
|
||||
foreach ($additionalBackupDirectoriesArray as $entry) {
|
||||
// Trim all unwanted chars on both sites
|
||||
$entry = trim($entry);
|
||||
if ($entry !== "") {
|
||||
@@ -764,175 +188,38 @@ class ConfigurationManager
|
||||
}
|
||||
}
|
||||
|
||||
public function shouldLatestMajorGetInstalled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['install_latest_major'])) {
|
||||
$config['install_latest_major'] = '';
|
||||
}
|
||||
return $config['install_latest_major'] !== '';
|
||||
static function GetAdditionalBackupDirectoriesString(): string {
|
||||
return file_exists(DataConst::GetAdditionalBackupDirectoriesFile())
|
||||
? file_get_contents(DataConst::GetAdditionalBackupDirectoriesFile())
|
||||
: '';
|
||||
}
|
||||
|
||||
public function GetAdditionalBackupDirectoriesString() : string {
|
||||
if (!file_exists(DataConst::GetAdditionalBackupDirectoriesFile())) {
|
||||
return '';
|
||||
}
|
||||
$additionalBackupDirectories = file_get_contents(DataConst::GetAdditionalBackupDirectoriesFile());
|
||||
return $additionalBackupDirectories;
|
||||
}
|
||||
|
||||
public function GetAdditionalBackupDirectoriesArray() : array {
|
||||
$additionalBackupDirectories = $this->GetAdditionalBackupDirectoriesString();
|
||||
static function GetAdditionalBackupDirectoriesArray(): array {
|
||||
$additionalBackupDirectories = self::GetAdditionalBackupDirectoriesString();
|
||||
$additionalBackupDirectoriesArray = explode("\n", $additionalBackupDirectories);
|
||||
$additionalBackupDirectoriesArray = array_unique($additionalBackupDirectoriesArray, SORT_REGULAR);
|
||||
return $additionalBackupDirectoriesArray;
|
||||
}
|
||||
|
||||
public function isDailyBackupRunning() : bool {
|
||||
static function isDailyBackupRunning(): bool {
|
||||
if (file_exists(DataConst::GetDailyBackupBlockFile())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetTimezone() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['timezone'])) {
|
||||
$config['timezone'] = '';
|
||||
}
|
||||
|
||||
return $config['timezone'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetTimezone(string $timezone) : void {
|
||||
if ($timezone === "") {
|
||||
throw new InvalidSettingConfigurationException("The timezone must not be empty!");
|
||||
}
|
||||
|
||||
if (!preg_match("#^[a-zA-Z0-9_\-\/\+]+$#", $timezone)) {
|
||||
throw new InvalidSettingConfigurationException("The entered timezone does not seem to be a valid timezone!");
|
||||
}
|
||||
|
||||
$config = $this->GetConfig();
|
||||
$config['timezone'] = $timezone;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function DeleteTimezone() : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['timezone'] = '';
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function shouldDomainValidationBeSkipped() : bool {
|
||||
public function shouldDomainValidationBeSkipped(): bool {
|
||||
if (getenv('SKIP_DOMAIN_VALIDATION') !== false) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetNextcloudStartupApps() : string {
|
||||
static function GetNextcloudStartupApps(): string {
|
||||
$apps = getenv('NEXTCLOUD_STARTUP_APPS');
|
||||
if (is_string($apps)) {
|
||||
return trim($apps);
|
||||
}
|
||||
return 'deck twofactor_totp tasks calendar contacts notes';
|
||||
}
|
||||
|
||||
public function GetCollaboraDictionaries() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['collabora_dictionaries'])) {
|
||||
$config['collabora_dictionaries'] = '';
|
||||
}
|
||||
|
||||
return $config['collabora_dictionaries'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetCollaboraDictionaries(string $CollaboraDictionaries) : void {
|
||||
if ($CollaboraDictionaries === "") {
|
||||
throw new InvalidSettingConfigurationException("The dictionaries must not be empty!");
|
||||
}
|
||||
|
||||
if (!preg_match("#^[a-zA-Z_ ]+$#", $CollaboraDictionaries)) {
|
||||
throw new InvalidSettingConfigurationException("The entered dictionaries do not seem to be a valid!");
|
||||
}
|
||||
|
||||
$config = $this->GetConfig();
|
||||
$config['collabora_dictionaries'] = $CollaboraDictionaries;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function DeleteCollaboraDictionaries() : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['collabora_dictionaries'] = '';
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function GetApacheIPBinding() : string {
|
||||
$envVariableName = 'APACHE_IP_BINDING';
|
||||
$configName = 'apache_ip_binding';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
private function GetDisableBackupSection() : string {
|
||||
$envVariableName = 'AIO_DISABLE_BACKUP_SECTION';
|
||||
$configName = 'disable_backup_section';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function isBackupSectionEnabled() : bool {
|
||||
if ($this->GetDisableBackupSection() === 'true') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private function GetCommunityContainers() : string {
|
||||
$envVariableName = 'AIO_COMMUNITY_CONTAINERS';
|
||||
$configName = 'aio_community_containers';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetEnabledCommunityContainers() : array {
|
||||
return explode(' ', $this->GetCommunityContainers());
|
||||
}
|
||||
|
||||
private function GetEnabledDriDevice() : string {
|
||||
$envVariableName = 'NEXTCLOUD_ENABLE_DRI_DEVICE';
|
||||
$configName = 'nextcloud_enable_dri_device';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function isDriDeviceEnabled() : bool {
|
||||
if ($this->GetEnabledDriDevice() === 'true') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function GetKeepDisabledApps() : string {
|
||||
$envVariableName = 'NEXTCLOUD_KEEP_DISABLED_APPS';
|
||||
$configName = 'nextcloud_keep_disabled_apps';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function shouldDisabledAppsGetRemoved() : bool {
|
||||
if ($this->GetKeepDisabledApps() === 'true') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,30 +3,24 @@
|
||||
namespace AIO\Data;
|
||||
|
||||
use AIO\Auth\PasswordGenerator;
|
||||
use Random\RandomException;
|
||||
|
||||
class Setup
|
||||
{
|
||||
private PasswordGenerator $passwordGenerator;
|
||||
private ConfigurationManager $configurationManager;
|
||||
|
||||
public function __construct(
|
||||
PasswordGenerator $passwordGenerator,
|
||||
ConfigurationManager $configurationManager) {
|
||||
$this->passwordGenerator = $passwordGenerator;
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
public function Setup() : string {
|
||||
if(!$this->CanBeInstalled()) {
|
||||
readonly class Setup {
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
* @throws RandomException
|
||||
*/
|
||||
static function Setup(): string {
|
||||
if (!self::CanBeInstalled()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$password = $this->passwordGenerator->GeneratePassword(8);
|
||||
$this->configurationManager->SetPassword($password);
|
||||
$password = PasswordGenerator::GeneratePassword(8);
|
||||
ConfigurationManager::storeConfigFile(ConfigFile::blank($password));
|
||||
return $password;
|
||||
}
|
||||
|
||||
public function CanBeInstalled() : bool {
|
||||
static function CanBeInstalled(): bool {
|
||||
return !file_exists(DataConst::GetConfigFile());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use AIO\Container\State\NotRestartingState;
|
||||
use AIO\Container\State\VersionDifferentState;
|
||||
use AIO\Container\State\StoppedState;
|
||||
use AIO\Container\State\VersionEqualState;
|
||||
use AIO\Data\ConfigFile;
|
||||
use AIO\Data\ConfigurationManager;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use AIO\ContainerDefinitionFetcher;
|
||||
@@ -21,16 +22,13 @@ class DockerActionManager
|
||||
{
|
||||
private const string API_VERSION = 'v1.41';
|
||||
private \GuzzleHttp\Client $guzzleClient;
|
||||
private ConfigurationManager $configurationManager;
|
||||
private ContainerDefinitionFetcher $containerDefinitionFetcher;
|
||||
private DockerHubManager $dockerHubManager;
|
||||
|
||||
public function __construct(
|
||||
ConfigurationManager $configurationManager,
|
||||
ContainerDefinitionFetcher $containerDefinitionFetcher,
|
||||
DockerHubManager $dockerHubManager
|
||||
) {
|
||||
$this->configurationManager = $configurationManager;
|
||||
$this->containerDefinitionFetcher = $containerDefinitionFetcher;
|
||||
$this->dockerHubManager = $dockerHubManager;
|
||||
$this->guzzleClient = new \GuzzleHttp\Client(
|
||||
@@ -130,12 +128,13 @@ class DockerActionManager
|
||||
return new ImageDoesNotExistState();
|
||||
}
|
||||
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
$containerName = $container->GetIdentifier();
|
||||
$internalPort = $container->GetInternalPort();
|
||||
if($internalPort === '%APACHE_PORT%') {
|
||||
$internalPort = $this->configurationManager->GetApachePort();
|
||||
$internalPort = $config->apachePort;
|
||||
} elseif($internalPort === '%TALK_PORT%') {
|
||||
$internalPort = $this->configurationManager->GetTalkPort();
|
||||
$internalPort = $config->talkPort;
|
||||
}
|
||||
|
||||
if ($internalPort !== "" && $internalPort !== 'host') {
|
||||
@@ -221,11 +220,13 @@ class DockerActionManager
|
||||
}
|
||||
|
||||
public function CreateContainer(Container $container) : void {
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
|
||||
$volumes = [];
|
||||
foreach ($container->GetVolumes()->GetVolumes() as $volume) {
|
||||
// // NEXTCLOUD_MOUNT gets added via bind-mount later on
|
||||
// if ($container->GetIdentifier() === 'nextcloud-aio-nextcloud') {
|
||||
// if ($volume->name === $this->configurationManager->GetNextcloudMount()) {
|
||||
// if ($volume->name === $config->GetNextcloudMount()) {
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
@@ -249,17 +250,15 @@ class DockerActionManager
|
||||
}
|
||||
|
||||
foreach($container->GetSecrets() as $secret) {
|
||||
$this->configurationManager->GetAndGenerateSecret($secret);
|
||||
ConfigurationManager::GetAndGenerateSecret($secret);
|
||||
}
|
||||
|
||||
$aioVariables = $container->GetAioVariables()->GetVariables();
|
||||
foreach($aioVariables as $variable) {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$variableArray = explode('=', $variable);
|
||||
$config[$variableArray[0]] = $variableArray[1];
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
sleep(1);
|
||||
$config->overwrite($variableArray[0], $variableArray[1]);
|
||||
}
|
||||
if(!empty($aioVariables)) ConfigurationManager::storeConfigFile($config);
|
||||
|
||||
$envs = $container->GetEnvironmentVariables()->GetVariables();
|
||||
// Special thing for the nextcloud container
|
||||
@@ -269,8 +268,8 @@ class DockerActionManager
|
||||
foreach($envs as $key => $env) {
|
||||
// TODO: This whole block below is a hack and needs to get reworked in order to support multiple substitutions per line by default for all envs
|
||||
if (str_starts_with($env, 'extra_params=')) {
|
||||
$env = str_replace('%COLLABORA_SECCOMP_POLICY%', $this->configurationManager->GetCollaboraSeccompPolicy(), $env);
|
||||
$env = str_replace('%NC_DOMAIN%', $this->configurationManager->GetDomain(), $env);
|
||||
$env = str_replace('%COLLABORA_SECCOMP_POLICY%', $config->getCollaboraSeccompPolicy(), $env);
|
||||
$env = str_replace('%NC_DOMAIN%', $config->getDomain(), $env);
|
||||
$envs[$key] = $env;
|
||||
continue;
|
||||
}
|
||||
@@ -282,130 +281,130 @@ class DockerActionManager
|
||||
$replacements = array();
|
||||
|
||||
if($out[1] === 'NC_DOMAIN') {
|
||||
$replacements[1] = $this->configurationManager->GetDomain();
|
||||
$replacements[1] = $config->GetDomain();
|
||||
} elseif($out[1] === 'NC_BASE_DN') {
|
||||
$replacements[1] = $this->configurationManager->GetBaseDN();
|
||||
$replacements[1] = $config->GetBaseDN();
|
||||
} elseif ($out[1] === 'AIO_TOKEN') {
|
||||
$replacements[1] = $this->configurationManager->GetToken();
|
||||
$replacements[1] = $config->GetToken();
|
||||
} elseif ($out[1] === 'BORGBACKUP_MODE') {
|
||||
$replacements[1] = $this->configurationManager->GetBackupMode();
|
||||
$replacements[1] = $config->GetBackupMode();
|
||||
} elseif ($out[1] === 'AIO_URL') {
|
||||
$replacements[1] = $this->configurationManager->GetAIOURL();
|
||||
$replacements[1] = $config->aioUrl;
|
||||
} elseif ($out[1] === 'SELECTED_RESTORE_TIME') {
|
||||
$replacements[1] = $this->configurationManager->GetSelectedRestoreTime();
|
||||
$replacements[1] = $config->GetSelectedRestoreTime();
|
||||
} elseif ($out[1] === 'APACHE_PORT') {
|
||||
$replacements[1] = $this->configurationManager->GetApachePort();
|
||||
$replacements[1] = $config->apachePort;
|
||||
} elseif ($out[1] === 'TALK_PORT') {
|
||||
$replacements[1] = $this->configurationManager->GetTalkPort();
|
||||
$replacements[1] = $config->talkPort;
|
||||
} elseif ($out[1] === 'NEXTCLOUD_MOUNT') {
|
||||
$replacements[1] = $this->configurationManager->GetNextcloudMount();
|
||||
$replacements[1] = $config->nextcloudMount;
|
||||
} elseif ($out[1] === 'BACKUP_RESTORE_PASSWORD') {
|
||||
$replacements[1] = $this->configurationManager->GetBorgRestorePassword();
|
||||
$replacements[1] = $config->getBorgPassword();
|
||||
} elseif ($out[1] === 'CLAMAV_ENABLED') {
|
||||
if ($this->configurationManager->isClamavEnabled()) {
|
||||
if ($config->isClamavEnabled()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'TALK_RECORDING_ENABLED') {
|
||||
if ($this->configurationManager->isTalkRecordingEnabled()) {
|
||||
if ($config->isTalkRecordingEnabled()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'ONLYOFFICE_ENABLED') {
|
||||
if ($this->configurationManager->isOnlyofficeEnabled()) {
|
||||
if ($config->isOnlyofficeEnabled()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'COLLABORA_ENABLED') {
|
||||
if ($this->configurationManager->isCollaboraEnabled()) {
|
||||
if ($config->isCollaboraEnabled()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'TALK_ENABLED') {
|
||||
if ($this->configurationManager->isTalkEnabled()) {
|
||||
if ($config->talkEnabled) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'UPDATE_NEXTCLOUD_APPS') {
|
||||
if ($this->configurationManager->isDailyBackupRunning() && $this->configurationManager->areAutomaticUpdatesEnabled()) {
|
||||
if (ConfigurationManager::isDailyBackupRunning() && ConfigurationManager::areAutomaticUpdatesEnabled()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'TIMEZONE') {
|
||||
if ($this->configurationManager->GetTimezone() === '') {
|
||||
if ($config->GetTimezone() === '') {
|
||||
$replacements[1] = 'Etc/UTC';
|
||||
} else {
|
||||
$replacements[1] = $this->configurationManager->GetTimezone();
|
||||
$replacements[1] = $config->getTimezone();
|
||||
}
|
||||
} elseif ($out[1] === 'COLLABORA_DICTIONARIES') {
|
||||
if ($this->configurationManager->GetCollaboraDictionaries() === '') {
|
||||
if ($config->getCollaboraDictionaries() === '') {
|
||||
$replacements[1] = 'de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru';
|
||||
} else {
|
||||
$replacements[1] = $this->configurationManager->GetCollaboraDictionaries();
|
||||
$replacements[1] = $config->getCollaboraDictionaries();
|
||||
}
|
||||
} elseif ($out[1] === 'IMAGINARY_ENABLED') {
|
||||
if ($this->configurationManager->isImaginaryEnabled()) {
|
||||
if ($config->imaginaryEnabled) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'FULLTEXTSEARCH_ENABLED') {
|
||||
if ($this->configurationManager->isFulltextsearchEnabled()) {
|
||||
if ($config->fulltextsearchEnabled) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'DOCKER_SOCKET_PROXY_ENABLED') {
|
||||
if ($this->configurationManager->isDockerSocketProxyEnabled()) {
|
||||
if ($config->dockerSocketProxyEnabled) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'NEXTCLOUD_UPLOAD_LIMIT') {
|
||||
$replacements[1] = $this->configurationManager->GetNextcloudUploadLimit();
|
||||
$replacements[1] = $config->nextcloudUploadLimit;
|
||||
} elseif ($out[1] === 'NEXTCLOUD_MEMORY_LIMIT') {
|
||||
$replacements[1] = $this->configurationManager->GetNextcloudMemoryLimit();
|
||||
$replacements[1] = $config->nextcloudMemoryLimit;
|
||||
} elseif ($out[1] === 'NEXTCLOUD_MAX_TIME') {
|
||||
$replacements[1] = $this->configurationManager->GetNextcloudMaxTime();
|
||||
$replacements[1] = $config->nextcloudMaxTime;
|
||||
} elseif ($out[1] === 'BORG_RETENTION_POLICY') {
|
||||
$replacements[1] = $this->configurationManager->GetBorgRetentionPolicy();
|
||||
$replacements[1] = $config->borgRetentionPolicy;
|
||||
} elseif ($out[1] === 'NEXTCLOUD_TRUSTED_CACERTS_DIR') {
|
||||
$replacements[1] = $this->configurationManager->GetTrustedCacertsDir();
|
||||
$replacements[1] = $config->trustedCacertsDir;
|
||||
} elseif ($out[1] === 'ADDITIONAL_DIRECTORIES_BACKUP') {
|
||||
if ($this->configurationManager->GetAdditionalBackupDirectoriesString() !== '') {
|
||||
if (ConfigurationManager::GetAdditionalBackupDirectoriesString() !== '') {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'BORGBACKUP_HOST_LOCATION') {
|
||||
$replacements[1] = $this->configurationManager->GetBorgBackupHostLocation();
|
||||
$replacements[1] = $config->getBorgLocation();
|
||||
} elseif ($out[1] === 'APACHE_MAX_SIZE') {
|
||||
$replacements[1] = $this->configurationManager->GetApacheMaxSize();
|
||||
$replacements[1] = $config->GetApacheMaxSize();
|
||||
} elseif ($out[1] === 'COLLABORA_SECCOMP_POLICY') {
|
||||
$replacements[1] = $this->configurationManager->GetCollaboraSeccompPolicy();
|
||||
$replacements[1] = $config->GetCollaboraSeccompPolicy();
|
||||
} elseif ($out[1] === 'NEXTCLOUD_STARTUP_APPS') {
|
||||
$replacements[1] = $this->configurationManager->GetNextcloudStartupApps();
|
||||
$replacements[1] = ConfigurationManager::GetNextcloudStartupApps();
|
||||
} elseif ($out[1] === 'NEXTCLOUD_ADDITIONAL_APKS') {
|
||||
$replacements[1] = $this->configurationManager->GetNextcloudAdditionalApks();
|
||||
$replacements[1] = $config->nextcloudAdditionalApks;
|
||||
} elseif ($out[1] === 'NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS') {
|
||||
$replacements[1] = $this->configurationManager->GetNextcloudAdditionalPhpExtensions();
|
||||
$replacements[1] = $config->nextcloudAdditionalPhpExtensions;
|
||||
} elseif ($out[1] === 'INSTALL_LATEST_MAJOR') {
|
||||
if ($this->configurationManager->shouldLatestMajorGetInstalled()) {
|
||||
if ($config->installLatestMajor) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'REMOVE_DISABLED_APPS') {
|
||||
if ($this->configurationManager->shouldDisabledAppsGetRemoved()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
if ($config->nextcloudKeepDisabledApps) {
|
||||
$replacements[1] = '';
|
||||
} else {
|
||||
$replacements[1] = 'yes';
|
||||
}
|
||||
// Allow to get local ip-address of database container which allows to talk to it even in host mode (the container that requires this needs to be started first then)
|
||||
} elseif ($out[1] === 'AIO_DATABASE_HOST') {
|
||||
@@ -413,12 +412,18 @@ class DockerActionManager
|
||||
// Allow to get local ip-address of caddy container and add it to trusted proxies automatically
|
||||
} elseif ($out[1] === 'CADDY_IP_ADDRESS') {
|
||||
$replacements[1] = '';
|
||||
$communityContainers = $this->configurationManager->GetEnabledCommunityContainers();
|
||||
$communityContainers = $config->aioCommunityContainers;
|
||||
if (in_array('caddy', $communityContainers, true)) {
|
||||
$replacements[1] = gethostbyname('nextcloud-aio-caddy');
|
||||
}
|
||||
} elseif ($out[1] === 'WHITEBOARD_ENABLED') {
|
||||
if ($config->whiteboardEnabled) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} else {
|
||||
$secret = $this->configurationManager->GetSecret($out[1]);
|
||||
$secret = $config->GetSecret($out[1]);
|
||||
if ($secret === "") {
|
||||
throw new \Exception("The secret " . $out[1] . " is empty. Cannot substitute its value. Please check if it is defined in secrets of containers.json.");
|
||||
}
|
||||
@@ -443,13 +448,13 @@ class DockerActionManager
|
||||
$port = $value->port;
|
||||
$protocol = $value->protocol;
|
||||
if ($port === '%APACHE_PORT%') {
|
||||
$port = $this->configurationManager->GetApachePort();
|
||||
$port = $config->apachePort;
|
||||
// Do not expose udp if AIO is in reverse proxy mode
|
||||
if ($port !== '443' && $protocol === 'udp') {
|
||||
continue;
|
||||
}
|
||||
} else if ($port === '%TALK_PORT%') {
|
||||
$port = $this->configurationManager->GetTalkPort();
|
||||
$port = $config->talkPort;
|
||||
}
|
||||
$portWithProtocol = $port . '/' . $protocol;
|
||||
$exposedPorts[$portWithProtocol] = null;
|
||||
@@ -465,17 +470,17 @@ class DockerActionManager
|
||||
$port = $value->port;
|
||||
$protocol = $value->protocol;
|
||||
if ($port === '%APACHE_PORT%') {
|
||||
$port = $this->configurationManager->GetApachePort();
|
||||
$port = $config->apachePort;
|
||||
// Do not expose udp if AIO is in reverse proxy mode
|
||||
if ($port !== '443' && $protocol === 'udp') {
|
||||
continue;
|
||||
}
|
||||
} else if ($port === '%TALK_PORT%') {
|
||||
$port = $this->configurationManager->GetTalkPort();
|
||||
$port = $config->talkPort;
|
||||
}
|
||||
$ipBinding = $value->ipBinding;
|
||||
if ($ipBinding === '%APACHE_IP_BINDING%') {
|
||||
$ipBinding = $this->configurationManager->GetApacheIPBinding();
|
||||
$ipBinding = $config->apacheIpBinding;
|
||||
// Do not expose if AIO is in internal network mode
|
||||
if ($ipBinding === '@INTERNAL') {
|
||||
continue;
|
||||
@@ -493,7 +498,7 @@ class DockerActionManager
|
||||
|
||||
$devices = [];
|
||||
foreach($container->GetDevices() as $device) {
|
||||
if ($device === '/dev/dri' && ! $this->configurationManager->isDriDeviceEnabled()) {
|
||||
if ($device === '/dev/dri' && ! $config->nextcloudEnableDriDevice) {
|
||||
continue;
|
||||
}
|
||||
$devices[] = ["PathOnHost" => $device, "PathInContainer" => $device, "CgroupPermissions" => "rwm"];
|
||||
@@ -549,7 +554,7 @@ class DockerActionManager
|
||||
$mounts[] = ["Type" => "volume", "Source" => $additionalBackupVolumes, "Target" => "/nextcloud_aio_volumes/" . $additionalBackupVolumes, "ReadOnly" => false];
|
||||
}
|
||||
}
|
||||
foreach ($this->configurationManager->GetAdditionalBackupDirectoriesArray() as $additionalBackupDirectories) {
|
||||
foreach (ConfigurationManager::GetAdditionalBackupDirectoriesArray() as $additionalBackupDirectories) {
|
||||
if ($additionalBackupDirectories !== '') {
|
||||
if (!str_starts_with($additionalBackupDirectories, '/')) {
|
||||
$mounts[] = ["Type" => "volume", "Source" => $additionalBackupDirectories, "Target" => "/docker_volumes/" . $additionalBackupDirectories, "ReadOnly" => true];
|
||||
@@ -565,7 +570,7 @@ class DockerActionManager
|
||||
// // Special things for the nextcloud container which should not be exposed in the containers.json
|
||||
// } elseif ($container->GetIdentifier() === 'nextcloud-aio-nextcloud') {
|
||||
// foreach ($container->GetVolumes()->GetVolumes() as $volume) {
|
||||
// if ($volume->name !== $this->configurationManager->GetNextcloudMount()) {
|
||||
// if ($volume->name !== $config->GetNextcloudMount()) {
|
||||
// continue;
|
||||
// }
|
||||
// $mounts[] = ["Type" => "bind", "Source" => $volume->name, "Target" => $volume->mountPoint, "ReadOnly" => !$volume->isWritable, "BindOptions" => [ "Propagation" => "rshared"]];
|
||||
@@ -646,7 +651,8 @@ class DockerActionManager
|
||||
|
||||
public function isAnyUpdateAvailable() : bool {
|
||||
// return early if instance is not installed
|
||||
if (!$this->configurationManager->wasStartButtonClicked()) {
|
||||
$config = ConfigurationManager::loadConfigFile();
|
||||
if (!$config->wasStartButtonClicked) {
|
||||
return false;
|
||||
}
|
||||
$id = 'nextcloud-aio-apache';
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
<form method="POST" action="/api/auth/logout">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" id="logout" value="Log out" />
|
||||
<input type="submit" value="Log out" />
|
||||
</form>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h1>Nextcloud AIO v9.4.1</h1>
|
||||
<main>
|
||||
<h1>Nextcloud AIO v9.6.0</h1>
|
||||
|
||||
{# Add 2nd tab warning #}
|
||||
<script type="text/javascript" src="second-tab-warning.js"></script>
|
||||
@@ -31,7 +31,7 @@
|
||||
{% set isBackupOrRestoreRunning = false %}
|
||||
{% set isApacheStarting = false %}
|
||||
{# Setting newMajorVersion to '' will hide corresponding options/elements, can be set to an integer like 26 in order to show corresponding elements. If set, also increase installLatestMajor in https://github.com/nextcloud/all-in-one/blob/main/php/src/Controller/DockerController.php #}
|
||||
{% set newMajorVersion = '' %}
|
||||
{% set newMajorVersion = 30 %}
|
||||
|
||||
{% if is_backup_container_running == true %}
|
||||
{% if borg_backup_mode == 'backup' or borg_backup_mode == 'restore' %}
|
||||
@@ -58,107 +58,107 @@
|
||||
{% endfor %}
|
||||
|
||||
{% if is_daily_backup_running == true %}
|
||||
<span class="status running"></span> Daily backup currently running. (<a href="/api/docker/logs?id=nextcloud-aio-mastercontainer" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
<p><span class="status running"></span> Daily backup currently running. (<a href="/api/docker/logs?id=nextcloud-aio-mastercontainer" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
{% if automatic_updates == true %}
|
||||
This will update your containers, the mastercontainer and, on Saturdays, your Nextcloud apps if the backup is successful.<br /><br />
|
||||
<p>This will update your containers, the mastercontainer and, on Saturdays, your Nextcloud apps if the backup is successful.</p>
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
When the mastercontainer is updated it will restart, making it unavailable for a moment. (<a href="/api/docker/logs?id=nextcloud-aio-watchtower" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
<p>When the mastercontainer is updated it will restart, making it unavailable for a moment. (<a href="/api/docker/logs?id=nextcloud-aio-watchtower" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if has_update_available == false %}
|
||||
The whole process should not take more than a few minutes.<br /><br />
|
||||
<p>The whole process should not take more than a few minutes.</p>
|
||||
{% elseif automatic_updates == true %}
|
||||
The whole process can take a while as your containers will be updated.<br /><br />
|
||||
<p>The whole process can take a while as your containers will be updated.</p>
|
||||
{% endif %}
|
||||
<a href="" class="button reload">Reload ↻</a><br/><br/>
|
||||
If the daily backup is stuck somehow, you can unstick it by running <strong>sudo docker exec nextcloud-aio-mastercontainer rm /mnt/docker-aio-config/data/daily_backup_running</strong> and afterwards reloading this interface.<br /><br />
|
||||
<p><a href="" class="button reload">Reload ↻</a></p>
|
||||
<p>If the daily backup is stuck somehow, you can unstick it by running <strong>sudo docker exec nextcloud-aio-mastercontainer rm /mnt/docker-aio-config/data/daily_backup_running</strong> and afterwards reloading this interface.</p>
|
||||
{% elseif isWatchtowerRunning == true %}
|
||||
<span class="status running"></span> Mastercontainer update currently running. Once the update is complete the mastercontainer will restart, making it unavailable for a moment. Please wait until it's done. (<a href="/api/docker/logs?id=nextcloud-aio-watchtower" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
<a href="" class="button reload">Reload ↻</a><br/>
|
||||
<p><span class="status running"></span> Mastercontainer update currently running. Once the update is complete the mastercontainer will restart, making it unavailable for a moment. Please wait until it's done. (<a href="/api/docker/logs?id=nextcloud-aio-watchtower" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
<p><a href="" class="button reload">Reload ↻</a></p>
|
||||
{% else %}
|
||||
{% if is_backup_container_running == false and domain == "" %}
|
||||
{% if isDomaincheckRunning == false %}
|
||||
<h2>Domaincheck container is not running</h2>
|
||||
This is not expected. Most likely this happened because port {{ apache_port }} is already in use on your server. You can check the mastercontainer logs and domaincheck container logs for further clues. You should be able to resolve this by adjusting the APACHE_PORT by following the <strong><a href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md">reverse proxy documentation</a></strong>. Advice: have a detailed look at the changed docker run command for AIO.
|
||||
<p>This is not expected. Most likely this happened because port {{ apache_port }} is already in use on your server. You can check the mastercontainer logs and domaincheck container logs for further clues. You should be able to resolve this by adjusting the APACHE_PORT by following the <strong><a href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md">reverse proxy documentation</a></strong>. Advice: have a detailed look at the changed docker run command for AIO.</p>
|
||||
{% elseif is_mastercontainer_update_available == true %}
|
||||
<h2>Mastercontainer update</h2>
|
||||
⚠️ A mastercontainer update is available. Please click on the button below to update it. Afterwards, you will be able to proceed with the setup.<br><br>
|
||||
<p>⚠️ A mastercontainer update is available. Please click on the button below to update it. Afterwards, you will be able to proceed with the setup.</p>
|
||||
<form method="POST" action="/api/docker/watchtower" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Update mastercontainer" />
|
||||
<input type="submit" value="Update mastercontainer" />
|
||||
</form>
|
||||
{% else %}
|
||||
{% if borg_backup_host_location == '' and borg_restore_password == '' %}
|
||||
The official Nextcloud installation method. Nextcloud All-in-One provides easy deployment and maintenance with most features included in this one Nextcloud instance.<br><br>
|
||||
You can either create a new AIO instance or restore a former AIO instance from backup. See the two sections below.<br><br>
|
||||
<p>The official Nextcloud installation method. Nextcloud All-in-One provides easy deployment and maintenance with most features included in this one Nextcloud instance.</p>
|
||||
<p>You can either create a new AIO instance or restore a former AIO instance from backup. See the two sections below.</p>
|
||||
{{ include('includes/aio-config.twig') }}
|
||||
<h2>New AIO instance</h2>
|
||||
{% if apache_port == '443' %}
|
||||
AIO is currently in "normal mode" which means that it handles the TLS proxying itself. This also means that it cannot be installed behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). If you want to run AIO behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), see the <strong><a href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md">reverse proxy documentation</a></strong>. Advice: have a detailed look at the changed docker run command for AIO.<br><br>
|
||||
<p>AIO is currently in "normal mode" which means that it handles the TLS proxying itself. This also means that it cannot be installed behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). If you want to run AIO behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), see the <strong><a href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md">reverse proxy documentation</a></strong>. Advice: have a detailed look at the changed docker run command for AIO.</p>
|
||||
{% else %}
|
||||
AIO is currently in "reverse proxy mode" which means that it can be installed behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) and does not do the TLS proxying itself.<br><br>
|
||||
<p>AIO is currently in "reverse proxy mode" which means that it can be installed behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) and does not do the TLS proxying itself.</p>
|
||||
{% endif %}
|
||||
Please type the domain that will be used for Nextcloud below in order to create a new AIO instance.<br><br />
|
||||
<p>Please type the domain that will be used for Nextcloud below in order to create a new AIO instance.</p>
|
||||
{% if skip_domain_validation == true %}
|
||||
<strong>Please note:</strong> The domain validation is disabled so any domain will be accepted here! Make sure you do not make a typo here as you will not be able to change it afterwards!<br><br>
|
||||
<p><strong>Please note:</strong> The domain validation is disabled so any domain will be accepted here! Make sure you do not make a typo here as you will not be able to change it afterwards!</p>
|
||||
{% endif %}
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" name="domain" value="{{ domain }}" placeholder="nextcloud.yourdomain.com"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit domain" />
|
||||
<input type="submit" value="Submit domain" />
|
||||
</form>
|
||||
{% if skip_domain_validation == false %}
|
||||
Make sure that this server is reachable on port 443 (port 443/tcp is open/forwarded in your firewall/router and 443/udp as well if you want to enable http3) and that you've correctly set up the DNS config for the domain that you enter (set the A record to your public ipv4-address and if you need ipv6, set the AAAA record to your public ipv6-address. A CNAME record is, of course, also possible). You should see hints on what went wrong in the top right corner if your domain is not accepted.<br><br>
|
||||
<p>Make sure that this server is reachable on port 443 (port 443/tcp is open/forwarded in your firewall/router and 443/udp as well if you want to enable http3) and that you've correctly set up the DNS config for the domain that you enter (set the A record to your public ipv4-address and if you need ipv6, set the AAAA record to your public ipv6-address. A CNAME record is, of course, also possible). You should see hints on what went wrong in the top right corner if your domain is not accepted.</p>
|
||||
<details>
|
||||
<summary>Click here for further hints</summary><br />
|
||||
If you do not have a domain yet, you can get one for free e.g. from duckdns.org and others.<br><br>
|
||||
If you have a dynamic public IP-address, you can use e.g. <a href="https://ddclient.net/">DDclient</a> with a compatible domain provider for DNS updates.<br /><br/>
|
||||
If you only want to install AIO locally without exposing it to the public internet or if you cannot do so, feel free to follow <a href="https://github.com/nextcloud/all-in-one/blob/main/local-instance.md">this documentation</a>.<br><br>
|
||||
If you should be using Cloudflare Proxy for your domain, make sure to disable the Proxy feature temporarily as it might block the domain validation attempts.<br /><br/>
|
||||
<summary>Click here for further hints</summary>
|
||||
<p>If you do not have a domain yet, you can get one for free e.g. from duckdns.org and others.</p>
|
||||
<p>If you have a dynamic public IP-address, you can use e.g. <a href="https://ddclient.net/">DDclient</a> with a compatible domain provider for DNS updates.</p>
|
||||
<p>If you only want to install AIO locally without exposing it to the public internet or if you cannot do so, feel free to follow <a href="https://github.com/nextcloud/all-in-one/blob/main/local-instance.md">this documentation</a>.</p>
|
||||
<p>If you should be using Cloudflare Proxy for your domain, make sure to disable the Proxy feature temporarily as it might block the domain validation attempts.</p>
|
||||
{% if apache_port != '443' %}
|
||||
If you run into issues with your domain being accepted, see <a href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#6-how-to-debug-things">these steps</a> for how to debug things. <br /><br/>
|
||||
<p>If you run into issues with your domain being accepted, see <a href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#6-how-to-debug-things">these steps</a> for how to debug things.</p>
|
||||
{% endif %}
|
||||
<strong>Hint:</strong> If the domain validation fails but you are completely sure that you've configured everything correctly, you may skip the domain validation by following <a href="https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation">this documentation</a>.<br />
|
||||
<p><strong>Hint:</strong> If the domain validation fails but you are completely sure that you've configured everything correctly, you may skip the domain validation by following <a href="https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation">this documentation</a>.</p>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
<h2>Restore former AIO instance from backup</h2>
|
||||
You can alternatively restore a former AIO instance from backup.<br><br>
|
||||
<p>You can alternatively restore a former AIO instance from backup.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if is_instance_restore_attempt == false %}
|
||||
{% if borg_backup_host_location != '' and borg_restore_password != '' %}
|
||||
{% if borg_backup_mode in ['test', 'check'] %}
|
||||
{% if backup_exit_code > 0 %}
|
||||
<span class="status error"></span> Last {{ borg_backup_mode }} failed! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
<p><span class="status error"></span> Last {{ borg_backup_mode }} failed! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
{% if borg_backup_mode == 'test' %}
|
||||
Please adjust the path and/or the encryption password in order to make it work!<br><br>
|
||||
<p>Please adjust the path and/or the encryption password in order to make it work!</p>
|
||||
{% elseif borg_backup_mode == 'check' %}
|
||||
The backup archive seems to be corrupt. Please try to use a different intact backup archive or try to fix it by following <a href="https://borgbackup.readthedocs.io/en/stable/faq.html#i-get-an-integrityerror-or-similar-what-now"><strong>this documentation</strong></a><br><br>
|
||||
<p>The backup archive seems to be corrupt. Please try to use a different intact backup archive or try to fix it by following <a href="https://borgbackup.readthedocs.io/en/stable/faq.html#i-get-an-integrityerror-or-similar-what-now"><strong>this documentation</strong></a></p>
|
||||
<details>
|
||||
<summary>Reveal repair option</summary><br />
|
||||
Below is the option to repair the integrity of your backup. <strong>Please note:</strong> Please only use this after you have read the documentation above! (It will run the command 'borg check --repair' for you.)<br><br>
|
||||
<summary>Reveal repair option</summary>
|
||||
<p>Below is the option to repair the integrity of your backup. <strong>Please note:</strong> Please only use this after you have read the documentation above! (It will run the command 'borg check --repair' for you.)</p>
|
||||
<form method="POST" action="/api/docker/backup-check-repair" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Check and repair backup integrity" onclick="return confirm('Check and repair backup integrity? Are you sure that you want to check and repair the backup integrity? This should only be done after reading the mentioned documentation.')"/><br/>
|
||||
</form><br />
|
||||
</details><br />
|
||||
<input type="submit" value="Check and repair backup integrity" onclick="return confirm('Check and repair backup integrity? Are you sure that you want to check and repair the backup integrity? This should only be done after reading the mentioned documentation.')"/>
|
||||
</form>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% elseif backup_exit_code == 0 %}
|
||||
<span class="status success"></span> Last {{ borg_backup_mode }} successful! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
<p><span class="status success"></span> Last {{ borg_backup_mode }} successful! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
{% if borg_backup_mode == 'test' %}
|
||||
Feel free to check the integrity of the backup archive below before starting the restore process in order to make ensure that the restore will work. This can take a long time though depending on the size of the backup archive and is thus not required.<br><br>
|
||||
<p>Feel free to check the integrity of the backup archive below before starting the restore process in order to make ensure that the restore will work. This can take a long time though depending on the size of the backup archive and is thus not required.</p>
|
||||
<form method="POST" action="/api/docker/backup-check" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Check backup integrity"/><br/>
|
||||
<input type="submit" value="Check backup integrity"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
Choose the backup that you want to restore and click on the button below to restore the selected backup. This will restore the whole AIO instance. Please note that the current AIO passphrase will be kept and the previous AIO passphrase will not be restored from backup!<br><br>
|
||||
<strong>Please note:</strong> If the backup that you want to restore contained any <a href="https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers">community container</a>, but you did not specify the same community containers via environmental variable while creating this new AIO instance, you need to restore the same backup a second time after this attempt so that the community container data is also correctly restored.<br><br>
|
||||
<p>Choose the backup that you want to restore and click on the button below to restore the selected backup. This will restore the whole AIO instance. Please note that the current AIO passphrase will be kept and the previous AIO passphrase will not be restored from backup!</p>
|
||||
<p><strong>Please note:</strong> If the backup that you want to restore contained any <a href="https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers">community container</a>, but you did not specify the same community containers via environmental variable while creating this new AIO instance, you need to restore the same backup a second time after this attempt so that the community container data is also correctly restored.</p>
|
||||
<form method="POST" action="/api/docker/restore" class="xhr" id="restore_selection">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
@@ -167,53 +167,53 @@
|
||||
<option value="{{ restore_time }}">{{ restore_time }} UTC</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input class="button" type="submit" value="Restore selected backup"/>
|
||||
<input type="submit" value="Restore selected backup"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% elseif borg_backup_mode == 'restore' %}
|
||||
{% if backup_exit_code > 0 %}
|
||||
<span class="status error"></span> Last restore failed! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
The restore process has unexpectedly failed! Please adjust the path and encryption password, test it and try to restore again!
|
||||
<p><span class="status error"></span> Last restore failed! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
<p>The restore process has unexpectedly failed! Please adjust the path and encryption password, test it and try to restore again!</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if borg_backup_host_location == '' or borg_restore_password == '' or borg_backup_mode not in ['test', 'check', ''] or backup_exit_code > 0 %}
|
||||
Please enter the location of the backup archive on your host and the encryption password of the backup archive below:<br><br>
|
||||
<p>Please enter the location of the backup archive on your host and the encryption password of the backup archive below:</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" name="borg_restore_host_location" value="{{borg_backup_host_location}}" placeholder="/mnt/backup"/>
|
||||
<input type="text" name="borg_restore_password" value="{{borg_restore_password}}" placeholder="encryption password"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit location and encryption password" />
|
||||
<input type="submit" value="Submit location and encryption password" />
|
||||
</form>
|
||||
{{ include('includes/backup-dirs.twig') }}
|
||||
⚠️ Please note that the backup archive must be located in a subfolder of the folder that you enter here and the subfolder which contains the archive must be named 'borg', or the backup container will not be able to find the backup archive!<br><br>
|
||||
<p>⚠️ Please note that the backup archive must be located in a subfolder of the folder that you enter here and the subfolder which contains the archive must be named 'borg', or the backup container will not be able to find the backup archive!</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<strong>Everything set!</strong> Click on the button below to test the path and encryption password:<br/><br/>
|
||||
<p><strong>Everything set!</strong> Click on the button below to test the path and encryption password:</p>
|
||||
<form method="POST" action="/api/docker/backup-test" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Test path and encryption password"/><br/>
|
||||
<input type="submit" value="Test path and encryption password"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<h2>How to reset the AIO instance?</h2>
|
||||
If something should be going wrong, for example during the initial installation, you can reset the instance by following <a href="https://github.com/nextcloud/all-in-one#how-to-properly-reset-the-instance">this documentation</a>.<br><br>
|
||||
<p>If something should be going wrong, for example during the initial installation, you can reset the instance by following <a href="https://github.com/nextcloud/all-in-one#how-to-properly-reset-the-instance">this documentation</a>.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if was_start_button_clicked == true %}
|
||||
{% if current_channel starts with 'latest' or current_channel starts with 'beta' or current_channel starts with 'develop' %}
|
||||
You are running the <a href="https://github.com/nextcloud/all-in-one#how-to-switch-the-channel"><strong>{{ current_channel }}</strong></a> channel. (<a href="/api/docker/logs?id=nextcloud-aio-mastercontainer" target="_blank" rel="noopener">Logs</a>)<br><br>
|
||||
<p>You are running the <a href="https://github.com/nextcloud/all-in-one#how-to-switch-the-channel"><strong>{{ current_channel }}</strong></a> channel. (<a href="/api/docker/logs?id=nextcloud-aio-mastercontainer" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
{% else %}
|
||||
No channel was found. This means that AIO is not able to update itself and its component and will also not be able to report about updates. Updates need to be done externally.
|
||||
<p>No channel was found. This means that AIO is not able to update itself and its component and will also not be able to report about updates. Updates need to be done externally.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_backup_container_running == true %}
|
||||
<span class="status running"></span> Backup container is currently running: {{ borg_backup_mode }} (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
<a href="" class="button reload">Reload ↻</a><br/><br>
|
||||
<p><span class="status running"></span> Backup container is currently running: {{ borg_backup_mode }} (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
<p><a href="" class="button reload">Reload ↻</a></p>
|
||||
{% endif %}
|
||||
|
||||
{% if domain != "" %}
|
||||
@@ -221,31 +221,30 @@
|
||||
{% if isApacheStarting != true %}
|
||||
{% if borg_backup_host_location != '' %}
|
||||
<details>
|
||||
<summary>Click here to reveal the initial Nextcloud credentials</summary><br />
|
||||
<summary>Click here to reveal the initial Nextcloud credentials</summary>
|
||||
{% endif %}
|
||||
Initial Nextcloud username: <strong>admin</strong><br />
|
||||
Initial Nextcloud password:
|
||||
<p>Initial Nextcloud username: <strong>admin</strong></p>
|
||||
{% if borg_backup_host_location != '' %}
|
||||
{# nextcloud_password needs to be duplicated due to a bug in Firefox. See https://github.com/nextcloud/all-in-one/issues/638. #}
|
||||
<strong>{{ nextcloud_password }}</strong><br /></details><br />
|
||||
<p>Initial Nextcloud password: <strong>{{ nextcloud_password }}</strong></p></details>
|
||||
{% else %}
|
||||
<strong>{{ nextcloud_password }}</strong><br><br>
|
||||
<p>Initial Nextcloud password: <strong>{{ nextcloud_password }}</strong></p>
|
||||
{% endif %}
|
||||
<a href="https://{{ domain }}" class="button" target="_blank" rel="noopener">Open your Nextcloud ↗</a><br/><br>
|
||||
<p><a href="https://{{ domain }}" class="button" target="_blank" rel="noopener">Open your Nextcloud ↗</a></p>
|
||||
{% if borg_backup_host_location == '' %}
|
||||
If your Nextcloud does not open when clicking the button above, see <strong><a href="https://github.com/nextcloud/all-in-one/discussions/2105">this documentation</a></strong><br><br>
|
||||
<p>If your Nextcloud does not open when clicking the button above, see <strong><a href="https://github.com/nextcloud/all-in-one/discussions/2105">this documentation</a></strong></p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if isAnyRestarting == false %}
|
||||
<span class="status running"></span> Containers are currently starting. You might inspect the container logs by clicking on <strong>Starting</strong> next to each container for further details.<br /><br />
|
||||
<a href="" class="button reload">Reload ↻</a><br/><br>
|
||||
<p><span class="status running"></span> Containers are currently starting. You might inspect the container logs by clicking on <strong>Starting</strong> next to each container for further details.</p>
|
||||
<p><a href="" class="button reload">Reload ↻</a></p>
|
||||
{% else %}
|
||||
It seems at least one container was not able to start correctly and is currently restarting.<br><br>
|
||||
To break this endless loop, you can stop the containers below and investigate the issue in the container logs before starting the containers again.<br><br>
|
||||
<p>It seems at least one container was not able to start correctly and is currently restarting.</p>
|
||||
<p>To break this endless loop, you can stop the containers below and investigate the issue in the container logs before starting the containers again.</p>
|
||||
<form method="POST" action="/api/docker/stop" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Stop containers" />
|
||||
<input type="submit" value="Stop containers" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -291,16 +290,16 @@
|
||||
|
||||
{% if has_update_available == true %}
|
||||
{% if is_mastercontainer_update_available == false %}
|
||||
⚠️ Container updates are available. Click on <strong>Stop containers</strong> and <strong>Start and update containers</strong> to update them. You should consider creating a backup first.<br><br>
|
||||
<p>⚠️ Container updates are available. Click on <strong>Stop containers</strong> and <strong>Start and update containers</strong> to update them. You should consider creating a backup first.</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if is_mastercontainer_update_available == false %}
|
||||
Your containers are up-to-date.<br><br>
|
||||
<p>Your containers are up-to-date.</p>
|
||||
{% if newMajorVersion != '' and isAnyRunning == true and isApacheStarting != true %}
|
||||
<details>
|
||||
<summary>Note about <strong>Nextcloud {{ newMajorVersion }}</strong></summary><br>
|
||||
If you haven't upgraded to Nextcloud {{ newMajorVersion }} yet and want to do that now, feel free to follow <strong><a href="https://github.com/nextcloud/all-in-one/discussions/4542">this documentation</a></strong><br/>
|
||||
</details><br>
|
||||
<summary>Note about <strong>Nextcloud Hub {{ newMajorVersion - 21 }}</strong></summary>
|
||||
<p>If you haven't upgraded to Nextcloud Hub {{ newMajorVersion - 21 }} yet and want to do that now, feel free to follow <strong><a href="https://github.com/nextcloud/all-in-one/discussions/5133">this documentation</a></strong></p>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -309,34 +308,34 @@
|
||||
{% if isAnyRunning == true %}
|
||||
{% if isApacheStarting != true %}
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
⚠️ A mastercontainer update is available. Please click on the button below to stop your containers in order to update the mastercontainer.<br /><br />
|
||||
<p>⚠️ A mastercontainer update is available. Please click on the button below to stop your containers in order to update the mastercontainer.</p>
|
||||
{% if current_channel starts with 'latest' %}
|
||||
You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases/latest"><strong>here</strong></a><br><br>
|
||||
<p>You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases/latest"><strong>here</strong></a></p>
|
||||
{% elseif current_channel starts with 'beta' %}
|
||||
You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases"><strong>here</strong></a><br><br>
|
||||
<p>You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases"><strong>here</strong></a></p>
|
||||
{% elseif current_channel starts with 'develop' %}
|
||||
You can find all changes <a href="https://github.com/nextcloud-releases/all-in-one/commits/main"><strong>here</strong></a><br><br>
|
||||
<p>You can find all changes <a href="https://github.com/nextcloud-releases/all-in-one/commits/main"><strong>here</strong></a></p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<form method="POST" action="/api/docker/stop" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Stop containers" />
|
||||
<input type="submit" value="Stop containers" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if isBackupOrRestoreRunning == true %}
|
||||
Restore or Backup currently running. Cannot start the containers until Restore or Backup is complete.<br /><br />
|
||||
<p>Restore or Backup currently running. Cannot start the containers until Restore or Backup is complete.</p>
|
||||
{% else %}
|
||||
{% if was_start_button_clicked == false %}
|
||||
<br>Clicking on the button below will download all docker containers and start them. This can take a long time depending on your internet connection. Since the overall size is a few GB, this can take around 5-10 min or more. Please be patient!<br><br>
|
||||
<p>Clicking on the button below will download all docker containers and start them. This can take a long time depending on your internet connection. Since the overall size is a few GB, this can take around 5-10 min or more. Please be patient!</p>
|
||||
{% endif %}
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
⚠️ A mastercontainer update is available. Please click on the button below to update it.<br><br>
|
||||
<p>⚠️ A mastercontainer update is available. Please click on the button below to update it.</p>
|
||||
<form method="POST" action="/api/docker/watchtower" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Update mastercontainer" />
|
||||
<input type="submit" value="Update mastercontainer" />
|
||||
</form>
|
||||
{% else %}
|
||||
{% if was_start_button_clicked == false %}
|
||||
@@ -344,15 +343,15 @@
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
{% if newMajorVersion != '' %}
|
||||
<input type="checkbox" id="install_latest_major" name="install_latest_major"><label for="install_latest_major">Install Nextcloud {{ newMajorVersion }} (if unchecked, Nextcloud {{ newMajorVersion - 1 }} will get installed)</label><br>
|
||||
<input type="checkbox" id="install_latest_major" name="install_latest_major"><label for="install_latest_major">Install Nextcloud Hub {{ newMajorVersion - 21 }} (if unchecked, Nextcloud Hub {{ newMajorVersion - 22 }} will get installed)</label><br>
|
||||
{% endif %}
|
||||
<input class="button" type="submit" value="Download and start containers" />
|
||||
<input type="submit" value="Download and start containers" />
|
||||
</form>
|
||||
{% elseif has_update_available == false %}
|
||||
<form method="POST" action="/api/docker/start" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Start containers" />
|
||||
<input type="submit" value="Start containers" />
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="POST" action="/api/docker/start" class="xhr">
|
||||
@@ -369,16 +368,16 @@
|
||||
|
||||
{% if is_backup_section_enabled == false %}
|
||||
<h2>Backup and restore</h2>
|
||||
The backup section is disabled via environmental variable.<br><br>
|
||||
<p>The backup section is disabled via environmental variable.</p>
|
||||
{% else %}
|
||||
{% if is_backup_container_running == false and borg_backup_host_location == "" and isApacheStarting != true %}
|
||||
<h2>Backup and restore</h2>
|
||||
Please enter the directory path below where backups will be created on the host system. It's best to choose a location on a separate drive and not on your root drive.<br><br>
|
||||
<p>Please enter the directory path below where backups will be created on the host system. It's best to choose a location on a separate drive and not on your root drive.</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" name="borg_backup_host_location" placeholder="/mnt/backup"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit backup location" />
|
||||
<input type="submit" value="Submit backup location" />
|
||||
</form>
|
||||
{{ include('includes/backup-dirs.twig') }}
|
||||
{% endif %}
|
||||
@@ -390,33 +389,33 @@
|
||||
{% if is_backup_container_running == false %}
|
||||
<h2>Backup and restore</h2>
|
||||
{% if backup_exit_code > 0 %}
|
||||
<span class="status error"></span> Last {{ borg_backup_mode }} failed! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
<p><span class="status error"></span> Last {{ borg_backup_mode }} failed! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
{% if borg_backup_mode == "check" %}
|
||||
The backup check was not successful. This might indicate a corrupt archive (look at the logs). If that should be the case, you can try to fix it by following <a href="https://borgbackup.readthedocs.io/en/stable/faq.html#i-get-an-integrityerror-or-similar-what-now"><strong>this documentation</strong></a><br /><br />
|
||||
<p>The backup check was not successful. This might indicate a corrupt archive (look at the logs). If that should be the case, you can try to fix it by following <a href="https://borgbackup.readthedocs.io/en/stable/faq.html#i-get-an-integrityerror-or-similar-what-now"><strong>this documentation</strong></a></p>
|
||||
<details>
|
||||
<summary>Reveal repair option</summary><br />
|
||||
Below is the option to repair the integrity of your backup. <strong>Please note:</strong> Please only use this after you have read the documentation above! (It will run the command 'borg check --repair' for you.)<br><br>
|
||||
<summary>Reveal repair option</summary>
|
||||
<p>Below is the option to repair the integrity of your backup. <strong>Please note:</strong> Please only use this after you have read the documentation above! (It will run the command 'borg check --repair' for you.)</p>
|
||||
<form method="POST" action="/api/docker/backup-check-repair" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Check and repair backup integrity" onclick="return confirm('Check and repair backup integrity? Are you sure that you want to check and repair the backup integrity? This should only be done after reading the mentioned documentation.')"/><br/>
|
||||
</form><br />
|
||||
</details><br />
|
||||
<input type="submit" value="Check and repair backup integrity" onclick="return confirm('Check and repair backup integrity? Are you sure that you want to check and repair the backup integrity? This should only be done after reading the mentioned documentation.')"/>
|
||||
</form>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% if has_backup_run_once == false %}
|
||||
You may change the backup path again since the initial backup was not successful. After submitting the new value, you need to click on <strong>Create Backup</strong> to test the new value.<br /><br />
|
||||
<p>You may change the backup path again since the initial backup was not successful. After submitting the new value, you need to click on <strong>Create Backup</strong> to test the new value.</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" value="{{borg_backup_host_location}}" name="borg_backup_host_location" placeholder="/mnt/backup" />
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Set backup location again" />
|
||||
<input type="submit" value="Set backup location again" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% elseif backup_exit_code == 0 %}
|
||||
{% if borg_backup_mode == "backup" %}
|
||||
<span class="status success"></span> Last {{ borg_backup_mode }} successful on {{ last_backup_time }} UTC! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
<p><span class="status success"></span> Last {{ borg_backup_mode }} successful on {{ last_backup_time }} UTC! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
{% else %}
|
||||
<span class="status success"></span> Last {{ borg_backup_mode }} successful! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)<br /><br />
|
||||
<p><span class="status success"></span> Last {{ borg_backup_mode }} successful! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank" rel="noopener">Logs</a>)</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -424,51 +423,51 @@
|
||||
{% if is_backup_container_running == false and isApacheStarting == false %}
|
||||
{% if has_backup_run_once == true %}
|
||||
<details>
|
||||
<summary>Click here to reveal all backup options (including an option for automatic updates)</summary><br />
|
||||
<summary>Click here to reveal all backup options (including an option for automatic updates)</summary>
|
||||
{% endif %}
|
||||
<h3>Backup information</h3>
|
||||
This is your encryption password for backups: <strong>{{ borgbackup_password }}</strong><br /><br/>
|
||||
Please save this password in a safe place. You won't be able to restore from backup if you lose this password! <br /><br/>
|
||||
All important data from your Nextcloud AIO instance such as the database, your files and the mastercontainer's configuration files, will be backed up.<br /><br/>
|
||||
The backup uses a tool called <a href="https://github.com/borgbackup/borg#what-is-borgbackup"><strong>BorgBackup</strong></a>, a well-known server backup tool that efficiently backs up your files and encrypts them on the fly. <br /><br/>
|
||||
By using this tool, backups are incremental, differential, compressed and encrypted – so only the first backup will take a while. Further backups should be fast as only changes are taken into account.<br /><br/>
|
||||
Backups will be created in the following directory on the host: <strong>{{ borg_backup_host_location }}/borg</strong> <br /><br/>
|
||||
Be aware that this solution does not backup files and folders that are mounted into Nextcloud using the external storage app, but you can add further Docker volumes and host paths that you want to back up after the initial backup is done.<br><br>
|
||||
For information about backup retention, see <strong><a href="https://github.com/nextcloud/all-in-one#how-to-adjust-borgs-retention-policy">this</a></strong>.<br><br>
|
||||
Daily backups can be enabled after the initial backup is done. Enabling this also allows you to enable an option to update all containers, Nextcloud, and its apps automatically.<br><br>
|
||||
For further documentation and options on this backup solution refer to <strong><a href="https://github.com/nextcloud/all-in-one#backup-solution">this section</a></strong> and below.<br>
|
||||
<p>This is your encryption password for backups: <strong>{{ borgbackup_password }}</strong></p>
|
||||
<p>Please save this password in a safe place. You won't be able to restore from backup if you lose this password!</p>
|
||||
<p>All important data from your Nextcloud AIO instance such as the database, your files and the mastercontainer's configuration files, will be backed up.</p>
|
||||
<p>The backup uses a tool called <a href="https://github.com/borgbackup/borg#what-is-borgbackup"><strong>BorgBackup</strong></a>, a well-known server backup tool that efficiently backs up your files and encrypts them on the fly.</p>
|
||||
<p>By using this tool, backups are incremental, differential, compressed and encrypted – so only the first backup will take a while. Further backups should be fast as only changes are taken into account.</p>
|
||||
<p>Backups will be created in the following directory on the host: <strong>{{ borg_backup_host_location }}/borg</strong></p>
|
||||
<p>Be aware that this solution does not backup files and folders that are mounted into Nextcloud using the external storage app, but you can add further Docker volumes and host paths that you want to back up after the initial backup is done.</p>
|
||||
<p>For information about backup retention, see <strong><a href="https://github.com/nextcloud/all-in-one#how-to-adjust-borgs-retention-policy">this</a></strong>.</p>
|
||||
<p>Daily backups can be enabled after the initial backup is done. Enabling this also allows you to enable an option to update all containers, Nextcloud, and its apps automatically.</p>
|
||||
<p>For further documentation and options on this backup solution refer to <strong><a href="https://github.com/nextcloud/all-in-one#backup-solution">this section</a></strong> and below.</p>
|
||||
|
||||
{% if isApacheStarting != true %}
|
||||
<h3>Backup creation</h3>
|
||||
Clicking on the button below will create a backup.<br><br/>
|
||||
<p>Clicking on the button below will create a backup.</p>
|
||||
<form method="POST" action="/api/docker/backup" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Create backup" onclick="return confirm('Create backup? Are you sure that you want to create a backup? This will stop all running containers and create the backup.')" />
|
||||
<input type="submit" value="Create backup" onclick="return confirm('Create backup? Are you sure that you want to create a backup? This will stop all running containers and create the backup.')" />
|
||||
</form>
|
||||
|
||||
{% if has_backup_run_once == false %}
|
||||
<h3>Reset backup host location</h3>
|
||||
If the configured backup host location <strong>{{ borg_backup_host_location }}</strong> is wrong, you can reset it by clicking on the button below.<br><br/>
|
||||
<p>If the configured backup host location <strong>{{ borg_backup_host_location }}</strong> is wrong, you can reset it by clicking on the button below.</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="hidden" name="delete_borg_backup_host_location" value="yes"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Reset backup location" />
|
||||
<input type="submit" value="Reset backup location" />
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% if has_backup_run_once == true %}
|
||||
<h3>Backup check</h3>
|
||||
Click on the button below to perform a backup integrity check. This is an option that verifies that your backup is intact. It shouldn't be needed in most situations.<br><br/>
|
||||
<p>Click on the button below to perform a backup integrity check. This is an option that verifies that your backup is intact. It shouldn't be needed in most situations.</p>
|
||||
<form method="POST" action="/api/docker/backup-check" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Check backup integrity" onclick="return confirm('Check backup integrity? Are you sure that you want to check the backup? This can take a long time depending on the size of your backup.')" /><br/>
|
||||
<input type="submit" value="Check backup integrity" onclick="return confirm('Check backup integrity? Are you sure that you want to check the backup? This can take a long time depending on the size of your backup.')" />
|
||||
</form>
|
||||
|
||||
<h3>Backup restore</h3>
|
||||
Choose the backup that you want to restore and click on the button below to restore the selected backup. This will overwrite all your files with the chosen backup so you should consider creating a backup first. You can run an integrity check before restoring your files but this shouldn't be needed in most situations. Please note that this will not restore additionally chosen backup directories! The restore process should be pretty fast as rsync, which only transfers changed files, is used to restore the chosen backup.<br><br>
|
||||
<p>Choose the backup that you want to restore and click on the button below to restore the selected backup. This will overwrite all your files with the chosen backup so you should consider creating a backup first. You can run an integrity check before restoring your files but this shouldn't be needed in most situations. Please note that this will not restore additionally chosen backup directories! The restore process should be pretty fast as rsync, which only transfers changed files, is used to restore the chosen backup.</p>
|
||||
<form method="POST" action="/api/docker/restore" class="xhr" id="restore_selection">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
@@ -477,53 +476,51 @@
|
||||
<option value="{{ restore_time }}">{{ restore_time }} UTC</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input class="button" type="submit" value="Restore selected backup" onclick="return confirm('Restore the selected backup? Are you sure that you want to restore the selected backup? This will stop all running containers and restore the selected backup. It is recommended to create a backup first. You might also want to check the backup integrity.')" />
|
||||
<input type="submit" value="Restore selected backup" onclick="return confirm('Restore the selected backup? Are you sure that you want to restore the selected backup? This will stop all running containers and restore the selected backup. It is recommended to create a backup first. You might also want to check the backup integrity.')" />
|
||||
</form>
|
||||
|
||||
<h3>Daily backup and automatic updates</h3>
|
||||
{% if daily_backup_time == "" %}
|
||||
By entering a time below, you can enable daily backups. It will create them at the entered time in 24h format. E.g. <strong>04:00</strong> will create backups at 4 am UTC and <strong>16:00</strong> at 4 pm UTC. When creating the backup, containers will be stopped and restarted after the backup is complete.<br><br/>
|
||||
<p>By entering a time below, you can enable daily backups. It will create them at the entered time in 24h format. E.g. <strong>04:00</strong> will create backups at 4 am UTC and <strong>16:00</strong> at 4 pm UTC. When creating the backup, containers will be stopped and restarted after the backup is complete.</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" name="daily_backup_time" value="04:00" placeholder="04:00"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit backup time" /><br>
|
||||
<input type="submit" value="Submit backup time" /><br>
|
||||
<input type="checkbox" id="automatic_updates" name="automatic_updates" checked="checked"><label for="automatic_updates">Automatically update all containers, the mastercontainer and on saturdays your Nextcloud apps</label><br>
|
||||
<input type="checkbox" id="success_notification" name="success_notification" checked="checked"><label for="success_notification">Send notifications about successful backups (notifications about unsuccessful backups will always be sent)</label><br>
|
||||
<input type="checkbox" id="success_notification" name="success_notification" checked="checked"><label for="success_notification">Send notifications about successful backups (notifications about unsuccessful backups will always be sent)</label>
|
||||
</form>
|
||||
{% else %}
|
||||
Daily backups will be created at <strong>{{ daily_backup_time }} UTC</strong>. A notification about the result of the backup will be sent.
|
||||
<p>Daily backups will be created at <strong>{{ daily_backup_time }} UTC</strong>. A notification about the result of the backup will be sent.</p>
|
||||
{% if automatic_updates == true %}
|
||||
Also your containers, the mastercontainer and, on Saturdays, your Nextcloud apps will be automatically updated.
|
||||
Also your containers, the mastercontainer and, on Saturdays, your Nextcloud apps will be automatically updated.
|
||||
{% endif %}
|
||||
To change your backup time first disable Daily Backups, then enter your new backup time, and then re-enable them.<br><br/>
|
||||
<p>To change your backup time first disable Daily Backups, then enter your new backup time, and then re-enable them.</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="hidden" name="delete_daily_backup_time" value="yes"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Disable or change daily backups" />
|
||||
<input type="submit" value="Disable or change daily backups" />
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
<h3>Back up additional directories and docker volumes of your host</h3>
|
||||
Below you can enter directories and docker volumes of your host that will be backed up into the same borg backup archive.<br><br>
|
||||
<p>Below you can enter directories and docker volumes of your host that will be backed up into the same borg backup archive.</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<textarea id="additional_backup_directories" name="additional_backup_directories" rows="4" cols="50" placeholder="/directory/on/the/host my_custom_docker_volume">{{ additional_backup_directories }}</textarea>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit additional backup locations" /><br>
|
||||
<input type="submit" value="Submit additional backup locations" />
|
||||
</form>
|
||||
Each line and entry needs to start with a slash or letter/digit. Only <strong>a-z</strong>, <strong>A-Z</strong>, <strong>.</strong>, <strong>0-9</strong>, <strong>_</strong>, <strong>-</strong>, and <strong>/</strong> are allowed. If the entry begins with a letter/digit slashes are not supported. Two valid entries are <strong>/directory/on/the/host</strong> and <strong>my_custom_docker_volume</strong>. You need to make sure that all given directories exist or the backup container will fail to start!<br><br/>
|
||||
Be sure to individually specify all storage that you want to back up as storage will not be mounted recursively. E.g. providing <strong>/</strong> as additional backup directory will only back up files and folders that are stored on the root partition and not on the EFI partition or any other. Excluded by the backup will be caches and a few other directories. If you want to back up the root partition you should make sure to stop all services before the backup so it can run correctly. For automating this see <a href="https://github.com/nextcloud/all-in-one#how-to-stopstartupdate-containers-or-trigger-the-daily-backup-from-a-script-externally">this documentation</a><br><br/>
|
||||
Please note that the chosen directories/volumes will not be restored when you restore your instance, so this would need to be done manually. <br><br>
|
||||
<p>Each line and entry needs to start with a slash or letter/digit. Only <strong>a-z</strong>, <strong>A-Z</strong>, <strong>.</strong>, <strong>0-9</strong>, <strong>_</strong>, <strong>-</strong>, and <strong>/</strong> are allowed. If the entry begins with a letter/digit slashes are not supported. Two valid entries are <strong>/directory/on/the/host</strong> and <strong>my_custom_docker_volume</strong>. You need to make sure that all given directories exist or the backup container will fail to start!</p>
|
||||
<p>Be sure to individually specify all storage that you want to back up as storage will not be mounted recursively. E.g. providing <strong>/</strong> as additional backup directory will only back up files and folders that are stored on the root partition and not on the EFI partition or any other. Excluded by the backup will be caches and a few other directories. If you want to back up the root partition you should make sure to stop all services before the backup so it can run correctly. For automating this see <a href="https://github.com/nextcloud/all-in-one#how-to-stopstartupdate-containers-or-trigger-the-daily-backup-from-a-script-externally">this documentation</a></p>
|
||||
<p>Please note that the chosen directories/volumes will not be restored when you restore your instance, so this would need to be done manually.</p>
|
||||
{% if additional_backup_directories != "" %}
|
||||
This option is currently set. You can disable it again by clearing the field and submitting your changes.<br><br>
|
||||
<p>This option is currently set. You can disable it again by clearing the field and submitting your changes.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if has_backup_run_once == false %}
|
||||
<br />
|
||||
{% else %}
|
||||
{% if has_backup_run_once == true %}
|
||||
</details>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -531,79 +528,84 @@
|
||||
{% endif %}
|
||||
|
||||
{% if is_backup_container_running == false %}
|
||||
{% if isApacheStarting == false %}
|
||||
{% if isApacheStarting == false %}
|
||||
<h2>AIO passphrase change</h2>
|
||||
<details>
|
||||
<summary>Click here to change your AIO passphrase</summary><br />
|
||||
You can change your AIO passphrase below:<br><br />
|
||||
<summary>Click here to change your AIO passphrase</summary>
|
||||
<p>You can change your AIO passphrase below:</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="password" autocomplete="current-password" name="current-master-password" placeholder="Your current AIO passphrase" id="current-master-password" oninput="showPassword('current-master-password')">
|
||||
<input type="password" autocomplete="new-password" name="new-master-password" placeholder="Your new AIO passphrase" id="new-master-password" oninput="showPassword('new-master-password')">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit passphrase change" />
|
||||
<input type="submit" value="Submit passphrase change" />
|
||||
</form>
|
||||
The new passphrase needs to be at least 24 characters long. Allowed characters are the <a href="https://en.wikipedia.org/wiki/Latin_alphabet#/media/File:Abecedarium.png"><strong>latin characters</strong></a> <strong>a-z</strong>, <strong>A-Z</strong>, <strong>0-9</strong> and <strong>spaces</strong>.<br>
|
||||
<p>The new passphrase needs to be at least 24 characters long. Allowed characters are the <a href="https://en.wikipedia.org/wiki/Latin_alphabet#/media/File:Abecedarium.png"><strong>latin characters</strong></a> <strong>a-z</strong>, <strong>A-Z</strong>, <strong>0-9</strong> and <strong>spaces</strong>.</p>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if is_backup_container_running == false %}
|
||||
<h2>Optional containers</h2>
|
||||
In this section you can enable or disable optional containers. There are further community containers available that are not listed below. See <strong><a href="https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers">this documentation</a></strong> how to add them.<br><br>
|
||||
<p>In this section you can enable or disable optional containers. There are further community containers available that are not listed below. See <strong><a href="https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers">this documentation</a></strong> how to add them.</p>
|
||||
{% if isAnyRunning == true %}
|
||||
<strong>Please note:</strong> You can enable or disable the options below only when your containers are stopped.<br><br>
|
||||
<p><strong>Please note:</strong> You can enable or disable the options below only when your containers are stopped.</p>
|
||||
{% else %}
|
||||
<strong>Please note:</strong> Make sure to save your changes by clicking <strong>Save changes</strong> below the list of optional containers. The changes will not be auto-saved.<br><br>
|
||||
<p><strong>Please note:</strong> Make sure to save your changes by clicking <strong>Save changes</strong> below the list of optional containers. The changes will not be auto-saved.</p>
|
||||
{% endif %}
|
||||
<form id="options-form" method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="hidden" name="options-form" value="options-form">
|
||||
{% if is_clamav_enabled == true %}
|
||||
<input type="checkbox" id="clamav" name="clamav" checked="checked"><label for="clamav">ClamAV (Antivirus backend for Nextcloud, only supported on x64, needs ~1GB additional RAM)</label><br><br>
|
||||
<p><input type="checkbox" id="clamav" name="clamav" checked="checked"><label for="clamav">ClamAV (Antivirus backend for Nextcloud, only supported on x64, needs ~1GB additional RAM)</label></p>
|
||||
{% else %}
|
||||
<input type="checkbox" id="clamav" name="clamav"><label for="clamav">ClamAV (Antivirus backend for Nextcloud, only supported on x64, needs ~1GB additional RAM)</label><br><br>
|
||||
<p><input type="checkbox" id="clamav" name="clamav"><label for="clamav">ClamAV (Antivirus backend for Nextcloud, only supported on x64, needs ~1GB additional RAM)</label></p>
|
||||
{% endif %}
|
||||
{% if is_collabora_enabled == true %}
|
||||
<input type="checkbox" id="collabora" name="collabora" checked="checked"><label for="collabora">Collabora (Nextcloud Office)</label><br>
|
||||
<p><input type="checkbox" id="collabora" name="collabora" checked="checked"><label for="collabora">Collabora (Nextcloud Office)</label></p>
|
||||
{% else %}
|
||||
<input type="checkbox" id="collabora" name="collabora"><label for="collabora">Collabora (Nextcloud Office)</label><br>
|
||||
<p><input type="checkbox" id="collabora" name="collabora"><label for="collabora">Collabora (Nextcloud Office)</label></p>
|
||||
{% endif %}
|
||||
{% if is_fulltextsearch_enabled == true %}
|
||||
<input type="checkbox" id="fulltextsearch" name="fulltextsearch" checked="checked"><label for="fulltextsearch">Fulltextsearch (needs ~1GB additional RAM)</label><br>
|
||||
<p><input type="checkbox" id="fulltextsearch" name="fulltextsearch" checked="checked"><label for="fulltextsearch">Fulltextsearch (needs ~1GB additional RAM)</label></p>
|
||||
{% else %}
|
||||
<input type="checkbox" id="fulltextsearch" name="fulltextsearch"><label for="fulltextsearch">Fulltextsearch (needs ~1GB additional RAM. <strong>Please note:</strong> the initial indexing can take a long time during which Nextcloud will be unavailable)</label><br><br>
|
||||
<p><input type="checkbox" id="fulltextsearch" name="fulltextsearch"><label for="fulltextsearch">Fulltextsearch (needs ~1GB additional RAM. <strong>Please note:</strong> the initial indexing can take a long time during which Nextcloud will be unavailable)</label></p>
|
||||
{% endif %}
|
||||
{% if is_imaginary_enabled == true %}
|
||||
<input type="checkbox" id="imaginary" name="imaginary" checked="checked"><label for="imaginary">Imaginary (for previews of heic, heif, illustrator, pdf, svg, tiff and webp. Imaginary is currently <a href="https://github.com/nextcloud/server/issues/34262">incompatible with server-side-encryption</a>)</label><br><br>
|
||||
<p><input type="checkbox" id="imaginary" name="imaginary" checked="checked"><label for="imaginary">Imaginary (for previews of heic, heif, illustrator, pdf, svg, tiff and webp. Imaginary is currently <a href="https://github.com/nextcloud/server/issues/34262">incompatible with server-side-encryption</a>)</label></p>
|
||||
{% else %}
|
||||
<input type="checkbox" id="imaginary" name="imaginary"><label for="imaginary">Imaginary (for previews of heic, heif, illustrator, pdf, svg, tiff and webp. Imaginary is currently <a href="https://github.com/nextcloud/server/issues/34262">incompatible with server-side-encryption</a>)</label><br><br>
|
||||
<p><input type="checkbox" id="imaginary" name="imaginary"><label for="imaginary">Imaginary (for previews of heic, heif, illustrator, pdf, svg, tiff and webp. Imaginary is currently <a href="https://github.com/nextcloud/server/issues/34262">incompatible with server-side-encryption</a>)</label></p>
|
||||
{% endif %}
|
||||
{% if is_talk_enabled == true %}
|
||||
<input type="checkbox" id="talk" name="talk" checked="checked"><label for="talk">Nextcloud Talk (needs ports {{ talk_port }}/TCP and {{ talk_port }}/UDP open/forwarded in your firewall/router)</label><br><br>
|
||||
<p><input type="checkbox" id="talk" name="talk" checked="checked"><label for="talk">Nextcloud Talk (needs ports {{ talk_port }}/TCP and {{ talk_port }}/UDP open/forwarded in your firewall/router)</label></p>
|
||||
{% else %}
|
||||
<input type="checkbox" id="talk" name="talk"><label for="talk">Nextcloud Talk (needs ports {{ talk_port }}/TCP and {{ talk_port }}/UDP open/forwarded in your firewall/router)</label><br><br>
|
||||
<p><input type="checkbox" id="talk" name="talk"><label for="talk">Nextcloud Talk (needs ports {{ talk_port }}/TCP and {{ talk_port }}/UDP open/forwarded in your firewall/router)</label></p>
|
||||
{% endif %}
|
||||
{% if is_talk_recording_enabled == true %}
|
||||
<input type="checkbox" id="talk-recording" name="talk-recording" checked="checked"><label for="talk-recording">Nextcloud Talk Recording-server (needs Nextcloud Talk being enabled and ~1GB additional RAM and ~2 additional vCPUs)</label><br><br>
|
||||
<p><input type="checkbox" id="talk-recording" name="talk-recording" checked="checked"><label for="talk-recording">Nextcloud Talk Recording-server (needs Nextcloud Talk being enabled and ~1GB additional RAM and ~2 additional vCPUs)</label></p>
|
||||
{% else %}
|
||||
<input type="checkbox" id="talk-recording" name="talk-recording"><label for="talk-recording">Nextcloud Talk Recording-server (needs Nextcloud Talk being enabled and ~1GB additional RAM ~2 additional vCPUs)</label><br><br>
|
||||
<p><input type="checkbox" id="talk-recording" name="talk-recording"><label for="talk-recording">Nextcloud Talk Recording-server (needs Nextcloud Talk being enabled and ~1GB additional RAM ~2 additional vCPUs)</label></p>
|
||||
{% endif %}
|
||||
{% if is_onlyoffice_enabled == true %}
|
||||
<input type="checkbox" id="onlyoffice" name="onlyoffice" checked="checked"><label for="onlyoffice">OnlyOffice</label><br>
|
||||
<p><input type="checkbox" id="onlyoffice" name="onlyoffice" checked="checked"><label for="onlyoffice">OnlyOffice</label></p>
|
||||
{% else %}
|
||||
{#<input type="checkbox" id="onlyoffice" name="onlyoffice"><label for="onlyoffice">OnlyOffice</label><br>#}
|
||||
{#<p><input type="checkbox" id="onlyoffice" name="onlyoffice"><label for="onlyoffice">OnlyOffice</label></p>#}
|
||||
{% endif %}
|
||||
{% if is_docker_socket_proxy_enabled == true %}
|
||||
<input type="checkbox" id="docker-socket-proxy" name="docker-socket-proxy" checked="checked"><label for="docker-socket-proxy">Docker Socket Proxy (needed for <a href="https://github.com/cloud-py-api/app_api#nextcloud-appapi">Nextcloud App API</a>)</label><br><br>
|
||||
<p><input type="checkbox" id="docker-socket-proxy" name="docker-socket-proxy" checked="checked"><label for="docker-socket-proxy">Docker Socket Proxy (needed for <a href="https://github.com/cloud-py-api/app_api#nextcloud-appapi">Nextcloud App API</a>)</label></p>
|
||||
{% else %}
|
||||
<input type="checkbox" id="docker-socket-proxy" name="docker-socket-proxy"><label for="docker-socket-proxy">Docker Socket Proxy (needed for <a href="https://github.com/cloud-py-api/app_api#nextcloud-appapi">Nextcloud App API</a>)</label><br><br>
|
||||
<p><input type="checkbox" id="docker-socket-proxy" name="docker-socket-proxy"><label for="docker-socket-proxy">Docker Socket Proxy (needed for <a href="https://github.com/cloud-py-api/app_api#nextcloud-appapi">Nextcloud App API</a>)</label></p>
|
||||
{% endif %}
|
||||
<input id="options-form-submit" class="button" type="submit" value="Save changes" />
|
||||
{% if is_whiteboard_enabled == true %}
|
||||
<p><input type="checkbox" id="whiteboard" name="whiteboard" checked="checked"><label for="whiteboard">Whiteboard</label></p>
|
||||
{% else %}
|
||||
<p><input type="checkbox" id="whiteboard" name="whiteboard"><label for="whiteboard">Whiteboard</label></p>
|
||||
{% endif %}
|
||||
<input id="options-form-submit" type="submit" value="Save changes" />
|
||||
<script type="text/javascript" src="options-form-submit.js"></script>
|
||||
</form>
|
||||
<strong>Minimal system requirements:</strong> When any optional container is enabled, at least 2GB RAM, a dual-core CPU and 40GB system storage are required. When enabling ClamAV, Nextcloud Talk Recording-server or Fulltextsearch, at least 3GB RAM are required. For Talk Recording-server additional 2 vCPUs are required. When enabling everything, at least 5GB RAM and a quad-core CPU are required. Recommended are at least 1GB more RAM than the minimal requirement. For further advices and recommendations see <strong><a href="https://github.com/nextcloud/all-in-one/discussions/1335">this documentation</a></strong><br>
|
||||
<p><strong>Minimal system requirements:</strong> When any optional container is enabled, at least 2GB RAM, a dual-core CPU and 40GB system storage are required. When enabling ClamAV, Nextcloud Talk Recording-server or Fulltextsearch, at least 3GB RAM are required. For Talk Recording-server additional 2 vCPUs are required. When enabling everything, at least 5GB RAM and a quad-core CPU are required. Recommended are at least 1GB more RAM than the minimal requirement. For further advices and recommendations see <strong><a href="https://github.com/nextcloud/all-in-one/discussions/1335">this documentation</a></strong></p>
|
||||
{% if isAnyRunning == true or is_x64_platform == false %}
|
||||
<script type="text/javascript" src="disable-clamav.js"></script>
|
||||
{% endif %}
|
||||
@@ -615,27 +617,28 @@
|
||||
<script type="text/javascript" src="disable-imaginary.js"></script>
|
||||
<script type="text/javascript" src="disable-fulltextsearch.js"></script>
|
||||
<script type="text/javascript" src="disable-talk-recording.js"></script>
|
||||
<script type="text/javascript" src="disable-whiteboard.js"></script>
|
||||
{% endif %}
|
||||
|
||||
{% if is_collabora_enabled == true and isAnyRunning == false and was_start_button_clicked == true %}
|
||||
<h3>Collabora dictionaries</h3>
|
||||
|
||||
{% if collabora_dictionaries == "" %}
|
||||
In order to get the correct dictionaries in Collabora, you may configure the dictionaries below:<br><br>
|
||||
<p>In order to get the correct dictionaries in Collabora, you may configure the dictionaries below:</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" name="collabora_dictionaries" placeholder="de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru" />
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit collabora dictionaries" />
|
||||
<input type="submit" value="Submit collabora dictionaries" />
|
||||
</form>
|
||||
You need to make sure that the dictionaries that you enter are valid. An example is <strong>de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru</strong>.<br><br>
|
||||
<p>You need to make sure that the dictionaries that you enter are valid. An example is <strong>de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru</strong>.</p>
|
||||
{% else %}
|
||||
The dictionaries for Collabora are currently set to <strong>{{ collabora_dictionaries }}</strong>. You can reset them again by clicking on the button below.<br><br/>
|
||||
<p>The dictionaries for Collabora are currently set to <strong>{{ collabora_dictionaries }}</strong>. You can reset them again by clicking on the button below.</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="hidden" name="delete_collabora_dictionaries" value="yes"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Reset collabora dictionaries" />
|
||||
<input type="submit" value="Reset collabora dictionaries" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -643,27 +646,27 @@
|
||||
<h2>Timezone change</h2>
|
||||
{% if isAnyRunning == true %}
|
||||
{% if timezone != "" %}
|
||||
The timezone for Nextcloud is currently set to <strong>{{ timezone }}</strong>.<br><br>
|
||||
<p>The timezone for Nextcloud is currently set to <strong>{{ timezone }}</strong>.</p>
|
||||
{% endif %}
|
||||
<strong>Please note:</strong> You can change the timezone when your containers are stopped.<br><br>
|
||||
<p><strong>Please note:</strong> You can change the timezone when your containers are stopped.</p>
|
||||
{% else %}
|
||||
{% if timezone == "" %}
|
||||
To get the correct time values for certain Nextcloud features, set the timezone for Nextcloud to the one that your users mainly use. Please note that this setting does not apply to the mastercontainer and any backup option.<br><br>
|
||||
You can configure the timezone for Nextcloud below:<br><br>
|
||||
<p>To get the correct time values for certain Nextcloud features, set the timezone for Nextcloud to the one that your users mainly use. Please note that this setting does not apply to the mastercontainer and any backup option.</p>
|
||||
<p>You can configure the timezone for Nextcloud below:</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" id="timezone" name="timezone" placeholder="Europe/Berlin" />
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit timezone" onclick="return confirm('Are you sure that this is a valid timezone? Please double check by following the wikipedia article and checking the correct column. If the timezone is not valid, it will break the startup since the database will not be correctly initialized and you will end up in a startup loop.')" />
|
||||
<input type="submit" value="Submit timezone" onclick="return confirm('Are you sure that this is a valid timezone? Please double check by following the wikipedia article and checking the correct column. If the timezone is not valid, it will break the startup since the database will not be correctly initialized and you will end up in a startup loop.')" />
|
||||
</form>
|
||||
You need to make sure that the timezone that you enter is valid. An example is <strong>Europe/Berlin</strong>. You can get valid values by looking at the 'TZ identifier' column of this list: <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List"><strong>click here</strong></a>. The default is <strong>Etc/UTC</strong> if nothing is entered.<br><br>
|
||||
<p>You need to make sure that the timezone that you enter is valid. An example is <strong>Europe/Berlin</strong>. You can get valid values by looking at the 'TZ identifier' column of this list: <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List"><strong>click here</strong></a>. The default is <strong>Etc/UTC</strong> if nothing is entered.</p>
|
||||
{% else %}
|
||||
The timezone for Nextcloud is currently set to <strong>{{ timezone }}</strong>. You can change the timezone by clicking on the button below.<br><br/>
|
||||
<p>The timezone for Nextcloud is currently set to <strong>{{ timezone }}</strong>. You can change the timezone by clicking on the button below.</p>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="hidden" name="delete_timezone" value="yes"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Reset the timezone" />
|
||||
<input type="submit" value="Reset the timezone" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -677,7 +680,7 @@
|
||||
<script type="text/javascript" src="before-unload.js"></script>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</main>
|
||||
<div id="overlay">
|
||||
<div class="loader"></div>
|
||||
</div>
|
||||
|
||||
@@ -1,36 +1,40 @@
|
||||
<details>
|
||||
<summary>Click here to view the current AIO config and documentation links</summary><br />
|
||||
<summary>Click here to view the current AIO config and documentation links</summary>
|
||||
{% if was_start_button_clicked == true %}
|
||||
Nextclouds config.php file is stored in the nextcloud_aio_nextcloud Docker volume and can be edited by following the <a href="https://github.com/nextcloud/all-in-one#how-to-edit-nextclouds-configphp-file-with-a-texteditor">config.php documentation</a>.<br><br>
|
||||
You can run Nextcloud's usual occ commands by following the <a href="https://github.com/nextcloud/all-in-one#how-to-run-occ-commands">occ documentation</a></strong>.<br><br>
|
||||
<p>Nextclouds config.php file is stored in the nextcloud_aio_nextcloud Docker volume and can be edited by following the <a href="https://github.com/nextcloud/all-in-one#how-to-edit-nextclouds-configphp-file-with-a-texteditor">config.php documentation</a>.</p>
|
||||
<p>You can run Nextcloud's usual occ commands by following the <a href="https://github.com/nextcloud/all-in-one#how-to-run-occ-commands">occ documentation</a></strong>.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if nextcloud_datadir starts with '/' %}
|
||||
Nextcloud's datadir is getting stored in the {{ nextcloud_datadir }} directory.
|
||||
{% else %}
|
||||
Nextcloud's datadir is getting stored in the {{ nextcloud_datadir }} Docker volume.
|
||||
{% endif %}
|
||||
See the <a href="https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir">NEXTCLOUD_DATADIR documentation</a> on how to change this.<br><br>
|
||||
|
||||
{% if nextcloud_mount == '' %}
|
||||
The Nextcloud container is confied and local external storage in Nextcloud is disabled.
|
||||
{% else %}
|
||||
The Nextcloud container is getting gets access to the {{ nextcloud_mount }} directory and local external storage in Nextcloud is enabled.
|
||||
{% endif %}
|
||||
See the <a href="https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host">NEXTCLOUD_MOUNT documentation</a> on how to change this.<br><br>
|
||||
<p>
|
||||
{% if nextcloud_datadir starts with '/' %}
|
||||
Nextcloud's datadir is getting stored in the {{ nextcloud_datadir }} directory.
|
||||
{% else %}
|
||||
Nextcloud's datadir is getting stored in the {{ nextcloud_datadir }} Docker volume.
|
||||
{% endif %}
|
||||
See the <a href="https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir">NEXTCLOUD_DATADIR documentation</a> on how to change this.
|
||||
</p>
|
||||
|
||||
Nextcloud has an upload limit of {{ nextcloud_upload_limit }} configured (for public link uploads. Bigger uploads are always possible when users are logged in). See the <a href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-upload-limit-for-nextcloud">NEXTCLOUD_UPLOAD_LIMIT documentation</a> on how to change this.<br><br>
|
||||
<p>
|
||||
{% if nextcloud_mount == '' %}
|
||||
The Nextcloud container is confied and local external storage in Nextcloud is disabled.
|
||||
{% else %}
|
||||
The Nextcloud container is getting gets access to the {{ nextcloud_mount }} directory and local external storage in Nextcloud is enabled.
|
||||
{% endif %}
|
||||
See the <a href="https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host">NEXTCLOUD_MOUNT documentation</a> on how to change this.</p>
|
||||
|
||||
For Nextcloud, a memory limit of {{ nextcloud_memory_limit }} per PHP process is configured. See the <a href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-php-memory-limit-for-nextcloud">NEXTCLOUD_MEMORY_LIMIT documentation</a> on how to change this.<br><br>
|
||||
<p>Nextcloud has an upload limit of {{ nextcloud_upload_limit }} configured (for public link uploads. Bigger uploads are always possible when users are logged in). See the <a href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-upload-limit-for-nextcloud">NEXTCLOUD_UPLOAD_LIMIT documentation</a> on how to change this.</p>
|
||||
|
||||
Nextcloud has a timeout of {{ nextcloud_max_time }} seconds configured (important for big file uploads). See the <a href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-max-execution-time-for-nextcloud">NEXTCLOUD_MAX_TIME documentation</a> on how to change this.<br><br>
|
||||
<p>For Nextcloud, a memory limit of {{ nextcloud_memory_limit }} per PHP process is configured. See the <a href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-php-memory-limit-for-nextcloud">NEXTCLOUD_MEMORY_LIMIT documentation</a> on how to change this.</p>
|
||||
|
||||
{% if is_dri_device_enabled == true %}
|
||||
The /dev/dri device which is needed for hardware transcoding is getting attached to the Nextcloud container.
|
||||
{% else %}
|
||||
The /dev/dri device which is needed for hardware transcoding is not attached to the Nextcloud container.
|
||||
{% endif %}
|
||||
See the <a href="https://github.com/nextcloud/all-in-one#how-to-enable-hardware-transcoding-for-nextcloud">NEXTCLOUD_ENABLE_DRI_DEVICE documentation</a> on how to change this.<br><br>
|
||||
<p>Nextcloud has a timeout of {{ nextcloud_max_time }} seconds configured (important for big file uploads). See the <a href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-max-execution-time-for-nextcloud">NEXTCLOUD_MAX_TIME documentation</a> on how to change this.</p>
|
||||
|
||||
For further documentation on AIO, refer to <strong><a href="https://github.com/nextcloud/all-in-one#nextcloud-all-in-one">this page</a></strong>. You can use the browser search [CTRL]+[F] to search through the documentation. Additional documentation can be found <strong><a href="https://github.com/nextcloud/all-in-one/discussions/categories/wiki">here</a></strong>.<br>
|
||||
<p>
|
||||
{% if is_dri_device_enabled == true %}
|
||||
The /dev/dri device which is needed for hardware transcoding is getting attached to the Nextcloud container.
|
||||
{% else %}
|
||||
The /dev/dri device which is needed for hardware transcoding is not attached to the Nextcloud container.
|
||||
{% endif %}
|
||||
See the <a href="https://github.com/nextcloud/all-in-one#how-to-enable-hardware-transcoding-for-nextcloud">NEXTCLOUD_ENABLE_DRI_DEVICE documentation</a> on how to change this.</p>
|
||||
|
||||
<p>For further documentation on AIO, refer to <strong><a href="https://github.com/nextcloud/all-in-one#nextcloud-all-in-one">this page</a></strong>. You can use the browser search [CTRL]+[F] to search through the documentation. Additional documentation can be found <strong><a href="https://github.com/nextcloud/all-in-one/discussions/categories/wiki">here</a></strong>.</p>
|
||||
</details>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The folder path that you enter must start with <strong>/</strong> and must <strong>not</strong> end with <strong>/</strong>.<br><br>
|
||||
An example for Linux is <strong>/mnt/backup</strong>.<br><br>
|
||||
On Synology it could be <strong>/volume1/docker/nextcloud/backup</strong>.<br><br>
|
||||
For macOS it may be <strong>/var/backup</strong>.<br><br>
|
||||
On Windows it might be <strong>/run/desktop/mnt/host/c/backup</strong>. (This path is equivalent to 'C:\backup' on your Windows host so you need to translate the path accordingly. Hint: the path that you enter needs to start with '/run/desktop/mnt/host/'. Append to that the exact location on your windows host, e.g. 'c/backup' which is equivalent to 'C:\backup'.) ⚠️ <strong>Please note</strong>: This does not work with external drives like USB or network drives and only with internal drives like SATA or NVME drives.<br><br>
|
||||
Another option is to enter a specific volume name here: <strong>nextcloud_aio_backupdir</strong>. This volume needs to be created beforehand manually by you in order to be able to use it. See <a href="https://github.com/nextcloud/all-in-one#how-to-create-the-backup-volume-on-windows">this documentation</a> for an example.<br><br>
|
||||
<p>The folder path that you enter must start with <strong>/</strong> and must <strong>not</strong> end with <strong>/</strong>.</p>
|
||||
<p>An example for Linux is <strong>/mnt/backup</strong>.</p>
|
||||
<p>On Synology it could be <strong>/volume1/docker/nextcloud/backup</strong>.</p>
|
||||
<p>For macOS it may be <strong>/var/backup</strong>.</p>
|
||||
<p>On Windows it might be <strong>/run/desktop/mnt/host/c/backup</strong>. (This path is equivalent to 'C:\backup' on your Windows host so you need to translate the path accordingly. Hint: the path that you enter needs to start with '/run/desktop/mnt/host/'. Append to that the exact location on your windows host, e.g. 'c/backup' which is equivalent to 'C:\backup'.) ⚠️ <strong>Please note</strong>: This does not work with external drives like USB or network drives and only with internal drives like SATA or NVME drives.</p>
|
||||
<p>Another option is to enter a specific volume name here: <strong>nextcloud_aio_backupdir</strong>. This volume needs to be created beforehand manually by you in order to be able to use it. See <a href="https://github.com/nextcloud/all-in-one#how-to-create-the-backup-volume-on-windows">this documentation</a> for an example.</p>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>AIO</title>
|
||||
<link rel="stylesheet" href="/style.css" media="all" />
|
||||
<link rel="stylesheet" href="/style.css?v2" media="all" />
|
||||
<link rel="icon" href="/img/favicon.png">
|
||||
<script type="text/javascript" src="forms.js"></script>
|
||||
</head>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% block body %}
|
||||
<div class="login-wrapper">
|
||||
<div class="login">
|
||||
<img src="/img/logo-blue.svg" style="margin-left: auto;margin-right: auto;display: block;">
|
||||
<img alt="Nextcloud logo" src="/img/logo-blue.svg" style="margin-left: auto;margin-right: auto;display: block;">
|
||||
<h1>Nextcloud AIO Login</h1>
|
||||
{% if is_login_allowed == true %}
|
||||
<p>Log in using your Nextcloud AIO passphrase:</p>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% block body %}
|
||||
<div class="login-wrapper">
|
||||
<div class="login">
|
||||
<img src="/img/logo-blue.svg" style="margin-left: auto;margin-right: auto;display: block;">
|
||||
<img alt="Nextcloud logo" src="/img/logo-blue.svg" style="margin-left: auto;margin-right: auto;display: block;">
|
||||
<h1>All-in-One setup</h1>
|
||||
<p>The official Nextcloud installation method. Nextcloud All-in-One provides easy deployment and maintenance with most features included in this one Nextcloud instance.</p>
|
||||
<p>⚠️ <strong>Please note down the passphrase to access the AIO interface and don't lose it!</strong></p>
|
||||
|
||||
16
readme.md
16
readme.md
@@ -11,6 +11,8 @@ Included are:
|
||||
- Imaginary (optional, for previews of heic, heif, illustrator, pdf, svg, tiff and webp)
|
||||
- ClamAV (optional, Antivirus backend for Nextcloud)
|
||||
- Fulltextsearch (optional)
|
||||
- Whiteboard (optional)
|
||||
- Docker Socket Proxy (optional, needed for [Nextcloud App API](https://github.com/cloud-py-api/app_api#nextcloud-appapi))
|
||||
<details><summary>And much more:</summary>
|
||||
|
||||
- Simple web interface included that enables easy installation and maintenance
|
||||
@@ -75,7 +77,7 @@ Included are:
|
||||
## Screenshots
|
||||
| First setup | After installation |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
## How to use this?
|
||||
The following instructions are meant for installations without a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) already being in place. If you want to run AIO behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), see the [reverse proxy documentation](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md). Also, the instructions below are especially meant for Linux. For macOS see [this](#how-to-run-aio-on-macos), for Windows see [this](#how-to-run-aio-on-windows) and for Synology see [this](#how-to-run-aio-on-synology-dsm).
|
||||
@@ -129,6 +131,9 @@ If your firewall/router has port 80 and 8443 open/forwarded and you point a doma
|
||||
### How does it work?
|
||||
Nextcloud AIO is inspired by projects like Portainer that manage the docker daemon by talking to it through the docker socket directly. This concept allows a user to install only one container with a single command that does the heavy lifting of creating and managing all containers that are needed in order to provide a Nextcloud installation with most features included. It also makes updating a breeze and is not bound to the host system (and its slow updates) anymore as everything is in containers. Additionally, it is very easy to handle from a user perspective because a simple interface for managing your Nextcloud AIO installation is provided.
|
||||
|
||||
### How to contribute?
|
||||
See [this issue](https://github.com/nextcloud/all-in-one/issues/5251) for a list of feature requests that need help by contributors.
|
||||
|
||||
### Are reverse proxies supported?
|
||||
Yes. Please refer to the following documentation on this: [reverse-proxy.md](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md)
|
||||
|
||||
@@ -207,17 +212,18 @@ On TrueNAS SCALE, there are two ways to run AIO. The preferred one is to run AIO
|
||||
Another but untested way is to install Portainer on your TrueNAS SCALE from here https://truecharts.org/charts/stable/portainer/installation-notes and add the Helm-chart repository https://nextcloud.github.io/all-in-one/ into Portainer by following https://docs.portainer.io/user/kubernetes/helm. More docs on AIOs Helm Chart are available here: https://github.com/nextcloud/all-in-one/tree/main/nextcloud-aio-helm-chart#nextcloud-aio-helm-chart.
|
||||
|
||||
### Notes on Cloudflare (proxy/tunnel)
|
||||
- Using Cloudflare Tunnel potentially slows down Nextcloud by a lot since local access via the configured domain is not possible since TLS proxying is in that case offloaded to Cloudflares infrastructure. You can fix this by setting up your own reverse proxy that handles TLS proxying locally.
|
||||
- Cloudflare Proxy and Cloudflare Tunnel both require Cloudflare to perform TLS termination on their side and thus decrypt all the traffic on their infrastructure. This is a privacy concern and you will need to look for other solutions if it's unacceptable for you.
|
||||
- Using Cloudflare Tunnel might potentially slow down Nextcloud since local access via the configured domain is not possible because TLS termination is in that case offloaded to Cloudflare's infrastructure. There is no way to disable this behavior in Cloudflare Tunnel.
|
||||
- It is known that the domain validation may not work correctly behind Cloudflare since Cloudflare might block the validation attempt. You can simply skip it in that case by following: https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation
|
||||
- Make sure to [disable Cloudflares Rocket Loader feature](https://help.nextcloud.com/t/login-page-not-working-solved/149417/8) as otherwise Nextcloud's login prompt will not be shown.
|
||||
- Cloudflare only supports uploading files up to 100 MB in the free plan, if you try to upload bigger files you will get an error (413 - Payload Too Large) if no chunking is used (e.g. for public uploads in the web, or if chunks are configured to be bigger than 100 MB in the clients or the web). If you need to upload bigger files, you need to disable the proxy option in your DNS settings, or you must use another proxy than Cloudflare tunnels. Both options will disable Cloudflare DDoS protection.
|
||||
- Cloudflare only supports uploading files up to 100 MB in the free plan, if you try to upload bigger files you will get an error (413 - Payload Too Large) if no chunking is used (e.g. for public uploads in the web, or if chunks are configured to be bigger than 100 MB in the clients or the web). If you need to upload bigger files, you need to disable the proxy option in your DNS settings. Note that this will both disable Cloudflare DDoS protection and Cloudflare Tunnel as these services require the proxy option to be enabled.
|
||||
- If using Cloudflare Tunnel and the Nextcloud Desktop Client [Set Chunking on Nextcloud Desktop Client](https://github.com/nextcloud/desktop/issues/4271#issuecomment-1159578065)
|
||||
- Cloudflare only allows a max timeout of 100s for requests which is not configurable. This means that any server-side processing e.g. for assembling chunks for big files during upload that take longer than 100s will simply not work. See https://github.com/nextcloud/server/issues/19223. If you need to upload big files reliably, you need to disable the proxy option in your DNS settings, or you must use another proxy than Cloudflare tunnels. Both options will disable Cloudflare DDoS protection.
|
||||
- Cloudflare only allows a max timeout of 100s for requests which is not configurable. This means that any server-side processing e.g. for assembling chunks for big files during upload that take longer than 100s will simply not work. See https://github.com/nextcloud/server/issues/19223. If you need to upload big files reliably, you need to disable the proxy option in your DNS settings. Note that this will both disable Cloudflare DDoS protection and Cloudflare Tunnel as these services require the proxy option to be enabled.
|
||||
- It is known that the in AIO included collabora (Nextcloud Office) does not work out of the box behind Cloudflare. To make it work, you need to add all [Cloudflare IP-ranges](https://www.cloudflare.com/ips/) to the wopi-allowlist in `https://yourdomain.com/settings/admin/richdocuments`
|
||||
- Cloudflare Proxy might block the Turnserver for Nextcloud Talk from working correctly. You might want to disable Cloudflare Proxy thus. See https://github.com/nextcloud/all-in-one/discussions/2463#discussioncomment-5779981
|
||||
- The built-in turn-server for Nextcloud Talk will not work behind Cloudflare Tunnel since it needs a separate port (by default 3478 or as chosen) available on the same domain. If you still want to use the feature, you will need to install your own turnserver or use a publicly available one and adjust and test your stun and turn settings in `https://yourdomain.com/settings/admin/talk`.
|
||||
- If you get an error in Nextcloud's admin overview that the HSTS header is not set correctly, you might need to enable it in Cloudflare manually.
|
||||
- If you are using AIO's built-in Reverse Proxy and don't use your own, then may the certificate issuing possibly not work out-of-the-box because Cloudflare might block the attempt. In that case you need to disable the Proxy feature at least temporarily in order to make it work. See https://github.com/nextcloud/all-in-one/discussions/1101.
|
||||
- If you are using AIO's built-in Reverse Proxy and don't use your own, then the certificate issuing may possibly not work out-of-the-box because Cloudflare might block the attempt. In that case you need to disable the Proxy feature at least temporarily in order to make it work. Note that this isn't an option if you need Cloudflare Tunnel as disabling the proxy would also disable Cloudflare Tunnel which would in turn make your server unreachable for the verification. See https://github.com/nextcloud/all-in-one/discussions/1101.
|
||||
|
||||
### How to run Nextcloud behind a Cloudflare Tunnel?
|
||||
Although it does not seems like it is the case but from AIO perspective a Cloudflare Tunnel works like a reverse proxy. So please follow the [reverse proxy documentation](./reverse-proxy.md) where is documented how to make it run behind a Cloudflare Tunnel. However please see the [caveats](https://github.com/nextcloud/all-in-one#notes-on-cloudflare-proxytunnel) before proceeding.
|
||||
|
||||
@@ -639,6 +639,74 @@ The examples below define the dynamic configuration in YAML files. If you rather
|
||||
|
||||
</details>
|
||||
|
||||
### IIS with ARR and URL Rewrite
|
||||
|
||||
<details>
|
||||
|
||||
<summary>click here to expand</summary>
|
||||
|
||||
**Disclaimer:** It might be possible that the config below is not working 100% correctly, yet. Improvements to it are very welcome!
|
||||
|
||||
**Please note:** Using IIS as a reverse proxy comes with some limitations:
|
||||
- A maximum upload size of 4GiB, in the example configuration below the limit is set to 2GiB.
|
||||
|
||||
|
||||
#### Prerequisites
|
||||
1. **Windows Server** with IIS installed.
|
||||
2. [**Application Request Routing (ARR)**](https://www.iis.net/downloads/microsoft/application-request-routing) and [**URL Rewrite**](https://www.iis.net/downloads/microsoft/url-rewrite) modules installed.
|
||||
3. [**WebSocket Protocol**](https://learn.microsoft.com/en-us/iis/configuration/system.webserver/websocket) feature enabled.
|
||||
|
||||
For information on how to set up IIS as a reverse proxy please refer to [this](https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/reverse-proxy-with-url-rewrite-v2-and-application-request-routing).
|
||||
There are also information on how to use the IIS Manager [here](https://learn.microsoft.com/en-us/iis/).
|
||||
|
||||
The following configuration example assumes the following:
|
||||
* A site has been created that is configured with HTTPS support and the desired host name.
|
||||
* A server farm named `nc-server-farm` has been created and is pointing to the Nextcloud server.
|
||||
* No global Rewrite Rules has been created for the `nc-server-farm` server farm.
|
||||
|
||||
Add the following `web.config` file to the root of the site you created as the reverse proxy.
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<system.web>
|
||||
<!-- Allow all urls -->
|
||||
<httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters="" />
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<rewrite>
|
||||
<rules>
|
||||
<!-- Force https -->
|
||||
<rule name="Https" stopProcessing="true">
|
||||
<match url="(.*)" />
|
||||
<conditions>
|
||||
<add input="{HTTPS}" pattern="^OFF$" />
|
||||
</conditions>
|
||||
<action type="Redirect" url="https://{HTTP_HOST}/{REQUEST_URI}" appendQueryString="false" />
|
||||
</rule>
|
||||
<!-- Redirect to internal nextcloud server -->
|
||||
<rule name="To nextcloud" stopProcessing="true">
|
||||
<match url="(.*)" />
|
||||
<conditions>
|
||||
<add input="{HTTPS}" pattern="^ON$" />
|
||||
</conditions>
|
||||
<action type="Rewrite" url="http://nc-server-farm:11000/{UNENCODED_URL}" appendQueryString="false" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
<security>
|
||||
<!-- Increase upload limit to 2GiB -->
|
||||
<requestFiltering allowDoubleEscaping="true">
|
||||
<requestLimits maxAllowedContentLength="2147483648" />
|
||||
</requestFiltering>
|
||||
</security>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
|
||||
```
|
||||
⚠️ **Please note:** Look into [this](#adapting-the-sample-web-server-configurations-below) to adapt the above example configuration.
|
||||
|
||||
</details>
|
||||
|
||||
### Others
|
||||
|
||||
<details>
|
||||
|
||||
Reference in New Issue
Block a user