mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-05-21 10:50:10 +00:00
Compare commits
2 Commits
v10.0.0
...
enh/noid/o
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f69143531 | ||
|
|
f2e71532e7 |
72
.github/workflows/json-validator.yml
vendored
72
.github/workflows/json-validator.yml
vendored
@@ -1,37 +1,35 @@
|
||||
name: Json Validator
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.json'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '**.json'
|
||||
|
||||
jobs:
|
||||
json-validator:
|
||||
name: Json Validator
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Validate Json
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install python3-venv -y --no-install-recommends
|
||||
python3 -m venv venv
|
||||
. venv/bin/activate
|
||||
pip3 install json-spec
|
||||
if ! json validate --schema-file=php/containers-schema.json --document-file=php/containers.json; then
|
||||
exit 1
|
||||
fi
|
||||
JSON_FILES="$(find ./community-containers -name '*.json')"
|
||||
mapfile -t JSON_FILES <<< "$JSON_FILES"
|
||||
for file in "${JSON_FILES[@]}"; do
|
||||
json validate --schema-file=php/containers-schema.json --document-file="$file" 2>&1 | tee -a ./json-validator.log
|
||||
done
|
||||
if grep -q "document does not validate with schema.\|invalid JSONFile" ./json-validator.log; then
|
||||
exit 1
|
||||
fi
|
||||
name: Json Validator
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.json'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '**.json'
|
||||
|
||||
jobs:
|
||||
json-validator:
|
||||
name: Json Validator
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Validate Json
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install python3-pip -y --no-install-recommends
|
||||
sudo pip3 install json-spec
|
||||
if ! json validate --schema-file=php/containers-schema.json --document-file=php/containers.json; then
|
||||
exit 1
|
||||
fi
|
||||
JSON_FILES="$(find ./community-containers -name '*.json')"
|
||||
mapfile -t JSON_FILES <<< "$JSON_FILES"
|
||||
for file in "${JSON_FILES[@]}"; do
|
||||
json validate --schema-file=php/containers-schema.json --document-file="$file" 2>&1 | tee -a ./json-validator.log
|
||||
done
|
||||
if grep -q "document does not validate with schema.\|invalid JSONFile" ./json-validator.log; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
18
.github/workflows/nextcloud-update.yml
vendored
18
.github/workflows/nextcloud-update.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
| sort -V \
|
||||
| tail -1
|
||||
)"
|
||||
sed -i "s|\(pecl install[^;]*APCu-\)[0-9.]*|\1$apcu_version|" ./Containers/nextcloud/Dockerfile
|
||||
sed -i "s|pecl install APCu.*\;|pecl install APCu-$apcu_version\;|" ./Containers/nextcloud/Dockerfile
|
||||
|
||||
# Memcached
|
||||
memcached_version="$(
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
| sort -V \
|
||||
| tail -1
|
||||
)"
|
||||
sed -i "s|\(pecl install[^;]*memcached-\)[0-9.]*|\1$memcached_version|" ./Containers/nextcloud/Dockerfile
|
||||
sed -i "s|pecl install memcached.* |pecl install memcached-$memcached_version |" ./Containers/nextcloud/Dockerfile
|
||||
|
||||
# Redis
|
||||
redis_version="$(
|
||||
@@ -47,24 +47,18 @@ jobs:
|
||||
| sort -V \
|
||||
| tail -1
|
||||
)"
|
||||
sed -i "s|\(pecl install[^;]*redis-\)[0-9.]*|\1$redis_version|" ./Containers/nextcloud/Dockerfile
|
||||
sed -i "s|pecl install redis.* |pecl install redis-$redis_version |" ./Containers/nextcloud/Dockerfile
|
||||
|
||||
# Imagick
|
||||
imagick_version="$(
|
||||
git ls-remote --tags https://github.com/imagick/imagick.git \
|
||||
git ls-remote --tags https://github.com/mkoppanen/imagick.git \
|
||||
| cut -d/ -f3 \
|
||||
| grep -viE '[a-z]' \
|
||||
| tr -d '^{}' \
|
||||
| sort -V \
|
||||
| tail -1
|
||||
)"
|
||||
sed -i "s|\(pecl install[^;]*imagick-\)[0-9.]*|\1$imagick_version|" ./Containers/nextcloud/Dockerfile
|
||||
|
||||
# Imagick git-commit-hash from HEAD
|
||||
imagick_commit_hash="$(
|
||||
git ls-remote https://github.com/imagick/imagick.git HEAD | awk '{print $1}'
|
||||
)"
|
||||
sed -i "s/\(ARG IMAGICK_COMMIT_HASH=\)[a-fA-F0-9]*$/\1$imagick_commit_hash/" ./Containers/nextcloud/Dockerfile
|
||||
sed -i "s|pecl install imagick.*\;|pecl install imagick-$imagick_version\;|" ./Containers/nextcloud/Dockerfile
|
||||
|
||||
# Igbinary
|
||||
igbinary_version="$(
|
||||
@@ -75,7 +69,7 @@ jobs:
|
||||
| sort -V \
|
||||
| tail -1
|
||||
)"
|
||||
sed -i "s|\(pecl install[^;]*igbinary-\)[0-9.]*|\1$igbinary_version|" ./Containers/nextcloud/Dockerfile
|
||||
sed -i "s|pecl install igbinary.*\;|pecl install igbinary-$igbinary_version\;|" ./Containers/nextcloud/Dockerfile
|
||||
|
||||
# Nextcloud
|
||||
NC_MAJOR="$(grep "ENV NEXTCLOUD_VERSION" ./Containers/nextcloud/Dockerfile | grep -oP '[23][0-9]')"
|
||||
|
||||
11
.github/workflows/update-copyright.yml
vendored
11
.github/workflows/update-copyright.yml
vendored
@@ -1,11 +0,0 @@
|
||||
name: Update Copyright
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update-copyright:
|
||||
name: update copyright
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -81,7 +81,7 @@ RUN set -ex; \
|
||||
\
|
||||
echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||
|
||||
USER 33
|
||||
USER www-data
|
||||
|
||||
ENTRYPOINT ["/start.sh"]
|
||||
CMD ["/usr/bin/supervisord", "-c", "/supervisord.conf"]
|
||||
|
||||
@@ -9,8 +9,8 @@ logfile_backups=10
|
||||
loglevel=error
|
||||
|
||||
[program:apache]
|
||||
# Stdout logging is disabled as otherwise the logs are spammed
|
||||
stdout_logfile=NONE
|
||||
# stdout_logfile=/dev/stdout
|
||||
# stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
command=apachectl -DFOREGROUND
|
||||
|
||||
@@ -11,13 +11,11 @@ RUN set -ex; \
|
||||
rsync \
|
||||
fuse \
|
||||
py3-llfuse \
|
||||
jq \
|
||||
openssh-client
|
||||
jq
|
||||
|
||||
VOLUME /root
|
||||
|
||||
COPY --chmod=770 *.sh /
|
||||
COPY borg_excludes /
|
||||
|
||||
ENTRYPOINT ["/start.sh"]
|
||||
# hadolint ignore=DL3002
|
||||
|
||||
@@ -34,23 +34,19 @@ for volume in "${DEFAULT_VOLUMES[@]}"; do
|
||||
done
|
||||
|
||||
# Check if target is mountpoint
|
||||
if [ -z "$BORG_REMOTE_REPO" ] && ! mountpoint -q "$MOUNT_DIR"; then
|
||||
echo "$MOUNT_DIR is not a mountpoint which is not allowed."
|
||||
if ! mountpoint -q /mnt/borgbackup; then
|
||||
echo "/mnt/borgbackup is not a mountpoint which is not allowed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if repo is uninitialized
|
||||
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != test ] && ! borg info > /dev/null; then
|
||||
if [ -n "$BORG_REMOTE_REPO" ]; then
|
||||
echo "The repository is uninitialized or cannot connect to remote. Cannot perform check or restore."
|
||||
else
|
||||
echo "The repository is uninitialized. Cannot perform check or restore."
|
||||
fi
|
||||
# Check if target is empty
|
||||
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != test ] && ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||
echo "The repository is empty. Cannot perform check or restore."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Do not continue if this file exists (needed for simple external blocking)
|
||||
if [ -z "$BORG_REMOTE_REPO" ] && [ -f "$BORG_BACKUP_DIRECTORY/aio-lockfile" ]; then
|
||||
if [ -f "$BORG_BACKUP_DIRECTORY/aio-lockfile" ]; then
|
||||
echo "Not continuing because aio-lockfile exists – it seems like a script is externally running which is locking the backup archive."
|
||||
echo "If this should not be the case, you can fix this by deleting the 'aio-lockfile' file from the backup archive directory."
|
||||
exit 1
|
||||
@@ -61,15 +57,6 @@ if [ "$BORG_MODE" = backup ] || [ "$BORG_MODE" = restore ]; then
|
||||
touch "/nextcloud_aio_volumes/nextcloud_aio_database_dump/backup-is-running"
|
||||
fi
|
||||
|
||||
if [ -n "$BORG_REMOTE_REPO" ] && ! [ -f "$BORGBACKUP_KEY" ]; then
|
||||
echo "First run, creating borg ssh key"
|
||||
ssh-keygen -f "$BORGBACKUP_KEY" -N ""
|
||||
echo "You should configure the remote to accept this public key"
|
||||
fi
|
||||
if [ -n "$BORG_REMOTE_REPO" ] && [ -f "$BORGBACKUP_KEY.pub" ]; then
|
||||
echo "Your public ssh key for borgbackup is: $(cat "$BORGBACKUP_KEY.pub")"
|
||||
fi
|
||||
|
||||
# Do the backup
|
||||
if [ "$BORG_MODE" = backup ]; then
|
||||
|
||||
@@ -113,22 +100,15 @@ if [ "$BORG_MODE" = backup ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$BORG_REMOTE_REPO" ]; then
|
||||
# Create backup folder
|
||||
mkdir -p "$BORG_BACKUP_DIRECTORY"
|
||||
fi
|
||||
# Create backup folder
|
||||
mkdir -p "$BORG_BACKUP_DIRECTORY"
|
||||
|
||||
# Initialize the repository if can't get info from target
|
||||
if ! borg info > /dev/null; then
|
||||
# Initialize the repository if the target is empty
|
||||
if ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||
# Don't initialize if already initialized
|
||||
if [ -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config" ]; then
|
||||
if [ -n "$BORG_REMOTE_REPO" ]; then
|
||||
echo "Borg could not get info from the remote repo."
|
||||
echo "This might be a failure to connect to the remote server. See the above borg info output for details."
|
||||
else
|
||||
echo "Borg could not get info from the targeted directory."
|
||||
echo "This might happen if the targeted directory is located on an external drive and the drive not connected anymore. You should check this."
|
||||
fi
|
||||
echo "No borg config file was found in the targeted directory."
|
||||
echo "This might happen if the targeted directory is located on an external drive and the drive not connected anymore. You should check this."
|
||||
echo "If you instead want to initialize a new backup repository, you may delete the 'borg.config' file that is stored in the mastercontainer volume manually, which will allow you to initialize a new borg repository in the chosen directory:"
|
||||
echo "sudo docker exec nextcloud-aio-mastercontainer rm /mnt/docker-aio-config/data/borg.config"
|
||||
exit 1
|
||||
@@ -136,44 +116,28 @@ if [ "$BORG_MODE" = backup ]; then
|
||||
|
||||
echo "Initializing repository..."
|
||||
NEW_REPOSITORY=1
|
||||
if ! borg init --debug --encryption=repokey-blake2; then
|
||||
if ! borg init --debug --encryption=repokey-blake2 "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "Could not initialize borg repository."
|
||||
if [ -z "$BORG_REMOTE_REPO" ]; then
|
||||
# Originally we checked for presence of the config file instead of calling `borg info`. Likely `borg info`
|
||||
# will error on a partially initialized repo, so this line is probably no longer necessary
|
||||
rm -f "$BORG_BACKUP_DIRECTORY/config"
|
||||
fi
|
||||
rm -f "$BORG_BACKUP_DIRECTORY/config"
|
||||
exit 1
|
||||
fi
|
||||
borg config "$BORG_BACKUP_DIRECTORY" additional_free_space 2G
|
||||
|
||||
if [ -z "$BORG_REMOTE_REPO" ]; then
|
||||
# borg config only works for local repos; it's up to the remote to ensure the disk isn't full
|
||||
borg config :: additional_free_space 2G
|
||||
# Fix too large Borg cache
|
||||
# https://borgbackup.readthedocs.io/en/stable/faq.html#the-borg-cache-eats-way-too-much-disk-space-what-can-i-do
|
||||
BORG_ID="$(borg config "$BORG_BACKUP_DIRECTORY" id)"
|
||||
rm -r "/root/.cache/borg/$BORG_ID/chunks.archive.d"
|
||||
touch "/root/.cache/borg/$BORG_ID/chunks.archive.d"
|
||||
|
||||
# Fix too large Borg cache
|
||||
# https://borgbackup.readthedocs.io/en/stable/faq.html#the-borg-cache-eats-way-too-much-disk-space-what-can-i-do
|
||||
BORG_ID="$(borg config :: id)"
|
||||
rm -r "/root/.cache/borg/$BORG_ID/chunks.archive.d"
|
||||
touch "/root/.cache/borg/$BORG_ID/chunks.archive.d"
|
||||
fi
|
||||
|
||||
if ! borg info > /dev/null; then
|
||||
echo "Borg can't get info from the repo it created. Something is wrong."
|
||||
# Make a backup from the borg config file
|
||||
if ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||
echo "The borg config file wasn't created. Something is wrong."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"
|
||||
if [ -n "$BORG_REMOTE_REPO" ]; then
|
||||
# `borg config` does not support remote repos so instead create a dummy file and rely on the remote to avoid
|
||||
# corruption of the config file (which contains the encryption key). We don't actually use the contents of
|
||||
# this file anywhere, so a touch is all we need so we remember we already initialized the repo.
|
||||
touch "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"
|
||||
else
|
||||
# Make a backup from the borg config file
|
||||
if ! cp "$BORG_BACKUP_DIRECTORY/config" "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"; then
|
||||
echo "Could not copy config file to second place. Cannot perform backup."
|
||||
exit 1
|
||||
fi
|
||||
if ! cp "$BORG_BACKUP_DIRECTORY/config" "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"; then
|
||||
echo "Could not copy config file to second place. Cannot perform backup."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Repository successfully initialized."
|
||||
@@ -203,9 +167,9 @@ if [ "$BORG_MODE" = backup ]; then
|
||||
# Create the backup
|
||||
echo "Starting the backup..."
|
||||
get_start_time
|
||||
if ! borg create "${BORG_OPTS[@]}" "${BORG_EXCLUDE[@]}" "::$CURRENT_DATE-nextcloud-aio" "/nextcloud_aio_volumes/" --exclude-from /borg_excludes; then
|
||||
if ! borg create "${BORG_OPTS[@]}" "${BORG_EXCLUDE[@]}" "$BORG_BACKUP_DIRECTORY::$CURRENT_DATE-nextcloud-aio" "/nextcloud_aio_volumes/"; then
|
||||
echo "Deleting the failed backup archive..."
|
||||
borg delete --stats "::$CURRENT_DATE-nextcloud-aio"
|
||||
borg delete --stats "$BORG_BACKUP_DIRECTORY::$CURRENT_DATE-nextcloud-aio"
|
||||
echo "Backup failed!"
|
||||
echo "You might want to check the backup integrity via the AIO interface."
|
||||
if [ "$NEW_REPOSITORY" = 1 ]; then
|
||||
@@ -224,14 +188,14 @@ if [ "$BORG_MODE" = backup ]; then
|
||||
|
||||
# Prune archives
|
||||
echo "Pruning the archives..."
|
||||
if ! borg prune --stats --glob-archives '*_*-nextcloud-aio' "${BORG_PRUNE_OPTS[@]}"; then
|
||||
if ! borg prune --stats --glob-archives '*_*-nextcloud-aio' "${BORG_PRUNE_OPTS[@]}" "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "Failed to prune archives!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Compact archives
|
||||
echo "Compacting the archives..."
|
||||
if ! borg compact; then
|
||||
if ! borg compact "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "Failed to compact archives!"
|
||||
exit 1
|
||||
fi
|
||||
@@ -248,19 +212,19 @@ if [ "$BORG_MODE" = backup ]; then
|
||||
fi
|
||||
done
|
||||
echo "Starting the backup for additional volumes..."
|
||||
if ! borg create "${BORG_OPTS[@]}" "::$CURRENT_DATE-additional-docker-volumes" "/docker_volumes/"; then
|
||||
if ! borg create "${BORG_OPTS[@]}" "$BORG_BACKUP_DIRECTORY::$CURRENT_DATE-additional-docker-volumes" "/docker_volumes/"; then
|
||||
echo "Deleting the failed backup archive..."
|
||||
borg delete --stats "::$CURRENT_DATE-additional-docker-volumes"
|
||||
borg delete --stats "$BORG_BACKUP_DIRECTORY::$CURRENT_DATE-additional-docker-volumes"
|
||||
echo "Backup of additional docker-volumes failed!"
|
||||
exit 1
|
||||
fi
|
||||
echo "Pruning additional volumes..."
|
||||
if ! borg prune --stats --glob-archives '*_*-additional-docker-volumes' "${BORG_PRUNE_OPTS[@]}"; then
|
||||
if ! borg prune --stats --glob-archives '*_*-additional-docker-volumes' "${BORG_PRUNE_OPTS[@]}" "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "Failed to prune additional docker-volumes archives!"
|
||||
exit 1
|
||||
fi
|
||||
echo "Compacting additional volumes..."
|
||||
if ! borg compact; then
|
||||
if ! borg compact "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "Failed to compact additional docker-volume archives!"
|
||||
exit 1
|
||||
fi
|
||||
@@ -278,19 +242,19 @@ if [ "$BORG_MODE" = backup ]; then
|
||||
EXCLUDE_DIRS+=(--exclude "/host_mounts/$directory/")
|
||||
done
|
||||
echo "Starting the backup for additional host mounts..."
|
||||
if ! borg create "${BORG_OPTS[@]}" "${EXCLUDE_DIRS[@]}" "::$CURRENT_DATE-additional-host-mounts" "/host_mounts/"; then
|
||||
if ! borg create "${BORG_OPTS[@]}" "${EXCLUDE_DIRS[@]}" "$BORG_BACKUP_DIRECTORY::$CURRENT_DATE-additional-host-mounts" "/host_mounts/"; then
|
||||
echo "Deleting the failed backup archive..."
|
||||
borg delete --stats "::$CURRENT_DATE-additional-host-mounts"
|
||||
borg delete --stats "$BORG_BACKUP_DIRECTORY::$CURRENT_DATE-additional-host-mounts"
|
||||
echo "Backup of additional host-mounts failed!"
|
||||
exit 1
|
||||
fi
|
||||
echo "Pruning additional host mounts..."
|
||||
if ! borg prune --stats --glob-archives '*_*-additional-host-mounts' "${BORG_PRUNE_OPTS[@]}"; then
|
||||
if ! borg prune --stats --glob-archives '*_*-additional-host-mounts' "${BORG_PRUNE_OPTS[@]}" "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "Failed to prune additional host-mount archives!"
|
||||
exit 1
|
||||
fi
|
||||
echo "Compacting additional host mounts..."
|
||||
if ! borg compact; then
|
||||
if ! borg compact "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "Failed to compact additional host-mount archives!"
|
||||
exit 1
|
||||
fi
|
||||
@@ -312,24 +276,17 @@ fi
|
||||
if [ "$BORG_MODE" = restore ]; then
|
||||
get_start_time
|
||||
|
||||
# Pick archive to restore
|
||||
# Perform the restore
|
||||
if [ -n "$SELECTED_RESTORE_TIME" ]; then
|
||||
SELECTED_ARCHIVE="$(borg list | grep "nextcloud-aio" | grep "$SELECTED_RESTORE_TIME" | awk -F " " '{print $1}' | head -1)"
|
||||
SELECTED_ARCHIVE="$(borg list "$BORG_BACKUP_DIRECTORY" | grep "nextcloud-aio" | grep "$SELECTED_RESTORE_TIME" | awk -F " " '{print $1}' | head -1)"
|
||||
else
|
||||
SELECTED_ARCHIVE="$(borg list | grep "nextcloud-aio" | awk -F " " '{print $1}' | sort -r | head -1)"
|
||||
SELECTED_ARCHIVE="$(borg list "$BORG_BACKUP_DIRECTORY" | grep "nextcloud-aio" | awk -F " " '{print $1}' | sort -r | head -1)"
|
||||
fi
|
||||
echo "Restoring '$SELECTED_ARCHIVE'..."
|
||||
|
||||
# Exclude previews from restore if selected to speed up process
|
||||
ADDITIONAL_RSYNC_EXCLUDES=()
|
||||
ADDITIONAL_BORG_EXCLUDES=()
|
||||
ADDITIONAL_FIND_EXCLUDES=()
|
||||
if [ -n "$RESTORE_EXCLUDE_PREVIEWS" ]; then
|
||||
# Keep these 3 in sync. Beware, the pattern syntax and the paths differ
|
||||
ADDITIONAL_RSYNC_EXCLUDES=(--exclude "nextcloud_aio_nextcloud_data/appdata_*/preview/**")
|
||||
ADDITIONAL_BORG_EXCLUDES=(--exclude "sh:nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/appdata_*/preview/**")
|
||||
ADDITIONAL_FIND_EXCLUDES=(-o -regex 'nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/appdata_[^/]*/preview\(/.*\)?')
|
||||
echo "Excluding previews from restore"
|
||||
mkdir -p /tmp/borg
|
||||
if ! borg mount "$BORG_BACKUP_DIRECTORY::$SELECTED_ARCHIVE" /tmp/borg; then
|
||||
echo "Could not mount the backup!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Save Additional Backup dirs
|
||||
@@ -342,12 +299,27 @@ if [ "$BORG_MODE" = restore ]; then
|
||||
DAILY_BACKUPTIME="$(cat /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_time)"
|
||||
fi
|
||||
|
||||
# Restore everything except the configuration file
|
||||
if ! rsync --stats --archive --human-readable -vv --delete \
|
||||
--exclude "nextcloud_aio_apache/caddy/**" \
|
||||
--exclude "nextcloud_aio_mastercontainer/caddy/**" \
|
||||
--exclude "nextcloud_aio_nextcloud/data/nextcloud.log*" \
|
||||
--exclude "nextcloud_aio_nextcloud/data/audit.log" \
|
||||
--exclude "nextcloud_aio_mastercontainer/certs/**" \
|
||||
--exclude "nextcloud_aio_mastercontainer/data/configuration.json" \
|
||||
--exclude "nextcloud_aio_mastercontainer/data/daily_backup_running" \
|
||||
--exclude "nextcloud_aio_mastercontainer/data/session_date_file" \
|
||||
--exclude "nextcloud_aio_mastercontainer/session/**" \
|
||||
/tmp/borg/nextcloud_aio_volumes/ /nextcloud_aio_volumes/; then
|
||||
RESTORE_FAILED=1
|
||||
echo "Something failed while restoring from backup."
|
||||
fi
|
||||
|
||||
# Save current aio password
|
||||
AIO_PASSWORD="$(jq '.password' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
|
||||
# Save current backup location vars
|
||||
# Save current path
|
||||
BORG_LOCATION="$(jq '.borg_backup_host_location' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
REMOTE_REPO="$(jq '.borg_remote_repo' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
|
||||
# Save current nextcloud datadir
|
||||
if grep -q '"nextcloud_datadir":' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json; then
|
||||
@@ -356,114 +328,21 @@ if [ "$BORG_MODE" = restore ]; then
|
||||
NEXTCLOUD_DATADIR='""'
|
||||
fi
|
||||
|
||||
if [ -z "$BORG_REMOTE_REPO" ]; then
|
||||
mkdir -p /tmp/borg
|
||||
if ! borg mount "::$SELECTED_ARCHIVE" /tmp/borg; then
|
||||
echo "Could not mount the backup!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Restore everything except the configuration file
|
||||
#
|
||||
# These exclude patterns need to be kept in sync with the borg_excludes file and the find excludes in this file,
|
||||
# which use a different syntax (patterns appear in 3 places in total)
|
||||
if ! rsync --stats --archive --human-readable -vv --delete \
|
||||
--exclude "nextcloud_aio_apache/caddy/**" \
|
||||
--exclude "nextcloud_aio_mastercontainer/caddy/**" \
|
||||
--exclude "nextcloud_aio_nextcloud/data/nextcloud.log*" \
|
||||
--exclude "nextcloud_aio_nextcloud/data/audit.log" \
|
||||
--exclude "nextcloud_aio_mastercontainer/certs/**" \
|
||||
--exclude "nextcloud_aio_mastercontainer/data/configuration.json" \
|
||||
--exclude "nextcloud_aio_mastercontainer/data/daily_backup_running" \
|
||||
--exclude "nextcloud_aio_mastercontainer/data/session_date_file" \
|
||||
--exclude "nextcloud_aio_mastercontainer/session/**" \
|
||||
"${ADDITIONAL_RSYNC_EXCLUDES[@]}" \
|
||||
/tmp/borg/nextcloud_aio_volumes/ /nextcloud_aio_volumes/; then
|
||||
RESTORE_FAILED=1
|
||||
echo "Something failed while restoring from backup."
|
||||
fi
|
||||
|
||||
# Restore the configuration file
|
||||
if ! rsync --archive --human-readable -vv \
|
||||
/tmp/borg/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json \
|
||||
/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json; then
|
||||
RESTORE_FAILED=1
|
||||
echo "Something failed while restoring the configuration.json."
|
||||
fi
|
||||
|
||||
if ! umount /tmp/borg; then
|
||||
echo "Failed to unmount the borg archive but should still be able to restore successfully"
|
||||
fi
|
||||
else
|
||||
# Restore nearly everything
|
||||
#
|
||||
# borg mount is really slow for remote repos (did not check whether it's slow for local repos too),
|
||||
# using extract to /tmp would require temporarily storing a second copy of the data.
|
||||
# So instead extract directly on top of the destination with exclude patterns for the config, but
|
||||
# then we do still need to delete local files which are not present in the archive.
|
||||
#
|
||||
# Older backups may still contain files we've since excluded, so we have to exclude on extract as well.
|
||||
cd / # borg extract has no destination arg and extracts to CWD
|
||||
if ! borg extract "::$SELECTED_ARCHIVE" --progress --exclude-from /borg_excludes "${ADDITIONAL_BORG_EXCLUDES[@]}" --pattern '+nextcloud_aio_volumes/**'
|
||||
then
|
||||
RESTORE_FAILED=1
|
||||
echo "Failed to extract backup archive."
|
||||
else
|
||||
# Delete files/dirs present locally, but not in the backup archive, excluding conf files
|
||||
# https://unix.stackexchange.com/a/759341
|
||||
# This comm does not support -z, but I doubt any file names would have \n in them
|
||||
#
|
||||
# These find patterns need to be kept in sync with the borg_excludes file and the rsync excludes in this
|
||||
# file, which use a different syntax (patterns appear in 3 places in total)
|
||||
echo "Deleting local files which do not exist in the backup"
|
||||
if ! find nextcloud_aio_volumes \
|
||||
-not \( \
|
||||
-path nextcloud_aio_volumes/nextcloud_aio_apache/caddy \
|
||||
-o -path "nextcloud_aio_volumes/nextcloud_aio_apache/caddy/*" \
|
||||
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/caddy \
|
||||
-o -path "nextcloud_aio_volumes/nextcloud_aio_mastercontainer/caddy/*" \
|
||||
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/certs \
|
||||
-o -path "nextcloud_aio_volumes/nextcloud_aio_mastercontainer/certs/*" \
|
||||
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/session \
|
||||
-o -path "nextcloud_aio_volumes/nextcloud_aio_mastercontainer/session/*" \
|
||||
-o -path "nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/nextcloud.log*" \
|
||||
-o -path nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/audit.log \
|
||||
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_running \
|
||||
-o -path nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/session_date_file \
|
||||
-o -path "nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/id_borg*" \
|
||||
"${ADDITIONAL_FIND_EXCLUDES[@]}" \
|
||||
\) \
|
||||
| LC_ALL=C sort \
|
||||
| LC_ALL=C comm -23 - \
|
||||
<(borg list "::$SELECTED_ARCHIVE" --short --exclude-from /borg_excludes --pattern '+nextcloud_aio_volumes/**' | LC_ALL=C sort) \
|
||||
> /tmp/local_files_not_in_backup
|
||||
then
|
||||
RESTORE_FAILED=1
|
||||
echo "Failed to delete local files not in backup archive."
|
||||
else
|
||||
# More robust than e.g. xargs as I got a ~"args line too long" error while testing that, but it's slower
|
||||
# https://stackoverflow.com/a/21848934
|
||||
while IFS= read -r file
|
||||
do rm -vrf -- "$file" || DELETE_FAILED=1
|
||||
done < /tmp/local_files_not_in_backup
|
||||
|
||||
if [ "$DELETE_FAILED" = 1 ]; then
|
||||
RESTORE_FAILED=1
|
||||
echo "Failed to delete (some) local files not in backup archive."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# Restore the configuration file
|
||||
if ! rsync --archive --human-readable -vv \
|
||||
/tmp/borg/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json \
|
||||
/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json; then
|
||||
RESTORE_FAILED=1
|
||||
echo "Something failed while restoring the configuration.json."
|
||||
fi
|
||||
|
||||
# Set backup-mode to restore since it was a restore
|
||||
CONTENTS="$(jq '."backup-mode" = "restore"' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
|
||||
|
||||
# Reset the backup location vars to the currently used one
|
||||
# Reset the backup path to the currently used one
|
||||
CONTENTS="$(jq ".borg_backup_host_location = $BORG_LOCATION" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
|
||||
CONTENTS="$(jq ".borg_remote_repo = $REMOTE_REPO" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
|
||||
|
||||
# Reset the AIO password to the currently used one
|
||||
CONTENTS="$(jq ".password = $AIO_PASSWORD" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
@@ -487,6 +366,8 @@ if [ "$BORG_MODE" = restore ]; then
|
||||
chmod 770 "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_time"
|
||||
fi
|
||||
|
||||
umount /tmp/borg
|
||||
|
||||
if [ "$RESTORE_FAILED" = 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -503,12 +384,6 @@ if [ "$BORG_MODE" = restore ]; then
|
||||
touch "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/fingerprint.update"
|
||||
chmod 777 "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/fingerprint.update"
|
||||
|
||||
# Add file to Netcloud container to trigger a preview scan the next time it starts
|
||||
if [ -n "$RESTORE_EXCLUDE_PREVIEWS" ]; then
|
||||
touch "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/trigger-preview.scan"
|
||||
chmod 777 "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/trigger-preview.scan"
|
||||
fi
|
||||
|
||||
# Delete redis cache
|
||||
rm -f "/mnt/redis/dump.rdb"
|
||||
fi
|
||||
@@ -519,7 +394,7 @@ if [ "$BORG_MODE" = check ]; then
|
||||
echo "Checking the backup integrity..."
|
||||
|
||||
# Perform the check
|
||||
if ! borg check -v --verify-data; then
|
||||
if ! borg check -v --verify-data "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "Some errors were found while checking the backup integrity!"
|
||||
echo "Check the AIO interface for advices on how to proceed now!"
|
||||
exit 1
|
||||
@@ -537,7 +412,7 @@ if [ "$BORG_MODE" = "check-repair" ]; then
|
||||
echo "Checking the backup integrity and repairing it..."
|
||||
|
||||
# Perform the check-repair
|
||||
if ! echo YES | borg check -v --repair; then
|
||||
if ! echo YES | borg check -v --repair "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "Some errors were found while checking and repairing the backup integrity!"
|
||||
exit 1
|
||||
fi
|
||||
@@ -550,29 +425,19 @@ fi
|
||||
|
||||
# Do the backup test
|
||||
if [ "$BORG_MODE" = test ]; then
|
||||
if [ -n "$BORG_REMOTE_REPO" ]; then
|
||||
if ! borg info > /dev/null; then
|
||||
echo "Borg could not get info from the remote repo."
|
||||
echo "See the above borg info output for details."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! [ -d "$BORG_BACKUP_DIRECTORY" ]; then
|
||||
echo "No 'borg' directory in the given backup directory found!"
|
||||
echo "Only the files/folders below have been found in the given directory."
|
||||
ls -a "$MOUNT_DIR"
|
||||
echo "Please adjust the directory so that the borg archive is positioned in a folder named 'borg' inside the given directory!"
|
||||
exit 1
|
||||
elif ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||
echo "A 'borg' directory was found but could not find the borg archive."
|
||||
echo "Only the files/folders below have been found in the borg directory."
|
||||
ls -a "$BORG_BACKUP_DIRECTORY"
|
||||
echo "The archive and most importantly the config file must be positioned directly in the 'borg' subfolder."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! borg list; then
|
||||
if ! [ -d "$BORG_BACKUP_DIRECTORY" ]; then
|
||||
echo "No 'borg' directory in the given backup directory found!"
|
||||
echo "Only the files/folders below have been found in the given directory."
|
||||
ls -a "$MOUNT_DIR"
|
||||
echo "Please adjust the directory so that the borg archive is positioned in a folder named 'borg' inside the given directory!"
|
||||
exit 1
|
||||
elif ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||
echo "A 'borg' directory was found but could not find the borg archive."
|
||||
echo "Only the files/folders below have been found in the borg directory."
|
||||
ls -a "$BORG_BACKUP_DIRECTORY"
|
||||
echo "The archive and most importantly the config file must be positioned directly in the 'borg' subfolder."
|
||||
exit 1
|
||||
elif ! borg list "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "The entered path seems to be valid but could not open the backup archive."
|
||||
echo "Most likely the entered password was wrong so please adjust it accordingly!"
|
||||
exit 1
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# These patterns need to be kept in sync with rsync and find excludes in backupscript.sh,
|
||||
# which use a different syntax (patterns appear in 3 places in total)
|
||||
nextcloud_aio_volumes/nextcloud_aio_apache/caddy/
|
||||
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/caddy/
|
||||
nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/nextcloud.log*
|
||||
nextcloud_aio_volumes/nextcloud_aio_nextcloud/data/audit.log
|
||||
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/certs/
|
||||
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/daily_backup_running
|
||||
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/session_date_file
|
||||
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/session/
|
||||
nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/id_borg*
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Variables
|
||||
export MOUNT_DIR="/mnt/borgbackup"
|
||||
export BORG_BACKUP_DIRECTORY="$MOUNT_DIR/borg" # necessary even when remote to store the aio-lockfile
|
||||
export BORG_BACKUP_DIRECTORY="$MOUNT_DIR/borg"
|
||||
|
||||
# Validate BORG_PASSWORD
|
||||
if [ -z "$BORG_PASSWORD" ] && [ -z "$BACKUP_RESTORE_PASSWORD" ]; then
|
||||
@@ -18,18 +18,6 @@ else
|
||||
fi
|
||||
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
|
||||
export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes
|
||||
if [ -n "$BORG_REMOTE_REPO" ]; then
|
||||
export BORG_REPO="$BORG_REMOTE_REPO"
|
||||
|
||||
# Location to create the borg ssh pub/priv key
|
||||
export BORGBACKUP_KEY="/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/id_borg"
|
||||
|
||||
# Accept any host key the first time connecting to the remote. Strictly speaking should be provided by user but you'd
|
||||
# have to be very unlucky to get MitM'ed on your first connection.
|
||||
export BORG_RSH="ssh -o StrictHostKeyChecking=accept-new -i $BORGBACKUP_KEY"
|
||||
else
|
||||
export BORG_REPO="$BORG_BACKUP_DIRECTORY"
|
||||
fi
|
||||
|
||||
# Validate BORG_MODE
|
||||
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != restore ] && [ "$BORG_MODE" != check ] && [ "$BORG_MODE" != "check-repair" ] && [ "$BORG_MODE" != test ]; then
|
||||
@@ -48,8 +36,8 @@ fi
|
||||
rm -f "/nextcloud_aio_volumes/nextcloud_aio_database_dump/backup-is-running"
|
||||
|
||||
# Get a list of all available borg archives
|
||||
if borg list &>/dev/null; then
|
||||
borg list | grep "nextcloud-aio" | awk -F " " '{print $1","$3,$4}' > "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
|
||||
if borg list "$BORG_BACKUP_DIRECTORY" &>/dev/null; then
|
||||
borg list "$BORG_BACKUP_DIRECTORY" | grep "nextcloud-aio" | awk -F " " '{print $1","$3,$4}' > "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
|
||||
else
|
||||
echo "" > "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
|
||||
fi
|
||||
|
||||
@@ -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.4.1-12
|
||||
FROM clamav/clamav:1.4.1-5
|
||||
|
||||
COPY clamav.conf /clamav.conf
|
||||
COPY --chmod=775 start.script /start.script
|
||||
@@ -19,7 +19,7 @@ RUN set -ex; \
|
||||
|
||||
VOLUME /var/lib/clamav
|
||||
|
||||
USER 100
|
||||
USER clamav
|
||||
|
||||
LABEL com.centurylinklabs.watchtower.enable="false"
|
||||
|
||||
|
||||
@@ -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.9.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.6-alpine
|
||||
FROM haproxy:3.0.5-alpine
|
||||
|
||||
# hadolint ignore=DL3002
|
||||
USER root
|
||||
|
||||
@@ -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.15.3
|
||||
FROM elasticsearch:8.15.1
|
||||
|
||||
USER root
|
||||
|
||||
@@ -14,7 +14,8 @@ RUN set -ex; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
tzdata \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*;
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
elasticsearch-plugin install --batch ingest-attachment
|
||||
|
||||
USER 1000:0
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM golang:1.23.3-alpine3.20 AS go
|
||||
FROM golang:1.23.1-alpine3.20 AS go
|
||||
|
||||
ENV IMAGINARY_HASH=8f36a26c448be8c151a3878404b75fcd1cd3cf0c
|
||||
ENV IMAGINARY_HASH=6cd9edd1d3fb151eb773c14552886e4fc8e50138
|
||||
|
||||
RUN set -ex; \
|
||||
apk add --no-cache \
|
||||
@@ -33,7 +33,7 @@ COPY --chmod=775 start.sh /start.sh
|
||||
|
||||
ENV PORT=9000
|
||||
|
||||
USER 65534
|
||||
USER nobody
|
||||
|
||||
# https://github.com/h2non/imaginary#memory-issues
|
||||
ENV MALLOC_ARENA_MAX=2
|
||||
|
||||
@@ -6,7 +6,7 @@ FROM docker:27.3.1-cli AS docker
|
||||
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.13-fpm-alpine3.20
|
||||
FROM php:8.3.11-fpm-alpine3.20
|
||||
|
||||
EXPOSE 80
|
||||
EXPOSE 8080
|
||||
|
||||
@@ -193,14 +193,6 @@ It is set to '$APACHE_IP_BINDING'."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -n "$APACHE_ADDITIONAL_NETWORK" ]; then
|
||||
if ! echo "$APACHE_ADDITIONAL_NETWORK" | grep -q "^[a-zA-Z0-9_-]\+$"; then
|
||||
print_red "You've set APACHE_ADDITIONAL_NETWORK but not to an allowed value.
|
||||
It needs to be a string with letters, numbers, hyphens and underscores.
|
||||
It is set to '$APACHE_ADDITIONAL_NETWORK'."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -n "$TALK_PORT" ]; then
|
||||
if ! check_if_number "$TALK_PORT"; then
|
||||
print_red "You provided an Talk port but did not only use numbers.
|
||||
|
||||
@@ -9,16 +9,16 @@ loglevel=error
|
||||
user=root
|
||||
|
||||
[program:php-fpm]
|
||||
# Stdout logging is disabled as otherwise the logs are spammed
|
||||
stdout_logfile=NONE
|
||||
# stdout_logfile=/dev/stdout
|
||||
# stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
command=php-fpm
|
||||
user=root
|
||||
|
||||
[program:apache]
|
||||
# Stdout logging is disabled as otherwise the logs are spammed
|
||||
stdout_logfile=NONE
|
||||
# stdout_logfile=/dev/stdout
|
||||
# stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
command=httpd -DFOREGROUND
|
||||
@@ -58,7 +58,9 @@ user=root
|
||||
|
||||
[program:domain-validator]
|
||||
# Logging is disabled as otherwise all attempts will be logged which spams the logs
|
||||
stdout_logfile=NONE
|
||||
stderr_logfile=NONE
|
||||
# stdout_logfile=/dev/stdout
|
||||
# stdout_logfile_maxbytes=0
|
||||
# stderr_logfile=/dev/stderr
|
||||
# stderr_logfile_maxbytes=0
|
||||
command=php -S 127.0.0.1:9876 /var/www/docker-aio/php/domain-validator.php
|
||||
user=www-data
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM php:8.3.13-fpm-alpine3.20
|
||||
FROM php:8.2.23-fpm-alpine3.20
|
||||
|
||||
ENV PHP_MEMORY_LIMIT=512M
|
||||
ENV PHP_UPLOAD_LIMIT=10G
|
||||
@@ -8,14 +8,11 @@ ENV SOURCE_LOCATION=/usr/src/nextcloud
|
||||
ENV REDIS_DB_INDEX=0
|
||||
|
||||
# AIO settings start # Do not remove or change this line!
|
||||
ENV NEXTCLOUD_VERSION=30.0.2
|
||||
ENV NEXTCLOUD_VERSION=29.0.7
|
||||
ENV AIO_TOKEN=123456
|
||||
ENV AIO_URL=localhost
|
||||
# AIO settings end # Do not remove or change this line!
|
||||
|
||||
# Define the commit hash for imagick as a variable
|
||||
ARG IMAGICK_COMMIT_HASH=28f27044e435a2b203e32675e942eb8de620ee58
|
||||
|
||||
COPY --chmod=775 *.sh /
|
||||
COPY --chmod=774 upgrade.exclude /upgrade.exclude
|
||||
COPY config/*.php /
|
||||
@@ -81,24 +78,13 @@ RUN set -ex; \
|
||||
; \
|
||||
\
|
||||
# pecl will claim success even if one install fails, so we need to perform each install separately
|
||||
pecl install -o igbinary-3.2.16; \
|
||||
pecl install igbinary-3.2.16; \
|
||||
pecl install APCu-5.1.24; \
|
||||
pecl install -D 'enable-memcached-igbinary="yes"' memcached-3.3.0; \
|
||||
pecl install -oD 'enable-redis-igbinary="yes" enable-redis-zstd="yes" enable-redis-lz4="yes"' redis-6.1.0; \
|
||||
# pecl install -o imagick-3.7.0; \
|
||||
# Begin workaround ->
|
||||
# The master version on the imagick repository is compatible with PHP 8.3. However, the PECL version is not updated yet.
|
||||
# As soon as it will get updated, we can switch back to the PECL version, instead of having this workaround.
|
||||
apk add --no-cache --virtual .git-build-deps git \
|
||||
&& git clone https://github.com/imagick/imagick.git --depth 1 /tmp/imagick \
|
||||
&& cd /tmp/imagick \
|
||||
&& git fetch --depth 1 origin ${IMAGICK_COMMIT_HASH} \
|
||||
&& git checkout ${IMAGICK_COMMIT_HASH} \
|
||||
&& sed -i "s/@PACKAGE_VERSION@/git-${IMAGICK_COMMIT_HASH:0:7}/" php_imagick.h \
|
||||
&& phpize && ./configure && make && make install; \
|
||||
apk del .git-build-deps; \
|
||||
cd && rm -r /tmp/imagick; \
|
||||
# <- End workaround
|
||||
pecl install memcached-3.2.0 \
|
||||
--configureoptions 'enable-memcached-igbinary="yes"'; \
|
||||
pecl install redis-6.0.2 \
|
||||
--configureoptions 'enable-redis-igbinary="yes" enable-redis-zstd="yes" enable-redis-lz4="yes"'; \
|
||||
pecl install imagick-3.7.0; \
|
||||
\
|
||||
docker-php-ext-enable \
|
||||
igbinary \
|
||||
@@ -150,7 +136,6 @@ RUN set -ex; \
|
||||
echo 'redis.session.locking_enabled = 1'; \
|
||||
echo 'redis.session.lock_retries = -1'; \
|
||||
echo 'redis.session.lock_wait_time = 10000'; \
|
||||
echo 'session.gc_maxlifetime = 86400'; \
|
||||
} > /usr/local/etc/php/conf.d/redis-session.ini; \
|
||||
\
|
||||
mkdir -p /var/www/data; \
|
||||
@@ -238,7 +223,6 @@ RUN set -ex; \
|
||||
sudo \
|
||||
grep \
|
||||
nodejs \
|
||||
libreoffice \
|
||||
bind-tools \
|
||||
imagemagick \
|
||||
imagemagick-svg \
|
||||
@@ -272,7 +256,10 @@ RUN set -ex; \
|
||||
\
|
||||
mkdir -p /nc-updater; \
|
||||
chown -R www-data:www-data /nc-updater; \
|
||||
chmod -R 770 /nc-updater
|
||||
chmod -R 770 /nc-updater; \
|
||||
\
|
||||
# Give root a random password
|
||||
echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||
|
||||
# hadolint ignore=DL3002
|
||||
USER root
|
||||
|
||||
@@ -20,11 +20,6 @@ run_upgrade_if_needed_due_to_app_update() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Adjust DATABASE_TYPE to by Nextcloud supported value
|
||||
if [ "$DATABASE_TYPE" = postgres ]; then
|
||||
export DATABASE_TYPE=pgsql
|
||||
fi
|
||||
|
||||
# Only start container if redis is accessible
|
||||
# shellcheck disable=SC2153
|
||||
while ! nc -z "$REDIS_HOST" "6379"; do
|
||||
@@ -242,12 +237,12 @@ if ! [ -f "$NEXTCLOUD_DATA_DIR/skip.update" ]; then
|
||||
);
|
||||
DATADIR_PERMISSION_CONF
|
||||
|
||||
echo "Installing with $DATABASE_TYPE database"
|
||||
echo "Installing with PostgreSQL database"
|
||||
# Set a default value for POSTGRES_PORT
|
||||
if [ -z "$POSTGRES_PORT" ]; then
|
||||
POSTGRES_PORT=5432
|
||||
fi
|
||||
INSTALL_OPTIONS+=(--database "$DATABASE_TYPE" --database-name "$POSTGRES_DB" --database-user "$POSTGRES_USER" --database-pass "$POSTGRES_PASSWORD" --database-host "$POSTGRES_HOST" --database-port "$POSTGRES_PORT")
|
||||
INSTALL_OPTIONS+=(--database pgsql --database-name "$POSTGRES_DB" --database-user "$POSTGRES_USER" --database-pass "$POSTGRES_PASSWORD" --database-host "$POSTGRES_HOST" --database-port "$POSTGRES_PORT")
|
||||
|
||||
echo "Starting Nextcloud installation..."
|
||||
if ! php /var/www/html/occ maintenance:install "${INSTALL_OPTIONS[@]}"; then
|
||||
@@ -495,12 +490,6 @@ if [ -f "$NEXTCLOUD_DATA_DIR/fingerprint.update" ]; then
|
||||
rm "$NEXTCLOUD_DATA_DIR/fingerprint.update"
|
||||
fi
|
||||
|
||||
# Perform preview scan if previews were excluded from restore
|
||||
if [ -f "$NEXTCLOUD_DATA_DIR/trigger-preview.scan" ]; then
|
||||
php /var/www/html/occ files:scan-app-data preview -vvv
|
||||
rm "$NEXTCLOUD_DATA_DIR/trigger-preview.scan"
|
||||
fi
|
||||
|
||||
# AIO one-click settings start # Do not remove or change this line!
|
||||
# Apply one-click-instance settings
|
||||
echo "Applying one-click-instance settings..."
|
||||
@@ -542,7 +531,6 @@ php /var/www/html/occ config:system:set allow_local_remote_servers --type=bool -
|
||||
php /var/www/html/occ config:system:set davstorage.request_timeout --value="$PHP_MAX_TIME" --type=int
|
||||
php /var/www/html/occ config:system:set trusted_domains 1 --value="$NC_DOMAIN"
|
||||
php /var/www/html/occ config:system:set overwrite.cli.url --value="https://$NC_DOMAIN/"
|
||||
php /var/www/html/occ config:system:set documentation_url.server_logs --value="https://github.com/nextcloud/all-in-one/discussions/5425"
|
||||
php /var/www/html/occ config:system:set htaccess.RewriteBase --value="/"
|
||||
php /var/www/html/occ maintenance:update:htaccess
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ mapfile -t NC_USERS <<< "$NC_USERS"
|
||||
for user in "${NC_USERS[@]}"
|
||||
do
|
||||
echo "Posting '$SUBJECT' to: $user"
|
||||
"${COMMAND[@]}" notification:generate "$user" "$NC_DOMAIN: $SUBJECT" -l "$MESSAGE" --object-type='update' --object-id="$SUBJECT"
|
||||
"${COMMAND[@]}" notification:generate "$user" "$NC_DOMAIN: $SUBJECT" -l "$MESSAGE"
|
||||
done
|
||||
|
||||
echo "Done!"
|
||||
|
||||
@@ -28,7 +28,7 @@ done
|
||||
for admin in "${NC_ADMIN_USER[@]}"
|
||||
do
|
||||
echo "Posting '$SUBJECT' to: $admin"
|
||||
"${COMMAND[@]}" notification:generate "$admin" "$NC_DOMAIN: $SUBJECT" -l "$MESSAGE" --object-type='update' --object-id="$SUBJECT"
|
||||
"${COMMAND[@]}" notification:generate "$admin" "$NC_DOMAIN: $SUBJECT" -l "$MESSAGE"
|
||||
done
|
||||
|
||||
echo "Done!"
|
||||
|
||||
@@ -17,11 +17,6 @@ done
|
||||
POSTGRES_USER="oc_$POSTGRES_USER"
|
||||
export POSTGRES_USER
|
||||
|
||||
# Check that db type is not empty
|
||||
if [ -z "$DATABASE_TYPE" ]; then
|
||||
export DATABASE_TYPE=postgres
|
||||
fi
|
||||
|
||||
# Fix false database connection on old instances
|
||||
if [ -f "/var/www/html/config/config.php" ]; then
|
||||
sleep 2
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z "$NEXTCLOUD_HOST" ]; then
|
||||
echo "NEXTCLOUD_HOST needs to be provided. Exiting!"
|
||||
echo "NEXTCLOUD_HOST need to be provided. Exiting!"
|
||||
exit 1
|
||||
elif [ -z "$POSTGRES_HOST" ]; then
|
||||
echo "POSTGRES_HOST needs to be provided. Exiting!"
|
||||
echo "POSTGRES_HOST need to be provided. Exiting!"
|
||||
exit 1
|
||||
elif [ -z "$REDIS_HOST" ]; then
|
||||
echo "REDIS_HOST needs to be provided. Exiting!"
|
||||
echo "REDIS_HOST need to be provided. Exiting!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -52,16 +52,9 @@ fi
|
||||
if [ -z "$REDIS_DB_INDEX" ]; then
|
||||
REDIS_DB_INDEX=0
|
||||
fi
|
||||
# Set a default for db type
|
||||
if [ -z "$DATABASE_TYPE" ]; then
|
||||
DATABASE_TYPE=postgres
|
||||
elif [ "$DATABASE_TYPE" != postgres ] && [ "$DATABASE_TYPE" != mysql ]; then
|
||||
echo "DB type must be either postgres or mysql"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set sensitive values as env
|
||||
export DATABASE_URL="$DATABASE_TYPE://oc_$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB"
|
||||
export DATABASE_URL="postgres://oc_$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB"
|
||||
export REDIS_URL="redis://:$REDIS_HOST_PASSWORD@$REDIS_HOST/$REDIS_DB_INDEX"
|
||||
|
||||
# Run it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# From https://github.com/ONLYOFFICE/Docker-DocumentServer/blob/master/Dockerfile
|
||||
FROM onlyoffice/documentserver:8.2.0.1
|
||||
FROM onlyoffice/documentserver:8.1.3.2
|
||||
|
||||
# USER root is probably used
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ RUN set -ex; \
|
||||
|
||||
VOLUME /mnt/data
|
||||
|
||||
USER 999
|
||||
USER postgres
|
||||
ENTRYPOINT ["/start.sh"]
|
||||
|
||||
HEALTHCHECK CMD /healthcheck.sh
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# From https://github.com/docker-library/redis/blob/master/7.2/alpine/Dockerfile
|
||||
FROM redis:7.2.6-alpine
|
||||
FROM redis:7.2.5-alpine
|
||||
|
||||
COPY --chmod=775 start.sh /start.sh
|
||||
|
||||
@@ -14,7 +14,7 @@ RUN set -ex; \
|
||||
# Get rid of unused binaries
|
||||
rm -f /usr/local/bin/gosu;
|
||||
|
||||
USER 999
|
||||
USER redis
|
||||
ENTRYPOINT ["/start.sh"]
|
||||
|
||||
HEALTHCHECK CMD redis-cli -a $REDIS_HOST_PASSWORD PING || exit 1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM python:3.13.0-alpine3.20
|
||||
FROM python:3.12.6-alpine3.20
|
||||
|
||||
COPY --chmod=775 start.sh /start.sh
|
||||
|
||||
@@ -28,7 +28,7 @@ RUN set -ex; \
|
||||
build-base \
|
||||
linux-headers \
|
||||
geckodriver; \
|
||||
useradd -d /tmp --system recording -u 122; \
|
||||
useradd -d /tmp --system recording; \
|
||||
# Give root a random password
|
||||
echo "root:$(openssl rand -base64 12)" | chpasswd; \
|
||||
git clone --recursive https://github.com/nextcloud/nextcloud-talk-recording --depth=1 --single-branch --branch "$RECORDING_VERSION" /src; \
|
||||
@@ -48,9 +48,8 @@ RUN set -ex; \
|
||||
build-base \
|
||||
linux-headers;
|
||||
|
||||
VOLUME /tmp
|
||||
WORKDIR /tmp
|
||||
USER 122
|
||||
USER recording
|
||||
ENTRYPOINT ["/start.sh"]
|
||||
CMD ["python", "-m", "nextcloud.talk.recording", "--config", "/conf/recording.conf"]
|
||||
|
||||
|
||||
@@ -16,9 +16,6 @@ if [ -z "$HPB_DOMAIN" ]; then
|
||||
export HPB_DOMAIN="$NC_DOMAIN"
|
||||
fi
|
||||
|
||||
# Delete all contents on startup to start fresh
|
||||
rm -fr /tmp/{*,.*}
|
||||
|
||||
cat << RECORDING_CONF > "/conf/recording.conf"
|
||||
[logs]
|
||||
# 30 means Warning
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM nats:2.10.22-scratch AS nats
|
||||
FROM eturnal/eturnal:1.12.1 AS eturnal
|
||||
FROM strukturag/nextcloud-spreed-signaling:2.0.1 AS signaling
|
||||
FROM nats:2.10.20-scratch AS nats
|
||||
FROM eturnal/eturnal:1.12.0 AS eturnal
|
||||
FROM strukturag/nextcloud-spreed-signaling:2.0.0 AS signaling
|
||||
FROM alpine:3.20.3 AS janus
|
||||
|
||||
ARG JANUS_VERSION=v0.14.4
|
||||
@@ -99,7 +99,7 @@ RUN set -ex; \
|
||||
ln -s /opt/eturnal/bin/stun /usr/local/bin/stun; \
|
||||
ln -s /opt/eturnal/bin/eturnalctl /usr/local/bin/eturnalctl
|
||||
|
||||
USER 1000
|
||||
USER eturnal
|
||||
ENTRYPOINT ["/start.sh"]
|
||||
CMD ["supervisord", "-c", "/supervisord.conf"]
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM ghcr.io/nextcloud-releases/whiteboard:v1.0.4
|
||||
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 65534
|
||||
USER nobody
|
||||
|
||||
COPY --chmod=775 start.sh /start.sh
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<name>Nextcloud All-in-One</name>
|
||||
<summary>Provides a login link for admins.</summary>
|
||||
<description>Add a link to the admin settings that gives access to the Nextcloud All-in-One admin interface</description>
|
||||
<version>0.7.0</version>
|
||||
<version>0.6.0</version>
|
||||
<licence>agpl</licence>
|
||||
<author>Azul</author>
|
||||
<namespace>AllInOne</namespace>
|
||||
@@ -13,7 +13,7 @@
|
||||
<category>monitoring</category>
|
||||
<bugs>https://github.com/nextcloud/all-in-one/issues</bugs>
|
||||
<dependencies>
|
||||
<nextcloud min-version="29" max-version="30"/>
|
||||
<nextcloud min-version="28" max-version="29"/>
|
||||
</dependencies>
|
||||
|
||||
<settings>
|
||||
|
||||
@@ -19,7 +19,6 @@ This container bundles Local AI and auto-configures it for you.
|
||||
name: gpt4all-j
|
||||
```
|
||||
- To make it work, you first need to browse `https://your-nc-domain.com/settings/admin/ai` and enable or disable specific features for your models in the openAI settings. Afterwards using the Nextcloud Assistant should work.
|
||||
- See [this guide](https://github.com/nextcloud/all-in-one/discussions/5430) for how to improve AI task pickup speed
|
||||
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
|
||||
|
||||
### Repository
|
||||
|
||||
@@ -17,11 +17,6 @@
|
||||
"source": "%NEXTCLOUD_DATADIR%",
|
||||
"destination": "/mnt/ncdata",
|
||||
"writeable": false
|
||||
},
|
||||
{
|
||||
"source": "%NEXTCLOUD_MOUNT%",
|
||||
"destination": "%NEXTCLOUD_MOUNT%",
|
||||
"writeable": false
|
||||
}
|
||||
],
|
||||
"devices": [
|
||||
|
||||
@@ -7,7 +7,7 @@ This container contains a fork of the Nginx Proxy Manager, which is a WebUI for
|
||||
- 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.
|
||||
- After the container was started the first time, please check the logs for errors. Then you can open NPMplus on `https://<ip>:81` and change the password.
|
||||
- The default password is `iArhP1j7p1P6TA92FA2FMbbUGYqwcYzxC4AVEe12Wbi94FY9gNN62aKyF1shrvG4NycjjX9KfmDQiwkLZH1ZDR9xMjiG2QmoHXi` and the default email is `admin@example.org`
|
||||
- The default password is `iArhP1j7p1P6TA92FA2FMbbUGYqwcYzxC4AVEe12Wbi94FY9gNN62aKyF1shrvG4NycjjX9KfmDQiwkLZH1ZDR9xMjiG2QmoHXi` and the default email is `admin@example.com`
|
||||
- If you want to use NPMplus behind a domain and outside localhost just create a new proxy host inside the NPMplus which proxies to `https`, `127.0.0.1` and port `81` - all other settings should be the same as for the AIO host.
|
||||
- If you want to set env options from this [compose.yaml](https://github.com/ZoeyVid/NPMplus/blob/develop/compose.yaml), please set them inside the `.env` file which you can find in the `nextcloud_aio_npmplus` volume
|
||||
- The data (certs, configs, etc.) of NPMplus will be automatically included in AIOs backup solution!
|
||||
|
||||
45
compose.yaml
45
compose.yaml
@@ -14,10 +14,8 @@ services:
|
||||
- 8443:8443 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
# environment: # Is needed when using any of the options below
|
||||
# AIO_DISABLE_BACKUP_SECTION: false # Setting this to true allows to hide the backup section in the AIO interface. See https://github.com/nextcloud/all-in-one#how-to-disable-the-backup-section
|
||||
# AIO_COMMUNITY_CONTAINERS: # With this variable, you can add community containers very easily. See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers
|
||||
# APACHE_PORT: 11000 # Is needed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
# APACHE_IP_BINDING: 127.0.0.1 # Should be set when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) that is running on the same host. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
# APACHE_ADDITIONAL_NETWORK: frontend_net # (Optional) Connect the apache container to an additional docker network. Needed when behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) running in a different docker network on same server. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
# BORG_RETENTION_POLICY: --keep-within=7d --keep-weekly=4 --keep-monthly=6 # Allows to adjust borgs retention policy. See https://github.com/nextcloud/all-in-one#how-to-adjust-borgs-retention-policy
|
||||
# COLLABORA_SECCOMP_DISABLED: false # Setting this to true allows to disable Collabora's Seccomp feature. See https://github.com/nextcloud/all-in-one#how-to-disable-collaboras-seccomp-feature
|
||||
# NEXTCLOUD_DATADIR: /mnt/ncdata # Allows to set the host directory for Nextcloud's datadir. ⚠️⚠️⚠️ Warning: do not set or adjust this value after the initial Nextcloud installation is done! See https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir
|
||||
@@ -31,39 +29,26 @@ services:
|
||||
# NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS: imagick # This allows to add additional php extensions to the Nextcloud container permanently. Default is imagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-php-extensions-permanently-to-the-nextcloud-container
|
||||
# NEXTCLOUD_ENABLE_DRI_DEVICE: true # This allows to enable the /dev/dri device in the Nextcloud container. ⚠️⚠️⚠️ Warning: this only works if the '/dev/dri' device is present on the host! If it should not exist on your host, don't set this to true as otherwise the Nextcloud container will fail to start! See https://github.com/nextcloud/all-in-one#how-to-enable-hardware-transcoding-for-nextcloud
|
||||
# NEXTCLOUD_KEEP_DISABLED_APPS: false # Setting this to true will keep Nextcloud apps that are disabled in the AIO interface and not uninstall them if they should be installed. See https://github.com/nextcloud/all-in-one#how-to-keep-disabled-apps
|
||||
# SKIP_DOMAIN_VALIDATION: false # This should only be set to true if things are correctly configured. See https://github.com/nextcloud/all-in-one?tab=readme-ov-file#how-to-skip-the-domain-validation
|
||||
# DISABLE_OVERWRITE_URL: true # Setting this to true will disable the ability to overwrite the URL in the AIO interface. See https://github.com/nextcloud/all-in-one#can-i-use-aio-with-multiple-domains
|
||||
# TALK_PORT: 3478 # This allows to adjust the port that the talk container is using. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-talk-port
|
||||
# WATCHTOWER_DOCKER_SOCKET_PATH: /var/run/docker.sock # Needs to be specified if the docker socket on the host is not located in the default '/var/run/docker.sock'. Otherwise mastercontainer updates will fail. For macos it needs to be '/var/run/docker.sock'
|
||||
# security_opt: ["label:disable"] # Is needed when using SELinux
|
||||
|
||||
# # Optional: Caddy reverse proxy. See https://github.com/nextcloud/all-in-one/discussions/575
|
||||
# # Hint: You need to uncomment APACHE_PORT: 11000 above, adjust cloud.example.com to your domain and uncomment the necessary docker volumes at the bottom of this file in order to make it work
|
||||
# # You can find further examples here: https://github.com/nextcloud/all-in-one/discussions/588
|
||||
# caddy:
|
||||
# image: caddy:alpine
|
||||
# restart: always
|
||||
# container_name: caddy
|
||||
# volumes:
|
||||
# - caddy_certs:/certs
|
||||
# - caddy_config:/config
|
||||
# - caddy_data:/data
|
||||
# - caddy_sites:/srv
|
||||
# network_mode: "host"
|
||||
# configs:
|
||||
# - source: Caddyfile
|
||||
# target: /etc/caddy/Caddyfile
|
||||
# configs:
|
||||
# Caddyfile:
|
||||
# content: |
|
||||
# # Adjust cloud.example.com to your domain below
|
||||
# https://cloud.example.com:443 {
|
||||
# reverse_proxy localhost:11000
|
||||
# }
|
||||
# # Optional: Caddy reverse proxy. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
# # You can find further examples here: https://github.com/nextcloud/all-in-one/discussions/588
|
||||
# caddy:
|
||||
# image: caddy:alpine
|
||||
# restart: always
|
||||
# container_name: caddy
|
||||
# volumes:
|
||||
# - ./Caddyfile:/etc/caddy/Caddyfile
|
||||
# - ./certs:/certs
|
||||
# - ./config:/config
|
||||
# - ./data:/data
|
||||
# - ./sites:/srv
|
||||
# network_mode: "host"
|
||||
|
||||
volumes: # If you want to store the data on a different drive, see https://github.com/nextcloud/all-in-one#how-to-store-the-filesinstallation-on-a-separate-drive
|
||||
nextcloud_aio_mastercontainer:
|
||||
name: nextcloud_aio_mastercontainer # This line is not allowed to be changed as otherwise the built-in backup solution will not work
|
||||
# caddy_certs:
|
||||
# caddy_config:
|
||||
# caddy_data:
|
||||
# caddy_sites:
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ You can run AIO with docker rootless by following the steps below.
|
||||
Almost all commands in this project's documentation use `sudo docker ...`. Since `sudo` is not needed in case of docker rootless, you simply remove `sudo` from the commands and they should work.
|
||||
|
||||
### Note regarding permissions
|
||||
All files outside the containers get created, written to and accessed as the user that is running the docker daemon or a subuid of it. So for the built-in backup to work you need to allow this user to write to the target directory. E.g. with `sudo chown -R USERNAME:GROUPNAME /mnt/backup`. The same applies when changing Nextcloud's datadir via NEXTCLOUD_DATADIR. E.g. `sudo chown -R USERNAME:GROUPNAME /mnt/ncdata`. When you want to use the NEXTCLOUD_MOUNT option for local external storage, you need to adjust the permissions of the chosen folders to be accessible/writeable by the userid `100032:100032` (if running `grep ^$(whoami): /etc/subuid` as the user that is running the docker daemon returns 100000 as first value).
|
||||
|
||||
All files outside the containers get created, written to and accessed as the user that is running the docker daemon or a subuid of it. So for the built-in backup to work you need to allow this user to write to the target directory. E.g. with `sudo chown -R USERNAME:GROUPNAME /mnt/backup`. The same applies when changing Nextcloud's datadir. E.g. `sudo chown -R USERNAME:GROUPNAME /mnt/ncdata`. When you want to use the NEXTCLOUD_MOUNT option for local external storage, you need to adjust the permissions of the chosen folders to be accessible/writeable by the userid `100032:100032` (if running `grep ^$(whoami): /etc/subuid` as the user that is running the docker daemon returns 100000 as first value).
|
||||
|
||||
### Note regarding docker network driver
|
||||
By default rootless docker uses the `slirp4netns` IP driver and the `builtin` port driver. As mentioned in [the documentation](https://docs.docker.com/engine/security/rootless/#networking-errors), this combination doesn't provide "Source IP propagation". This means that Apache and Nextcloud will see all connections as coming from the docker gateway (e.g 172.19.0.1), which can lead to the Nextcloud brute force protection blocking all connection attempts. To expose the correct source IP, you will need to configure docker to also use `slirp4netns` as the port driver (see also [this guide](https://rootlesscontaine.rs/getting-started/docker/#changing-the-port-forwarder)).
|
||||
@@ -30,10 +29,9 @@ As stated in the documentation, this change will likely lead to decreased networ
|
||||
with the following content:
|
||||
```
|
||||
[Service]
|
||||
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns"
|
||||
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns"
|
||||
```
|
||||
* Restart the docker daemon
|
||||
```
|
||||
systemctl --user restart docker
|
||||
```
|
||||
```
|
||||
@@ -1,12 +1,5 @@
|
||||
# Local instance
|
||||
It is possible due to several reasons that you do not want or cannot open Nextcloud to the public internet. Perhaps you were hoping to access AIO directly from an `ip.add.r.ess` (unsupported) or without a valid domain. However, AIO requires a valid certificate to work correctly. Below is discussed how you can achieve both: Having a valid certificate for Nextcloud and only using it locally.
|
||||
|
||||
### Content
|
||||
- [1. The recommended way](#1-the-recommended-way)
|
||||
- [2. Use the ACME DNS-challenge](#2-use-the-acme-dns-challenge)
|
||||
- [3. Use Cloudflare](#3-use-cloudflare)
|
||||
- [4. Buy a certificate and use that](#4-buy-a-certificate-and-use-that)
|
||||
- [5. Tailscale network](#5-tailscale-network)
|
||||
It is possible due to several reasons that you do not want or cannot open Nextcloud to the public internet. However AIO requires a valid certificate to work correctly. Below is discussed how you can achieve both: Having a valid certificate for Nextcloud and only using it locally.
|
||||
|
||||
## 1. The recommended way
|
||||
The recommended way is the following:
|
||||
@@ -16,8 +9,6 @@ The recommended way is the following:
|
||||
1. Enter the ip-address of your local dns-server in the daemon.json file for docker so that you are sure that all docker containers use the correct local dns-server.
|
||||
1. Now, entering the domain in the AIO-interface should work as expected and should allow you to continue with the setup
|
||||
|
||||
**Hint:** You may have a look at [this video](https://youtu.be/zk-y2wVkY4c) for a more complete but possibly outdated example.
|
||||
|
||||
## 2. Use the ACME DNS-challenge
|
||||
You can alternatively use the ACME DNS-challenge to get a valid certificate for Nextcloud. Here is described how to set it up: https://github.com/nextcloud/all-in-one#how-to-get-nextcloud-running-using-the-acme-dns-challenge
|
||||
|
||||
@@ -26,6 +17,3 @@ If you do not have any control over the network, you may think about using Cloud
|
||||
|
||||
## 4. Buy a certificate and use that
|
||||
If none of the above ways work for you, you may simply buy a certificate from an issuer for your domain. You then download the certificate onto your server, configure AIO in [reverse proxy mode](./reverse-proxy.md) and use the certificate for your domain in your reverse proxy config.
|
||||
|
||||
## 5. Tailscale network
|
||||
For a reverse proxy example guide for Tailscale, see this guide by @flll: https://github.com/nextcloud/all-in-one/discussions/5439
|
||||
|
||||
@@ -20,21 +20,20 @@ services:
|
||||
condition: service_started
|
||||
required: false
|
||||
image: nextcloud/aio-apache:latest
|
||||
user: "33"
|
||||
init: true
|
||||
ports:
|
||||
- ${APACHE_IP_BINDING}:${APACHE_PORT}:${APACHE_PORT}/tcp
|
||||
- ${APACHE_IP_BINDING}:${APACHE_PORT}:${APACHE_PORT}/udp
|
||||
environment:
|
||||
- NC_DOMAIN
|
||||
- NC_DOMAIN=${NC_DOMAIN}
|
||||
- NEXTCLOUD_HOST=nextcloud-aio-nextcloud
|
||||
- APACHE_HOST=nextcloud-aio-apache
|
||||
- COLLABORA_HOST=nextcloud-aio-collabora
|
||||
- TALK_HOST=nextcloud-aio-talk
|
||||
- APACHE_PORT
|
||||
- APACHE_PORT=${APACHE_PORT}
|
||||
- ONLYOFFICE_HOST=nextcloud-aio-onlyoffice
|
||||
- TZ=${TIMEZONE}
|
||||
- APACHE_MAX_SIZE
|
||||
- APACHE_MAX_SIZE=${APACHE_MAX_SIZE}
|
||||
- APACHE_MAX_TIME=${NEXTCLOUD_MAX_TIME}
|
||||
- NOTIFY_PUSH_HOST=nextcloud-aio-notify-push
|
||||
- WHITEBOARD_HOST=nextcloud-aio-whiteboard
|
||||
@@ -42,6 +41,8 @@ services:
|
||||
- nextcloud_aio_nextcloud:/var/www/html:ro
|
||||
- nextcloud_aio_apache:/mnt/data:rw
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /var/log/supervisord
|
||||
@@ -54,7 +55,6 @@ services:
|
||||
|
||||
nextcloud-aio-database:
|
||||
image: nextcloud/aio-postgresql:latest
|
||||
user: "999"
|
||||
init: true
|
||||
expose:
|
||||
- "5432"
|
||||
@@ -70,6 +70,8 @@ services:
|
||||
stop_grace_period: 1800s
|
||||
restart: unless-stopped
|
||||
shm_size: 268435456
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /var/run/postgresql
|
||||
@@ -114,63 +116,64 @@ services:
|
||||
- POSTGRES_USER=nextcloud
|
||||
- REDIS_HOST=nextcloud-aio-redis
|
||||
- REDIS_HOST_PASSWORD=${REDIS_PASSWORD}
|
||||
- NC_DOMAIN
|
||||
- NC_DOMAIN=${NC_DOMAIN}
|
||||
- ADMIN_USER=admin
|
||||
- ADMIN_PASSWORD=${NEXTCLOUD_PASSWORD}
|
||||
- NEXTCLOUD_DATA_DIR=/mnt/ncdata
|
||||
- OVERWRITEHOST=${NC_DOMAIN}
|
||||
- OVERWRITEPROTOCOL=https
|
||||
- TURN_SECRET
|
||||
- SIGNALING_SECRET
|
||||
- ONLYOFFICE_SECRET
|
||||
- NEXTCLOUD_MOUNT
|
||||
- CLAMAV_ENABLED
|
||||
- TURN_SECRET=${TURN_SECRET}
|
||||
- SIGNALING_SECRET=${SIGNALING_SECRET}
|
||||
- ONLYOFFICE_SECRET=${ONLYOFFICE_SECRET}
|
||||
- NEXTCLOUD_MOUNT=${NEXTCLOUD_MOUNT}
|
||||
- CLAMAV_ENABLED=${CLAMAV_ENABLED}
|
||||
- CLAMAV_HOST=nextcloud-aio-clamav
|
||||
- ONLYOFFICE_ENABLED
|
||||
- COLLABORA_ENABLED
|
||||
- ONLYOFFICE_ENABLED=${ONLYOFFICE_ENABLED}
|
||||
- COLLABORA_ENABLED=${COLLABORA_ENABLED}
|
||||
- COLLABORA_HOST=nextcloud-aio-collabora
|
||||
- TALK_ENABLED
|
||||
- TALK_ENABLED=${TALK_ENABLED}
|
||||
- ONLYOFFICE_HOST=nextcloud-aio-onlyoffice
|
||||
- UPDATE_NEXTCLOUD_APPS
|
||||
- UPDATE_NEXTCLOUD_APPS=${UPDATE_NEXTCLOUD_APPS}
|
||||
- TZ=${TIMEZONE}
|
||||
- TALK_PORT
|
||||
- IMAGINARY_ENABLED
|
||||
- TALK_PORT=${TALK_PORT}
|
||||
- IMAGINARY_ENABLED=${IMAGINARY_ENABLED}
|
||||
- IMAGINARY_HOST=nextcloud-aio-imaginary
|
||||
- CLAMAV_MAX_SIZE=${APACHE_MAX_SIZE}
|
||||
- PHP_UPLOAD_LIMIT=${NEXTCLOUD_UPLOAD_LIMIT}
|
||||
- PHP_MEMORY_LIMIT=${NEXTCLOUD_MEMORY_LIMIT}
|
||||
- FULLTEXTSEARCH_ENABLED
|
||||
- FULLTEXTSEARCH_ENABLED=${FULLTEXTSEARCH_ENABLED}
|
||||
- FULLTEXTSEARCH_HOST=nextcloud-aio-fulltextsearch
|
||||
- PHP_MAX_TIME=${NEXTCLOUD_MAX_TIME}
|
||||
- TRUSTED_CACERTS_DIR=${NEXTCLOUD_TRUSTED_CACERTS_DIR}
|
||||
- STARTUP_APPS=${NEXTCLOUD_STARTUP_APPS}
|
||||
- ADDITIONAL_APKS=${NEXTCLOUD_ADDITIONAL_APKS}
|
||||
- ADDITIONAL_PHP_EXTENSIONS=${NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS}
|
||||
- INSTALL_LATEST_MAJOR
|
||||
- TALK_RECORDING_ENABLED
|
||||
- RECORDING_SECRET
|
||||
- INSTALL_LATEST_MAJOR=${INSTALL_LATEST_MAJOR}
|
||||
- TALK_RECORDING_ENABLED=${TALK_RECORDING_ENABLED}
|
||||
- RECORDING_SECRET=${RECORDING_SECRET}
|
||||
- TALK_RECORDING_HOST=nextcloud-aio-talk-recording
|
||||
- FULLTEXTSEARCH_PASSWORD
|
||||
- REMOVE_DISABLED_APPS
|
||||
- APACHE_PORT
|
||||
- IMAGINARY_SECRET
|
||||
- WHITEBOARD_SECRET
|
||||
- WHITEBOARD_ENABLED
|
||||
- FULLTEXTSEARCH_PASSWORD=${FULLTEXTSEARCH_PASSWORD}
|
||||
- REMOVE_DISABLED_APPS=${REMOVE_DISABLED_APPS}
|
||||
- APACHE_PORT=${APACHE_PORT}
|
||||
- IMAGINARY_SECRET=${IMAGINARY_SECRET}
|
||||
- WHITEBOARD_SECRET=${WHITEBOARD_SECRET}
|
||||
- WHITEBOARD_ENABLED=${WHITEBOARD_ENABLED}
|
||||
stop_grace_period: 600s
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
cap_drop:
|
||||
- NET_RAW
|
||||
|
||||
nextcloud-aio-notify-push:
|
||||
image: nextcloud/aio-notify-push:latest
|
||||
user: "33"
|
||||
init: true
|
||||
expose:
|
||||
- "7867"
|
||||
volumes:
|
||||
- nextcloud_aio_nextcloud:/nextcloud:ro
|
||||
environment:
|
||||
- NC_DOMAIN
|
||||
- NC_DOMAIN=${NC_DOMAIN}
|
||||
- NEXTCLOUD_HOST=nextcloud-aio-nextcloud
|
||||
- REDIS_HOST=nextcloud-aio-redis
|
||||
- REDIS_HOST_PASSWORD=${REDIS_PASSWORD}
|
||||
@@ -180,13 +183,14 @@ services:
|
||||
- POSTGRES_DB=nextcloud_database
|
||||
- POSTGRES_USER=nextcloud
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
read_only: true
|
||||
cap_drop:
|
||||
- NET_RAW
|
||||
|
||||
nextcloud-aio-redis:
|
||||
image: nextcloud/aio-redis:latest
|
||||
user: "999"
|
||||
init: true
|
||||
expose:
|
||||
- "6379"
|
||||
@@ -196,13 +200,14 @@ services:
|
||||
volumes:
|
||||
- nextcloud_aio_redis:/data:rw
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
read_only: true
|
||||
cap_drop:
|
||||
- NET_RAW
|
||||
|
||||
nextcloud-aio-collabora:
|
||||
image: nextcloud/aio-collabora:latest
|
||||
user: "100"
|
||||
init: true
|
||||
expose:
|
||||
- "9980"
|
||||
@@ -216,6 +221,8 @@ services:
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- collabora
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
cap_add:
|
||||
- MKNOD
|
||||
- SYS_ADMIN
|
||||
@@ -224,7 +231,6 @@ services:
|
||||
|
||||
nextcloud-aio-talk:
|
||||
image: nextcloud/aio-talk:latest
|
||||
user: "1000"
|
||||
init: true
|
||||
ports:
|
||||
- ${TALK_PORT}:${TALK_PORT}/tcp
|
||||
@@ -232,17 +238,19 @@ services:
|
||||
expose:
|
||||
- "8081"
|
||||
environment:
|
||||
- NC_DOMAIN
|
||||
- NC_DOMAIN=${NC_DOMAIN}
|
||||
- TALK_HOST=nextcloud-aio-talk
|
||||
- TURN_SECRET
|
||||
- SIGNALING_SECRET
|
||||
- TURN_SECRET=${TURN_SECRET}
|
||||
- SIGNALING_SECRET=${SIGNALING_SECRET}
|
||||
- TZ=${TIMEZONE}
|
||||
- TALK_PORT
|
||||
- TALK_PORT=${TALK_PORT}
|
||||
- INTERNAL_SECRET=${TALK_INTERNAL_SECRET}
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- talk
|
||||
- talk-recording
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /var/log/supervisord
|
||||
@@ -255,19 +263,20 @@ services:
|
||||
|
||||
nextcloud-aio-talk-recording:
|
||||
image: nextcloud/aio-talk-recording:latest
|
||||
user: "122"
|
||||
init: true
|
||||
expose:
|
||||
- "1234"
|
||||
environment:
|
||||
- NC_DOMAIN
|
||||
- NC_DOMAIN=${NC_DOMAIN}
|
||||
- TZ=${TIMEZONE}
|
||||
- RECORDING_SECRET
|
||||
- RECORDING_SECRET=${RECORDING_SECRET}
|
||||
- INTERNAL_SECRET=${TALK_INTERNAL_SECRET}
|
||||
shm_size: 2147483648
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- talk-recording
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp
|
||||
@@ -277,7 +286,6 @@ services:
|
||||
|
||||
nextcloud-aio-clamav:
|
||||
image: nextcloud/aio-clamav:latest
|
||||
user: "100"
|
||||
init: false
|
||||
expose:
|
||||
- "3310"
|
||||
@@ -290,6 +298,8 @@ services:
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- clamav
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /var/lock
|
||||
@@ -313,18 +323,19 @@ services:
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- onlyoffice
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
cap_drop:
|
||||
- NET_RAW
|
||||
|
||||
nextcloud-aio-imaginary:
|
||||
image: nextcloud/aio-imaginary:latest
|
||||
user: "65534"
|
||||
init: true
|
||||
expose:
|
||||
- "9000"
|
||||
environment:
|
||||
- TZ=${TIMEZONE}
|
||||
- IMAGINARY_SECRET
|
||||
- IMAGINARY_SECRET=${IMAGINARY_SECRET}
|
||||
restart: unless-stopped
|
||||
cap_add:
|
||||
- SYS_NICE
|
||||
@@ -332,6 +343,8 @@ services:
|
||||
- NET_RAW
|
||||
profiles:
|
||||
- imaginary
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp
|
||||
@@ -351,18 +364,19 @@ services:
|
||||
- http.port=9200
|
||||
- xpack.license.self_generated.type=basic
|
||||
- xpack.security.enabled=false
|
||||
- FULLTEXTSEARCH_PASSWORD
|
||||
- FULLTEXTSEARCH_PASSWORD=${FULLTEXTSEARCH_PASSWORD}
|
||||
volumes:
|
||||
- nextcloud_aio_elasticsearch:/usr/share/elasticsearch/data:rw
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- fulltextsearch
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
cap_drop:
|
||||
- NET_RAW
|
||||
|
||||
nextcloud-aio-whiteboard:
|
||||
image: nextcloud/aio-whiteboard:latest
|
||||
user: "65534"
|
||||
init: true
|
||||
expose:
|
||||
- "3002"
|
||||
@@ -377,6 +391,8 @@ services:
|
||||
profiles:
|
||||
- whiteboard
|
||||
read_only: true
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
cap_drop:
|
||||
- NET_RAW
|
||||
|
||||
@@ -401,5 +417,5 @@ volumes:
|
||||
name: nextcloud_aio_nextcloud_data
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
nextcloud-aio:
|
||||
name: nextcloud-aio
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash -ex
|
||||
#!/bin/bash
|
||||
|
||||
type {jq,sudo} || { echo "Commands not found. Please install them"; exit 127; }
|
||||
set -ex
|
||||
|
||||
jq -c . ./php/containers.json > /tmp/containers.json
|
||||
sed -i 's|aio_services_v1|services|g' /tmp/containers.json
|
||||
@@ -18,8 +18,6 @@ OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[].devices)')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[].backup_volumes)')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[].nextcloud_exec_commands)')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[].image_tag)')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[].networks)')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[].documentation)')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-watchtower"))')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-domaincheck"))')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-borgbackup"))')"
|
||||
@@ -27,7 +25,7 @@ OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "next
|
||||
OUTPUT="$(echo "$OUTPUT" | jq '.services[] |= if has("depends_on") then .depends_on |= if contains(["nextcloud-aio-docker-socket-proxy"]) then del(.[index("nextcloud-aio-docker-socket-proxy")]) else . end else . end')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq '.services[] |= if has("depends_on") then .depends_on |= map({ (.): { "condition": "service_started", "required": false } }) else . end' | jq '.services[] |= if has("depends_on") then .depends_on |= reduce .[] as $item ({}; . + $item) else . end')"
|
||||
|
||||
sudo snap install yq
|
||||
snap install yq
|
||||
mkdir -p ./manual-install
|
||||
echo "$OUTPUT" | yq -P > ./manual-install/containers.yml
|
||||
|
||||
@@ -141,12 +139,13 @@ done
|
||||
cat << NETWORK >> containers.yml
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
nextcloud-aio:
|
||||
name: nextcloud-aio
|
||||
NETWORK
|
||||
|
||||
mv containers.yml latest.yml
|
||||
cat containers.yml > latest.yml
|
||||
sed -i "/image:/s/$/:latest/" latest.yml
|
||||
sed -i 's/\( *- \(\w*\)\)=\${\2\}/\1/' latest.yml
|
||||
|
||||
rm containers.yml
|
||||
|
||||
set +ex
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: nextcloud-aio-helm-chart
|
||||
description: A generated Helm Chart for Nextcloud AIO from Skippbox Kompose
|
||||
version: 9.8.0
|
||||
version: 9.6.0
|
||||
apiVersion: v2
|
||||
keywords:
|
||||
- latest
|
||||
|
||||
@@ -25,7 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -64,7 +64,7 @@ spec:
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
- name: WHITEBOARD_HOST
|
||||
value: nextcloud-aio-whiteboard
|
||||
image: "nextcloud/aio-apache:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-apache:20240925_080419"
|
||||
name: nextcloud-aio-apache
|
||||
ports:
|
||||
- containerPort: {{ .Values.APACHE_PORT }}
|
||||
@@ -72,12 +72,9 @@ spec:
|
||||
- containerPort: {{ .Values.APACHE_PORT }}
|
||||
protocol: UDP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 33
|
||||
volumeMounts:
|
||||
- mountPath: /var/www/html
|
||||
name: nextcloud-aio-nextcloud
|
||||
|
||||
@@ -26,7 +26,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
@@ -36,7 +36,7 @@ spec:
|
||||
- name: nextcloud-aio-clamav
|
||||
mountPath: /nextcloud-aio-clamav
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chown
|
||||
- 100:100
|
||||
@@ -53,18 +53,15 @@ spec:
|
||||
value: "{{ .Values.NEXTCLOUD_UPLOAD_LIMIT }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "nextcloud/aio-clamav:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-clamav:20240925_080419"
|
||||
name: nextcloud-aio-clamav
|
||||
ports:
|
||||
- containerPort: 3310
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 100
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/clamav
|
||||
subPath: data
|
||||
|
||||
@@ -36,19 +36,16 @@ 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: "nextcloud/aio-collabora:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-collabora:20240925_080419"
|
||||
name: nextcloud-aio-collabora
|
||||
ports:
|
||||
- containerPort: 9980
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
add:
|
||||
- MKNOD
|
||||
- SYS_ADMIN
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 100
|
||||
{{- end }}
|
||||
|
||||
@@ -25,7 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
@@ -38,7 +38,7 @@ spec:
|
||||
- name: nextcloud-aio-database
|
||||
mountPath: /nextcloud-aio-database
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chown
|
||||
- 999:999
|
||||
@@ -62,18 +62,15 @@ spec:
|
||||
value: nextcloud
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "nextcloud/aio-postgresql:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-postgresql:20240925_080419"
|
||||
name: nextcloud-aio-database
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 999
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/postgresql/data
|
||||
subPath: data
|
||||
|
||||
@@ -26,7 +26,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -56,14 +56,12 @@ spec:
|
||||
value: basic
|
||||
- name: xpack.security.enabled
|
||||
value: "false"
|
||||
image: "nextcloud/aio-fulltextsearch:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-fulltextsearch:20240925_080419"
|
||||
name: nextcloud-aio-fulltextsearch
|
||||
ports:
|
||||
- containerPort: 9200
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- NET_RAW
|
||||
|
||||
@@ -28,18 +28,15 @@ spec:
|
||||
value: "{{ .Values.IMAGINARY_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "nextcloud/aio-imaginary:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-imaginary:20240925_080419"
|
||||
name: nextcloud-aio-imaginary
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
add:
|
||||
- SYS_NICE
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 65534
|
||||
{{- end }}
|
||||
|
||||
@@ -15,22 +15,6 @@ spec:
|
||||
- from:
|
||||
- podSelector: {}
|
||||
egress:
|
||||
- {} # Allows all egress traffic
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
namespace: "{{ .Values.NAMESPACE }}"
|
||||
name: nextcloud-aio-webserver-allow
|
||||
spec:
|
||||
podSelector:
|
||||
matchExpressions:
|
||||
- key: io.kompose.service
|
||||
operator: In
|
||||
values:
|
||||
- nextcloud-aio-apache
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- {} # Allows all ingress traffic
|
||||
- to:
|
||||
- podSelector: {}
|
||||
{{- end }}
|
||||
|
||||
@@ -25,7 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: "delete-lost-found"
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- rm
|
||||
- "-rf"
|
||||
@@ -36,7 +36,7 @@ spec:
|
||||
- name: nextcloud-aio-nextcloud
|
||||
mountPath: /nextcloud-aio-nextcloud
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -173,7 +173,7 @@ spec:
|
||||
value: "{{ .Values.WHITEBOARD_ENABLED }}"
|
||||
- name: WHITEBOARD_SECRET
|
||||
value: "{{ .Values.WHITEBOARD_SECRET }}"
|
||||
image: "nextcloud/aio-nextcloud:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-nextcloud:20240925_080419"
|
||||
name: nextcloud-aio-nextcloud
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
|
||||
@@ -25,7 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -53,18 +53,15 @@ spec:
|
||||
value: nextcloud-aio-redis
|
||||
- name: REDIS_HOST_PASSWORD
|
||||
value: "{{ .Values.REDIS_PASSWORD }}"
|
||||
image: "nextcloud/aio-notify-push:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-notify-push:20240925_080419"
|
||||
name: nextcloud-aio-notify-push
|
||||
ports:
|
||||
- containerPort: 7867
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 33
|
||||
volumeMounts:
|
||||
- mountPath: /nextcloud
|
||||
name: nextcloud-aio-nextcloud
|
||||
|
||||
@@ -26,7 +26,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -44,7 +44,7 @@ spec:
|
||||
value: "{{ .Values.ONLYOFFICE_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "nextcloud/aio-onlyoffice:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-onlyoffice:20240925_080419"
|
||||
name: nextcloud-aio-onlyoffice
|
||||
ports:
|
||||
- containerPort: 80
|
||||
|
||||
@@ -25,7 +25,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -39,18 +39,15 @@ spec:
|
||||
value: "{{ .Values.REDIS_PASSWORD }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "nextcloud/aio-redis:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-redis:20240925_080419"
|
||||
name: nextcloud-aio-redis
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 999
|
||||
volumeMounts:
|
||||
- mountPath: /data
|
||||
name: nextcloud-aio-redis
|
||||
|
||||
@@ -42,7 +42,7 @@ spec:
|
||||
value: "{{ .Values.TURN_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "nextcloud/aio-talk:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-talk:20240925_080419"
|
||||
name: nextcloud-aio-talk
|
||||
ports:
|
||||
- containerPort: {{ .Values.TALK_PORT }}
|
||||
@@ -52,10 +52,7 @@ spec:
|
||||
- containerPort: 8081
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 1000
|
||||
{{- end }}
|
||||
|
||||
@@ -32,16 +32,13 @@ spec:
|
||||
value: "{{ .Values.RECORDING_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "nextcloud/aio-talk-recording:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-talk-recording:20240925_080419"
|
||||
name: nextcloud-aio-talk-recording
|
||||
ports:
|
||||
- containerPort: 1234
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 122
|
||||
{{- end }}
|
||||
|
||||
@@ -36,16 +36,13 @@ spec:
|
||||
value: redis
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: "nextcloud/aio-whiteboard:20241106_101604"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/aio-whiteboard:20240925_080419"
|
||||
name: nextcloud-aio-whiteboard
|
||||
ports:
|
||||
- containerPort: 3002
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- NET_RAW
|
||||
runAsUser: 65534
|
||||
{{- end }}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -z "$1" ] && { echo "Error: Docker tag is not specified. Usage: ./nextcloud-aio-helm-chart/update-helm.sh <Docker tag>"; exit 2; }
|
||||
|
||||
DOCKER_TAG="$1"
|
||||
|
||||
# The logic needs the files in ./helm-chart
|
||||
cp -r ./nextcloud-aio-helm-chart ./helm-chart
|
||||
mv ./nextcloud-aio-helm-chart ./helm-chart
|
||||
|
||||
# Clean
|
||||
rm -f ./helm-chart/values.yaml
|
||||
@@ -17,15 +15,13 @@ chmod +x kompose
|
||||
sudo mv ./kompose /usr/local/bin/kompose
|
||||
|
||||
# Install yq
|
||||
sudo snap install yq
|
||||
snap install yq
|
||||
|
||||
set -ex
|
||||
|
||||
# Conversion of docker-compose
|
||||
cd manual-install
|
||||
cp latest.yml latest.yml.backup
|
||||
|
||||
sed -i -E '/^( *- )(NET_RAW|SYS_NICE|MKNOD|SYS_ADMIN)$/!s/( *- )([A-Z_]+)$/\1\2=${\2}/' latest.yml
|
||||
cp sample.conf /tmp/
|
||||
sed -i 's|^|export |' /tmp/sample.conf
|
||||
# shellcheck disable=SC1091
|
||||
@@ -45,7 +41,8 @@ sed -i "/NEXTCLOUD_DATADIR/d" latest.yml
|
||||
sed -i "/\${NEXTCLOUD_MOUNT}/d" latest.yml
|
||||
sed -i "/^volumes:/a\ \ nextcloud_aio_nextcloud_trusted_cacerts:\n \ \ \ \ name: nextcloud_aio_nextcloud_trusted_cacerts" latest.yml
|
||||
sed -i "s|\${NEXTCLOUD_TRUSTED_CACERTS_DIR}:|nextcloud_aio_nextcloud_trusted_cacerts:|g#" latest.yml
|
||||
sed -i 's/\${/{{ .Values./g; s/}/ }}/g' latest.yml
|
||||
sed -i 's|\${|{{ .Values.|g' latest.yml
|
||||
sed -i 's|}| }}|g' latest.yml
|
||||
yq -i 'del(.services.[].profiles)' latest.yml
|
||||
# Delete read_only and tmpfs setting while https://github.com/kubernetes/kubernetes/issues/48912 is not fixed
|
||||
yq -i 'del(.services.[].read_only)' latest.yml
|
||||
@@ -62,7 +59,7 @@ find ./ -name '*networkpolicy.yaml' -exec sed -i "s|manual-install-nextcloud-aio
|
||||
cat << EOL > /tmp/initcontainers
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -71,14 +68,14 @@ EOL
|
||||
cat << EOL > /tmp/initcontainers.database
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
- /nextcloud-aio-database/data
|
||||
volumeMountsInitContainer:
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chown
|
||||
- 999:999
|
||||
@@ -88,14 +85,14 @@ EOL
|
||||
cat << EOL > /tmp/initcontainers.clamav
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
- /nextcloud-aio-clamav/data
|
||||
volumeMountsInitContainer:
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chown
|
||||
- 100:100
|
||||
@@ -105,14 +102,14 @@ EOL
|
||||
cat << EOL > /tmp/initcontainers.nextcloud
|
||||
initContainers:
|
||||
- name: "delete-lost-found"
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- rm
|
||||
- "-rf"
|
||||
- "/nextcloud-aio-nextcloud/lost+found"
|
||||
volumeMountsInitRmLostFound:
|
||||
- name: init-volumes
|
||||
image: "alpine:3.20"
|
||||
image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.ALPINE_IMAGE_ORG }}alpine"
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -289,6 +286,9 @@ EOL
|
||||
# shellcheck disable=SC1083
|
||||
find ./ -name '*talk-deployment.yaml' -exec sed -i "/^.*\- env:/r /tmp/additional-talk.config" \{} \;
|
||||
|
||||
# shellcheck disable=SC1083
|
||||
find ./ -name '*deployment.yaml' -exec sed -i '/image: nextcloud/s/$/"/;s|image: nextcloud/|image: "{{ .Values.IMAGE_MIRROR_PREFIX }}{{ .Values.NEXTCLOUD_IMAGE_ORG }}/|;' \{} \;
|
||||
|
||||
cat << EOL > templates/nextcloud-aio-networkpolicy.yaml
|
||||
{{- if eq .Values.NETWORK_POLICY_ENABLED "yes" }}
|
||||
# https://github.com/ahmetb/kubernetes-network-policy-recipes/blob/master/04-deny-traffic-from-other-namespaces.md
|
||||
@@ -307,24 +307,8 @@ spec:
|
||||
- from:
|
||||
- podSelector: {}
|
||||
egress:
|
||||
- {} # Allows all egress traffic
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
namespace: "{{ .Values.NAMESPACE }}"
|
||||
name: nextcloud-aio-webserver-allow
|
||||
spec:
|
||||
podSelector:
|
||||
matchExpressions:
|
||||
- key: io.kompose.service
|
||||
operator: In
|
||||
values:
|
||||
- nextcloud-aio-apache
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- {} # Allows all ingress traffic
|
||||
- to:
|
||||
- podSelector: {}
|
||||
{{- end }}
|
||||
EOL
|
||||
|
||||
@@ -368,7 +352,7 @@ cat << ADDITIONAL_CONFIG >> /tmp/sample.conf
|
||||
|
||||
NAMESPACE: default # By changing this, you can adjust the namespace of the installation which allows to install multiple instances on one kubernetes cluster
|
||||
NAMESPACE_DISABLED: "no" # By setting this to "yes", you can disabled the creation of the namespace so that you can use a pre-created one
|
||||
NETWORK_POLICY_ENABLED: "no" # By setting this to "yes", you can enable a network policy that limits network access to the same namespace. Except the Web server service which is reachable from all endpoints.
|
||||
NETWORK_POLICY_ENABLED: "no" # By setting this to "yes", you can enable a network policy that limits network access to the same namespace. ⚠️ Attention: this breaks if you use an ingress!!! So it should be disabled if you do so!
|
||||
SUBSCRIPTION_KEY: # This allows to set the Nextcloud Enterprise key via ENV
|
||||
SERVERINFO_TOKEN: # This allows to set the serverinfo app token for monitoring your Nextcloud via the serverinfo app
|
||||
APPS_ALLOWLIST: # This allows to configure allowed apps that will be shown in Nextcloud's Appstore. You need to enter the app-IDs of the apps here and separate them with spaces. E.g. 'files richdocuments'
|
||||
@@ -386,6 +370,10 @@ MAIL_FROM_ADDRESS: # (not set by default): Set the local-part for the 'f
|
||||
MAIL_DOMAIN: # (not set by default): Set a different domain for the emails than the domain where Nextcloud is installed.
|
||||
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. 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. It needs a trailing slash!
|
||||
ADDITIONAL_CONFIG
|
||||
|
||||
mv /tmp/sample.conf ../helm-chart/values.yaml
|
||||
@@ -416,13 +404,6 @@ find ./ -name "*nextcloud-aio-elasticsearch-persistentvolumeclaim.yaml" -exec se
|
||||
# shellcheck disable=SC1083
|
||||
find ./ -name "*nextcloud-aio-elasticsearch-persistentvolumeclaim.yaml" -exec sed -i "$ a {{- end }}" \{} \;
|
||||
|
||||
cat << EOL >> /tmp/security.conf
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
EOL
|
||||
# shellcheck disable=SC1083
|
||||
find ./ \( -not -name '*nextcloud-deployment.yaml*' -not -name '*onlyoffice-deployment.yaml*' -name "*deployment.yaml" \) -exec sed -i "/^.*securityContext:$/r /tmp/security.conf" \{} \;
|
||||
|
||||
chmod 777 -R ./
|
||||
|
||||
# Seems like the dir needs to match the name of the chart
|
||||
|
||||
@@ -51,7 +51,7 @@ REDIS_STORAGE_SIZE: 1Gi # You can change the size of the redis volume that
|
||||
|
||||
NAMESPACE: default # By changing this, you can adjust the namespace of the installation which allows to install multiple instances on one kubernetes cluster
|
||||
NAMESPACE_DISABLED: "no" # By setting this to "yes", you can disabled the creation of the namespace so that you can use a pre-created one
|
||||
NETWORK_POLICY_ENABLED: "no" # By setting this to "yes", you can enable a network policy that limits network access to the same namespace. Except the Web server service which is reachable from all endpoints.
|
||||
NETWORK_POLICY_ENABLED: "no" # By setting this to "yes", you can enable a network policy that limits network access to the same namespace. ⚠️ Attention: this breaks if you use an ingress!!! So it should be disabled if you do so!
|
||||
SUBSCRIPTION_KEY: # This allows to set the Nextcloud Enterprise key via ENV
|
||||
SERVERINFO_TOKEN: # This allows to set the serverinfo app token for monitoring your Nextcloud via the serverinfo app
|
||||
APPS_ALLOWLIST: # This allows to configure allowed apps that will be shown in Nextcloud's Appstore. You need to enter the app-IDs of the apps here and separate them with spaces. E.g. 'files richdocuments'
|
||||
@@ -69,3 +69,7 @@ MAIL_FROM_ADDRESS: # (not set by default): Set the local-part for the 'f
|
||||
MAIL_DOMAIN: # (not set by default): Set a different domain for the emails than the domain where Nextcloud is installed.
|
||||
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. 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. It needs a trailing slash!
|
||||
|
||||
@@ -33,7 +33,6 @@ docker run \
|
||||
--rm \
|
||||
--name nextcloud-aio-mastercontainer \
|
||||
--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
nextcloud/all-in-one:latest
|
||||
```
|
||||
|
||||
@@ -56,7 +55,6 @@ Note: You can restart the server by preceding the command with other environment
|
||||
|-----------------------------------------|----------------------------------------|
|
||||
| `composer run dev` | Starts the development server |
|
||||
| `composer run psalm` | Run Psalm static analysis |
|
||||
| `composer run psalm:strict` | Run Psalm static analysis strict |
|
||||
| `composer run psalm:update-baseline` | Run Psalm with `--update-baseline` arg |
|
||||
| `composer run lint` | Run PHP Syntax check |
|
||||
| `composer run lint:twig` | Run Twig Syntax check |
|
||||
|
||||
@@ -1,36 +1,35 @@
|
||||
{
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"AIO\\": ["src/"]
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "8.3.*",
|
||||
"ext-json": "*",
|
||||
"ext-sodium": "*",
|
||||
"ext-curl": "*",
|
||||
"slim/slim": "^4.11",
|
||||
"php-di/slim-bridge": "^3.3",
|
||||
"guzzlehttp/guzzle": "^7.5",
|
||||
"guzzlehttp/psr7": "^2.4",
|
||||
"http-interop/http-factory-guzzle": "^1.2",
|
||||
"slim/twig-view": "^3.3",
|
||||
"slim/csrf": "^1.3",
|
||||
"ext-apcu": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"sserbin/twig-linter": "@dev",
|
||||
"vimeo/psalm": "^5.25",
|
||||
"wapmorgan/php-deprecation-detector": "dev-master"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"php -S localhost:8080 -t public"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"AIO\\": ["src/"]
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "8.3.*",
|
||||
"ext-json": "*",
|
||||
"ext-sodium": "*",
|
||||
"ext-curl": "*",
|
||||
"slim/slim": "^4.11",
|
||||
"php-di/slim-bridge": "^3.3",
|
||||
"guzzlehttp/guzzle": "^7.5",
|
||||
"guzzlehttp/psr7": "^2.4",
|
||||
"http-interop/http-factory-guzzle": "^1.2",
|
||||
"slim/twig-view": "^3.3",
|
||||
"slim/csrf": "^1.3",
|
||||
"ext-apcu": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"sserbin/twig-linter": "@dev",
|
||||
"vimeo/psalm": "^5.25",
|
||||
"wapmorgan/php-deprecation-detector": "dev-master"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"php -S localhost:8080 -t public"
|
||||
],
|
||||
"psalm": "psalm --threads=1",
|
||||
"psalm:update-baseline": "psalm --threads=1 --monochrome --no-progress --output-format=text --update-baseline",
|
||||
"psalm:strict": "psalm --threads=1 --show-info=true",
|
||||
"lint": "php -l src/*.php src/**/*.php public/index.php",
|
||||
"lint:twig": "twig-linter lint ./templates",
|
||||
"php-deprecation-detector": "phpdd scan -n -t 8.3 src/*.php src/**/*.php public/index.php"
|
||||
|
||||
144
php/composer.lock
generated
144
php/composer.lock
generated
@@ -134,16 +134,16 @@
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/promises.git",
|
||||
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455"
|
||||
"reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
|
||||
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
|
||||
"reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -197,7 +197,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/promises/issues",
|
||||
"source": "https://github.com/guzzle/promises/tree/2.0.4"
|
||||
"source": "https://github.com/guzzle/promises/tree/2.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -213,7 +213,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-17T10:06:22+00:00"
|
||||
"time": "2024-07-18T10:29:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
@@ -1632,16 +1632,16 @@
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.14.2",
|
||||
"version": "v3.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a"
|
||||
"reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a",
|
||||
"reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
|
||||
"reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1695,7 +1695,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.14.2"
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.14.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1707,7 +1707,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-07T12:36:22+00:00"
|
||||
"time": "2024-09-09T17:55:12+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@@ -2469,16 +2469,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.19.4",
|
||||
"version": "v4.19.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2"
|
||||
"reference": "0ed4c8949a32986043e977dbe14776c14d644c45"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2",
|
||||
"reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ed4c8949a32986043e977dbe14776c14d644c45",
|
||||
"reference": "0ed4c8949a32986043e977dbe14776c14d644c45",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2487,7 +2487,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"ircmaxell/php-yacc": "^0.0.7",
|
||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
|
||||
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/php-parse"
|
||||
@@ -2519,9 +2519,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.2"
|
||||
},
|
||||
"time": "2024-09-29T15:01:53+00:00"
|
||||
"time": "2024-09-17T19:36:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
@@ -2578,16 +2578,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "5.6.0",
|
||||
"version": "5.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "f3558a4c23426d12bffeaab463f8a8d8b681193c"
|
||||
"reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/f3558a4c23426d12bffeaab463f8a8d8b681193c",
|
||||
"reference": "f3558a4c23426d12bffeaab463f8a8d8b681193c",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c",
|
||||
"reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2596,17 +2596,17 @@
|
||||
"php": "^7.4 || ^8.0",
|
||||
"phpdocumentor/reflection-common": "^2.2",
|
||||
"phpdocumentor/type-resolver": "^1.7",
|
||||
"phpstan/phpdoc-parser": "^1.7|^2.0",
|
||||
"phpstan/phpdoc-parser": "^1.7",
|
||||
"webmozart/assert": "^1.9.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.3.5 || ~1.6.0",
|
||||
"mockery/mockery": "~1.3.5",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan": "^1.8",
|
||||
"phpstan/phpstan-mockery": "^1.1",
|
||||
"phpstan/phpstan-webmozart-assert": "^1.2",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/phar": "^5.26"
|
||||
"vimeo/psalm": "^5.13"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -2636,29 +2636,29 @@
|
||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
|
||||
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.0"
|
||||
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1"
|
||||
},
|
||||
"time": "2024-11-12T11:25:25+00:00"
|
||||
"time": "2024-05-21T05:55:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
"version": "1.10.0",
|
||||
"version": "1.8.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||
"reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
|
||||
"reference": "153ae662783729388a584b4361f2545e4d841e3c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
|
||||
"reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c",
|
||||
"reference": "153ae662783729388a584b4361f2545e4d841e3c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/deprecations": "^1.0",
|
||||
"php": "^7.3 || ^8.0",
|
||||
"phpdocumentor/reflection-common": "^2.0",
|
||||
"phpstan/phpdoc-parser": "^1.18|^2.0"
|
||||
"phpstan/phpdoc-parser": "^1.13"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-tokenizer": "*",
|
||||
@@ -2694,36 +2694,36 @@
|
||||
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2"
|
||||
},
|
||||
"time": "2024-11-09T15:12:26+00:00"
|
||||
"time": "2024-02-23T11:10:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
"version": "2.0.0",
|
||||
"version": "1.32.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||
"reference": "c00d78fb6b29658347f9d37ebe104bffadf36299"
|
||||
"reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/c00d78fb6b29658347f9d37ebe104bffadf36299",
|
||||
"reference": "c00d78fb6b29658347f9d37ebe104bffadf36299",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6ca22b154efdd9e3c68c56f5d94670920a1c19a4",
|
||||
"reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0"
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^2.0",
|
||||
"nikic/php-parser": "^5.3.0",
|
||||
"nikic/php-parser": "^4.15",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"phpstan/phpstan": "^1.5",
|
||||
"phpstan/phpstan-phpunit": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"symfony/process": "^5.2"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -2741,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/2.0.0"
|
||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.32.0"
|
||||
},
|
||||
"time": "2024-10-13T11:29:49+00:00"
|
||||
"time": "2024-09-26T07:23:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
@@ -2940,16 +2940,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.4.14",
|
||||
"version": "v6.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b"
|
||||
"reference": "72d080eb9edf80e36c19be61f72c98ed8273b765"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/897c2441ed4eec8a8a2c37b943427d24dba3f26b",
|
||||
"reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/72d080eb9edf80e36c19be61f72c98ed8273b765",
|
||||
"reference": "72d080eb9edf80e36c19be61f72c98ed8273b765",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3014,7 +3014,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v6.4.14"
|
||||
"source": "https://github.com/symfony/console/tree/v6.4.12"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3030,20 +3030,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-05T15:34:40+00:00"
|
||||
"time": "2024-09-20T08:15:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v7.1.6",
|
||||
"version": "v7.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "c835867b3c62bb05c7fe3d637c871c7ae52024d4"
|
||||
"reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/c835867b3c62bb05c7fe3d637c871c7ae52024d4",
|
||||
"reference": "c835867b3c62bb05c7fe3d637c871c7ae52024d4",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/61fe0566189bf32e8cfee78335d8776f64a66f5a",
|
||||
"reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3080,7 +3080,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v7.1.6"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v7.1.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3096,20 +3096,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-25T15:11:02+00:00"
|
||||
"time": "2024-09-17T09:16:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v6.4.13",
|
||||
"version": "v6.4.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958"
|
||||
"reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/daea9eca0b08d0ed1dc9ab702a46128fd1be4958",
|
||||
"reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/d7eb6daf8cd7e9ac4976e9576b32042ef7253453",
|
||||
"reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3144,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.13"
|
||||
"source": "https://github.com/symfony/finder/tree/v6.4.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3160,7 +3160,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-01T08:30:56+00:00"
|
||||
"time": "2024-08-13T14:27:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
@@ -3406,16 +3406,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v7.1.6",
|
||||
"version": "v7.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "61b72d66bf96c360a727ae6232df5ac83c71f626"
|
||||
"reference": "d66f9c343fa894ec2037cc928381df90a7ad4306"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/61b72d66bf96c360a727ae6232df5ac83c71f626",
|
||||
"reference": "61b72d66bf96c360a727ae6232df5ac83c71f626",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306",
|
||||
"reference": "d66f9c343fa894ec2037cc928381df90a7ad4306",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3473,7 +3473,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v7.1.6"
|
||||
"source": "https://github.com/symfony/string/tree/v7.1.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3489,7 +3489,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-25T14:20:29+00:00"
|
||||
"time": "2024-09-20T08:28:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vimeo/psalm",
|
||||
@@ -3742,6 +3742,6 @@
|
||||
"ext-curl": "*",
|
||||
"ext-apcu": "*"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
||||
@@ -68,10 +68,6 @@
|
||||
"stop_grace_period": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]{1,6}$"
|
||||
},
|
||||
"ports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
],
|
||||
"display_name": "Apache",
|
||||
"image": "nextcloud/aio-apache",
|
||||
"user": "33",
|
||||
"init": true,
|
||||
"ports": [
|
||||
{
|
||||
@@ -79,7 +78,6 @@
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Database",
|
||||
"image": "nextcloud/aio-postgresql",
|
||||
"user": "999",
|
||||
"init": true,
|
||||
"expose": [
|
||||
"5432"
|
||||
@@ -190,15 +188,15 @@
|
||||
"ADMIN_USER=admin",
|
||||
"ADMIN_PASSWORD=%NEXTCLOUD_PASSWORD%",
|
||||
"NEXTCLOUD_DATA_DIR=/mnt/ncdata",
|
||||
"OVERWRITEHOST=%NC_DOMAIN%",
|
||||
"OVERWRITEPROTOCOL=https",
|
||||
"OVERWRITEHOST=%OVERWRITEHOST%",
|
||||
"OVERWRITEPROTOCOL=%OVERWRITEPROTOCOL%",
|
||||
"TURN_SECRET=%TURN_SECRET%",
|
||||
"SIGNALING_SECRET=%SIGNALING_SECRET%",
|
||||
"ONLYOFFICE_SECRET=%ONLYOFFICE_SECRET%",
|
||||
"AIO_URL=%AIO_URL%",
|
||||
"NEXTCLOUD_MOUNT=%NEXTCLOUD_MOUNT%",
|
||||
"CLAMAV_ENABLED=%CLAMAV_ENABLED%",
|
||||
"CLAMAV_HOST=nextcloud-aio-clamav",
|
||||
"CLAMAV_HOST=nextcloud-aio-clamav.nextcloud-aio",
|
||||
"ONLYOFFICE_ENABLED=%ONLYOFFICE_ENABLED%",
|
||||
"COLLABORA_ENABLED=%COLLABORA_ENABLED%",
|
||||
"COLLABORA_HOST=nextcloud-aio-collabora",
|
||||
@@ -208,12 +206,12 @@
|
||||
"TZ=%TIMEZONE%",
|
||||
"TALK_PORT=%TALK_PORT%",
|
||||
"IMAGINARY_ENABLED=%IMAGINARY_ENABLED%",
|
||||
"IMAGINARY_HOST=nextcloud-aio-imaginary",
|
||||
"IMAGINARY_HOST=nextcloud-aio-imaginary.nextcloud-aio",
|
||||
"CLAMAV_MAX_SIZE=%APACHE_MAX_SIZE%",
|
||||
"PHP_UPLOAD_LIMIT=%NEXTCLOUD_UPLOAD_LIMIT%",
|
||||
"PHP_MEMORY_LIMIT=%NEXTCLOUD_MEMORY_LIMIT%",
|
||||
"FULLTEXTSEARCH_ENABLED=%FULLTEXTSEARCH_ENABLED%",
|
||||
"FULLTEXTSEARCH_HOST=nextcloud-aio-fulltextsearch",
|
||||
"FULLTEXTSEARCH_HOST=nextcloud-aio-fulltextsearch.nextcloud-aio",
|
||||
"PHP_MAX_TIME=%NEXTCLOUD_MAX_TIME%",
|
||||
"TRUSTED_CACERTS_DIR=%NEXTCLOUD_TRUSTED_CACERTS_DIR%",
|
||||
"STARTUP_APPS=%NEXTCLOUD_STARTUP_APPS%",
|
||||
@@ -222,7 +220,7 @@
|
||||
"INSTALL_LATEST_MAJOR=%INSTALL_LATEST_MAJOR%",
|
||||
"TALK_RECORDING_ENABLED=%TALK_RECORDING_ENABLED%",
|
||||
"RECORDING_SECRET=%RECORDING_SECRET%",
|
||||
"TALK_RECORDING_HOST=nextcloud-aio-talk-recording",
|
||||
"TALK_RECORDING_HOST=nextcloud-aio-talk-recording.nextcloud-aio",
|
||||
"FULLTEXTSEARCH_PASSWORD=%FULLTEXTSEARCH_PASSWORD%",
|
||||
"DOCKER_SOCKET_PROXY_ENABLED=%DOCKER_SOCKET_PROXY_ENABLED%",
|
||||
"REMOVE_DISABLED_APPS=%REMOVE_DISABLED_APPS%",
|
||||
@@ -253,7 +251,6 @@
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Notify Push",
|
||||
"image": "nextcloud/aio-notify-push",
|
||||
"user": "33",
|
||||
"init": true,
|
||||
"expose": [
|
||||
"7867"
|
||||
@@ -295,7 +292,6 @@
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Redis",
|
||||
"image": "nextcloud/aio-redis",
|
||||
"user": "999",
|
||||
"init": true,
|
||||
"expose": [
|
||||
"6379"
|
||||
@@ -329,10 +325,8 @@
|
||||
{
|
||||
"container_name": "nextcloud-aio-collabora",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"documentation": "https://github.com/nextcloud/all-in-one/discussions/1358",
|
||||
"display_name": "Collabora",
|
||||
"image": "nextcloud/aio-collabora",
|
||||
"user": "100",
|
||||
"init": true,
|
||||
"expose": [
|
||||
"9980"
|
||||
@@ -368,10 +362,8 @@
|
||||
{
|
||||
"container_name": "nextcloud-aio-talk",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"documentation": "https://github.com/nextcloud/all-in-one/discussions/1358",
|
||||
"display_name": "Talk",
|
||||
"image": "nextcloud/aio-talk",
|
||||
"user": "1000",
|
||||
"init": true,
|
||||
"ports": [
|
||||
{
|
||||
@@ -428,7 +420,6 @@
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Talk Recording",
|
||||
"image": "nextcloud/aio-talk-recording",
|
||||
"user": "122",
|
||||
"init": true,
|
||||
"expose": [
|
||||
"1234"
|
||||
@@ -440,13 +431,6 @@
|
||||
"RECORDING_SECRET=%RECORDING_SECRET%",
|
||||
"INTERNAL_SECRET=%TALK_INTERNAL_SECRET%"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"source": "nextcloud_aio_talk_recording",
|
||||
"destination": "/tmp",
|
||||
"writeable": true
|
||||
}
|
||||
],
|
||||
"shm_size": 2147483648,
|
||||
"secrets": [
|
||||
"RECORDING_SECRET",
|
||||
@@ -461,6 +445,7 @@
|
||||
],
|
||||
"read_only": true,
|
||||
"tmpfs": [
|
||||
"/tmp",
|
||||
"/conf"
|
||||
],
|
||||
"cap_drop": [
|
||||
@@ -473,11 +458,9 @@
|
||||
"image": "nextcloud/aio-borgbackup",
|
||||
"init": true,
|
||||
"environment": [
|
||||
"BORG_REMOTE_REPO=%BORGBACKUP_REMOTE_REPO%",
|
||||
"BORG_PASSWORD=%BORGBACKUP_PASSWORD%",
|
||||
"BORG_MODE=%BORGBACKUP_MODE%",
|
||||
"SELECTED_RESTORE_TIME=%SELECTED_RESTORE_TIME%",
|
||||
"RESTORE_EXCLUDE_PREVIEWS=%RESTORE_EXCLUDE_PREVIEWS%",
|
||||
"BACKUP_RESTORE_PASSWORD=%BACKUP_RESTORE_PASSWORD%",
|
||||
"ADDITIONAL_DIRECTORIES_BACKUP=%ADDITIONAL_DIRECTORIES_BACKUP%",
|
||||
"BORGBACKUP_HOST_LOCATION=%BORGBACKUP_HOST_LOCATION%",
|
||||
@@ -590,7 +573,6 @@
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "ClamAV",
|
||||
"image": "nextcloud/aio-clamav",
|
||||
"user": "100",
|
||||
"init": false,
|
||||
"expose": [
|
||||
"3310"
|
||||
@@ -671,7 +653,6 @@
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Imaginary",
|
||||
"image": "nextcloud/aio-imaginary",
|
||||
"user": "65534",
|
||||
"init": true,
|
||||
"expose": [
|
||||
"9000"
|
||||
@@ -705,7 +686,6 @@
|
||||
{
|
||||
"container_name": "nextcloud-aio-fulltextsearch",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"documentation": "https://github.com/nextcloud/all-in-one/discussions/1709",
|
||||
"display_name": "Fulltextsearch",
|
||||
"image": "nextcloud/aio-fulltextsearch",
|
||||
"init": false,
|
||||
@@ -777,7 +757,6 @@
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Whiteboard",
|
||||
"image": "nextcloud/aio-whiteboard",
|
||||
"user": "65534",
|
||||
"init": true,
|
||||
"expose": [
|
||||
"3002"
|
||||
|
||||
@@ -1,22 +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 vendor/vimeo/psalm/config.xsd"
|
||||
errorBaseline="psalm-baseline.xml"
|
||||
xsi:schemaLocation="https://getpsalm.org/schema/config"
|
||||
errorBaseline="psalm-baseline.xml"
|
||||
findUnusedBaselineEntry="true"
|
||||
findUnusedCode="false"
|
||||
>
|
||||
<projectFiles>
|
||||
<directory name="templates"/>
|
||||
<directory name="src"/>
|
||||
<file name="public/index.php"/>
|
||||
<ignoreFiles>
|
||||
<directory name="vendor" />
|
||||
</ignoreFiles>
|
||||
</projectFiles>
|
||||
<extraFiles>
|
||||
<directory name="vendor" />
|
||||
</extraFiles>
|
||||
<issueHandlers>
|
||||
</issueHandlers>
|
||||
</psalm>
|
||||
|
||||
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: 176 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 97 KiB |
3
php/public/img/logo-blue.svg
Normal file
3
php/public/img/logo-blue.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
1
php/public/img/logo.svg
Normal file
1
php/public/img/logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="256" height="128" version="1.1" viewBox="0 0 256 128" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke-width="22"><circle cx="40" cy="64" r="26" stroke="#ffffff" fill="none"/><circle cx="216" cy="64" r="26" stroke="#ffffff" fill="none"/><circle cx="128" cy="64" r="46" stroke="#ffffff" fill="none"/></g></svg>
|
||||
|
After Width: | Height: | Size: 330 B |
@@ -1,4 +0,0 @@
|
||||
<svg id="nextcloud-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 142 100" width="142" height="100">
|
||||
<g id="logo" stroke="currentColor" fill="none" stroke-width="11" transform="scale(1.109)"><circle cx="20" cy="32" r="13"/><circle cx="64" cy="32" r="23"/><circle cx="108" cy="32" r="13"/></g>
|
||||
<g id="Nextcloud" fill="currentColor" transform="translate(-3.4, -3.4) scale(1.17)"><path d="M15.4,67.4c-0.4,0-0.5,0.2-0.5,0.6v14.6c0,0.4,0.2,0.5,0.5,0.5h0.4c0.4,0,0.5-0.2,0.5-0.5V70.4 l7.9,12.3c0,0.1,0.1,0.1,0.1,0.1c0,0,0,0,0,0c0,0,0.1,0,0.1,0.1c0,0,0,0,0.1,0c0,0,0,0,0,0c0.1,0,0.1,0,0.2,0h0.4 c0.4,0,0.5-0.2,0.5-0.5V68c0-0.4-0.2-0.6-0.5-0.6h-0.4c-0.4,0-0.6,0.2-0.6,0.6v12.1l-7.9-12.3c0,0-0.1-0.1-0.1-0.1 c-0.1-0.1-0.2-0.2-0.4-0.2L15.4,67.4z M110.8,67.6c-0.4,0-0.2,0.2-0.2,0.6v5c0,0.5,0,0.9,0,0.9h0c0,0-1-2.2-3.6-2.2 c-2.9,0-5,2.3-4.9,5.7c0,3.4,1.9,5.8,4.8,5.8c2.9,0,3.8-2.3,3.8-2.3h0.1c0,0-0.1,0.3-0.1,0.7v0.9c0,0.4,0.2,0.5,0.6,0.5h0.4 c0.4,0,0.5-0.2,0.5-0.6V68.2c0-0.4-0.6-0.6-0.9-0.6H110.8z M71.8,67.7c-0.4,0-0.1,0.2-0.1,0.6v12.3c0,2.4,1.6,2.7,2.5,2.7 c0.4,0,0.6-0.2,0.6-0.6v-0.4c0-0.4-0.2-0.5-0.5-0.5c-0.5-0.1-1.2-0.2-1.2-1.6v-12c0-0.4-0.6-0.6-0.9-0.6L71.8,67.7z M53.8,69 c-0.4,0-0.6,0.2-0.6,0.6v2.6v1.3v5.7c0,2.6,1.5,4.1,3.9,4.1c0.5,0,0.6-0.1,0.6-0.5v-0.3c0-0.4-0.1-0.5-0.6-0.6 c-0.9-0.1-2.4-0.4-2.4-2.9v-5.5h2.3c0.4,0,0.6-0.1,0.6-0.5v-0.2c0-0.4-0.2-0.6-0.6-0.6h-2.3v-2.6c0-0.4-0.1-0.6-0.5-0.6L53.8,69z M33.8,71.8c-3,0-5.4,2.2-5.5,5.8c0,3.4,2.5,5.8,5.8,5.8c1.8,0,3.1-0.8,3.7-1.2c0.3-0.2,0.3-0.5,0.2-0.7l-0.2-0.2 c-0.2-0.3-0.4-0.4-0.7-0.2c-0.5,0.4-1.5,1-2.9,1c-2.3,0-4.2-1.6-4.3-4.4h8c0.3,0,0.6-0.3,0.6-0.6C38.4,73.9,36.8,71.8,33.8,71.8z M65,71.8c-3.3,0-5.8,2.4-5.8,5.8c0,3.4,2.5,5.8,5.8,5.8c2,0,3.4-1,3.9-1.4c0.3-0.3,0.3-0.5,0.1-0.8L68.8,81 c-0.2-0.3-0.4-0.4-0.7-0.2C67.6,81.3,66.6,82,65,82c-2.4,0-4.3-1.8-4.3-4.4c0-2.7,1.9-4.5,4.3-4.5c1.3,0,2.3,0.7,2.8,1 c0.3,0.2,0.6,0.2,0.8-0.1l0.2-0.3c0.3-0.3,0.2-0.6-0.1-0.8C68.1,72.6,66.9,71.8,65,71.8L65,71.8z M81.9,71.8 c-3.2,0-5.8,2.5-5.8,5.7c0,3.3,2.6,5.8,5.8,5.8c3.2,0,5.8-2.5,5.8-5.8C87.8,74.3,85.1,71.8,81.9,71.8z M49.5,72 c-0.1,0-0.2,0.1-0.4,0.2l-2,2.4l-1.5,1.8l-2.3-2.7L42,72.2c-0.1-0.1-0.2-0.2-0.4-0.2c-0.1,0-0.3,0-0.4,0.2l-0.3,0.3 c-0.3,0.2-0.3,0.5,0,0.7l2,2.4l1.7,2l-2.5,2.9c0,0,0,0,0,0L40.9,82c-0.2,0.3-0.2,0.6,0.1,0.8l0.3,0.3c0.3,0.2,0.5,0.2,0.7-0.1 l2-2.4l1.5-1.8l2.3,2.7c0,0,0,0,0,0l1.2,1.5c0.2,0.3,0.5,0.3,0.8,0.1l0.3-0.3c0.3-0.2,0.3-0.5,0-0.7l-2-2.4l-1.7-2l2.5-2.9 c0,0,0,0,0,0l1.2-1.5c0.2-0.3,0.2-0.6-0.1-0.8l-0.3-0.3C49.7,72,49.6,71.9,49.5,72L49.5,72z M90.7,72c-0.4,0-0.5,0.2-0.5,0.6v6.5 c0,2.9,2.1,4.3,4.7,4.3c2.6,0,4.7-1.4,4.7-4.3v-6.5c0.1-0.4-0.1-0.6-0.5-0.6h-0.4c-0.4,0-0.6,0.2-0.6,0.6v6.1 c0,1.7-1.1,3.3-3.3,3.3c-2.1,0-3.3-1.6-3.3-3.3v-6.1c0-0.4-0.2-0.6-0.6-0.6L90.7,72z M33.8,73c1.6,0,3,1.2,3.1,3.5h-6.9 C30.3,74.3,31.9,73,33.8,73z M81.9,73.1c2.4,0,4.3,1.9,4.3,4.4c0,2.6-1.9,4.5-4.3,4.5c-2.4,0-4.3-2-4.3-4.5 C77.6,75.1,79.6,73.1,81.9,73.1z M107.1,73.1c2.4,0,3.5,2.2,3.5,4.4c0,3.2-1.7,4.5-3.6,4.5c-2.1,0-3.5-1.8-3.5-4.5 C103.5,74.8,105.1,73.1,107.1,73.1z"/></g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.0 KiB |
@@ -86,8 +86,6 @@ $app->get('/containers', function (Request $request, Response $response, array $
|
||||
'domain' => $configurationManager->GetDomain(),
|
||||
'apache_port' => $configurationManager->GetApachePort(),
|
||||
'borg_backup_host_location' => $configurationManager->GetBorgBackupHostLocation(),
|
||||
'borg_remote_repo' => $configurationManager->GetBorgRemoteRepo(),
|
||||
'borg_public_key' => $configurationManager->GetBorgPublicKey(),
|
||||
'nextcloud_password' => $configurationManager->GetAndGenerateSecret('NEXTCLOUD_PASSWORD'),
|
||||
'containers' => (new \AIO\ContainerDefinitionFetcher($container->get(\AIO\Data\ConfigurationManager::class), $container))->FetchDefinition(),
|
||||
'borgbackup_password' => $configurationManager->GetAndGenerateSecret('BORGBACKUP_PASSWORD'),
|
||||
|
||||
@@ -1,60 +1,73 @@
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Hide submit button initially
|
||||
const optionsFormSubmit = document.getElementById("options-form-submit");
|
||||
function makeOptionsFormSubmitVisible() {
|
||||
let optionsFormSubmit = document.getElementById("options-form-submit");
|
||||
optionsFormSubmit.style.display = 'block';
|
||||
}
|
||||
|
||||
function handleTalkVisibility() {
|
||||
let talk = document.getElementById("talk");
|
||||
let talkRecording = document.getElementById("talk-recording")
|
||||
if (talk.checked) {
|
||||
talkRecording.disabled = false
|
||||
} else {
|
||||
talkRecording.checked = false
|
||||
talkRecording.disabled = true
|
||||
}
|
||||
}
|
||||
|
||||
function handleDockerSocketProxyWarning() {
|
||||
let dockerSocketProxy = document.getElementById("docker-socket-proxy");
|
||||
if (dockerSocketProxy.checked) {
|
||||
alert('⚠️ Warning! Enabling this container comes with possible Security problems since you are exposing the docker socket and all its privileges to the Nextcloud container. Enable this only if you are sure what you are doing!')
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// handle submit button for options form
|
||||
let optionsFormSubmit = document.getElementById("options-form-submit");
|
||||
optionsFormSubmit.style.display = 'none';
|
||||
|
||||
// Store initial states for all checkboxes
|
||||
const initialState = {};
|
||||
const checkboxes = document.querySelectorAll("#options-form input[type='checkbox']");
|
||||
// Clamav
|
||||
let clamav = document.getElementById("clamav");
|
||||
clamav.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
|
||||
checkboxes.forEach(checkbox => {
|
||||
initialState[checkbox.id] = checkbox.checked; // Use checked property to capture actual initial state
|
||||
});
|
||||
|
||||
// Function to compare current states to initial states
|
||||
function checkForChanges() {
|
||||
let hasChanges = false;
|
||||
|
||||
checkboxes.forEach(checkbox => {
|
||||
if (checkbox.checked !== initialState[checkbox.id]) {
|
||||
hasChanges = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Show or hide submit button based on changes
|
||||
optionsFormSubmit.style.display = hasChanges ? 'block' : 'none';
|
||||
// OnlyOffice
|
||||
let onlyoffice = document.getElementById("onlyoffice");
|
||||
if (onlyoffice) {
|
||||
onlyoffice.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
}
|
||||
|
||||
// Event listener to trigger visibility check on each change
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.addEventListener("change", checkForChanges);
|
||||
});
|
||||
// Collabora
|
||||
let collabora = document.getElementById("collabora");
|
||||
collabora.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
|
||||
// Custom behaviors for specific options
|
||||
function handleTalkVisibility() {
|
||||
const talkRecording = document.getElementById("talk-recording");
|
||||
if (document.getElementById("talk").checked) {
|
||||
talkRecording.disabled = false;
|
||||
} else {
|
||||
talkRecording.checked = false;
|
||||
talkRecording.disabled = true;
|
||||
}
|
||||
checkForChanges(); // Check changes after toggling Talk Recording
|
||||
// Talk
|
||||
let talk = document.getElementById("talk");
|
||||
talk.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
talk.addEventListener('change', handleTalkVisibility);
|
||||
|
||||
// Talk-recording
|
||||
let talkRecording = document.getElementById("talk-recording");
|
||||
talkRecording.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
if (!talk.checked) {
|
||||
talkRecording.disabled = true
|
||||
}
|
||||
|
||||
function handleDockerSocketProxyWarning() {
|
||||
if (document.getElementById("docker-socket-proxy").checked) {
|
||||
alert('⚠️ Warning! Enabling this container comes with possible Security problems since you are exposing the docker socket and all its privileges to the Nextcloud container. Enable this only if you are sure what you are doing!');
|
||||
}
|
||||
// Imaginary
|
||||
let imaginary = document.getElementById("imaginary");
|
||||
imaginary.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
|
||||
// Fulltextsearch
|
||||
let fulltextsearch = document.getElementById("fulltextsearch");
|
||||
fulltextsearch.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
|
||||
// Docker socket proxy
|
||||
let dockerSocketProxy = document.getElementById("docker-socket-proxy");
|
||||
if (dockerSocketProxy) {
|
||||
dockerSocketProxy.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
// dockerSocketProxy.addEventListener('change', handleDockerSocketProxyWarning);
|
||||
}
|
||||
|
||||
// Initialize event listeners for specific behaviors
|
||||
document.getElementById("talk").addEventListener('change', handleTalkVisibility);
|
||||
document.getElementById("docker-socket-proxy").addEventListener('change', handleDockerSocketProxyWarning);
|
||||
|
||||
// Initialize talk-recording visibility on page load
|
||||
handleTalkVisibility(); // Ensure talk-recording is correctly initialized
|
||||
|
||||
// Initial call to check for changes
|
||||
checkForChanges();
|
||||
// Whiteboard
|
||||
let whiteboard = document.getElementById("whiteboard");
|
||||
whiteboard.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
});
|
||||
|
||||
@@ -1,78 +1,12 @@
|
||||
:root {
|
||||
--color-nextcloud-blue: #0082c9;
|
||||
--color-nextcloud-logo: var(--color-nextcloud-blue);
|
||||
--color-main-background: white;
|
||||
--color-input-background: white;
|
||||
--color-main-text: black;
|
||||
--color-main-border: black;
|
||||
--color-main-border-hover: var(--color-main-border);
|
||||
--color-error: #db0606;
|
||||
--color-error-hover: #df2525;
|
||||
--color-error-text: #c20505;
|
||||
--color-success: #46ba61;
|
||||
--color-running: #ffd000;
|
||||
--color-info: #0071ad;
|
||||
--color-info-hover: #00aaef;
|
||||
--color-border-maxcontrast: #7d7d7d;
|
||||
--color-loader: #f3f3f3;
|
||||
--color-disabled: #d3d3d3; /* light gray background for disabled checkboxes */
|
||||
--color-border-disabled: #a9a9a9; /* darker gray border for disabled checkboxes */
|
||||
--color-text-disabled: #a9a9a9; /* matching label text color for disabled checkboxes */
|
||||
--border: .5px;
|
||||
--border-hover: 2px;
|
||||
--border-radius: 7px;
|
||||
--border-radius-large: 12px;
|
||||
--default-font-size: 13px;
|
||||
--checkbox-size: 16px;
|
||||
--max-width: 500px;
|
||||
--container-top-margin: 20px;
|
||||
--container-bottom-margin: 20px;
|
||||
--container-padding: 2px;
|
||||
--container-height-calculation-difference: calc(var(--container-top-margin) + var(--container-bottom-margin));
|
||||
--main-height-calculation-difference: calc(var(--container-height-calculation-difference) + calc(var(--container-padding) * 2));
|
||||
--main-padding: 50px;
|
||||
}
|
||||
|
||||
/* Breakpoint calculation: 500px (max-width) + 100px (main-padding * 2) + 200px (additional space) = 800px
|
||||
Note: Unfortunately, it's not possible to calculate this dynamically using CSS variables in media queries */
|
||||
@media only screen and (max-width: 800px) {
|
||||
:root {
|
||||
--container-top-margin: 50px;
|
||||
--container-bottom-margin: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--color-main-background: #171717;
|
||||
--color-input-background: #ebebeb;
|
||||
--color-main-text: #ebebeb;
|
||||
--color-nextcloud-logo: var(--color-main-text);
|
||||
--color-main-border: var(--color-border-maxcontrast);
|
||||
--color-main-border-hover: var(--color-main-text);
|
||||
--color-error: #ff3333;
|
||||
--color-error-hover: #ff6666;
|
||||
--color-error-text: #ff8080;
|
||||
--color-info: #00aeff;
|
||||
--color-info-hover: #33beff;
|
||||
--color-loader: var(--color-border-maxcontrast);
|
||||
--border-hover: var(--border);
|
||||
}
|
||||
|
||||
html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Oxygen-Sans, Cantarell, Ubuntu, 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
background-color: var(--color-main-background);
|
||||
color: var(--color-main-text);
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Cantarell, Ubuntu, Helvetica Neue, Arial, Noto Color Emoji, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: var(--color-info);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--color-info-hover);
|
||||
color: #0082c9;
|
||||
}
|
||||
|
||||
a.button,
|
||||
@@ -81,24 +15,19 @@ input[type="submit"] {
|
||||
width: auto;
|
||||
height: 34px;
|
||||
cursor: pointer;
|
||||
background-color: var(--color-nextcloud-blue);
|
||||
background-color: #0082c9;
|
||||
font-weight: bold;
|
||||
border-radius: var(--border-radius);
|
||||
border-radius: 8px;
|
||||
margin: 3px 3px 3px 0;
|
||||
font-size: var(--default-font-size);
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
border: .5px solid var(--color-main-border);
|
||||
border: .5px solid black;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a.button:focus,
|
||||
input[type="submit"]:focus {
|
||||
border: 1px solid var(--color-main-border);
|
||||
}
|
||||
|
||||
a.button:hover,
|
||||
input[type="submit"]:hover {
|
||||
background-color: var(--color-info-hover);
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
summary {
|
||||
@@ -112,36 +41,38 @@ ul {
|
||||
|
||||
li {
|
||||
padding-bottom: 5px;
|
||||
text-indent: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
span.error {
|
||||
background-color: var(--color-error);
|
||||
background-color: #e9322d;
|
||||
}
|
||||
|
||||
div.toast.error {
|
||||
border-left-color: var(--color-error);
|
||||
border-left-color: #e9322d;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: inline-block;
|
||||
height: var(--checkbox-size);
|
||||
width: var(--checkbox-size);
|
||||
vertical-align: text-bottom;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
vertical-align: text-bottom
|
||||
}
|
||||
|
||||
.status {
|
||||
border-radius: 50%
|
||||
}
|
||||
|
||||
|
||||
span.success {
|
||||
background-color: var(--color-success);
|
||||
background-color: #46ba61;
|
||||
}
|
||||
|
||||
span.running {
|
||||
background-color: var(--color-running);
|
||||
background-color: rgb(255, 208, 0);
|
||||
}
|
||||
|
||||
div.toast.success {
|
||||
border-left-color: var(--color-success);
|
||||
border-left-color: #46ba61;
|
||||
}
|
||||
|
||||
div.toast {
|
||||
@@ -153,36 +84,19 @@ div.toast {
|
||||
margin-top: 45px;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--color-main-background) none;
|
||||
color: var(--color-main-text);
|
||||
}
|
||||
|
||||
.nextcloud-logo {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
color: var(--color-nextcloud-logo);
|
||||
}
|
||||
|
||||
.fallback-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg:not(:has(use)) .fallback-text {
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
background: white none;
|
||||
}
|
||||
|
||||
.login {
|
||||
padding: 50px;
|
||||
background-color: var(--color-main-background);
|
||||
color: var(--color-main-text);
|
||||
background-color: white;
|
||||
width: 500px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: var(--border-radius-large);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.login > .monospace {
|
||||
@@ -190,6 +104,33 @@ svg:not(:has(use)) .fallback-text {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
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"] {
|
||||
@@ -212,114 +153,34 @@ svg:not(:has(use)) .fallback-text {
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
.login-wrapper {
|
||||
min-height: 100dvh;
|
||||
min-width: 100vw;
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
background-image: url("img/jenna-kim-the-globe.webp");
|
||||
height: auto;
|
||||
background-image: url("img/Background_Light.jpg");
|
||||
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .wrapper {
|
||||
background-image: url("img/jenna-kim-the-globe-dark.webp");
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"],
|
||||
select {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
height: 34px;
|
||||
margin-bottom: 15px;
|
||||
border-radius: var(--border-radius);
|
||||
border: var(--border) solid var(--color-border-maxcontrast);
|
||||
background: var(--color-main-background);
|
||||
color: var(--color-main-text);
|
||||
}
|
||||
|
||||
input[type="text"]:hover,
|
||||
input[type="password"]:hover,
|
||||
select:hover {
|
||||
border: var(--border-hover) solid var(--color-main-border-hover);
|
||||
}
|
||||
|
||||
textarea {
|
||||
border-radius: var(--border-radius);
|
||||
border: .5px solid var(--color-main-border);
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
input[type="text"]:focus,
|
||||
input[type="password"]:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border: 1px solid var(--color-main-border);
|
||||
}
|
||||
|
||||
/* Scroll bar for dark mode */
|
||||
html[data-theme="dark"] ::-webkit-scrollbar {
|
||||
width: 8px; /* Width of the scroll bar */
|
||||
}
|
||||
|
||||
html[data-theme="dark"] ::-webkit-scrollbar-thumb {
|
||||
background-color: #444; /* Dark mode scrollbar thumb color */
|
||||
border-radius: 4px; /* Rounded corners for the thumb */
|
||||
}
|
||||
|
||||
html[data-theme="dark"] ::-webkit-scrollbar-track {
|
||||
background-color: #333; /* Dark mode scrollbar track color */
|
||||
}
|
||||
|
||||
/* Scroll bar for light mode */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px; /* Width of the scroll bar */
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #888; /* Light mode scrollbar thumb color */
|
||||
border-radius: 4px; /* Rounded corners for the thumb */
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: #f0f0f0; /* Light mode scrollbar track color */
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: var(--container-top-margin) auto var(--container-bottom-margin) auto;
|
||||
padding: var(--container-padding);
|
||||
max-width: calc(var(--max-width) + calc(var(--main-padding) * 2) + 8px);
|
||||
background-color: var(--color-main-background);
|
||||
border-radius: var(--border-radius-large);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
max-height: calc(100dvh - var(--container-height-calculation-difference));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-left: var(--main-padding);
|
||||
padding-right: var(--main-padding);
|
||||
background-color: transparent; /* transparent, since color comes from outer container */
|
||||
color: var(--color-main-text);
|
||||
max-height: calc(100dvh - var(--main-height-calculation-difference));
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
max-width: 100%;
|
||||
word-break: break-word;
|
||||
max-width: calc(var(--max-width) + calc(var(--main-padding) * 2));
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.logo {
|
||||
color: white;
|
||||
background-image: url('/img/logo.svg');
|
||||
height: 50px;
|
||||
background-repeat: no-repeat;
|
||||
display: inline-flex;
|
||||
background-size: contain;
|
||||
background-position: center center;
|
||||
width: 62px;
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
@@ -328,93 +189,16 @@ main {
|
||||
}
|
||||
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
background-color: #0082c9;
|
||||
background-image: linear-gradient(40deg, #0082c9 0%, #30b6ff 100%);
|
||||
height: 50px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
padding: 0 20px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
header > form {
|
||||
margin-left: auto;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
/* Standard styling for enabled checkboxes */
|
||||
input[type="checkbox"]:not(:disabled) {
|
||||
width: var(--checkbox-size);
|
||||
height: var(--checkbox-size);
|
||||
-webkit-appearance: none; /* remove default styling */
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border: 1px solid var(--color-nextcloud-blue);
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
vertical-align: middle; /* align checkbox vertically with text */
|
||||
margin-top: -1px; /* adjust for better alignment */
|
||||
}
|
||||
|
||||
/* Hover effects for enabled checkboxes */
|
||||
input[type="checkbox"]:not(:disabled):hover {
|
||||
border-color: var(--color-info-hover);
|
||||
}
|
||||
|
||||
/* Checkmark styling for enabled checkboxes */
|
||||
input[type="checkbox"]:checked:not(:disabled) {
|
||||
background-color: var(--color-nextcloud-blue);
|
||||
border-color: var(--color-border-maxcontrast);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked:not(:disabled)::after {
|
||||
content: ''; /* Creates a pseudo-element for the checkmark */
|
||||
position: absolute; /* Positions it absolutely */
|
||||
left: 4px; /* Positioning of the checkmark */
|
||||
top: 0; /* Positioning of the checkmark */
|
||||
width: 4px; /* Width of the checkmark */
|
||||
height: 9px; /* Height of the checkmark */
|
||||
border: solid white; /* Color of the checkmark */
|
||||
border-width: 0 2px 3px 0; /* Creates the checkmark shape */
|
||||
transform: rotate(45deg); /* Rotates to form a checkmark */
|
||||
}
|
||||
|
||||
/* Styling for disabled checkboxes (grayed out, no hover, no pointer) */
|
||||
input[type="checkbox"]:disabled:not(:checked) {
|
||||
background-color: var(--color-disabled);
|
||||
border-color: var(--color-border-disabled);
|
||||
cursor: default;
|
||||
opacity: 0.5; /* Makes the checkbox appear faded */
|
||||
}
|
||||
|
||||
/* Styling for disabled checked checkboxes (no pointer) */
|
||||
input[type="checkbox"]:disabled:checked {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:disabled:hover {
|
||||
border-color: var(--color-border-disabled); /* Keeps disabled state without hover effect */
|
||||
}
|
||||
|
||||
/* General Label styling */
|
||||
label {
|
||||
cursor: pointer;
|
||||
margin-left: 4px;
|
||||
line-height: var(--checkbox-size);
|
||||
}
|
||||
|
||||
/* Label cursor for disabled checkboxes */
|
||||
input[type="checkbox"]:disabled + label {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* Label styling for disabled, not checked checkboxes */
|
||||
input[type="checkbox"]:disabled:not(:checked) + label {
|
||||
color: var(--color-text-disabled);
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
@@ -437,9 +221,9 @@ input[type="checkbox"]:disabled:not(:checked) + label {
|
||||
}
|
||||
|
||||
.loader {
|
||||
border: 16px solid var(--color-loader);
|
||||
border: 16px solid #f3f3f3;
|
||||
border-radius: 50%;
|
||||
border-top: 16px solid var(--color-nextcloud-blue);
|
||||
border-top: 16px solid #0082c9;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
-webkit-animation: spin 2s linear infinite; /* Safari */
|
||||
@@ -459,58 +243,3 @@ input[type="checkbox"]:disabled:not(:checked) + label {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* General theme button styling */
|
||||
#theme-toggle {
|
||||
position: fixed; /* Keep the button in the same position */
|
||||
right: 30px; /* Adjust the distance from the right */
|
||||
bottom: 30px; /* Adjust the distance from the bottom */
|
||||
background-color: transparent; /* Make the background transparent */
|
||||
border: none; /* Remove border */
|
||||
font-size: 36px; /* Adjust font size */
|
||||
cursor: pointer; /* Change cursor to pointer */
|
||||
outline: none;
|
||||
z-index: 9999; /* Ensures the icon is on top of every layer */
|
||||
}
|
||||
|
||||
/* Icon styling: default state */
|
||||
#theme-icon {
|
||||
display: inline-block;
|
||||
border-radius: 50%; /* Round shape */
|
||||
position: relative; /* For the pseudo-element positioning */
|
||||
transition: box-shadow 0.3s, background-color 0.3s; /* Smooth transition for hover effect */
|
||||
opacity: 0.6; /* Slightly transparent by default */
|
||||
filter: grayscale(100%); /* Make the icon black and white */
|
||||
}
|
||||
|
||||
/* Create the inner glow effect with ::after */
|
||||
#theme-icon::after {
|
||||
content: ''; /* Empty content for the pseudo-element */
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0px; /* Invisible dot */
|
||||
height: 0px; /* Invisible dot */
|
||||
background-color: transparent; /* Invisible by default */
|
||||
border-radius: 50%; /* Circle shape */
|
||||
transform: translate(-50%, -50%); /* Center the dot */
|
||||
transition: box-shadow 0.3s, background-color 0.3s; /* Smooth transition for hover */
|
||||
}
|
||||
|
||||
/* Hover effect for both light and dark modes */
|
||||
#theme-toggle:hover #theme-icon {
|
||||
position: relative; /* Ensures stacking order */
|
||||
filter: grayscale(0%); /* Restore full color */
|
||||
opacity: 1; /* Fully visible on hover */
|
||||
}
|
||||
|
||||
/* Inner glow when hovered */
|
||||
#theme-toggle:hover #theme-icon::after {
|
||||
box-shadow: 0 0 40px 40px rgba(128, 128, 128, 0.4); /* Blur effect from inside */
|
||||
background-color: rgba(128, 128, 128, 0.2); /* Light glow inside */
|
||||
}
|
||||
|
||||
/* Remove hover effects when not hovering */
|
||||
#theme-toggle:not(:hover) #theme-icon {
|
||||
opacity: 0.6; /* Slightly transparent */
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Function to toggle theme
|
||||
function toggleTheme() {
|
||||
const currentTheme = document.documentElement.getAttribute('data-theme');
|
||||
const newTheme = (currentTheme === 'dark') ? '' : 'dark'; // Toggle between no theme and dark theme
|
||||
document.documentElement.setAttribute('data-theme', newTheme);
|
||||
localStorage.setItem('theme', newTheme);
|
||||
|
||||
// Change the icon based on the current theme
|
||||
const themeIcon = document.getElementById('theme-icon');
|
||||
themeIcon.textContent = newTheme === 'dark' ? '☀️' : '🌙'; // Switch between moon and sun icons
|
||||
}
|
||||
|
||||
// Function to immediately apply saved theme without icon update
|
||||
function applySavedThemeImmediately() {
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme === 'dark') {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
} else {
|
||||
document.documentElement.removeAttribute('data-theme'); // Default to light theme
|
||||
}
|
||||
}
|
||||
|
||||
// Function to apply theme-icon update
|
||||
function setThemeIcon() {
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme === 'dark') {
|
||||
document.getElementById('theme-icon').textContent = '☀️'; // Sun icon for dark mode
|
||||
} else {
|
||||
document.getElementById('theme-icon').textContent = '🌙'; // Moon icon for light mode
|
||||
}
|
||||
}
|
||||
|
||||
// Immediately apply the saved theme to avoid flickering
|
||||
applySavedThemeImmediately();
|
||||
|
||||
// Apply theme when the page loads
|
||||
document.addEventListener('DOMContentLoaded', setThemeIcon);
|
||||
@@ -6,12 +6,12 @@ use AIO\Data\ConfigurationManager;
|
||||
use AIO\Data\DataConst;
|
||||
use \DateTime;
|
||||
|
||||
readonly class AuthManager {
|
||||
class AuthManager {
|
||||
private const string SESSION_KEY = 'aio_authenticated';
|
||||
private ConfigurationManager $configurationManager;
|
||||
|
||||
public function __construct(
|
||||
private ConfigurationManager $configurationManager
|
||||
) {
|
||||
public function __construct(ConfigurationManager $configurationManager) {
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
public function CheckCredentials(string $password) : bool {
|
||||
|
||||
@@ -2,42 +2,92 @@
|
||||
|
||||
namespace AIO\Container;
|
||||
|
||||
use AIO\Container\State\IContainerState;
|
||||
use AIO\Data\ConfigurationManager;
|
||||
use AIO\Docker\DockerActionManager;
|
||||
use AIO\ContainerDefinitionFetcher;
|
||||
|
||||
readonly class Container {
|
||||
class Container {
|
||||
private string $identifier;
|
||||
private string $displayName;
|
||||
private string $containerName;
|
||||
private string $restartPolicy;
|
||||
private int $maxShutdownTime;
|
||||
private ContainerPorts $ports;
|
||||
private string $internalPorts;
|
||||
private ContainerVolumes $volumes;
|
||||
private ContainerEnvironmentVariables $containerEnvironmentVariables;
|
||||
/** @var string[] */
|
||||
private array $dependsOn;
|
||||
/** @var string[] */
|
||||
private array $secrets;
|
||||
/** @var string[] */
|
||||
private array $devices;
|
||||
/** @var string[] */
|
||||
private array $capAdd;
|
||||
private int $shmSize;
|
||||
private bool $apparmorUnconfined;
|
||||
/** @var string[] */
|
||||
private array $backupVolumes;
|
||||
private array $nextcloudExecCommands;
|
||||
private bool $readOnlyRootFs;
|
||||
private array $tmpfs;
|
||||
private bool $init;
|
||||
private string $imageTag;
|
||||
private AioVariables $aioVariables;
|
||||
private string $documentation;
|
||||
private DockerActionManager $dockerActionManager;
|
||||
|
||||
public function __construct(
|
||||
private string $identifier,
|
||||
private string $displayName,
|
||||
private string $containerName,
|
||||
private string $restartPolicy,
|
||||
private int $maxShutdownTime,
|
||||
private ContainerPorts $ports,
|
||||
private string $internalPorts,
|
||||
private ContainerVolumes $volumes,
|
||||
private ContainerEnvironmentVariables $containerEnvironmentVariables,
|
||||
/** @var string[] */
|
||||
private array $dependsOn,
|
||||
/** @var string[] */
|
||||
private array $secrets,
|
||||
/** @var string[] */
|
||||
private array $devices,
|
||||
/** @var string[] */
|
||||
private array $capAdd,
|
||||
private int $shmSize,
|
||||
private bool $apparmorUnconfined,
|
||||
/** @var string[] */
|
||||
private array $backupVolumes,
|
||||
private array $nextcloudExecCommands,
|
||||
private bool $readOnlyRootFs,
|
||||
private array $tmpfs,
|
||||
private bool $init,
|
||||
private string $imageTag,
|
||||
private AioVariables $aioVariables,
|
||||
private string $documentation,
|
||||
private DockerActionManager $dockerActionManager
|
||||
string $identifier,
|
||||
string $displayName,
|
||||
string $containerName,
|
||||
string $restartPolicy,
|
||||
int $maxShutdownTime,
|
||||
ContainerPorts $ports,
|
||||
string $internalPorts,
|
||||
ContainerVolumes $volumes,
|
||||
ContainerEnvironmentVariables $containerEnvironmentVariables,
|
||||
array $dependsOn,
|
||||
array $secrets,
|
||||
array $devices,
|
||||
array $capAdd,
|
||||
int $shmSize,
|
||||
bool $apparmorUnconfined,
|
||||
array $backupVolumes,
|
||||
array $nextcloudExecCommands,
|
||||
bool $readOnlyRootFs,
|
||||
array $tmpfs,
|
||||
bool $init,
|
||||
string $imageTag,
|
||||
AioVariables $aioVariables,
|
||||
string $documentation,
|
||||
DockerActionManager $dockerActionManager
|
||||
) {
|
||||
$this->identifier = $identifier;
|
||||
$this->displayName = $displayName;
|
||||
$this->containerName = $containerName;
|
||||
$this->restartPolicy = $restartPolicy;
|
||||
$this->maxShutdownTime = $maxShutdownTime;
|
||||
$this->ports = $ports;
|
||||
$this->internalPorts = $internalPorts;
|
||||
$this->volumes = $volumes;
|
||||
$this->containerEnvironmentVariables = $containerEnvironmentVariables;
|
||||
$this->dependsOn = $dependsOn;
|
||||
$this->secrets = $secrets;
|
||||
$this->devices = $devices;
|
||||
$this->capAdd = $capAdd;
|
||||
$this->shmSize = $shmSize;
|
||||
$this->apparmorUnconfined = $apparmorUnconfined;
|
||||
$this->backupVolumes = $backupVolumes;
|
||||
$this->nextcloudExecCommands = $nextcloudExecCommands;
|
||||
$this->readOnlyRootFs = $readOnlyRootFs;
|
||||
$this->tmpfs = $tmpfs;
|
||||
$this->init = $init;
|
||||
$this->imageTag = $imageTag;
|
||||
$this->aioVariables = $aioVariables;
|
||||
$this->documentation = $documentation;
|
||||
$this->dockerActionManager = $dockerActionManager;
|
||||
}
|
||||
|
||||
public function GetIdentifier() : string {
|
||||
@@ -112,19 +162,19 @@ readonly class Container {
|
||||
return $this->volumes;
|
||||
}
|
||||
|
||||
public function GetRunningState() : ContainerState {
|
||||
public function GetRunningState() : IContainerState {
|
||||
return $this->dockerActionManager->GetContainerRunningState($this);
|
||||
}
|
||||
|
||||
public function GetRestartingState() : ContainerState {
|
||||
public function GetRestartingState() : IContainerState {
|
||||
return $this->dockerActionManager->GetContainerRestartingState($this);
|
||||
}
|
||||
|
||||
public function GetUpdateState() : VersionState {
|
||||
public function GetUpdateState() : IContainerState {
|
||||
return $this->dockerActionManager->GetContainerUpdateState($this);
|
||||
}
|
||||
|
||||
public function GetStartingState() : ContainerState {
|
||||
public function GetStartingState() : IContainerState {
|
||||
return $this->dockerActionManager->GetContainerStartingState($this);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,17 @@
|
||||
namespace AIO\Container;
|
||||
|
||||
class ContainerPort {
|
||||
public string $port;
|
||||
public string $ipBinding;
|
||||
public string $protocol;
|
||||
|
||||
public function __construct(
|
||||
public string $port,
|
||||
public string $ipBinding,
|
||||
public string $protocol
|
||||
string $port,
|
||||
string $ipBinding,
|
||||
string $protocol
|
||||
) {
|
||||
$this->port = $port;
|
||||
$this->ipBinding = $ipBinding;
|
||||
$this->protocol = $protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container;
|
||||
|
||||
enum ContainerState: string {
|
||||
case ImageDoesNotExist = 'image_does_not_exist';
|
||||
case NotRestarting = 'not_restarting';
|
||||
case Restarting = 'restarting';
|
||||
case Running = 'running';
|
||||
case Starting = 'starting';
|
||||
case Stopped = 'stopped';
|
||||
}
|
||||
@@ -3,10 +3,17 @@
|
||||
namespace AIO\Container;
|
||||
|
||||
class ContainerVolume {
|
||||
public string $name;
|
||||
public string $mountPoint;
|
||||
public bool $isWritable;
|
||||
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public string $mountPoint,
|
||||
public bool $isWritable
|
||||
string $name,
|
||||
string $mountPoint,
|
||||
bool $isWritable
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->mountPoint = $mountPoint;
|
||||
$this->isWritable = $isWritable;
|
||||
}
|
||||
}
|
||||
|
||||
5
php/src/Container/State/IContainerState.php
Normal file
5
php/src/Container/State/IContainerState.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
interface IContainerState {}
|
||||
6
php/src/Container/State/ImageDoesNotExistState.php
Normal file
6
php/src/Container/State/ImageDoesNotExistState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class ImageDoesNotExistState implements IContainerState
|
||||
{}
|
||||
6
php/src/Container/State/NotRestartingState.php
Normal file
6
php/src/Container/State/NotRestartingState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class NotRestartingState implements IContainerState
|
||||
{}
|
||||
6
php/src/Container/State/RestartingState.php
Normal file
6
php/src/Container/State/RestartingState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class RestartingState implements IContainerState
|
||||
{}
|
||||
6
php/src/Container/State/RunningState.php
Normal file
6
php/src/Container/State/RunningState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class RunningState implements IContainerState
|
||||
{}
|
||||
6
php/src/Container/State/StartingState.php
Normal file
6
php/src/Container/State/StartingState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class StartingState implements IContainerState
|
||||
{}
|
||||
6
php/src/Container/State/StoppedState.php
Normal file
6
php/src/Container/State/StoppedState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class StoppedState implements IContainerState
|
||||
{}
|
||||
6
php/src/Container/State/VersionDifferentState.php
Normal file
6
php/src/Container/State/VersionDifferentState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class VersionDifferentState implements IContainerState
|
||||
{}
|
||||
6
php/src/Container/State/VersionEqualState.php
Normal file
6
php/src/Container/State/VersionEqualState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class VersionEqualState implements IContainerState
|
||||
{}
|
||||
@@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container;
|
||||
|
||||
enum VersionState: string {
|
||||
case Different = 'different';
|
||||
case Equal = 'equal';
|
||||
}
|
||||
@@ -9,15 +9,23 @@ use AIO\Container\ContainerPort;
|
||||
use AIO\Container\ContainerPorts;
|
||||
use AIO\Container\ContainerVolume;
|
||||
use AIO\Container\ContainerVolumes;
|
||||
use AIO\Container\State\RunningState;
|
||||
use AIO\Data\ConfigurationManager;
|
||||
use AIO\Data\DataConst;
|
||||
use AIO\Docker\DockerActionManager;
|
||||
|
||||
readonly class ContainerDefinitionFetcher {
|
||||
class ContainerDefinitionFetcher
|
||||
{
|
||||
private ConfigurationManager $configurationManager;
|
||||
private \DI\Container $container;
|
||||
|
||||
public function __construct(
|
||||
private ConfigurationManager $configurationManager,
|
||||
private \DI\Container $container
|
||||
) {
|
||||
ConfigurationManager $configurationManager,
|
||||
\DI\Container $container
|
||||
)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function GetContainerById(string $id): Container
|
||||
@@ -95,7 +103,7 @@ readonly class ContainerDefinitionFetcher {
|
||||
|
||||
$ports = new ContainerPorts();
|
||||
if (isset($entry['ports'])) {
|
||||
foreach ($entry['ports'] as $value) {
|
||||
foreach ($entry['ports'] as $value) {
|
||||
$ports->AddPort(
|
||||
new ContainerPort(
|
||||
$value['port_number'],
|
||||
@@ -204,7 +212,7 @@ readonly class ContainerDefinitionFetcher {
|
||||
$dependsOn[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$variables = new ContainerEnvironmentVariables();
|
||||
if (isset($entry['environment'])) {
|
||||
foreach ($entry['environment'] as $value) {
|
||||
|
||||
@@ -9,10 +9,14 @@ use AIO\Docker\DockerActionManager;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
readonly class ConfigurationController {
|
||||
class ConfigurationController
|
||||
{
|
||||
private ConfigurationManager $configurationManager;
|
||||
|
||||
public function __construct(
|
||||
private ConfigurationManager $configurationManager
|
||||
ConfigurationManager $configurationManager
|
||||
) {
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
public function SetConfig(Request $request, Response $response, array $args) : Response {
|
||||
@@ -28,17 +32,15 @@ readonly class ConfigurationController {
|
||||
$this->configurationManager->ChangeMasterPassword($currentMasterPassword, $newMasterPassword);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['borg_backup_host_location']) || isset($request->getParsedBody()['borg_remote_repo'])) {
|
||||
if (isset($request->getParsedBody()['borg_backup_host_location'])) {
|
||||
$location = $request->getParsedBody()['borg_backup_host_location'] ?? '';
|
||||
$borgRemoteRepo = $request->getParsedBody()['borg_remote_repo'] ?? '';
|
||||
$this->configurationManager->SetBorgLocationVars($location, $borgRemoteRepo);
|
||||
$this->configurationManager->SetBorgBackupHostLocation($location);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['borg_restore_host_location']) || isset($request->getParsedBody()['borg_restore_remote_repo']) || isset($request->getParsedBody()['borg_restore_password'])) {
|
||||
if (isset($request->getParsedBody()['borg_restore_host_location']) || isset($request->getParsedBody()['borg_restore_password'])) {
|
||||
$restoreLocation = $request->getParsedBody()['borg_restore_host_location'] ?? '';
|
||||
$borgRemoteRepo = $request->getParsedBody()['borg_restore_remote_repo'] ?? '';
|
||||
$borgPassword = $request->getParsedBody()['borg_restore_password'] ?? '';
|
||||
$this->configurationManager->SetBorgRestoreLocationVarsAndPassword($restoreLocation, $borgRemoteRepo, $borgPassword);
|
||||
$this->configurationManager->SetBorgRestoreHostLocationAndPassword($restoreLocation, $borgPassword);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['daily_backup_time'])) {
|
||||
@@ -134,8 +136,8 @@ readonly class ConfigurationController {
|
||||
$this->configurationManager->SetCollaboraDictionaries($collaboraDictionaries);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['delete_borg_backup_location_vars'])) {
|
||||
$this->configurationManager->DeleteBorgBackupLocationVars();
|
||||
if (isset($request->getParsedBody()['delete_borg_backup_host_location'])) {
|
||||
$this->configurationManager->DeleteBorgBackupHostLocation();
|
||||
}
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '/');
|
||||
|
||||
@@ -2,21 +2,28 @@
|
||||
|
||||
namespace AIO\Controller;
|
||||
|
||||
use AIO\Container\ContainerState;
|
||||
use AIO\Container\State\RunningState;
|
||||
use AIO\ContainerDefinitionFetcher;
|
||||
use AIO\Docker\DockerActionManager;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use AIO\Data\ConfigurationManager;
|
||||
|
||||
readonly class DockerController {
|
||||
class DockerController
|
||||
{
|
||||
private DockerActionManager $dockerActionManager;
|
||||
private ContainerDefinitionFetcher $containerDefinitionFetcher;
|
||||
private const string TOP_CONTAINER = 'nextcloud-aio-apache';
|
||||
private ConfigurationManager $configurationManager;
|
||||
|
||||
public function __construct(
|
||||
private DockerActionManager $dockerActionManager,
|
||||
private ContainerDefinitionFetcher $containerDefinitionFetcher,
|
||||
private ConfigurationManager $configurationManager
|
||||
DockerActionManager $dockerActionManager,
|
||||
ContainerDefinitionFetcher $containerDefinitionFetcher,
|
||||
ConfigurationManager $configurationManager
|
||||
) {
|
||||
$this->dockerActionManager = $dockerActionManager;
|
||||
$this->containerDefinitionFetcher = $containerDefinitionFetcher;
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
private function PerformRecursiveContainerStart(string $id, bool $pullImage = true) : void {
|
||||
@@ -28,7 +35,7 @@ readonly class DockerController {
|
||||
|
||||
// Don't start if container is already running
|
||||
// This is expected to happen if a container is defined in depends_on of multiple containers
|
||||
if ($container->GetRunningState() === ContainerState::Running) {
|
||||
if ($container->GetRunningState() instanceof RunningState) {
|
||||
error_log('Not starting ' . $id . ' because it was already started.');
|
||||
return;
|
||||
}
|
||||
@@ -41,7 +48,7 @@ readonly 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)) {
|
||||
@@ -113,11 +120,6 @@ readonly class DockerController {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'restore';
|
||||
$config['selected-restore-time'] = $request->getParsedBody()['selected_restore_time'] ?? '';
|
||||
if (isset($request->getParsedBody()['restore-exclude-previews'])) {
|
||||
$config['restore-exclude-previews'] = 1;
|
||||
} else {
|
||||
$config['restore-exclude-previews'] = '';
|
||||
}
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
@@ -259,10 +261,10 @@ readonly class DockerController {
|
||||
$domaincheckContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById(self::TOP_CONTAINER);
|
||||
// Don't start if apache is already running
|
||||
if ($apacheContainer->GetRunningState() === ContainerState::Running) {
|
||||
if ($apacheContainer->GetRunningState() instanceof RunningState) {
|
||||
return;
|
||||
// Don't start if domaincheck is already running
|
||||
} elseif ($domaincheckContainer->GetRunningState() === ContainerState::Running) {
|
||||
} elseif ($domaincheckContainer->GetRunningState() instanceof RunningState) {
|
||||
$domaincheckWasStarted = apcu_fetch($cacheKey);
|
||||
// Start domaincheck again when 10 minutes are over by not returning here
|
||||
if($domaincheckWasStarted !== false && is_string($domaincheckWasStarted)) {
|
||||
|
||||
@@ -9,11 +9,14 @@ use AIO\Docker\DockerActionManager;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
readonly class LoginController {
|
||||
public function __construct(
|
||||
private AuthManager $authManager,
|
||||
private DockerActionManager $dockerActionManager,
|
||||
) {
|
||||
class LoginController
|
||||
{
|
||||
private AuthManager $authManager;
|
||||
private DockerActionManager $dockerActionManager;
|
||||
|
||||
public function __construct(AuthManager $authManager, DockerActionManager $dockerActionManager) {
|
||||
$this->authManager = $authManager;
|
||||
$this->dockerActionManager = $dockerActionManager;
|
||||
}
|
||||
|
||||
public function TryLogin(Request $request, Response $response, array $args) : Response {
|
||||
|
||||
@@ -71,7 +71,7 @@ class ConfigurationManager
|
||||
if (!file_exists(DataConst::GetBackupArchivesList())) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
$content = file_get_contents(DataConst::GetBackupArchivesList());
|
||||
if ($content === '') {
|
||||
return '';
|
||||
@@ -91,7 +91,7 @@ class ConfigurationManager
|
||||
if ($lastBackupTime === "") {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
return $lastBackupTime;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ class ConfigurationManager
|
||||
if (!file_exists(DataConst::GetBackupArchivesList())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
$content = file_get_contents(DataConst::GetBackupArchivesList());
|
||||
if ($content === '') {
|
||||
return [];
|
||||
@@ -110,7 +110,7 @@ class ConfigurationManager
|
||||
foreach($backupLines as $lines) {
|
||||
if ($lines !== "") {
|
||||
$backupTimesTemp = explode(',', $lines);
|
||||
$backupTimes[] = $backupTimesTemp[1];
|
||||
$backupTimes[] = $backupTimesTemp[1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ class ConfigurationManager
|
||||
if (!$this->isx64Platform()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isClamavEnabled']) && $config['isClamavEnabled'] === 1) {
|
||||
return true;
|
||||
@@ -364,7 +364,7 @@ class ConfigurationManager
|
||||
$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_CONNECTTIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
$response = (string)curl_exec($ch);
|
||||
# Get rid of trailing \n
|
||||
@@ -427,15 +427,6 @@ class ConfigurationManager
|
||||
return $config['selected-restore-time'];
|
||||
}
|
||||
|
||||
public function GetRestoreExcludePreviews() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['restore-exclude-previews'])) {
|
||||
$config['restore-exclude-previews'] = '';
|
||||
}
|
||||
|
||||
return $config['restore-exclude-previews'];
|
||||
}
|
||||
|
||||
public function GetAIOURL() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['AIO_URL'])) {
|
||||
@@ -448,61 +439,48 @@ class ConfigurationManager
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetBorgLocationVars(string $location, string $repo) : void {
|
||||
$this->ValidateBorgLocationVars($location, $repo);
|
||||
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;
|
||||
$config['borg_remote_repo'] = $repo;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
private function ValidateBorgLocationVars(string $location, string $repo) : void {
|
||||
if ($location === '' && $repo === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter a path or a remote repo url!");
|
||||
} elseif ($location !== '' && $repo !== '') {
|
||||
throw new InvalidSettingConfigurationException("Location and remote repo url are mutually exclusive!");
|
||||
}
|
||||
|
||||
if ($location !== '') {
|
||||
$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 '/'!");
|
||||
}
|
||||
} else {
|
||||
$this->ValidateBorgRemoteRepo($repo);
|
||||
}
|
||||
}
|
||||
|
||||
private function ValidateBorgRemoteRepo(string $repo) : void {
|
||||
$commonMsg = "For valid urls, see the remote examples at https://borgbackup.readthedocs.io/en/stable/usage/general.html#repository-urls";
|
||||
if ($repo === "") {
|
||||
// Ok, remote repo is optional
|
||||
} elseif (!str_contains($repo, "@")) {
|
||||
throw new InvalidSettingConfigurationException("The remote repo must contain '@'. $commonMsg");
|
||||
} elseif (!str_contains($repo, ":")) {
|
||||
throw new InvalidSettingConfigurationException("The remote repo must contain ':'. $commonMsg");
|
||||
}
|
||||
}
|
||||
|
||||
public function DeleteBorgBackupLocationVars() : void {
|
||||
public function DeleteBorgBackupHostLocation() : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['borg_backup_host_location'] = '';
|
||||
$config['borg_remote_repo'] = '';
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetBorgRestoreLocationVarsAndPassword(string $location, string $repo, string $password) : void {
|
||||
$this->ValidateBorgLocationVars($location, $repo);
|
||||
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!");
|
||||
@@ -510,7 +488,6 @@ class ConfigurationManager
|
||||
|
||||
$config = $this->GetConfig();
|
||||
$config['borg_backup_host_location'] = $location;
|
||||
$config['borg_remote_repo'] = $repo;
|
||||
$config['borg_restore_password'] = $password;
|
||||
$config['instance_restore_attempt'] = 1;
|
||||
$this->WriteConfig($config);
|
||||
@@ -558,6 +535,10 @@ class ConfigurationManager
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function IsOverwriteEnable() : bool {
|
||||
return getenv('DISABLE_OVERWRITE_URL') !== 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
@@ -605,23 +586,6 @@ class ConfigurationManager
|
||||
return $config['borg_backup_host_location'];
|
||||
}
|
||||
|
||||
public function GetBorgRemoteRepo() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['borg_remote_repo'])) {
|
||||
$config['borg_remote_repo'] = '';
|
||||
}
|
||||
|
||||
return $config['borg_remote_repo'];
|
||||
}
|
||||
|
||||
public function GetBorgPublicKey() : string {
|
||||
if (!file_exists(DataConst::GetBackupPublicKey())) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return trim(file_get_contents(DataConst::GetBackupPublicKey()));
|
||||
}
|
||||
|
||||
public function GetBorgRestorePassword() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['borg_restore_password'])) {
|
||||
@@ -753,7 +717,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 {
|
||||
@@ -928,13 +892,6 @@ class ConfigurationManager
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function GetApacheAdditionalNetwork() : string {
|
||||
$envVariableName = 'APACHE_ADDITIONAL_NETWORK';
|
||||
$configName = 'apache_additional_network';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetApacheIPBinding() : string {
|
||||
$envVariableName = 'APACHE_IP_BINDING';
|
||||
$configName = 'apache_ip_binding';
|
||||
|
||||
@@ -23,10 +23,6 @@ class DataConst {
|
||||
return self::GetDataDirectory() . '/configuration.json';
|
||||
}
|
||||
|
||||
public static function GetBackupPublicKey() : string {
|
||||
return self::GetDataDirectory() . '/id_borg.pub';
|
||||
}
|
||||
|
||||
public static function GetBackupSecretFile() : string {
|
||||
return self::GetDataDirectory() . '/backupsecret';
|
||||
}
|
||||
|
||||
@@ -4,11 +4,16 @@ namespace AIO\Data;
|
||||
|
||||
use AIO\Auth\PasswordGenerator;
|
||||
|
||||
readonly class Setup {
|
||||
class Setup
|
||||
{
|
||||
private PasswordGenerator $passwordGenerator;
|
||||
private ConfigurationManager $configurationManager;
|
||||
|
||||
public function __construct(
|
||||
private PasswordGenerator $passwordGenerator,
|
||||
private ConfigurationManager $configurationManager,
|
||||
) {
|
||||
PasswordGenerator $passwordGenerator,
|
||||
ConfigurationManager $configurationManager) {
|
||||
$this->passwordGenerator = $passwordGenerator;
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
public function Setup() : string {
|
||||
|
||||
@@ -3,24 +3,44 @@
|
||||
namespace AIO\Docker;
|
||||
|
||||
use AIO\Container\Container;
|
||||
use AIO\Container\VersionState;
|
||||
use AIO\Container\ContainerState;
|
||||
use AIO\Container\State\IContainerState;
|
||||
use AIO\Container\State\ImageDoesNotExistState;
|
||||
use AIO\Container\State\StartingState;
|
||||
use AIO\Container\State\RunningState;
|
||||
use AIO\Container\State\RestartingState;
|
||||
use AIO\Container\State\NotRestartingState;
|
||||
use AIO\Container\State\VersionDifferentState;
|
||||
use AIO\Container\State\StoppedState;
|
||||
use AIO\Container\State\VersionEqualState;
|
||||
use AIO\Data\ConfigurationManager;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use AIO\ContainerDefinitionFetcher;
|
||||
use http\Env\Response;
|
||||
|
||||
readonly class DockerActionManager {
|
||||
class DockerActionManager
|
||||
{
|
||||
private const string API_VERSION = 'v1.41';
|
||||
private Client $guzzleClient;
|
||||
private \GuzzleHttp\Client $guzzleClient;
|
||||
private ConfigurationManager $configurationManager;
|
||||
private ContainerDefinitionFetcher $containerDefinitionFetcher;
|
||||
private DockerHubManager $dockerHubManager;
|
||||
|
||||
public function __construct(
|
||||
private ConfigurationManager $configurationManager,
|
||||
private ContainerDefinitionFetcher $containerDefinitionFetcher,
|
||||
private DockerHubManager $dockerHubManager
|
||||
ConfigurationManager $configurationManager,
|
||||
ContainerDefinitionFetcher $containerDefinitionFetcher,
|
||||
DockerHubManager $dockerHubManager
|
||||
) {
|
||||
$this->guzzleClient = new Client(['curl' => [CURLOPT_UNIX_SOCKET_PATH => '/var/run/docker.sock']]);
|
||||
$this->configurationManager = $configurationManager;
|
||||
$this->containerDefinitionFetcher = $containerDefinitionFetcher;
|
||||
$this->dockerHubManager = $dockerHubManager;
|
||||
$this->guzzleClient = new \GuzzleHttp\Client(
|
||||
[
|
||||
'curl' => [
|
||||
CURLOPT_UNIX_SOCKET_PATH => '/var/run/docker.sock',
|
||||
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private function BuildApiUrl(string $url) : string {
|
||||
@@ -35,14 +55,14 @@ readonly class DockerActionManager {
|
||||
return $container->GetContainerName() . ':' . $tag;
|
||||
}
|
||||
|
||||
public function GetContainerRunningState(Container $container) : ContainerState
|
||||
public function GetContainerRunningState(Container $container) : IContainerState
|
||||
{
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
|
||||
try {
|
||||
$response = $this->guzzleClient->get($url);
|
||||
} catch (RequestException $e) {
|
||||
if ($e->getCode() === 404) {
|
||||
return ContainerState::ImageDoesNotExist;
|
||||
return new ImageDoesNotExistState();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
@@ -50,20 +70,20 @@ readonly class DockerActionManager {
|
||||
$responseBody = json_decode((string)$response->getBody(), true);
|
||||
|
||||
if ($responseBody['State']['Running'] === true) {
|
||||
return ContainerState::Running;
|
||||
return new RunningState();
|
||||
} else {
|
||||
return ContainerState::Stopped;
|
||||
return new StoppedState();
|
||||
}
|
||||
}
|
||||
|
||||
public function GetContainerRestartingState(Container $container) : ContainerState
|
||||
public function GetContainerRestartingState(Container $container) : IContainerState
|
||||
{
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
|
||||
try {
|
||||
$response = $this->guzzleClient->get($url);
|
||||
} catch (RequestException $e) {
|
||||
if ($e->getCode() === 404) {
|
||||
return ContainerState::ImageDoesNotExist;
|
||||
return new ImageDoesNotExistState();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
@@ -71,13 +91,13 @@ readonly class DockerActionManager {
|
||||
$responseBody = json_decode((string)$response->getBody(), true);
|
||||
|
||||
if ($responseBody['State']['Restarting'] === true) {
|
||||
return ContainerState::Restarting;
|
||||
return new RestartingState();
|
||||
} else {
|
||||
return ContainerState::NotRestarting;
|
||||
return new NotRestartingState();
|
||||
}
|
||||
}
|
||||
|
||||
public function GetContainerUpdateState(Container $container) : VersionState
|
||||
public function GetContainerUpdateState(Container $container) : IContainerState
|
||||
{
|
||||
$tag = $container->GetImageTag();
|
||||
if ($tag === '%AIO_CHANNEL%') {
|
||||
@@ -86,26 +106,28 @@ readonly class DockerActionManager {
|
||||
|
||||
$runningDigests = $this->GetRepoDigestsOfContainer($container->GetIdentifier());
|
||||
if ($runningDigests === null) {
|
||||
return VersionState::Different;
|
||||
return new VersionDifferentState();
|
||||
}
|
||||
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($container->GetContainerName(), $tag);
|
||||
if ($remoteDigest === null) {
|
||||
return VersionState::Equal;
|
||||
return new VersionEqualstate();
|
||||
}
|
||||
|
||||
foreach($runningDigests as $runningDigest) {
|
||||
if ($runningDigest === $remoteDigest) {
|
||||
return VersionState::Equal;
|
||||
return new VersionEqualState();
|
||||
}
|
||||
}
|
||||
return VersionState::Different;
|
||||
return new VersionDifferentState();
|
||||
}
|
||||
|
||||
public function GetContainerStartingState(Container $container) : ContainerState
|
||||
public function GetContainerStartingState(Container $container) : IContainerState
|
||||
{
|
||||
$runningState = $this->GetContainerRunningState($container);
|
||||
if ($runningState === ContainerState::Stopped || $runningState === ContainerState::ImageDoesNotExist) {
|
||||
return $runningState;
|
||||
if ($runningState instanceof StoppedState) {
|
||||
return new StoppedState();
|
||||
} elseif ($runningState instanceof ImageDoesNotExistState) {
|
||||
return new ImageDoesNotExistState();
|
||||
}
|
||||
|
||||
$containerName = $container->GetIdentifier();
|
||||
@@ -120,12 +142,12 @@ readonly class DockerActionManager {
|
||||
$connection = @fsockopen($containerName, (int)$internalPort, $errno, $errstr, 0.2);
|
||||
if ($connection) {
|
||||
fclose($connection);
|
||||
return ContainerState::Running;
|
||||
return new RunningState();
|
||||
} else {
|
||||
return ContainerState::Starting;
|
||||
return new StartingState();
|
||||
}
|
||||
} else {
|
||||
return ContainerState::Running;
|
||||
return new RunningState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,20 +287,28 @@ readonly class DockerActionManager {
|
||||
$replacements[1] = $this->configurationManager->GetBaseDN();
|
||||
} elseif ($out[1] === 'AIO_TOKEN') {
|
||||
$replacements[1] = $this->configurationManager->GetToken();
|
||||
} elseif ($out[1] === 'BORGBACKUP_REMOTE_REPO') {
|
||||
$replacements[1] = $this->configurationManager->GetBorgRemoteRepo();
|
||||
} elseif ($out[1] === 'BORGBACKUP_MODE') {
|
||||
$replacements[1] = $this->configurationManager->GetBackupMode();
|
||||
} elseif ($out[1] === 'AIO_URL') {
|
||||
$replacements[1] = $this->configurationManager->GetAIOURL();
|
||||
} elseif ($out[1] === 'SELECTED_RESTORE_TIME') {
|
||||
$replacements[1] = $this->configurationManager->GetSelectedRestoreTime();
|
||||
} elseif ($out[1] === 'RESTORE_EXCLUDE_PREVIEWS') {
|
||||
$replacements[1] = $this->configurationManager->GetRestoreExcludePreviews();
|
||||
} elseif ($out[1] === 'APACHE_PORT') {
|
||||
$replacements[1] = $this->configurationManager->GetApachePort();
|
||||
} elseif ($out[1] === 'TALK_PORT') {
|
||||
$replacements[1] = $this->configurationManager->GetTalkPort();
|
||||
} elseif($out[1] === 'OVERWRITEHOST') {
|
||||
if ($this->configurationManager->IsOverwriteEnable()) {
|
||||
$replacements[1] = $this->configurationManager->GetDomain();
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif($out[1] === 'OVERWRITEPROTOCOL') {
|
||||
if ($this->configurationManager->IsOverwriteEnable()) {
|
||||
$replacements[1] = 'https';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'NEXTCLOUD_MOUNT') {
|
||||
$replacements[1] = $this->configurationManager->GetNextcloudMount();
|
||||
} elseif ($out[1] === 'BACKUP_RESTORE_PASSWORD') {
|
||||
@@ -623,7 +653,7 @@ readonly class DockerActionManager {
|
||||
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
|
||||
$updateAvailable = "";
|
||||
if ($container->GetUpdateState() === VersionState::Different) {
|
||||
if ($container->GetUpdateState() instanceof VersionDifferentState) {
|
||||
$updateAvailable = '1';
|
||||
}
|
||||
foreach ($container->GetDependsOn() as $dependency) {
|
||||
@@ -740,13 +770,16 @@ readonly class DockerActionManager {
|
||||
$output = json_decode($this->guzzleClient->get($url)->getBody()->getContents(), true);
|
||||
$containerChecksum = $output['Image'];
|
||||
$tagArray = explode(':', $output['Config']['Image']);
|
||||
if (count($tagArray) === 2) {
|
||||
$tag = $tagArray[1];
|
||||
} else {
|
||||
$tag = $tagArray[1];
|
||||
apcu_add($cacheKey, $tag);
|
||||
/**
|
||||
* @psalm-suppress TypeDoesNotContainNull
|
||||
* @psalm-suppress DocblockTypeContradiction
|
||||
*/
|
||||
if ($tag === null) {
|
||||
error_log("No tag was found when getting the current channel. You probably did not follow the documentation correctly. Changing the channel to the default 'latest'.");
|
||||
$tag = 'latest';
|
||||
}
|
||||
apcu_add($cacheKey, $tag);
|
||||
return $tag;
|
||||
} catch (\Exception $e) {
|
||||
error_log('Could not get current channel ' . $e->getMessage());
|
||||
@@ -781,7 +814,7 @@ readonly class DockerActionManager {
|
||||
|
||||
public function sendNotification(Container $container, string $subject, string $message, string $file = '/notify.sh') : void
|
||||
{
|
||||
if ($this->GetContainerStartingState($container) === ContainerState::Running) {
|
||||
if ($this->GetContainerStartingState($container) instanceof RunningState) {
|
||||
|
||||
$containerName = $container->GetIdentifier();
|
||||
|
||||
@@ -845,49 +878,44 @@ readonly class DockerActionManager {
|
||||
}
|
||||
}
|
||||
|
||||
private function ConnectContainerIdToNetwork(string $id, string $internalPort, string $network = 'nextcloud-aio', bool $createNetwork = true, string $alias = '') : void
|
||||
private function ConnectContainerIdToNetwork(string $id, string $internalPort, string $network = 'nextcloud-aio') : void
|
||||
{
|
||||
if ($internalPort === 'host') {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($createNetwork) {
|
||||
$url = $this->BuildApiUrl('networks/create');
|
||||
try {
|
||||
$this->guzzleClient->request(
|
||||
'POST',
|
||||
$url,
|
||||
[
|
||||
'json' => [
|
||||
'Name' => $network,
|
||||
'CheckDuplicate' => true,
|
||||
'Driver' => 'bridge',
|
||||
'Internal' => false,
|
||||
]
|
||||
$url = $this->BuildApiUrl('networks/create');
|
||||
try {
|
||||
$this->guzzleClient->request(
|
||||
'POST',
|
||||
$url,
|
||||
[
|
||||
'json' => [
|
||||
'Name' => $network,
|
||||
'CheckDuplicate' => true,
|
||||
'Driver' => 'bridge',
|
||||
'Internal' => false,
|
||||
]
|
||||
);
|
||||
} catch (RequestException $e) {
|
||||
// 409 is undocumented and gets thrown if the network already exists.
|
||||
if ($e->getCode() !== 409) {
|
||||
throw new \Exception("Could not create the nextcloud-aio network: " . $e->getMessage());
|
||||
}
|
||||
]
|
||||
);
|
||||
} catch (RequestException $e) {
|
||||
// 409 is undocumented and gets thrown if the network already exists.
|
||||
if ($e->getCode() !== 409) {
|
||||
throw new \Exception("Could not create the nextcloud-aio network: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$url = $this->BuildApiUrl(
|
||||
sprintf('networks/%s/connect', $network)
|
||||
);
|
||||
$jsonPayload = [ 'Container' => $id ];
|
||||
if ($alias !== '' ) {
|
||||
$jsonPayload['EndpointConfig'] = ['Aliases' => [ $alias ]];
|
||||
}
|
||||
|
||||
try {
|
||||
$this->guzzleClient->request(
|
||||
'POST',
|
||||
$url,
|
||||
[
|
||||
'json' => $jsonPayload
|
||||
'json' => [
|
||||
'container' => $id,
|
||||
]
|
||||
]
|
||||
);
|
||||
} catch (RequestException $e) {
|
||||
@@ -907,19 +935,7 @@ readonly class DockerActionManager {
|
||||
|
||||
public function ConnectContainerToNetwork(Container $container) : void
|
||||
{
|
||||
// Add a secondary alias for domaincheck container, to keep it as similar to actual apache controller as possible.
|
||||
// If a reverse-proxy is relying on container name as hostname this allows it to operate as usual and still validate the domain
|
||||
// The domaincheck container and apache container are never supposed to be active at the same time because they use the same APACHE_PORT anyway, so this doesn't add any new constraints.
|
||||
$alias = ($container->GetIdentifier() === 'nextcloud-aio-domaincheck') ? 'nextcloud-aio-apache' : '';
|
||||
|
||||
$this->ConnectContainerIdToNetwork($container->GetIdentifier(), $container->GetInternalPort(), alias: $alias);
|
||||
|
||||
if ($container->GetIdentifier() === 'nextcloud-aio-apache' || $container->GetIdentifier() === 'nextcloud-aio-domaincheck') {
|
||||
$apacheAdditionalNetwork = $this->configurationManager->GetApacheAdditionalNetwork();
|
||||
if ($apacheAdditionalNetwork !== '') {
|
||||
$this->ConnectContainerIdToNetwork($container->GetIdentifier(), $container->GetInternalPort(), $apacheAdditionalNetwork, false, $alias);
|
||||
}
|
||||
}
|
||||
$this->ConnectContainerIdToNetwork($container->GetIdentifier(), $container->GetInternalPort());
|
||||
}
|
||||
|
||||
public function StopContainer(Container $container) : void {
|
||||
@@ -982,7 +998,7 @@ readonly class DockerActionManager {
|
||||
public function isLoginAllowed() : bool {
|
||||
$id = 'nextcloud-aio-apache';
|
||||
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
if ($this->GetContainerStartingState($apacheContainer) === ContainerState::Running) {
|
||||
if ($this->GetContainerStartingState($apacheContainer) instanceof RunningState) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -991,7 +1007,7 @@ readonly class DockerActionManager {
|
||||
public function isBackupContainerRunning() : bool {
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$backupContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
if ($this->GetContainerRunningState($backupContainer) === ContainerState::Running) {
|
||||
if ($this->GetContainerRunningState($backupContainer) instanceof RunningState) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -6,11 +6,12 @@ use AIO\ContainerDefinitionFetcher;
|
||||
use AIO\Data\ConfigurationManager;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
readonly class DockerHubManager {
|
||||
class DockerHubManager
|
||||
{
|
||||
private Client $guzzleClient;
|
||||
|
||||
public function __construct(
|
||||
) {
|
||||
public function __construct()
|
||||
{
|
||||
$this->guzzleClient = new Client();
|
||||
}
|
||||
|
||||
@@ -58,4 +59,4 @@ readonly class DockerHubManager {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,12 @@ use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
readonly class AuthMiddleware {
|
||||
public function __construct(
|
||||
private AuthManager $authManager
|
||||
) {
|
||||
class AuthMiddleware
|
||||
{
|
||||
private AuthManager $authManager;
|
||||
|
||||
public function __construct(AuthManager $authManager) {
|
||||
$this->authManager = $authManager;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
|
||||
@@ -3,13 +3,17 @@
|
||||
namespace AIO\Twig;
|
||||
|
||||
use Slim\Csrf\Guard;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\Extension\GlobalsInterface;
|
||||
|
||||
class CsrfExtension extends AbstractExtension implements GlobalsInterface {
|
||||
public function __construct(
|
||||
protected Guard $csrf
|
||||
) {
|
||||
class CsrfExtension extends \Twig\Extension\AbstractExtension implements \Twig\Extension\GlobalsInterface
|
||||
{
|
||||
/**
|
||||
* @var Guard
|
||||
*/
|
||||
protected Guard $csrf;
|
||||
|
||||
public function __construct(Guard $csrf)
|
||||
{
|
||||
$this->csrf = $csrf;
|
||||
}
|
||||
|
||||
public function getGlobals() : array
|
||||
@@ -31,4 +35,4 @@ class CsrfExtension extends AbstractExtension implements GlobalsInterface {
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,5 @@
|
||||
{% extends "layout.twig" %}
|
||||
|
||||
{% block body %}
|
||||
<div class="login">
|
||||
<svg class="nextcloud-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 142 100" width="142" height="100">
|
||||
<use href="/img/nextcloud-logo.svg#logo"></use>
|
||||
<use href="/img/nextcloud-logo.svg#Nextcloud"></use>
|
||||
<text x="10" y="50" fill="var(--color-nextcloud-logo)" class="fallback-text">Nextcloud Logo</text>
|
||||
</svg>
|
||||
<h2>Nextcloud All-In-One is already installed</h2>
|
||||
<a href="/" class="button">Open Nextcloud AIO</a>
|
||||
</div>
|
||||
Already installed.
|
||||
{% endblock %}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user