mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-05-21 19:00:33 +00:00
Compare commits
143 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9b13a7786 | ||
|
|
37b33c7f4b | ||
|
|
1f819e403b | ||
|
|
e3826f85b9 | ||
|
|
3e5ab69512 | ||
|
|
7d6695de7e | ||
|
|
06dd83f07a | ||
|
|
cd055c0838 | ||
|
|
1e3bb9ccfe | ||
|
|
7144eb84ff | ||
|
|
def87f38e8 | ||
|
|
0a63b49504 | ||
|
|
e672a5029b | ||
|
|
e22c6d6cef | ||
|
|
2290c0aede | ||
|
|
e448bc1f64 | ||
|
|
fb898b0ab3 | ||
|
|
9cb2801e0f | ||
|
|
d7a528075a | ||
|
|
9c80cc1bb3 | ||
|
|
8d93da24d6 | ||
|
|
faaa59e29a | ||
|
|
3b1014d34d | ||
|
|
3e9b191f94 | ||
|
|
b95bb65af8 | ||
|
|
b72a1c0e59 | ||
|
|
8c7e0bc63a | ||
|
|
f5e8e5630d | ||
|
|
89ff6ea408 | ||
|
|
814f4942f5 | ||
|
|
0941b6dee0 | ||
|
|
ae36403762 | ||
|
|
30eaaaa5f9 | ||
|
|
92a96ca245 | ||
|
|
59a49c62b4 | ||
|
|
0b9108f566 | ||
|
|
7c04f844a1 | ||
|
|
c2056ec215 | ||
|
|
8032f5b966 | ||
|
|
c79d46b868 | ||
|
|
1e7161d524 | ||
|
|
3eede90e86 | ||
|
|
33c822fd1e | ||
|
|
32935d1c33 | ||
|
|
72ca611d2f | ||
|
|
6c6c56fa1b | ||
|
|
6aa0b7097a | ||
|
|
89caf9d725 | ||
|
|
90ba2f7e92 | ||
|
|
55f4a8ec7f | ||
|
|
5f130528ce | ||
|
|
9cffb5a6ee | ||
|
|
164f7026b0 | ||
|
|
a89358ead8 | ||
|
|
31bba7ab80 | ||
|
|
7d49155fc1 | ||
|
|
9dfe5ab770 | ||
|
|
87e018b55f | ||
|
|
fa916c95a7 | ||
|
|
dbef6f1d4a | ||
|
|
fe83acd3cc | ||
|
|
3a0ad6a66f | ||
|
|
1976223efb | ||
|
|
9ff9a7901c | ||
|
|
9c6425308f | ||
|
|
52c926e052 | ||
|
|
1854417c28 | ||
|
|
9cc4393e99 | ||
|
|
cfa207916e | ||
|
|
7586ecefad | ||
|
|
12e30fe316 | ||
|
|
4c50b606bc | ||
|
|
38bd04ded9 | ||
|
|
95ba20d7f9 | ||
|
|
ff042fc742 | ||
|
|
8fedcb4810 | ||
|
|
9a85799220 | ||
|
|
7fc95050d4 | ||
|
|
666064389b | ||
|
|
7c333037fc | ||
|
|
955692a874 | ||
|
|
f2b26d262f | ||
|
|
c46b81da93 | ||
|
|
be0bad4740 | ||
|
|
f40f4a54b6 | ||
|
|
1b86445b6a | ||
|
|
7bcd0c16c0 | ||
|
|
68ac85e60b | ||
|
|
8ce9bd2cc2 | ||
|
|
ea098a4d1a | ||
|
|
b5e45e270b | ||
|
|
1fc8f2dd0f | ||
|
|
8317b30658 | ||
|
|
1a62857df7 | ||
|
|
172ae49cdf | ||
|
|
d385d43af0 | ||
|
|
064ea0f931 | ||
|
|
7f645b1c1a | ||
|
|
38726f039a | ||
|
|
79fdbee6b4 | ||
|
|
4c304d8775 | ||
|
|
8a21f2a8f5 | ||
|
|
1be6c725c2 | ||
|
|
c6d40e91e0 | ||
|
|
4fc4ca1e3e | ||
|
|
31f86c1570 | ||
|
|
a8d380ec7a | ||
|
|
6dd88239d1 | ||
|
|
ead69baae3 | ||
|
|
6be1154914 | ||
|
|
f9772a856c | ||
|
|
83ae27ef76 | ||
|
|
e60949aec9 | ||
|
|
817df30465 | ||
|
|
07ad9a7eb8 | ||
|
|
9c96806084 | ||
|
|
0e1edde3a7 | ||
|
|
8661bdf020 | ||
|
|
c3579476c6 | ||
|
|
ae349b8afb | ||
|
|
20bf2cfa7e | ||
|
|
0cbffeb90a | ||
|
|
8983a97ef6 | ||
|
|
0670c7cedf | ||
|
|
cd00e5af83 | ||
|
|
2c7146b15f | ||
|
|
975f4220d4 | ||
|
|
6beaa3b391 | ||
|
|
6b3cba411e | ||
|
|
ab747de69d | ||
|
|
480b57178b | ||
|
|
c9650aa0ef | ||
|
|
0e660f4c04 | ||
|
|
6722dee1d6 | ||
|
|
79af222c2d | ||
|
|
79473fac76 | ||
|
|
9b11c817b2 | ||
|
|
fb05818764 | ||
|
|
15a289e820 | ||
|
|
d5868a9626 | ||
|
|
22d3b0ba30 | ||
|
|
2b98a936b9 | ||
|
|
3263184e8f |
32
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: 🐛 Bug report
|
||||
about: Help us improving by reporting a bug
|
||||
labels: bug, 0. Needs triage
|
||||
---
|
||||
|
||||
<!--- Please keep this note for other contributors -->
|
||||
### How to use GitHub
|
||||
|
||||
* Please use the 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to show that you are affected by the same issue.
|
||||
* Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
|
||||
* Subscribe to receive notifications on status change and new comments.
|
||||
|
||||
<!--- Please fill out the whole template below -->
|
||||
### Steps to reproduce
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Expected behaviour <!--- Tell us what should happen -->
|
||||
|
||||
### Actual behaviour <!--- Tell us what happens instead -->
|
||||
|
||||
|
||||
### Host OS <!--- (the host OS on which you are trying to install AIO on) -->
|
||||
|
||||
|
||||
#### Nextcloud AIO version <!--- (see Nextcloud AIO interface) -->
|
||||
|
||||
#### Current channel <!--- (see the channel name in the Mastercontainer section) -->
|
||||
|
||||
#### Other valuable info <!--- (like logs, screenshots & Co.) -->
|
||||
24
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: 📖 Existing feature/documentation enhancement
|
||||
about: Suggest an enhancement of an existing feature/documentation - for other types, please use the feature request option below
|
||||
labels: enhancement, 0. Needs triage
|
||||
---
|
||||
|
||||
<!--- Please keep this note for other contributors -->
|
||||
### How to use GitHub
|
||||
* Please use the 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to show that you are interested into the same feature.
|
||||
* Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
|
||||
* Subscribe to receive notifications on status change and new comments.
|
||||
|
||||
<!--- Please fill out the whole template below -->
|
||||
### Is your feature request related to a problem? Please describe.
|
||||
<!--- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||
|
||||
### Describe the solution you'd like
|
||||
<!--- A clear and concise description of what you want to happen. -->
|
||||
|
||||
### Describe alternatives you've considered
|
||||
<!--- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
### Additional context
|
||||
<!--- Add any other context or screenshots about the feature request below. -->
|
||||
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💡 Suggest a new feature or discuss one
|
||||
url: https://github.com/nextcloud/all-in-one/discussions
|
||||
about: For new feature requests and discussion of existing ones
|
||||
- name: ❓ Community Support and Help
|
||||
url: https://help.nextcloud.com/tag/aio
|
||||
about: For other types of questions
|
||||
- name: 💼 Nextcloud Enterprise
|
||||
url: https://portal.nextcloud.com/
|
||||
about: If you are a Nextcloud Enterprise customer, or need Professional support, so it can be resolved directly by our dedicated engineers more quickly
|
||||
25
.github/dependabot.yml
vendored
25
.github/dependabot.yml
vendored
@@ -1,9 +1,14 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
- package-ecosystem: composer
|
||||
directory: "/php/"
|
||||
schedule:
|
||||
interval: daily
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
@@ -108,3 +113,21 @@ updates:
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/clamav"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/onlyoffice"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
|
||||
16
.github/workflows/dependency-updates.yml
vendored
16
.github/workflows/dependency-updates.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
name: Run dependency update script
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: nanasess/setup-php@master
|
||||
with:
|
||||
php-version: '8.0'
|
||||
@@ -31,8 +31,20 @@ jobs:
|
||||
done
|
||||
echo "outdated dependencies:
|
||||
$(composer outdated)"
|
||||
- name: Update apcu
|
||||
run: |
|
||||
# APCU
|
||||
apcu_version="$(
|
||||
git ls-remote --tags https://github.com/krakjoe/apcu.git \
|
||||
| cut -d/ -f3 \
|
||||
| grep -vE -- '-rc|-b' \
|
||||
| sed -E 's/^v//' \
|
||||
| sort -V \
|
||||
| tail -1
|
||||
)"
|
||||
sed -i "s|pecl install APCu.*\;|pecl install APCu-$apcu_version\;|" ./Containers/mastercontainer/Dockerfile
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
commit-message: dependency updates
|
||||
signoff: true
|
||||
|
||||
20
.github/workflows/lock-threads.yml
vendored
Normal file
20
.github/workflows/lock-threads.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: 'Lock Threads'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
concurrency:
|
||||
group: lock
|
||||
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
issue-inactive-days: '14'
|
||||
process-only: 'issues'
|
||||
4
.github/workflows/nextcloud-update.yml
vendored
4
.github/workflows/nextcloud-update.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
name: Run nextcloud-update script
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run nextcloud-update script
|
||||
run: |
|
||||
# Inspired by https://github.com/nextcloud/docker/blob/master/update.sh
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
sed -i "s|^ENV NEXTCLOUD_VERSION.*|ENV NEXTCLOUD_VERSION $NCVERSION|" ./Containers/nextcloud/Dockerfile
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
commit-message: nextcloud-update automated change
|
||||
signoff: true
|
||||
|
||||
2
.github/workflows/psalm-analysis.yml
vendored
2
.github/workflows/psalm-analysis.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Psalm
|
||||
uses: docker://ghcr.io/nextcloud/all-in-one-psalm
|
||||
with:
|
||||
|
||||
2
.github/workflows/psalm-security.yml
vendored
2
.github/workflows/psalm-security.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Psalm
|
||||
uses: docker://ghcr.io/nextcloud/all-in-one-psalm
|
||||
with:
|
||||
|
||||
4
.github/workflows/psalm-update-baseline.yml
vendored
4
.github/workflows/psalm-update-baseline.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up php8.0
|
||||
uses: shivammathur/setup-php@v2
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
commit-message: Update psalm baseline
|
||||
|
||||
2
.github/workflows/shellcheck.yml
vendored
2
.github/workflows/shellcheck.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
name: Github Actions
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run Shellcheck
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
with:
|
||||
|
||||
2
.github/workflows/spellcheck.yml
vendored
2
.github/workflows/spellcheck.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: spelling or typos
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: misspell
|
||||
uses: reviewdog/action-misspell@v1
|
||||
with:
|
||||
|
||||
@@ -31,6 +31,14 @@
|
||||
reverse_proxy {$COLLABORA_HOST}:9980
|
||||
}
|
||||
|
||||
# Onlyoffice
|
||||
route /onlyoffice/* {
|
||||
uri strip_prefix /onlyoffice
|
||||
reverse_proxy {$ONLYOFFICE_HOST}:80 {
|
||||
header_up X-Forwarded-Host {http.request.host}/onlyoffice
|
||||
}
|
||||
}
|
||||
|
||||
# Nextcloud
|
||||
route {
|
||||
rewrite /.well-known/carddav /remote.php/dav
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
FROM debian:bullseye-20220228-slim
|
||||
# Caddy is a requirement
|
||||
FROM caddy:2.4.6-alpine as caddy
|
||||
|
||||
FROM debian:bullseye-20220328-slim
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
@@ -21,10 +24,8 @@ RUN set -ex; \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN set -ex; \
|
||||
wget "https://caddyserver.com/api/download?os=linux&arch=$(dpkg-architecture --query DEB_BUILD_ARCH)" -O "/usr/bin/caddy" \
|
||||
&& chmod +x /usr/bin/caddy \
|
||||
&& /usr/bin/caddy version
|
||||
COPY --from=caddy /usr/bin/caddy /usr/bin/
|
||||
RUN chmod +x /usr/bin/caddy
|
||||
|
||||
RUN a2enmod rewrite \
|
||||
headers \
|
||||
|
||||
@@ -17,12 +17,6 @@ while ! nc -z "$NEXTCLOUD_HOST" 9000; do
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Only start container if collabora is started
|
||||
while ! nc -z "$COLLABORA_HOST" 9980; do
|
||||
echo "Waiting for Collabora to start..."
|
||||
sleep 5
|
||||
done
|
||||
|
||||
if [ -z "$APACHE_PORT" ]; then
|
||||
export APACHE_PORT="443"
|
||||
fi
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:bullseye-20220125-slim
|
||||
FROM debian:bullseye-20220328-slim
|
||||
|
||||
RUN set -ex; \
|
||||
\
|
||||
@@ -8,6 +8,7 @@ RUN set -ex; \
|
||||
rsync \
|
||||
fuse \
|
||||
python3-llfuse \
|
||||
jq \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ if ! mountpoint -q /mnt/borgbackup; then
|
||||
fi
|
||||
|
||||
# Check if target is empty
|
||||
if [ "$BORG_MODE" != backup ] && ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != test ] && ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||
echo "The repository is empty. cannot perform check or restore."
|
||||
exit 1
|
||||
fi
|
||||
@@ -173,17 +173,46 @@ if [ "$BORG_MODE" = restore ]; then
|
||||
echo "Could not mount the backup!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Restore everything except the configuration file
|
||||
if ! rsync --stats --archive --human-readable -vv --delete \
|
||||
--exclude "nextcloud_aio_mastercontainer/session/"** \
|
||||
--exclude "nextcloud_aio_mastercontainer/certs/"** \
|
||||
--exclude "nextcloud_aio_mastercontainer/data/configuration.json" \
|
||||
/tmp/borg/nextcloud_aio_volumes/ /nextcloud_aio_volumes; then
|
||||
echo "Something failed while restoring the boot partition."
|
||||
echo "Something failed while restoring from backup."
|
||||
umount /tmp/borg
|
||||
exit 1
|
||||
fi
|
||||
umount /tmp/borg
|
||||
|
||||
# TODO: reset fetchtimes in configuration.json so that it doesn't get the latest directly...
|
||||
# Save current aio password
|
||||
AIO_PASSWORD="$(jq '.password' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
|
||||
# Save current path
|
||||
BORG_LOCATION="$(jq '.borg_backup_host_location' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
|
||||
# Restore the configuration file
|
||||
if ! rsync --archive --human-readable -vv \
|
||||
/tmp/borg/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json \
|
||||
/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json; then
|
||||
echo "Something failed while restoring the configuration.json."
|
||||
umount /tmp/borg
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set backup-mode to restore since it was a restore
|
||||
CONTENTS="$(jq '."backup-mode" = "restore"' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
|
||||
|
||||
# Reset the backup path to the currently used one
|
||||
CONTENTS="$(jq ".borg_backup_host_location = $BORG_LOCATION" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
|
||||
|
||||
# Reset the AIO password to the currently used one
|
||||
CONTENTS="$(jq ".password = $AIO_PASSWORD" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
|
||||
echo -E "${CONTENTS}" > /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
|
||||
|
||||
umount /tmp/borg
|
||||
|
||||
# Inform user
|
||||
get_expiration_time
|
||||
@@ -192,17 +221,12 @@ if [ "$BORG_MODE" = restore ]; then
|
||||
# Add file to Nextcloud container so that it skips any update the next time
|
||||
touch "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/skip.update"
|
||||
chmod 777 "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/skip.update"
|
||||
|
||||
# Set backup-mode to restore since it was a restore
|
||||
sed -i 's/"backup-mode":"[a-z]\+"/"backup-mode":"restore"/g' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Do the Backup check
|
||||
if [ "$BORG_MODE" = check ]; then
|
||||
get_start_time
|
||||
echo "Checking the backup integity..."
|
||||
echo "Checking the backup integrity..."
|
||||
|
||||
# Perform the check
|
||||
if ! borg check --verify-data --progress "$BORG_BACKUP_DIRECTORY"; then
|
||||
@@ -215,3 +239,23 @@ if [ "$BORG_MODE" = check ]; then
|
||||
echo "Check finished successfully on $END_DATE_READABLE ($DURATION_READABLE)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Do the backup test
|
||||
if [ "$BORG_MODE" = test ]; then
|
||||
if ! [ -d "$BORG_BACKUP_DIRECTORY" ]; then
|
||||
echo "No 'borg' directory in the given backup directory found!"
|
||||
echo "Please adjust the directory so that the borg archive is positioned in a folder named 'borg' inside the given directory!"
|
||||
exit 1
|
||||
elif ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||
echo "A 'borg' directory was found but could not find the borg archive."
|
||||
echo "It must be positioned directly in the 'borg' subfolder."
|
||||
exit 1
|
||||
elif ! borg list "$BORG_BACKUP_DIRECTORY"; then
|
||||
echo "The entered path seems to be valid but could not open the backup archive."
|
||||
echo "Most likely the entered password was wrong so please adjust it accordingly!"
|
||||
exit 1
|
||||
else
|
||||
echo "Everything looks fine so feel free to continue!"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -4,19 +4,23 @@
|
||||
export BORG_BACKUP_DIRECTORY="/mnt/borgbackup/borg"
|
||||
|
||||
# Validate BORG_PASSWORD
|
||||
if [ -z "$BORG_PASSWORD" ]; then
|
||||
echo "BORG_PASSWORD is not allowed to be empty."
|
||||
if [ -z "$BORG_PASSWORD" ] && [ -z "$BACKUP_RESTORE_PASSWORD" ]; then
|
||||
echo "Neither BORG_PASSWORD nor BACKUP_RESTORE_PASSWORD are set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Export defaults
|
||||
export BORG_PASSPHRASE="$BORG_PASSWORD"
|
||||
# Export defaults
|
||||
if [ -n "$BACKUP_RESTORE_PASSWORD" ]; then
|
||||
export BORG_PASSPHRASE="$BACKUP_RESTORE_PASSWORD"
|
||||
else
|
||||
export BORG_PASSPHRASE="$BORG_PASSWORD"
|
||||
fi
|
||||
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
|
||||
export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes
|
||||
|
||||
# Validate BORG_MODE
|
||||
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != restore ] && [ "$BORG_MODE" != check ]; then
|
||||
echo "No correct BORG_MODE mode applied. Valid are 'backup' and 'restore'."
|
||||
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != restore ] && [ "$BORG_MODE" != check ] && [ "$BORG_MODE" != test ]; then
|
||||
echo "No correct BORG_MODE mode applied. Valid are 'backup', 'check', 'restore' and 'test'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
5
Containers/clamav/Dockerfile
Normal file
5
Containers/clamav/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
# Probably from this file: https://github.com/Cisco-Talos/clamav/blob/main/Dockerfile
|
||||
FROM clamav/clamav:0.104.2-2
|
||||
|
||||
COPY clamav.conf /tmp/
|
||||
RUN cat /tmp/clamav.conf >> /etc/clamav/clamd.conf
|
||||
4
Containers/clamav/clamav.conf
Normal file
4
Containers/clamav/clamav.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
MaxDirectoryRecursion 30
|
||||
MaxFileSize 100M
|
||||
PCREMaxFileSize 100M
|
||||
StreamMaxLength 100M
|
||||
@@ -1,2 +1,2 @@
|
||||
# From a file located probably somewhere here: https://github.com/CollaboraOnline/online/tree/master/docker
|
||||
FROM collabora/code:21.11.2.4.1
|
||||
FROM collabora/code:21.11.3.4.1
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.15.0
|
||||
FROM alpine:3.15.3
|
||||
RUN apk add --update --no-cache lighttpd bash
|
||||
|
||||
RUN adduser -S www-data -G www-data
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# Docker CLI is a requirement
|
||||
FROM docker:20.10.12-dind-alpine3.15 as dind
|
||||
FROM docker:20.10.14-dind-alpine3.15 as dind
|
||||
|
||||
# Caddy is a requirement
|
||||
FROM caddy:2.4.6-alpine as caddy
|
||||
|
||||
# From https://github.com/docker-library/php/blob/master/8.0/bullseye/apache/Dockerfile
|
||||
FROM php:8.0.16-apache-bullseye
|
||||
FROM php:8.0.17-apache-bullseye
|
||||
|
||||
EXPOSE 80
|
||||
EXPOSE 8080
|
||||
@@ -26,17 +29,15 @@ RUN apt-get update; \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN set -ex; \
|
||||
curl "https://caddyserver.com/api/download?os=linux&arch=$(dpkg-architecture --query DEB_BUILD_ARCH)" -o "/usr/bin/caddy" \
|
||||
&& chmod +x /usr/bin/caddy \
|
||||
&& /usr/bin/caddy version
|
||||
COPY --from=caddy /usr/bin/caddy /usr/bin/
|
||||
RUN chmod +x /usr/bin/caddy
|
||||
|
||||
COPY --from=dind /usr/local/bin/docker /usr/local/bin/
|
||||
RUN chmod +x /usr/local/bin/docker
|
||||
|
||||
RUN mkdir -p /usr/src/php/ext/apcu && \
|
||||
curl -fsSL https://pecl.php.net/get/apcu | tar xvz -C "/usr/src/php/ext/apcu" --strip 1 && \
|
||||
docker-php-ext-install apcu
|
||||
RUN set -ex; \
|
||||
pecl install APCu-5.1.21; \
|
||||
docker-php-ext-enable apcu
|
||||
|
||||
RUN set -e && \
|
||||
curl -sS https://getcomposer.org/installer | php && \
|
||||
|
||||
@@ -43,7 +43,7 @@ elif ! sudo -u www-data test -r /var/run/docker.sock; then
|
||||
fi
|
||||
|
||||
# Check if api version is supported
|
||||
if ! docker info &>/dev/null; then
|
||||
if ! sudo -u www-data docker info &>/dev/null; then
|
||||
echo "Cannot connect to the docker socket. Cannot proceed."
|
||||
exit 1
|
||||
fi
|
||||
@@ -51,7 +51,7 @@ API_VERSION_FILE="$(find ./ -name DockerActionManager.php | head -1)"
|
||||
API_VERSION="$(grep -oP 'const API_VERSION.*\;' "$API_VERSION_FILE" | grep -oP '[0-9]+.[0-9]+' | head -1)"
|
||||
# shellcheck disable=SC2001
|
||||
API_VERSION_NUMB="$(echo "$API_VERSION" | sed 's/\.//')"
|
||||
LOCAL_API_VERSION_NUMB="$(docker version | grep -i "api version" | grep -oP '[0-9]+.[0-9]+' | head -1 | sed 's/\.//')"
|
||||
LOCAL_API_VERSION_NUMB="$(sudo -u www-data docker version | grep -i "api version" | grep -oP '[0-9]+.[0-9]+' | head -1 | sed 's/\.//')"
|
||||
if [ -n "$LOCAL_API_VERSION_NUMB" ] && [ -n "$API_VERSION_NUMB" ]; then
|
||||
if ! [ "$LOCAL_API_VERSION_NUMB" -ge "$API_VERSION_NUMB" ]; then
|
||||
echo "Docker v$API_VERSION is not supported by your docker engine. Cannot proceed."
|
||||
@@ -63,10 +63,10 @@ else
|
||||
fi
|
||||
|
||||
# Check if startup command was executed correctly
|
||||
if ! docker ps | grep -q "nextcloud-aio-mastercontainer"; then
|
||||
if ! sudo -u www-data docker ps | grep -q "nextcloud-aio-mastercontainer"; then
|
||||
echo "It seems like you did not give the mastercontainer the correct name?"
|
||||
exit 1
|
||||
elif ! docker volume ls | grep -q "nextcloud_aio_mastercontainer"; then
|
||||
elif ! sudo -u www-data docker volume ls | grep -q "nextcloud_aio_mastercontainer"; then
|
||||
echo "It seems like you did not give the mastercontainer volume the correct name?"
|
||||
exit 1
|
||||
fi
|
||||
@@ -74,24 +74,26 @@ fi
|
||||
# Check for other options
|
||||
if [ -n "$NEXTCLOUD_DATADIR" ]; then
|
||||
if ! echo "$NEXTCLOUD_DATADIR" | grep -q "^/mnt/" \
|
||||
&& ! echo "$NEXTCLOUD_DATADIR" | grep -q "^/media/"
|
||||
&& ! echo "$NEXTCLOUD_DATADIR" | grep -q "^/media/" \
|
||||
&& ! echo "$NEXTCLOUD_DATADIR" | grep -q "^/host_mnt/"
|
||||
then
|
||||
echo "You've set NEXTCLOUD_DATADIR but not to an allowed value.
|
||||
The string must start with '/mnt/' or '/media/'. E.g. '/mnt/ncdata'"
|
||||
The string must start with '/mnt/', '/media/' or '/host_mnt/'. E.g. '/mnt/ncdata'"
|
||||
exit 1
|
||||
elif [ "$NEXTCLOUD_DATADIR" = "/mnt/" ] || [ "$NEXTCLOUD_DATADIR" = "/media/" ]; then
|
||||
elif [ "$NEXTCLOUD_DATADIR" = "/mnt/" ] || [ "$NEXTCLOUD_DATADIR" = "/media/" ] || [ "$NEXTCLOUD_DATADIR" = "/host_mnt/" ]; then
|
||||
echo "You've set NEXTCLOUD_DATADIR but not to an allowed value.
|
||||
The string must start with '/mnt/' or '/media/' and not be equal to these."
|
||||
The string must start with '/mnt/', '/media/' or '/host_mnt/' and not be equal to these."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -n "$NEXTCLOUD_MOUNT" ]; then
|
||||
if ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/mnt/" \
|
||||
&& ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/media/" \
|
||||
&& ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/host_mnt/" \
|
||||
&& ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/var/backups$"
|
||||
then
|
||||
echo "You've set NEXCLOUD_MOUNT but not to an allowed value.
|
||||
The string must be equal to/start with '/mnt/' or '/media/' or be equal to '/var/backups'."
|
||||
The string must be equal to/start with '/mnt/', '/media/' or '/host_mnt/' or be equal to '/var/backups'."
|
||||
exit 1
|
||||
elif [ "$NEXTCLOUD_MOUNT" = "/mnt/ncdata" ] || echo "$NEXTCLOUD_MOUNT" | grep -q "^/mnt/ncdata/"; then
|
||||
echo "/mnt/ncdata and /mnt/ncdata/ are not allowed for NEXTCLOUD_MOUNT."
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# From https://github.com/nextcloud/docker/blob/master/23/fpm-alpine/Dockerfile
|
||||
FROM php:8.0.16-fpm-alpine3.15
|
||||
FROM php:8.0.17-fpm-alpine3.15
|
||||
|
||||
# Custom: change id of www-data user as it needs to be the same like on old installations
|
||||
RUN set -ex; \
|
||||
@@ -105,7 +105,7 @@ RUN { \
|
||||
VOLUME /var/www/html
|
||||
|
||||
|
||||
ENV NEXTCLOUD_VERSION 23.0.2
|
||||
ENV NEXTCLOUD_VERSION 23.0.3
|
||||
|
||||
RUN set -ex; \
|
||||
apk add --no-cache --virtual .fetch-deps \
|
||||
|
||||
@@ -251,6 +251,13 @@ php /var/www/html/occ config:system:set overwrite.cli.url --value="https://$NC_D
|
||||
php /var/www/html/occ config:system:set htaccess.RewriteBase --value="/"
|
||||
php /var/www/html/occ maintenance:update:htaccess
|
||||
|
||||
# Disallow creating local external storages when nothing was mounted
|
||||
if [ -z "$NEXTCLOUD_MOUNT" ]; then
|
||||
php /var/www/html/occ config:system:set files_external_allow_create_new_local --type=bool --value=false
|
||||
else
|
||||
php /var/www/html/occ config:system:set files_external_allow_create_new_local --type=bool --value=true
|
||||
fi
|
||||
|
||||
# AIO app
|
||||
if [ "$(php /var/www/html/occ config:app:get nextcloud-aio enabled)" = "" ]; then
|
||||
php /var/www/html/occ app:enable nextcloud-aio
|
||||
@@ -270,32 +277,91 @@ php /var/www/html/occ config:system:set trusted_proxies 0 --value="127.0.0.1"
|
||||
php /var/www/html/occ config:app:set notify_push base_endpoint --value="https://$NC_DOMAIN/push"
|
||||
|
||||
# Collabora
|
||||
if ! [ -d "/var/www/html/custom_apps/richdocuments" ]; then
|
||||
php /var/www/html/occ app:install richdocuments
|
||||
elif [ "$(php /var/www/html/occ config:app:get richdocuments enabled)" = "no" ]; then
|
||||
php /var/www/html/occ app:enable richdocuments
|
||||
if [ "$COLLABORA_ENABLED" = 'yes' ]; then
|
||||
if ! [ -d "/var/www/html/custom_apps/richdocuments" ]; then
|
||||
php /var/www/html/occ app:install richdocuments
|
||||
elif [ "$(php /var/www/html/occ config:app:get richdocuments enabled)" = "no" ]; then
|
||||
php /var/www/html/occ app:enable richdocuments
|
||||
else
|
||||
php /var/www/html/occ app:update richdocuments
|
||||
fi
|
||||
php /var/www/html/occ config:app:set richdocuments wopi_url --value="https://$NC_DOMAIN/"
|
||||
php /var/www/html/occ config:app:set richdocuments public_wopi_url --value="https://$NC_DOMAIN/"
|
||||
# php /var/www/html/occ richdocuments:activate-config
|
||||
# Fix https://github.com/nextcloud/all-in-one/issues/188:
|
||||
php /var/www/html/occ config:system:set allow_local_remote_servers --type=bool --value=true
|
||||
else
|
||||
php /var/www/html/occ app:update richdocuments
|
||||
if [ -d "/var/www/html/custom_apps/richdocuments" ]; then
|
||||
php /var/www/html/occ config:system:delete allow_local_remote_servers
|
||||
php /var/www/html/occ app:remove richdocuments
|
||||
fi
|
||||
fi
|
||||
|
||||
# OnlyOffice
|
||||
if [ "$ONLYOFFICE_ENABLED" = 'yes' ]; then
|
||||
while ! nc -z "$ONLYOFFICE_HOST" 80; do
|
||||
echo "waiting for OnlyOffice to become available..."
|
||||
sleep 5
|
||||
done
|
||||
if ! [ -d "/var/www/html/custom_apps/onlyoffice" ]; then
|
||||
php /var/www/html/occ app:install onlyoffice
|
||||
elif [ "$(php /var/www/html/occ config:app:get onlyoffice enabled)" = "no" ]; then
|
||||
php /var/www/html/occ app:enable onlyoffice
|
||||
else
|
||||
php /var/www/html/occ app:update onlyoffice
|
||||
fi
|
||||
php /var/www/html/occ config:app:set onlyoffice DocumentServerUrl --value="https://$NC_DOMAIN/onlyoffice"
|
||||
else
|
||||
if [ -d "/var/www/html/custom_apps/onlyoffice" ]; then
|
||||
php /var/www/html/occ app:remove onlyoffice
|
||||
fi
|
||||
fi
|
||||
php /var/www/html/occ config:app:set richdocuments wopi_url --value="https://$NC_DOMAIN/"
|
||||
# php /var/www/html/occ richdocuments:activate-config
|
||||
# Fix https://github.com/nextcloud/all-in-one/issues/188:
|
||||
php /var/www/html/occ config:system:set allow_local_remote_servers --type=bool --value=true
|
||||
|
||||
# Talk
|
||||
if ! [ -d "/var/www/html/custom_apps/spreed" ]; then
|
||||
php /var/www/html/occ app:install spreed
|
||||
elif [ "$(php /var/www/html/occ config:app:get spreed enabled)" = "no" ]; then
|
||||
php /var/www/html/occ app:enable spreed
|
||||
if [ "$TALK_ENABLED" = 'yes' ]; then
|
||||
if ! [ -d "/var/www/html/custom_apps/spreed" ]; then
|
||||
php /var/www/html/occ app:install spreed
|
||||
elif [ "$(php /var/www/html/occ config:app:get spreed enabled)" = "no" ]; then
|
||||
php /var/www/html/occ app:enable spreed
|
||||
else
|
||||
php /var/www/html/occ app:update spreed
|
||||
fi
|
||||
STUN_SERVERS="[\"$NC_DOMAIN:3478\"]"
|
||||
TURN_SERVERS="[{\"server\":\"$NC_DOMAIN:3478\",\"secret\":\"$TURN_SECRET\",\"protocols\":\"udp,tcp\"}]"
|
||||
SIGNALING_SERVERS="{\"servers\":[{\"server\":\"https://$NC_DOMAIN/standalone-signaling/\",\"verify\":true}],\"secret\":\"$SIGNALING_SECRET\"}"
|
||||
php /var/www/html/occ config:app:set spreed stun_servers --value="$STUN_SERVERS" --output json
|
||||
php /var/www/html/occ config:app:set spreed turn_servers --value="$TURN_SERVERS" --output json
|
||||
php /var/www/html/occ config:app:set spreed signaling_servers --value="$SIGNALING_SERVERS" --output json
|
||||
else
|
||||
php /var/www/html/occ app:update spreed
|
||||
if [ -d "/var/www/html/custom_apps/spreed" ]; then
|
||||
php /var/www/html/occ app:remove spreed
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clamav
|
||||
if [ "$CLAMAV_ENABLED" = 'yes' ]; then
|
||||
while ! nc -z "$CLAMAV_HOST" 3310; do
|
||||
echo "waiting for clamav to become available..."
|
||||
sleep 5
|
||||
done
|
||||
if ! [ -d "/var/www/html/custom_apps/files_antivirus" ]; then
|
||||
php /var/www/html/occ app:install files_antivirus
|
||||
elif [ "$(php /var/www/html/occ config:app:get files_antivirus enabled)" = "no" ]; then
|
||||
php /var/www/html/occ app:enable files_antivirus
|
||||
else
|
||||
php /var/www/html/occ app:update files_antivirus
|
||||
fi
|
||||
php /var/www/html/occ config:app:set files_antivirus av_mode --value="daemon"
|
||||
php /var/www/html/occ config:app:set files_antivirus av_port --value="3310"
|
||||
php /var/www/html/occ config:app:set files_antivirus av_host --value="$CLAMAV_HOST"
|
||||
php /var/www/html/occ config:app:set files_antivirus av_stream_max_length --value="104857600"
|
||||
php /var/www/html/occ config:app:set files_antivirus av_max_file_size --value="-1"
|
||||
php /var/www/html/occ config:app:set files_antivirus av_infected_action --value="only_log"
|
||||
else
|
||||
if [ -d "/var/www/html/custom_apps/files_antivirus" ]; then
|
||||
php /var/www/html/occ app:remove files_antivirus
|
||||
fi
|
||||
fi
|
||||
STUN_SERVERS="[\"$NC_DOMAIN:3478\"]"
|
||||
TURN_SERVERS="[{\"server\":\"$NC_DOMAIN:3478\",\"secret\":\"$TURN_SECRET\",\"protocols\":\"udp,tcp\"}]"
|
||||
SIGNALING_SERVERS="{\"servers\":[{\"server\":\"https://$NC_DOMAIN/standalone-signaling/\",\"verify\":true}],\"secret\":\"$SIGNALING_SECRET\"}"
|
||||
php /var/www/html/occ config:app:set spreed stun_servers --value="$STUN_SERVERS" --output json
|
||||
php /var/www/html/occ config:app:set spreed turn_servers --value="$TURN_SERVERS" --output json
|
||||
php /var/www/html/occ config:app:set spreed signaling_servers --value="$SIGNALING_SERVERS" --output json
|
||||
|
||||
# Remove the update skip file always
|
||||
rm -f /mnt/ncdata/skip.update
|
||||
|
||||
2
Containers/onlyoffice/Dockerfile
Normal file
2
Containers/onlyoffice/Dockerfile
Normal file
@@ -0,0 +1,2 @@
|
||||
# From https://github.com/ONLYOFFICE/Docker-DocumentServer/blob/master/Dockerfile
|
||||
FROM onlyoffice/documentserver:7.0.1.37
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:focal-20220302
|
||||
FROM ubuntu:focal-20220316
|
||||
|
||||
EXPOSE 3478
|
||||
|
||||
@@ -49,12 +49,16 @@ RUN chmod +x /usr/bin/start.sh; \
|
||||
sed -i '/TURNSERVER_ENABLED/c\TURNSERVER_ENABLED=1' /etc/default/coturn; \
|
||||
mkdir -p /var/tmp;
|
||||
|
||||
RUN curl -sL -o "/usr/share/janus/lua/json.lua" "https://raw.githubusercontent.com/rxi/json.lua/master/json.lua"; \
|
||||
curl -sL -o "/usr/share/janus/lua/ansicolors.lua" "https://raw.githubusercontent.com/kikito/ansicolors.lua/master/ansicolors.lua"
|
||||
|
||||
RUN mkdir -p /etc/nats; \
|
||||
echo "listen: 127.0.0.1:4222" > /etc/nats/nats.conf; \
|
||||
chown talk:talk /etc; \
|
||||
chown talk:talk -R /etc/nats; \
|
||||
chown talk:talk -R /etc/janus; \
|
||||
chown talk:talk -R /etc/signaling; \
|
||||
chown talk:talk -R /usr/share/janus
|
||||
chown talk:talk -R /usr
|
||||
|
||||
# Give root a random password
|
||||
RUN echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||
|
||||
@@ -19,6 +19,7 @@ fi
|
||||
cat << TURN_CONF > "/etc/turnserver.conf"
|
||||
listening-port=3478
|
||||
fingerprint
|
||||
lt-cred-mech
|
||||
use-auth-secret
|
||||
static-auth-secret=$TURN_SECRET
|
||||
realm=$NC_DOMAIN
|
||||
@@ -31,33 +32,51 @@ pidfile=/var/tmp/turnserver.pid
|
||||
TURN_CONF
|
||||
|
||||
# Janus
|
||||
sed -i "s|#turn_rest_api_key.*|turn_rest_api_key = $JANUS_API_KEY|" /etc/janus/janus.jcfg
|
||||
sed -i "s|#full_trickle|full_trickle|g" /etc/janus/janus.jcfg
|
||||
set -x
|
||||
sed -i "s|#turn_rest_api_key.*|turn_rest_api_key = \"$JANUS_API_KEY\"|" /etc/janus/janus.jcfg
|
||||
sed -i "s|#full_trickle.*|full_trickle = true|g" /etc/janus/janus.jcfg
|
||||
sed -i 's|#stun_server.*|stun_server = "127.0.0.1"|g' /etc/janus/janus.jcfg
|
||||
sed -i "s|#stun_port.*|stun_port = 3478|g" /etc/janus/janus.jcfg
|
||||
sed -i "s|#turn_port.*|turn_port = 3478|g" /etc/janus/janus.jcfg
|
||||
sed -i 's|#turn_server.*|turn_server = "127.0.0.1"|g'/etc/janus/janus.jcfg
|
||||
sed -i 's|#turn_type .*|turn_type = "udp"|g' /etc/janus/janus.jcfg
|
||||
sed -i 's|#ice_ignore_list .*|ice_ignore_list = "udp"|g' /etc/janus/janus.jcfg
|
||||
sed -i 's|#interface.*|interface = "lo"|g' /etc/janus/janus.transport.websockets.jcfg
|
||||
sed -i 's|#ws_interface.*|ws_interface = "lo"|g' /etc/janus/janus.transport.websockets.jcfg
|
||||
set +x
|
||||
|
||||
# Signling
|
||||
cat << SIGNALING_CONF > "/etc/signaling/server.conf"
|
||||
[http]
|
||||
listen = 0.0.0.0:8081
|
||||
|
||||
[app]
|
||||
debug = false
|
||||
|
||||
[sessions]
|
||||
hashkey = $(openssl rand -hex 16)
|
||||
blockkey = $(openssl rand -hex 16)
|
||||
|
||||
[clients]
|
||||
internalsecret = $(openssl rand -hex 16)
|
||||
|
||||
[backend]
|
||||
allowed = ${NC_DOMAIN}
|
||||
backends = backend-1
|
||||
allowall = false
|
||||
secret = ${SIGNALING_SECRET}
|
||||
timeout = 10
|
||||
connectionsperhost = 8
|
||||
|
||||
[backend-1]
|
||||
url = https://${NC_DOMAIN}
|
||||
secret = ${SIGNALING_SECRET}
|
||||
|
||||
[nats]
|
||||
url = nats://127.0.0.1:4222
|
||||
|
||||
[mcu]
|
||||
type = janus
|
||||
url = ws://127.0.0.1:8188
|
||||
|
||||
[turn]
|
||||
apikey = ${JANUS_API_KEY}
|
||||
secret = ${TURN_SECRET}
|
||||
|
||||
@@ -27,7 +27,7 @@ stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
command=janus
|
||||
command=/usr/bin/janus --config=/etc/janus/janus.jcfg --disable-colors --daemon --log-stdout
|
||||
|
||||
[program:signaling]
|
||||
stdout_logfile=/dev/stdout
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# From https://github.com/containrrr/watchtower/blob/main/dockerfiles/Dockerfile.self-contained
|
||||
FROM containrrr/watchtower:1.4.0 as watchtower
|
||||
|
||||
FROM alpine:3.15.0
|
||||
FROM alpine:3.15.3
|
||||
|
||||
RUN apk add --update --no-cache bash
|
||||
COPY --from=watchtower /watchtower /
|
||||
|
||||
62
php/composer.lock
generated
62
php/composer.lock
generated
@@ -8,16 +8,16 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "7.4.1",
|
||||
"version": "7.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle.git",
|
||||
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79"
|
||||
"reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee0a041b1760e6a53d2a39c8c34115adc2af2c79",
|
||||
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/ac1ec1cd9b5624694c3a40be801d94137afb12b4",
|
||||
"reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -112,7 +112,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.4.1"
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.4.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -128,7 +128,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-12-06T18:43:05+00:00"
|
||||
"time": "2022-03-20T14:16:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
@@ -216,16 +216,16 @@
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "2.1.0",
|
||||
"version": "2.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72"
|
||||
"reference": "c94a94f120803a18554c1805ef2e539f8285f9a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/089edd38f5b8abba6cb01567c2a8aaa47cec4c72",
|
||||
"reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/c94a94f120803a18554c1805ef2e539f8285f9a2",
|
||||
"reference": "c94a94f120803a18554c1805ef2e539f8285f9a2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -249,7 +249,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
"dev-master": "2.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -311,7 +311,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/psr7/issues",
|
||||
"source": "https://github.com/guzzle/psr7/tree/2.1.0"
|
||||
"source": "https://github.com/guzzle/psr7/tree/2.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -327,7 +327,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-10-06T17:43:30+00:00"
|
||||
"time": "2022-03-20T21:55:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "http-interop/http-factory-guzzle",
|
||||
@@ -1192,22 +1192,22 @@
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "4.9.0",
|
||||
"version": "4.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slimphp/Slim.git",
|
||||
"reference": "44d3c9c0bfcc47e52e42b097b6062689d21b904b"
|
||||
"reference": "0dfc7d2fdf2553b361d864d51af3fe8a6ad168b0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/44d3c9c0bfcc47e52e42b097b6062689d21b904b",
|
||||
"reference": "44d3c9c0bfcc47e52e42b097b6062689d21b904b",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/0dfc7d2fdf2553b361d864d51af3fe8a6ad168b0",
|
||||
"reference": "0dfc7d2fdf2553b361d864d51af3fe8a6ad168b0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"nikic/fast-route": "^1.3",
|
||||
"php": "^7.3 || ^8.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"psr/container": "^1.0 || ^2.0",
|
||||
"psr/http-factory": "^1.0",
|
||||
"psr/http-message": "^1.0",
|
||||
@@ -1218,13 +1218,15 @@
|
||||
"require-dev": {
|
||||
"adriansuter/php-autoload-override": "^1.2",
|
||||
"ext-simplexml": "*",
|
||||
"guzzlehttp/psr7": "^2.0",
|
||||
"guzzlehttp/psr7": "^2.1",
|
||||
"httpsoft/http-message": "^1.0",
|
||||
"httpsoft/http-server-request": "^1.0",
|
||||
"laminas/laminas-diactoros": "^2.8",
|
||||
"nyholm/psr7": "^1.4",
|
||||
"nyholm/psr7": "^1.5",
|
||||
"nyholm/psr7-server": "^1.0",
|
||||
"phpspec/prophecy": "^1.14",
|
||||
"phpspec/prophecy": "^1.15",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpstan/phpstan": "^0.12.99",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"slim/http": "^1.2",
|
||||
"slim/psr7": "^1.5",
|
||||
@@ -1301,7 +1303,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-10-05T03:00:00+00:00"
|
||||
"time": "2022-03-14T14:18:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slim/twig-view",
|
||||
@@ -1681,16 +1683,16 @@
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.3.8",
|
||||
"version": "v3.3.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "972d8604a92b7054828b539f2febb0211dd5945c"
|
||||
"reference": "6ff9b0e440fa66f97f207e181c41340ddfa5683d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/972d8604a92b7054828b539f2febb0211dd5945c",
|
||||
"reference": "972d8604a92b7054828b539f2febb0211dd5945c",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/6ff9b0e440fa66f97f207e181c41340ddfa5683d",
|
||||
"reference": "6ff9b0e440fa66f97f207e181c41340ddfa5683d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1741,7 +1743,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.3.8"
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.3.9"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1753,7 +1755,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-02-04T06:59:48+00:00"
|
||||
"time": "2022-03-25T09:37:52+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
@@ -1770,5 +1772,5 @@
|
||||
"ext-apcu": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.2.0"
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
"production": [
|
||||
{
|
||||
"dependsOn": [
|
||||
"nextcloud-aio-nextcloud",
|
||||
"nextcloud-aio-onlyoffice",
|
||||
"nextcloud-aio-collabora",
|
||||
"nextcloud-aio-talk"
|
||||
"nextcloud-aio-clamav",
|
||||
"nextcloud-aio-talk",
|
||||
"nextcloud-aio-nextcloud"
|
||||
],
|
||||
"identifier": "nextcloud-aio-apache",
|
||||
"displayName": "Apache",
|
||||
@@ -21,7 +23,8 @@
|
||||
"NEXTCLOUD_HOST=nextcloud-aio-nextcloud",
|
||||
"COLLABORA_HOST=nextcloud-aio-collabora",
|
||||
"TALK_HOST=nextcloud-aio-talk",
|
||||
"APACHE_PORT=%APACHE_PORT%"
|
||||
"APACHE_PORT=%APACHE_PORT%",
|
||||
"ONLYOFFICE_HOST=nextcloud-aio-onlyoffice"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -122,7 +125,14 @@
|
||||
"OVERWRITEPROTOCOL=https",
|
||||
"TURN_SECRET=%TURN_SECRET%",
|
||||
"SIGNALING_SECRET=%SIGNALING_SECRET%",
|
||||
"AIO_URL=%AIO_URL%"
|
||||
"AIO_URL=%AIO_URL%",
|
||||
"NEXTCLOUD_MOUNT=%NEXTCLOUD_MOUNT%",
|
||||
"CLAMAV_ENABLED=%CLAMAV_ENABLED%",
|
||||
"CLAMAV_HOST=nextcloud-aio-clamav",
|
||||
"ONLYOFFICE_ENABLED=%ONLYOFFICE_ENABLED%",
|
||||
"COLLABORA_ENABLED=%COLLABORA_ENABLED%",
|
||||
"TALK_ENABLED=%TALK_ENABLED%",
|
||||
"ONLYOFFICE_HOST=nextcloud-aio-onlyoffice"
|
||||
],
|
||||
"maxShutdownTime": 10,
|
||||
"restartPolicy": "unless-stopped"
|
||||
@@ -201,7 +211,8 @@
|
||||
"environmentVariables": [
|
||||
"BORG_PASSWORD=%BORGBACKUP_PASSWORD%",
|
||||
"BORG_MODE=%BORGBACKUP_MODE%",
|
||||
"SELECTED_RESTORE_TIME=%SELECTED_RESTORE_TIME%"
|
||||
"SELECTED_RESTORE_TIME=%SELECTED_RESTORE_TIME%",
|
||||
"BACKUP_RESTORE_PASSWORD=%BACKUP_RESTORE_PASSWORD%"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -291,6 +302,48 @@
|
||||
],
|
||||
"maxShutdownTime": 1,
|
||||
"restartPolicy": ""
|
||||
},
|
||||
{
|
||||
"dependsOn": [],
|
||||
"identifier": "nextcloud-aio-clamav",
|
||||
"displayName": "ClamAV",
|
||||
"containerName": "nextcloud/aio-clamav",
|
||||
"ports": [],
|
||||
"internalPorts": [
|
||||
"3310"
|
||||
],
|
||||
"environmentVariables": [],
|
||||
"volumes": [
|
||||
{
|
||||
"name": "nextcloud_aio_clamav",
|
||||
"location": "/var/lib/clamav",
|
||||
"writeable": true
|
||||
}
|
||||
],
|
||||
"secrets": [],
|
||||
"maxShutdownTime": 10,
|
||||
"restartPolicy": "unless-stopped"
|
||||
},
|
||||
{
|
||||
"dependsOn": [],
|
||||
"identifier": "nextcloud-aio-onlyoffice",
|
||||
"displayName": "OnlyOffice",
|
||||
"containerName": "nextcloud/aio-onlyoffice",
|
||||
"ports": [],
|
||||
"internalPorts": [
|
||||
"80"
|
||||
],
|
||||
"environmentVariables": [],
|
||||
"volumes": [
|
||||
{
|
||||
"name": "nextcloud_aio_onlyoffice",
|
||||
"location": "/var/lib/onlyoffice",
|
||||
"writeable": true
|
||||
}
|
||||
],
|
||||
"secrets": [],
|
||||
"maxShutdownTime": 10,
|
||||
"restartPolicy": "unless-stopped"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,21 +18,10 @@
|
||||
<MissingParamType occurrences="1">
|
||||
<code>$args</code>
|
||||
</MissingParamType>
|
||||
<PossiblyInvalidArrayAccess occurrences="2">
|
||||
<code>$request->getParsedBody()['borg_backup_host_location']</code>
|
||||
<code>$request->getParsedBody()['domain']</code>
|
||||
</PossiblyInvalidArrayAccess>
|
||||
<PossiblyNullArgument occurrences="2">
|
||||
<code>$request->getParsedBody()['borg_backup_host_location']</code>
|
||||
<code>$request->getParsedBody()['domain']</code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullArrayAccess occurrences="2">
|
||||
<code>$request->getParsedBody()['borg_backup_host_location']</code>
|
||||
<code>$request->getParsedBody()['domain']</code>
|
||||
</PossiblyNullArrayAccess>
|
||||
</file>
|
||||
<file src="src/Controller/DockerController.php">
|
||||
<MissingParamType occurrences="7">
|
||||
<MissingParamType occurrences="8">
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
@@ -44,19 +33,9 @@
|
||||
<PossiblyInvalidArrayAccess occurrences="1">
|
||||
<code>$request->getParsedBody()['selected_restore_time']</code>
|
||||
</PossiblyInvalidArrayAccess>
|
||||
<PossiblyNullArgument occurrences="1">
|
||||
<code>$container</code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullArrayAccess occurrences="1">
|
||||
<code>$request->getParsedBody()['selected_restore_time']</code>
|
||||
</PossiblyNullArrayAccess>
|
||||
<PossiblyNullReference occurrences="5">
|
||||
<code>GetDependsOn</code>
|
||||
<code>GetDependsOn</code>
|
||||
<code>GetIdentifier</code>
|
||||
<code>GetIdentifier</code>
|
||||
<code>GetRunningState</code>
|
||||
</PossiblyNullReference>
|
||||
</file>
|
||||
<file src="src/Controller/LoginController.php">
|
||||
<MissingParamType occurrences="3">
|
||||
@@ -74,12 +53,6 @@
|
||||
<code>$request->getParsedBody()['password']</code>
|
||||
</PossiblyNullArrayAccess>
|
||||
</file>
|
||||
<file src="src/Cron/cron.php">
|
||||
<PossiblyNullArgument occurrences="2">
|
||||
<code>$nextcloudContainer</code>
|
||||
<code>$nextcloudContainer</code>
|
||||
</PossiblyNullArgument>
|
||||
</file>
|
||||
<file src="src/Docker/DockerActionManager.php">
|
||||
<InvalidReturnType occurrences="1">
|
||||
<code>IContainerState</code>
|
||||
@@ -90,12 +63,6 @@
|
||||
<PossiblyFalseOperand occurrences="1">
|
||||
<code>strpos($fullDigest, "@")</code>
|
||||
</PossiblyFalseOperand>
|
||||
<PossiblyNullArgument occurrences="1">
|
||||
<code>$apacheContainer</code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullReference occurrences="1">
|
||||
<code>GetUpdateState</code>
|
||||
</PossiblyNullReference>
|
||||
<RedundantCondition occurrences="1">
|
||||
<code>$container->GetInternalPorts() !== null</code>
|
||||
</RedundantCondition>
|
||||
|
||||
17
php/public/automatic_reload.js
Normal file
17
php/public/automatic_reload.js
Normal file
@@ -0,0 +1,17 @@
|
||||
if (document.hasFocus()) {
|
||||
// hide reload button if the site reloads automatically
|
||||
var list = document.getElementsByClassName("reload button");
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
// list[i] is a node with the desired class name
|
||||
list[i].style.display = 'none';
|
||||
}
|
||||
|
||||
// set timeout for reload
|
||||
setTimeout(function(){
|
||||
window.location.reload(1);
|
||||
}, 5000);
|
||||
} else {
|
||||
window.addEventListener("beforeunload", function() {
|
||||
document.getElementById('overlay').classList.add('loading')
|
||||
});
|
||||
}
|
||||
3
php/public/before-unload.js
Normal file
3
php/public/before-unload.js
Normal file
@@ -0,0 +1,3 @@
|
||||
window.addEventListener("beforeunload", function() {
|
||||
document.getElementById('overlay').classList.add('loading')
|
||||
});
|
||||
5
php/public/disable-clamav.js
Normal file
5
php/public/disable-clamav.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Clamav
|
||||
var clamav = document.getElementById("clamav");
|
||||
clamav.disabled = true;
|
||||
});
|
||||
5
php/public/disable-collabora.js
Normal file
5
php/public/disable-collabora.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Collabora
|
||||
var collabora = document.getElementById("collabora");
|
||||
collabora.disabled = true;
|
||||
});
|
||||
5
php/public/disable-onlyoffice.js
Normal file
5
php/public/disable-onlyoffice.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// OnlyOffice
|
||||
var onlyoffice = document.getElementById("onlyoffice");
|
||||
onlyoffice.disabled = true;
|
||||
});
|
||||
5
php/public/disable-talk.js
Normal file
5
php/public/disable-talk.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Talk
|
||||
var talk = document.getElementById("talk");
|
||||
talk.disabled = true;
|
||||
});
|
||||
@@ -48,9 +48,11 @@ $app->add(new \AIO\Middleware\AuthMiddleware($container->get(\AIO\Auth\AuthManag
|
||||
|
||||
// API
|
||||
$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');
|
||||
$app->post('/api/docker/backup', AIO\Controller\DockerController::class . ':StartBackupContainerBackup');
|
||||
$app->post('/api/docker/backup-check', AIO\Controller\DockerController::class . ':StartBackupContainerCheck');
|
||||
$app->post('/api/docker/backup-test', AIO\Controller\DockerController::class . ':StartBackupContainerTest');
|
||||
$app->post('/api/docker/restore', AIO\Controller\DockerController::class . ':StartBackupContainerRestore');
|
||||
$app->post('/api/docker/stop', AIO\Controller\DockerController::class . ':StopContainer');
|
||||
$app->get('/api/docker/logs', AIO\Controller\DockerController::class . ':GetLogs');
|
||||
@@ -72,18 +74,25 @@ $app->get('/containers', function ($request, $response, $args) use ($container)
|
||||
return $view->render($response, 'containers.twig', [
|
||||
'domain' => $configurationManager->GetDomain(),
|
||||
'borg_backup_host_location' => $configurationManager->GetBorgBackupHostLocation(),
|
||||
'borg_backup_mode' => $configurationManager->GetBorgBackupMode(),
|
||||
'nextcloud_password' => $configurationManager->GetSecret('NEXTCLOUD_PASSWORD'),
|
||||
'containers' => (new \AIO\ContainerDefinitionFetcher($container->get(\AIO\Data\ConfigurationManager::class), $container))->FetchDefinition(),
|
||||
'borgbackup_password' => $configurationManager->GetSecret('BORGBACKUP_PASSWORD'),
|
||||
'is_mastercontainer_update_available' => $dockerActionManger->IsMastercontainerUpdateAvailable(),
|
||||
'has_backup_run_once' => $configurationManager->hasBackupRunOnce(),
|
||||
'is_backup_container_running' => $dockerActionManger->isBackupContainerRunning(),
|
||||
'backup_exit_code' => $dockerActionManger->GetBackupcontainerExitCode(),
|
||||
'borg_backup_mode' => $configurationManager->GetBorgBackupMode(),
|
||||
'was_start_button_clicked' => $configurationManager->wasStartButtonClicked(),
|
||||
'has_update_available' => $dockerActionManger->isAnyUpdateAvailable(),
|
||||
'last_backup_time' => $configurationManager->GetLastBackupTime(),
|
||||
'backup_times' => $configurationManager->GetBackupTimes(),
|
||||
'current_channel' => $dockerActionManger->GetCurrentChannel(),
|
||||
'is_x64_platform' => $configurationManager->isx64Platform(),
|
||||
'is_clamav_enabled' => $configurationManager->isClamavEnabled(),
|
||||
'is_onlyoffice_enabled' => $configurationManager->isOnlyofficeEnabled(),
|
||||
'is_collabora_enabled' => $configurationManager->isCollaboraEnabled(),
|
||||
'is_talk_enabled' => $configurationManager->isTalkEnabled(),
|
||||
'borg_restore_password' => $configurationManager->GetBorgRestorePassword(),
|
||||
]);
|
||||
})->setName('profile');
|
||||
$app->get('/login', function ($request, $response, $args) use ($container) {
|
||||
@@ -138,4 +147,6 @@ $app->get('/', function (\Psr\Http\Message\RequestInterface $request, \Psr\Http\
|
||||
}
|
||||
});
|
||||
|
||||
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
|
||||
|
||||
$app->run();
|
||||
|
||||
26
php/public/options-form-submit.js
Normal file
26
php/public/options-form-submit.js
Normal file
@@ -0,0 +1,26 @@
|
||||
function makeOptionsFormSubmitVisible() {
|
||||
var optionsFormSubmit = document.getElementById("options-form-submit");
|
||||
optionsFormSubmit.style.display = 'block';
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// handle submit button for options form
|
||||
var optionsFormSubmit = document.getElementById("options-form-submit");
|
||||
optionsFormSubmit.style.display = 'none';
|
||||
|
||||
// Clamav
|
||||
var clamav = document.getElementById("clamav");
|
||||
clamav.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
|
||||
// OnlyOffice
|
||||
var onlyoffice = document.getElementById("onlyoffice");
|
||||
onlyoffice.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
|
||||
// Collabora
|
||||
var collabora = document.getElementById("collabora");
|
||||
collabora.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
|
||||
// Talk
|
||||
var talk = document.getElementById("talk");
|
||||
talk.addEventListener('change', makeOptionsFormSubmitVisible);
|
||||
});
|
||||
@@ -23,6 +23,10 @@ a {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
@@ -91,6 +91,10 @@ class Container {
|
||||
return $this->dockerActionManager->GetContainerRunningState($this);
|
||||
}
|
||||
|
||||
public function GetRestartingState() : IContainerState {
|
||||
return $this->dockerActionManager->GetContainerRestartingState($this);
|
||||
}
|
||||
|
||||
public function GetUpdateState() : IContainerState {
|
||||
return $this->dockerActionManager->GetContainerUpdateState($this);
|
||||
}
|
||||
|
||||
6
php/src/Container/State/NotRestartingState.php
Normal file
6
php/src/Container/State/NotRestartingState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class NotRestartingState implements IContainerState
|
||||
{}
|
||||
6
php/src/Container/State/RestartingState.php
Normal file
6
php/src/Container/State/RestartingState.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AIO\Container\State;
|
||||
|
||||
class RestartingState implements IContainerState
|
||||
{}
|
||||
@@ -27,7 +27,7 @@ class ContainerDefinitionFetcher
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function GetContainerById(string $id): ?Container
|
||||
public function GetContainerById(string $id): Container
|
||||
{
|
||||
$containers = $this->FetchDefinition();
|
||||
|
||||
@@ -37,7 +37,7 @@ class ContainerDefinitionFetcher
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new \Exception("The provided id " . $id . " was not found in the container definition.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,6 +49,24 @@ class ContainerDefinitionFetcher
|
||||
|
||||
$containers = [];
|
||||
foreach ($data['production'] as $entry) {
|
||||
if ($entry['identifier'] === 'nextcloud-aio-clamav') {
|
||||
if (!$this->configurationManager->isClamavEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['identifier'] === 'nextcloud-aio-onlyoffice') {
|
||||
if (!$this->configurationManager->isOnlyofficeEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['identifier'] === 'nextcloud-aio-collabora') {
|
||||
if (!$this->configurationManager->isCollaboraEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($entry['identifier'] === 'nextcloud-aio-talk') {
|
||||
if (!$this->configurationManager->isTalkEnabled()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$ports = new ContainerPorts();
|
||||
foreach ($entry['ports'] as $port) {
|
||||
if($port === '%APACHE_PORT%/tcp') {
|
||||
@@ -99,6 +117,28 @@ class ContainerDefinitionFetcher
|
||||
);
|
||||
}
|
||||
|
||||
$dependsOn = [];
|
||||
foreach ($entry['dependsOn'] as $value) {
|
||||
if ($value === 'nextcloud-aio-clamav') {
|
||||
if (!$this->configurationManager->isClamavEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-onlyoffice') {
|
||||
if (!$this->configurationManager->isOnlyofficeEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-collabora') {
|
||||
if (!$this->configurationManager->isCollaboraEnabled()) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value === 'nextcloud-aio-talk') {
|
||||
if (!$this->configurationManager->isTalkEnabled()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$dependsOn[] = $value;
|
||||
}
|
||||
|
||||
$variables = new ContainerEnvironmentVariables();
|
||||
foreach ($entry['environmentVariables'] as $value) {
|
||||
$variables->AddVariable($value);
|
||||
@@ -114,7 +154,7 @@ class ContainerDefinitionFetcher
|
||||
$internalPorts,
|
||||
$volumes,
|
||||
$variables,
|
||||
$entry['dependsOn'],
|
||||
$dependsOn,
|
||||
$entry['secrets'],
|
||||
$this->container->get(DockerActionManager::class)
|
||||
);
|
||||
|
||||
@@ -22,7 +22,8 @@ class ConfigurationController
|
||||
public function SetConfig(Request $request, Response $response, $args) : Response {
|
||||
try {
|
||||
if (isset($request->getParsedBody()['domain'])) {
|
||||
$this->configurationManager->SetDomain($request->getParsedBody()['domain']);
|
||||
$domain = $request->getParsedBody()['domain'] ?? '';
|
||||
$this->configurationManager->SetDomain($domain);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['current-master-password']) || isset($request->getParsedBody()['new-master-password'])) {
|
||||
@@ -32,7 +33,40 @@ class ConfigurationController
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['borg_backup_host_location'])) {
|
||||
$this->configurationManager->SetBorgBackupHostLocation($request->getParsedBody()['borg_backup_host_location']);
|
||||
$location = $request->getParsedBody()['borg_backup_host_location'] ?? '';
|
||||
$this->configurationManager->SetBorgBackupHostLocation($location);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['borg_restore_host_location']) || isset($request->getParsedBody()['borg_restore_password'])) {
|
||||
$restoreLocation = $request->getParsedBody()['borg_restore_host_location'] ?? '';
|
||||
$borgPassword = $request->getParsedBody()['borg_restore_password'] ?? '';
|
||||
$this->configurationManager->SetBorgRestoreHostLocationAndPassword($restoreLocation, $borgPassword);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['options-form'])) {
|
||||
if (isset($request->getParsedBody()['collabora']) && isset($request->getParsedBody()['onlyoffice'])) {
|
||||
throw new InvalidSettingConfigurationException("Collabora and Onlyoffice are not allowed to be enabled at the same time!");
|
||||
}
|
||||
if (isset($request->getParsedBody()['clamav'])) {
|
||||
$this->configurationManager->SetClamavEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetClamavEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['onlyoffice'])) {
|
||||
$this->configurationManager->SetOnlyofficeEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetOnlyofficeEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['collabora'])) {
|
||||
$this->configurationManager->SetCollaboraEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetCollaboraEnabledState(0);
|
||||
}
|
||||
if (isset($request->getParsedBody()['talk'])) {
|
||||
$this->configurationManager->SetTalkEnabledState(1);
|
||||
} else {
|
||||
$this->configurationManager->SetTalkEnabledState(0);
|
||||
}
|
||||
}
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '/');
|
||||
|
||||
@@ -33,9 +33,19 @@ class DockerController
|
||||
$this->PerformRecursiveContainerStart($dependency);
|
||||
}
|
||||
|
||||
$pullcontainer = true;
|
||||
if ($id === 'nextcloud-aio-database') {
|
||||
if ($this->dockerActionManager->GetDatabasecontainerExitCode() > 0) {
|
||||
$pullcontainer = false;
|
||||
}
|
||||
}
|
||||
$this->dockerActionManager->DeleteContainer($container);
|
||||
$this->dockerActionManager->CreateVolumes($container);
|
||||
$this->dockerActionManager->PullContainer($container);
|
||||
if ($pullcontainer) {
|
||||
$this->dockerActionManager->PullContainer($container);
|
||||
} else {
|
||||
error_log('Not pulling the latest database image because the container was not correctly shut down.');
|
||||
}
|
||||
$this->dockerActionManager->CreateContainer($container);
|
||||
$this->dockerActionManager->StartContainer($container);
|
||||
$this->dockerActionManager->ConnectContainerToNetwork($container);
|
||||
@@ -44,8 +54,12 @@ class DockerController
|
||||
public function GetLogs(Request $request, Response $response, $args) : Response
|
||||
{
|
||||
$id = $request->getQueryParams()['id'];
|
||||
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
$logs = $this->dockerActionManager->GetLogs($container);
|
||||
if (str_starts_with($id, 'nextcloud-aio-')) {
|
||||
$logs = $this->dockerActionManager->GetLogs($id);
|
||||
} else {
|
||||
$logs = 'Container not found.';
|
||||
}
|
||||
|
||||
$body = $response->getBody();
|
||||
$body->write($logs);
|
||||
|
||||
@@ -95,6 +109,20 @@ class DockerController
|
||||
return $response->withStatus(201)->withHeader('Location', '/');
|
||||
}
|
||||
|
||||
public function StartBackupContainerTest(Request $request, Response $response, $args) : Response {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'test';
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
$this->PerformRecursiveContainerStop($id);
|
||||
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
|
||||
return $response->withStatus(201)->withHeader('Location', '/');
|
||||
}
|
||||
|
||||
public function StartContainer(Request $request, Response $response, $args) : Response
|
||||
{
|
||||
$uri = $request->getUri();
|
||||
@@ -149,22 +177,33 @@ class DockerController
|
||||
public function StartDomaincheckContainer() : void
|
||||
{
|
||||
# Don't start if domain is already set
|
||||
if ($this->configurationManager->GetDomain() != '') {
|
||||
if ($this->configurationManager->GetDomain() !== '' || $this->configurationManager->wasStartButtonClicked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$id = 'nextcloud-aio-domaincheck';
|
||||
|
||||
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
// don't start if the domaincheck is already running
|
||||
if ($container->GetIdentifier() === $id && $container->GetRunningState() instanceof RunningState) {
|
||||
return;
|
||||
// don't start if apache is already running
|
||||
} elseif ($container->GetIdentifier() === self::TOP_CONTAINER && $container->GetRunningState() instanceof RunningState) {
|
||||
$cacheKey = 'domaincheckWasStarted';
|
||||
|
||||
$domaincheckContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById(self::TOP_CONTAINER);
|
||||
// Don't start if apache is already running
|
||||
if ($apacheContainer->GetRunningState() instanceof RunningState) {
|
||||
return;
|
||||
// Don't start if domaincheck is already running
|
||||
} elseif ($domaincheckContainer->GetRunningState() instanceof RunningState) {
|
||||
$domaincheckWasStarted = apcu_fetch($cacheKey);
|
||||
// Start domaincheck again when 10 minutes are over by not returning here
|
||||
if($domaincheckWasStarted !== false && is_string($domaincheckWasStarted)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->StopDomaincheckContainer();
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
|
||||
// Cache the start for 10 minutes
|
||||
apcu_add($cacheKey, '1', 600);
|
||||
}
|
||||
|
||||
private function StopDomaincheckContainer() : void
|
||||
|
||||
@@ -102,6 +102,9 @@ class ConfigurationManager
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the array to list newest backup first
|
||||
$backupTimes = array_reverse($backupTimes);
|
||||
|
||||
return $backupTimes;
|
||||
}
|
||||
|
||||
@@ -113,6 +116,74 @@ class ConfigurationManager
|
||||
}
|
||||
}
|
||||
|
||||
public function isx64Platform() : bool {
|
||||
if (php_uname('m') === 'x86_64') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function isClamavEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isClamavEnabled']) && $config['isClamavEnabled'] === 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetClamavEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isClamavEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function isOnlyofficeEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isOnlyofficeEnabled']) && $config['isOnlyofficeEnabled'] === 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetOnlyofficeEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isOnlyofficeEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function isCollaboraEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isCollaboraEnabled']) && $config['isCollaboraEnabled'] === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetCollaboraEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isCollaboraEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function isTalkEnabled() : bool {
|
||||
$config = $this->GetConfig();
|
||||
if (isset($config['isTalkEnabled']) && $config['isTalkEnabled'] === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetTalkEnabledState(int $value) : void {
|
||||
$config = $this->GetConfig();
|
||||
$config['isTalkEnabled'] = $value;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
@@ -166,6 +237,8 @@ class ConfigurationManager
|
||||
// Write domain
|
||||
$config = $this->GetConfig();
|
||||
$config['domain'] = $domain;
|
||||
// Reset the borg restore password when setting the domain
|
||||
$config['borg_restore_password'] = '';
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
@@ -212,6 +285,7 @@ class ConfigurationManager
|
||||
$allowedPrefixes = [
|
||||
'/mnt/',
|
||||
'/media/',
|
||||
'/host_mnt/',
|
||||
];
|
||||
|
||||
$isValidPath = false;
|
||||
@@ -227,7 +301,7 @@ class ConfigurationManager
|
||||
}
|
||||
|
||||
if(!$isValidPath) {
|
||||
throw new InvalidSettingConfigurationException("The path must start with '/mnt/' or '/media/' or be equal to '/var/backups'.");
|
||||
throw new InvalidSettingConfigurationException("The path must start with '/mnt/', '/media/' or '/host_mnt/' or be equal to '/var/backups'.");
|
||||
}
|
||||
|
||||
|
||||
@@ -236,6 +310,33 @@ class ConfigurationManager
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetBorgRestoreHostLocationAndPassword(string $location, string $password) : void {
|
||||
if ($location === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter a path!");
|
||||
}
|
||||
|
||||
$isValidPath = false;
|
||||
if (str_starts_with($location, '/') && !str_ends_with($location, '/')) {
|
||||
$isValidPath = true;
|
||||
}
|
||||
|
||||
if(!$isValidPath) {
|
||||
throw new InvalidSettingConfigurationException("The path may start with '/mnt/', '/media/' or '/host_mnt/' or may be equal to '/var/backups'.");
|
||||
}
|
||||
|
||||
if ($password === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter the password!");
|
||||
}
|
||||
|
||||
$config = $this->GetConfig();
|
||||
$config['borg_backup_host_location'] = $location;
|
||||
$config['borg_restore_password'] = $password;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
@@ -265,26 +366,10 @@ class ConfigurationManager
|
||||
}
|
||||
|
||||
public function GetApachePort() : string {
|
||||
$port = getenv('APACHE_PORT');
|
||||
if ($port === false) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['apache_port']) || $config['apache_port'] === '') {
|
||||
$config['apache_port'] = '443';
|
||||
}
|
||||
return $config['apache_port'];
|
||||
} else {
|
||||
if(file_exists(DataConst::GetConfigFile())) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['apache_port'])) {
|
||||
$config['apache_port'] = '';
|
||||
}
|
||||
if ($port !== $config['apache_port']) {
|
||||
$config['apache_port'] = $port;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
}
|
||||
return $port;
|
||||
}
|
||||
$envVariableName = 'APACHE_PORT';
|
||||
$configName = 'apache_port';
|
||||
$defaultValue = '443';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,6 +382,28 @@ class ConfigurationManager
|
||||
file_put_contents(DataConst::GetConfigFile(), json_encode($config));
|
||||
}
|
||||
|
||||
private function GetEnvironmentalVariableOrConfig(string $envVariableName, string $configName, string $defaultValue) : string {
|
||||
$envVariableOutput = getenv($envVariableName);
|
||||
if ($envVariableOutput === false) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config[$configName]) || $config[$configName] === '') {
|
||||
$config[$configName] = $defaultValue;
|
||||
}
|
||||
return $config[$configName];
|
||||
}
|
||||
if(file_exists(DataConst::GetConfigFile())) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config[$configName])) {
|
||||
$config[$configName] = '';
|
||||
}
|
||||
if ($envVariableOutput !== $config[$configName]) {
|
||||
$config[$configName] = $envVariableOutput;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
}
|
||||
return $envVariableOutput;
|
||||
}
|
||||
|
||||
public function GetBorgBackupHostLocation() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['borg_backup_host_location'])) {
|
||||
@@ -306,6 +413,15 @@ class ConfigurationManager
|
||||
return $config['borg_backup_host_location'];
|
||||
}
|
||||
|
||||
public function GetBorgRestorePassword() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['borg_restore_password'])) {
|
||||
$config['borg_restore_password'] = '';
|
||||
}
|
||||
|
||||
return $config['borg_restore_password'];
|
||||
}
|
||||
|
||||
public function GetBorgBackupMode() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['backup-mode'])) {
|
||||
@@ -316,48 +432,16 @@ class ConfigurationManager
|
||||
}
|
||||
|
||||
public function GetNextcloudMount() : string {
|
||||
$mount = getenv('NEXTCLOUD_MOUNT');
|
||||
if ($mount === false) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['nextcloud_mount'])) {
|
||||
$config['nextcloud_mount'] = '';
|
||||
}
|
||||
return $config['nextcloud_mount'];
|
||||
} else {
|
||||
if(file_exists(DataConst::GetConfigFile())) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['nextcloud_mount'])) {
|
||||
$config['nextcloud_mount'] = '';
|
||||
}
|
||||
if ($mount !== $config['nextcloud_mount']) {
|
||||
$config['nextcloud_mount'] = $mount;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
}
|
||||
return $mount;
|
||||
}
|
||||
$envVariableName = 'NEXTCLOUD_MOUNT';
|
||||
$configName = 'nextcloud_mount';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetNextcloudDatadirMount() : string {
|
||||
$mount = getenv('NEXTCLOUD_DATADIR');
|
||||
if ($mount === false) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['nextcloud_datadir']) || $config['nextcloud_datadir'] === '') {
|
||||
$config['nextcloud_datadir'] = 'nextcloud_aio_nextcloud_data';
|
||||
}
|
||||
return $config['nextcloud_datadir'];
|
||||
} else {
|
||||
if(file_exists(DataConst::GetConfigFile())) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['nextcloud_datadir'])) {
|
||||
$config['nextcloud_datadir'] = '';
|
||||
}
|
||||
if ($mount !== $config['nextcloud_datadir']) {
|
||||
$config['nextcloud_datadir'] = $mount;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
}
|
||||
return $mount;
|
||||
}
|
||||
$envVariableName = 'NEXTCLOUD_DATADIR';
|
||||
$configName = 'nextcloud_datadir';
|
||||
$defaultValue = 'nextcloud_aio_nextcloud_data';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ use AIO\Container\State\IContainerState;
|
||||
use AIO\Container\State\ImageDoesNotExistState;
|
||||
use AIO\Container\State\StartingState;
|
||||
use AIO\Container\State\RunningState;
|
||||
use AIO\Container\State\RestartingState;
|
||||
use AIO\Container\State\NotRestartingState;
|
||||
use AIO\Container\State\VersionDifferentState;
|
||||
use AIO\Container\State\StoppedState;
|
||||
use AIO\Container\State\VersionEqualState;
|
||||
@@ -70,6 +72,27 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function GetContainerRestartingState(Container $container) : IContainerState
|
||||
{
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
|
||||
try {
|
||||
$response = $this->guzzleClient->get($url);
|
||||
} catch (RequestException $e) {
|
||||
if ($e->getCode() === 404) {
|
||||
return new ImageDoesNotExistState();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$responseBody = json_decode((string)$response->getBody(), true);
|
||||
|
||||
if ($responseBody['State']['Restarting'] === true) {
|
||||
return new RestartingState();
|
||||
} else {
|
||||
return new NotRestartingState();
|
||||
}
|
||||
}
|
||||
|
||||
public function GetContainerUpdateState(Container $container) : IContainerState
|
||||
{
|
||||
$tag = $this->GetCurrentChannel();
|
||||
@@ -120,12 +143,12 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLogs(Container $container) : string
|
||||
public function GetLogs(string $id) : string
|
||||
{
|
||||
$url = $this->BuildApiUrl(
|
||||
sprintf(
|
||||
'containers/%s/logs?stdout=true&stderr=true',
|
||||
urlencode($container->GetIdentifier())
|
||||
urlencode($id)
|
||||
));
|
||||
$responseBody = (string)$this->guzzleClient->get($url)->getBody();
|
||||
|
||||
@@ -216,6 +239,34 @@ class DockerActionManager
|
||||
$replacements[1] = $this->configurationManager->GetSelectedRestoreTime();
|
||||
} elseif ($out[1] === 'APACHE_PORT') {
|
||||
$replacements[1] = $this->configurationManager->GetApachePort();
|
||||
} elseif ($out[1] === 'NEXTCLOUD_MOUNT') {
|
||||
$replacements[1] = $this->configurationManager->GetNextcloudMount();
|
||||
} elseif ($out[1] === 'BACKUP_RESTORE_PASSWORD') {
|
||||
$replacements[1] = $this->configurationManager->GetBorgRestorePassword();
|
||||
} elseif ($out[1] === 'CLAMAV_ENABLED') {
|
||||
if ($this->configurationManager->isClamavEnabled()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'ONLYOFFICE_ENABLED') {
|
||||
if ($this->configurationManager->isOnlyofficeEnabled()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'COLLABORA_ENABLED') {
|
||||
if ($this->configurationManager->isCollaboraEnabled()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} elseif ($out[1] === 'TALK_ENABLED') {
|
||||
if ($this->configurationManager->isTalkEnabled()) {
|
||||
$replacements[1] = 'yes';
|
||||
} else {
|
||||
$replacements[1] = '';
|
||||
}
|
||||
} else {
|
||||
$replacements[1] = $this->configurationManager->GetSecret($out[1]);
|
||||
}
|
||||
@@ -250,30 +301,30 @@ class DockerActionManager
|
||||
}
|
||||
|
||||
$url = $this->BuildApiUrl('containers/create?name=' . $container->GetIdentifier());
|
||||
$this->guzzleClient->request(
|
||||
'POST',
|
||||
$url,
|
||||
[
|
||||
'json' => $requestBody
|
||||
]
|
||||
);
|
||||
try {
|
||||
$this->guzzleClient->request(
|
||||
'POST',
|
||||
$url,
|
||||
[
|
||||
'json' => $requestBody
|
||||
]
|
||||
);
|
||||
} catch (RequestException $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function PullContainer(Container $container) : void
|
||||
{
|
||||
$pullcontainer = true;
|
||||
if ($container->GetIdentifier() === 'nextcloud-aio-database') {
|
||||
if ($this->GetDatabasecontainerExitCode() > 0) {
|
||||
$pullcontainer = false;
|
||||
}
|
||||
}
|
||||
if ($pullcontainer) {
|
||||
$url = $this->BuildApiUrl(sprintf('images/create?fromImage=%s', urlencode($this->BuildImageName($container))));
|
||||
try {
|
||||
$this->guzzleClient->post($url);
|
||||
} catch (RequestException $e) {
|
||||
throw $e;
|
||||
}
|
||||
$url = $this->BuildApiUrl(sprintf('images/create?fromImage=%s', urlencode($this->BuildImageName($container))));
|
||||
try {
|
||||
$this->guzzleClient->post($url);
|
||||
} catch (RequestException $e) {
|
||||
error_log('Could not get image ' . $this->BuildImageName($container) . ' from docker hub. Probably due to rate limits. ' . $e->getMessage());
|
||||
// Don't exit here because it is possible that the image is already present
|
||||
// and we ran into docker hub limits.
|
||||
// We will exit later if not image should be available.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +369,7 @@ class DockerActionManager
|
||||
|
||||
return null;
|
||||
} catch (\Exception $e) {
|
||||
error_log('Could not get digest of container ' . $this->BuildApiUrl($containerName) . ' ' . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -339,6 +391,7 @@ class DockerActionManager
|
||||
apcu_add($cacheKey, $tag);
|
||||
return $tag;
|
||||
} catch (\Exception $e) {
|
||||
error_log('Could not get current channel ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return 'latest';
|
||||
@@ -425,6 +478,7 @@ class DockerActionManager
|
||||
]
|
||||
);
|
||||
} catch (RequestException $e) {
|
||||
error_log('Could not disconnect container from network ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,4 +600,13 @@ class DockerActionManager
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isBackupContainerRunning() : bool {
|
||||
$id = 'nextcloud-aio-borgbackup';
|
||||
$backupContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
if ($this->GetContainerRunningState($backupContainer) instanceof RunningState) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ class DockerHubManager
|
||||
return $cachedVersion;
|
||||
}
|
||||
|
||||
// If one of the links below should ever become outdated, we can still upgrade the mastercontainer via the webinterface manually by opening '/api/docker/getwatchtower'
|
||||
|
||||
try {
|
||||
$authTokenRequest = $this->guzzleClient->request(
|
||||
'GET',
|
||||
|
||||
@@ -16,42 +16,45 @@
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h1>Nextcloud AIO Beta v0.7.0</h1>
|
||||
<h1>Nextcloud AIO Beta v0.9.1</h1>
|
||||
This is beta software and not production ready.<br><br>
|
||||
|
||||
{% set isAnyRunning = false %}
|
||||
{% set isAnyRestarting = false %}
|
||||
{% set isWatchtowerRunning = false %}
|
||||
{% set isBackupContainerRunning = false %}
|
||||
{% set isRestoreRunning = false %}
|
||||
{% set isBackupOrRestoreRunning = false %}
|
||||
{% set isApacheStarting = false %}
|
||||
|
||||
{% if is_backup_container_running == true %}
|
||||
{% if borg_backup_mode == 'restore' %}
|
||||
{% set isRestoreRunning = true %}
|
||||
{% endif %}
|
||||
{% if borg_backup_mode == 'backup' or borg_backup_mode == 'restore' %}
|
||||
{% set isBackupOrRestoreRunning = true %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% for container in containers %}
|
||||
{% if class(container.GetRunningState()) == 'AIO\\Container\\State\\RunningState' and container.GetIdentifier() != 'nextcloud-aio-domaincheck' and container.GetIdentifier() != 'nextcloud-aio-borgbackup' and container.GetIdentifier() != 'nextcloud-aio-watchtower' %}
|
||||
{% if container.GetIdentifier() not in ['nextcloud-aio-domaincheck', 'nextcloud-aio-borgbackup', 'nextcloud-aio-watchtower'] and class(container.GetRunningState()) == 'AIO\\Container\\State\\RunningState' %}
|
||||
{% set isAnyRunning = true %}
|
||||
{% endif %}
|
||||
{% if container.GetIdentifier() not in ['nextcloud-aio-domaincheck', 'nextcloud-aio-borgbackup', 'nextcloud-aio-watchtower'] and class(container.GetRestartingState()) == 'AIO\\Container\\State\\RestartingState' %}
|
||||
{% set isAnyRestarting = true %}
|
||||
{% endif %}
|
||||
{% if container.GetIdentifier() == 'nextcloud-aio-watchtower' and class(container.GetRunningState()) == 'AIO\\Container\\State\\RunningState' %}
|
||||
{% set isWatchtowerRunning = true %}
|
||||
{% endif %}
|
||||
{% if container.GetIdentifier() == 'nextcloud-aio-apache' and class(container.GetStartingState()) == 'AIO\\Container\\State\\StartingState' %}
|
||||
{% set isApacheStarting = true %}
|
||||
{% endif %}
|
||||
{% if container.GetIdentifier() == 'nextcloud-aio-borgbackup' and class(container.GetRunningState()) == 'AIO\\Container\\State\\RunningState' %}
|
||||
{% set isBackupContainerRunning = true %}
|
||||
{% if borg_backup_mode == 'restore' %}
|
||||
{% set isRestoreRunning = true %}
|
||||
{% endif %}
|
||||
{% if borg_backup_mode == 'backup' or borg_backup_mode == 'restore' %}
|
||||
{% set isBackupOrRestoreRunning = true %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if isWatchtowerRunning == true %}
|
||||
Mastercontainer update currently running. It will restart the mastercontainer soon which will make it unavailable for a moment. Please wait until that's done.<br /><br />
|
||||
<span class="status running"></span> Mastercontainer update currently running. It will restart the mastercontainer soon which will make it unavailable for a moment. Please wait until that's done. (<a href="/api/docker/logs?id=nextcloud-aio-mastercontainer">Logs</a>)<br /><br />
|
||||
<a href="" class="button reload">Reload ↻</a><br/>
|
||||
{% else %}
|
||||
{% if isBackupOrRestoreRunning == false and domain == "" %}
|
||||
{% if is_backup_container_running == false and domain == "" %}
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
<h2>Mastercontainer update</h2>
|
||||
⚠ A mastercontainer update is available. Please click on the button below to update it. Afterwards, you will be able to proceed with the setup.<br><br>
|
||||
@@ -61,29 +64,115 @@
|
||||
<input class="button" type="submit" value="Update mastercontainer" />
|
||||
</form>
|
||||
{% else %}
|
||||
Please type in the domain that will be used for Nextcloud:<br><br />
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" name="domain" value="{{ domain }}" placeholder="nextcloud.yourdomain.com"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit" />
|
||||
</form>
|
||||
Make sure that this server is reachable on Port 443 and you've correctly set up the DNS config for the domain that you enter. <br><br>
|
||||
If you have a dynamic IP-address, you can use e.g. <a href="https://ddclient.net/">DDclient</a> with a compatible domain provider for DNS updates.
|
||||
{% if borg_backup_host_location == '' and borg_restore_password == '' %}
|
||||
Nextcloud AIO stands for Nextcloud All In One and provides easy deployment and maintenance with most features included in this one Nextcloud instance.<br><br>
|
||||
<h2>New AIO instance</h2>
|
||||
Please type in the domain that will be used for Nextcloud if you want to create a new instance:<br><br />
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" name="domain" value="{{ domain }}" placeholder="nextcloud.yourdomain.com"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit" />
|
||||
</form>
|
||||
Make sure that this server is reachable on Port 443 and you've correctly set up the DNS config for the domain that you enter. <br><br>
|
||||
If you have a dynamic IP-address, you can use e.g. <a href="https://ddclient.net/">DDclient</a> with a compatible domain provider for DNS updates. <br /><br/>
|
||||
{% endif %}
|
||||
|
||||
<h2>Restore AIO instance from backup</h2>
|
||||
You can alternatively restore an AIO instance from backup.<br><br>
|
||||
|
||||
{% if borg_backup_host_location != '' and borg_restore_password != '' %}
|
||||
{% if borg_backup_mode in ['test', 'check'] %}
|
||||
{% if backup_exit_code > 0 %}
|
||||
<span class="status error"></span> Last {{ borg_backup_mode }} failed! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
{% if borg_backup_mode == 'test' %}
|
||||
Please adjust the path and/or password in order to make it work! Afterwards click on 'Test path and password' button to verify the settings!<br><br>
|
||||
{% elseif borg_backup_mode == 'check' %}
|
||||
The backup archive seems to be corrupt. Please try to use a different intact backup archive or try to fix it by following <a href="https://borgbackup.readthedocs.io/en/stable/faq.html?highlight=repair#:~:text=repairing%20a%20damaged%20repository"><b>this documentation</b></a>
|
||||
{% endif %}
|
||||
{% elseif backup_exit_code == 0 %}
|
||||
<span class="status success"></span> Last {{ borg_backup_mode }} successful! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
{% if borg_backup_mode == 'test' %}
|
||||
Feel free to check the integrity of the backup archive below before starting the restore process in order to make double-sure that the restore will work. This can take a long time though depending on the size of the backup archive and is thus not required.<br><br>
|
||||
<form method="POST" action="/api/docker/backup-check" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Check backup integrity"/><br/>
|
||||
</form>
|
||||
{% endif %}
|
||||
Choose the backup that you want to restore and click on the button below to restore the selected backup. This will restore the whole AIO instance from backup. Please not that the current AIO password will be kept and the AIO password not restored from backup!<br><br>
|
||||
<form method="POST" action="/api/docker/restore" class="xhr" id="restore_selection">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<select id="selected_restore_time" name="selected_restore_time" form="restore_selection">
|
||||
{% for restore_time in backup_times %}
|
||||
<option value="{{ restore_time }}">{{ restore_time }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input class="button" type="submit" value="Restore selected backup"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% elseif borg_backup_mode == 'restore' %}
|
||||
{% if backup_exit_code > 0 %}
|
||||
<span class="status error"></span> Last restore failed! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
Somehow the restore failed which is unexpected! Please adjust the path and password, test it and try to restore again!
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if borg_backup_host_location == '' or borg_restore_password == '' or borg_backup_mode not in ['test', 'check', ''] or backup_exit_code > 0 %}
|
||||
Please enter the location of the backup archive on your host and the password of the backup archive below:<br><br>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" name="borg_restore_host_location" value="{{borg_backup_host_location}}" placeholder="/mnt/backup"/>
|
||||
<input type="text" name="borg_restore_password" value="{{borg_restore_password}}" placeholder="enter the borg password"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit" />
|
||||
</form>
|
||||
The folder path that you enter may start with <b>/mnt/</b>, <b>/media/</b> or <b>/host_mnt/</b> or may be equal to <b>/var/backups</b>.<br><br>So e.g. <b>/mnt/backup</b> on Linux and macOS or <b>/host_mnt/c/backup/directory</b> on Windows. (This Windows example would be equivalent to 'C:\backup\directory' on the Windows host. So you need to translate the path that you want to use into the correct format.)<br><br>
|
||||
⚠ 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'. Otherwise will the backup container not find the backup archive!<br><br>
|
||||
{% endif %}
|
||||
{% if borg_backup_host_location != '' and borg_restore_password != '' %}
|
||||
{% if borg_backup_mode not in ['test', 'check'] or backup_exit_code != 0 %}
|
||||
<b>Everything set!</b> Click on the button below to test the path and password:<br/><br/>
|
||||
<form method="POST" action="/api/docker/backup-test" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Test path and password"/><br/>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if is_backup_container_running == true %}
|
||||
<span class="status running"></span> Backup container is currently running. (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
<a href="" class="button reload">Reload ↻</a><br/><br>
|
||||
{% endif %}
|
||||
|
||||
{% if domain != "" %}
|
||||
You are currently running the {{ current_channel }} channel. (<a href="/api/docker/logs?id=nextcloud-aio-mastercontainer">Logs</a>)<br><br>
|
||||
|
||||
{% if isAnyRunning == true %}
|
||||
{% if isApacheStarting != true %}
|
||||
Your initial Nextcloud credentials:<br><br />
|
||||
Initial Nextcloud username: admin<br />
|
||||
Initial Nextcloud password: {{ nextcloud_password }}<br /><br/>
|
||||
<details>
|
||||
<summary>Click here to reveal the initial Nextcloud credentials</summary><br />
|
||||
Initial Nextcloud username: admin<br />
|
||||
Initial Nextcloud password: {{ nextcloud_password }}
|
||||
</details><br /><br />
|
||||
<a href="https://{{ domain }}" class="button" target="_blank" rel="noopener">Open your Nextcloud ↗</a><br/>
|
||||
{% else %}
|
||||
Containers are currently starting.<br /><br />
|
||||
<a href="" class="button reload">Reload ↻</a><br/>
|
||||
{% if isAnyRestarting == false %}
|
||||
<span class="status running"></span> Containers are currently starting.<br /><br />
|
||||
<a href="" class="button reload">Reload ↻</a><br/><br>
|
||||
{% else %}
|
||||
It seems like at least one container is currently restarting which means it is not able to start correctly.<br><br>
|
||||
To break out this endless loop, you can stop the containers below and investigate the issue by having a look at the container logs before starting them again.<br><br>
|
||||
<form method="POST" action="/api/docker/stop" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Stop containers" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -92,7 +181,7 @@
|
||||
<ul>
|
||||
{# @var containers \AIO\Container\Container[] #}
|
||||
{% for container in containers %}
|
||||
{% if container.GetIdentifier() != 'nextcloud-aio-borgbackup' and container.GetIdentifier() != 'nextcloud-aio-watchtower' and container.GetIdentifier() != 'nextcloud-aio-domaincheck' %}
|
||||
{% if container.GetIdentifier() not in ['nextcloud-aio-borgbackup', 'nextcloud-aio-watchtower', 'nextcloud-aio-domaincheck'] %}
|
||||
<li>
|
||||
{% if class(container.GetStartingState()) == 'AIO\\Container\\State\\StartingState' %}
|
||||
<span class="status running"></span>
|
||||
@@ -111,7 +200,7 @@
|
||||
|
||||
{% if has_update_available == true %}
|
||||
{% if is_mastercontainer_update_available == false %}
|
||||
⚠ Container updates are available. Click on `Stop Containers` and `Start Containers` to update them. You should consider creating a backup first.<br><br>
|
||||
⚠ Container updates are available. Click on 'Stop Containers' and 'Start Containers' to update them. You should consider creating a backup first.<br><br>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if is_mastercontainer_update_available == false %}
|
||||
@@ -124,6 +213,13 @@
|
||||
{% if isApacheStarting != true %}
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
⚠ A mastercontainer update is available. Please click on the button below to stop your containers in order to be able to update the mastercontainer.<br /><br />
|
||||
{% if current_channel starts with 'latest' %}
|
||||
You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases/latest"><b>here</b></a><br><br>
|
||||
{% elseif current_channel starts with 'beta' %}
|
||||
You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases"><b>here</b></a><br><br>
|
||||
{% elseif current_channel starts with 'develop' %}
|
||||
You can find all changes <a href="https://github.com/nextcloud-releases/all-in-one/commits/main"><b>here</b></a><br><br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<form method="POST" action="/api/docker/stop" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
@@ -141,7 +237,12 @@
|
||||
Clicking on the button below will download all docker containers and start them. This can take a lot of time depending on your internect connection. Since the overall size is a few GB, this will take around 5-10 min or more. So be aware and patient!<br><br>
|
||||
{% endif %}
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
⚠ Please update your mastercontainer. Afterwards, you will be able to start your containers again.<br><br>
|
||||
⚠ A mastercontainer update is available. Please click on the button below to update it.<br><br>
|
||||
<form method="POST" action="/api/docker/watchtower" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Update mastercontainer" />
|
||||
</form>
|
||||
{% else %}
|
||||
{% if was_start_button_clicked == false or has_update_available == false %}
|
||||
<form method="POST" action="/api/docker/start" class="xhr">
|
||||
@@ -161,58 +262,22 @@
|
||||
{% endif %}
|
||||
|
||||
{% if was_start_button_clicked == true %}
|
||||
|
||||
{% if isBackupOrRestoreRunning == false %}
|
||||
<h2>Mastercontainer</h2>
|
||||
You are currently running the {{ current_channel }} channel.<br><br>
|
||||
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
{% if isAnyRunning == false %}
|
||||
⚠ A mastercontainer update is available. Please click on the button below to update it.<br><br>
|
||||
<form method="POST" action="/api/docker/watchtower" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Update mastercontainer" />
|
||||
</form>
|
||||
{% else %}
|
||||
⚠ A mastercontainer update is available. Please stop your containers in order to be able to update the mastercontainer.<br><br>
|
||||
{% endif %}
|
||||
{% if current_channel starts with 'latest' %}
|
||||
You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases/latest">here</a><br><br>
|
||||
{% elseif current_channel starts with 'beta' %}
|
||||
You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases">here</a><br><br>
|
||||
{% elseif current_channel starts with 'develop' %}
|
||||
You can find all changes <a href="https://github.com/nextcloud-releases/all-in-one/commits/main">here</a><br><br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if isApacheStarting == false %}
|
||||
You can change your AIO password below:<br><br />
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" autocomplete="current-password" name="current-master-password" placeholder="your current aio password"/>
|
||||
<input type="text" autocomplete="new-password" name="new-master-password" placeholder="your new aio password"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit" />
|
||||
</form>
|
||||
The new password needs to be at least 24 characters long. Allowed characters are the <a href="https://en.wikipedia.org/wiki/Latin_alphabet#/media/File:Abecedarium.png">latin characters</a> 'a-z', 'A-Z', '0-9' and spaces.<br><br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if isBackupOrRestoreRunning == false and borg_backup_host_location == "" and isApacheStarting != true %}
|
||||
{% if is_backup_container_running == false and borg_backup_host_location == "" and isApacheStarting != true %}
|
||||
<h2>Backup and restore</h2>
|
||||
Please type in the directory where backups will get created on the host system:<br><br>
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" name="borg_backup_host_location" value="/mnt/backup" placeholder="/mnt/backup"/>
|
||||
<input type="text" name="borg_backup_host_location" placeholder="/mnt/backup"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit" />
|
||||
</form>
|
||||
The folder path that you enter must start with <b>/mnt/</b> or <b>/media/</b> or be equal to <b>/var/backups</b>. So e.g. <b>/mnt/backup</b> or <b>/var/backups</b>
|
||||
The folder path that you enter must start with <b>/mnt/</b>, <b>/media/</b> or <b>/host_mnt/</b> or be equal to <b>/var/backups</b>.<br><br>So e.g. <b>/mnt/backup</b> on Linux and macOS or <b>/host_mnt/c/backup/directory</b> on Windows. (This Windows example would be equivalent to 'C:\backup\directory' on the Windows host. So you need to translate the path that you want to use into the correct format.)
|
||||
{% endif %}
|
||||
|
||||
{% if borg_backup_host_location != "" %}
|
||||
<h2>Backup and restore</h2>
|
||||
{% if isBackupContainerRunning == false %}
|
||||
{% if is_backup_container_running == false %}
|
||||
<h2>Backup and restore</h2>
|
||||
{% if backup_exit_code > 0 %}
|
||||
<span class="status error"></span> Last {{ borg_backup_mode }} failed! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
{% elseif backup_exit_code == 0 %}
|
||||
@@ -224,15 +289,22 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if isBackupContainerRunning == false %}
|
||||
{% if is_backup_container_running == false %}
|
||||
{% if has_backup_run_once == true %}
|
||||
<details>
|
||||
<summary>Click here to reveal all backup options</summary><br />
|
||||
{% endif %}
|
||||
<h3>Backup information</h3>
|
||||
This is your encryption password for backups: {{ borgbackup_password }} <br /><br/>
|
||||
Please save it at a safe place since you won't be able to restore from backup if you loose this password! <br /><br/>
|
||||
Backed up will get all important data of your Nextcloud AIO instance like the database, your files and configuration files of the mastercontainer and else. <br /><br/>
|
||||
The backup itself will use a tool that is called <a href="https://github.com/borgbackup/borg#what-is-borgbackup">BorgBackup<a/> which is a well-known server backup tool that efficiently backs up your files and encrypts them on the fly. <br /><br/>
|
||||
Backups get created in the following directory on the host: {{ borg_backup_host_location }}/borg <br /><br/>
|
||||
Be aware that this solution does not back up files and folders that are mounted into Nextcloud using the external storage app. <br /><br/>
|
||||
Be aware that this solution does not back up files and folders that are mounted into Nextcloud using the external storage app.
|
||||
|
||||
{% if isApacheStarting != true %}
|
||||
<h3>Backup creation</h3>
|
||||
Clicking on the button below will create a backup.<br><br/>
|
||||
<form method="POST" action="/api/docker/backup" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
@@ -240,6 +312,7 @@
|
||||
</form>
|
||||
|
||||
{% if has_backup_run_once == true %}
|
||||
<h3>Backup check</h3>
|
||||
Click on the button below to perform a backup integrity check. This is an option that verifies that your backup is intact but it should't be needed in most situtations.<br><br/>
|
||||
<form method="POST" action="/api/docker/backup-check" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
@@ -247,6 +320,7 @@
|
||||
<input class="button" type="submit" value="Check backup integrity" onclick="return confirm('Check backup integrity? Are you sure that you want to check the backup? This can take a long time depending on the size of your backup.')" /><br/>
|
||||
</form>
|
||||
|
||||
<h3>Backup restore</h3>
|
||||
Choose the backup that you want to restore and click on the button below to restore the selected backup. This will overwrite all your files with the state of the backup so you should consider creating a backup first. It also makes sense to run an integrity check before restoring your files but is not mandatory since it shouldn't be needed in most situations.<br><br>
|
||||
<form method="POST" action="/api/docker/restore" class="xhr" id="restore_selection">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
@@ -260,36 +334,75 @@
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if has_backup_run_once == false %}
|
||||
<br /><br />
|
||||
{% else %}
|
||||
</details><br /><br />
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<span class="status running"></span> Backup container currently running. (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
<a href="" class="button reload">Reload ↻</a><br/>
|
||||
{% if is_backup_container_running == false %}
|
||||
{% if isApacheStarting == false %}
|
||||
<h2>AIO password change</h2>
|
||||
You can change your AIO password below:<br><br />
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" autocomplete="current-password" name="current-master-password" placeholder="Your current AIO password"/>
|
||||
<input type="text" autocomplete="new-password" name="new-master-password" placeholder="Your new AIO password"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit" />
|
||||
</form>
|
||||
The new password needs to be at least 24 characters long. Allowed characters are the <a href="https://en.wikipedia.org/wiki/Latin_alphabet#/media/File:Abecedarium.png"><b>latin characters</b></a> <b>a-z</b>, <b>A-Z</b>, <b>0-9</b> and <b>spaces</b>.
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<h2>Optional</h2>
|
||||
In this section, you will find optional addons in the future.
|
||||
It will disable the ability to change them when any containers are running and allow to change them when they are stopped.
|
||||
Also, it will display possible sections for optional addons. (which itself will be displayed when enabled and running).
|
||||
{% if is_backup_container_running == false %}
|
||||
<h2>Optional addons</h2>
|
||||
In this section, you can find optional addons.<br>
|
||||
You can enable or disaable them when your containers are stopped.<br><br>
|
||||
<form id="options-form" method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="hidden" name="options-form" value="options-form">
|
||||
{% if is_clamav_enabled == true %}
|
||||
<input type="checkbox" id="clamav" name="clamav" checked="checked"><label for="clamav">ClamAV (only supported on x64, needs ~1GB additional RAM)</label><br>
|
||||
{% else %}
|
||||
<input type="checkbox" id="clamav" name="clamav"><label for="clamav">ClamAV (only supported on x64, needs ~1GB additional RAM)</label><br>
|
||||
{% endif %}
|
||||
{% if is_collabora_enabled == true %}
|
||||
<input type="checkbox" id="collabora" name="collabora" checked="checked"><label for="collabora">Collabora</label><br>
|
||||
{% else %}
|
||||
<input type="checkbox" id="collabora" name="collabora"><label for="collabora">Collabora</label><br>
|
||||
{% endif %}
|
||||
{% if is_talk_enabled == true %}
|
||||
<input type="checkbox" id="talk" name="talk" checked="checked"><label for="talk">Nextcloud Talk (needs ports 3478/TCP and 3478/UDP open in your firewall/router)</label><br><br>
|
||||
{% else %}
|
||||
<input type="checkbox" id="talk" name="talk"><label for="talk">Nextcloud Talk (needs ports 3478/TCP and 3478/UDP open in your firewall/router)</label><br><br>
|
||||
{% endif %}
|
||||
{% if is_onlyoffice_enabled == true %}
|
||||
<input type="checkbox" id="onlyoffice" name="onlyoffice" checked="checked"><label for="onlyoffice">OnlyOffice (only supported on x64)</label><br>
|
||||
{% else %}
|
||||
<input type="checkbox" id="onlyoffice" name="onlyoffice"><label for="onlyoffice">OnlyOffice (only supported on x64)</label><br>
|
||||
{% endif %}
|
||||
<input id="options-form-submit" class="button" type="submit" value="Save changes" />
|
||||
</form>
|
||||
{% if isAnyRunning == true or is_x64_platform == false %}
|
||||
<script type="text/javascript" src="disable-clamav.js"></script>
|
||||
<script type="text/javascript" src="disable-onlyoffice.js"></script>
|
||||
{% endif %}
|
||||
{% if isAnyRunning == true %}
|
||||
<script type="text/javascript" src="disable-talk.js"></script>
|
||||
<script type="text/javascript" src="disable-collabora.js"></script>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if isApacheStarting == true or isBackupContainerRunning == true or isWatchtowerRunning == true %}
|
||||
<script>
|
||||
if (document.hasFocus()) {
|
||||
// hide reload button if the site reloads automatically
|
||||
var list = document.getElementsByClassName("reload button");
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
// list[i] is a node with the desired class name
|
||||
list[i].style.display = 'none';
|
||||
}
|
||||
|
||||
// set timeout for reload
|
||||
setTimeout(function(){
|
||||
window.location.reload(1);
|
||||
}, 5000);
|
||||
}
|
||||
</script>
|
||||
{% if isApacheStarting == true or is_backup_container_running == true or isWatchtowerRunning == true %}
|
||||
<script type="text/javascript" src="automatic_reload.js"></script>
|
||||
{% else %}
|
||||
<script type="text/javascript" src="before-unload.js"></script>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<link rel="stylesheet" href="/style.css" media="all" />
|
||||
<link rel="icon" href="/img/favicon.png">
|
||||
<script type="text/javascript" src="forms.js"></script>
|
||||
<script type="text/javascript" src="options-form-submit.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<img src="/img/logo-blue.svg" style="margin-left: auto;margin-right: auto;display: block;">
|
||||
<h1>Your password for Nextcloud AIO Beta</h1>
|
||||
<p>Please note down the password to access the AIO interface and don't loose it!</p>
|
||||
<p>Nextcloud AIO stands for Nextcloud All In One and provides easy deployment and maintenance with most features included in this one Nextcloud instance.</p>
|
||||
<strong>Password</strong><br/> <span class="monospace">{{ password }}</span><br>
|
||||
<a href="/" class="button" target="_blank" rel="noopener">Open Nextcloud AIO login ↗</a>
|
||||
</div>
|
||||
|
||||
88
readme.md
88
readme.md
@@ -15,26 +15,14 @@ Included are:
|
||||
**Found a bug?** Please file an issue at https://github.com/nextcloud/all-in-one
|
||||
|
||||
## How to use this?
|
||||
The following instructions are especially meant for Linux. For macOS see [this](#how-to-run-it-on-macos), for Windows see [this](#how-to-run-it-on-windows).
|
||||
1. Install Docker on your Linux installation using:
|
||||
```
|
||||
curl -fsSL get.docker.com | sudo sh
|
||||
```
|
||||
2. Make sure to pull the latest image:
|
||||
```
|
||||
# For x64 CPUs:
|
||||
sudo docker pull nextcloud/all-in-one:latest
|
||||
```
|
||||
<details>
|
||||
<summary>Command for arm64 CPUs like the Raspberry Pi 4</summary>
|
||||
|
||||
```
|
||||
# For arm64 CPUs:
|
||||
sudo docker pull nextcloud/all-in-one:latest-arm64
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
3. Run the following command in order to start the container:
|
||||
2. Run the following command in order to start the container:<br>
|
||||
(For people that cannot use ports 80 and/or 443 on this server, please follow [this documentation](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md). Otherwise please run the command below!)
|
||||
```
|
||||
# For x64 CPUs:
|
||||
sudo docker run -it \
|
||||
@@ -65,11 +53,11 @@ Included are:
|
||||
|
||||
</details>
|
||||
|
||||
4. After the initial startup, you should be able to open the Nextcloud AIO Interface now on port 8080 of this server.<br>
|
||||
3. After the initial startup, you should be able to open the Nextcloud AIO Interface now on port 8080 of this server.<br>
|
||||
E.g. `https://internal.ip.of.this.server:8080`<br>
|
||||
If your server has port 80 and 8443 open and you point a domain to your server, you can get a valid certificate automatially by opening the Nextcloud AIO Interface via:<br>
|
||||
If your firewall/router has port 80 and 8443 open and you point a domain to your server, you can get a valid certificate automatially by opening the Nextcloud AIO Interface via:<br>
|
||||
`https://your-domain-that-points-to-this-server.tld:8443`
|
||||
5. Please do not forget to open port `3478/TCP` and `3478/UDP` for the Talk container!
|
||||
4. Please do not forget to open port `3478/TCP` and `3478/UDP` in your firewall/router for the Talk container!
|
||||
|
||||
## FAQ
|
||||
### How does it work?
|
||||
@@ -78,7 +66,7 @@ Nextcloud AIO is inspired by projects like Portainer that allow to manage the do
|
||||
### Are reverse proxies supported?
|
||||
Yes. Please refer to the following documentation on this: [reverse-proxy.md](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md)
|
||||
|
||||
### Which ports are mandatory to be open?
|
||||
### Which ports are mandatory to be open in your firewall/router?
|
||||
Only those (if you acces the Mastercontainer Interface internally via port 8080):
|
||||
- `443/TCP` for the Apache container
|
||||
- `3478/TCP` and `3478/UDP` for the Talk container
|
||||
@@ -86,9 +74,31 @@ Only those (if you acces the Mastercontainer Interface internally via port 8080)
|
||||
### Explanation of used ports:
|
||||
- `8080/TCP`: Mastercontainer Interface with self-signed certificate (works always, also if only access via IP-address is possible, e.g. `https://internal.ip.address:8080/`)
|
||||
- `80/TCP`: redirects to Nextcloud (is used for getting the certificate via ACME http-challenge for the Mastercontainer)
|
||||
- `8443/TCP`: Mastercontainer Interface with valid certificate (only works if port 80 and 8443 are open and you point a domain to your server. It generates a valid certificate then automatically and access via e.g. `https://public.domain.com:8443/` is possible.)
|
||||
- `443/TCP`: will be used by the Apache container later on and needs to be open
|
||||
- `3478/TCP` and `3478/UDP`: will be used by the Turnserver inside the Talk container and needs to be open
|
||||
- `8443/TCP`: Mastercontainer Interface with valid certificate (only works if port 80 and 8443 are open in your firewall/router and you point a domain to your server. It generates a valid certificate then automatically and access via e.g. `https://public.domain.com:8443/` is possible.)
|
||||
- `443/TCP`: will be used by the Apache container later on and needs to be open in your firewall/router
|
||||
- `3478/TCP` and `3478/UDP`: will be used by the Turnserver inside the Talk container and needs to be open in your firewall/router
|
||||
|
||||
### How to run it on macOS?
|
||||
On macOS, there is one specialty in comparison to Linux: instead of using `--volume /var/run/docker.sock:/var/run/docker.sock:ro`, you need to use `--volume /var/run/docker.sock.raw:/var/run/docker.sock:ro` to run it after you installed [Docker Desktop](https://www.docker.com/products/docker-desktop/). Apart from that it should work and behave the same like on Linux.
|
||||
|
||||
### How to run it on Windows?
|
||||
On Windows, the following command should work after you installed [Docker Desktop](https://www.docker.com/products/docker-desktop/):
|
||||
<details>
|
||||
<summary>Click here to show it</summary>
|
||||
|
||||
```
|
||||
docker run -it ^
|
||||
--name nextcloud-aio-mastercontainer ^
|
||||
--restart always ^
|
||||
-p 80:80 ^
|
||||
-p 8080:8080 ^
|
||||
-p 8443:8443 ^
|
||||
--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config ^
|
||||
--volume //var/run/docker.sock:/var/run/docker.sock:ro ^
|
||||
nextcloud/all-in-one:latest
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### How to run `occ` commands?
|
||||
Simply run the following: `sudo docker exec -it nextcloud-aio-nextcloud php occ your-command`. Of course `your-command` needs to be exchanged with the command that you want to run.
|
||||
@@ -104,7 +114,7 @@ If a new `Mastercontainer` update was found, you'll see an additional section be
|
||||
Additionally, there is a cronjob that runs once a day that checks for container and mastercontainer updates and sends a notification to all Nextcloud admins if a new update was found.
|
||||
|
||||
### How to easily log in to the AIO interface?
|
||||
If your Nextcloud is running and you are logged in as admin in your Nextcloud, you can easily log in to the AIO interface by opening `https://yourdomain.tld/settings/admin/overview` which will show a button on top that enables you to log in to the AIO interface by just clicking on this button.
|
||||
If your Nextcloud is running and you are logged in as admin in your Nextcloud, you can easily log in to the AIO interface by opening `https://yourdomain.tld/settings/admin/overview` which will show a button on top that enables you to log in to the AIO interface by just clicking on this button. **Note:** You can change the domain/ip-address/port of the button by simply stopping the containers, visiting the AIO interface from the correct and desired domain/ip-address/port and clicking once on `Start containers`.
|
||||
|
||||
### Backup solution
|
||||
Nextcloud AIO provides a local backup solution based on BorgBackup. These backups act as a local restore point in case the installation gets corrupted.
|
||||
@@ -113,6 +123,19 @@ It is recommended to create a backup before any container update. By doing this,
|
||||
|
||||
If you connect an external drive to your host, and choose the backup directory to be on that drive, you are also kind of save against drive failures of the drive where the docker volumes are stored on.
|
||||
|
||||
<details>
|
||||
<summary>How to do the above step for step</summary>
|
||||
|
||||
<br>
|
||||
|
||||
1. Mount an external/backup HDD to the host OS using the built-in functionality or udev rules or whatever way you prefer. (E.g. follow this video: https://www.youtube.com/watch?v=2lSyX4D3v_s) and mount the drive in best case in `/mnt/backup`.
|
||||
2. If not already done, fire up the docker container and set up Nextcloud as per the guide.
|
||||
3. Now open the AIO interface.
|
||||
4. Under backup section, add your external disk mountpoint as backup directory, e.g. `/mnt/backup`.
|
||||
5. Click on `Create Backup` which should create the first backup on the external disk.
|
||||
|
||||
</details>
|
||||
|
||||
Backups can be created and restored in the AIO interface using the buttons `Create Backup` and `Restore selected backup`. Additionally, a backup check is provided that checks the integrity of your backups but it shouldn't be needed in most situations.
|
||||
|
||||
The backups itself get encrypted with an encryption key that gets shown to you in the AIO interface. Please save that at a safe place as you will not be able to restore from backup without this key.
|
||||
@@ -200,6 +223,11 @@ if ! [ -d "$SOURCE_DIRECTORY" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$(ls -A "$SOURCE_DIRECTORY/")" ]; then
|
||||
echo "The source directory is empty which is not allowed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -d "$DRIVE_MOUNTPOINT" ]; then
|
||||
echo "The drive mountpoint must be an existing directory"
|
||||
exit 1
|
||||
@@ -235,13 +263,13 @@ if ! rsync --stats --archive --human-readable --delete "$SOURCE_DIRECTORY/" "$TA
|
||||
fi
|
||||
|
||||
umount "$DRIVE_MOUNTPOINT"
|
||||
if mountpoint -q "$DRIVE_MOUNTPOINT"; then
|
||||
echo "Synced the backup repository successfully but failed to unmount the target drive."
|
||||
exit 0
|
||||
|
||||
if docker ps --format "{{.Names}}" | grep "^nextcloud-aio-nextcloud$"; then
|
||||
docker exec -it nextcloud-aio-nextcloud bash /notify.sh "Rsync backup successful!" "Synced the backup repository successfully."
|
||||
else
|
||||
echo "Synced the backup repository successfully."
|
||||
fi
|
||||
|
||||
echo "Synced the backup repository successfully and unmounted the target drive."
|
||||
exit 0
|
||||
```
|
||||
|
||||
</details>
|
||||
@@ -251,10 +279,10 @@ You can simply copy and past the script into a file e.g. named `backup-script.sh
|
||||
Afterwards apply the correct permissions with `sudo chown root:root /root/backup-script.sh` and `sudo chmod 700 /root/backup-script.sh`. Then you can create a cronjob that runs e.g. at `20:00` each week on sundays like this: `crontab -u root -l | { cat; echo "0 20 * * 7 /root/backup-script.sh"; } | crontab -u root -`. Make sure that it does not collidate with the daily backups from AIO (if configured) since the target backup repository might get into an inconsistent state. (There is no check in place that checks this.)
|
||||
|
||||
### How to change the default location of Nextcloud's Datadir?
|
||||
You can configure the Nextcloud container to use a specific directory on your host as data directory. You can do so by adding the environmental variable `NEXTCLOUD_DATADIR` to the initial startup of the mastercontainer. Allowed values for that variable are strings that start with `/mnt/` or `/media/`. An example for this is `-e NEXTCLOUD_DATADIR="/mnt/ncdata"`. Please make sure to apply the correct permissions to the chosen directory before starting Nextcloud the first time. In this example would the command for this be: `sudo chown -R 33:0 /mnt/ncdata`. **Attention:** It is very important to change the datadir **before** Nextcloud is installed/started the first time and not to change it afterwards!
|
||||
You can configure the Nextcloud container to use a specific directory on your host as data directory. You can do so by adding the environmental variable `NEXTCLOUD_DATADIR` to the initial startup of the mastercontainer. Allowed values for that variable are strings that start with `/mnt/`, `/media/` or `/host_mnt/`. An example for Linux and macOS is `-e NEXTCLOUD_DATADIR="/mnt/ncdata"`. On Windows it might be `-e NEXTCLOUD_DATADIR="/host_mnt/c/your/data/path"` (This Windows example would be equivalent to `C:\your\data\path` on the Windows host. So you need to translate the path that you want to use into the correct format.) Please make sure to apply the correct permissions to the chosen directory before starting Nextcloud the first time (not needed on Windows). In this example would the command for this be: `sudo chown -R 33:0 /mnt/ncdata`. ⚠ **Attention:** It is very important to change the datadir **before** Nextcloud is installed/started the first time and not to change it afterwards!
|
||||
|
||||
### How to allow the Nextcloud container to access directories on the host?
|
||||
By default, the Nextcloud container is confined and cannot access directories on the host OS. You might want to change this when you are planning to use local external storage in Nextcloud to store some files outside the data directory and can do so by adding the environmental variable `NEXTCLOUD_MOUNT` to the initial startup of the mastercontainer. Allowed values for that variable are strings that are equal to or start with `/mnt/` or `/media/` or are equal to `/var/backups` and unequal to `/mnt/ncdata`. Two examples for this are: `-e NEXTCLOUD_MOUNT="/mnt/"` or `-e NEXTCLOUD_MOUNT="/media/"`. After doing so, please make sure to apply the correct permissions to the directories that you want to use in Nextcloud. E.g. `sudo chown -R 33:0 /mnt/your-drive-mountpoint` should make it work. You can then navigate to the apps management page, activate the external storage app, navigate to `https://your-nc-domain.com/settings/admin/externalstorages` and add a local external storage directory that will be accessible inside the container at the same place that you've entered. E.g. `/mnt/your-drive-mountpoint` will be mounted to `/mnt/your-drive-mountpoint` inside the container, etc. Be aware though that these locations will not be covered by the built-in backup solution!
|
||||
By default, the Nextcloud container is confined and cannot access directories on the host OS. You might want to change this when you are planning to use local external storage in Nextcloud to store some files outside the data directory and can do so by adding the environmental variable `NEXTCLOUD_MOUNT` to the initial startup of the mastercontainer. Allowed values for that variable are strings that are equal to or start with `/mnt/`, `/media/` or `/host_mnt/` or are equal to `/var/backups` and unequal to `/mnt/ncdata`. Two examples for Linux and macOS are: `-e NEXTCLOUD_MOUNT="/mnt/"` or `-e NEXTCLOUD_MOUNT="/media/"`. On Windows it might be `-e NEXTCLOUD_DATADIR="/host_mnt/c"` (This Windows example would be equivalent to `C:\` on the Windows host. So you need to translate the path that you want to use into the correct format.) After using this option, please make sure to apply the correct permissions to the directories that you want to use in Nextcloud (not needed on Windows). E.g. `sudo chown -R 33:0 /mnt/your-drive-mountpoint` should make it work. You can then navigate to the apps management page, activate the external storage app, navigate to `https://your-nc-domain.com/settings/admin/externalstorages` and add a local external storage directory that will be accessible inside the container at the same place that you've entered. E.g. `/mnt/your-drive-mountpoint` will be mounted to `/mnt/your-drive-mountpoint` inside the container, etc. Be aware though that these locations will not be covered by the built-in backup solution!
|
||||
|
||||
### Huge docker logs
|
||||
When your containers run for a few days without a restart, the container logs that you can view from the AIO interface can get really huge. You can limit the loge sizes by enabling logrotate for docker container logs. Feel free to enable this by following those instructions: https://sandro-keil.de/blog/logrotate-for-docker-container/
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
## Reverse Proxy Config
|
||||
## Reverse Proxy Documentation
|
||||
|
||||
Basically, you need to specify the port that the apache container shall use and modify the startup command a bit.
|
||||
|
||||
All examples below will use port `11000` as example apache port. Also it is supposed that the reverse proxy runs on the same server like AIO, hence `localhost` is used and not an internal ip-address to point to the AIO instance. Modify both to your needings.
|
||||
|
||||
### Caddy reverse proxy config example
|
||||
### Reverse proxy config examples
|
||||
|
||||
#### Caddy
|
||||
|
||||
<details>
|
||||
|
||||
<summary>click here to expand</summary>
|
||||
<br>
|
||||
Add this to your Caddyfile:
|
||||
|
||||
```
|
||||
@@ -17,8 +23,38 @@ https://<your-nc-domain>:443 {
|
||||
|
||||
Of course you need to modify `<your-nc-domain>` to the domain on which you want to run Nextcloud.
|
||||
|
||||
</details>
|
||||
|
||||
#### Nginx
|
||||
|
||||
<details>
|
||||
|
||||
<summary>click here to expand</summary>
|
||||
<br>
|
||||
Add this to you nginx config:
|
||||
|
||||
```
|
||||
location / {
|
||||
proxy_pass http://localhost:11000;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# Websocket
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
}
|
||||
```
|
||||
|
||||
Of course SSL needs to be set up as well e.g. by using certbot and your domain must be also added inside the nginx config.
|
||||
|
||||
</details>
|
||||
|
||||
### Startup command
|
||||
|
||||
After adjusting your reverse proxy config, use the following command to start AIO:
|
||||
|
||||
```
|
||||
# For x64 CPUs:
|
||||
sudo docker run -it \
|
||||
@@ -49,7 +85,26 @@ nextcloud/all-in-one:latest-arm64
|
||||
|
||||
</details>
|
||||
|
||||
After doing so, you should be able to access the AIO Interface via `https://internal.ip.of.this.server:8080`. Enter your domain that you've entered in the reverse proxy config and you should be done. Please do not forget to open port `3478/TCP` and `3478/UDP` for the Talk container!
|
||||
On macOS see https://github.com/nextcloud/all-in-one#how-to-run-it-on-macos.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Command for Windows</summary>
|
||||
|
||||
```
|
||||
docker run -it ^
|
||||
--name nextcloud-aio-mastercontainer ^
|
||||
--restart always ^
|
||||
-p 8080:8080 ^
|
||||
-e APACHE_PORT=11000 ^
|
||||
--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config ^
|
||||
--volume //var/run/docker.sock:/var/run/docker.sock:ro ^
|
||||
nextcloud/all-in-one:latest
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
After doing so, you should be able to access the AIO Interface via `https://internal.ip.of.this.server:8080`. Enter your domain that you've entered in the reverse proxy config and you should be done. Please do not forget to open port `3478/TCP` and `3478/UDP` in your firewall/router for the Talk container!
|
||||
|
||||
### Optional
|
||||
|
||||
@@ -65,4 +120,4 @@ https://<your-nc-domain>:8443 {
|
||||
}
|
||||
```
|
||||
|
||||
Of course you also need to modify `<your-nc-domain>` to the domain that you want to use. Afterwards should the AIO interface be accessible via `https://<your-nc-domain>:8443`.
|
||||
Of course, you also need to modify `<your-nc-domain>` to the domain that you want to use. Afterwards should the AIO interface be accessible via `https://<your-nc-domain>:8443`. You can alternatively change the domain to a different subdomain by using `https://<your-alternative-domain>:443` in the Caddyfile and use that to access the AIO interface.
|
||||
|
||||
Reference in New Issue
Block a user