mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-05-22 11:20:13 +00:00
Compare commits
245 Commits
v12.7.0
...
translatio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ffc810c0b | ||
|
|
b4efbed23f | ||
|
|
021854144b | ||
|
|
228f785987 | ||
|
|
7c8cabdb2d | ||
|
|
7049448541 | ||
|
|
35dd0a2c00 | ||
|
|
fbe60b852c | ||
|
|
5782a01b7f | ||
|
|
46b325f2bd | ||
|
|
05f9fa0e25 | ||
|
|
443f3a4bee | ||
|
|
d280786934 | ||
|
|
253df4ee0c | ||
|
|
8073f3c562 | ||
|
|
a3dac35edb | ||
|
|
b222639bbd | ||
|
|
a5d4f2dd88 | ||
|
|
51c7b270b4 | ||
|
|
754a317fea | ||
|
|
7f35ee5fbb | ||
|
|
b7b6cc8a16 | ||
|
|
7dc489168a | ||
|
|
d71683ff38 | ||
|
|
d4743d9800 | ||
|
|
f1b635c196 | ||
|
|
ecd85281cc | ||
|
|
558e8735b5 | ||
|
|
e0ff3acb3d | ||
|
|
4963558691 | ||
|
|
90d5d6bcf1 | ||
|
|
b19c6dfddb | ||
|
|
904921c815 | ||
|
|
7d63b13a40 | ||
|
|
83102e46b2 | ||
|
|
9e49f81c43 | ||
|
|
25a63abbc8 | ||
|
|
f1eeea9337 | ||
|
|
156e55d0ad | ||
|
|
c5501c885d | ||
|
|
de7b5cd8e4 | ||
|
|
d6981be067 | ||
|
|
0755000456 | ||
|
|
b169790488 | ||
|
|
9a6b74dd16 | ||
|
|
b28572e67f | ||
|
|
8b2a4c057a | ||
|
|
669ea45749 | ||
|
|
1e76d39742 | ||
|
|
c2e7990d33 | ||
|
|
1821e695aa | ||
|
|
d761f22fa1 | ||
|
|
3738890c05 | ||
|
|
726e639f0b | ||
|
|
8bac8f029f | ||
|
|
828b7784f7 | ||
|
|
0cb0d86471 | ||
|
|
1b69fb88ae | ||
|
|
6fd537cd5d | ||
|
|
11dbc4978d | ||
|
|
43de29e071 | ||
|
|
eed853e942 | ||
|
|
bdb8e171f7 | ||
|
|
68c5dc8d60 | ||
|
|
dfe7eb7ec1 | ||
|
|
2016789bea | ||
|
|
b0969d9644 | ||
|
|
6e8c8dab19 | ||
|
|
1e23c1a6dd | ||
|
|
c4f4ff22c9 | ||
|
|
a7703283dc | ||
|
|
9ce33d1d1d | ||
|
|
d86eee5847 | ||
|
|
eda48383b4 | ||
|
|
7302b48fcf | ||
|
|
26c0d6204b | ||
|
|
4ee7f573e6 | ||
|
|
04e424b3a7 | ||
|
|
ba3ee91c35 | ||
|
|
c24f9c1642 | ||
|
|
50b309c5a2 | ||
|
|
1419f29d2b | ||
|
|
9a37170f08 | ||
|
|
1e4e040dad | ||
|
|
ad534c83cc | ||
|
|
26aced2126 | ||
|
|
2ce73190e2 | ||
|
|
585a8ef13b | ||
|
|
a97877ee6b | ||
|
|
203b1a335e | ||
|
|
109f2493af | ||
|
|
9ed23f1952 | ||
|
|
385eeb1621 | ||
|
|
ee4df40708 | ||
|
|
2999fb4413 | ||
|
|
1620f83bf7 | ||
|
|
eccfa8b9d9 | ||
|
|
9b64fff193 | ||
|
|
349443c240 | ||
|
|
49d743c17c | ||
|
|
c45913a6ff | ||
|
|
7f394f5297 | ||
|
|
e561fad2af | ||
|
|
eb9cb26ff1 | ||
|
|
1022b408a7 | ||
|
|
ee137e497a | ||
|
|
71b384be64 | ||
|
|
7922d38aa6 | ||
|
|
dd103fa0f1 | ||
|
|
909ef96748 | ||
|
|
978a4ce282 | ||
|
|
b972c5703f | ||
|
|
8c3b5b2e21 | ||
|
|
6e87758ba9 | ||
|
|
4b1c7286bc | ||
|
|
510032d7a1 | ||
|
|
b248710803 | ||
|
|
9040ccdab8 | ||
|
|
c7041c4f6f | ||
|
|
23f5ae2a10 | ||
|
|
ea326ba723 | ||
|
|
b4db823d9b | ||
|
|
61e6e233f4 | ||
|
|
1abb0e2b94 | ||
|
|
31999ade2e | ||
|
|
744efad0f4 | ||
|
|
11553a3c0f | ||
|
|
0cdbf3aa96 | ||
|
|
2d4903492b | ||
|
|
8cd82a6fb8 | ||
|
|
c5e20e3024 | ||
|
|
b82e34ddef | ||
|
|
e910c0c21a | ||
|
|
d5b334177c | ||
|
|
ea52b11c7b | ||
|
|
825787e228 | ||
|
|
c827221188 | ||
|
|
78cfc91d1e | ||
|
|
0048e46272 | ||
|
|
fc6626918d | ||
|
|
50b89ba7d8 | ||
|
|
7224f659b3 | ||
|
|
d4e753ef84 | ||
|
|
31c30cce9d | ||
|
|
2ef20b2937 | ||
|
|
45bebab55d | ||
|
|
7cd2ac1bbd | ||
|
|
00896009cd | ||
|
|
c1faa785b3 | ||
|
|
004674fada | ||
|
|
a58edd9a64 | ||
|
|
f5810bd601 | ||
|
|
6734ff4c7f | ||
|
|
96de08456d | ||
|
|
ad6b5d4087 | ||
|
|
2fce6352c8 | ||
|
|
0a97eba954 | ||
|
|
360b7c2614 | ||
|
|
2c61ecddd4 | ||
|
|
a863d9255d | ||
|
|
680a2fefcb | ||
|
|
b07c24f813 | ||
|
|
d7775ef6f5 | ||
|
|
d11650f798 | ||
|
|
40b4839693 | ||
|
|
87a9396ebe | ||
|
|
c9d413638c | ||
|
|
fe60e7b5d3 | ||
|
|
042eded639 | ||
|
|
f12b47b301 | ||
|
|
0633f665d5 | ||
|
|
d028bf9534 | ||
|
|
696afdc7e9 | ||
|
|
c359f78f6c | ||
|
|
aedeee48cc | ||
|
|
00d7dc6c43 | ||
|
|
5113045e87 | ||
|
|
280898be6f | ||
|
|
517d68b106 | ||
|
|
4f8c828202 | ||
|
|
4f687be298 | ||
|
|
f46358b50e | ||
|
|
9184fe7cb4 | ||
|
|
c3322c65c0 | ||
|
|
862a17ab4e | ||
|
|
1ddaa30b0f | ||
|
|
ceafca8a3a | ||
|
|
8344d8ade6 | ||
|
|
22d0da73ac | ||
|
|
faea2c0525 | ||
|
|
fdcf41558f | ||
|
|
ff09f47f39 | ||
|
|
96e73317f9 | ||
|
|
3737c182f0 | ||
|
|
07eca6ca9c | ||
|
|
a888648c1b | ||
|
|
d1b27efedf | ||
|
|
d7c7443ff5 | ||
|
|
bad972bac3 | ||
|
|
b192f496dc | ||
|
|
1c0222774b | ||
|
|
148a60e51c | ||
|
|
a7d137b92a | ||
|
|
c5b088ef33 | ||
|
|
eed6181731 | ||
|
|
91b8593a6c | ||
|
|
d43046e28a | ||
|
|
09b310a777 | ||
|
|
b2c8afb661 | ||
|
|
5f3716b2da | ||
|
|
e9a5039211 | ||
|
|
f8f34c0558 | ||
|
|
987191ac14 | ||
|
|
92372abfe7 | ||
|
|
5c242195a8 | ||
|
|
3f0abf2b31 | ||
|
|
1660656b52 | ||
|
|
77136b5c34 | ||
|
|
6b20209886 | ||
|
|
56f34703fa | ||
|
|
0a5590bfa7 | ||
|
|
01e64bf259 | ||
|
|
fee94d10bc | ||
|
|
bf2d9ff394 | ||
|
|
410dc0e489 | ||
|
|
cf507d6159 | ||
|
|
91152877c9 | ||
|
|
1d85bfe302 | ||
|
|
4da3a06458 | ||
|
|
e0d82965a2 | ||
|
|
b70b5f6486 | ||
|
|
e4f34da3bb | ||
|
|
fd4263a31c | ||
|
|
a5876486dd | ||
|
|
8fef1b084e | ||
|
|
636554ee50 | ||
|
|
c44a3533a5 | ||
|
|
d4bbeae02d | ||
|
|
c1a435b077 | ||
|
|
ec762a8a66 | ||
|
|
c1bf30980c | ||
|
|
0c0e92c956 | ||
|
|
2af9f1df5a | ||
|
|
63bb5845de | ||
|
|
1ed7196de6 |
1
.github/workflows/collabora.yml
vendored
1
.github/workflows/collabora.yml
vendored
@@ -20,6 +20,7 @@ jobs:
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: collabora-seccomp-update automated change
|
||||
signoff: true
|
||||
title: collabora seccomp update
|
||||
|
||||
12
.github/workflows/dependency-updates.yml
vendored
12
.github/workflows/dependency-updates.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
|
||||
with:
|
||||
php-version: 8.4
|
||||
php-version: 8.5
|
||||
extensions: apcu
|
||||
- name: Run dependency update script
|
||||
run: |
|
||||
@@ -43,9 +43,19 @@ jobs:
|
||||
| tail -1
|
||||
)"
|
||||
sed -i "s|pecl install APCu.*\;|pecl install APCu-$apcu_version\;|" ./Containers/mastercontainer/Dockerfile
|
||||
|
||||
# CADDY_REMOTE_HOST_HASH
|
||||
CADDY_REMOTE_HOST_HASH="$(
|
||||
git ls-remote https://github.com/muety/caddy-remote-host master \
|
||||
| cut -f1 \
|
||||
| tail -1
|
||||
)"
|
||||
sed -i "s|^ARG CADDY_REMOTE_HOST_HASH.*$|ARG CADDY_REMOTE_HOST_HASH=$CADDY_REMOTE_HOST_HASH|" ./Containers/mastercontainer/Dockerfile
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: php dependency updates
|
||||
signoff: true
|
||||
title: PHP dependency updates
|
||||
|
||||
1
.github/workflows/imaginary-update.yml
vendored
1
.github/workflows/imaginary-update.yml
vendored
@@ -24,6 +24,7 @@ jobs:
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: imaginary-update automated change
|
||||
signoff: true
|
||||
title: Imaginary update
|
||||
|
||||
2
.github/workflows/lint-php.yml
vendored
2
.github/workflows/lint-php.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: [ "8.4" ]
|
||||
php-versions: [ "8.5" ]
|
||||
|
||||
name: php-lint
|
||||
|
||||
|
||||
2
.github/workflows/lint-yaml.yml
vendored
2
.github/workflows/lint-yaml.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
line-length: warning
|
||||
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
|
||||
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
|
||||
|
||||
- name: Check GitHub actions
|
||||
run: uvx zizmor --min-severity medium .github/workflows/*.yml
|
||||
|
||||
1
.github/workflows/nextcloud-update.yml
vendored
1
.github/workflows/nextcloud-update.yml
vendored
@@ -81,6 +81,7 @@ jobs:
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: nextcloud-update automated change
|
||||
signoff: true
|
||||
title: Nextcloud dependency update
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- name: Set up php
|
||||
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
|
||||
with:
|
||||
php-version: 8.4
|
||||
php-version: 8.5
|
||||
extensions: apcu
|
||||
coverage: none
|
||||
|
||||
|
||||
8
.github/workflows/playwright-on-push.yml
vendored
8
.github/workflows/playwright-on-push.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
node-version: lts/*
|
||||
|
||||
@@ -36,11 +36,11 @@ jobs:
|
||||
- name: Install Playwright Browsers
|
||||
run: cd php/tests && npx playwright install --with-deps chromium
|
||||
|
||||
- name: Set up php 8.4
|
||||
- name: Set up php 8.5
|
||||
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2.36.0
|
||||
with:
|
||||
extensions: apcu
|
||||
php-version: 8.4
|
||||
php-version: 8.5
|
||||
coverage: none
|
||||
ini-file: development
|
||||
env:
|
||||
@@ -114,7 +114,7 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: playwright-report
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
node-version: lts/*
|
||||
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: playwright-report
|
||||
|
||||
5
.github/workflows/psalm-update-baseline.yml
vendored
5
.github/workflows/psalm-update-baseline.yml
vendored
@@ -15,9 +15,10 @@ jobs:
|
||||
- name: Set up php
|
||||
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
|
||||
with:
|
||||
php-version: 8.4
|
||||
php-version: 8.5
|
||||
extensions: apcu
|
||||
coverage: none
|
||||
ini-file: development
|
||||
|
||||
- name: Run script
|
||||
run: |
|
||||
@@ -32,7 +33,7 @@ jobs:
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
|
||||
with:
|
||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: Update psalm baseline
|
||||
committer: GitHub <noreply@github.com>
|
||||
author: nextcloud-command <nextcloud-command@users.noreply.github.com>
|
||||
|
||||
5
.github/workflows/psalm.yml
vendored
5
.github/workflows/psalm.yml
vendored
@@ -39,12 +39,11 @@ jobs:
|
||||
- name: Set up php
|
||||
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2.36.0
|
||||
with:
|
||||
php-version: 8.4
|
||||
php-version: 8.5
|
||||
extensions: apcu
|
||||
coverage: none
|
||||
ini-file: development
|
||||
# Temporary workaround for missing pcntl_* in PHP 8.3
|
||||
ini-values: disable_functions=
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
62
.github/workflows/pull-translations.yml
vendored
Normal file
62
.github/workflows/pull-translations.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Pull Translations from Transifex
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run every day at 02:00 UTC
|
||||
- cron: '0 2 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
org:
|
||||
description: 'Transifex organisation slug'
|
||||
required: false
|
||||
default: 'nextcloud'
|
||||
project:
|
||||
description: 'Transifex project slug'
|
||||
required: false
|
||||
default: 'nextcloud-all-in-one'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
pull-translations:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install jq
|
||||
run: sudo apt-get install -y jq
|
||||
|
||||
- name: Make pull script executable
|
||||
run: chmod +x php/translations/pull.sh
|
||||
|
||||
- name: Pull translations from Transifex
|
||||
env:
|
||||
TRANSIFEX_TOKEN: ${{ secrets.TRANSIFEX_TOKEN }}
|
||||
TRANSIFEX_ORG: ${{ inputs.org || 'nextcloud' }}
|
||||
TRANSIFEX_PROJECT: ${{ inputs.project || 'nextcloud-all-in-one' }}
|
||||
run: php/translations/pull.sh
|
||||
|
||||
- name: Check for changes
|
||||
id: changes
|
||||
run: |
|
||||
git diff --quiet php/translations/ && echo "changed=false" >> "$GITHUB_OUTPUT" || echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create Pull Request
|
||||
if: steps.changes.outputs.changed == 'true'
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: 'chore(i18n): update translations from Transifex'
|
||||
branch: chore/update-translations
|
||||
delete-branch: true
|
||||
title: 'chore(i18n): update translations from Transifex'
|
||||
body: |
|
||||
Automated pull of the latest translations from Transifex.
|
||||
|
||||
This PR was created automatically by the **Pull Translations** workflow.
|
||||
Please review the changes and merge when ready.
|
||||
labels: translations
|
||||
1
.github/workflows/talk.yml
vendored
1
.github/workflows/talk.yml
vendored
@@ -47,6 +47,7 @@ jobs:
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: talk-update automated change
|
||||
signoff: true
|
||||
title: talk container update
|
||||
|
||||
2
.github/workflows/twig-lint.yml
vendored
2
.github/workflows/twig-lint.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
- name: Set up php ${{ matrix.php-versions }}
|
||||
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
|
||||
with:
|
||||
php-version: 8.4
|
||||
php-version: 8.5
|
||||
extensions: apcu
|
||||
coverage: none
|
||||
|
||||
|
||||
1
.github/workflows/watchtower-update.yml
vendored
1
.github/workflows/watchtower-update.yml
vendored
@@ -28,6 +28,7 @@ jobs:
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: watchtower-update automated change
|
||||
signoff: true
|
||||
title: watchtower container update
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
}
|
||||
|
||||
https://{$ADDITIONAL_TRUSTED_DOMAIN}:443,
|
||||
http://{$APACHE_HOST}:23973, # For Collabora callback and WOPI requests, see containers.json
|
||||
http://{$APACHE_HOST}.nextcloud-aio:23973, # For Collabora callback and WOPI requests, see containers.json
|
||||
{$PROTOCOL}://{$NC_DOMAIN}:{$APACHE_PORT} {
|
||||
header -Server
|
||||
header -X-Powered-By
|
||||
@@ -58,6 +58,11 @@ http://{$APACHE_HOST}:23973, # For Collabora callback and WOPI requests, see con
|
||||
reverse_proxy {$WHITEBOARD_HOST}:3002
|
||||
}
|
||||
|
||||
# HaRP (ExApps)
|
||||
route /exapps/* {
|
||||
reverse_proxy {$HARP_HOST}:8780
|
||||
}
|
||||
|
||||
# Nextcloud
|
||||
route {
|
||||
header Strict-Transport-Security max-age=31536000;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM caddy:2.10.2-alpine AS caddy
|
||||
FROM caddy:2.11.2-alpine AS caddy
|
||||
|
||||
# From https://github.com/docker-library/httpd/blob/master/2.4/alpine/Dockerfile
|
||||
FROM httpd:2.4.66-alpine3.23
|
||||
|
||||
@@ -77,6 +77,10 @@ if [ "$BORG_MODE" = backup ]; then
|
||||
if ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json" ]; then
|
||||
echo "configuration.json not present. Cannot perform the backup!"
|
||||
exit 1
|
||||
elif ! grep -q '"domain"' "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json" \
|
||||
|| ! grep -q '"wasStartButtonClicked"' "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json"; then
|
||||
echo "It seems like the configuration.json setup was not done correctly. Something is wrong! (Most likely the provided configuration.json is invalid)"
|
||||
exit 1
|
||||
elif ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud/config/config.php" ]; then
|
||||
echo "config.php is missing. Cannot perform backup!"
|
||||
exit 1
|
||||
@@ -514,6 +518,10 @@ if [ "$BORG_MODE" = restore ]; then
|
||||
|
||||
if [ "$RESTORE_FAILED" = 1 ]; then
|
||||
exit 1
|
||||
elif ! grep -q '"domain"' "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json" \
|
||||
|| ! grep -q '"wasStartButtonClicked"' "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json"; then
|
||||
echo "It seems like the restore of the configuration.json was not done correctly. Something is wrong! (Most likely is the restore archive already incorrect)!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Inform user
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# From a file located probably somewhere here: https://github.com/CollaboraOnline/online/blob/master/docker/from-packages/Dockerfile
|
||||
FROM collabora/code:25.04.8.3.1
|
||||
FROM collabora/code:25.04.9.4.1
|
||||
|
||||
USER root
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM haproxy:3.3.3-alpine
|
||||
FROM haproxy:3.3.6-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.19.11
|
||||
FROM elasticsearch:8.19.13
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM golang:1.26.0-alpine3.23 AS go
|
||||
FROM golang:1.26.1-alpine3.23 AS go
|
||||
|
||||
ENV IMAGINARY_HASH=6a274b488759a896aff02f52afee6e50b5e3a3ee
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
# auto_https will create redirects for https://{host}:8443 instead of https://{host}
|
||||
# https redirects are added manually in the http://:80 block
|
||||
auto_https disable_redirects
|
||||
|
||||
storage file_system {
|
||||
root /mnt/docker-aio-config/caddy/
|
||||
}
|
||||
|
||||
log {
|
||||
level ERROR
|
||||
}
|
||||
|
||||
servers {
|
||||
protocols h1 h2 h2c
|
||||
}
|
||||
|
||||
on_demand_tls {
|
||||
ask http://127.0.0.1:9876/
|
||||
}
|
||||
}
|
||||
|
||||
http://:80 {
|
||||
redir https://{host}{uri} permanent
|
||||
}
|
||||
|
||||
https://:8443 {
|
||||
|
||||
reverse_proxy 127.0.0.1:8000
|
||||
|
||||
tls {
|
||||
on_demand
|
||||
issuer acme {
|
||||
disable_tlsalpn_challenge
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,17 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# Docker CLI is a requirement
|
||||
FROM docker:29.2.1-cli AS docker
|
||||
FROM docker:29.3.0-cli AS docker
|
||||
|
||||
ARG CADDY_REMOTE_HOST_HASH=b21775afa730ffb52a24ddff310c8a6d1fd37276
|
||||
|
||||
# Caddy is a requirement
|
||||
FROM caddy:2.10.2-alpine AS caddy
|
||||
FROM caddy:2.11.2-builder-alpine AS caddy
|
||||
RUN set -ex; \
|
||||
xcaddy build --with github.com/muety/caddy-remote-host@"$CADDY_REMOTE_HOST_HASH"; \
|
||||
/usr/bin/caddy list-modules
|
||||
|
||||
# From https://github.com/docker-library/php/blob/master/8.4/alpine3.23/fpm/Dockerfile
|
||||
FROM php:8.4.17-fpm-alpine3.23
|
||||
# From https://github.com/docker-library/php/blob/master/8.5/alpine3.23/fpm/Dockerfile
|
||||
FROM php:8.5.4-fpm-alpine3.23
|
||||
|
||||
EXPOSE 80
|
||||
EXPOSE 8080
|
||||
@@ -21,9 +26,8 @@ COPY --from=docker /usr/local/bin/docker /usr/local/bin/docker
|
||||
COPY community-containers /var/www/docker-aio/community-containers
|
||||
COPY php /var/www/docker-aio/php
|
||||
COPY --chmod=775 Containers/mastercontainer/*.sh /
|
||||
COPY --chmod=664 Containers/mastercontainer/Caddyfile /Caddyfile
|
||||
COPY --chmod=664 Containers/mastercontainer/*.Caddyfile /
|
||||
COPY --chmod=664 Containers/mastercontainer/supervisord.conf /supervisord.conf
|
||||
COPY Containers/mastercontainer/mastercontainer.conf /etc/apache2/sites-available/mastercontainer.conf
|
||||
|
||||
WORKDIR /var/www/docker-aio
|
||||
|
||||
@@ -37,13 +41,8 @@ RUN set -ex; \
|
||||
apk add --no-cache \
|
||||
util-linux-misc \
|
||||
ca-certificates \
|
||||
wget \
|
||||
bash \
|
||||
apache2 \
|
||||
apache2-proxy \
|
||||
apache2-ssl \
|
||||
supervisor \
|
||||
openssl \
|
||||
sudo \
|
||||
netcat-openbsd \
|
||||
curl \
|
||||
@@ -67,11 +66,12 @@ RUN set -ex; \
|
||||
sed -i 's/^pm = dynamic/pm = ondemand/' /usr/local/etc/php-fpm.d/www.conf; \
|
||||
sed -i 's/^pm.max_children =.*/pm.max_children = 80/' /usr/local/etc/php-fpm.d/www.conf; \
|
||||
sed -i 's|access.log = /proc/self/fd/2|access.log = /proc/self/fd/1|' /usr/local/etc/php-fpm.d/docker.conf; \
|
||||
grep -q ';listen.allowed_clients' /usr/local/etc/php-fpm.d/www.conf; \
|
||||
sed -i 's|;listen.allowed_clients.*|listen.allowed_clients = 127.0.0.1,::1|' /usr/local/etc/php-fpm.d/www.conf; \
|
||||
grep -q '^listen =' /usr/local/etc/php-fpm.d/docker.conf; \
|
||||
sed -i 's|listen =.*|listen = /run/php.sock|' /usr/local/etc/php-fpm.d/docker.conf; \
|
||||
echo "listen.owner = www-data" | tee -a /usr/local/etc/php-fpm.d/docker.conf; \
|
||||
\
|
||||
apk add --no-cache git; \
|
||||
wget https://getcomposer.org/installer -O - | php -- --install-dir=/usr/local/bin --filename=composer; \
|
||||
curl https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer; \
|
||||
chmod +x /usr/local/bin/composer; \
|
||||
cd /var/www/docker-aio; \
|
||||
rm -r ./php/tests; \
|
||||
@@ -86,42 +86,6 @@ RUN set -ex; \
|
||||
rm -r php/data; \
|
||||
rm -r php/session; \
|
||||
\
|
||||
mkdir -p /etc/apache2/certs; \
|
||||
cd /etc/apache2/certs; \
|
||||
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj "/C=DE/ST=BE/L=Local/O=Dev/CN=nextcloud.local" -keyout /etc/apache2/certs/ssl.key -out /etc/apache2/certs/ssl.crt; \
|
||||
\
|
||||
sed -i \
|
||||
-e '/^Listen /d' \
|
||||
-e 's/^LogLevel .*/LogLevel error/' \
|
||||
-e 's|^ErrorLog .*|ErrorLog /proc/self/fd/2|' \
|
||||
-e 's/User apache/User www-data/g' \
|
||||
-e 's/Group apache/Group www-data/g' \
|
||||
-e 's/^#\(LoadModule .*mod_rewrite.so\)/\1/' \
|
||||
-e 's/^#\(LoadModule .*mod_headers.so\)/\1/' \
|
||||
-e 's/^#\(LoadModule .*mod_env.so\)/\1/' \
|
||||
-e 's/^#\(LoadModule .*mod_mime.so\)/\1/' \
|
||||
-e 's/^#\(LoadModule .*mod_dir.so\)/\1/' \
|
||||
-e 's/^#\(LoadModule .*mod_authz_core.so\)/\1/' \
|
||||
-e 's/^#\(LoadModule .*mod_mpm_event.so\)/\1/' \
|
||||
-e 's/\(LoadModule .*mod_mpm_worker.so\)/#\1/' \
|
||||
-e 's/\(LoadModule .*mod_mpm_prefork.so\)/#\1/' \
|
||||
-e 's/\(ScriptAlias \)/#\1/' \
|
||||
/etc/apache2/httpd.conf; \
|
||||
mkdir -p /etc/apache2/logs; \
|
||||
rm /etc/apache2/conf.d/ssl.conf; \
|
||||
echo "ServerName localhost" | tee -a /etc/apache2/httpd.conf; \
|
||||
grep -q '^LoadModule lbmethod_heartbeat_module' /etc/apache2/conf.d/proxy.conf; \
|
||||
sed -i 's|^LoadModule lbmethod_heartbeat_module.*|#LoadModule lbmethod_heartbeat_module|' /etc/apache2/conf.d/proxy.conf; \
|
||||
echo "SSLSessionCache nonenotnull" | tee -a /etc/apache2/httpd.conf; \
|
||||
echo "LoadModule ssl_module modules/mod_ssl.so" | tee -a /etc/apache2/httpd.conf; \
|
||||
echo "LoadModule socache_shmcb_module modules/mod_socache_shmcb.so" | tee -a /etc/apache2/httpd.conf; \
|
||||
echo "Include /etc/apache2/sites-available/mastercontainer.conf" | tee -a /etc/apache2/httpd.conf; \
|
||||
\
|
||||
rm -f /etc/apache2/conf.d/default.conf \
|
||||
/etc/apache2/conf.d/userdir.conf \
|
||||
/etc/apache2/conf.d/info.conf; \
|
||||
\
|
||||
rm -rf /var/www/localhost/cgi-bin/; \
|
||||
mkdir /var/log/supervisord; \
|
||||
mkdir /var/run/supervisord;
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ The mastercontainer acts as the central orchestration service for the deployment
|
||||
of all other containers in the Nextcloud All-in-One stack. It hosts:
|
||||
|
||||
- A dedicated PHP SAPI/backend (php-fpm) for AIO itself (not Nextcloud Server)
|
||||
- An Apache service for accessing the AIO interface via a self-signed HTTPS VirtualHost on 8080/tcp
|
||||
- A Caddy reverse proxy service enabling HTTPS access to the AIO frontend on port 8443/tcp.
|
||||
- A Caddy server enabling self-signed HTTPS access to the AIO frontend on port 8080/tcp.
|
||||
- A Caddy server enabling trusted HTTPS access to the AIO frontend on port 8443/tcp.
|
||||
- Caddy will automatically issue a Let's Encrypt issued certificate if port 80 and 8443
|
||||
is open/forwarded and a domain pointer is in place; then, simply open the Nextcloud AIO interface using the
|
||||
domain (`https://your-domain-that-points-to-this-server.tld:8443`). The Let's Encrypt certificate request will
|
||||
|
||||
52
Containers/mastercontainer/acme.Caddyfile
Normal file
52
Containers/mastercontainer/acme.Caddyfile
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
admin off
|
||||
|
||||
# auto_https will create redirects for https://{host}:8443 instead of https://{host}
|
||||
# https redirects are added manually in the http://:80 block
|
||||
auto_https disable_redirects
|
||||
|
||||
storage file_system {
|
||||
root /mnt/docker-aio-config/caddy/
|
||||
}
|
||||
|
||||
log {
|
||||
level ERROR
|
||||
# We need to exclude the remote-host plugin from logging as it would spam the logs
|
||||
# See https://github.com/nextcloud/all-in-one/pull/7006#issuecomment-4003238239
|
||||
exclude http.matchers.remote_host
|
||||
}
|
||||
|
||||
servers {
|
||||
# Only h1 is allowed as we prevent `ERR_NETWORK_CHANGED` from happening
|
||||
protocols h1
|
||||
}
|
||||
|
||||
on_demand_tls {
|
||||
ask http://127.0.0.1:9876/
|
||||
}
|
||||
|
||||
skip_install_trust
|
||||
}
|
||||
|
||||
http://:80 {
|
||||
redir https://{host}{uri} permanent
|
||||
}
|
||||
|
||||
https://:8443 {
|
||||
@denied {
|
||||
path /api/auth/login /api/auth/getlogin
|
||||
remote_host nextcloud-aio-nextcloud
|
||||
}
|
||||
abort @denied
|
||||
|
||||
root * /var/www/docker-aio/php/public
|
||||
php_fastcgi unix//run/php.sock
|
||||
file_server
|
||||
|
||||
tls {
|
||||
on_demand
|
||||
issuer acme {
|
||||
disable_tlsalpn_challenge
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
if [ -f "/mnt/docker-aio-config/data/configuration.json" ]; then
|
||||
nc -z 127.0.0.1 80 || exit 1
|
||||
nc -z 127.0.0.1 8000 || exit 1
|
||||
nc -z 127.0.0.1 8080 || exit 1
|
||||
nc -z 127.0.0.1 8443 || exit 1
|
||||
nc -z 127.0.0.1 9000 || exit 1
|
||||
test -S /run/php.sock || exit 1
|
||||
nc -z 127.0.0.1 9876 || exit 1
|
||||
fi
|
||||
|
||||
38
Containers/mastercontainer/internal.Caddyfile
Normal file
38
Containers/mastercontainer/internal.Caddyfile
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
admin off
|
||||
|
||||
storage file_system {
|
||||
root /mnt/docker-aio-config/caddy/
|
||||
}
|
||||
|
||||
log {
|
||||
level ERROR
|
||||
# We need to exclude the remote-host plugin from logging as it would spam the logs
|
||||
# See https://github.com/nextcloud/all-in-one/pull/7006#issuecomment-4003238239
|
||||
exclude http.matchers.remote_host
|
||||
}
|
||||
|
||||
servers {
|
||||
# Only h1 is allowed as we prevent `ERR_NETWORK_CHANGED` from happening
|
||||
protocols h1
|
||||
}
|
||||
|
||||
skip_install_trust
|
||||
}
|
||||
|
||||
https://:8080 {
|
||||
@denied {
|
||||
path /api/auth/login /api/auth/getlogin
|
||||
remote_host nextcloud-aio-nextcloud
|
||||
}
|
||||
abort @denied
|
||||
|
||||
root * /var/www/docker-aio/php/public
|
||||
php_fastcgi unix//run/php.sock
|
||||
file_server
|
||||
|
||||
tls {
|
||||
on_demand
|
||||
issuer internal
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
Listen 127.0.0.1:8000
|
||||
Listen 8080 https
|
||||
|
||||
# Deny access to .ht files
|
||||
<Files ".ht*">
|
||||
Require all denied
|
||||
</Files>
|
||||
|
||||
# Http host
|
||||
<VirtualHost 127.0.0.1:8000>
|
||||
ServerName 127.0.0.1
|
||||
|
||||
# Add error log
|
||||
CustomLog /proc/self/fd/1 proxy
|
||||
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy
|
||||
ErrorLog /proc/self/fd/2
|
||||
ErrorLogFormat "[%t] [%l] [%E] [client: %{X-Forwarded-For}i] [%M] [%{User-Agent}i]"
|
||||
LogLevel warn
|
||||
|
||||
# PHP match
|
||||
<FilesMatch "\.php$">
|
||||
SetHandler "proxy:fcgi://127.0.0.1:9000"
|
||||
</FilesMatch>
|
||||
# Master dir
|
||||
DocumentRoot /var/www/docker-aio/php/public/
|
||||
<Directory /var/www/docker-aio/php/public/>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [QSA,L]
|
||||
Options Indexes FollowSymLinks
|
||||
Require all granted
|
||||
AllowOverride All
|
||||
Options FollowSymLinks MultiViews
|
||||
Satisfy Any
|
||||
<IfModule mod_dav.c>
|
||||
Dav off
|
||||
</IfModule>
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
|
||||
# Https host
|
||||
<VirtualHost *:8080>
|
||||
# Proxy to https
|
||||
ProxyPass / http://127.0.0.1:8000/
|
||||
ProxyPassReverse / http://127.0.0.1:8000/
|
||||
ProxyPreserveHost On
|
||||
# SSL
|
||||
SSLCertificateKeyFile /etc/apache2/certs/ssl.key
|
||||
SSLCertificateFile /etc/apache2/certs/ssl.crt
|
||||
SSLEngine on
|
||||
SSLProtocol -all +TLSv1.2 +TLSv1.3
|
||||
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
|
||||
SSLHonorCipherOrder off
|
||||
SSLSessionTickets off
|
||||
</VirtualHost>
|
||||
|
||||
# Increase timeout in case e.g. the initial download takes a long time
|
||||
Timeout 7200
|
||||
ProxyTimeout 7200
|
||||
|
||||
# See https://httpd.apache.org/docs/trunk/mod/core.html#traceenable
|
||||
TraceEnable Off
|
||||
@@ -162,6 +162,9 @@ if ! sudo -E -u www-data docker ps --format "{{.Names}}" | grep -q "^nextcloud-a
|
||||
Using a different name is not supported since mastercontainer updates will not work in that case!
|
||||
If you are on docker swarm and try to run AIO, see https://github.com/nextcloud/all-in-one#can-i-run-this-with-docker-swarm"
|
||||
exit 1
|
||||
elif sudo -E -u www-data docker inspect nextcloud-aio-mastercontainer --format "{{.Config.Image}}" | grep -q '@'; then
|
||||
print_red "It seems like you used a hash for the mastercontainer image tag. This is not supported!"
|
||||
exit 1
|
||||
elif ! sudo -E -u www-data docker volume ls --format "{{.Name}}" | grep -q "^nextcloud_aio_mastercontainer$"; then
|
||||
print_red "It seems like you did not give the mastercontainer volume the correct name? (The 'nextcloud_aio_mastercontainer' volume was not found.)
|
||||
Using a different name is not supported since the built-in backup solution will not work in that case!"
|
||||
@@ -361,7 +364,6 @@ fi
|
||||
mkdir -p /mnt/docker-aio-config/data/
|
||||
mkdir -p /mnt/docker-aio-config/session/
|
||||
mkdir -p /mnt/docker-aio-config/caddy/
|
||||
mkdir -p /mnt/docker-aio-config/certs/
|
||||
|
||||
# Adjust permissions for all instances
|
||||
chmod 770 -R /mnt/docker-aio-config
|
||||
@@ -369,37 +371,6 @@ chmod 777 /mnt/docker-aio-config
|
||||
chown www-data:www-data -R /mnt/docker-aio-config/data/
|
||||
chown www-data:www-data -R /mnt/docker-aio-config/session/
|
||||
chown www-data:www-data -R /mnt/docker-aio-config/caddy/
|
||||
chown root:root -R /mnt/docker-aio-config/certs/
|
||||
|
||||
# Don't allow access to the AIO interface from the Nextcloud container
|
||||
# Probably more cosmetic than anything but at least an attempt
|
||||
if ! grep -q '# nextcloud-aio-block' /etc/apache2/httpd.conf; then
|
||||
cat << APACHE_CONF >> /etc/apache2/httpd.conf
|
||||
# nextcloud-aio-block-start
|
||||
<Location />
|
||||
order allow,deny
|
||||
deny from nextcloud-aio-nextcloud.nextcloud-aio
|
||||
allow from all
|
||||
</Location>
|
||||
# nextcloud-aio-block-end
|
||||
APACHE_CONF
|
||||
fi
|
||||
|
||||
# Adjust certs
|
||||
GENERATED_CERTS="/mnt/docker-aio-config/certs"
|
||||
TMP_CERTS="/etc/apache2/certs"
|
||||
mkdir -p "$GENERATED_CERTS"
|
||||
cd "$GENERATED_CERTS" || exit 1
|
||||
if ! [ -f ./ssl.crt ] && ! [ -f ./ssl.key ]; then
|
||||
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj "/C=DE/ST=BE/L=Local/O=Dev/CN=nextcloud.local" -keyout ./ssl.key -out ./ssl.crt
|
||||
fi
|
||||
if [ -f ./ssl.crt ] && [ -f ./ssl.key ]; then
|
||||
cd "$TMP_CERTS" || exit 1
|
||||
rm ./ssl.crt
|
||||
rm ./ssl.key
|
||||
cp "$GENERATED_CERTS/ssl.crt" ./
|
||||
cp "$GENERATED_CERTS/ssl.key" ./
|
||||
fi
|
||||
|
||||
print_green "Initial startup of Nextcloud All-in-One complete!
|
||||
You should be able to open the Nextcloud AIO Interface now on port 8080 of this server!
|
||||
@@ -412,8 +383,11 @@ https://your-domain-that-points-to-this-server.tld:8443"
|
||||
# Set the timezone to Etc/UTC
|
||||
export TZ=Etc/UTC
|
||||
|
||||
# Fix apache startup
|
||||
rm -f /var/run/apache2/httpd.pid
|
||||
# Remove unused certs
|
||||
rm -vrf /mnt/docker-aio-config/certs
|
||||
|
||||
# Remove the php socket as safeguard
|
||||
rm -vf /run/php.sock
|
||||
|
||||
# Fix caddy startup
|
||||
if [ -d "/mnt/docker-aio-config/caddy/locks" ]; then
|
||||
@@ -421,7 +395,8 @@ if [ -d "/mnt/docker-aio-config/caddy/locks" ]; then
|
||||
fi
|
||||
|
||||
# Fix the Caddyfile format
|
||||
caddy fmt --overwrite /Caddyfile
|
||||
caddy fmt --overwrite /acme.Caddyfile
|
||||
caddy fmt --overwrite /internal.Caddyfile
|
||||
|
||||
# Fix caddy log
|
||||
chmod 777 /root
|
||||
|
||||
@@ -16,20 +16,20 @@ stderr_logfile_maxbytes=0
|
||||
command=php-fpm
|
||||
user=root
|
||||
|
||||
[program:apache]
|
||||
# Stdout logging is disabled as otherwise the logs are spammed
|
||||
stdout_logfile=NONE
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
command=httpd -DFOREGROUND
|
||||
user=root
|
||||
|
||||
[program:caddy]
|
||||
[program:caddy-internal]
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
command=/usr/bin/caddy run --config /Caddyfile
|
||||
command=/usr/bin/caddy run --config /internal.Caddyfile
|
||||
user=www-data
|
||||
|
||||
[program:caddy-acme]
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
command=/usr/bin/caddy run --config /acme.Caddyfile
|
||||
user=www-data
|
||||
|
||||
[program:cron]
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
<?php
|
||||
if (getenv('REDIS_HOST')) {
|
||||
if (getenv('REDIS_MODE') !== 'rediscluster') {
|
||||
$CONFIG = array(
|
||||
'memcache.distributed' => '\OC\Memcache\Redis',
|
||||
'memcache.locking' => '\OC\Memcache\Redis',
|
||||
'redis' => array(
|
||||
'host' => getenv('REDIS_HOST'),
|
||||
'password' => (string) getenv('REDIS_HOST_PASSWORD'),
|
||||
),
|
||||
);
|
||||
|
||||
if (getenv('REDIS_HOST')) {
|
||||
$CONFIG['redis']['host'] = (string) getenv('REDIS_HOST');
|
||||
}
|
||||
|
||||
if (getenv('REDIS_HOST_PASSWORD')) {
|
||||
$CONFIG['redis']['password'] = (string) getenv('REDIS_HOST_PASSWORD');
|
||||
}
|
||||
|
||||
if (getenv('REDIS_PORT')) {
|
||||
$CONFIG['redis']['port'] = (int) getenv('REDIS_PORT');
|
||||
}
|
||||
@@ -17,7 +21,44 @@ if (getenv('REDIS_HOST')) {
|
||||
$CONFIG['redis']['dbindex'] = (int) getenv('REDIS_DB_INDEX');
|
||||
}
|
||||
|
||||
if (getenv('REDIS_USER_AUTH') !== false) {
|
||||
if (getenv('REDIS_USER_AUTH')) {
|
||||
$CONFIG['redis']['user'] = str_replace("&auth[]=", "", getenv('REDIS_USER_AUTH'));
|
||||
}
|
||||
|
||||
if (getenv('NEXTCLOUD_TRUSTED_CERTIFICATES_REDIS')) {
|
||||
$CONFIG['redis']['ssl_context']['cafile'] = '/var/www/html/data/certificates/ca-bundle.crt';
|
||||
}
|
||||
} else {
|
||||
$CONFIG = array(
|
||||
'memcache.distributed' => '\OC\Memcache\Redis',
|
||||
'memcache.locking' => '\OC\Memcache\Redis',
|
||||
'redis.cluster' => array(
|
||||
'timeout' => 0.0,
|
||||
'read_timeout' => 0.0,
|
||||
'failover_mode' => \RedisCluster::FAILOVER_ERROR,
|
||||
'seeds' => array_values(array_filter(array(
|
||||
(getenv('REDIS_HOST') && getenv('REDIS_PORT')) ? (getenv('REDIS_HOST') . ':' . (string)getenv('REDIS_PORT')) : null,
|
||||
(getenv('REDIS_HOST_2') && getenv('REDIS_PORT_2')) ? (getenv('REDIS_HOST_2') . ':' . (string)getenv('REDIS_PORT_2')) : null,
|
||||
(getenv('REDIS_HOST_3') && getenv('REDIS_PORT_3')) ? (getenv('REDIS_HOST_3') . ':' . (string)getenv('REDIS_PORT_3')) : null,
|
||||
(getenv('REDIS_HOST_4') && getenv('REDIS_PORT_4')) ? (getenv('REDIS_HOST_4') . ':' . (string)getenv('REDIS_PORT_4')) : null,
|
||||
(getenv('REDIS_HOST_5') && getenv('REDIS_PORT_5')) ? (getenv('REDIS_HOST_5') . ':' . (string)getenv('REDIS_PORT_5')) : null,
|
||||
(getenv('REDIS_HOST_6') && getenv('REDIS_PORT_6')) ? (getenv('REDIS_HOST_6') . ':' . (string)getenv('REDIS_PORT_6')) : null,
|
||||
(getenv('REDIS_HOST_7') && getenv('REDIS_PORT_7')) ? (getenv('REDIS_HOST_7') . ':' . (string)getenv('REDIS_PORT_7')) : null,
|
||||
(getenv('REDIS_HOST_8') && getenv('REDIS_PORT_8')) ? (getenv('REDIS_HOST_8') . ':' . (string)getenv('REDIS_PORT_8')) : null,
|
||||
(getenv('REDIS_HOST_9') && getenv('REDIS_PORT_9')) ? (getenv('REDIS_HOST_9') . ':' . (string)getenv('REDIS_PORT_9')) : null,
|
||||
))),
|
||||
),
|
||||
);
|
||||
|
||||
if (getenv('REDIS_HOST_PASSWORD')) {
|
||||
$CONFIG['redis.cluster']['password'] = (string) getenv('REDIS_HOST_PASSWORD');
|
||||
}
|
||||
|
||||
if (getenv('REDIS_USER_AUTH')) {
|
||||
$CONFIG['redis.cluster']['user'] = str_replace("&auth[]=", "", getenv('REDIS_USER_AUTH'));
|
||||
}
|
||||
|
||||
if (getenv('NEXTCLOUD_TRUSTED_CERTIFICATES_REDIS')) {
|
||||
$CONFIG['redis.cluster']['ssl_context']['cafile'] = '/var/www/html/data/certificates/ca-bundle.crt';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,4 +34,14 @@ if (getenv('OBJECTSTORE_S3_BUCKET')) {
|
||||
if ($sse_c_key) {
|
||||
$CONFIG['objectstore']['arguments']['sse_c_key'] = $sse_c_key;
|
||||
}
|
||||
|
||||
$requestChecksumValidation = getenv('OBJECTSTORE_S3_REQUEST_CHECKSUM_VALIDATION');
|
||||
if ($requestChecksumValidation) {
|
||||
$CONFIG['objectstore']['arguments']['request_checksum_calculation'] = $requestChecksumValidation;
|
||||
}
|
||||
|
||||
$responseChecksumValidation = getenv('OBJECTSTORE_S3_RESPONSE_CHECKSUM_VALIDATION');
|
||||
if ($responseChecksumValidation) {
|
||||
$CONFIG['objectstore']['arguments']['response_checksum_validation'] = $responseChecksumValidation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,8 +669,12 @@ php /var/www/html/occ config:system:set documentation_url.server_logs --value="h
|
||||
php /var/www/html/occ config:system:set htaccess.RewriteBase --value="/"
|
||||
php /var/www/html/occ maintenance:update:htaccess
|
||||
|
||||
# Revert dbpersistent setting to check if it fixes too many db connections
|
||||
php /var/www/html/occ config:system:set dbpersistent --value=false --type=bool
|
||||
# Handle db persistent settings
|
||||
if [ "$NEXTCLOUD_PERSIST_DATABASE_CONNECTIONS" = "yes" ]; then
|
||||
php /var/www/html/occ config:system:set dbpersistent --value=true --type=bool
|
||||
else
|
||||
php /var/www/html/occ config:system:set dbpersistent --value=false --type=bool
|
||||
fi
|
||||
|
||||
if [ "$DISABLE_BRUTEFORCE_PROTECTION" = yes ]; then
|
||||
php /var/www/html/occ config:system:set auth.bruteforce.protection.enabled --type=bool --value=false
|
||||
@@ -1025,13 +1029,13 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
# Docker socket proxy
|
||||
# Docker socket proxy / HaRP
|
||||
# app_api is a shipped app
|
||||
if [ -d "/var/www/html/custom_apps/app_api" ]; then
|
||||
php /var/www/html/occ app:disable app_api
|
||||
rm -r "/var/www/html/custom_apps/app_api"
|
||||
fi
|
||||
if [ "$DOCKER_SOCKET_PROXY_ENABLED" = 'yes' ]; then
|
||||
if [ "$DOCKER_SOCKET_PROXY_ENABLED" = 'yes' ] || [ "$HARP_ENABLED" = 'yes' ]; then
|
||||
if [ "$(php /var/www/html/occ config:app:get app_api enabled)" != "yes" ]; then
|
||||
php /var/www/html/occ app:enable app_api
|
||||
fi
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
/custom_apps/
|
||||
/themes/
|
||||
/version.php
|
||||
/lost+found
|
||||
|
||||
@@ -11,7 +11,6 @@ RUN set -ex; \
|
||||
netcat-openbsd \
|
||||
tzdata \
|
||||
bash \
|
||||
jq \
|
||||
openssl; \
|
||||
# Give root a random password
|
||||
echo "root:$(openssl rand -base64 12)" | chpasswd; \
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
if [ -z "$NEXTCLOUD_HOST" ]; then
|
||||
echo "NEXTCLOUD_HOST needs to be provided. Exiting!"
|
||||
exit 1
|
||||
elif [ -z "$POSTGRES_HOST" ]; then
|
||||
echo "POSTGRES_HOST needs to be provided. Exiting!"
|
||||
exit 1
|
||||
elif [ -z "$REDIS_HOST" ]; then
|
||||
echo "REDIS_HOST needs to be provided. Exiting!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Only start container if nextcloud is accessible
|
||||
@@ -28,7 +22,7 @@ elif [ "$CPU_ARCH" != "x86_64" ]; then
|
||||
fi
|
||||
|
||||
# Add warning
|
||||
if ! [ -f /nextcloud/custom_apps/notify_push/bin/"$CPU_ARCH"/notify_push ]; then
|
||||
if ! [ -f /var/www/html/custom_apps/notify_push/bin/"$CPU_ARCH"/notify_push ]; then
|
||||
echo "The notify_push binary was not found."
|
||||
echo "Most likely is DNS resolution not working correctly."
|
||||
echo "You can try to fix this by configuring a DNS server globally in dockers daemon.json."
|
||||
@@ -44,52 +38,9 @@ fi
|
||||
|
||||
echo "notify-push was started"
|
||||
|
||||
# Set a default value for POSTGRES_PORT
|
||||
if [ -z "$POSTGRES_PORT" ]; then
|
||||
POSTGRES_PORT=5432
|
||||
fi
|
||||
# Set a default for redis db index
|
||||
if [ -z "$REDIS_DB_INDEX" ]; then
|
||||
REDIS_DB_INDEX=0
|
||||
fi
|
||||
# Set a default value for REDIS_PORT
|
||||
if [ -z "$REDIS_PORT" ]; then
|
||||
REDIS_PORT=6379
|
||||
fi
|
||||
# Set a default for db type
|
||||
if [ -z "$DATABASE_TYPE" ]; then
|
||||
DATABASE_TYPE=postgres
|
||||
elif [ "$DATABASE_TYPE" != postgres ] && [ "$DATABASE_TYPE" != mysql ]; then
|
||||
echo "DB type must be either postgres or mysql"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use the correct Postgres username
|
||||
if [ "$POSTGRES_USER" = nextcloud ]; then
|
||||
POSTGRES_USER="oc_$POSTGRES_USER"
|
||||
export POSTGRES_USER
|
||||
fi
|
||||
|
||||
# URL-encode passwords
|
||||
POSTGRES_PASSWORD="$(jq -rn --arg v "$POSTGRES_PASSWORD" '$v|@uri')"
|
||||
REDIS_HOST_PASSWORD="$(jq -rn --arg v "$REDIS_HOST_PASSWORD" '$v|@uri')"
|
||||
|
||||
# Postgres root cert
|
||||
if [ -f "/nextcloud/data/certificates/POSTGRES" ]; then
|
||||
CERT_OPTIONS="?sslmode=verify-ca&sslrootcert=/nextcloud/data/certificates/ca-bundle.crt"
|
||||
# Mysql root cert
|
||||
elif [ -f "/nextcloud/data/certificates/MYSQL" ]; then
|
||||
CERT_OPTIONS="?sslmode=verify-ca&ssl-ca=/nextcloud/data/certificates/ca-bundle.crt"
|
||||
fi
|
||||
|
||||
# Set sensitive values as env
|
||||
export DATABASE_URL="$DATABASE_TYPE://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB$CERT_OPTIONS"
|
||||
export REDIS_URL="redis://$REDIS_USER:$REDIS_HOST_PASSWORD@$REDIS_HOST:$REDIS_PORT/$REDIS_DB_INDEX"
|
||||
|
||||
# Run it
|
||||
/nextcloud/custom_apps/notify_push/bin/"$CPU_ARCH"/notify_push \
|
||||
--database-prefix="oc_" \
|
||||
--nextcloud-url "https://$NC_DOMAIN" \
|
||||
--port 7867
|
||||
/var/www/html/custom_apps/notify_push/bin/"$CPU_ARCH"/notify_push \
|
||||
--port 7867 \
|
||||
/var/www/html/config/config.php
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# From https://github.com/ONLYOFFICE/Docker-DocumentServer/blob/master/Dockerfile
|
||||
FROM onlyoffice/documentserver:9.2.1.1
|
||||
FROM onlyoffice/documentserver:9.3.1.2
|
||||
|
||||
# USER root is probably used
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# From https://github.com/docker-library/postgres/blob/master/17/alpine3.23/Dockerfile
|
||||
FROM postgres:17.8-alpine
|
||||
FROM postgres:17.9-alpine
|
||||
|
||||
COPY --chmod=775 start.sh /start.sh
|
||||
COPY --chmod=775 healthcheck.sh /healthcheck.sh
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# From https://github.com/redis/docker-library-redis/blob/release/8.2/alpine/Dockerfile
|
||||
FROM redis:8.2.3-alpine
|
||||
FROM redis:8.6.1-alpine
|
||||
|
||||
COPY --chmod=775 start.sh /start.sh
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ RUN set -ex; \
|
||||
xvfb \
|
||||
ffmpeg \
|
||||
firefox \
|
||||
font-noto-all \
|
||||
font-noto-cjk \
|
||||
font-noto-cjk-extra \
|
||||
bind-tools \
|
||||
netcat-openbsd \
|
||||
git \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM nats:2.12.4-scratch AS nats
|
||||
FROM nats:2.12.5-scratch AS nats
|
||||
FROM eturnal/eturnal:1.12.2-alpine AS eturnal
|
||||
FROM strukturag/nextcloud-spreed-signaling:2.1.0 AS signaling
|
||||
FROM strukturag/nextcloud-spreed-signaling:2.1.1 AS signaling
|
||||
FROM alpine:3.23.3 AS janus
|
||||
|
||||
ARG JANUS_VERSION=v1.4.0
|
||||
@@ -70,7 +70,8 @@ RUN set -ex; \
|
||||
libwebsockets \
|
||||
\
|
||||
shadow \
|
||||
grep; \
|
||||
grep \
|
||||
util-linux-misc; \
|
||||
useradd --system -u 1000 eturnal; \
|
||||
apk del --no-cache \
|
||||
shadow; \
|
||||
|
||||
@@ -18,6 +18,22 @@ elif [ -z "$INTERNAL_SECRET" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Trust additional CA certificates, if the user provided NEXTCLOUD_TRUSTED_CACERTS_DIR
|
||||
# The container is read-only, so we build a custom bundle in /tmp (tmpfs) and
|
||||
# point Go's TLS stack to it via SSL_CERT_FILE.
|
||||
if mountpoint -q /usr/local/share/ca-certificates; then
|
||||
echo "Trusting additional CA certificates..."
|
||||
set -x
|
||||
cp /etc/ssl/certs/ca-certificates.crt /tmp/ca-certificates.crt
|
||||
for cert in /usr/local/share/ca-certificates/*; do
|
||||
if [ -f "$cert" ]; then
|
||||
cat "$cert" >> /tmp/ca-certificates.crt
|
||||
fi
|
||||
done
|
||||
export SSL_CERT_FILE=/tmp/ca-certificates.crt
|
||||
set +x
|
||||
fi
|
||||
|
||||
set -x
|
||||
IPv4_ADDRESS_TALK_RELAY="$(hostname -i | grep -oP '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
|
||||
# shellcheck disable=SC2153
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM golang:1.26.0-alpine3.23 AS go
|
||||
FROM golang:1.26.1-alpine3.23 AS go
|
||||
|
||||
ENV WATCHTOWER_COMMIT_HASH=b09b3a5c5e1094b746575a19a7fc0135c8908c9d
|
||||
ENV WATCHTOWER_COMMIT_HASH=5a33e3c0aa3b2770c648a114b4a9d32e0a5b55ba
|
||||
|
||||
RUN set -ex; \
|
||||
apk upgrade --no-cache -a; \
|
||||
apk add --no-cache \
|
||||
build-base; \
|
||||
go install github.com/nicholas-fedor/watchtower@$WATCHTOWER_COMMIT_HASH # v1.14.1
|
||||
go install github.com/nicholas-fedor/watchtower@$WATCHTOWER_COMMIT_HASH # v1.14.4
|
||||
|
||||
FROM alpine:3.23.3
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
# Probably from this file: https://github.com/nextcloud/whiteboard/blob/main/Dockerfile
|
||||
FROM ghcr.io/nextcloud-releases/whiteboard:v1.5.6
|
||||
FROM ghcr.io/nextcloud-releases/whiteboard:v1.5.7
|
||||
|
||||
USER root
|
||||
RUN set -ex; \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
## Caddy with geoblocking
|
||||
This container bundles caddy and auto-configures it for you. It also covers [vaultwarden](https://github.com/nextcloud/all-in-one/tree/main/community-containers/vaultwarden) by listening on `bw.$NC_DOMAIN`, if installed. It also covers [stalwart](https://github.com/nextcloud/all-in-one/tree/main/community-containers/stalwart) by listening on `mail.$NC_DOMAIN`, if installed. It also covers [jellyfin](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyfin) by listening on `media.$NC_DOMAIN`, if installed. It also covers [lldap](https://github.com/nextcloud/all-in-one/tree/main/community-containers/lldap) by listening on `ldap.$NC_DOMAIN`, if installed. It also covers [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb) by listening on `tables.$NC_DOMAIN`, if installed. It also covers [jellyseerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr) by listening on `requests.$NC_DOMAIN`, if installed. It also covers [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter) by listening on `metrics.$NC_DOMAIN`, if installed. It also covers [LocalAI](https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai) by listening on `ai.$NC_DOMAIN`, if installed.
|
||||
This container bundles caddy and auto-configures it for you. It also covers [vaultwarden](https://github.com/nextcloud/all-in-one/tree/main/community-containers/vaultwarden) by listening on `bw.$NC_DOMAIN`, if installed. It also covers [stalwart](https://github.com/nextcloud/all-in-one/tree/main/community-containers/stalwart) by listening on `mail.$NC_DOMAIN`, if installed. It also covers [jellyfin](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyfin) by listening on `media.$NC_DOMAIN`, if installed. It also covers [lldap](https://github.com/nextcloud/all-in-one/tree/main/community-containers/lldap) by listening on `ldap.$NC_DOMAIN`, if installed. It also covers [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb) by listening on `tables.$NC_DOMAIN`, if installed. It also covers [seerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr) by listening on `requests.$NC_DOMAIN`, if installed. It also covers [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter) by listening on `metrics.$NC_DOMAIN`, if installed. It also covers [LocalAI](https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai) by listening on `ai.$NC_DOMAIN`, if installed.
|
||||
|
||||
### Notes
|
||||
- This container is incompatible with the [npmplus](https://github.com/nextcloud/all-in-one/tree/main/community-containers/npmplus) community container. So make sure that you do not enable both at the same time!
|
||||
@@ -12,7 +12,7 @@ This container bundles caddy and auto-configures it for you. It also covers [vau
|
||||
- If you want to use this with [jellyfin](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyfin), make sure that you point `media.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for jellyfin.
|
||||
- If you want to use this with [lldap](https://github.com/nextcloud/all-in-one/tree/main/community-containers/lldap), make sure that you point `ldap.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for lldap.
|
||||
- If you want to use this with [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb), make sure that you point `tables.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for nocodb.
|
||||
- If you want to use this with [jellyseerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr), make sure that you point `requests.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for jellyseerr.
|
||||
- If you want to use this with [seerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr), make sure that you point `requests.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for seerr.
|
||||
- If you want to use this with [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter), make sure that you point `metrics.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for nextcloud-exporter.
|
||||
- If you want to use this with [local AI](https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai), make sure that you point `ai.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for local AI.
|
||||
- After the container was started the first time, you should see a new `nextcloud-aio-caddy` folder and inside there an `allowed-countries.txt` file when you open the files app with the default `admin` user. In there you can adjust the allowed country codes for caddy by adding them to the first line, e.g. `IT FR` would allow access from italy and france. Private ip-ranges are always allowed. Additionally, in order to activate this config, you need to get an account at https://dev.maxmind.com/geoip/geolite2-free-geolocation-data and download the `GeoLite2-Country.mmdb` and upload it with this exact name into the `nextcloud-aio-caddy` folder. Afterwards restart all containers from the AIO interface and your new config should be active!
|
||||
|
||||
38
community-containers/glances/glances.json
Normal file
38
community-containers/glances/glances.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"aio_services_v1": [
|
||||
{
|
||||
"container_name": "nextcloud-aio-glances",
|
||||
"display_name": "Glances",
|
||||
"documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/glances",
|
||||
"image": "nicolargo/glances",
|
||||
"image_tag": "latest-full",
|
||||
"internal_port": "61208",
|
||||
"restart": "unless-stopped",
|
||||
"ports": [
|
||||
{
|
||||
"ip_binding": "",
|
||||
"port_number": "61208",
|
||||
"protocol": "tcp"
|
||||
}
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"source": "nextcloud_aio_glances",
|
||||
"destination": "/etc/glances",
|
||||
"writeable": true
|
||||
},
|
||||
{
|
||||
"source": "%WATCHTOWER_DOCKER_SOCKET_PATH%",
|
||||
"destination": "/var/run/docker.sock",
|
||||
"writeable": false
|
||||
}
|
||||
],
|
||||
"environment": [
|
||||
"GLANCES_OPT=-w"
|
||||
],
|
||||
"backup_volumes": [
|
||||
"nextcloud_aio_glances"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
18
community-containers/glances/readme.md
Normal file
18
community-containers/glances/readme.md
Normal file
@@ -0,0 +1,18 @@
|
||||
## Glances
|
||||
This container starts Glances, a web-based info-board, and auto-configures it for you.
|
||||
|
||||
> [!CAUTION]
|
||||
> This container mounts the docker-socket from the host-system.
|
||||
|
||||
### Notes
|
||||
- After adding and starting the container, you can directly visit http://ip.address.of.server:61208/ and access your new Glances instance!
|
||||
- It is recommended to start this container only in home networks, because there is no built-in authentication. But you can do a http-auth with your proxy.
|
||||
- In order to access your Glances outside the local network, you have to set up your own reverse proxy. You can set up a reverse proxy following [these instructions](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md).
|
||||
- The data of Glances will be automatically included in AIO's backup solution!
|
||||
- See [here](https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers) how to add it to the AIO stack.
|
||||
|
||||
### Repository
|
||||
https://github.com/nicolargo/glances
|
||||
|
||||
### Maintainer
|
||||
https://github.com/pi-farm
|
||||
@@ -2,13 +2,13 @@
|
||||
"aio_services_v1": [
|
||||
{
|
||||
"container_name": "nextcloud-aio-jellyseerr",
|
||||
"display_name": "Jellyseerr",
|
||||
"display_name": "Seerr",
|
||||
"documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr",
|
||||
"image": "fallenbagel/jellyseerr",
|
||||
"image": "ghcr.io/seerr-team/seerr",
|
||||
"image_tag": "latest",
|
||||
"internal_port": "5055",
|
||||
"restart": "unless-stopped",
|
||||
"init": false,
|
||||
"init": true,
|
||||
"ports": [
|
||||
{
|
||||
"ip_binding": "%APACHE_IP_BINDING%",
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
## Jellyseerr
|
||||
This container bundles Jellyseerr and auto-configures it for you.
|
||||
## Seerr
|
||||
This container bundles Seerr and auto-configures it for you.
|
||||
|
||||
### Notes
|
||||
- **Migration from Jellyseerr**: Jellyseer previously ran as the root user. With the migration to Seerr, the container now runs rootless with userid 1000, meaning that if you previously used Jellyseerr, Seerr will not be able to access the config files generated by the old Jellyseerr container. To migrate, execute the following steps: 1. stop all containers using the AIO-interface, 2. run `sudo docker run --rm -v nextcloud_aio_jellyseerr:/data alpine chown -R 1000:1000 /data`
|
||||
- This container is only intended to be used inside home networks as it uses http for its management page by default.
|
||||
- After adding and starting the container, you can directly visit `http://ip.address.of.server:5055` and access your new Jellyseerr instance, which can be used to manage Plex, Jellyfin, and Emby.
|
||||
- In order to access your Jellyseerr outside the local network, you have to set up your own reverse proxy. You can set up a reverse proxy following [these instructions](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md) and [Jellyseerr's reverse proxy documentation.](https://docs.jellyseerr.dev/extending-jellyseerr/reverse-proxy), OR use the Caddy community container that will automatically configure requests.$NC_DOMAIN to redirect to your Jellyseerr. Note that it is recommended to [enable CSRF protection in Jellyseerr](https://docs.jellyseerr.dev/using-jellyseerr/settings/general#enable-csrf-protection) for added security if you plan to use Jellyseerr outside the local network, but make sure to read up on it and understand the caveats first.
|
||||
- If you want to secure the installation with fail2ban, you might want to check out https://github.com/nextcloud/all-in-one/tree/main/community-containers/fail2ban. Note that [enabling the proxy support option in Jellyseerr](https://docs.jellyseerr.dev/using-jellyseerr/settings/general#enable-proxy-support) is required for this to work properly.
|
||||
- The config of Jellyseerr will be automatically included in AIO's backup solution!
|
||||
- After adding and starting the container, you can directly visit `http://ip.address.of.server:5055` and access your new Seerr instance, which can be used to manage Plex, Jellyfin, and Emby.
|
||||
- In order to access your Seerr outside the local network, you have to set up your own reverse proxy. You can set up a reverse proxy following [these instructions](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md) and [Seerr's reverse proxy documentation.](https://docs.seerr.dev/extending-Seerr/reverse-proxy), OR use the Caddy community container that will automatically configure requests.$NC_DOMAIN to redirect to your Seerr. Note that it is recommended to [enable CSRF protection in Seerr](https://docs.seerr.dev/using-Seerr/settings/general#enable-csrf-protection) for added security if you plan to use Seerr outside the local network, but make sure to read up on it and understand the caveats first.
|
||||
- If you want to secure the installation with fail2ban, you might want to check out https://github.com/nextcloud/all-in-one/tree/main/community-containers/fail2ban. Note that [enabling the proxy support option in Seerr](https://docs.seerr.dev/using-Seerr/settings/general#enable-proxy-support) is required for this to work properly.
|
||||
- The config of Seerr will be automatically included in AIO's backup solution!
|
||||
- See [here](https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers) how to add it to the AIO stack.
|
||||
|
||||
### Repository
|
||||
https://github.com/Fallenbagel/jellyseerr
|
||||
https://github.com/seerr-team/seerr
|
||||
|
||||
### Maintainer
|
||||
https://github.com/Anvil5465
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
## LanguageTool for Collabora
|
||||
This container bundles a LanguageTool for Collabora which adds spell checking functionality to Collabora.
|
||||
## LanguageTool for Nextcloud Office
|
||||
This container bundles a LanguageTool for Nextcloud Office which adds spell checking functionality to Nextcloud Office.
|
||||
|
||||
### Notes
|
||||
- Make sure to have collabora enabled via the AIO interface
|
||||
- After adding this container via the AIO Interface, while all containers are still stopped, you need to scroll down to the `Additional Collabora options` section and enter `--o:languagetool.enabled=true --o:languagetool.base_url=http://nextcloud-aio-languagetool:8010/v2`.
|
||||
- Make sure to have Nextcloud Office enabled via the AIO interface
|
||||
- After adding this container via the AIO Interface, while all containers are still stopped, you need to scroll down to the `Additional Nextcloud Office options` section and enter `--o:languagetool.enabled=true --o:languagetool.base_url=http://nextcloud-aio-languagetool:8010/v2`.
|
||||
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
|
||||
|
||||
### Repository
|
||||
|
||||
@@ -11,9 +11,9 @@ services:
|
||||
network_mode: bridge # This adds the container to the same network as docker run would do. Comment this line and uncomment the line below and the networks section at the end of the file if you want to define a custom MTU size for the docker network
|
||||
# networks: ["nextcloud-aio"]
|
||||
ports:
|
||||
- 80:80 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
- 8080:8080 # This is the AIO interface, served via https and self-signed certificate. See https://github.com/nextcloud/all-in-one#explanation-of-used-ports
|
||||
- 8443:8443 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
- "80:80" # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
- "8080:8080" # This is the AIO interface, served via https and self-signed certificate. See https://github.com/nextcloud/all-in-one#explanation-of-used-ports
|
||||
- "8443:8443" # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
# security_opt: ["label:disable"] # Is needed when using SELinux. See https://github.com/nextcloud/all-in-one#are-there-known-problems-when-selinux-is-enabled
|
||||
# environment: # Is needed when using any of the options below
|
||||
# AIO_DISABLE_BACKUP_SECTION: false # Setting this to true allows to hide the backup section in the AIO interface. See https://github.com/nextcloud/all-in-one#how-to-disable-the-backup-section
|
||||
|
||||
@@ -45,6 +45,7 @@ services:
|
||||
- APACHE_MAX_TIME=${NEXTCLOUD_MAX_TIME}
|
||||
- NOTIFY_PUSH_HOST=nextcloud-aio-notify-push
|
||||
- WHITEBOARD_HOST=nextcloud-aio-whiteboard
|
||||
- HARP_HOST=nextcloud-aio-harp
|
||||
volumes:
|
||||
- nextcloud_aio_nextcloud:/var/www/html:ro
|
||||
- nextcloud_aio_apache:/mnt/data:rw
|
||||
@@ -202,19 +203,10 @@ services:
|
||||
expose:
|
||||
- "7867"
|
||||
volumes:
|
||||
- nextcloud_aio_nextcloud:/nextcloud:ro
|
||||
- nextcloud_aio_nextcloud:/var/www/html:ro
|
||||
environment:
|
||||
- NC_DOMAIN
|
||||
- NEXTCLOUD_HOST=nextcloud-aio-nextcloud
|
||||
- TZ=${TIMEZONE}
|
||||
- REDIS_HOST=nextcloud-aio-redis
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_HOST_PASSWORD=${REDIS_PASSWORD}
|
||||
- POSTGRES_HOST=nextcloud-aio-database
|
||||
- POSTGRES_PORT=5432
|
||||
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
|
||||
- POSTGRES_DB=nextcloud_database
|
||||
- POSTGRES_USER=nextcloud
|
||||
restart: unless-stopped
|
||||
read_only: true
|
||||
cap_drop:
|
||||
|
||||
@@ -12,7 +12,7 @@ You can run the containers that are build for AIO with docker-compose. This come
|
||||
- You lose the AIO interface
|
||||
- You lose update notifications and automatic updates
|
||||
- You lose all AIO backup and restore features
|
||||
- You lose the built-in [Docker Socket Proxy container](https://github.com/nextcloud/docker-socket-proxy#readme) (needed for [Nextcloud App API](https://github.com/nextcloud/app_api#nextcloud-appapi))
|
||||
- You lose the built-in [Docker Socket Proxy container](https://github.com/nextcloud/docker-socket-proxy#readme) and [HaRP container](https://github.com/nextcloud/HaRP) (needed for [Nextcloud App API](https://github.com/nextcloud/app_api#nextcloud-appapi))
|
||||
- You lose all community containers: https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers
|
||||
- **You need to know what you are doing, especially when modifying the compose.yaml file**
|
||||
- For updating, you need to strictly follow the at the bottom described update routine
|
||||
|
||||
@@ -27,6 +27,8 @@ OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "next
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-borgbackup"))')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-docker-socket-proxy"))')"
|
||||
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 'del(.services[] | select(.container_name == "nextcloud-aio-harp"))')"
|
||||
OUTPUT="$(echo "$OUTPUT" | jq '.services[] |= if has("depends_on") then .depends_on |= if contains(["nextcloud-aio-harp"]) then del(.[index("nextcloud-aio-harp")]) 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
|
||||
@@ -45,6 +47,8 @@ sed -i 's|- ip_binding: |- |' containers.yml
|
||||
sed -i '/AIO_TOKEN/d' containers.yml
|
||||
sed -i '/AIO_URL/d' containers.yml
|
||||
sed -i '/DOCKER_SOCKET_PROXY_ENABLED/d' containers.yml
|
||||
sed -i '/HARP_ENABLED/d' containers.yml
|
||||
sed -i '/HP_SHARED_KEY/d' containers.yml
|
||||
sed -i '/ADDITIONAL_TRUSTED_PROXY/d' containers.yml
|
||||
sed -i '/TURN_DOMAIN/d' containers.yml
|
||||
sed -i '/NC_AIO_VERSION/d' containers.yml
|
||||
|
||||
@@ -180,6 +180,7 @@ apt install --no-install-recommends qemu-system qemu-utils libvirt-clients libvi
|
||||
# Virtual machine #1 - "example1-com"
|
||||
https://[DOMAIN_NAME_1]:8443 {
|
||||
reverse_proxy https://[IP_ADDRESS_1]:8080 {
|
||||
header_up Host {host}
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
@@ -192,6 +193,7 @@ apt install --no-install-recommends qemu-system qemu-utils libvirt-clients libvi
|
||||
# Virtual machine #2 - "example2-com"
|
||||
https://[DOMAIN_NAME_2]:8443 {
|
||||
reverse_proxy https://[IP_ADDRESS_2]:8080 {
|
||||
header_up Host {host}
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: nextcloud-aio-helm-chart
|
||||
description: A generated Helm Chart for Nextcloud AIO from Skippbox Kompose
|
||||
version: 12.6.1
|
||||
version: 12.8.0
|
||||
apiVersion: v2
|
||||
keywords:
|
||||
- latest
|
||||
|
||||
@@ -47,6 +47,8 @@ spec:
|
||||
value: "{{ .Values.APACHE_PORT }}"
|
||||
- name: COLLABORA_HOST
|
||||
value: nextcloud-aio-collabora
|
||||
- name: HARP_HOST
|
||||
value: nextcloud-aio-harp
|
||||
- name: NC_DOMAIN
|
||||
value: "{{ .Values.NC_DOMAIN }}"
|
||||
- name: NEXTCLOUD_HOST
|
||||
@@ -61,7 +63,7 @@ spec:
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
- name: WHITEBOARD_HOST
|
||||
value: nextcloud-aio-whiteboard
|
||||
image: ghcr.io/nextcloud-releases/aio-apache:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-apache:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -36,7 +36,7 @@ spec:
|
||||
{{- end }}
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260306_081319
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
@@ -59,7 +59,7 @@ spec:
|
||||
value: "{{ .Values.NEXTCLOUD_UPLOAD_LIMIT }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-clamav:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-clamav:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -36,9 +36,9 @@ spec:
|
||||
- name: server_name
|
||||
value: "{{ .Values.NC_DOMAIN }}"
|
||||
{{- if contains "--o:support_key=" (join " " (.Values.ADDITIONAL_COLLABORA_OPTIONS | default list)) }}
|
||||
image: ghcr.io/nextcloud-releases/aio-collabora-online:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-collabora-online:20260306_081319
|
||||
{{- else }}
|
||||
image: ghcr.io/nextcloud-releases/aio-collabora:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-collabora:20260306_081319
|
||||
{{- end }}
|
||||
readinessProbe:
|
||||
exec:
|
||||
|
||||
@@ -35,7 +35,7 @@ spec:
|
||||
{{- end }}
|
||||
initContainers:
|
||||
- name: init-subpath
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260306_081319
|
||||
command:
|
||||
- mkdir
|
||||
- "-p"
|
||||
@@ -64,7 +64,7 @@ spec:
|
||||
value: nextcloud
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-postgresql:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-postgresql:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -24,7 +24,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260306_081319
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -54,7 +54,7 @@ spec:
|
||||
value: basic
|
||||
- name: xpack.security.enabled
|
||||
value: "false"
|
||||
image: ghcr.io/nextcloud-releases/aio-fulltextsearch:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-fulltextsearch:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -38,7 +38,7 @@ spec:
|
||||
value: "{{ .Values.IMAGINARY_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-imaginary:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-imaginary:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -38,7 +38,7 @@ spec:
|
||||
# AIO settings start # Do not remove or change this line!
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260306_081319
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -190,7 +190,7 @@ spec:
|
||||
value: "{{ .Values.WHITEBOARD_ENABLED }}"
|
||||
- name: WHITEBOARD_SECRET
|
||||
value: "{{ .Values.WHITEBOARD_SECRET }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-nextcloud:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-nextcloud:20260306_081319
|
||||
{{- if eq (.Values.RPSS_ENABLED | default "no") "yes" }} # AIO-config - do not change this comment!
|
||||
securityContext:
|
||||
# The items below only work in container context
|
||||
|
||||
@@ -35,29 +35,11 @@ spec:
|
||||
{{- end }}
|
||||
containers:
|
||||
- env:
|
||||
- name: NC_DOMAIN
|
||||
value: "{{ .Values.NC_DOMAIN }}"
|
||||
- name: NEXTCLOUD_HOST
|
||||
value: nextcloud-aio-nextcloud
|
||||
- name: POSTGRES_DB
|
||||
value: nextcloud_database
|
||||
- name: POSTGRES_HOST
|
||||
value: nextcloud-aio-database
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: "{{ .Values.DATABASE_PASSWORD }}"
|
||||
- name: POSTGRES_PORT
|
||||
value: "5432"
|
||||
- name: POSTGRES_USER
|
||||
value: nextcloud
|
||||
- name: REDIS_HOST
|
||||
value: nextcloud-aio-redis
|
||||
- name: REDIS_HOST_PASSWORD
|
||||
value: "{{ .Values.REDIS_PASSWORD }}"
|
||||
- name: REDIS_PORT
|
||||
value: "6379"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-notify-push:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-notify-push:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
@@ -86,7 +68,7 @@ spec:
|
||||
drop: ["NET_RAW"]
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- mountPath: /nextcloud
|
||||
- mountPath: /var/www/html
|
||||
name: nextcloud-aio-nextcloud
|
||||
readOnly: true
|
||||
volumes:
|
||||
|
||||
@@ -24,7 +24,7 @@ spec:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: init-volumes
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-alpine:20260306_081319
|
||||
command:
|
||||
- chmod
|
||||
- "777"
|
||||
@@ -42,7 +42,7 @@ spec:
|
||||
value: "{{ .Values.ONLYOFFICE_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-onlyoffice:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-onlyoffice:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -39,7 +39,7 @@ spec:
|
||||
value: "{{ .Values.REDIS_PASSWORD }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-redis:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-redis:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -52,7 +52,7 @@ spec:
|
||||
value: "{{ .Values.TURN_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-talk:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-talk:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -44,7 +44,7 @@ spec:
|
||||
value: "{{ .Values.RECORDING_SECRET }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-talk-recording:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-talk-recording:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -50,7 +50,7 @@ spec:
|
||||
value: redis
|
||||
- name: TZ
|
||||
value: "{{ .Values.TIMEZONE }}"
|
||||
image: ghcr.io/nextcloud-releases/aio-whiteboard:20260211_141900
|
||||
image: ghcr.io/nextcloud-releases/aio-whiteboard:20260306_081319
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
|
||||
@@ -418,8 +418,9 @@ sed -i 's|= |: |' /tmp/sample.conf
|
||||
sed -i '/^NEXTCLOUD_DATADIR/d' /tmp/sample.conf
|
||||
sed -i '/^APACHE_IP_BINDING/d' /tmp/sample.conf
|
||||
sed -i '/^NEXTCLOUD_MOUNT/d' /tmp/sample.conf
|
||||
sed -i '/_ENABLED.*/s/ yes / "yes" /' /tmp/sample.conf
|
||||
sed -i '/_ENABLED.*/s/ no / "no" /' /tmp/sample.conf
|
||||
sed -i 's/ yes / "yes" /' /tmp/sample.conf
|
||||
sed -i 's/ no / "no" /' /tmp/sample.conf
|
||||
sed -i 's/"no" authentication/no authentication/' /tmp/sample.conf
|
||||
sed -i 's|^NEXTCLOUD_TRUSTED_CACERTS_DIR: .*|NEXTCLOUD_TRUSTED_CACERTS_DIR: # Setting this to any value allows to automatically import root certificates into the Nextcloud container|' /tmp/sample.conf
|
||||
sed -i 's|17179869184|"17179869184"|' /tmp/sample.conf
|
||||
# shellcheck disable=SC2129
|
||||
|
||||
@@ -26,7 +26,7 @@ APACHE_PORT: 443 # Changing this to a different value than 443 will all
|
||||
ADDITIONAL_COLLABORA_OPTIONS: ['--o:security.seccomp=true'] # You can add additional collabora options here by using the array syntax.
|
||||
COLLABORA_DICTIONARIES: de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru # You can change this in order to enable other dictionaries for collabora
|
||||
FULLTEXTSEARCH_JAVA_OPTIONS: -Xms512M -Xmx512M # Allows to adjust the fulltextsearch java options.
|
||||
INSTALL_LATEST_MAJOR: no # Setting this to yes will install the latest Major Nextcloud version upon the first installation
|
||||
INSTALL_LATEST_MAJOR: "no" # Setting this to "yes" will install the latest Major Nextcloud version upon the first installation
|
||||
NEXTCLOUD_ADDITIONAL_APKS: imagemagick # This allows to add additional packages to the Nextcloud container permanently. Default is imagemagick but can be overwritten by modifying this value.
|
||||
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.
|
||||
NEXTCLOUD_MAX_TIME: 3600 # This allows to change the upload time limit of the Nextcloud container
|
||||
@@ -34,9 +34,9 @@ NEXTCLOUD_MEMORY_LIMIT: 512M # This allows to change the PHP memory lim
|
||||
NEXTCLOUD_STARTUP_APPS: deck twofactor_totp tasks calendar contacts notes # Allows to modify the Nextcloud apps that are installed on starting AIO the first time
|
||||
NEXTCLOUD_TRUSTED_CACERTS_DIR: # Setting this to any value allows to automatically import root certificates into the Nextcloud container
|
||||
NEXTCLOUD_UPLOAD_LIMIT: 16G # This allows to change the upload limit of the Nextcloud container
|
||||
REMOVE_DISABLED_APPS: yes # Setting this to no keep Nextcloud apps that are disabled via their switch and not uninstall them if they should be installed in Nextcloud.
|
||||
REMOVE_DISABLED_APPS: "yes" # Setting this to "no" keep Nextcloud apps that are disabled via their switch and not uninstall them if they should be installed in Nextcloud.
|
||||
TALK_PORT: 3478 # This allows to adjust the port that the talk container is using. It should be set to something higher than 1024! Otherwise it might not work!
|
||||
UPDATE_NEXTCLOUD_APPS: no # When setting to yes (with quotes), it will automatically update all installed Nextcloud apps upon container startup on saturdays.
|
||||
UPDATE_NEXTCLOUD_APPS: "no" # When setting to "yes" (with quotes), it will automatically update all installed Nextcloud apps upon container startup on saturdays.
|
||||
|
||||
STORAGE_CLASS: # By setting this, you can adjust the storage class for your volumes. This should be a fast storage like SSD backed storage! This storage class must provide RWX and RWO volumes (ReadWriteMany and ReadWriteOnce).
|
||||
STORAGE_CLASS_DATA: # Allows to set a dedicated storage class for the Nextcloud data volume. This can be a bit slower storage than the one above. This storage class must provide RWX volumes (ReadWriteMany). ⚠️ Warning: only set this for new installations, not existing ones!
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "8.4.*",
|
||||
"php": "8.5.*",
|
||||
"ext-json": "*",
|
||||
"ext-sodium": "*",
|
||||
"ext-curl": "*",
|
||||
@@ -16,7 +16,8 @@
|
||||
"http-interop/http-factory-guzzle": "^1.2",
|
||||
"slim/twig-view": "^3.3",
|
||||
"slim/csrf": "^1.3",
|
||||
"ext-apcu": "*"
|
||||
"ext-apcu": "*",
|
||||
"slim/psr7": "^1.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"sserbin/twig-linter": "@dev",
|
||||
@@ -33,6 +34,6 @@
|
||||
"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.4 src/*.php src/**/*.php public/index.php"
|
||||
"php-deprecation-detector": "phpdd scan -n -t 8.5 src/*.php src/**/*.php public/index.php"
|
||||
}
|
||||
}
|
||||
|
||||
297
php/composer.lock
generated
297
php/composer.lock
generated
@@ -4,8 +4,64 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "19598625395cc28e64f15d2719f8f98f",
|
||||
"content-hash": "e49cef2ac29c2198aececcb842fce2fe",
|
||||
"packages": [
|
||||
{
|
||||
"name": "fig/http-message-util",
|
||||
"version": "1.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-message-util.git",
|
||||
"reference": "9d94dc0154230ac39e5bf89398b324a86f63f765"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765",
|
||||
"reference": "9d94dc0154230ac39e5bf89398b324a86f63f765",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3 || ^7.0 || ^8.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/http-message": "The package containing the PSR-7 interfaces"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Fig\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Utility classes and constants for use with PSR-7 (psr/http-message)",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-message",
|
||||
"psr",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-fig/http-message-util/issues",
|
||||
"source": "https://github.com/php-fig/http-message-util/tree/1.1.5"
|
||||
},
|
||||
"time": "2020-11-24T22:02:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "7.10.0",
|
||||
@@ -217,16 +273,16 @@
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "2.8.0",
|
||||
"version": "2.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "21dc724a0583619cd1652f673303492272778051"
|
||||
"reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
|
||||
"reference": "21dc724a0583619cd1652f673303492272778051",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884",
|
||||
"reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -242,6 +298,7 @@
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"http-interop/http-factory-tests": "0.9.0",
|
||||
"jshttp/mime-db": "1.54.0.1",
|
||||
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
|
||||
},
|
||||
"suggest": {
|
||||
@@ -313,7 +370,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/psr7/issues",
|
||||
"source": "https://github.com/guzzle/psr7/tree/2.8.0"
|
||||
"source": "https://github.com/guzzle/psr7/tree/2.9.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -329,7 +386,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-23T21:21:41+00:00"
|
||||
"time": "2026-03-10T16:41:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "http-interop/http-factory-guzzle",
|
||||
@@ -391,16 +448,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
"version": "v2.0.9",
|
||||
"version": "v2.0.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/serializable-closure.git",
|
||||
"reference": "8f631589ab07b7b52fead814965f5a800459cb3e"
|
||||
"reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/8f631589ab07b7b52fead814965f5a800459cb3e",
|
||||
"reference": "8f631589ab07b7b52fead814965f5a800459cb3e",
|
||||
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/870fc81d2f879903dfc5b60bf8a0f94a1609e669",
|
||||
"reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -448,7 +505,7 @@
|
||||
"issues": "https://github.com/laravel/serializable-closure/issues",
|
||||
"source": "https://github.com/laravel/serializable-closure"
|
||||
},
|
||||
"time": "2026-02-03T06:55:34+00:00"
|
||||
"time": "2026-02-20T19:59:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
@@ -1146,6 +1203,85 @@
|
||||
},
|
||||
"time": "2025-11-02T14:58:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slim/psr7",
|
||||
"version": "1.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slimphp/Slim-Psr7.git",
|
||||
"reference": "76e7e3b1cdfd583e9035c4c966c08e01e45ce959"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/76e7e3b1cdfd583e9035c4c966c08e01e45ce959",
|
||||
"reference": "76e7e3b1cdfd583e9035c4c966c08e01e45ce959",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"fig/http-message-util": "^1.1.5",
|
||||
"php": "^8.0",
|
||||
"psr/http-factory": "^1.1",
|
||||
"psr/http-message": "^1.0 || ^2.0",
|
||||
"ralouphie/getallheaders": "^3.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-factory-implementation": "^1.0",
|
||||
"psr/http-message-implementation": "^1.0 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"adriansuter/php-autoload-override": "^1.5|| ^2.0",
|
||||
"ext-json": "*",
|
||||
"http-interop/http-factory-tests": "^1.0 || ^2.0",
|
||||
"php-http/psr7-integration-tests": "^1.5",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpunit/phpunit": "^9.6 || ^10",
|
||||
"squizlabs/php_codesniffer": "^3.13"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Slim\\Psr7\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Josh Lockhart",
|
||||
"email": "hello@joshlockhart.com",
|
||||
"homepage": "https://joshlockhart.com"
|
||||
},
|
||||
{
|
||||
"name": "Andrew Smith",
|
||||
"email": "a.smith@silentworks.co.uk",
|
||||
"homepage": "https://silentworks.co.uk"
|
||||
},
|
||||
{
|
||||
"name": "Rob Allen",
|
||||
"email": "rob@akrabat.com",
|
||||
"homepage": "https://akrabat.com"
|
||||
},
|
||||
{
|
||||
"name": "Pierre Berube",
|
||||
"email": "pierre@lgse.com",
|
||||
"homepage": "https://www.lgse.com"
|
||||
}
|
||||
],
|
||||
"description": "Strict PSR-7 implementation",
|
||||
"homepage": "https://www.slimframework.com",
|
||||
"keywords": [
|
||||
"http",
|
||||
"psr-7",
|
||||
"psr7"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/slimphp/Slim-Psr7/issues",
|
||||
"source": "https://github.com/slimphp/Slim-Psr7/tree/1.8.0"
|
||||
},
|
||||
"time": "2025-11-02T17:51:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "4.15.1",
|
||||
@@ -1644,16 +1780,16 @@
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.23.0",
|
||||
"version": "v3.24.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9"
|
||||
"reference": "a6769aefb305efef849dc25c9fd1653358c148f0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9",
|
||||
"reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a6769aefb305efef849dc25c9fd1653358c148f0",
|
||||
"reference": "a6769aefb305efef849dc25c9fd1653358c148f0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1663,7 +1799,8 @@
|
||||
"symfony/polyfill-mbstring": "^1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"php-cs-fixer/shim": "^3.0@stable",
|
||||
"phpstan/phpstan": "^2.0@stable",
|
||||
"psr/container": "^1.0|^2.0",
|
||||
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
|
||||
},
|
||||
@@ -1707,7 +1844,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.23.0"
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.24.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1719,7 +1856,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-23T21:00:41+00:00"
|
||||
"time": "2026-03-17T21:31:11+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@@ -3111,20 +3248,20 @@
|
||||
},
|
||||
{
|
||||
"name": "league/uri",
|
||||
"version": "7.8.0",
|
||||
"version": "7.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/uri.git",
|
||||
"reference": "4436c6ec8d458e4244448b069cc572d088230b76"
|
||||
"reference": "08cf38e3924d4f56238125547b5720496fac8fd4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76",
|
||||
"reference": "4436c6ec8d458e4244448b069cc572d088230b76",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri/zipball/08cf38e3924d4f56238125547b5720496fac8fd4",
|
||||
"reference": "08cf38e3924d4f56238125547b5720496fac8fd4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"league/uri-interfaces": "^7.8",
|
||||
"league/uri-interfaces": "^7.8.1",
|
||||
"php": "^8.1",
|
||||
"psr/http-factory": "^1"
|
||||
},
|
||||
@@ -3197,7 +3334,7 @@
|
||||
"docs": "https://uri.thephpleague.com",
|
||||
"forum": "https://thephpleague.slack.com",
|
||||
"issues": "https://github.com/thephpleague/uri-src/issues",
|
||||
"source": "https://github.com/thephpleague/uri/tree/7.8.0"
|
||||
"source": "https://github.com/thephpleague/uri/tree/7.8.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3205,20 +3342,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-14T17:24:56+00:00"
|
||||
"time": "2026-03-15T20:22:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/uri-interfaces",
|
||||
"version": "7.8.0",
|
||||
"version": "7.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/uri-interfaces.git",
|
||||
"reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4"
|
||||
"reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4",
|
||||
"reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/85d5c77c5d6d3af6c54db4a78246364908f3c928",
|
||||
"reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3281,7 +3418,7 @@
|
||||
"docs": "https://uri.thephpleague.com",
|
||||
"forum": "https://thephpleague.slack.com",
|
||||
"issues": "https://github.com/thephpleague/uri-src/issues",
|
||||
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0"
|
||||
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3289,20 +3426,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-15T06:54:53+00:00"
|
||||
"time": "2026-03-08T20:05:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
"version": "v5.0.0",
|
||||
"version": "v5.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cweiske/jsonmapper.git",
|
||||
"reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c"
|
||||
"reference": "980674efdda65913492d29a8fd51c82270dd37bb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c",
|
||||
"reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/980674efdda65913492d29a8fd51c82270dd37bb",
|
||||
"reference": "980674efdda65913492d29a8fd51c82270dd37bb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3338,9 +3475,9 @@
|
||||
"support": {
|
||||
"email": "cweiske@cweiske.de",
|
||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v5.0.0"
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v5.0.1"
|
||||
},
|
||||
"time": "2024-09-08T10:20:00+00:00"
|
||||
"time": "2026-02-22T16:28:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
@@ -3455,16 +3592,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "6.0.1",
|
||||
"version": "6.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e"
|
||||
"reference": "7bae67520aa9f5ecc506d646810bd40d9da54582"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2f5cbed597cb261d1ea458f3da3a9ad32e670b1e",
|
||||
"reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/7bae67520aa9f5ecc506d646810bd40d9da54582",
|
||||
"reference": "7bae67520aa9f5ecc506d646810bd40d9da54582",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3514,9 +3651,9 @@
|
||||
"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/6.0.1"
|
||||
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.3"
|
||||
},
|
||||
"time": "2026-01-20T15:30:42+00:00"
|
||||
"time": "2026-03-18T20:49:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
@@ -3902,16 +4039,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.4.32",
|
||||
"version": "v6.4.35",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3"
|
||||
"reference": "49257c96304c508223815ee965c251e7c79e614e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3",
|
||||
"reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/49257c96304c508223815ee965c251e7c79e614e",
|
||||
"reference": "49257c96304c508223815ee965c251e7c79e614e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3976,7 +4113,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v6.4.32"
|
||||
"source": "https://github.com/symfony/console/tree/v6.4.35"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3996,20 +4133,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-13T08:45:59+00:00"
|
||||
"time": "2026-03-06T13:31:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v8.0.1",
|
||||
"version": "v8.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "d937d400b980523dc9ee946bb69972b5e619058d"
|
||||
"reference": "7bf9162d7a0dff98d079b72948508fa48018a770"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d",
|
||||
"reference": "d937d400b980523dc9ee946bb69972b5e619058d",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7bf9162d7a0dff98d079b72948508fa48018a770",
|
||||
"reference": "7bf9162d7a0dff98d079b72948508fa48018a770",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4046,7 +4183,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v8.0.1"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v8.0.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4066,20 +4203,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-01T09:13:36+00:00"
|
||||
"time": "2026-02-25T16:59:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v6.4.33",
|
||||
"version": "v6.4.34",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "24965ca011dac87431729640feef8bcf7b5523e0"
|
||||
"reference": "9590e86be1d1c57bfbb16d0dd040345378c20896"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/24965ca011dac87431729640feef8bcf7b5523e0",
|
||||
"reference": "24965ca011dac87431729640feef8bcf7b5523e0",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/9590e86be1d1c57bfbb16d0dd040345378c20896",
|
||||
"reference": "9590e86be1d1c57bfbb16d0dd040345378c20896",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4114,7 +4251,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.33"
|
||||
"source": "https://github.com/symfony/finder/tree/v6.4.34"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4134,7 +4271,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-26T13:03:48+00:00"
|
||||
"time": "2026-01-28T15:16:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
@@ -4472,16 +4609,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v7.4.4",
|
||||
"version": "v7.4.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f"
|
||||
"reference": "9f209231affa85aa930a5e46e6eb03381424b30b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/1c4b10461bf2ec27537b5f36105337262f5f5d6f",
|
||||
"reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b",
|
||||
"reference": "9f209231affa85aa930a5e46e6eb03381424b30b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4539,7 +4676,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v7.4.4"
|
||||
"source": "https://github.com/symfony/string/tree/v7.4.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4559,20 +4696,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-12T10:54:30+00:00"
|
||||
"time": "2026-02-09T09:33:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vimeo/psalm",
|
||||
"version": "6.15.1",
|
||||
"version": "6.16.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vimeo/psalm.git",
|
||||
"reference": "28dc127af1b5aecd52314f6f645bafc10d0e11f9"
|
||||
"reference": "f1f5de594dc76faf8784e02d3dc4716c91c6f6ac"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vimeo/psalm/zipball/28dc127af1b5aecd52314f6f645bafc10d0e11f9",
|
||||
"reference": "28dc127af1b5aecd52314f6f645bafc10d0e11f9",
|
||||
"url": "https://api.github.com/repos/vimeo/psalm/zipball/f1f5de594dc76faf8784e02d3dc4716c91c6f6ac",
|
||||
"reference": "f1f5de594dc76faf8784e02d3dc4716c91c6f6ac",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4677,7 +4814,7 @@
|
||||
"issues": "https://github.com/vimeo/psalm/issues",
|
||||
"source": "https://github.com/vimeo/psalm"
|
||||
},
|
||||
"time": "2026-02-07T19:27:16+00:00"
|
||||
"time": "2026-03-19T10:56:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "wapmorgan/php-deprecation-detector",
|
||||
@@ -4748,16 +4885,16 @@
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "2.1.2",
|
||||
"version": "2.1.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozarts/assert.git",
|
||||
"reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649"
|
||||
"reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozarts/assert/zipball/ce6a2f100c404b2d32a1dd1270f9b59ad4f57649",
|
||||
"reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649",
|
||||
"url": "https://api.github.com/repos/webmozarts/assert/zipball/ff31ad6efc62e66e518fbab1cde3453d389bcdc8",
|
||||
"reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4804,9 +4941,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/webmozarts/assert/issues",
|
||||
"source": "https://github.com/webmozarts/assert/tree/2.1.2"
|
||||
"source": "https://github.com/webmozarts/assert/tree/2.1.6"
|
||||
},
|
||||
"time": "2026-01-13T14:02:24+00:00"
|
||||
"time": "2026-02-27T10:28:38+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
@@ -4818,7 +4955,7 @@
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "8.4.*",
|
||||
"php": "8.5.*",
|
||||
"ext-json": "*",
|
||||
"ext-sodium": "*",
|
||||
"ext-curl": "*",
|
||||
|
||||
@@ -47,7 +47,10 @@
|
||||
},
|
||||
"display_name": {
|
||||
"type": "string",
|
||||
"pattern": "^[()A-Za-z 0-9-]+$"
|
||||
"pattern": "^[()A-Za-z &0-9-]+$"
|
||||
},
|
||||
"hide_from_list": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"environment": {
|
||||
"type": "array",
|
||||
@@ -229,4 +232,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
"nextcloud-aio-talk",
|
||||
"nextcloud-aio-notify-push",
|
||||
"nextcloud-aio-whiteboard",
|
||||
"nextcloud-aio-harp",
|
||||
"nextcloud-aio-nextcloud"
|
||||
],
|
||||
"display_name": "Apache",
|
||||
"display_name": "Apache & Caddy",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-apache",
|
||||
"user": "33",
|
||||
"init": true,
|
||||
@@ -49,7 +50,8 @@
|
||||
"APACHE_MAX_SIZE=%APACHE_MAX_SIZE%",
|
||||
"APACHE_MAX_TIME=%NEXTCLOUD_MAX_TIME%",
|
||||
"NOTIFY_PUSH_HOST=nextcloud-aio-notify-push",
|
||||
"WHITEBOARD_HOST=nextcloud-aio-whiteboard"
|
||||
"WHITEBOARD_HOST=nextcloud-aio-whiteboard",
|
||||
"HARP_HOST=nextcloud-aio-harp"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -83,7 +85,7 @@
|
||||
{
|
||||
"container_name": "nextcloud-aio-database",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Database",
|
||||
"display_name": "PostgreSQL",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-postgresql",
|
||||
"user": "999",
|
||||
"init": true,
|
||||
@@ -172,7 +174,8 @@
|
||||
"SIGNALING_SECRET",
|
||||
"FULLTEXTSEARCH_PASSWORD",
|
||||
"IMAGINARY_SECRET",
|
||||
"WHITEBOARD_SECRET"
|
||||
"WHITEBOARD_SECRET",
|
||||
"HP_SHARED_KEY"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -258,7 +261,9 @@
|
||||
"THIS_IS_AIO=true",
|
||||
"IMAGINARY_SECRET=%IMAGINARY_SECRET%",
|
||||
"WHITEBOARD_SECRET=%WHITEBOARD_SECRET%",
|
||||
"WHITEBOARD_ENABLED=%WHITEBOARD_ENABLED%"
|
||||
"WHITEBOARD_ENABLED=%WHITEBOARD_ENABLED%",
|
||||
"HARP_ENABLED=%HARP_ENABLED%",
|
||||
"HP_SHARED_KEY=%HP_SHARED_KEY%"
|
||||
],
|
||||
"stop_grace_period": 600,
|
||||
"restart": "unless-stopped",
|
||||
@@ -276,7 +281,7 @@
|
||||
{
|
||||
"container_name": "nextcloud-aio-notify-push",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Notify Push",
|
||||
"display_name": "Client Push",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-notify-push",
|
||||
"user": "33",
|
||||
"init": true,
|
||||
@@ -299,22 +304,13 @@
|
||||
"volumes": [
|
||||
{
|
||||
"source": "nextcloud_aio_nextcloud",
|
||||
"destination": "/nextcloud",
|
||||
"destination": "/var/www/html",
|
||||
"writeable": false
|
||||
}
|
||||
],
|
||||
"environment": [
|
||||
"NC_DOMAIN=%NC_DOMAIN%",
|
||||
"NEXTCLOUD_HOST=nextcloud-aio-nextcloud",
|
||||
"TZ=%TIMEZONE%",
|
||||
"REDIS_HOST=nextcloud-aio-redis",
|
||||
"REDIS_PORT=6379",
|
||||
"REDIS_HOST_PASSWORD=%REDIS_PASSWORD%",
|
||||
"POSTGRES_HOST=nextcloud-aio-database",
|
||||
"POSTGRES_PORT=5432",
|
||||
"POSTGRES_PASSWORD=%DATABASE_PASSWORD%",
|
||||
"POSTGRES_DB=nextcloud_database",
|
||||
"POSTGRES_USER=nextcloud"
|
||||
"TZ=%TIMEZONE%"
|
||||
],
|
||||
"restart": "unless-stopped",
|
||||
"read_only": true,
|
||||
@@ -367,7 +363,7 @@
|
||||
"container_name": "nextcloud-aio-collabora",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"documentation": "https://github.com/nextcloud/all-in-one/discussions/1358",
|
||||
"display_name": "Collabora",
|
||||
"display_name": "Nextcloud Office",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-collabora",
|
||||
"init": true,
|
||||
"healthcheck": {
|
||||
@@ -383,8 +379,8 @@
|
||||
],
|
||||
"internal_port": "9980",
|
||||
"environment": [
|
||||
"aliasgroup1=https://%NC_DOMAIN%:443,http://nextcloud-aio-apache:23973",
|
||||
"extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:logging.disable_server_audit=true --o:logging.level=warning --o:logging.level_startup=warning --o:welcome.enable=false %COLLABORA_SECCOMP_POLICY% --o:remote_font_config.url=https://%NC_DOMAIN%/apps/richdocuments/settings/fonts.json --o:net.post_allow.host[0]=.+",
|
||||
"aliasgroup1=https://%NC_DOMAIN%:443,http://nextcloud-aio-apache.nextcloud-aio:23973",
|
||||
"extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:logging.disable_server_audit=true --o:logging.level=warning --o:logging.level_startup=warning --o:welcome.enable=false --o:fetch_update_check=0 --o:allow_update_popup=false %COLLABORA_SECCOMP_POLICY% --o:remote_font_config.url=https://%NC_DOMAIN%/apps/richdocuments/settings/fonts.json --o:net.post_allow.host[0]=.+",
|
||||
"dictionaries=%COLLABORA_DICTIONARIES%",
|
||||
"TZ=%TIMEZONE%",
|
||||
"server_name=%NC_DOMAIN%",
|
||||
@@ -393,13 +389,12 @@
|
||||
"restart": "unless-stopped",
|
||||
"nextcloud_exec_commands": [
|
||||
"echo 'Activating Collabora config...'",
|
||||
"php /var/www/html/occ richdocuments:activate-config --wopi-url='http://nextcloud-aio-apache:23973' --callback-url='http://nextcloud-aio-apache:23973'"
|
||||
"php /var/www/html/occ richdocuments:activate-config --wopi-url='http://nextcloud-aio-apache.nextcloud-aio:23973' --callback-url='http://nextcloud-aio-apache.nextcloud-aio:23973'"
|
||||
],
|
||||
"profiles": [
|
||||
"collabora"
|
||||
],
|
||||
"cap_add": [
|
||||
"MKNOD",
|
||||
"SYS_ADMIN",
|
||||
"SYS_CHROOT",
|
||||
"FOWNER",
|
||||
@@ -413,7 +408,7 @@
|
||||
"container_name": "nextcloud-aio-talk",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"documentation": "https://github.com/nextcloud/all-in-one/discussions/1358",
|
||||
"display_name": "Talk",
|
||||
"display_name": "Nextcloud Talk",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-talk",
|
||||
"user": "1000",
|
||||
"init": true,
|
||||
@@ -441,6 +436,13 @@
|
||||
"8081"
|
||||
],
|
||||
"internal_port": "%TALK_PORT%",
|
||||
"volumes": [
|
||||
{
|
||||
"source": "%NEXTCLOUD_TRUSTED_CACERTS_DIR%",
|
||||
"destination": "/usr/local/share/ca-certificates",
|
||||
"writeable": false
|
||||
}
|
||||
],
|
||||
"environment": [
|
||||
"NC_DOMAIN=%NC_DOMAIN%",
|
||||
"TALK_HOST=nextcloud-aio-talk",
|
||||
@@ -475,7 +477,7 @@
|
||||
{
|
||||
"container_name": "nextcloud-aio-talk-recording",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Talk Recording",
|
||||
"display_name": "Nextcloud Talk Recording",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-talk-recording",
|
||||
"user": "122",
|
||||
"init": true,
|
||||
@@ -527,6 +529,8 @@
|
||||
},
|
||||
{
|
||||
"container_name": "nextcloud-aio-borgbackup",
|
||||
"display_name": "Borgbackup",
|
||||
"hide_from_list": true,
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-borgbackup",
|
||||
"init": true,
|
||||
@@ -595,6 +599,8 @@
|
||||
},
|
||||
{
|
||||
"container_name": "nextcloud-aio-watchtower",
|
||||
"display_name": "Watchtower",
|
||||
"hide_from_list": true,
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-watchtower",
|
||||
"init": true,
|
||||
@@ -615,6 +621,8 @@
|
||||
},
|
||||
{
|
||||
"container_name": "nextcloud-aio-domaincheck",
|
||||
"display_name": "Domaincheck",
|
||||
"hide_from_list": true,
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-domaincheck",
|
||||
"init": true,
|
||||
@@ -824,7 +832,7 @@
|
||||
{
|
||||
"container_name": "nextcloud-aio-docker-socket-proxy",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Docker Socket Proxy",
|
||||
"display_name": "Docker Socket Proxy (deprecated)",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-docker-socket-proxy",
|
||||
"init": true,
|
||||
"internal_port": "2375",
|
||||
@@ -847,10 +855,52 @@
|
||||
"NET_RAW"
|
||||
]
|
||||
},
|
||||
{
|
||||
"container_name": "nextcloud-aio-harp",
|
||||
"image_tag": "release",
|
||||
"display_name": "HaRP",
|
||||
"image": "ghcr.io/nextcloud/nextcloud-appapi-harp",
|
||||
"init": true,
|
||||
"internal_port": "8780",
|
||||
"expose": [
|
||||
"8780"
|
||||
],
|
||||
"environment": [
|
||||
"HP_SHARED_KEY=%HP_SHARED_KEY%",
|
||||
"NC_INSTANCE_URL=https://%NC_DOMAIN%",
|
||||
"HP_LOG_LEVEL=warning",
|
||||
"HP_FRP_DISABLE_TLS=true",
|
||||
"TZ=%TIMEZONE%"
|
||||
],
|
||||
"secrets": [
|
||||
"HP_SHARED_KEY"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"source": "%WATCHTOWER_DOCKER_SOCKET_PATH%",
|
||||
"destination": "/var/run/docker.sock",
|
||||
"writeable": false
|
||||
},
|
||||
{
|
||||
"source": "nextcloud_aio_harp",
|
||||
"destination": "/certs",
|
||||
"writeable": true
|
||||
}
|
||||
],
|
||||
"restart": "unless-stopped",
|
||||
"read_only": true,
|
||||
"tmpfs": [
|
||||
"/tmp",
|
||||
"/run/harp"
|
||||
],
|
||||
"cap_drop": [
|
||||
"NET_RAW"
|
||||
]
|
||||
},
|
||||
{
|
||||
"container_name": "nextcloud-aio-whiteboard",
|
||||
"image_tag": "%AIO_CHANNEL%",
|
||||
"display_name": "Whiteboard",
|
||||
"display_name": "Nextcloud Whiteboard",
|
||||
"image": "ghcr.io/nextcloud-releases/aio-whiteboard",
|
||||
"user": "65534",
|
||||
"init": true,
|
||||
|
||||
@@ -7,15 +7,15 @@ if (isset($_GET['domain']) && is_string($_GET['domain'])) {
|
||||
}
|
||||
|
||||
if (!str_contains($domain, '.')) {
|
||||
http_response_code(400);
|
||||
http_response_code(400);
|
||||
} elseif (str_contains($domain, '/')) {
|
||||
http_response_code(400);
|
||||
http_response_code(400);
|
||||
} elseif (str_contains($domain, ':')) {
|
||||
http_response_code(400);
|
||||
http_response_code(400);
|
||||
} elseif (filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) === false) {
|
||||
http_response_code(400);
|
||||
http_response_code(400);
|
||||
} elseif (filter_var($domain, FILTER_VALIDATE_IP)) {
|
||||
http_response_code(400);
|
||||
http_response_code(400);
|
||||
} else {
|
||||
// Commented because logging is disabled as otherwise all attempts will be logged which spams the logs
|
||||
// error_log($domain . ' was accepted as valid domain.');
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="6.15.1@28dc127af1b5aecd52314f6f645bafc10d0e11f9"/>
|
||||
<files psalm-version="6.16.1@f1f5de594dc76faf8784e02d3dc4716c91c6f6ac"/>
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Don't run if the expected form isn't present.
|
||||
if (document.getElementById('options-form') === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide submit button initially
|
||||
const optionsFormSubmit = document.querySelectorAll(".options-form-submit");
|
||||
optionsFormSubmit.forEach(element => {
|
||||
@@ -116,13 +121,26 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
function handleDockerSocketProxyWarning() {
|
||||
if (document.getElementById("docker-socket-proxy").checked) {
|
||||
// TODO: remove the line below and uncomment the lines further down once https://github.com/nextcloud/app_api/pull/800 is included
|
||||
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!');
|
||||
// alert('⚠️ The docker socket proxy container is deprecated. Please use the HaRP (High-availability Reverse Proxy for Nextcloud ExApps) instead!');
|
||||
// document.getElementById("docker-socket-proxy").checked = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleHarpWarning() {
|
||||
if (document.getElementById("harp").checked) {
|
||||
alert('⚠️ Warning! Enabling this container comes with possible Security problems since you are exposing the docker socket and all its privileges to the HaRP container. Enable this only if you are sure what you are doing!');
|
||||
document.getElementById("docker-socket-proxy").checked = false
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize event listeners for specific behaviors
|
||||
document.getElementById("talk").addEventListener('change', handleTalkVisibility);
|
||||
document.getElementById("docker-socket-proxy").addEventListener('change', handleDockerSocketProxyWarning);
|
||||
if (document.getElementById("harp")) {
|
||||
document.getElementById("harp").addEventListener('change', handleHarpWarning);
|
||||
}
|
||||
|
||||
// Initialize talk-recording visibility on page load
|
||||
handleTalkVisibility(); // Ensure talk-recording is correctly initialized
|
||||
|
||||
7
php/public/disable-harp.js
Normal file
7
php/public/disable-harp.js
Normal file
@@ -0,0 +1,7 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// HaRP
|
||||
let harp = document.getElementById("harp");
|
||||
if (harp) {
|
||||
harp.disabled = true;
|
||||
}
|
||||
});
|
||||
@@ -70,15 +70,24 @@ function showPassword(id) {
|
||||
}
|
||||
|
||||
form.onsubmit = submit;
|
||||
console.info(form);
|
||||
}
|
||||
|
||||
function initForms() {
|
||||
const forms = document.querySelectorAll('form.xhr')
|
||||
console.info("Making " + forms.length + " form(s) use XHR.");
|
||||
for (const form of forms) {
|
||||
initForm(form);
|
||||
}
|
||||
const overlayLogForms = document.querySelectorAll('form[target="overlay-log"]')
|
||||
for (const form of overlayLogForms) {
|
||||
form.onsubmit = function() {
|
||||
enableSpinner();
|
||||
document.getElementById('overlay-log')?.classList.add('visible');
|
||||
// Reload the page after the response was fully loaded into the iframe.
|
||||
document.querySelector('iframe[name="overlay-log"]').addEventListener('load', () => {
|
||||
location.reload();
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
|
||||
@@ -11,6 +11,7 @@ ini_set('max_execution_time', '7200');
|
||||
ini_set('log_errors_max_len', '0');
|
||||
|
||||
use DI\Container;
|
||||
use DI\NotFoundException;
|
||||
use Slim\Csrf\Guard;
|
||||
use Slim\Factory\AppFactory;
|
||||
use Slim\Views\Twig;
|
||||
@@ -20,9 +21,10 @@ use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$container = \AIO\DependencyInjection::GetContainer();
|
||||
$dataConst = $container->get(\AIO\Data\DataConst::class);
|
||||
ini_set('session.save_path', $dataConst->GetSessionDirectory());
|
||||
// Configure and start the session before building the DI container so that
|
||||
// TranslationManager (instantiated inside the container) can read
|
||||
// $_SESSION['aio_user_language'] from the very first request.
|
||||
ini_set('session.save_path', \AIO\Data\DataConst::GetSessionDirectory());
|
||||
|
||||
// Auto logout on browser close
|
||||
ini_set('session.cookie_lifetime', '0');
|
||||
@@ -30,6 +32,10 @@ ini_set('session.cookie_lifetime', '0');
|
||||
# Keep session for 24h max
|
||||
ini_set('session.gc_maxlifetime', '86400');
|
||||
|
||||
session_start();
|
||||
|
||||
$container = \AIO\DependencyInjection::GetContainer();
|
||||
|
||||
// Create app
|
||||
AppFactory::setContainer($container);
|
||||
$app = AppFactory::create();
|
||||
@@ -43,18 +49,19 @@ $container->set(Guard::class, function () use ($responseFactory) {
|
||||
});
|
||||
|
||||
// Register Middleware To Be Executed On All Routes
|
||||
session_start();
|
||||
$app->add(Guard::class);
|
||||
|
||||
// Create Twig
|
||||
$twig = Twig::create(__DIR__ . '/../templates/', ['cache' => false]);
|
||||
$app->add(TwigMiddleware::create($app, $twig));
|
||||
$twig->addExtension(new \AIO\Twig\CsrfExtension($container->get(Guard::class)));
|
||||
$twig->addExtension(new \AIO\Twig\TranslationExtension($container->get(\AIO\Translation\TranslationManager::class)));
|
||||
|
||||
// Auth Middleware
|
||||
$app->add(new \AIO\Middleware\AuthMiddleware($container->get(\AIO\Auth\AuthManager::class)));
|
||||
|
||||
// API
|
||||
$app->post('/api/language', AIO\Controller\LanguageController::class . ':SetLanguage');
|
||||
$app->post('/api/docker/watchtower', AIO\Controller\DockerController::class . ':StartWatchtowerContainer');
|
||||
$app->get('/api/docker/getwatchtower', AIO\Controller\DockerController::class . ':StartWatchtowerContainer');
|
||||
$app->post('/api/docker/start', AIO\Controller\DockerController::class . ':StartContainer');
|
||||
@@ -136,6 +143,7 @@ $app->get('/containers', function (Request $request, Response $response, array $
|
||||
'is_nvidia_gpu_enabled' => $configurationManager->enableNvidiaGpu,
|
||||
'is_talk_recording_enabled' => $configurationManager->isTalkRecordingEnabled,
|
||||
'is_docker_socket_proxy_enabled' => $configurationManager->isDockerSocketProxyEnabled,
|
||||
'is_harp_enabled' => $configurationManager->isHarpEnabled,
|
||||
'is_whiteboard_enabled' => $configurationManager->isWhiteboardEnabled,
|
||||
'community_containers' => $configurationManager->listAvailableCommunityContainers(),
|
||||
'community_containers_enabled' => $configurationManager->aioCommunityContainers,
|
||||
@@ -170,6 +178,15 @@ $app->get('/setup', function (Request $request, Response $response, array $args)
|
||||
]
|
||||
);
|
||||
});
|
||||
$app->get('/log', function (Request $request, Response $response, array $args) use ($container) {
|
||||
$params = $request->getQueryParams();
|
||||
$id = $params['id'] ?? '';
|
||||
if (!str_starts_with($id, 'nextcloud-aio-')) {
|
||||
throw new DI\NotFoundException();
|
||||
}
|
||||
$view = Twig::fromRequest($request);
|
||||
return $view->render($response, 'log.twig', ['id' => $id]);
|
||||
});
|
||||
|
||||
// Auth Redirector
|
||||
$app->get('/', function (\Psr\Http\Message\RequestInterface $request, Response $response, array $args) use ($container) {
|
||||
@@ -197,4 +214,13 @@ $app->get('/', function (\Psr\Http\Message\RequestInterface $request, Response $
|
||||
|
||||
$errorMiddleware = $app->addErrorMiddleware(false, true, true);
|
||||
|
||||
// Set a custom Not Found handler, which doesn't pollute the app output with 404 errors.
|
||||
$errorMiddleware->setErrorHandler(
|
||||
\Slim\Exception\HttpNotFoundException::class,
|
||||
function (Request $request, Throwable $exception, bool $displayErrorDetails) use ($app) {
|
||||
$response = $app->getResponseFactory()->createResponse();
|
||||
$response->getBody()->write('Not Found');
|
||||
return $response->withStatus(404);
|
||||
});
|
||||
|
||||
$app->run();
|
||||
|
||||
104
php/public/language-switcher.js
Normal file
104
php/public/language-switcher.js
Normal file
@@ -0,0 +1,104 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var STORAGE_KEY = 'aio_language';
|
||||
var API_ENDPOINT = 'api/language';
|
||||
|
||||
/**
|
||||
* Read the CSRF token fields that CsrfExtension injects into every page as
|
||||
* hidden inputs inside the logout form. We reuse them for the JSON POST so
|
||||
* that Slim's CSRF guard accepts our request.
|
||||
*/
|
||||
function getCsrfFields() {
|
||||
var nameInput = document.querySelector('input[name$="__token_name"]') // fallback selector
|
||||
|| document.querySelector('input[name^="csrf_name"]');
|
||||
var valueInput = document.querySelector('input[name$="__token_value"]')
|
||||
|| document.querySelector('input[name^="csrf_value"]');
|
||||
|
||||
// The Slim CSRF guard stores two hidden fields; their *name* attributes
|
||||
// are themselves dynamic (csrf_name / csrf_value carry the key names,
|
||||
// and csrf.name / csrf.value carry the actual token strings).
|
||||
// The simplest reliable approach: grab all hidden inputs from the logout
|
||||
// form and forward them all.
|
||||
var logoutForm = document.querySelector('form[action*="api/auth/logout"]');
|
||||
if (!logoutForm) {
|
||||
return {};
|
||||
}
|
||||
|
||||
var fields = {};
|
||||
var hiddenInputs = logoutForm.querySelectorAll('input[type="hidden"]');
|
||||
hiddenInputs.forEach(function (input) {
|
||||
fields[input.name] = input.value;
|
||||
});
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* POST the chosen language to the server, then reload on success.
|
||||
* Returns a Promise that resolves to true on success, false on failure.
|
||||
*/
|
||||
function postLanguage(lang) {
|
||||
var csrfFields = getCsrfFields();
|
||||
var body = Object.assign({ language: lang }, csrfFields);
|
||||
|
||||
return fetch(API_ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: new URLSearchParams(body).toString(),
|
||||
}).then(function (response) {
|
||||
return response.ok || response.status === 204;
|
||||
}).catch(function () {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist the language choice to localStorage and reload the page so the
|
||||
* server can render in the new language.
|
||||
*/
|
||||
function applyLanguage(lang, reload) {
|
||||
localStorage.setItem(STORAGE_KEY, lang);
|
||||
postLanguage(lang).then(function (ok) {
|
||||
if (ok && reload) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire up the <select> drop-down once the DOM is ready.
|
||||
*/
|
||||
function initSwitcher() {
|
||||
var select = document.getElementById('language-switcher');
|
||||
if (!select) {
|
||||
return;
|
||||
}
|
||||
|
||||
select.addEventListener('change', function () {
|
||||
var chosen = select.value;
|
||||
if (chosen) {
|
||||
applyLanguage(chosen, true);
|
||||
}
|
||||
});
|
||||
|
||||
// On page load: if localStorage holds a preference that differs from
|
||||
// the current server-side language, silently sync once and reload.
|
||||
var saved = localStorage.getItem(STORAGE_KEY);
|
||||
var current = select.dataset.current || select.value;
|
||||
|
||||
if (saved && saved !== current) {
|
||||
// Update the select to match the stored preference before posting,
|
||||
// so the UI doesn't flicker if the reload is slow.
|
||||
select.value = saved;
|
||||
applyLanguage(saved, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initSwitcher);
|
||||
} else {
|
||||
initSwitcher();
|
||||
}
|
||||
}());
|
||||
142
php/public/log-view.js
Normal file
142
php/public/log-view.js
Normal file
@@ -0,0 +1,142 @@
|
||||
class LogViewer {
|
||||
// Configure the interval in seconds for autoloading log data.
|
||||
autoloadIntervalSec = 5;
|
||||
// Set to true to see some debug log statements in the browser console.
|
||||
debugLog = false;
|
||||
|
||||
// Don't touch these, please.
|
||||
containerId;
|
||||
apiBaseUrl = 'api/docker/logs';
|
||||
autoloadIntervalId = null;
|
||||
logElem;
|
||||
lastLogTimestamp = '';
|
||||
autoloadingDisabledFromButton = false;
|
||||
loaderElem;
|
||||
dataLoadingLock;
|
||||
|
||||
constructor() {
|
||||
const id = document.body.dataset.containerId;
|
||||
if (typeof(id) !== 'string' || !id.startsWith('nextcloud-aio-')) {
|
||||
throw new Exception('Invalid container ID');
|
||||
}
|
||||
this.containerId = id;
|
||||
this.logElem = document.querySelector('pre');
|
||||
this.loaderElem = document.querySelector('.loader');
|
||||
this.initAutoloadingControls();
|
||||
// Enable automatic log data loading.
|
||||
this.startAutoloading();
|
||||
}
|
||||
|
||||
startAutoloading() {
|
||||
// Load log data immediately.
|
||||
this.loadAndAppendLogData();
|
||||
// Load new log data repeatedly.
|
||||
this.debug("Starting autoloading");
|
||||
this.autoloadIntervalId = setInterval(() => {
|
||||
if (this.isAutoloadingEnabled()) {
|
||||
this.loadAndAppendLogData();
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
stopAutoloading() {
|
||||
this.debug("Stopping autoloading");
|
||||
clearInterval(this.autoloadIntervalId);
|
||||
this.autoloadIntervalId = null;
|
||||
}
|
||||
|
||||
isAutoloadingEnabled() {
|
||||
return !!this.autoloadIntervalId;
|
||||
}
|
||||
|
||||
getUrl() {
|
||||
return `${this.apiBaseUrl}?id=${this.containerId}&since=${this.lastLogTimestamp}`;
|
||||
}
|
||||
|
||||
debug(...args) {
|
||||
if (this.debugLog) {
|
||||
console.debug('LogViewer:', ...args);
|
||||
}
|
||||
}
|
||||
|
||||
// Load log data and append it to the DOM.
|
||||
loadAndAppendLogData() {
|
||||
if (this.dataLoadingLock) {
|
||||
this.debug("Another log data loading request is still running, cancelling this request");
|
||||
return;
|
||||
}
|
||||
this.debug("Loading new log data");
|
||||
this.dataLoadingLock = true;
|
||||
this.loaderElem.classList.remove('hidden');
|
||||
fetch(this.getUrl())
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Error while fetching log data!");
|
||||
}
|
||||
return response;
|
||||
})
|
||||
.then((response) => response.text())
|
||||
.then((text) => {
|
||||
text = text.trim();
|
||||
if (text.length === 0) {
|
||||
this.debug("Received no new log data from server");
|
||||
return;
|
||||
}
|
||||
this.debug("Received", Math.round(text.length / 1024), "KB of new log data from server");
|
||||
this.logElem.append(text + "\n");
|
||||
this.scrollToBottom();
|
||||
this.lastLogTimestamp = text.split("\n").at(-1)?.split(' ')[0] ?? '';
|
||||
})
|
||||
.finally(() => {
|
||||
this.dataLoadingLock = false;
|
||||
this.loaderElem.classList.add('hidden');
|
||||
this.debug("Finished log data loading");
|
||||
})
|
||||
.catch((err) => console.error(err));
|
||||
}
|
||||
|
||||
scrollToBottom() {
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
}
|
||||
|
||||
initAutoloadingControls() {
|
||||
// Provide a button that allows to manually disable the autoloading.
|
||||
const button = document.getElementById('autoloading-control');
|
||||
const statusElem = document.getElementById('autoloading-status');
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
button.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
if (this.isAutoloadingEnabled()) {
|
||||
this.stopAutoloading();
|
||||
statusElem.textContent = 'disabled';
|
||||
button.textContent = 'Enable';
|
||||
this.autoloadingDisabledFromButton = true;
|
||||
} else {
|
||||
this.startAutoloading();
|
||||
statusElem.textContent = 'enabled';
|
||||
button.textContent = 'Disable';
|
||||
this.autoloadingDisabledFromButton = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Load new data immediately if the window gets visible to the user again (unless autoloading has been
|
||||
// disabled).
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
this.debug("Window became visible");
|
||||
if (!this.autoloadingDisabledFromButton) {
|
||||
this.startAutoloading();
|
||||
}
|
||||
} else {
|
||||
this.debug("Window became hidden");
|
||||
this.stopAutoloading();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
new LogViewer();
|
||||
});
|
||||
@@ -375,9 +375,38 @@ header {
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
header > form {
|
||||
.header-controls {
|
||||
margin-left: auto;
|
||||
margin-right: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.header-controls > form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.language-switcher {
|
||||
height: 34px;
|
||||
padding: 0 8px;
|
||||
font-size: var(--default-font-size);
|
||||
font-family: inherit;
|
||||
color: var(--color-main-text);
|
||||
background-color: var(--color-main-background);
|
||||
border: var(--border) solid var(--color-main-border);
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.language-switcher:hover {
|
||||
border-width: var(--border-hover);
|
||||
border-color: var(--color-main-border-hover);
|
||||
}
|
||||
|
||||
.language-switcher:focus {
|
||||
outline: 2px solid var(--color-main-border);
|
||||
}
|
||||
|
||||
/* Standard styling for enabled checkboxes */
|
||||
@@ -468,7 +497,29 @@ input[type="checkbox"]:disabled:not(:checked) + label {
|
||||
}
|
||||
|
||||
#overlay.loading {
|
||||
display: block;
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
row-gap: 2rem;
|
||||
}
|
||||
|
||||
#overlay #overlay-log.visible {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 1s ease-in;
|
||||
}
|
||||
|
||||
#overlay #overlay-log {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
align-self: start;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
border-radius: var(--border-radius-large);
|
||||
border: solid thin rgb(192, 192, 192);
|
||||
}
|
||||
|
||||
.overlay-iframe {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.loader {
|
||||
@@ -479,9 +530,7 @@ input[type="checkbox"]:disabled:not(:checked) + label {
|
||||
height: 120px;
|
||||
-webkit-animation: spin 2s linear infinite; /* Safari */
|
||||
animation: spin 2s linear infinite;
|
||||
position: absolute;
|
||||
top: calc(50% - 60px);
|
||||
left: calc(50% - 60px);
|
||||
align-self: end;
|
||||
}
|
||||
|
||||
/* Safari */
|
||||
@@ -705,4 +754,4 @@ input[type="checkbox"]:disabled:not(:checked) + label {
|
||||
.office-suite-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,28 +2,26 @@
|
||||
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);
|
||||
setThemeToDOM(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
|
||||
setThemeIcon(newTheme);
|
||||
}
|
||||
|
||||
// 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 setThemeToDOM(value) {
|
||||
// Set the theme to the root document and all possible iframe documents (so they can adapt their styling, too).
|
||||
const documents = [document, Array.from(document.querySelectorAll('iframe')).map((iframe) => iframe.contentDocument)].flat()
|
||||
documents.forEach((doc) => doc.documentElement.setAttribute('data-theme', value));
|
||||
}
|
||||
|
||||
function getSavedTheme() {
|
||||
return localStorage.getItem('theme') ?? '';
|
||||
}
|
||||
|
||||
// Function to apply theme-icon update
|
||||
function setThemeIcon() {
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme === 'dark') {
|
||||
function setThemeIcon(theme) {
|
||||
if (theme === 'dark') {
|
||||
document.getElementById('theme-icon').textContent = '☀️'; // Sun icon for dark mode
|
||||
} else {
|
||||
document.getElementById('theme-icon').textContent = '🌙'; // Moon icon for light mode
|
||||
@@ -31,7 +29,7 @@ function setThemeIcon() {
|
||||
}
|
||||
|
||||
// Immediately apply the saved theme to avoid flickering
|
||||
applySavedThemeImmediately();
|
||||
setThemeToDOM(getSavedTheme());
|
||||
|
||||
// Apply theme when the page loads
|
||||
document.addEventListener('DOMContentLoaded', setThemeIcon);
|
||||
document.addEventListener('DOMContentLoaded', () => setThemeIcon(getSavedTheme()));
|
||||
|
||||
@@ -38,6 +38,7 @@ readonly class Container {
|
||||
public string $imageTag,
|
||||
public AioVariables $aioVariables,
|
||||
public string $documentation,
|
||||
public bool $hideFromList,
|
||||
private DockerActionManager $dockerActionManager
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -91,6 +91,10 @@ readonly class ContainerDefinitionFetcher {
|
||||
if (!$this->configurationManager->isDockerSocketProxyEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-harp') {
|
||||
if (!$this->configurationManager->isHarpEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['container_name'] === 'nextcloud-aio-whiteboard') {
|
||||
if (!$this->configurationManager->isWhiteboardEnabled) {
|
||||
continue;
|
||||
@@ -200,6 +204,10 @@ readonly class ContainerDefinitionFetcher {
|
||||
if (!$this->configurationManager->isDockerSocketProxyEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-harp') {
|
||||
if (!$this->configurationManager->isHarpEnabled) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-whiteboard') {
|
||||
if (!$this->configurationManager->isWhiteboardEnabled) {
|
||||
continue;
|
||||
@@ -316,6 +324,8 @@ readonly class ContainerDefinitionFetcher {
|
||||
$documentation = $entry['documentation'];
|
||||
}
|
||||
|
||||
$hideFromList = $entry['hide_from_list'] ?? false;
|
||||
|
||||
$containers[] = new Container(
|
||||
$entry['container_name'],
|
||||
$displayName,
|
||||
@@ -341,6 +351,7 @@ readonly class ContainerDefinitionFetcher {
|
||||
$imageTag,
|
||||
$aioVariables,
|
||||
$documentation,
|
||||
$hideFromList,
|
||||
$this->container->get(DockerActionManager::class)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ readonly class ConfigurationController {
|
||||
$this->configurationManager->isImaginaryEnabled = isset($request->getParsedBody()['imaginary']);
|
||||
$this->configurationManager->isFulltextsearchEnabled = isset($request->getParsedBody()['fulltextsearch']);
|
||||
$this->configurationManager->isDockerSocketProxyEnabled = isset($request->getParsedBody()['docker-socket-proxy']);
|
||||
$this->configurationManager->isHarpEnabled = isset($request->getParsedBody()['harp']);
|
||||
$this->configurationManager->isWhiteboardEnabled = isset($request->getParsedBody()['whiteboard']);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace AIO\Controller;
|
||||
|
||||
use AIO\Container\Container;
|
||||
use AIO\Container\ContainerState;
|
||||
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;
|
||||
use Slim\Psr7\NonBufferedBody;
|
||||
|
||||
readonly class DockerController {
|
||||
private const string TOP_CONTAINER = 'nextcloud-aio-apache';
|
||||
@@ -20,12 +22,12 @@ readonly class DockerController {
|
||||
) {
|
||||
}
|
||||
|
||||
private function PerformRecursiveContainerStart(string $id, bool $pullImage = true) : void {
|
||||
private function PerformRecursiveContainerStart(string $id, bool $pullImage = true, ?\Closure $addToStreamingResponseBody = null) : void {
|
||||
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
|
||||
// Start all dependencies first and then itself
|
||||
foreach($container->dependsOn as $dependency) {
|
||||
$this->PerformRecursiveContainerStart($dependency, $pullImage);
|
||||
$this->PerformRecursiveContainerStart($dependency, $pullImage, $addToStreamingResponseBody);
|
||||
}
|
||||
|
||||
// Don't start if container is already running
|
||||
@@ -37,9 +39,9 @@ readonly class DockerController {
|
||||
|
||||
$this->dockerActionManager->DeleteContainer($container);
|
||||
$this->dockerActionManager->CreateVolumes($container);
|
||||
$this->dockerActionManager->PullImage($container, $pullImage);
|
||||
$this->dockerActionManager->PullImage($container, $pullImage, $addToStreamingResponseBody);
|
||||
$this->dockerActionManager->CreateContainer($container);
|
||||
$this->dockerActionManager->StartContainer($container);
|
||||
$this->dockerActionManager->StartContainer($container, $addToStreamingResponseBody);
|
||||
$this->dockerActionManager->ConnectContainerToNetwork($container);
|
||||
}
|
||||
|
||||
@@ -69,7 +71,8 @@ readonly class DockerController {
|
||||
$id = $requestParams['id'];
|
||||
}
|
||||
if (str_starts_with($id, 'nextcloud-aio-')) {
|
||||
$logs = $this->dockerActionManager->GetLogs($id);
|
||||
$since = $this->getTimestampForDockerLogsApiSince($requestParams['since'] ?? '');
|
||||
$logs = $this->dockerActionManager->GetLogs($id, $since);
|
||||
} else {
|
||||
$logs = 'Container not found.';
|
||||
}
|
||||
@@ -84,43 +87,64 @@ readonly class DockerController {
|
||||
}
|
||||
|
||||
public function StartBackupContainerBackup(Request $request, Response $response, array $args) : Response {
|
||||
// Get streaming response start and closure
|
||||
$nonbufResp = $this->startStreamingResponse($response);
|
||||
$addToStreamingResponseBody = $this->getAddToStreamingResponseBody($nonbufResp);
|
||||
|
||||
$forceStopNextcloud = true;
|
||||
$this->startBackup($forceStopNextcloud);
|
||||
return $response->withStatus(201)->withHeader('Location', '.');
|
||||
$this->startBackup($forceStopNextcloud, $addToStreamingResponseBody);
|
||||
|
||||
// End streaming response
|
||||
$this->finalizeStreamingResponse($nonbufResp);
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
public function startBackup(bool $forceStopNextcloud = false) : void {
|
||||
public function startBackup(bool $forceStopNextcloud = false, ?\Closure $addToStreamingResponseBody = null) : void {
|
||||
$this->configurationManager->backupMode = 'backup';
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
$this->PerformRecursiveContainerStop($id, $forceStopNextcloud);
|
||||
$this->PerformRecursiveContainerStop($id, $forceStopNextcloud, $addToStreamingResponseBody);
|
||||
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
$this->PerformRecursiveContainerStart($id, true, $addToStreamingResponseBody);
|
||||
}
|
||||
|
||||
public function StartBackupContainerCheck(Request $request, Response $response, array $args) : Response {
|
||||
$this->checkBackup();
|
||||
return $response->withStatus(201)->withHeader('Location', '.');
|
||||
// Get streaming response start and closure
|
||||
$nonbufResp = $this->startStreamingResponse($response);
|
||||
$addToStreamingResponseBody = $this->getAddToStreamingResponseBody($nonbufResp);
|
||||
|
||||
$this->checkBackup($addToStreamingResponseBody);
|
||||
|
||||
// End streaming response
|
||||
$this->finalizeStreamingResponse($nonbufResp);
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
public function StartBackupContainerList(Request $request, Response $response, array $args) : Response {
|
||||
$this->listBackup();
|
||||
return $response->withStatus(201)->withHeader('Location', '.');
|
||||
// Get streaming response start and closure
|
||||
$nonbufResp = $this->startStreamingResponse($response);
|
||||
$addToStreamingResponseBody = $this->getAddToStreamingResponseBody($nonbufResp);
|
||||
|
||||
$this->listBackup($addToStreamingResponseBody);
|
||||
|
||||
// End streaming response
|
||||
$this->finalizeStreamingResponse($nonbufResp);
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
public function checkBackup() : void {
|
||||
public function checkBackup(?\Closure $addToStreamingResponseBody = null) : void {
|
||||
$this->configurationManager->backupMode = 'check';
|
||||
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
$this->PerformRecursiveContainerStart($id, true, $addToStreamingResponseBody);
|
||||
}
|
||||
|
||||
private function listBackup() : void {
|
||||
private function listBackup(?\Closure $addToStreamingResponseBody = null) : void {
|
||||
$this->configurationManager->backupMode = 'list';
|
||||
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
$this->PerformRecursiveContainerStart($id, true, $addToStreamingResponseBody);
|
||||
}
|
||||
|
||||
public function StartBackupContainerRestore(Request $request, Response $response, array $args) : Response {
|
||||
@@ -130,26 +154,38 @@ readonly class DockerController {
|
||||
$this->configurationManager->restoreExcludePreviews = isset($request->getParsedBody()['restore-exclude-previews']);
|
||||
$this->configurationManager->commitTransaction();
|
||||
|
||||
// Get streaming response start and closure
|
||||
$nonbufResp = $this->startStreamingResponse($response);
|
||||
$addToStreamingResponseBody = $this->getAddToStreamingResponseBody($nonbufResp);
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
$forceStopNextcloud = true;
|
||||
$this->PerformRecursiveContainerStop($id, $forceStopNextcloud);
|
||||
$this->PerformRecursiveContainerStop($id, $forceStopNextcloud, $addToStreamingResponseBody);
|
||||
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
$this->PerformRecursiveContainerStart($id, true, $addToStreamingResponseBody);
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '.');
|
||||
// End streaming response
|
||||
$this->finalizeStreamingResponse($nonbufResp);
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
public function StartBackupContainerCheckRepair(Request $request, Response $response, array $args) : Response {
|
||||
$this->configurationManager->backupMode = 'check-repair';
|
||||
|
||||
// Get streaming response start and closure
|
||||
$nonbufResp = $this->startStreamingResponse($response);
|
||||
$addToStreamingResponseBody = $this->getAddToStreamingResponseBody($nonbufResp);
|
||||
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
$this->PerformRecursiveContainerStart($id, true, $addToStreamingResponseBody);
|
||||
|
||||
// Restore to backup check which is needed to make the UI logic work correctly
|
||||
$this->configurationManager->backupMode = 'check';
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '.');
|
||||
// End streaming response
|
||||
$this->finalizeStreamingResponse($nonbufResp);
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
public function StartBackupContainerTest(Request $request, Response $response, array $args) : Response {
|
||||
@@ -158,13 +194,19 @@ readonly class DockerController {
|
||||
$this->configurationManager->instanceRestoreAttempt = false;
|
||||
$this->configurationManager->commitTransaction();
|
||||
|
||||
// Get streaming response start and closure
|
||||
$nonbufResp = $this->startStreamingResponse($response);
|
||||
$addToStreamingResponseBody = $this->getAddToStreamingResponseBody($nonbufResp);
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
$this->PerformRecursiveContainerStop($id);
|
||||
$this->PerformRecursiveContainerStop($id, true, $addToStreamingResponseBody);
|
||||
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
$this->PerformRecursiveContainerStart($id, true, $addToStreamingResponseBody);
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '.');
|
||||
// End streaming response
|
||||
$this->finalizeStreamingResponse($nonbufResp);
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
public function StartContainer(Request $request, Response $response, array $args) : Response
|
||||
@@ -198,17 +240,24 @@ readonly class DockerController {
|
||||
if ($pullImage === false) {
|
||||
error_log('WARNING: Not pulling container images. Instead, using local ones.');
|
||||
}
|
||||
|
||||
// Get streaming response start and closure
|
||||
$nonbufResp = $this->startStreamingResponse($response);
|
||||
$addToStreamingResponseBody = $this->getAddToStreamingResponseBody($nonbufResp);
|
||||
|
||||
// Start container
|
||||
$this->startTopContainer($pullImage);
|
||||
$this->startTopContainer($pullImage, $addToStreamingResponseBody);
|
||||
|
||||
// Clear apcu cache in order to check if container updates are available
|
||||
// Temporarily disabled as it leads much faster to docker rate limits
|
||||
// apcu_clear_cache();
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '.');
|
||||
// End streaming response
|
||||
$this->finalizeStreamingResponse($nonbufResp);
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
public function startTopContainer(bool $pullImage) : void {
|
||||
public function startTopContainer(bool $pullImage, ?\Closure $addToStreamingResponseBody = null) : void {
|
||||
$this->configurationManager->aioToken = bin2hex(random_bytes(24));
|
||||
|
||||
// Stop domaincheck since apache would not be able to start otherwise
|
||||
@@ -216,21 +265,28 @@ readonly class DockerController {
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
|
||||
$this->PerformRecursiveContainerStart($id, $pullImage);
|
||||
$this->PerformRecursiveContainerStart($id, $pullImage, $addToStreamingResponseBody);
|
||||
}
|
||||
|
||||
public function StartWatchtowerContainer(Request $request, Response $response, array $args) : Response {
|
||||
$this->startWatchtower();
|
||||
return $response->withStatus(201)->withHeader('Location', '.');
|
||||
// Get streaming response start and closure
|
||||
$nonbufResp = $this->startStreamingResponse($response);
|
||||
$addToStreamingResponseBody = $this->getAddToStreamingResponseBody($nonbufResp);
|
||||
|
||||
$this->startWatchtower($addToStreamingResponseBody);
|
||||
|
||||
// End streaming response
|
||||
$this->finalizeStreamingResponse($nonbufResp);
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
public function startWatchtower() : void {
|
||||
public function startWatchtower(?\Closure $addToStreamingResponseBody = null) : void {
|
||||
$id = 'nextcloud-aio-watchtower';
|
||||
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
$this->PerformRecursiveContainerStart($id, true, $addToStreamingResponseBody);
|
||||
}
|
||||
|
||||
private function PerformRecursiveContainerStop(string $id, bool $forceStopNextcloud = false) : void
|
||||
private function PerformRecursiveContainerStop(string $id, bool $forceStopNextcloud = false, ?\Closure $addToStreamingResponseBody = null) : void
|
||||
{
|
||||
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
|
||||
@@ -238,7 +294,11 @@ readonly class DockerController {
|
||||
// Stop Collabora first to make sure it force-saves
|
||||
// See https://github.com/nextcloud/richdocuments/issues/3799
|
||||
if ($id === self::TOP_CONTAINER && $this->configurationManager->isCollaboraEnabled) {
|
||||
$this->PerformRecursiveContainerStop('nextcloud-aio-collabora');
|
||||
$this->PerformRecursiveContainerStop('nextcloud-aio-collabora', false, $addToStreamingResponseBody);
|
||||
}
|
||||
|
||||
if ($addToStreamingResponseBody !== null) {
|
||||
$addToStreamingResponseBody($container, "Stopping container");
|
||||
}
|
||||
|
||||
// Stop itself first and then all the dependencies
|
||||
@@ -249,17 +309,23 @@ readonly class DockerController {
|
||||
$this->dockerActionManager->StopContainer($container, $forceStopNextcloud);
|
||||
}
|
||||
foreach($container->dependsOn as $dependency) {
|
||||
$this->PerformRecursiveContainerStop($dependency, $forceStopNextcloud);
|
||||
$this->PerformRecursiveContainerStop($dependency, $forceStopNextcloud, $addToStreamingResponseBody);
|
||||
}
|
||||
}
|
||||
|
||||
public function StopContainer(Request $request, Response $response, array $args) : Response
|
||||
{
|
||||
// Get streaming response start and closure
|
||||
$nonbufResp = $this->startStreamingResponse($response);
|
||||
$addToStreamingResponseBody = $this->getAddToStreamingResponseBody($nonbufResp);
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
$forceStopNextcloud = true;
|
||||
$this->PerformRecursiveContainerStop($id, $forceStopNextcloud);
|
||||
$this->PerformRecursiveContainerStop($id, $forceStopNextcloud, $addToStreamingResponseBody);
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '.');
|
||||
// End streaming response
|
||||
$this->finalizeStreamingResponse($nonbufResp);
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
public function stopTopContainer() : void {
|
||||
@@ -308,4 +374,96 @@ readonly class DockerController {
|
||||
$id = 'nextcloud-aio-domaincheck';
|
||||
$this->PerformRecursiveContainerStop($id);
|
||||
}
|
||||
|
||||
private function getStreamingResponseHtmlStart() : string {
|
||||
return <<<END
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="overlay-iframe">
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../style.css?v8" media="all" />
|
||||
<script>
|
||||
const observer = new MutationObserver((records) => {
|
||||
const node = records[0]?.addedNodes[0];
|
||||
// Text nodes also appear here but can't be scrolled to, so we have to check for the
|
||||
// function being present.
|
||||
if (node && typeof(node.scrollIntoView) === 'function') {
|
||||
node.scrollIntoView();
|
||||
}
|
||||
});
|
||||
observer.observe(document, {childList: true, subtree: true});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
END;
|
||||
}
|
||||
|
||||
private function startStreamingResponse(Response $response) : Response {
|
||||
$nonbufResp = $response
|
||||
->withBody(new NonBufferedBody())
|
||||
->withHeader('Content-Type', 'text/html; charset=utf-8')
|
||||
->withHeader('X-Accel-Buffering', 'no')
|
||||
->withHeader('Content-Length', '-1')
|
||||
->withHeader('Cache-Control', 'no-cache');
|
||||
|
||||
// Text written into this body is immediately sent to the client, without waiting for later content.
|
||||
$streamingResponseBody = $nonbufResp->getBody();
|
||||
|
||||
$streamingResponseBody->write($this->getStreamingResponseHtmlStart());
|
||||
|
||||
return $nonbufResp;
|
||||
}
|
||||
|
||||
private function getAddToStreamingResponseBody(Response $nonbufResp) : ?\Closure {
|
||||
// Create a closure to pass around to the code, which should to the logging (because it e.g. decides
|
||||
// if it'll actually pull an image), but which should not need to know anything about the
|
||||
// wanted markup or formatting.
|
||||
$addToStreamingResponseBody = function (Container $container, string $message) use ($nonbufResp) : void {
|
||||
$nonbufResp->getBody()->write("<div>{$container->displayName}: {$message}</div>");
|
||||
};
|
||||
|
||||
return $addToStreamingResponseBody;
|
||||
}
|
||||
|
||||
private function finalizeStreamingResponse(Response $nonbufResp) : void {
|
||||
$nonbufResp->getBody()->write($this->getStreamingResponseHtmlEnd());
|
||||
}
|
||||
|
||||
private function getStreamingResponseHtmlEnd() : string {
|
||||
return "\n </body>\n</html>";
|
||||
}
|
||||
|
||||
private function getTimestampForDockerLogsApiSince(string $input) : string
|
||||
{
|
||||
if ($input === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// We expect an RFC3339Nano string with Timezone UTC here, as docker will put out.
|
||||
// Unfortunately PHP doesn't support this format with nanoseconds, so we have to help
|
||||
// ourselves a little bit.
|
||||
// First we split off the nanoseconds.
|
||||
preg_match('/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})\.(\d{9}).*/', $input, $match);
|
||||
if (count($match) !== 3) {
|
||||
// The input doesn't match our expectations, it might be manipulated, we ignore it.
|
||||
return '';
|
||||
}
|
||||
|
||||
$datetime = \DateTimeImmutable::createFromFormat("Y-m-d\\TH:i:s", $match[1]);
|
||||
$nanoseconds = $match[2];
|
||||
|
||||
if ($datetime === false) {
|
||||
// Input was not parseable, it might be manipulated, we ignore it.
|
||||
return '';
|
||||
}
|
||||
|
||||
// Format the datetime as unix timestamp.
|
||||
$timestamp = $datetime->format('U');
|
||||
|
||||
// Increase the nanoseconds by 1, so we don't get the line with exactly the original datetime again.
|
||||
$nanoseconds = strval(intval($nanoseconds) + 1);
|
||||
|
||||
// Now append the nanoseconds to the timestamp-string.
|
||||
return "{$timestamp}.{$nanoseconds}";
|
||||
}
|
||||
}
|
||||
|
||||
38
php/src/Controller/LanguageController.php
Normal file
38
php/src/Controller/LanguageController.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace AIO\Controller;
|
||||
|
||||
use AIO\Translation\TranslationManager;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
readonly class LanguageController
|
||||
{
|
||||
public function __construct(
|
||||
private TranslationManager $translationManager,
|
||||
) {
|
||||
}
|
||||
|
||||
public function SetLanguage(Request $request, Response $response, array $args): Response
|
||||
{
|
||||
/** @var array<string, mixed>|null $body */
|
||||
$body = $request->getParsedBody();
|
||||
|
||||
$language = '';
|
||||
if (is_array($body) && isset($body['language']) && is_string($body['language'])) {
|
||||
$language = $body['language'];
|
||||
}
|
||||
|
||||
$supported = $this->translationManager->getSupportedLanguages();
|
||||
|
||||
if ($language === '' || !in_array($language, $supported, true)) {
|
||||
$response->getBody()->write('Unsupported language.');
|
||||
return $response->withStatus(422);
|
||||
}
|
||||
|
||||
$_SESSION['aio_user_language'] = $language;
|
||||
|
||||
return $response->withStatus(204);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,11 @@ class ConfigurationManager
|
||||
set { $this->set('isDockerSocketProxyEnabled', $value); }
|
||||
}
|
||||
|
||||
public bool $isHarpEnabled {
|
||||
get => $this->get('isHarpEnabled', false);
|
||||
set { $this->set('isHarpEnabled', $value); }
|
||||
}
|
||||
|
||||
public bool $isWhiteboardEnabled {
|
||||
// Type-cast because old configs could have 1/0 for this key.
|
||||
get => (bool) $this->get('isWhiteboardEnabled', true);
|
||||
@@ -1035,6 +1040,7 @@ class ConfigurationManager
|
||||
'IMAGINARY_ENABLED' => $this->isImaginaryEnabled ? 'yes' : '',
|
||||
'FULLTEXTSEARCH_ENABLED' => $this->isFulltextsearchEnabled ? 'yes' : '',
|
||||
'DOCKER_SOCKET_PROXY_ENABLED' => $this->isDockerSocketProxyEnabled ? 'yes' : '',
|
||||
'HARP_ENABLED' => $this->isHarpEnabled ? 'yes' : '',
|
||||
'NEXTCLOUD_UPLOAD_LIMIT' => $this->nextcloudUploadLimit,
|
||||
'NEXTCLOUD_MEMORY_LIMIT' => $this->nextcloudMemoryLimit,
|
||||
'NEXTCLOUD_MAX_TIME' => $this->nextcloudMaxTime,
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace AIO;
|
||||
use AIO\Docker\DockerHubManager;
|
||||
use DI\Container;
|
||||
use AIO\Docker\GitHubContainerRegistryManager;
|
||||
use AIO\Translation\TranslationManager;
|
||||
|
||||
class DependencyInjection
|
||||
{
|
||||
@@ -50,6 +51,10 @@ class DependencyInjection
|
||||
$container->get(\AIO\Data\ConfigurationManager::class)
|
||||
)
|
||||
);
|
||||
$container->set(
|
||||
TranslationManager::class,
|
||||
new TranslationManager()
|
||||
);
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
@@ -145,11 +145,12 @@ readonly class DockerActionManager {
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLogs(string $id): string {
|
||||
public function GetLogs(string $id, string $since = ''): string {
|
||||
$url = $this->BuildApiUrl(
|
||||
sprintf(
|
||||
'containers/%s/logs?stdout=true&stderr=true×tamps=true',
|
||||
urlencode($id)
|
||||
'containers/%s/logs?stdout=true&stderr=true×tamps=true&since=%s',
|
||||
urlencode($id),
|
||||
$since
|
||||
));
|
||||
$responseBody = (string)$this->guzzleClient->get($url)->getBody();
|
||||
|
||||
@@ -166,9 +167,12 @@ readonly class DockerActionManager {
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function StartContainer(Container $container): void {
|
||||
public function StartContainer(Container $container, ?\Closure $addToStreamingResponseBody = null): void {
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/start', urlencode($container->identifier)));
|
||||
try {
|
||||
if ($addToStreamingResponseBody !== null) {
|
||||
$addToStreamingResponseBody($container, "Starting container");
|
||||
}
|
||||
$this->guzzleClient->post($url);
|
||||
} catch (RequestException $e) {
|
||||
throw new \Exception("Could not start container " . $container->identifier . ": " . $e->getResponse()?->getBody()->getContents());
|
||||
@@ -473,8 +477,7 @@ readonly class DockerActionManager {
|
||||
}
|
||||
}
|
||||
|
||||
public function PullImage(Container $container, bool $pullImage = true): void {
|
||||
|
||||
public function PullImage(Container $container, bool $pullImage = true, ?\Closure $addToStreamingResponseBody = null): void {
|
||||
// Skip database image pull if the last shutdown was not clean
|
||||
if ($container->identifier === 'nextcloud-aio-database') {
|
||||
if ($this->GetDatabasecontainerExitCode() > 0) {
|
||||
@@ -502,6 +505,9 @@ readonly class DockerActionManager {
|
||||
$url = $this->BuildApiUrl(sprintf('images/create?fromImage=%s', $encodedImageName));
|
||||
$imageIsThere = true;
|
||||
try {
|
||||
if ($addToStreamingResponseBody) {
|
||||
$addToStreamingResponseBody($container, "Pulling image");
|
||||
}
|
||||
$imageUrl = $this->BuildApiUrl(sprintf('images/%s/json', $encodedImageName));
|
||||
$this->guzzleClient->get($imageUrl)->getBody()->getContents();
|
||||
} catch (\Throwable $e) {
|
||||
@@ -649,8 +655,8 @@ readonly class DockerActionManager {
|
||||
if (count($imageNameArray) === 2) {
|
||||
$imageName = $imageNameArray[0];
|
||||
} else {
|
||||
error_log("No tag was found when getting the current channel. You probably did not follow the documentation correctly. Changing the imageName to the default " . $output['Config']['Image']);
|
||||
$imageName = $output['Config']['Image'];
|
||||
error_log("Unexpected image name was found when getting the current image name of the mastercontainer. You probably did not follow the documentation correctly. Changing the image name to the default 'ghcr.io/nextcloud-releases/all-in-one'.");
|
||||
$imageName = 'ghcr.io/nextcloud-releases/all-in-one';
|
||||
}
|
||||
apcu_add($cacheKey, $imageName);
|
||||
return $imageName;
|
||||
|
||||
264
php/src/Translation/TranslationManager.php
Normal file
264
php/src/Translation/TranslationManager.php
Normal file
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace AIO\Translation;
|
||||
|
||||
/**
|
||||
* Resolves the active language and loads translations from a flat JSON file.
|
||||
*
|
||||
* Language resolution order:
|
||||
* 1. PHP session ($_SESSION['aio_user_language'])
|
||||
* 2. Accept-Language HTTP header (first matching tag that has a JSON file)
|
||||
* 3. Hardcoded fallback: "en"
|
||||
*
|
||||
* English is the implicit source language — the key itself is the English
|
||||
* string, so no en.json is required.
|
||||
*
|
||||
* Translation files live at:
|
||||
* <project-root>/php/translations/{lang}.json
|
||||
* Each file is a flat JSON object: {"some_key": "Translated string", ...}
|
||||
*/
|
||||
final class TranslationManager
|
||||
{
|
||||
private const TRANSLATIONS_DIR = __DIR__ . '/../../translations';
|
||||
private const FALLBACK_LANGUAGE = 'en';
|
||||
private const SESSION_KEY = 'aio_user_language';
|
||||
|
||||
/** @var array<string, string> */
|
||||
private array $strings = [];
|
||||
|
||||
private string $currentLanguage;
|
||||
|
||||
/** @var list<string>|null Lazily populated from the filesystem. */
|
||||
private ?array $supportedLanguages = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->currentLanguage = $this->resolveLanguage();
|
||||
$this->loadStrings($this->currentLanguage);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return the translated string for $key, or $key itself when no
|
||||
* translation is available (English pass-through behaviour).
|
||||
*/
|
||||
public function translate(string $key): string
|
||||
{
|
||||
return $this->strings[$key] ?? $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* The language code that is currently active (e.g. "de", "fr", "en").
|
||||
*/
|
||||
public function getCurrentLanguage(): string
|
||||
{
|
||||
return $this->currentLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* All language codes for which a translations/*.json file exists.
|
||||
* The list is sorted alphabetically and always includes "en".
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getSupportedLanguages(): array
|
||||
{
|
||||
if ($this->supportedLanguages !== null) {
|
||||
return $this->supportedLanguages;
|
||||
}
|
||||
|
||||
$languages = ['en'];
|
||||
|
||||
$pattern = self::TRANSLATIONS_DIR . '/*.json';
|
||||
$files = glob($pattern);
|
||||
foreach ($files !== false ? $files : [] as $file) {
|
||||
$code = basename($file, '.json');
|
||||
if ($code !== 'en' && $this->isValidLanguageCode($code)) {
|
||||
$languages[] = $code;
|
||||
}
|
||||
}
|
||||
|
||||
sort($languages);
|
||||
$this->supportedLanguages = $languages;
|
||||
|
||||
return $this->supportedLanguages;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Language resolution
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private function resolveLanguage(): string
|
||||
{
|
||||
// 1. Session preference set by the user via the language switcher.
|
||||
if (
|
||||
isset($_SESSION[self::SESSION_KEY])
|
||||
&& is_string($_SESSION[self::SESSION_KEY])
|
||||
&& $this->isValidLanguageCode($_SESSION[self::SESSION_KEY])
|
||||
) {
|
||||
$lang = $this->normalise($_SESSION[self::SESSION_KEY]);
|
||||
if ($this->hasTranslationFile($lang) || $lang === self::FALLBACK_LANGUAGE) {
|
||||
return $lang;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Accept-Language header — try each tag in quality order.
|
||||
$acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
|
||||
if ($acceptLanguage !== '') {
|
||||
$candidate = $this->resolveFromAcceptLanguage($acceptLanguage);
|
||||
if ($candidate !== null) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Hardcoded fallback.
|
||||
return self::FALLBACK_LANGUAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an Accept-Language header value and return the best matching
|
||||
* language code for which we have a translation file, or null.
|
||||
*
|
||||
* Example header: "de-AT,de;q=0.9,en-US;q=0.8,en;q=0.7"
|
||||
*/
|
||||
private function resolveFromAcceptLanguage(string $header): ?string
|
||||
{
|
||||
// Split on comma, sort by quality weight (highest first).
|
||||
$tags = [];
|
||||
foreach (explode(',', $header) as $part) {
|
||||
$part = trim($part);
|
||||
if ($part === '') {
|
||||
continue;
|
||||
}
|
||||
$quality = 1.0;
|
||||
if (str_contains($part, ';q=')) {
|
||||
$segments = explode(';q=', $part, 2);
|
||||
$quality = (float) ($segments[1] ?? '1');
|
||||
$part = trim($segments[0]);
|
||||
}
|
||||
$tags[] = ['tag' => $part, 'q' => $quality];
|
||||
}
|
||||
usort($tags, static fn(array $a, array $b): int => $b['q'] <=> $a['q']);
|
||||
|
||||
foreach ($tags as $entry) {
|
||||
$tag = $entry['tag'];
|
||||
|
||||
// Try the exact tag first (e.g. "de-AT"), then the primary subtag
|
||||
// (e.g. "de"), then a case-insensitive match against known files.
|
||||
foreach ($this->candidatesFor($tag) as $candidate) {
|
||||
if ($candidate === self::FALLBACK_LANGUAGE) {
|
||||
return self::FALLBACK_LANGUAGE;
|
||||
}
|
||||
if ($this->hasTranslationFile($candidate)) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the normalised language code candidates to try for a given
|
||||
* Accept-Language tag, from most specific to least specific.
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
private function candidatesFor(string $tag): array
|
||||
{
|
||||
$candidates = [];
|
||||
|
||||
$normalised = $this->normalise($tag);
|
||||
if ($this->isValidLanguageCode($normalised)) {
|
||||
$candidates[] = $normalised;
|
||||
}
|
||||
|
||||
// If the tag contains a region/script subtag, also try just the
|
||||
// primary language subtag (e.g. "de-AT" → "de").
|
||||
if (str_contains($normalised, '-')) {
|
||||
$primary = explode('-', $normalised, 2)[0];
|
||||
if ($this->isValidLanguageCode($primary)) {
|
||||
$candidates[] = $primary;
|
||||
}
|
||||
}
|
||||
|
||||
return $candidates;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Translation file loading
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private function loadStrings(string $language): void
|
||||
{
|
||||
if ($language === self::FALLBACK_LANGUAGE) {
|
||||
// English: key == translation, nothing to load.
|
||||
$this->strings = [];
|
||||
return;
|
||||
}
|
||||
|
||||
$path = $this->translationFilePath($language);
|
||||
if (!file_exists($path)) {
|
||||
$this->strings = [];
|
||||
return;
|
||||
}
|
||||
|
||||
$contents = file_get_contents($path);
|
||||
if ($contents === false) {
|
||||
$this->strings = [];
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var mixed $decoded */
|
||||
$decoded = json_decode($contents, true);
|
||||
if (!is_array($decoded)) {
|
||||
$this->strings = [];
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var array<string, string> $strings */
|
||||
$strings = [];
|
||||
foreach ($decoded as $key => $value) {
|
||||
if (is_string($key) && is_string($value)) {
|
||||
$strings[$key] = $value;
|
||||
}
|
||||
}
|
||||
$this->strings = $strings;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private function hasTranslationFile(string $language): bool
|
||||
{
|
||||
return file_exists($this->translationFilePath($language));
|
||||
}
|
||||
|
||||
private function translationFilePath(string $language): string
|
||||
{
|
||||
return self::TRANSLATIONS_DIR . '/' . $language . '.json';
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise a language tag to lowercase with hyphens
|
||||
* (e.g. "de_AT" → "de-at", "ZH-Hans" → "zh-hans").
|
||||
*/
|
||||
private function normalise(string $tag): string
|
||||
{
|
||||
return strtolower(str_replace('_', '-', $tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanity-check that the string looks like a BCP-47 language tag and
|
||||
* cannot be used for path traversal.
|
||||
*/
|
||||
private function isValidLanguageCode(string $code): bool
|
||||
{
|
||||
return (bool) preg_match('/^[a-zA-Z]{2,8}(?:-[a-zA-Z0-9]{1,8})*$/', $code);
|
||||
}
|
||||
}
|
||||
48
php/src/Twig/TranslationExtension.php
Normal file
48
php/src/Twig/TranslationExtension.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace AIO\Twig;
|
||||
|
||||
use AIO\Translation\TranslationManager;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\Extension\GlobalsInterface;
|
||||
use Twig\TwigFilter;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
final class TranslationExtension extends AbstractExtension implements GlobalsInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TranslationManager $translationManager,
|
||||
) {
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function getFunctions(): array
|
||||
{
|
||||
return [
|
||||
new TwigFunction('t', $this->translate(...)),
|
||||
];
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function getFilters(): array
|
||||
{
|
||||
return [
|
||||
new TwigFilter('t', $this->translate(...)),
|
||||
];
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function getGlobals(): array
|
||||
{
|
||||
return [
|
||||
'currentLanguage' => $this->translationManager->getCurrentLanguage(),
|
||||
'supportedLanguages' => $this->translationManager->getSupportedLanguages(),
|
||||
];
|
||||
}
|
||||
|
||||
public function translate(string $key): string
|
||||
{
|
||||
return $this->translationManager->translate($key);
|
||||
}
|
||||
}
|
||||
@@ -4,26 +4,26 @@
|
||||
{% if c.GetStartingState().value == 'starting' %}
|
||||
<span class="status running"></span>
|
||||
{{ c.displayName }}
|
||||
(<a href="api/docker/logs?id={{ c.identifier }}" target="_blank">Starting</a>)
|
||||
(<a href="log?id={{ c.identifier }}" target="_blank">{{ t('Starting') }}</a>)
|
||||
{% elseif c.GetRunningState().value == 'running' %}
|
||||
<span class="status success"></span>
|
||||
{{ c.displayName }}
|
||||
(<a href="api/docker/logs?id={{ c.identifier }}" target="_blank">Running</a>)
|
||||
(<a href="log?id={{ c.identifier }}" target="_blank">{{ t('Running') }}</a>)
|
||||
{% else %}
|
||||
<span class="status error"></span>
|
||||
{{ c.displayName }}
|
||||
(<a href="api/docker/logs?id={{ c.identifier }}" target="_blank">Stopped</a>)
|
||||
(<a href="log?id={{ c.identifier }}" target="_blank">{{ t('Stopped') }}</a>)
|
||||
{% endif %}
|
||||
{% if c.documentation != '' %}
|
||||
(<a target="_blank" href="{{ c.documentation }}">docs</a>)
|
||||
(<a target="_blank" href="{{ c.documentation }}">{{ t('docs') }}</a>)
|
||||
{% endif %}
|
||||
{% if c.GetUpdateState().value == 'different' %}
|
||||
⚠️ Update available
|
||||
⚠️ {{ t('Update') }} {{ t('available') }}
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if c.GetUiSecret() != '' %}
|
||||
<details>
|
||||
<summary>Show password for {{ c.displayName }}</summary>
|
||||
<summary>{{ t('Show password for') }} {{ c.displayName }}</summary>
|
||||
<input type="text" value="{{ c.GetUiSecret() }}" readonly>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
@@ -8,17 +8,27 @@
|
||||
<svg class="logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 142 71" width="62" height="50">
|
||||
<use href="img/nextcloud-logo.svg#logo"></use>
|
||||
</svg>
|
||||
<form method="POST" action="api/auth/logout">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Log out" />
|
||||
</form>
|
||||
<div class="header-controls">
|
||||
{% if supportedLanguages|length > 1 %}
|
||||
<select id="language-switcher" class="language-switcher" data-current="{{ currentLanguage }}" aria-label="{{ t('Select language') }}">
|
||||
{% for lang in supportedLanguages %}
|
||||
<option value="{{ lang }}"{% if lang == currentLanguage %} selected{% endif %}>{{ lang }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% endif %}
|
||||
<form method="POST" action="api/auth/logout">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="{{ t('Log out') }}" />
|
||||
</form>
|
||||
</div>
|
||||
<script type="text/javascript" src="language-switcher.js"></script>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<main>
|
||||
{% set aio_version = include('includes/aio-version.twig') %}
|
||||
<h1>Nextcloud AIO v{{ aio_version }}</h1>
|
||||
<h1>{{ t('Nextcloud AIO v') }}{{ aio_version }}</h1>
|
||||
|
||||
{# Add 2nd tab warning #}
|
||||
<script type="text/javascript" src="second-tab-warning.js"></script>
|
||||
@@ -27,7 +37,7 @@
|
||||
<script type="text/javascript" src="timezone.js"></script>
|
||||
|
||||
{# js for optional containers and additional containers forms #}
|
||||
<script type="text/javascript" src="containers-form-submit.js?v5"></script>
|
||||
<script type="text/javascript" src="containers-form-submit.js?v6"></script>
|
||||
|
||||
{% set hasBackupLocation = borg_backup_host_location or borg_remote_repo %}
|
||||
{% set isAnyRunning = false %}
|
||||
@@ -47,10 +57,10 @@
|
||||
{% endif %}
|
||||
|
||||
{% for container in containers %}
|
||||
{% if container.displayName != '' and container.GetRunningState().value == 'running' %}
|
||||
{% if container.hideFromList != true and container.GetRunningState().value == 'running' %}
|
||||
{% set isAnyRunning = true %}
|
||||
{% endif %}
|
||||
{% if container.displayName != '' and container.GetRestartingState().value == 'restarting' %}
|
||||
{% if container.hideFromList != true and container.GetRestartingState().value == 'restarting' %}
|
||||
{% set isAnyRestarting = true %}
|
||||
{% endif %}
|
||||
{% if container.identifier == 'nextcloud-aio-watchtower' and container.GetRunningState().value == 'running' %}
|
||||
@@ -65,50 +75,50 @@
|
||||
{% endfor %}
|
||||
|
||||
{% if is_daily_backup_running == true %}
|
||||
<p><span class="status running"></span> Daily backup currently running. (<a href="api/docker/logs?id=nextcloud-aio-mastercontainer" target="_blank">Mastercontainer logs</a>) (<a href="api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank">Borg backup container logs</a>)</p>
|
||||
<p><span class="status running"></span> {{ t('Daily backup currently running.') }} (<a href="log?id=nextcloud-aio-mastercontainer" target="_blank">{{ t('Mastercontainer logs') }}</a>) (<a href="log?id=nextcloud-aio-borgbackup" target="_blank">{{ t('Borg backup container logs') }}</a>)</p>
|
||||
{% if automatic_updates == true %}
|
||||
<p>This will update your containers, the mastercontainer and, on Saturdays, your Nextcloud apps if the backup is successful.</p>
|
||||
<p>{{ t('This will update your containers, the mastercontainer and, on Saturdays, your Nextcloud apps if the backup is successful.') }}</p>
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
<p>When the mastercontainer is updated it will restart, making it unavailable for a moment. (<a href="api/docker/logs?id=nextcloud-aio-watchtower" target="_blank">Logs</a>)</p>
|
||||
<p>{{ t('When the mastercontainer is updated it will restart, making it unavailable for a moment.') }} (<a href="log?id=nextcloud-aio-watchtower" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if has_update_available == false %}
|
||||
<p>The whole process should not take more than a few minutes.</p>
|
||||
<p>{{ t('The whole process should not take more than a few minutes.') }}</p>
|
||||
{% elseif automatic_updates == true %}
|
||||
<p>The whole process can take a while as your containers will be updated.</p>
|
||||
<p>{{ t('The whole process can take a while as your containers will be updated.') }}</p>
|
||||
{% endif %}
|
||||
<p><a href="" class="button reload">Reload ↻</a></p>
|
||||
<p>If the daily backup is stuck somehow, you can unstick it by running <strong>sudo docker exec nextcloud-aio-mastercontainer rm /mnt/docker-aio-config/data/daily_backup_running</strong> and afterwards reloading this interface.</p>
|
||||
<p><a href="" class="button reload">{{ t('Reload ↻') }}</a></p>
|
||||
<p>{{ t('If the daily backup is stuck somehow, you can unstick it by running') }} <strong>sudo docker exec nextcloud-aio-mastercontainer rm /mnt/docker-aio-config/data/daily_backup_running</strong> {{ t('and afterwards reloading this interface.') }}</p>
|
||||
{% elseif isWatchtowerRunning == true %}
|
||||
<p><span class="status running"></span> Mastercontainer update currently running. Once the update is complete the mastercontainer will restart, making it unavailable for a moment. Please wait until it's done. (<a href="api/docker/logs?id=nextcloud-aio-watchtower" target="_blank">Logs</a>)</p>
|
||||
<p><a href="" class="button reload">Reload ↻</a></p>
|
||||
<p><span class="status running"></span> {{ t('Mastercontainer update currently running. Once the update is complete the mastercontainer will restart, making it unavailable for a moment. Please wait until it\'s done.') }} (<a href="log?id=nextcloud-aio-watchtower" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
<p><a href="" class="button reload">{{ t('Reload ↻') }}</a></p>
|
||||
{% else %}
|
||||
{% if is_backup_container_running == false and domain == "" %}
|
||||
{% if isDomaincheckRunning == false %}
|
||||
<h2>Domaincheck container is not running</h2>
|
||||
<p>This is not expected. Most likely this happened because port {{ apache_port }} is already in use on your server. You can check the mastercontainer logs and domaincheck container logs for further clues. You should be able to resolve this by adjusting the APACHE_PORT by following the <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md">reverse proxy documentation</a></strong>. Advice: have a detailed look at the changed docker run command for AIO.</p>
|
||||
<h2>{{ t('Domaincheck container is not running') }}</h2>
|
||||
<p>{{ t('This is not expected. Most likely this happened because port') }} {{ apache_port }} {{ t('is already in use on your server. You can check the mastercontainer logs and domaincheck container logs for further clues. You should be able to resolve this by adjusting the APACHE_PORT by following the') }} <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md">{{ t('reverse proxy documentation') }}</a></strong>. {{ t('Advice: have a detailed look at the changed docker run command for AIO.') }}</p>
|
||||
{% elseif is_mastercontainer_update_available == true %}
|
||||
<h2>Mastercontainer update</h2>
|
||||
<p>⚠️ A mastercontainer update is available. Please click on the button below to update it. Afterwards, you will be able to proceed with the setup.</p>
|
||||
<form method="POST" action="api/docker/watchtower" class="xhr">
|
||||
<h2>{{ t('Mastercontainer update') }}</h2>
|
||||
<p>⚠️ {{ t('A mastercontainer update is available. Please click on the button below to update it. Afterwards, you will be able to proceed with the setup.') }}</p>
|
||||
<form method="POST" action="api/docker/watchtower" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Update mastercontainer" />
|
||||
<input type="submit" value="{{ t('Update mastercontainer') }}" />
|
||||
</form>
|
||||
{% else %}
|
||||
{% if not hasBackupLocation %}
|
||||
<p>The official Nextcloud installation method. Nextcloud All-in-One provides easy deployment and maintenance with most features included in this one Nextcloud instance.</p>
|
||||
<p>You can either create a new AIO instance or restore a former AIO instance from backup. See the two sections below.</p>
|
||||
<p>{{ t('The official Nextcloud installation method. Nextcloud All-in-One provides easy deployment and maintenance with most features included in this one Nextcloud instance.') }}</p>
|
||||
<p>{{ t('You can either create a new AIO instance or restore a former AIO instance from backup. See the two sections below.') }}</p>
|
||||
{{ include('includes/aio-config.twig') }}
|
||||
<h2>New AIO instance</h2>
|
||||
<h2>{{ t('New AIO instance') }}</h2>
|
||||
{% if apache_port == '443' %}
|
||||
<p>AIO is currently in "normal mode" which means that it handles the TLS proxying itself. This also means that it cannot be installed behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). If you want to run AIO behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), see the <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md">reverse proxy documentation</a></strong>. Advice: have a detailed look at the changed docker run command for AIO.</p>
|
||||
<p>{{ t('AIO is currently in "normal mode" which means that it handles the TLS proxying itself. This also means that it cannot be installed behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). If you want to run AIO behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), see the') }} <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md">{{ t('reverse proxy documentation') }}</a></strong>. {{ t('Advice: have a detailed look at the changed docker run command for AIO.') }}</p>
|
||||
{% else %}
|
||||
<p>AIO is currently in "reverse proxy mode" which means that it can be installed behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) and does not do the TLS proxying itself.</p>
|
||||
<p>{{ t('AIO is currently in "reverse proxy mode" which means that it can be installed behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) and does not do the TLS proxying itself.') }}</p>
|
||||
{% endif %}
|
||||
<p>Please type in the domain that will be used for Nextcloud and submit it.</p>
|
||||
<p>{{ t('Please type in the domain that will be used for Nextcloud and submit it.') }}</p>
|
||||
{% if skip_domain_validation == true %}
|
||||
<p><strong>Please note:</strong> The domain validation is disabled so any domain will be accepted here! Make sure you do not make a typo here as you will not be able to change it afterwards!</p>
|
||||
<p><strong>{{ t('Please note:') }}</strong> {{ t('The domain validation is disabled so any domain will be accepted here! Make sure you do not make a typo here as you will not be able to change it afterwards!') }}</p>
|
||||
{% endif %}
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<input type="text" id="domain" name="domain" value="{{ domain }}" placeholder="nextcloud.yourdomain.com"/>
|
||||
@@ -117,59 +127,61 @@
|
||||
{% if skip_domain_validation == true %}
|
||||
<input type="hidden" name="skip_domain_validation" value="{{skip_domain_validation}}">
|
||||
{% endif %}
|
||||
<input type="submit" value="Submit domain" />
|
||||
<input type="submit" value="{{ t('Submit domain') }}" />
|
||||
</form>
|
||||
{% if skip_domain_validation == false %}
|
||||
<p>Make sure that this server is reachable on port 443 (port 443/tcp is open/forwarded in your firewall/router and 443/udp as well if you want to enable http3) and that you've correctly set up the DNS config for the domain that you enter (set the A record to your public ipv4-address and if you need ipv6, set the AAAA record to your public ipv6-address. A CNAME record is, of course, also possible). You should see hints on what went wrong in the top right corner if your domain is not accepted.</p>
|
||||
<p>{{ t('Make sure that this server is reachable on port 443 (port 443/tcp is open/forwarded in your firewall/router and 443/udp as well if you want to enable http3) and that you\'ve correctly set up the DNS config for the domain that you enter (set the A record to your public ipv4-address and if you need ipv6, set the AAAA record to your public ipv6-address. A CNAME record is, of course, also possible). You should see hints on what went wrong in the top right corner if your domain is not accepted.') }}</p>
|
||||
<details>
|
||||
<summary>Click here for further hints</summary>
|
||||
<p>If you do not have a domain yet, you can get one for free e.g. from duckdns.org and others. Recommended is to use <a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/6817">Tailscale</a></p>
|
||||
<p>If you have a dynamic public IP-address, you can use e.g. <a target="_blank" href="https://ddclient.net/">DDclient</a> with a compatible domain provider for DNS updates.</p>
|
||||
<p>If you only want to install AIO locally without exposing it to the public internet or if you cannot do so, feel free to follow <a target="_blank" href="https://github.com/nextcloud/all-in-one/blob/main/local-instance.md">this documentation</a>.</p>
|
||||
<p>If you should be using Cloudflare Proxy for your domain, make sure to disable the Proxy feature temporarily as it might block the domain validation attempts.</p>
|
||||
<summary>{{ t('Click here for further hints') }}</summary>
|
||||
<p>{{ t('If you do not have a domain yet, you can get one for free e.g. from duckdns.org and others. Recommended is to use') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/6817">Tailscale</a></p>
|
||||
<p>{{ t('If you have a dynamic public IP-address, you can use e.g.') }} <a target="_blank" href="https://ddclient.net/">DDclient</a> {{ t('with a compatible domain provider for DNS updates.') }}</p>
|
||||
<p>{{ t('If you only want to install AIO locally without exposing it to the public internet or if you cannot do so, feel free to follow') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one/blob/main/local-instance.md">{{ t('this documentation') }}</a>.</p>
|
||||
<p>{{ t('If you should be using Cloudflare Proxy for your domain, make sure to disable the Proxy feature temporarily as it might block the domain validation attempts.') }}</p>
|
||||
{% if apache_port != '443' %}
|
||||
<p>If you run into issues with your domain being accepted, see <a target="_blank" href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#how-to-debug">these steps</a> for how to debug things.</p>
|
||||
<p>{{ t('If you run into issues with your domain being accepted, see') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#how-to-debug">{{ t('these steps') }}</a> {{ t('for how to debug things.') }}</p>
|
||||
{% endif %}
|
||||
<p><strong>Hint:</strong> If the domain validation fails but you are completely sure that you've configured everything correctly, you may skip the domain validation by following <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation">this documentation</a>.</p>
|
||||
<p><strong>{{ t('Hint:') }}</strong> {{ t('If the domain validation fails but you are completely sure that you\'ve configured everything correctly, you may skip the domain validation by following') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation">{{ t('this documentation') }}</a>.</p>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
<h2>Restore former AIO instance from backup</h2>
|
||||
<p>You can alternatively restore a former AIO instance from backup.</p>
|
||||
<h2>{{ t('Restore former AIO instance from backup') }}</h2>
|
||||
<p>{{ t('You can alternatively restore a former AIO instance from backup.') }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if is_instance_restore_attempt == false %}
|
||||
{% if hasBackupLocation %}
|
||||
{% if borg_backup_mode in ['test', 'check'] %}
|
||||
{% if backup_exit_code > 0 %}
|
||||
<p><span class="status error"></span> Last {{ borg_backup_mode }} failed! (<a href="api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank">Logs</a>)</p>
|
||||
<p><span class="status error"></span> {{ t('Last') }} {{ borg_backup_mode }} {{ t('failed!') }} (<a href="log?id=nextcloud-aio-borgbackup" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
{% if borg_backup_mode == 'test' %}
|
||||
<p>Please adjust the path and/or the encryption password in order to make it work!</p>
|
||||
<p>{{ t('Please adjust the path and/or the encryption password in order to make it work!') }}</p>
|
||||
{% elseif borg_backup_mode == 'check' %}
|
||||
<p>The backup archive seems to be corrupt. Please try to use a different intact backup archive or try to fix it by following <a target="_blank" href="https://borgbackup.readthedocs.io/en/stable/faq.html#i-get-an-integrityerror-or-similar-what-now"><strong>this documentation</strong></a></p>
|
||||
<p>{{ t('The backup archive seems to be corrupt. Please try to use a different intact backup archive or try to fix it by following') }} <a target="_blank" href="https://borgbackup.readthedocs.io/en/stable/faq.html#i-get-an-integrityerror-or-similar-what-now"><strong>{{ t('this documentation') }}</strong></a></p>
|
||||
<details>
|
||||
<summary>Reveal repair option</summary>
|
||||
<p>Below is the option to repair the integrity of your backup. <strong>Please note:</strong> Please only use this after you have read the documentation above! (It will run the command 'borg check --repair' for you.)</p>
|
||||
<form method="POST" action="api/docker/backup-check-repair" class="xhr">
|
||||
<summary>{{ t('Reveal repair option') }}</summary>
|
||||
<p>{{ t('Below is the option to repair the integrity of your backup.') }} <strong>{{ t('Please note:') }}</strong> {{ t('Please only use this after you have read the documentation above! (It will run the command \'borg check --repair\' for you.)') }}</p>
|
||||
{% set confirmRepair = t('Check and repair backup integrity? Are you sure that you want to check and repair the backup integrity? This should only be done after reading the mentioned documentation.') %}
|
||||
<form method="POST" action="api/docker/backup-check-repair" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Check and repair backup integrity" onclick="return confirm('Check and repair backup integrity? Are you sure that you want to check and repair the backup integrity? This should only be done after reading the mentioned documentation.')"/>
|
||||
<input type="submit" value="{{ t('Check and repair backup integrity') }}" onclick="return confirm('{{ confirmRepair|e('js') }}')"/>
|
||||
</form>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% elseif backup_exit_code == 0 %}
|
||||
<p><span class="status success"></span> Last {{ borg_backup_mode }} successful! (<a href="api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank">Logs</a>)</p>
|
||||
<p><span class="status success"></span> {{ t('Last') }} {{ borg_backup_mode }} {{ t('successful!') }} (<a href="log?id=nextcloud-aio-borgbackup" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
{% if borg_backup_mode == 'test' %}
|
||||
<p>Feel free to check the integrity of the backup archive below before starting the restore process in order to make ensure that the restore will work. This can take a long time though depending on the size of the backup archive and is thus not required.</p>
|
||||
<form method="POST" action="api/docker/backup-check" class="xhr">
|
||||
<p>{{ t('Feel free to check the integrity of the backup archive below before starting the restore process in order to make ensure that the restore will work. This can take a long time though depending on the size of the backup archive and is thus not required.') }}</p>
|
||||
<form method="POST" action="api/docker/backup-check" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Check backup integrity"/>
|
||||
<input type="submit" value="{{ t('Check backup integrity') }}"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
<p>Choose the backup that you want to restore and click on the button below to restore the selected backup. This will restore the whole AIO instance. Please note that the current AIO passphrase will be kept and the previous AIO passphrase will not be restored from backup!</p>
|
||||
<p><strong>Important:</strong> If the backup that you want to restore contained any <a target="_blank" href="https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers">community container</a>, you need to restore the same backup a second time after this attempt so that the community container data is also correctly restored.</p>
|
||||
<form method="POST" action="api/docker/restore" class="xhr" id="restore_selection">
|
||||
<p>{{ t('Choose the backup that you want to restore and click on the button below to restore the selected backup. This will restore the whole AIO instance. Please note that the current AIO passphrase will be kept and the previous AIO passphrase will not be restored from backup!') }}</p>
|
||||
<p><strong>{{ t('Important:') }}</strong> {{ t('If the backup that you want to restore contained any') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers">{{ t('community container') }}</a>, {{ t('you need to restore the same backup a second time after this attempt so that the community container data is also correctly restored.') }}</p>
|
||||
{% set confirmRestore = t('⚠️ Important: If the backup that you want to restore contained any community container, you need to restore the same backup a second time after this attempt so that the community container data is also correctly restored.') %}
|
||||
<form method="POST" action="api/docker/restore" target="overlay-log" id="restore_selection">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<select id="selected_restore_time" name="selected_restore_time" form="restore_selection">
|
||||
@@ -177,14 +189,14 @@
|
||||
<option value="{{ restore_time }}">{{ restore_time }} UTC</option>
|
||||
{% endfor %}
|
||||
</select><br>
|
||||
<input type="checkbox" id="restore-exclude-previews" name="restore-exclude-previews"><label for="restore-exclude-previews">Exclude previews from restore which will speed up the restore process but will trigger a scan of the preview folder as soon as the Nextcloud container starts the next time</label><br>
|
||||
<input type="submit" value="Restore selected backup" onclick="return confirm('⚠️ Important: If the backup that you want to restore contained any community container, you need to restore the same backup a second time after this attempt so that the community container data is also correctly restored.')"/>
|
||||
<input type="checkbox" id="restore-exclude-previews" name="restore-exclude-previews"><label for="restore-exclude-previews">{{ t('Exclude previews from restore which will speed up the restore process but will trigger a scan of the preview folder as soon as the Nextcloud container starts the next time') }}</label><br>
|
||||
<input type="submit" value="{{ t('Restore selected backup') }}" onclick="return confirm('{{ confirmRestore|e('js') }}')"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% elseif borg_backup_mode == 'restore' %}
|
||||
{% if backup_exit_code > 0 %}
|
||||
<p><span class="status error"></span> Last restore failed! (<a href="api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank">Logs</a>)</p>
|
||||
<p>The restore process has unexpectedly failed! Please adjust the path and encryption password, test it and try to restore again!</p>
|
||||
<p><span class="status error"></span> {{ t('Last restore failed!') }} (<a href="log?id=nextcloud-aio-borgbackup" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
<p>{{ t('The restore process has unexpectedly failed! Please adjust the path and encryption password, test it and try to restore again!') }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -192,51 +204,51 @@
|
||||
{% if not hasBackupLocation or borg_backup_mode not in ['test', 'check', ''] or backup_exit_code > 0 %}
|
||||
{% if borg_remote_repo and backup_exit_code > 0 %}
|
||||
<p>
|
||||
You may still need to authorize this pubkey on your borg remote:<br><strong>{{ borg_public_key }}</strong><br>
|
||||
To try again, resubmit your location and rerun the test.
|
||||
{{ t('You may still need to authorize this pubkey on your borg remote:') }}<br><strong>{{ borg_public_key }}</strong><br>
|
||||
{{ t('To try again, resubmit your location and rerun the test.') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
Please enter the location of the backup archive on your host or a
|
||||
<a target="_blank" href="https://borgbackup.readthedocs.io/en/stable/usage/general.html#repository-urls">remote borg repo url</a>
|
||||
if stored remotely; and the encryption password of the backup archive below and submit all values:
|
||||
{{ t('Please enter the location of the backup archive on your host or a') }}
|
||||
<a target="_blank" href="https://borgbackup.readthedocs.io/en/stable/usage/general.html#repository-urls">{{ t('remote borg repo url') }}</a>
|
||||
{{ t('if stored remotely; and the encryption password of the backup archive below and submit all values:') }}
|
||||
</p>
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<label>Local backup location</label> <input type="text" id="borg_restore_host_location" name="borg_restore_host_location" value="{{borg_backup_host_location}}" placeholder="/mnt/backup"/><br>
|
||||
<label>Remote borg repo</label> <input type="text" name="borg_restore_remote_repo" value="{{borg_remote_repo}}" placeholder="ssh://user@host:port/path/to/repo"/><br>
|
||||
<label>Borg passphrase</label> <input type="text" id="borg_restore_password" name="borg_restore_password" value="{{borg_restore_password}}" placeholder="encryption password"/><br>
|
||||
<label>{{ t('Local backup location') }}</label> <input type="text" id="borg_restore_host_location" name="borg_restore_host_location" value="{{borg_backup_host_location}}" placeholder="/mnt/backup"/><br>
|
||||
<label>{{ t('Remote borg repo') }}</label> <input type="text" name="borg_restore_remote_repo" value="{{borg_remote_repo}}" placeholder="ssh://user@host:port/path/to/repo"/><br>
|
||||
<label>{{ t('Borg passphrase') }}</label> <input type="text" id="borg_restore_password" name="borg_restore_password" value="{{borg_restore_password}}" placeholder="{{ t('encryption password') }}"/><br>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Submit location and encryption password" />
|
||||
<input type="submit" value="{{ t('Submit location and encryption password') }}" />
|
||||
</form>
|
||||
{{ include('includes/backup-dirs.twig') }}
|
||||
<p>⚠️ Please note that the backup archive must be located in a subfolder of the folder that you enter here and the subfolder which contains the archive must be named 'borg', or the backup container will not be able to find the backup archive!</p>
|
||||
<p>⚠️ {{ t('Please note that the backup archive must be located in a subfolder of the folder that you enter here and the subfolder which contains the archive must be named \'borg\', or the backup container will not be able to find the backup archive!') }}</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p><strong>Everything set!</strong> Click on the button below to test the path and encryption password:</p>
|
||||
<form method="POST" action="api/docker/backup-test" class="xhr">
|
||||
<p><strong>{{ t('Everything set!') }}</strong> {{ t('Click on the button below to test the path and encryption password:') }}</p>
|
||||
<form method="POST" action="api/docker/backup-test" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Test path and encryption password"/>
|
||||
<input type="submit" value="{{ t('Test path and encryption password') }}"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<h2>How to reset the AIO instance?</h2>
|
||||
<p>If something should be going wrong, for example during the initial installation, you can reset the instance by following <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-properly-reset-the-instance">this documentation</a>.</p>
|
||||
<h2>{{ t('How to reset the AIO instance?') }}</h2>
|
||||
<p>{{ t('If something should be going wrong, for example during the initial installation, you can reset the instance by following') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-properly-reset-the-instance">{{ t('this documentation') }}</a>.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if was_start_button_clicked == true %}
|
||||
{% if current_channel starts with 'latest' or current_channel starts with 'beta' or current_channel starts with 'develop' %}
|
||||
<p>You are running the <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-switch-the-channel"><strong>{{ current_channel }}</strong></a> channel. (<a href="api/docker/logs?id=nextcloud-aio-mastercontainer" target="_blank">Logs</a>)</p>
|
||||
<p>{{ t('You are running the') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-switch-the-channel"><strong>{{ current_channel }}</strong></a> {{ t('channel.') }} (<a href="log?id=nextcloud-aio-mastercontainer" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
{% else %}
|
||||
<p>No channel was found. This means that AIO is not able to update itself and its component and will also not be able to report about updates. Updates need to be done externally.</p>
|
||||
<p>{{ t('No channel was found. This means that AIO is not able to update itself and its component and will also not be able to report about updates. Updates need to be done externally.') }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_backup_container_running == true %}
|
||||
<p><span class="status running"></span> Backup container is currently running: {{ borg_backup_mode }} (<a href="api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank">Logs</a>)</p>
|
||||
<p><a href="" class="button reload">Reload ↻</a></p>
|
||||
<p><span class="status running"></span> {{ t('Backup container is currently running:') }} {{ borg_backup_mode }} (<a href="log?id=nextcloud-aio-borgbackup" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
<p><a href="" class="button reload">{{ t('Reload ↻') }}</a></p>
|
||||
{% endif %}
|
||||
|
||||
{% if domain != "" %}
|
||||
@@ -244,30 +256,30 @@
|
||||
{% if isApacheStarting != true %}
|
||||
{% if hasBackupLocation %}
|
||||
<details>
|
||||
<summary>Click here to reveal the initial Nextcloud credentials</summary>
|
||||
<summary>{{ t('Click here to reveal the initial Nextcloud credentials') }}</summary>
|
||||
{% endif %}
|
||||
<p>Initial Nextcloud username: <strong>admin</strong></p>
|
||||
<p>{{ t('Initial Nextcloud username:') }} <strong>admin</strong></p>
|
||||
{% if hasBackupLocation %}
|
||||
{# nextcloud_password needs to be duplicated due to a bug in Firefox. See https://github.com/nextcloud/all-in-one/issues/638. #}
|
||||
<p>Initial Nextcloud password: <strong id="initial-nextcloud-password">{{ nextcloud_password }}</strong></p></details>
|
||||
<p>{{ t('Initial Nextcloud password:') }} <strong id="initial-nextcloud-password">{{ nextcloud_password }}</strong></p></details>
|
||||
{% else %}
|
||||
<p>Initial Nextcloud password: <strong id="initial-nextcloud-password">{{ nextcloud_password }}</strong></p>
|
||||
<p>{{ t('Initial Nextcloud password:') }} <strong id="initial-nextcloud-password">{{ nextcloud_password }}</strong></p>
|
||||
{% endif %}
|
||||
<p><a href="https://{{ domain }}" class="button" target="_blank">Open your Nextcloud ↗</a></p>
|
||||
<p><a href="https://{{ domain }}" class="button" target="_blank">{{ t('Open your Nextcloud ↗') }}</a></p>
|
||||
{% if not hasBackupLocation %}
|
||||
<p>If your Nextcloud does not open when clicking the button above, see <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/2105">this documentation</a></strong></p>
|
||||
<p>{{ t('If your Nextcloud does not open when clicking the button above, see') }} <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/2105">{{ t('this documentation') }}</a></strong></p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if isAnyRestarting == false %}
|
||||
<p><span class="status running"></span> Containers are currently starting. You might inspect the container logs by clicking on <strong>Starting</strong> next to each container for further details.</p>
|
||||
<p><a href="" class="button reload">Reload ↻</a></p>
|
||||
<p><span class="status running"></span> {{ t('Containers are currently starting. You might inspect the container logs by clicking on') }} <strong>{{ t('Starting') }}</strong> {{ t('next to each container for further details.') }}</p>
|
||||
<p><a href="" class="button reload">{{ t('Reload ↻') }}</a></p>
|
||||
{% else %}
|
||||
<p>It seems at least one container was not able to start correctly and is currently restarting.</p>
|
||||
<p>To break this endless loop, you can stop the containers below and investigate the issue in the container logs before starting the containers again.</p>
|
||||
<form method="POST" action="api/docker/stop" class="xhr">
|
||||
<p>{{ t('It seems at least one container was not able to start correctly and is currently restarting.') }}</p>
|
||||
<p>{{ t('To break this endless loop, you can stop the containers below and investigate the issue in the container logs before starting the containers again.') }}</p>
|
||||
<form method="POST" action="api/docker/stop" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Stop containers" />
|
||||
<input type="submit" value="{{ t('Stop containers') }}" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -278,11 +290,11 @@
|
||||
{% endif %}
|
||||
|
||||
{% if was_start_button_clicked == true %}
|
||||
<h2>Containers</h2>
|
||||
<h2>{{ t('Containers') }}</h2>
|
||||
<ul>
|
||||
{# @var containers \AIO\Container\Container[] #}
|
||||
{% for container in containers %}
|
||||
{% if container.displayName != '' %}
|
||||
{% if container.hideFromList != true %}
|
||||
{% include 'components/container-state.twig' with {'c': container} only %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -290,15 +302,15 @@
|
||||
|
||||
{% if has_update_available == true %}
|
||||
{% if is_mastercontainer_update_available == false %}
|
||||
<p>⚠️ Container updates are available. Click on <strong>Stop containers</strong> and <strong>Start and update containers</strong> to update them. You should consider creating a backup first.</p>
|
||||
<p>⚠️ {{ t('Container updates are available. Click on') }} <strong>{{ t('Stop containers') }}</strong> {{ t('and') }} <strong>{{ t('Start and update containers') }}</strong> {{ t('to update them. You should consider creating a backup first.') }}</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if is_mastercontainer_update_available == false %}
|
||||
<p>Your containers are up-to-date.</p>
|
||||
<p>{{ t('Your containers are up-to-date.') }}</p>
|
||||
{% if newMajorVersionString != '' and isAnyRunning == true and isApacheStarting != true %}
|
||||
<details>
|
||||
<summary>Note about <strong>Nextcloud Hub {{ newMajorVersionString }}</strong></summary>
|
||||
<p>If you haven't upgraded to Nextcloud Hub {{ newMajorVersionString }} yet and want to do that now, feel free to follow <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/7523">this documentation</a></strong></p>
|
||||
<summary>{{ t('Note about') }} <strong>Nextcloud Hub {{ newMajorVersionString }}</strong></summary>
|
||||
<p>{{ t('If you haven\'t upgraded to Nextcloud Hub') }} {{ newMajorVersionString }} {{ t('yet and want to do that now, feel free to follow') }} <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/7523">{{ t('this documentation') }}</a></strong></p>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -308,62 +320,66 @@
|
||||
{% if isAnyRunning == true %}
|
||||
{% if isApacheStarting != true %}
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
<p>⚠️ A mastercontainer update is available. Please click on the button below to stop your containers in order to update the mastercontainer.</p>
|
||||
<p>⚠️ {{ t('A mastercontainer update is available. Please click on the button below to stop your containers in order to update the mastercontainer.') }}</p>
|
||||
{% if current_channel starts with 'latest' %}
|
||||
<p>You can find the changelog <a target="_blank" href="https://github.com/nextcloud/all-in-one/releases/latest"><strong>here</strong></a></p>
|
||||
<p>{{ t('You can find the changelog') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one/releases/latest"><strong>{{ t('here') }}</strong></a></p>
|
||||
{% elseif current_channel starts with 'beta' %}
|
||||
<p>You can find the changelog <a target="_blank" href="https://github.com/nextcloud/all-in-one/releases"><strong>here</strong></a></p>
|
||||
<p>{{ t('You can find the changelog') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one/releases"><strong>{{ t('here') }}</strong></a></p>
|
||||
{% elseif current_channel starts with 'develop' %}
|
||||
<p>You can find all changes <a target="_blank" href="https://github.com/nextcloud-releases/all-in-one/commits/main"><strong>here</strong></a></p>
|
||||
<p>{{ t('You can find all changes') }} <a target="_blank" href="https://github.com/nextcloud-releases/all-in-one/commits/main"><strong>{{ t('here') }}</strong></a></p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<form method="POST" action="api/docker/stop" class="xhr">
|
||||
<form method="POST" action="api/docker/stop" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Stop containers" />
|
||||
<input type="submit" value="{{ t('Stop containers') }}" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if isBackupOrRestoreRunning == true %}
|
||||
<p>Restore or Backup currently running. Cannot start the containers until Restore or Backup is complete.</p>
|
||||
<p>{{ t('Restore or Backup currently running. Cannot start the containers until Restore or Backup is complete.') }}</p>
|
||||
{% else %}
|
||||
{% if was_start_button_clicked == false %}
|
||||
<p>Clicking on the button below will download all docker containers and start them. This can take a long time depending on your internet connection. Since the overall size is a few GB, this can take around 5-10 min or more. Please be patient!</p>
|
||||
<p>{{ t('Clicking on the button below will download all docker containers and start them. This can take a long time depending on your internet connection. Since the overall size is a few GB, this can take around 5-10 min or more. Please be patient!') }}</p>
|
||||
{% endif %}
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
<p>⚠️ A mastercontainer update is available. Please click on the button below to update it.</p>
|
||||
<form method="POST" action="api/docker/watchtower" class="xhr">
|
||||
<p>⚠️ {{ t('A mastercontainer update is available. Please click on the button below to update it.') }}</p>
|
||||
<form method="POST" action="api/docker/watchtower" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Update mastercontainer" />
|
||||
<input type="submit" value="{{ t('Update mastercontainer') }}" />
|
||||
</form>
|
||||
{% else %}
|
||||
{% if was_start_button_clicked == false %}
|
||||
<form method="POST" action="api/docker/start" class="xhr">
|
||||
<form method="POST" action="api/docker/start" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input id="base_path" type="hidden" name="base_path" value="">
|
||||
{% if newMajorVersionString != '' %}
|
||||
<input type="checkbox" id="install_latest_major" name="install_latest_major"><label for="install_latest_major">Install Nextcloud Hub {{ newMajorVersionString }} (if unchecked, Nextcloud Hub {{ oldMajorVersionString }} will get installed)</label><br>
|
||||
<input type="checkbox" id="install_latest_major" name="install_latest_major"><label for="install_latest_major">{{ t('Install Nextcloud Hub') }} {{ newMajorVersionString }} {{ t('(if unchecked, Nextcloud Hub') }} {{ oldMajorVersionString }} {{ t('will get installed)') }}</label><br>
|
||||
{% endif %}
|
||||
<input type="submit" value="Download and start containers" />
|
||||
<input type="submit" value="{{ t('Download and start containers') }}" />
|
||||
</form>
|
||||
{% elseif has_update_available == false %}
|
||||
<form method="POST" action="api/docker/start" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input id="base_path" type="hidden" name="base_path" value="">
|
||||
<input type="submit" value="Start containers" />
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="POST" action="api/docker/start" class="xhr">
|
||||
<form method="POST" action="api/docker/start" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input id="base_path" type="hidden" name="base_path" value="">
|
||||
{% if bypass_container_update == true %}
|
||||
<input type="hidden" name="bypass_container_update" value="{{bypass_container_update}}">
|
||||
<input type="hidden" name="bypass_container_update" value="true">
|
||||
{% endif %}
|
||||
<input class="button " type="submit" value="Start and update containers" onclick="return confirm('Start and update containers? You should consider creating a backup first.')" />
|
||||
<input type="submit" value="{{ t('Start containers') }}" />
|
||||
</form>
|
||||
{% else %}
|
||||
{% set confirmStartUpdate = t('Start and update containers? You should consider creating a backup first.') %}
|
||||
<form method="POST" action="api/docker/start" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input id="base_path" type="hidden" name="base_path" value="">
|
||||
{% if bypass_container_update == true %}
|
||||
<input type="hidden" name="bypass_container_update" value="true">
|
||||
{% endif %}
|
||||
<input class="button " type="submit" value="{{ t('Start and update containers') }}" onclick="return confirm('{{ confirmStartUpdate|e('js') }}')" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -373,23 +389,23 @@
|
||||
{% if was_start_button_clicked == true %}
|
||||
|
||||
{% if is_backup_section_enabled == false %}
|
||||
<h2>Backup and restore</h2>
|
||||
<p>The backup section is disabled via environmental variable.</p>
|
||||
<h2>{{ t('Backup and restore') }}</h2>
|
||||
<p>{{ t('The backup section is disabled via environmental variable.') }}</p>
|
||||
{% else %}
|
||||
{% if is_backup_container_running == false and not hasBackupLocation and isApacheStarting != true %}
|
||||
<h2>Backup and restore</h2>
|
||||
<p>Please enter the directory path below where backups will be created on the host system and submit it. It's best to choose a location on a separate drive and not on your root drive.</p>
|
||||
<h2>{{ t('Backup and restore') }}</h2>
|
||||
<p>{{ t('Please enter the directory path below where backups will be created on the host system and submit it. It\'s best to choose a location on a separate drive and not on your root drive.') }}</p>
|
||||
<p>
|
||||
To store backups remotely instead, fill in the
|
||||
<a target="_blank" href="https://borgbackup.readthedocs.io/en/stable/usage/general.html#repository-urls">remote borg repo url and submit it</a>.
|
||||
You will be provided with an SSH public key for authorization at the remote afterwards.
|
||||
{{ t('To store backups remotely instead, fill in the') }}
|
||||
<a target="_blank" href="https://borgbackup.readthedocs.io/en/stable/usage/general.html#repository-urls">{{ t('remote borg repo url and submit it') }}</a>.
|
||||
{{ t('You will be provided with an SSH public key for authorization at the remote afterwards.') }}
|
||||
</p>
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<label>Local backup location</label> <input type="text" id="borg_backup_host_location" name="borg_backup_host_location" placeholder="/mnt/backup"/><br>
|
||||
<label>Remote borg repo</label> <input type="text" name="borg_remote_repo" placeholder="ssh://user@host:port/path/to/repo"/><br>
|
||||
<label>{{ t('Local backup location') }}</label> <input type="text" id="borg_backup_host_location" name="borg_backup_host_location" placeholder="/mnt/backup"/><br>
|
||||
<label>{{ t('Remote borg repo') }}</label> <input type="text" name="borg_remote_repo" placeholder="ssh://user@host:port/path/to/repo"/><br>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Submit backup location" />
|
||||
<input type="submit" value="{{ t('Submit backup location') }}" />
|
||||
</form>
|
||||
{{ include('includes/backup-dirs.twig') }}
|
||||
{% endif %}
|
||||
@@ -399,45 +415,46 @@
|
||||
|
||||
{% if hasBackupLocation %}
|
||||
{% if is_backup_container_running == false %}
|
||||
<h2>Backup and restore</h2>
|
||||
<h2>{{ t('Backup and restore') }}</h2>
|
||||
{% if backup_exit_code > 0 %}
|
||||
<p><span class="status error"></span> Last {{ borg_backup_mode }} failed! (<a href="api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank">Logs</a>)</p>
|
||||
<p><span class="status error"></span> {{ t('Last') }} {{ borg_backup_mode }} {{ t('failed!') }} (<a href="log?id=nextcloud-aio-borgbackup" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
{% if borg_backup_mode == "check" %}
|
||||
<p>The backup check was not successful. This might indicate a corrupt archive (look at the logs). If that should be the case, you can try to fix it by following <a target="_blank" href="https://borgbackup.readthedocs.io/en/stable/faq.html#i-get-an-integrityerror-or-similar-what-now"><strong>this documentation</strong></a></p>
|
||||
<p>{{ t('The backup check was not successful. This might indicate a corrupt archive (look at the logs). If that should be the case, you can try to fix it by following') }} <a target="_blank" href="https://borgbackup.readthedocs.io/en/stable/faq.html#i-get-an-integrityerror-or-similar-what-now"><strong>{{ t('this documentation') }}</strong></a></p>
|
||||
<details>
|
||||
<summary>Reveal repair option</summary>
|
||||
<p>Below is the option to repair the integrity of your backup. <strong>Please note:</strong> Please only use this after you have read the documentation above! (It will run the command 'borg check --repair' for you.)</p>
|
||||
<form method="POST" action="api/docker/backup-check-repair" class="xhr">
|
||||
<summary>{{ t('Reveal repair option') }}</summary>
|
||||
<p>{{ t('Below is the option to repair the integrity of your backup.') }} <strong>{{ t('Please note:') }}</strong> {{ t('Please only use this after you have read the documentation above! (It will run the command \'borg check --repair\' for you.)') }}</p>
|
||||
{% set confirmRepair = t('Check and repair backup integrity? Are you sure that you want to check and repair the backup integrity? This should only be done after reading the mentioned documentation.') %}
|
||||
<form method="POST" action="api/docker/backup-check-repair" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Check and repair backup integrity" onclick="return confirm('Check and repair backup integrity? Are you sure that you want to check and repair the backup integrity? This should only be done after reading the mentioned documentation.')"/>
|
||||
<input type="submit" value="{{ t('Check and repair backup integrity') }}" onclick="return confirm('{{ confirmRepair|e('js') }}')"/>
|
||||
</form>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% if has_backup_run_once == false %}
|
||||
<p>The initial backup was not successful.</p>
|
||||
<p>{{ t('The initial backup was not successful.') }}</p>
|
||||
|
||||
{% if borg_remote_repo %}
|
||||
<p>
|
||||
You may still need to authorize this pubkey on your borg remote:<br><strong>{{ borg_public_key }}</strong><br>
|
||||
To try again, click <strong>Create backup</strong>.
|
||||
{{ t('You may still need to authorize this pubkey on your borg remote:') }}<br><strong>{{ borg_public_key }}</strong><br>
|
||||
{{ t('To try again, click') }} <strong>{{ t('Create backup') }}</strong>.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<p>You may change the backup path again since the initial backup was not successful. After submitting the new value, you need to click on <strong>Create Backup</strong> to test the new value.</p>
|
||||
<p>{{ t('You may change the backup path again since the initial backup was not successful. After submitting the new value, you need to click on') }} <strong>{{ t('Create Backup') }}</strong> {{ t('to test the new value.') }}</p>
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<label>Local backup location</label> <input type="text" name="borg_backup_host_location" placeholder="/mnt/backup"/><br>
|
||||
<label>Remote borg repo</label> <input type="text" name="borg_remote_repo" placeholder="ssh://user@host:port/path/to/repo"/><br>
|
||||
<label>{{ t('Local backup location') }}</label> <input type="text" name="borg_backup_host_location" placeholder="/mnt/backup"/><br>
|
||||
<label>{{ t('Remote borg repo') }}</label> <input type="text" name="borg_remote_repo" placeholder="ssh://user@host:port/path/to/repo"/><br>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Set backup location again" />
|
||||
<input type="submit" value="{{ t('Set backup location again') }}" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% elseif backup_exit_code == 0 %}
|
||||
{% if borg_backup_mode == "backup" %}
|
||||
<p><span class="status success"></span> Last {{ borg_backup_mode }} successful on {{ last_backup_time }} UTC! (<a href="api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank">Logs</a>)</p>
|
||||
<p><span class="status success"></span> {{ t('Last') }} {{ borg_backup_mode }} {{ t('successful on') }} {{ last_backup_time }} UTC! (<a href="log?id=nextcloud-aio-borgbackup" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
{% else %}
|
||||
<p><span class="status success"></span> Last {{ borg_backup_mode }} successful! (<a href="api/docker/logs?id=nextcloud-aio-borgbackup" target="_blank">Logs</a>)</p>
|
||||
<p><span class="status success"></span> {{ t('Last') }} {{ borg_backup_mode }} {{ t('successful!') }} (<a href="log?id=nextcloud-aio-borgbackup" target="_blank">{{ t('Logs') }}</a>)</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -445,54 +462,57 @@
|
||||
{% if is_backup_container_running == false and isApacheStarting == false %}
|
||||
{% if has_backup_run_once == true %}
|
||||
<details>
|
||||
<summary>Click here to reveal all backup options (including an option for automatic updates)</summary>
|
||||
<summary>{{ t('Click here to reveal all backup options (including an option for automatic updates)') }}</summary>
|
||||
{% endif %}
|
||||
<h3>Backup information</h3>
|
||||
<p>This is your encryption password for backups: <strong id="borg-backup-password">{{ borgbackup_password }}</strong></p>
|
||||
<p>Please save this password in a safe place. You won't be able to restore from backup if you lose this password!</p>
|
||||
<p>All important data from your Nextcloud AIO instance such as the database, your files and the mastercontainer's configuration files, will be backed up.</p>
|
||||
<p>The backup uses a tool called <a target="_blank" href="https://github.com/borgbackup/borg#what-is-borgbackup"><strong>BorgBackup</strong></a>, a well-known server backup tool that efficiently backs up your files and encrypts them on the fly.</p>
|
||||
<p>By using this tool, backups are incremental, differential, compressed and encrypted – so only the first backup will take a while. Further backups should be fast as only changes are taken into account.</p>
|
||||
<h3>{{ t('Backup information') }}</h3>
|
||||
<p>{{ t('This is your encryption password for backups:') }} <strong id="borg-backup-password">{{ borgbackup_password }}</strong></p>
|
||||
<p>{{ t('Please save this password in a safe place. You won\'t be able to restore from backup if you lose this password!') }}</p>
|
||||
<p>{{ t('All important data from your Nextcloud AIO instance such as the database, your files and the mastercontainer\'s configuration files, will be backed up.') }}</p>
|
||||
<p>{{ t('The backup uses a tool called') }} <a target="_blank" href="https://github.com/borgbackup/borg#what-is-borgbackup"><strong>BorgBackup</strong></a>, {{ t('a well-known server backup tool that efficiently backs up your files and encrypts them on the fly.') }}</p>
|
||||
<p>{{ t('By using this tool, backups are incremental, differential, compressed and encrypted – so only the first backup will take a while. Further backups should be fast as only changes are taken into account.') }}</p>
|
||||
{% if borg_remote_repo != '' %}
|
||||
<p>
|
||||
Backups get created remotely at:<br>
|
||||
{{ t('Backups get created remotely at:') }}<br>
|
||||
<strong>{{ borg_remote_repo }}</strong>
|
||||
{% if has_backup_run_once == true %}
|
||||
<br/>Your borg ssh public key is:<br><strong>{{ borg_public_key }}</strong>
|
||||
<br/>{{ t('Your borg ssh public key is:') }}<br><strong>{{ borg_public_key }}</strong>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% else %}
|
||||
<p>Backups will be created in the following directory on the host: <strong>{{ borg_backup_host_location }}/borg</strong></p>
|
||||
<p>{{ t('Backups will be created in the following directory on the host:') }} <strong>{{ borg_backup_host_location }}/borg</strong></p>
|
||||
{% endif %}
|
||||
<p>Be aware that this solution does not backup files and folders that are mounted into Nextcloud using the external storage app, but you can add further Docker volumes and host paths that you want to back up after the initial backup is done.</p>
|
||||
<p>For information about backup retention, see <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-adjust-borgs-retention-policy">this</a></strong>.</p>
|
||||
<p>Daily backups can be enabled after the initial backup is done. Enabling this also allows you to enable an option to update all containers, Nextcloud, and its apps automatically.</p>
|
||||
<p>For further documentation and options on this backup solution refer to <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one#backup">this section</a></strong> and below.</p>
|
||||
<p>{{ t('Be aware that this solution does not backup files and folders that are mounted into Nextcloud using the external storage app, but you can add further Docker volumes and host paths that you want to back up after the initial backup is done.') }}</p>
|
||||
<p>{{ t('For information about backup retention, see') }} <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-adjust-borgs-retention-policy">{{ t('this') }}</a></strong>.</p>
|
||||
<p>{{ t('Daily backups can be enabled after the initial backup is done. Enabling this also allows you to enable an option to update all containers, Nextcloud, and its apps automatically.') }}</p>
|
||||
<p>{{ t('For further documentation and options on this backup solution refer to') }} <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one#backup">{{ t('this section') }}</a></strong> {{ t('and below.') }}</p>
|
||||
|
||||
{% if isApacheStarting != true %}
|
||||
<h3>Backup creation</h3>
|
||||
<p>Clicking on the button below will create a backup.</p>
|
||||
<form method="POST" action="api/docker/backup" class="xhr">
|
||||
<h3>{{ t('Backup creation') }}</h3>
|
||||
<p>{{ t('Clicking on the button below will create a backup.') }}</p>
|
||||
{% set confirmBackup = t('Create backup? Are you sure that you want to create a backup? This will stop all running containers and create the backup.') %}
|
||||
<form method="POST" action="api/docker/backup" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Create backup" onclick="return confirm('Create backup? Are you sure that you want to create a backup? This will stop all running containers and create the backup.')" />
|
||||
<input type="submit" value="{{ t('Create backup') }}" onclick="return confirm('{{ confirmBackup|e('js') }}')" />
|
||||
</form>
|
||||
|
||||
{% if has_backup_run_once == true %}
|
||||
<h3>Backup Viewer</h3>
|
||||
<p>There is now a community container that allows to access your backups in a web session. See <a target="_blank" href="https://github.com/nextcloud/all-in-one/tree/main/community-containers/borgbackup-viewer"><strong>this documentation</strong></a>.</p>
|
||||
<h3>{{ t('Backup Viewer') }}</h3>
|
||||
<p>{{ t('There is now a community container that allows to access your backups in a web session. See') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one/tree/main/community-containers/borgbackup-viewer"><strong>{{ t('this documentation') }}</strong></a>.</p>
|
||||
|
||||
<h3>Backup check</h3>
|
||||
<p>Click on the button below to perform a backup integrity check. This is an option that verifies that your backup is intact. It shouldn't be needed in most situations.</p>
|
||||
<form method="POST" action="api/docker/backup-check" class="xhr">
|
||||
<h3>{{ t('Backup check') }}</h3>
|
||||
<p>{{ t('Click on the button below to perform a backup integrity check. This is an option that verifies that your backup is intact. It shouldn\'t be needed in most situations.') }}</p>
|
||||
{% set confirmCheck = t('Check backup integrity? Are you sure that you want to check the backup? This can take a long time depending on the size of your backup.') %}
|
||||
<form method="POST" action="api/docker/backup-check" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Check backup integrity" onclick="return confirm('Check backup integrity? Are you sure that you want to check the backup? This can take a long time depending on the size of your backup.')" />
|
||||
<input type="submit" value="{{ t('Check backup integrity') }}" onclick="return confirm('{{ confirmCheck|e('js') }}')" />
|
||||
</form>
|
||||
|
||||
<h3>Backup restore</h3>
|
||||
<p>Choose the backup that you want to restore and click on the button below to restore the selected backup. This will overwrite all your files with the chosen backup so you should consider creating a backup first. You can run an integrity check before restoring your files but this shouldn't be needed in most situations. Please note that this will not restore additionally chosen backup directories! The restore process should be pretty fast as rsync, which only transfers changed files, is used to restore the chosen backup.</p>
|
||||
<form method="POST" action="api/docker/restore" class="xhr" id="restore_selection">
|
||||
<h3>{{ t('Backup restore') }}</h3>
|
||||
<p>{{ t('Choose the backup that you want to restore and click on the button below to restore the selected backup. This will overwrite all your files with the chosen backup so you should consider creating a backup first. You can run an integrity check before restoring your files but this shouldn\'t be needed in most situations. Please note that this will not restore additionally chosen backup directories! The restore process should be pretty fast as rsync, which only transfers changed files, is used to restore the chosen backup.') }}</p>
|
||||
{% set confirmRestoreSelected = t('Restore the selected backup? Are you sure that you want to restore the selected backup? This will stop all running containers and restore the selected backup. It is recommended to create a backup first. You might also want to check the backup integrity.') %}
|
||||
<form method="POST" action="api/docker/restore" target="overlay-log" id="restore_selection">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<select id="selected_restore_time" name="selected_restore_time" form="restore_selection">
|
||||
@@ -500,74 +520,75 @@
|
||||
<option value="{{ restore_time }}">{{ restore_time }} UTC</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="submit" value="Restore selected backup" onclick="return confirm('Restore the selected backup? Are you sure that you want to restore the selected backup? This will stop all running containers and restore the selected backup. It is recommended to create a backup first. You might also want to check the backup integrity.')" />
|
||||
<input type="submit" value="{{ t('Restore selected backup') }}" onclick="return confirm('{{ confirmRestoreSelected|e('js') }}')" />
|
||||
</form>
|
||||
|
||||
<h3>Update backup list</h3>
|
||||
<h3>{{ t('Update backup list') }}</h3>
|
||||
<details>
|
||||
<summary>Click here to reveal this option</summary>
|
||||
<p>If you use an external snapshot tool to restore the server that runs AIO, you might run into a problem that the above listed available backups are not up-to-date to restore your server from. You can click the button below to update this list.</p>
|
||||
<form method="POST" action="api/docker/backup-list" class="xhr">
|
||||
<summary>{{ t('Click here to reveal this option') }}</summary>
|
||||
<p>{{ t('If you use an external snapshot tool to restore the server that runs AIO, you might run into a problem that the above listed available backups are not up-to-date to restore your server from. You can click the button below to update this list.') }}</p>
|
||||
<form method="POST" action="api/docker/backup-list" target="overlay-log">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Update backup list" />
|
||||
<input type="submit" value="{{ t('Update backup list') }}" />
|
||||
</form>
|
||||
</details>
|
||||
|
||||
<h3>Daily backup and automatic updates</h3>
|
||||
<h3>{{ t('Daily backup and automatic updates') }}</h3>
|
||||
{% if daily_backup_time == "" %}
|
||||
<p>By entering a time below and submitting it, you can enable daily backups. It will create them at the entered time in 24h format. E.g. <strong>04:00</strong> will create backups at 4 am UTC and <strong>16:00</strong> at 4 pm UTC. When creating the backup, containers will be stopped and restarted after the backup is complete.</p>
|
||||
<p>{{ t('By entering a time below and submitting it, you can enable daily backups. It will create them at the entered time in 24h format. E.g.') }} <strong>04:00</strong> {{ t('will create backups at 4 am UTC and') }} <strong>16:00</strong> {{ t('at 4 pm UTC. When creating the backup, containers will be stopped and restarted after the backup is complete.') }}</p>
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<input type="text" name="daily_backup_time" placeholder="04:00"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Submit daily backup time and settings" /><br>
|
||||
<input type="checkbox" id="automatic_updates" name="automatic_updates" checked="checked"><label for="automatic_updates">Automatically update all containers, the mastercontainer and on saturdays your Nextcloud apps</label><br>
|
||||
<input type="checkbox" id="success_notification" name="success_notification" checked="checked"><label for="success_notification">Send notifications about successful backups (notifications about unsuccessful backups will always be sent)</label>
|
||||
<input type="submit" value="{{ t('Submit daily backup time and settings') }}" /><br>
|
||||
<input type="checkbox" id="automatic_updates" name="automatic_updates" checked="checked"><label for="automatic_updates">{{ t('Automatically update all containers, the mastercontainer and on saturdays your Nextcloud apps') }}</label><br>
|
||||
<input type="checkbox" id="success_notification" name="success_notification" checked="checked"><label for="success_notification">{{ t('Send notifications about successful backups (notifications about unsuccessful backups will always be sent)') }}</label>
|
||||
</form>
|
||||
{% else %}
|
||||
<p>Daily backups will be created at <strong>{{ daily_backup_time }} UTC</strong>. A notification about the result of the backup will be sent.</p>
|
||||
<p>{{ t('Daily backups will be created at') }} <strong>{{ daily_backup_time }} UTC</strong>. {{ t('A notification about the result of the backup will be sent.') }}</p>
|
||||
{% if automatic_updates == true %}
|
||||
Also your containers, the mastercontainer and, on Saturdays, your Nextcloud apps will be automatically updated.
|
||||
{{ t('Also your containers, the mastercontainer and, on Saturdays, your Nextcloud apps will be automatically updated.') }}
|
||||
{% endif %}
|
||||
<p>To change your backup time first disable Daily Backups, then enter your new backup time, and then re-enable them.</p>
|
||||
<p>{{ t('To change your backup time first disable Daily Backups, then enter your new backup time, and then re-enable them.') }}</p>
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<input type="hidden" name="delete_daily_backup_time" value="yes"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Disable or change daily backup settings" />
|
||||
<input type="submit" value="{{ t('Disable or change daily backup settings') }}" />
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
<h3>Back up additional directories and docker volumes of your host</h3>
|
||||
<p>Below you can enter directories and docker volumes of your host that will be backed up into the same borg backup archive. Make sure to press the submit button after changing anything.</p>
|
||||
<h3>{{ t('Back up additional directories and docker volumes of your host') }}</h3>
|
||||
<p>{{ t('Below you can enter directories and docker volumes of your host that will be backed up into the same borg backup archive. Make sure to press the submit button after changing anything.') }}</p>
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<textarea id="additional_backup_directories" name="additional_backup_directories" rows="4" cols="50" placeholder="/directory/on/the/host my_custom_docker_volume">{{ additional_backup_directories }}</textarea>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Submit additional backup locations" />
|
||||
<input type="submit" value="{{ t('Submit additional backup locations') }}" />
|
||||
</form>
|
||||
<p>Each line and entry needs to start with a slash or letter/digit. Only <strong>a-z</strong>, <strong>A-Z</strong>, <strong>.</strong>, <strong>0-9</strong>, <strong>_</strong>, <strong>-</strong>, and <strong>/</strong> are allowed. If the entry begins with a letter/digit slashes are not supported. Two valid entries are <strong>/directory/on/the/host</strong> and <strong>my_custom_docker_volume</strong>. You need to make sure that all given directories exist or the backup container will fail to start!</p>
|
||||
<p>Be sure to individually specify all storage that you want to back up as storage will not be mounted recursively. E.g. providing <strong>/</strong> as additional backup directory will only back up files and folders that are stored on the root partition and not on the EFI partition or any other. Excluded by the backup will be caches and a few other directories. If you want to back up the root partition you should make sure to stop all services before the backup so it can run correctly. For automating this see <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-stopstartupdate-containers-or-trigger-the-daily-backup-from-a-script-externally">this documentation</a></p>
|
||||
<p>Please note that the chosen directories/volumes will not be restored when you restore your instance, so this would need to be done manually.</p>
|
||||
<p>{{ t('Each line and entry needs to start with a slash or letter/digit. Only') }} <strong>a-z</strong>, <strong>A-Z</strong>, <strong>.</strong>, <strong>0-9</strong>, <strong>_</strong>, <strong>-</strong>, {{ t('and') }} <strong>/</strong> {{ t('are allowed. If the entry begins with a letter/digit slashes are not supported. Two valid entries are') }} <strong>/directory/on/the/host</strong> {{ t('and') }} <strong>my_custom_docker_volume</strong>. {{ t('You need to make sure that all given directories exist or the backup container will fail to start!') }}</p>
|
||||
<p>{{ t('Be sure to individually specify all storage that you want to back up as storage will not be mounted recursively. E.g. providing') }} <strong>/</strong> {{ t('as additional backup directory will only back up files and folders that are stored on the root partition and not on the EFI partition or any other. Excluded by the backup will be caches and a few other directories. If you want to back up the root partition you should make sure to stop all services before the backup so it can run correctly. For automating this see') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-stopstartupdate-containers-or-trigger-the-daily-backup-from-a-script-externally">{{ t('this documentation') }}</a></p>
|
||||
<p>{{ t('Please note that the chosen directories/volumes will not be restored when you restore your instance, so this would need to be done manually.') }}</p>
|
||||
{% if additional_backup_directories != "" %}
|
||||
<p>This option is currently set. You can disable it again by clearing the field and submitting your changes.</p>
|
||||
<p>{{ t('This option is currently set. You can disable it again by clearing the field and submitting your changes.') }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<h3>Reset backup location</h3>
|
||||
<h3>{{ t('Reset backup location') }}</h3>
|
||||
<p>
|
||||
If the configured backup host location <strong>{{ borg_backup_host_location }}</strong>
|
||||
{{ t('If the configured backup host location') }} <strong>{{ borg_backup_host_location }}</strong>
|
||||
{% if borg_remote_repo %}
|
||||
or the remote repo <strong>{{ borg_remote_repo }}</strong>
|
||||
{{ t('or the remote repo') }} <strong>{{ borg_remote_repo }}</strong>
|
||||
{% endif %}
|
||||
is wrong or if you want to reset the backup location due to other reasons, you can do so by clicking on the button below.
|
||||
{{ t('is wrong or if you want to reset the backup location due to other reasons, you can do so by clicking on the button below.') }}
|
||||
</p>
|
||||
{% set confirmResetLocation = t('Are you sure that you want to reset the backup location?') %}
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<input type="hidden" name="delete_borg_backup_location_vars" value="yes"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Reset backup location" onclick="return confirm('Are you sure that you want to reset the backup location?')" />
|
||||
<input type="submit" value="{{ t('Reset backup location') }}" onclick="return confirm('{{ confirmResetLocation|e('js') }}')" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if has_backup_run_once == true %}
|
||||
@@ -579,18 +600,18 @@
|
||||
|
||||
{% if is_backup_container_running == false %}
|
||||
{% if isApacheStarting == false %}
|
||||
<h2>AIO passphrase change</h2>
|
||||
<h2>{{ t('AIO passphrase change') }}</h2>
|
||||
<details>
|
||||
<summary>Click here to change your AIO passphrase</summary>
|
||||
<p>You can change your AIO passphrase below:</p>
|
||||
<summary>{{ t('Click here to change your AIO passphrase') }}</summary>
|
||||
<p>{{ t('You can change your AIO passphrase below:') }}</p>
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<input type="password" autocomplete="current-password" name="current-master-password" placeholder="Your current AIO passphrase" id="current-master-password" oninput="showPassword('current-master-password')">
|
||||
<input type="password" autocomplete="new-password" name="new-master-password" placeholder="Your new AIO passphrase" id="new-master-password" oninput="showPassword('new-master-password')">
|
||||
<input type="password" autocomplete="current-password" name="current-master-password" placeholder="{{ t('Your current AIO passphrase') }}" id="current-master-password" oninput="showPassword('current-master-password')">
|
||||
<input type="password" autocomplete="new-password" name="new-master-password" placeholder="{{ t('Your new AIO passphrase') }}" id="new-master-password" oninput="showPassword('new-master-password')">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Submit passphrase change" />
|
||||
<input type="submit" value="{{ t('Submit passphrase change') }}" />
|
||||
</form>
|
||||
<p>The new passphrase needs to be at least 24 characters long. Allowed characters are the <a target="_blank" href="https://en.wikipedia.org/wiki/Latin_alphabet#/media/File:Abecedarium.png"><strong>latin characters</strong></a> <strong>a-z</strong>, <strong>A-Z</strong>, <strong>0-9</strong> and <strong>spaces</strong>.</p>
|
||||
<p>{{ t('The new passphrase needs to be at least 24 characters long. Allowed characters are the') }} <a target="_blank" href="https://en.wikipedia.org/wiki/Latin_alphabet#/media/File:Abecedarium.png"><strong>{{ t('latin characters') }}</strong></a> <strong>a-z</strong>, <strong>A-Z</strong>, <strong>0-9</strong> {{ t('and spaces.') }}</p>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -599,30 +620,31 @@
|
||||
|
||||
{{ include('includes/optional-containers.twig') }}
|
||||
|
||||
<h2>Timezone change</h2>
|
||||
<h2>{{ t('Timezone change') }}</h2>
|
||||
{% if isAnyRunning == true %}
|
||||
{% if timezone != "" %}
|
||||
<p>The timezone for Nextcloud is currently set to <strong>{{ timezone }}</strong>.</p>
|
||||
<p>{{ t('The timezone for Nextcloud is currently set to') }} <strong>{{ timezone }}</strong>.</p>
|
||||
{% endif %}
|
||||
<p><strong>Please note:</strong> You can change the timezone when your containers are stopped.</p>
|
||||
<p><strong>{{ t('Please note:') }}</strong> {{ t('You can change the timezone when your containers are stopped.') }}</p>
|
||||
{% else %}
|
||||
{% if timezone == "" %}
|
||||
<p>To get the correct time values for certain Nextcloud features, set the timezone for Nextcloud to the one that your users mainly use. Please note that this setting does not apply to the mastercontainer and any backup option.</p>
|
||||
<p>You can configure the timezone for Nextcloud below (Do not forget to submit the value!):</p>
|
||||
<p>{{ t('To get the correct time values for certain Nextcloud features, set the timezone for Nextcloud to the one that your users mainly use. Please note that this setting does not apply to the mastercontainer and any backup option.') }}</p>
|
||||
<p>{{ t('You can configure the timezone for Nextcloud below (Do not forget to submit the value!):') }}</p>
|
||||
{% set confirmTimezone = t('Are you sure that this is a valid timezone? Please double check by following the wikipedia article and checking the correct column. If the timezone is not valid, it will break the startup since the database will not be correctly initialized and you will end up in a startup loop.') %}
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<input type="text" id="timezone" name="timezone" placeholder="Europe/Berlin" />
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Submit timezone" onclick="return confirm('Are you sure that this is a valid timezone? Please double check by following the wikipedia article and checking the correct column. If the timezone is not valid, it will break the startup since the database will not be correctly initialized and you will end up in a startup loop.')" />
|
||||
<input type="submit" value="{{ t('Submit timezone') }}" onclick="return confirm('{{ confirmTimezone|e('js') }}')" />
|
||||
</form>
|
||||
<p>You need to make sure that the timezone that you enter is valid. An example is <strong>Europe/Berlin</strong>. You can get valid values by looking at the 'TZ identifier' column of this list: <a target="_blank" href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List"><strong>click here</strong></a>. The default is <strong>Etc/UTC</strong> if nothing is entered.</p>
|
||||
<p>{{ t('You need to make sure that the timezone that you enter is valid. An example is') }} <strong>Europe/Berlin</strong>. {{ t('You can get valid values by looking at the \'TZ identifier\' column of this list:') }} <a target="_blank" href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List"><strong>{{ t('click here') }}</strong></a>. {{ t('The default is') }} <strong>Etc/UTC</strong> {{ t('if nothing is entered.') }}</p>
|
||||
{% else %}
|
||||
<p>The timezone for Nextcloud is currently set to <strong>{{ timezone }}</strong>. You can change the timezone by clicking on the button below.</p>
|
||||
<p>{{ t('The timezone for Nextcloud is currently set to') }} <strong>{{ timezone }}</strong>. {{ t('You can change the timezone by clicking on the button below.') }}</p>
|
||||
<form method="POST" action="api/configuration" class="xhr">
|
||||
<input type="hidden" name="delete_timezone" value="yes"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" value="Reset the timezone" />
|
||||
<input type="submit" value="{{ t('Reset the timezone') }}" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
<details>
|
||||
<summary>Click here to view the current AIO config and documentation links</summary>
|
||||
<summary>{{ t('Click here to view the current AIO config and documentation links') }}</summary>
|
||||
{% if was_start_button_clicked == true %}
|
||||
<p>Nextcloud's config.php file is stored in the nextcloud_aio_nextcloud Docker volume and can be edited by following the <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-edit-nextclouds-configphp-file-with-a-texteditor">config.php documentation</a>.</p>
|
||||
<p>You can run Nextcloud's usual occ commands by following the <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-run-occ-commands">occ documentation</a></strong>.</p>
|
||||
<p>{{ t('Nextcloud\'s config.php file is stored in the nextcloud_aio_nextcloud Docker volume and can be edited by following the') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-edit-nextclouds-configphp-file-with-a-texteditor">{{ t('config.php documentation') }}</a>.</p>
|
||||
<p>{{ t('You can run Nextcloud\'s usual occ commands by following the') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-run-occ-commands">{{ t('occ documentation') }}</a>.</p>
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
{% if nextcloud_datadir starts with '/' %}
|
||||
Nextcloud's datadir is getting stored in the {{ nextcloud_datadir }} directory.
|
||||
{{ t('Nextcloud\'s datadir is getting stored in the') }} {{ nextcloud_datadir }} {{ t('directory.') }}
|
||||
{% else %}
|
||||
Nextcloud's datadir is getting stored in the {{ nextcloud_datadir }} Docker volume.
|
||||
{{ t('Nextcloud\'s datadir is getting stored in the') }} {{ nextcloud_datadir }} {{ t('Docker volume.') }}
|
||||
{% endif %}
|
||||
See the <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir">NEXTCLOUD_DATADIR documentation</a> on how to change this.
|
||||
{{ t('See the') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir">{{ t('NEXTCLOUD_DATADIR documentation') }}</a> {{ t('on how to change this.') }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{% if nextcloud_mount == '' %}
|
||||
The Nextcloud container is confined and local external storage in Nextcloud is disabled.
|
||||
{{ t('The Nextcloud container is confined and local external storage in Nextcloud is disabled.') }}
|
||||
{% else %}
|
||||
The Nextcloud container is getting access to the {{ nextcloud_mount }} directory and local external storage in Nextcloud is enabled.
|
||||
{{ t('The Nextcloud container is getting access to the') }} {{ nextcloud_mount }} {{ t('directory and local external storage in Nextcloud is enabled.') }}
|
||||
{% endif %}
|
||||
See the <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host">NEXTCLOUD_MOUNT documentation</a> on how to change this.</p>
|
||||
{{ t('See the') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host">{{ t('NEXTCLOUD_MOUNT documentation') }}</a> {{ t('on how to change this.') }}</p>
|
||||
|
||||
<p>Nextcloud has an upload limit of {{ nextcloud_upload_limit }} configured (for public link uploads. Bigger uploads are always possible when users are logged in). See the <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-upload-limit-for-nextcloud">NEXTCLOUD_UPLOAD_LIMIT documentation</a> on how to change this.</p>
|
||||
<p>{{ t('Nextcloud has an upload limit of') }} {{ nextcloud_upload_limit }} {{ t('configured (for public link uploads. Bigger uploads are always possible when users are logged in). See the') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-upload-limit-for-nextcloud">{{ t('NEXTCLOUD_UPLOAD_LIMIT documentation') }}</a> {{ t('on how to change this.') }}</p>
|
||||
|
||||
<p>For Nextcloud, a memory limit of {{ nextcloud_memory_limit }} per PHP process is configured. See the <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-php-memory-limit-for-nextcloud">NEXTCLOUD_MEMORY_LIMIT documentation</a> on how to change this.</p>
|
||||
<p>{{ t('For Nextcloud, a memory limit of') }} {{ nextcloud_memory_limit }} {{ t('per PHP process is configured. See the') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-php-memory-limit-for-nextcloud">{{ t('NEXTCLOUD_MEMORY_LIMIT documentation') }}</a> {{ t('on how to change this.') }}</p>
|
||||
|
||||
<p>Nextcloud has a timeout of {{ nextcloud_max_time }} seconds configured (important for big file uploads). See the <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-max-execution-time-for-nextcloud">NEXTCLOUD_MAX_TIME documentation</a> on how to change this.</p>
|
||||
<p>{{ t('Nextcloud has a timeout of') }} {{ nextcloud_max_time }} {{ t('seconds configured (important for big file uploads). See the') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-adjust-the-max-execution-time-for-nextcloud">{{ t('NEXTCLOUD_MAX_TIME documentation') }}</a> {{ t('on how to change this.') }}</p>
|
||||
|
||||
<p>
|
||||
{% if is_dri_device_enabled == true and is_nvidia_gpu_enabled == true %}
|
||||
Hardware acceleration is enabled with the /dev/dri device and the Nvidia runtime.
|
||||
{{ t('Hardware acceleration is enabled with the /dev/dri device and the Nvidia runtime.') }}
|
||||
{% elseif is_dri_device_enabled == true %}
|
||||
Hardware acceleration is enabled with the /dev/dri device.
|
||||
{{ t('Hardware acceleration is enabled with the /dev/dri device.') }}
|
||||
{% elseif is_nvidia_gpu_enabled == true %}
|
||||
Hardware acceleration is enabled with the Nvidia runtime.
|
||||
{{ t('Hardware acceleration is enabled with the Nvidia runtime.') }}
|
||||
{% else %}
|
||||
Hardware acceleration is not enabled. It's recommended to enable hardware transcoding for better performance.
|
||||
{{ t('Hardware acceleration is not enabled. It\'s recommended to enable hardware transcoding for better performance.') }}
|
||||
{% endif %}
|
||||
See the <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-enable-hardware-acceleration-for-nextcloud">hardware acceleration documentation</a> on how to change this.</p>
|
||||
{{ t('See the') }} <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-enable-hardware-acceleration-for-nextcloud">{{ t('hardware acceleration documentation') }}</a> {{ t('on how to change this.') }}</p>
|
||||
|
||||
<p>For further documentation on AIO, refer to <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one#nextcloud-all-in-one">this page</a></strong>. You can use the browser search [CTRL]+[F] to search through the documentation. Additional documentation can be found <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/categories/wiki">here</a></strong>.</p>
|
||||
</details>
|
||||
<p>{{ t('For further documentation on AIO, refer to') }} <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one#nextcloud-all-in-one">{{ t('this page') }}</a></strong>. {{ t('You can use the browser search [CTRL]+[F] to search through the documentation. Additional documentation can be found') }} <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/categories/wiki">{{ t('here') }}</a></strong>.</p>
|
||||
</details>
|
||||
@@ -1 +1 @@
|
||||
12.7.0
|
||||
12.9.0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user