mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-05-21 19:00:33 +00:00
Compare commits
285 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 | ||
|
|
85b445d576 | ||
|
|
52651559de | ||
|
|
36fd28da6f | ||
|
|
77979aaa4a | ||
|
|
5f753665ac | ||
|
|
e7ec998913 | ||
|
|
91c7f13171 | ||
|
|
d170feb1e7 | ||
|
|
1a55b94b93 | ||
|
|
a0656364b1 | ||
|
|
20c46a3809 | ||
|
|
866519be88 | ||
|
|
cfc157f672 | ||
|
|
8b813fe950 | ||
|
|
c1a5262769 | ||
|
|
5b8de658c7 | ||
|
|
0b51eab553 | ||
|
|
c8854ab1e3 | ||
|
|
7a18cf766d | ||
|
|
213de472a6 | ||
|
|
c9be73601d | ||
|
|
e2a6231257 | ||
|
|
b929d57a77 | ||
|
|
0168b29882 | ||
|
|
8836a884fb | ||
|
|
6adae6db3e | ||
|
|
0071703a24 | ||
|
|
3af23d5a5c | ||
|
|
17eb732a89 | ||
|
|
68ddc72e9b | ||
|
|
a03478c5d0 | ||
|
|
6e8aea3aeb | ||
|
|
2caa883453 | ||
|
|
1edcc4ef5f | ||
|
|
10f62ac401 | ||
|
|
f8f50e9186 | ||
|
|
a3e3dd4534 | ||
|
|
a6286a291f | ||
|
|
2dbd3a5f71 | ||
|
|
c1e2446d22 | ||
|
|
6232000e31 | ||
|
|
7c20d54dd0 | ||
|
|
8ce55a1334 | ||
|
|
853a880c9d | ||
|
|
0ecd2c8f78 | ||
|
|
24d1451325 | ||
|
|
8149c0de75 | ||
|
|
34660f3d17 | ||
|
|
d360031f12 | ||
|
|
efde2ab41a | ||
|
|
a89c183508 | ||
|
|
301b6e6297 | ||
|
|
6e839f5baf | ||
|
|
edb8bd228b | ||
|
|
23429f3e59 | ||
|
|
f4130a8475 | ||
|
|
e5aa3757d5 | ||
|
|
12f1549221 | ||
|
|
d34167b30f | ||
|
|
5e0118a3b5 | ||
|
|
220194b409 | ||
|
|
2943c6cf08 | ||
|
|
2040553822 | ||
|
|
d1656a0fcb | ||
|
|
6e9261f306 | ||
|
|
269f62615f | ||
|
|
704c4ad331 | ||
|
|
9afec142f3 | ||
|
|
9fbcaae567 | ||
|
|
82c371b519 | ||
|
|
2afc711983 | ||
|
|
a42f21555a | ||
|
|
d6ece6cad8 | ||
|
|
6f1da5fc5d | ||
|
|
2024cb8f26 | ||
|
|
1c01e9e21f | ||
|
|
628e55f076 | ||
|
|
5b49faf3b7 | ||
|
|
33a73a7b95 | ||
|
|
e2086ada2b | ||
|
|
c15bc86e06 | ||
|
|
ccc80c44cc | ||
|
|
d12df52864 | ||
|
|
5ed19687e2 | ||
|
|
af93aeebd7 | ||
|
|
aa366556f5 | ||
|
|
a88000095a | ||
|
|
15e914e3f4 | ||
|
|
472334948c | ||
|
|
663901cacd | ||
|
|
6f0e4dc175 | ||
|
|
b0894992b4 | ||
|
|
748dcea39e | ||
|
|
5b278ca261 | ||
|
|
d988706ae0 | ||
|
|
73193ee2d5 | ||
|
|
e955b0a96f | ||
|
|
11edcfe142 | ||
|
|
c779c91ef6 | ||
|
|
3b177a5f55 | ||
|
|
72f7106911 | ||
|
|
cbfe9c1907 | ||
|
|
db12a9a90b | ||
|
|
c777971906 | ||
|
|
0b8caa8cea | ||
|
|
eafe011ae9 | ||
|
|
bc50b0cc4f | ||
|
|
a2f60ba765 | ||
|
|
487688d000 | ||
|
|
30e2c6be25 | ||
|
|
777666cf11 | ||
|
|
221ab2515d | ||
|
|
ac3b8bc963 | ||
|
|
1df46bb805 | ||
|
|
89830a1b81 | ||
|
|
48e60872b3 | ||
|
|
9d9da9e47c | ||
|
|
3a9c305758 | ||
|
|
8f1fcde006 | ||
|
|
8a6de8f63c | ||
|
|
0880aff7ea | ||
|
|
2c3db2fd40 | ||
|
|
e357fc8bb9 | ||
|
|
a82b86b915 | ||
|
|
67705134cf | ||
|
|
ce15c64cd9 | ||
|
|
92492affe4 | ||
|
|
63e0849215 | ||
|
|
1515d0c210 | ||
|
|
4359792a48 | ||
|
|
3887275808 | ||
|
|
badd8d02a9 | ||
|
|
5bc10a56ed | ||
|
|
222dcd3317 | ||
|
|
cec86aa825 | ||
|
|
e7dfb2514b | ||
|
|
b0e570176b | ||
|
|
7756826eb3 | ||
|
|
836552e1a7 | ||
|
|
6e22b364ae | ||
|
|
4979d1d90e | ||
|
|
3029b277f1 |
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
|
||||
128
.github/dependabot.yml
vendored
128
.github/dependabot.yml
vendored
@@ -1,12 +1,132 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
- package-ecosystem: composer
|
||||
directory: "/php/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: saturday
|
||||
time: "03:00"
|
||||
timezone: Europe/Paris
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/apache"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/borgbackup"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/collabora"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/domaincheck"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/mastercontainer"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
ignore:
|
||||
- dependency-name: "php"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/nextcloud"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
ignore:
|
||||
- dependency-name: "php"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/postgresql"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
ignore:
|
||||
- dependency-name: "postgres"
|
||||
update-types: ["version-update:semver-major"]
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/redis"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/talk"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 3. to review
|
||||
- dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/Containers/watchtower"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "12:00"
|
||||
open-pull-requests-limit: 10
|
||||
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
|
||||
|
||||
54
.github/workflows/create-psalm-container.yml
vendored
Normal file
54
.github/workflows/create-psalm-container.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
name: Create Psalm Container
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '5 4 * * *'
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: Create Psalm Container
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
run: |
|
||||
git clone https://github.com/psalm/psalm-github-actions.git
|
||||
|
||||
- name: Modify the Dockerfile
|
||||
run: |
|
||||
set -x
|
||||
sed -i 's|FROM php:7.4-alpine|FROM php:8.0-alpine|' "psalm-github-actions/Dockerfile"
|
||||
cat << APCU >> "psalm-github-actions/Dockerfile"
|
||||
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
|
||||
APCU
|
||||
|
||||
- name: Log in to GitHub Docker Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: docker.pkg.github.com
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build container image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
context: 'psalm-github-actions'
|
||||
file: 'psalm-github-actions/Dockerfile'
|
||||
tags: |
|
||||
ghcr.io/nextcloud/all-in-one-psalm:latest
|
||||
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
|
||||
|
||||
18
.github/workflows/psalm-analysis.yml
vendored
Normal file
18
.github/workflows/psalm-analysis.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Psalm Analysis
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
psalm:
|
||||
name: Psalm
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Psalm
|
||||
uses: docker://ghcr.io/nextcloud/all-in-one-psalm
|
||||
with:
|
||||
composer_ignore_platform_reqs: false
|
||||
relative_dir: php
|
||||
25
.github/workflows/psalm-security.yml
vendored
Normal file
25
.github/workflows/psalm-security.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Psalm Security Analysis
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
psalm:
|
||||
name: Psalm
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Psalm
|
||||
uses: docker://ghcr.io/nextcloud/all-in-one-psalm
|
||||
with:
|
||||
relative_dir: php
|
||||
security_analysis: true
|
||||
composer_ignore_platform_reqs: false
|
||||
report_file: results.sarif
|
||||
- name: Upload Security Analysis results to GitHub
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
sarif_file: php/results.sarif
|
||||
48
.github/workflows/psalm-update-baseline.yml
vendored
Normal file
48
.github/workflows/psalm-update-baseline.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Update Psalm baseline
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '5 4 * * *'
|
||||
|
||||
jobs:
|
||||
update-psalm-baseline:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up php8.0
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.0
|
||||
extensions: apcu
|
||||
coverage: none
|
||||
|
||||
- name: Run script
|
||||
run: |
|
||||
set -x
|
||||
cd php
|
||||
composer global require vimeo/psalm --prefer-dist --no-progress --dev
|
||||
composer install
|
||||
composer run psalm -- --monochrome --no-progress --output-format=text --update-baseline
|
||||
git clean -f lib/composer
|
||||
git checkout composer.json composer.lock lib/composer
|
||||
continue-on-error: true
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
commit-message: Update psalm baseline
|
||||
committer: GitHub <noreply@github.com>
|
||||
author: nextcloud-command <nextcloud-command@users.noreply.github.com>
|
||||
signoff: true
|
||||
branch: automated/noid/psalm-baseline-update
|
||||
# Make sure we can open multiple PRs
|
||||
branch-suffix: timestamp
|
||||
title: '[Automated] Update psalm-baseline.xml'
|
||||
body: |
|
||||
Auto-generated update psalm-baseline.xml with fixed psalm warnings
|
||||
labels: |
|
||||
3. to review
|
||||
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:
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
https://{$NC_DOMAIN}:443 {
|
||||
{$PROTOCOL}://{$NC_DOMAIN}:{$APACHE_PORT} {
|
||||
|
||||
# Notify Push
|
||||
route /push/* {
|
||||
@@ -22,24 +22,20 @@ https://{$NC_DOMAIN}:443 {
|
||||
|
||||
# Collabora
|
||||
route /browser/* {
|
||||
reverse_proxy https://{$COLLABORA_HOST}:9980 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
reverse_proxy {$COLLABORA_HOST}:9980
|
||||
}
|
||||
route /hosting/* {
|
||||
reverse_proxy https://{$COLLABORA_HOST}:9980 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
reverse_proxy {$COLLABORA_HOST}:9980
|
||||
}
|
||||
route /cool/* {
|
||||
reverse_proxy https://{$COLLABORA_HOST}:9980 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
FROM debian:bullseye-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 \
|
||||
@@ -59,7 +60,8 @@ COPY start.sh /usr/bin/
|
||||
COPY supervisord.conf /
|
||||
RUN chmod +x /usr/bin/start.sh; \
|
||||
chmod +r /supervisord.conf; \
|
||||
chmod +r /Caddyfile;
|
||||
chmod a+w /Caddyfile; \
|
||||
chmod a+w /
|
||||
|
||||
# Give root a random password
|
||||
RUN echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||
|
||||
@@ -17,11 +17,18 @@ 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
|
||||
|
||||
if [ "$APACHE_PORT" != '443' ]; then
|
||||
export PROTOCOL="http"
|
||||
export NC_DOMAIN=""
|
||||
sed -i 's|auto_https.*|auto_https off|' /Caddyfile
|
||||
else
|
||||
export PROTOCOL="https"
|
||||
sed -i 's|auto_https.*|auto_https disable_redirects|' /Caddyfile
|
||||
fi
|
||||
|
||||
# Add caddy path
|
||||
mkdir -p /mnt/data/caddy/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:bullseye-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/*
|
||||
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Variables
|
||||
BORG_BACKUP_DIRECTORY="/mnt/borgbackup/borg"
|
||||
|
||||
# Functions
|
||||
get_start_time(){
|
||||
START_TIME=$(date +%s)
|
||||
CURRENT_DATE=$(date --date @"$START_TIME" +"%Y%m%d_%H%M%S")
|
||||
CURRENT_DATE_READABLE=$(date --date @"$START_TIME" +"%d.%m.%Y - %H:%M:%S")
|
||||
}
|
||||
get_expiration_time() {
|
||||
END_TIME=$(date +%s)
|
||||
@@ -19,11 +15,6 @@ get_expiration_time() {
|
||||
DURATION_READABLE=$(printf "%02d hours %02d minutes %02d seconds" $DURATION_HOUR $DURATION_MIN $DURATION_SEC)
|
||||
}
|
||||
|
||||
# Export defaults
|
||||
export BORG_PASSPHRASE="$BORG_PASSWORD"
|
||||
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
|
||||
export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes
|
||||
|
||||
# Test if all volumes aren't empty
|
||||
VOLUME_DIRS="$(find /nextcloud_aio_volumes -mindepth 1 -maxdepth 1 -type d)"
|
||||
mapfile -t VOLUME_DIRS <<< "$VOLUME_DIRS"
|
||||
@@ -41,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
|
||||
@@ -150,9 +141,6 @@ if [ "$BORG_MODE" = backup ]; then
|
||||
# Remove the update skip file because the backup was successful
|
||||
rm -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data/skip.update"
|
||||
|
||||
echo "$CURRENT_DATE,$CURRENT_DATE_READABLE" >> "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
|
||||
chmod +r "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
|
||||
|
||||
# Prune options
|
||||
BORG_PRUNE_OPTS=(--stats --progress --keep-within=7d --keep-weekly=4 --keep-monthly=6 "$BORG_BACKUP_DIRECTORY")
|
||||
|
||||
@@ -172,27 +160,59 @@ fi
|
||||
# Do the restore
|
||||
if [ "$BORG_MODE" = restore ]; then
|
||||
get_start_time
|
||||
echo "Restoring the last backup..."
|
||||
|
||||
# Perform the restore
|
||||
FIRST_ARCHIVE="$(borg list "$BORG_BACKUP_DIRECTORY" | grep "nextcloud-aio" | awk -F " " '{print $1}' | sort -r | head -1)"
|
||||
if [ -n "$SELECTED_RESTORE_TIME" ]; then
|
||||
SELECTED_ARCHIVE="$(borg list "$BORG_BACKUP_DIRECTORY" | grep "nextcloud-aio" | grep "$SELECTED_RESTORE_TIME" | awk -F " " '{print $1}' | head -1)"
|
||||
else
|
||||
SELECTED_ARCHIVE="$(borg list "$BORG_BACKUP_DIRECTORY" | grep "nextcloud-aio" | awk -F " " '{print $1}' | sort -r | head -1)"
|
||||
fi
|
||||
echo "Restoring '$SELECTED_ARCHIVE'..."
|
||||
mkdir -p /tmp/borg
|
||||
if ! borg mount "$BORG_BACKUP_DIRECTORY::$FIRST_ARCHIVE" /tmp/borg; then
|
||||
if ! borg mount "$BORG_BACKUP_DIRECTORY::$SELECTED_ARCHIVE" /tmp/borg; 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/data/backup_archives.list" \
|
||||
--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
|
||||
@@ -201,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
|
||||
@@ -224,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
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Variables
|
||||
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 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
|
||||
|
||||
@@ -24,6 +34,12 @@ fi
|
||||
# Remove lockfile
|
||||
rm -f "/nextcloud_aio_volumes/nextcloud_aio_database_dump/backup-is-running"
|
||||
|
||||
# Get a list of all available borg archives
|
||||
set -x
|
||||
borg list "$BORG_BACKUP_DIRECTORY" | grep "nextcloud-aio" | awk -F " " '{print $1","$3,$4}' > "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
|
||||
chmod +r "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
|
||||
set +x
|
||||
|
||||
if [ -n "$FAILED" ]; then
|
||||
if [ "$BORG_MODE" = backup ]; then
|
||||
# Add file to Nextcloud container so that it skips any update the next time
|
||||
|
||||
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:latest
|
||||
FROM collabora/code:21.11.3.4.1
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine
|
||||
FROM alpine:3.15.3
|
||||
RUN apk add --update --no-cache lighttpd bash
|
||||
|
||||
RUN adduser -S www-data -G www-data
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
server.document-root = "/var/www/domaincheck/"
|
||||
|
||||
server.port = 443
|
||||
server.port = env.APACHE_PORT
|
||||
|
||||
server.username = "www-data"
|
||||
server.groupname = "www-data"
|
||||
|
||||
@@ -7,6 +7,10 @@ fi
|
||||
|
||||
echo "$INSTANCE_ID" > /var/www/domaincheck/index.html
|
||||
|
||||
if [ -z "$APACHE_PORT" ]; then
|
||||
export APACHE_PORT="443"
|
||||
fi
|
||||
|
||||
# Check config file
|
||||
lighttpd -tt -f /etc/lighttpd/lighttpd.conf
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Docker CLI is a requirement
|
||||
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-apache-bullseye
|
||||
FROM php:8.0.17-apache-bullseye
|
||||
|
||||
EXPOSE 80
|
||||
EXPOSE 8080
|
||||
@@ -23,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=docker:dind /usr/local/bin/docker /usr/local/bin/
|
||||
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 && \
|
||||
|
||||
@@ -6,5 +6,7 @@ while true; do
|
||||
sudo -u www-data php /var/www/docker-aio/php/src/Cron/cron.php
|
||||
# Remove dangling images
|
||||
sudo -u www-data docker image prune -f
|
||||
# Remove sessions older than 24h
|
||||
find "/mnt/docker-aio-config/session/" -mindepth 1 -mmin +1440 -delete
|
||||
sleep 1d
|
||||
done
|
||||
|
||||
@@ -6,6 +6,14 @@ print_green() {
|
||||
printf "%b%s%b\n" "\e[0;92m" "$TEXT" "\e[0m"
|
||||
}
|
||||
|
||||
# Function to check if number was provided
|
||||
check_if_number() {
|
||||
case "${1}" in
|
||||
''|*[!0-9]*) return 1 ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Check if socket is available and readable
|
||||
if ! [ -a "/var/run/docker.sock" ]; then
|
||||
echo "Docker socket is not available. Cannot continue."
|
||||
@@ -35,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
|
||||
@@ -43,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."
|
||||
@@ -54,6 +62,60 @@ else
|
||||
sleep 10
|
||||
fi
|
||||
|
||||
# Check if startup command was executed correctly
|
||||
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 ! 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
|
||||
|
||||
# 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 "^/host_mnt/"
|
||||
then
|
||||
echo "You've set NEXTCLOUD_DATADIR but not to an allowed value.
|
||||
The string must start with '/mnt/', '/media/' or '/host_mnt/'. E.g. '/mnt/ncdata'"
|
||||
exit 1
|
||||
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/', '/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/', '/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."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -n "$NEXTCLOUD_DATADIR" ] && [ -n "$NEXTCLOUD_MOUNT" ]; then
|
||||
if [ "$NEXTCLOUD_DATADIR" = "$NEXTCLOUD_MOUNT" ]; then
|
||||
echo "NEXTCLOUD_DATADIR and NEXTCLOUD_MOUNT are not allowed to be equal."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -n "$APACHE_PORT" ]; then
|
||||
if ! check_if_number "$APACHE_PORT"; then
|
||||
echo "You provided an Apache port but did not only use numbers"
|
||||
exit 1
|
||||
elif ! [ "$APACHE_PORT" -le 65535 ] || ! [ "$APACHE_PORT" -ge 1 ]; then
|
||||
echo "The provided Apache port is invalid. It must be between 1 and 65535"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Add important folders
|
||||
mkdir -p /mnt/docker-aio-config/data/
|
||||
mkdir -p /mnt/docker-aio-config/session/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# From https://github.com/nextcloud/docker/blob/master/23/fpm-alpine/Dockerfile
|
||||
FROM php:8.0-fpm-alpine
|
||||
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; \
|
||||
@@ -62,7 +62,7 @@ RUN set -ex; \
|
||||
# pecl will claim success even if one install fails, so we need to perform each install separately
|
||||
pecl install APCu-5.1.21; \
|
||||
pecl install memcached-3.1.5; \
|
||||
pecl install redis-5.3.6; \
|
||||
pecl install redis-5.3.7; \
|
||||
pecl install imagick-3.7.0; \
|
||||
\
|
||||
docker-php-ext-enable \
|
||||
@@ -105,7 +105,7 @@ RUN { \
|
||||
VOLUME /var/www/html
|
||||
|
||||
|
||||
ENV NEXTCLOUD_VERSION 23.0.1
|
||||
ENV NEXTCLOUD_VERSION 23.0.3
|
||||
|
||||
RUN set -ex; \
|
||||
apk add --no-cache --virtual .fetch-deps \
|
||||
|
||||
@@ -18,8 +18,3 @@ $overwriteCondAddr = getenv('OVERWRITECONDADDR');
|
||||
if ($overwriteCondAddr) {
|
||||
$CONFIG['overwritecondaddr'] = $overwriteCondAddr;
|
||||
}
|
||||
|
||||
$trustedProxies = getenv('TRUSTED_PROXIES');
|
||||
if ($trustedProxies) {
|
||||
$CONFIG['trusted_proxies'] = array_filter(array_map('trim', explode(' ', $trustedProxies)));
|
||||
}
|
||||
|
||||
@@ -21,6 +21,15 @@ redis.session.lock_retries = -1
|
||||
redis.session.lock_wait_time = 10000
|
||||
REDIS_CONF
|
||||
|
||||
# Check permissions in ncdata
|
||||
touch "/mnt/ncdata/this-is-a-test-file"
|
||||
if ! [ -f "/mnt/ncdata/this-is-a-test-file" ]; then
|
||||
echo "The www-data user doesn't seem to have access rights in /mnt/ncdata.
|
||||
Did you maybe change the datadir and did forget to apply the correct permissions?"
|
||||
exit 1
|
||||
fi
|
||||
rm "/mnt/ncdata/this-is-a-test-file"
|
||||
|
||||
if [ -f /var/www/html/version.php ]; then
|
||||
# shellcheck disable=SC2016
|
||||
installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
|
||||
@@ -223,6 +232,13 @@ if ! [ -f "/mnt/ncdata/skip.update" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if appdata is present
|
||||
# If not, something broke (e.g. changing ncdatadir after aio was first started)
|
||||
if [ -z "$(find "/mnt/ncdata/" -maxdepth 1 -mindepth 1 -type d -name "appdata_*")" ]; then
|
||||
echo "Appdata is not present. Did you maybe change the datadir after aio was first started?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Apply one-click-instance settings
|
||||
echo "Applying one-click-instance settings..."
|
||||
php /var/www/html/occ config:system:set one-click-instance --value=true --type=bool
|
||||
@@ -235,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
|
||||
@@ -250,35 +273,95 @@ elif [ "$(php /var/www/html/occ config:app:get notify_push enabled)" = "no" ]; t
|
||||
else
|
||||
php /var/www/html/occ app:update notify_push
|
||||
fi
|
||||
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
|
||||
|
||||
@@ -6,6 +6,16 @@ while ! nc -z "$POSTGRES_HOST" 5432; do
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Use the correct Postgres username
|
||||
POSTGRES_USER="oc_$POSTGRES_USER"
|
||||
export POSTGRES_USER
|
||||
|
||||
# Fix false database connection on old instances
|
||||
if [ -f "/var/www/html/config/config.php" ] && sleep 2 && psql -d "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:5432/$POSTGRES_DB" -c "select now()"; then
|
||||
sed -i "s|'dbuser'.*=>.*$|'dbuser' => '$POSTGRES_USER',|" /var/www/html/config/config.php
|
||||
sed -i "s|'dbpassword'.*=>.*$|'dbpassword' => '$POSTGRES_PASSWORD',|" /var/www/html/config/config.php
|
||||
fi
|
||||
|
||||
# Run original entrypoint
|
||||
if ! bash /entrypoint.sh; then
|
||||
exit 1
|
||||
|
||||
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,7 +1,7 @@
|
||||
# From https://github.com/docker-library/postgres/blob/master/13/alpine/Dockerfile
|
||||
FROM postgres:13-alpine
|
||||
FROM postgres:14.2-alpine3.15
|
||||
|
||||
RUN apk add --update --no-cache bash openssl shadow
|
||||
RUN apk add --update --no-cache bash openssl shadow netcat-openbsd
|
||||
|
||||
# We need to use the same gid and uid as on old installations
|
||||
RUN set -ex; \
|
||||
@@ -17,7 +17,9 @@ RUN set -ex; \
|
||||
chown -R postgres:postgres "$PGDATA"
|
||||
|
||||
COPY start.sh /usr/bin/
|
||||
RUN chmod +x /usr/bin/start.sh
|
||||
COPY init-user-db.sh /docker-entrypoint-initdb.d/
|
||||
RUN chmod +x /usr/bin/start.sh; \
|
||||
chmod +xr /docker-entrypoint-initdb.d/init-user-db.sh
|
||||
|
||||
RUN mkdir /mnt/data; \
|
||||
chown postgres:postgres /mnt/data;
|
||||
|
||||
9
Containers/postgresql/init-user-db.sh
Normal file
9
Containers/postgresql/init-user-db.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
CREATE USER "oc_$POSTGRES_USER" WITH PASSWORD '$POSTGRES_PASSWORD' CREATEDB;
|
||||
ALTER DATABASE "$POSTGRES_DB" OWNER TO "oc_$POSTGRES_USER";
|
||||
EOSQL
|
||||
|
||||
set +ex
|
||||
@@ -18,10 +18,18 @@ if ! [ -w "$DUMP_DIR" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Delete the datadir once (needed for setting the correct credentials on old instances once)
|
||||
if ! [ -f "$DUMP_DIR/export.failed" ] && ! [ -f "$DUMP_DIR/initial-cleanup-done" ]; then
|
||||
set -ex
|
||||
rm -rf "${DATADIR:?}/"*
|
||||
touch "$DUMP_DIR/initial-cleanup-done"
|
||||
set +ex
|
||||
fi
|
||||
|
||||
# Test if some things match
|
||||
# shellcheck disable=SC2235
|
||||
if ( [ -f "$DATADIR/PG_VERSION" ] && [ "$PG_MAJOR" != "$(cat "$DATADIR/PG_VERSION")" ] ) \
|
||||
|| ( ! [ -f "$DATADIR/PG_VERSION" ] && [ -f "$DUMP_FILE" ] ); then
|
||||
|| ( ! [ -f "$DATADIR/PG_VERSION" ] && ( [ -f "$DUMP_FILE" ] || [ -f "$DUMP_DIR/export.failed" ] ) ); then
|
||||
# The DUMP_file must be provided
|
||||
if ! [ -f "$DUMP_FILE" ]; then
|
||||
echo "Unable to restore the database because the database dump is missing."
|
||||
@@ -39,7 +47,7 @@ if ( [ -f "$DATADIR/PG_VERSION" ] && [ "$PG_MAJOR" != "$(cat "$DATADIR/PG_VERSIO
|
||||
echo "Restoring from database dump."
|
||||
|
||||
# Exit if any command fails
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
# Remove old database files
|
||||
rm -rf "${DATADIR:?}/"*
|
||||
@@ -50,13 +58,33 @@ if ( [ -f "$DATADIR/PG_VERSION" ] && [ "$PG_MAJOR" != "$(cat "$DATADIR/PG_VERSIO
|
||||
# Create new database
|
||||
exec docker-entrypoint.sh postgres &
|
||||
|
||||
# Wait 2s for creation
|
||||
sleep 2s
|
||||
# Wait for creation
|
||||
while ! nc -z localhost 11000; do
|
||||
echo "Waiting for the database to start."
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Set correct permissions
|
||||
if grep -q "Owner: oc_admin" "$DUMP_FILE" && ! grep -q "Owner: oc_$POSTGRES_USER" "$DUMP_FILE"; then
|
||||
OC_ADMIN_EXISTS=1
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
CREATE USER oc_admin WITH PASSWORD '$POSTGRES_PASSWORD' CREATEDB;
|
||||
ALTER DATABASE "$POSTGRES_DB" OWNER TO oc_admin;
|
||||
EOSQL
|
||||
fi
|
||||
|
||||
# Restore database
|
||||
echo "Restoring the database from database dump"
|
||||
psql "$POSTGRES_DB" -U "$POSTGRES_USER" < "$DUMP_FILE"
|
||||
|
||||
# Correct permissions
|
||||
if [ -n "$OC_ADMIN_EXISTS" ]; then
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
ALTER DATABASE "$POSTGRES_DB" OWNER TO "oc_$POSTGRES_USER";
|
||||
REASSIGN OWNED BY oc_admin TO "oc_$POSTGRES_USER";
|
||||
EOSQL
|
||||
fi
|
||||
|
||||
# Shut down the database to be able to start it again
|
||||
pg_ctl stop -m fast
|
||||
|
||||
@@ -64,7 +92,7 @@ if ( [ -f "$DATADIR/PG_VERSION" ] && [ "$PG_MAJOR" != "$(cat "$DATADIR/PG_VERSIO
|
||||
export PGPORT=5432
|
||||
|
||||
# Don't exit if command fails anymore
|
||||
set +e
|
||||
set +ex
|
||||
fi
|
||||
|
||||
# Cover the last case
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# From https://github.com/docker-library/redis/blob/master/6.2/alpine/Dockerfile
|
||||
FROM redis:6.2-alpine
|
||||
FROM redis:6.2.6-alpine3.15
|
||||
|
||||
RUN apk add --update --no-cache openssl bash
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:focal
|
||||
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:latest as watchtower
|
||||
FROM containrrr/watchtower:1.4.0 as watchtower
|
||||
|
||||
FROM alpine:latest
|
||||
FROM alpine:3.15.3
|
||||
|
||||
RUN apk add --update --no-cache bash
|
||||
COPY --from=watchtower /watchtower /
|
||||
|
||||
@@ -17,5 +17,9 @@
|
||||
"slim/twig-view": "^3.2",
|
||||
"slim/csrf": "^1.2",
|
||||
"ext-apcu": "*"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"psalm": "psalm --threads=1",
|
||||
"psalm:update-baseline": "psalm --threads=1 --update-baseline"
|
||||
}
|
||||
}
|
||||
|
||||
122
php/composer.lock
generated
122
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": {
|
||||
@@ -50,12 +50,12 @@
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
]
|
||||
],
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -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",
|
||||
@@ -157,12 +157,12 @@
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Promise\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
]
|
||||
],
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Promise\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -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",
|
||||
@@ -465,12 +465,12 @@
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Opis\\Closure\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"functions.php"
|
||||
]
|
||||
],
|
||||
"psr-4": {
|
||||
"Opis\\Closure\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -595,12 +595,12 @@
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"DI\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
]
|
||||
],
|
||||
"psr-4": {
|
||||
"DI\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -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",
|
||||
@@ -1437,7 +1439,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.24.0",
|
||||
"version": "v1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
@@ -1469,12 +1471,12 @@
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -1499,7 +1501,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1519,7 +1521,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.24.0",
|
||||
"version": "v1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
@@ -1551,12 +1553,12 @@
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -1582,7 +1584,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1602,7 +1604,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.24.0",
|
||||
"version": "v1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
@@ -1661,7 +1663,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -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,25 +2,29 @@
|
||||
"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",
|
||||
"containerName": "nextcloud/aio-apache",
|
||||
"ports": [
|
||||
"443/tcp"
|
||||
"%APACHE_PORT%/tcp"
|
||||
],
|
||||
"internalPorts": [
|
||||
"443"
|
||||
"%APACHE_PORT%"
|
||||
],
|
||||
"secrets": [],
|
||||
"environmentVariables": [
|
||||
"NC_DOMAIN=%NC_DOMAIN%",
|
||||
"NEXTCLOUD_HOST=nextcloud-aio-nextcloud",
|
||||
"COLLABORA_HOST=nextcloud-aio-collabora",
|
||||
"TALK_HOST=nextcloud-aio-talk"
|
||||
"TALK_HOST=nextcloud-aio-talk",
|
||||
"APACHE_PORT=%APACHE_PORT%",
|
||||
"ONLYOFFICE_HOST=nextcloud-aio-onlyoffice"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -95,9 +99,14 @@
|
||||
"writeable": true
|
||||
},
|
||||
{
|
||||
"name": "nextcloud_aio_nextcloud_data",
|
||||
"name": "%NEXTCLOUD_DATADIR%",
|
||||
"location": "/mnt/ncdata",
|
||||
"writeable": true
|
||||
},
|
||||
{
|
||||
"name": "%NEXTCLOUD_MOUNT%",
|
||||
"location": "%NEXTCLOUD_MOUNT%",
|
||||
"writeable": true
|
||||
}
|
||||
],
|
||||
"environmentVariables": [
|
||||
@@ -114,10 +123,16 @@
|
||||
"NEXTCLOUD_DATA_DIR=/mnt/ncdata",
|
||||
"OVERWRITEHOST=%NC_DOMAIN%",
|
||||
"OVERWRITEPROTOCOL=https",
|
||||
"TRUSTED_PROXIES=127.0.0.1",
|
||||
"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"
|
||||
@@ -151,7 +166,8 @@
|
||||
"9980"
|
||||
],
|
||||
"environmentVariables": [
|
||||
"domain=%NC_DOMAIN%"
|
||||
"domain=%NC_DOMAIN%",
|
||||
"extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:logging.level=warning"
|
||||
],
|
||||
"volumes": [],
|
||||
"secrets": [],
|
||||
@@ -194,7 +210,9 @@
|
||||
"internalPorts": [],
|
||||
"environmentVariables": [
|
||||
"BORG_PASSWORD=%BORGBACKUP_PASSWORD%",
|
||||
"BORG_MODE=%BORGBACKUP_MODE%"
|
||||
"BORG_MODE=%BORGBACKUP_MODE%",
|
||||
"SELECTED_RESTORE_TIME=%SELECTED_RESTORE_TIME%",
|
||||
"BACKUP_RESTORE_PASSWORD=%BACKUP_RESTORE_PASSWORD%"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -208,7 +226,7 @@
|
||||
"writeable": true
|
||||
},
|
||||
{
|
||||
"name": "nextcloud_aio_nextcloud_data",
|
||||
"name": "%NEXTCLOUD_DATADIR%",
|
||||
"location": "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data",
|
||||
"writeable": true
|
||||
},
|
||||
@@ -271,11 +289,12 @@
|
||||
"displayName": "Domaincheck",
|
||||
"containerName": "nextcloud/aio-domaincheck",
|
||||
"ports": [
|
||||
"443/tcp"
|
||||
"%APACHE_PORT%/tcp"
|
||||
],
|
||||
"internalPorts": [],
|
||||
"environmentVariables": [
|
||||
"INSTANCE_ID=%INSTANCE_ID%"
|
||||
"INSTANCE_ID=%INSTANCE_ID%",
|
||||
"APACHE_PORT=%APACHE_PORT%"
|
||||
],
|
||||
"volumes": [],
|
||||
"secrets": [
|
||||
@@ -283,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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
80
php/psalm-baseline.xml
Normal file
80
php/psalm-baseline.xml
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="4.22.0@fc2c6ab4d5fa5d644d8617089f012f3bb84b8703">
|
||||
<file src="public/index.php">
|
||||
<MissingClosureParamType occurrences="10">
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$request</code>
|
||||
<code>$request</code>
|
||||
<code>$request</code>
|
||||
<code>$response</code>
|
||||
<code>$response</code>
|
||||
<code>$response</code>
|
||||
</MissingClosureParamType>
|
||||
</file>
|
||||
<file src="src/Controller/ConfigurationController.php">
|
||||
<MissingParamType occurrences="1">
|
||||
<code>$args</code>
|
||||
</MissingParamType>
|
||||
</file>
|
||||
<file src="src/Controller/DockerController.php">
|
||||
<MissingParamType occurrences="8">
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
</MissingParamType>
|
||||
<PossiblyInvalidArrayAccess occurrences="1">
|
||||
<code>$request->getParsedBody()['selected_restore_time']</code>
|
||||
</PossiblyInvalidArrayAccess>
|
||||
<PossiblyNullArrayAccess occurrences="1">
|
||||
<code>$request->getParsedBody()['selected_restore_time']</code>
|
||||
</PossiblyNullArrayAccess>
|
||||
</file>
|
||||
<file src="src/Controller/LoginController.php">
|
||||
<MissingParamType occurrences="3">
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
<code>$args</code>
|
||||
</MissingParamType>
|
||||
<PossiblyInvalidArrayAccess occurrences="1">
|
||||
<code>$request->getParsedBody()['password']</code>
|
||||
</PossiblyInvalidArrayAccess>
|
||||
<PossiblyNullArgument occurrences="1">
|
||||
<code>$password</code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullArrayAccess occurrences="1">
|
||||
<code>$request->getParsedBody()['password']</code>
|
||||
</PossiblyNullArrayAccess>
|
||||
</file>
|
||||
<file src="src/Docker/DockerActionManager.php">
|
||||
<InvalidReturnType occurrences="1">
|
||||
<code>IContainerState</code>
|
||||
</InvalidReturnType>
|
||||
<InvalidScalarArgument occurrences="1">
|
||||
<code>$internalPort</code>
|
||||
</InvalidScalarArgument>
|
||||
<PossiblyFalseOperand occurrences="1">
|
||||
<code>strpos($fullDigest, "@")</code>
|
||||
</PossiblyFalseOperand>
|
||||
<RedundantCondition occurrences="1">
|
||||
<code>$container->GetInternalPorts() !== null</code>
|
||||
</RedundantCondition>
|
||||
</file>
|
||||
<file src="src/Middleware/AuthMiddleware.php">
|
||||
<UndefinedInterfaceMethod occurrences="1">
|
||||
<code>withStatus</code>
|
||||
</UndefinedInterfaceMethod>
|
||||
</file>
|
||||
<file src="src/Twig/ClassExtension.php">
|
||||
<MissingParamType occurrences="1">
|
||||
<code>$object</code>
|
||||
</MissingParamType>
|
||||
</file>
|
||||
</files>
|
||||
15
php/psalm.xml
Normal file
15
php/psalm.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
<psalm
|
||||
errorLevel="2"
|
||||
resolveFromConfigFile="true"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="https://getpsalm.org/schema/config"
|
||||
xsi:schemaLocation="https://getpsalm.org/schema/config"
|
||||
errorBaseline="psalm-baseline.xml"
|
||||
>
|
||||
<projectFiles>
|
||||
<directory name="templates"/>
|
||||
<directory name="src"/>
|
||||
<file name="public/index.php"/>
|
||||
</projectFiles>
|
||||
</psalm>
|
||||
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;
|
||||
});
|
||||
@@ -22,11 +22,6 @@ ini_set('session.save_path', $dataConst->GetSessionDirectory());
|
||||
// Auto logout on browser close
|
||||
ini_set('session.cookie_lifetime', '0');
|
||||
|
||||
// Make sure to delete all stale sessions after at least one day
|
||||
ini_set('session.gc_maxlifetime', '86400');
|
||||
ini_set('session.gc_probability', '1');
|
||||
ini_set('session.gc_divisor', '1');
|
||||
|
||||
// Create app
|
||||
AppFactory::setContainer($container);
|
||||
$app = AppFactory::create();
|
||||
@@ -53,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');
|
||||
@@ -77,16 +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) {
|
||||
@@ -141,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;
|
||||
@@ -136,7 +140,7 @@ input {
|
||||
padding: 20px;
|
||||
max-width: 100%;
|
||||
word-break: break-word;
|
||||
max-width: 450px;
|
||||
max-width: 470px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,7 +6,7 @@ class ContainerVolumes {
|
||||
/** @var ContainerVolume[] */
|
||||
private array $volumes = [];
|
||||
|
||||
public function AddVolume(ContainerVolume $volume) {
|
||||
public function AddVolume(ContainerVolume $volume) : void {
|
||||
$this->volumes[] = $volume;
|
||||
}
|
||||
|
||||
|
||||
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,13 +49,37 @@ 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') {
|
||||
$port = $this->configurationManager->GetApachePort() . '/tcp';
|
||||
}
|
||||
$ports->AddPort($port);
|
||||
}
|
||||
|
||||
$internalPorts = new ContainerInternalPorts();
|
||||
foreach ($entry['internalPorts'] as $internalPort) {
|
||||
if($internalPort === '%APACHE_PORT%') {
|
||||
$internalPort = $this->configurationManager->GetApachePort();
|
||||
}
|
||||
$internalPorts->AddInternalPort($internalPort);
|
||||
}
|
||||
|
||||
@@ -67,6 +91,23 @@ class ContainerDefinitionFetcher
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if($value['name'] === '%NEXTCLOUD_MOUNT%') {
|
||||
$value['name'] = $this->configurationManager->GetNextcloudMount();
|
||||
if($value['name'] === '') {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value['name'] === '%NEXTCLOUD_DATADIR%') {
|
||||
$value['name'] = $this->configurationManager->GetNextcloudDatadirMount();
|
||||
if ($value['name'] === '') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if($value['location'] === '%NEXTCLOUD_MOUNT%') {
|
||||
$value['location'] = $this->configurationManager->GetNextcloudMount();
|
||||
if($value['location'] === '') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$volumes->AddVolume(
|
||||
new ContainerVolume(
|
||||
$value['name'],
|
||||
@@ -76,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);
|
||||
@@ -91,7 +154,7 @@ class ContainerDefinitionFetcher
|
||||
$internalPorts,
|
||||
$volumes,
|
||||
$variables,
|
||||
$entry['dependsOn'],
|
||||
$dependsOn,
|
||||
$entry['secrets'],
|
||||
$this->container->get(DockerActionManager::class)
|
||||
);
|
||||
|
||||
@@ -22,11 +22,51 @@ 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'])) {
|
||||
$currentMasterPassword = $request->getParsedBody()['current-master-password'] ?? '';
|
||||
$newMasterPassword = $request->getParsedBody()['new-master-password'] ?? '';
|
||||
$this->configurationManager->ChangeMasterPassword($currentMasterPassword, $newMasterPassword);
|
||||
}
|
||||
|
||||
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', '/');
|
||||
|
||||
@@ -26,16 +26,26 @@ class DockerController
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
private function PerformRecursiveContainerStart(string $id) {
|
||||
private function PerformRecursiveContainerStart(string $id) : void {
|
||||
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
|
||||
foreach($container->GetDependsOn() as $dependency) {
|
||||
$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);
|
||||
|
||||
@@ -83,6 +97,21 @@ class DockerController
|
||||
public function StartBackupContainerRestore(Request $request, Response $response, $args) : Response {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'restore';
|
||||
$config['selected-restore-time'] = $request->getParsedBody()['selected_restore_time'];
|
||||
$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 StartBackupContainerTest(Request $request, Response $response, $args) : Response {
|
||||
$config = $this->configurationManager->GetConfig();
|
||||
$config['backup-mode'] = 'test';
|
||||
$this->configurationManager->WriteConfig($config);
|
||||
|
||||
$id = self::TOP_CONTAINER;
|
||||
@@ -125,14 +154,15 @@ class DockerController
|
||||
return $response->withStatus(201)->withHeader('Location', '/');
|
||||
}
|
||||
|
||||
private function PerformRecursiveContainerStop(string $id)
|
||||
private function PerformRecursiveContainerStop(string $id) : void
|
||||
{
|
||||
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
foreach($container->GetDependsOn() as $dependency) {
|
||||
$this->PerformRecursiveContainerStop($dependency);
|
||||
}
|
||||
|
||||
$this->dockerActionManager->DisconnectContainerFromNetwork($container);
|
||||
// Disconnecting is not needed. This also allows to start the containers manually via docker-cli
|
||||
//$this->dockerActionManager->DisconnectContainerFromNetwork($container);
|
||||
$this->dockerActionManager->StopContainer($container);
|
||||
}
|
||||
|
||||
@@ -144,28 +174,39 @@ class DockerController
|
||||
return $response->withStatus(201)->withHeader('Location', '/');
|
||||
}
|
||||
|
||||
public function StartDomaincheckContainer()
|
||||
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()
|
||||
private function StopDomaincheckContainer() : void
|
||||
{
|
||||
$id = 'nextcloud-aio-domaincheck';
|
||||
$this->PerformRecursiveContainerStop($id);
|
||||
|
||||
@@ -46,7 +46,7 @@ class ConfigurationManager
|
||||
return $config['secrets'][$secretId];
|
||||
}
|
||||
|
||||
private function DoubleSafeBackupSecret(string $borgBackupPassword) {
|
||||
private function DoubleSafeBackupSecret(string $borgBackupPassword) : void {
|
||||
file_put_contents(DataConst::GetBackupSecretFile(), $borgBackupPassword);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class ConfigurationManager
|
||||
}
|
||||
|
||||
$content = file_get_contents(DataConst::GetBackupArchivesList());
|
||||
if ($content === "") {
|
||||
if ($content === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -83,6 +83,31 @@ class ConfigurationManager
|
||||
return $lastBackupTime;
|
||||
}
|
||||
|
||||
public function GetBackupTimes() : array {
|
||||
if (!file_exists(DataConst::GetBackupArchivesList())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$content = file_get_contents(DataConst::GetBackupArchivesList());
|
||||
if ($content === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$backupLines = explode("\n", $content);
|
||||
$backupTimes = [];
|
||||
foreach($backupLines as $lines) {
|
||||
if ($lines !== "") {
|
||||
$backupTimesTemp = explode(',', $lines);
|
||||
$backupTimes[] = $backupTimesTemp[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the array to list newest backup first
|
||||
$backupTimes = array_reverse($backupTimes);
|
||||
|
||||
return $backupTimes;
|
||||
}
|
||||
|
||||
public function wasStartButtonClicked() : bool {
|
||||
if (isset($this->GetConfig()['wasStartButtonClicked'])) {
|
||||
return true;
|
||||
@@ -91,15 +116,88 @@ 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
|
||||
*/
|
||||
public function SetDomain(string $domain) : void {
|
||||
// Validate URL
|
||||
if (!filter_var('http://' . $domain, FILTER_VALIDATE_URL)) {
|
||||
// Validate domain
|
||||
if (!filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
|
||||
throw new InvalidSettingConfigurationException("Domain is not in a valid format!");
|
||||
}
|
||||
|
||||
// Validate that it is not an IP-address
|
||||
if(filter_var($domain, FILTER_VALIDATE_IP)) {
|
||||
throw new InvalidSettingConfigurationException("Please enter a domain and not an IP-address!");
|
||||
}
|
||||
|
||||
$dnsRecordIP = gethostbyname($domain);
|
||||
|
||||
// Validate IP
|
||||
@@ -117,20 +215,30 @@ class ConfigurationManager
|
||||
// Get Instance ID
|
||||
$instanceID = $this->GetSecret('INSTANCE_ID');
|
||||
|
||||
// set protocol
|
||||
$port = $this->GetApachePort();
|
||||
if ($port !== '443') {
|
||||
$protocol = 'https://';
|
||||
} else {
|
||||
$protocol = 'http://';
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL,'http://' . $domain . ':443');
|
||||
curl_setopt($ch, CURLOPT_URL, $protocol . $domain . ':443');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$response = curl_exec($ch);
|
||||
$response = (string)curl_exec($ch);
|
||||
# Get rid of trailing \n
|
||||
$response = str_replace("\n", "", $response);
|
||||
|
||||
if($response !== $instanceID) {
|
||||
throw new InvalidSettingConfigurationException("Domain does not point to this server.");
|
||||
throw new InvalidSettingConfigurationException("Domain does not point to this server or reverse proxy not configured correctly.");
|
||||
}
|
||||
|
||||
// Write domain
|
||||
$config = $this->GetConfig();
|
||||
$config['domain'] = $domain;
|
||||
// Reset the borg restore password when setting the domain
|
||||
$config['borg_restore_password'] = '';
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
@@ -152,6 +260,15 @@ class ConfigurationManager
|
||||
return $config['backup-mode'];
|
||||
}
|
||||
|
||||
public function GetSelectedRestoreTime() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['selected-restore-time'])) {
|
||||
$config['selected-restore-time'] = '';
|
||||
}
|
||||
|
||||
return $config['selected-restore-time'];
|
||||
}
|
||||
|
||||
public function GetAIOURL() : string {
|
||||
$config = $this->GetConfig();
|
||||
if(!isset($config['AIO_URL'])) {
|
||||
@@ -168,6 +285,7 @@ class ConfigurationManager
|
||||
$allowedPrefixes = [
|
||||
'/mnt/',
|
||||
'/media/',
|
||||
'/host_mnt/',
|
||||
];
|
||||
|
||||
$isValidPath = false;
|
||||
@@ -183,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'.");
|
||||
}
|
||||
|
||||
|
||||
@@ -192,6 +310,68 @@ 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
|
||||
*/
|
||||
public function ChangeMasterPassword(string $currentPassword, string $newPassword) : void {
|
||||
if ($currentPassword === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter your current password.");
|
||||
}
|
||||
|
||||
if ($currentPassword !== $this->GetPassword()) {
|
||||
throw new InvalidSettingConfigurationException("The entered current password is not correct.");
|
||||
}
|
||||
|
||||
if ($newPassword === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter a new password.");
|
||||
}
|
||||
|
||||
if (strlen($newPassword) < 24) {
|
||||
throw new InvalidSettingConfigurationException("New passwords must be >= 24 digits.");
|
||||
}
|
||||
|
||||
if (!preg_match("#^[a-zA-Z0-9 ]+$#", $newPassword)) {
|
||||
throw new InvalidSettingConfigurationException('Not allowed characters in the new password.');
|
||||
}
|
||||
|
||||
// All checks pass so set the password
|
||||
$this->SetPassword($newPassword);
|
||||
}
|
||||
|
||||
public function GetApachePort() : string {
|
||||
$envVariableName = 'APACHE_PORT';
|
||||
$configName = 'apache_port';
|
||||
$defaultValue = '443';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
@@ -202,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'])) {
|
||||
@@ -211,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'])) {
|
||||
@@ -219,4 +430,18 @@ class ConfigurationManager
|
||||
|
||||
return $config['backup-mode'];
|
||||
}
|
||||
|
||||
public function GetNextcloudMount() : string {
|
||||
$envVariableName = 'NEXTCLOUD_MOUNT';
|
||||
$configName = 'nextcloud_mount';
|
||||
$defaultValue = '';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetNextcloudDatadirMount() : string {
|
||||
$envVariableName = 'NEXTCLOUD_DATADIR';
|
||||
$configName = 'nextcloud_datadir';
|
||||
$defaultValue = 'nextcloud_aio_nextcloud_data';
|
||||
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -77,7 +100,7 @@ class DockerActionManager
|
||||
$runningDigest = $this->GetRepoDigestOfContainer($container->GetIdentifier());
|
||||
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($container->GetContainerName(), $tag);
|
||||
|
||||
if ($runningDigest === $remoteDigest) {
|
||||
if ($runningDigest === $remoteDigest || $remoteDigest === null || $runningDigest === null) {
|
||||
return new VersionEqualState();
|
||||
} else {
|
||||
return new VersionDifferentState();
|
||||
@@ -109,7 +132,7 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function DeleteContainer(Container $container) {
|
||||
public function DeleteContainer(Container $container) : void {
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s?v=true', urlencode($container->GetIdentifier())));
|
||||
try {
|
||||
$this->guzzleClient->delete($url);
|
||||
@@ -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();
|
||||
|
||||
@@ -142,12 +165,12 @@ class DockerActionManager
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function StartContainer(Container $container) {
|
||||
public function StartContainer(Container $container) : void {
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/start', urlencode($container->GetIdentifier())));
|
||||
$this->guzzleClient->post($url);
|
||||
}
|
||||
|
||||
public function CreateVolumes(Container $container)
|
||||
public function CreateVolumes(Container $container): void
|
||||
{
|
||||
$url = $this->BuildApiUrl('volumes/create');
|
||||
foreach($container->GetVolumes()->GetVolumes() as $volume) {
|
||||
@@ -170,7 +193,7 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function CreateContainer(Container $container) {
|
||||
public function CreateContainer(Container $container) : void {
|
||||
$volumes = [];
|
||||
foreach($container->GetVolumes()->GetVolumes() as $volume) {
|
||||
$volumeEntry = $volume->name . ':' . $volume->mountPoint;
|
||||
@@ -212,6 +235,38 @@ class DockerActionManager
|
||||
$replacements[1] = $this->configurationManager->GetBackupMode();
|
||||
} elseif ($out[1] === 'AIO_URL') {
|
||||
$replacements[1] = $this->configurationManager->GetAIOURL();
|
||||
} elseif ($out[1] === 'SELECTED_RESTORE_TIME') {
|
||||
$replacements[1] = $this->configurationManager->GetSelectedRestoreTime();
|
||||
} elseif ($out[1] === '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]);
|
||||
}
|
||||
@@ -246,22 +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)
|
||||
public function PullContainer(Container $container) : void
|
||||
{
|
||||
$url = $this->BuildApiUrl(sprintf('images/create?fromImage=%s', urlencode($this->BuildImageName($container))));
|
||||
try {
|
||||
$this->guzzleClient->post($url);
|
||||
} catch (RequestException $e) {
|
||||
throw $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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,10 +342,9 @@ class DockerActionManager
|
||||
return $updateAvailable;
|
||||
}
|
||||
|
||||
public function isAnyUpdateAvailable() {
|
||||
public function isAnyUpdateAvailable() : bool {
|
||||
$id = 'nextcloud-aio-apache';
|
||||
|
||||
|
||||
if ($this->isContainerUpdateAvailable($id) !== "") {
|
||||
return true;
|
||||
} else {
|
||||
@@ -307,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;
|
||||
}
|
||||
}
|
||||
@@ -328,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';
|
||||
@@ -343,14 +407,14 @@ class DockerActionManager
|
||||
$runningDigest = $this->GetRepoDigestOfContainer($containerName);
|
||||
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($imageName, $tag);
|
||||
|
||||
if ($remoteDigest === $runningDigest) {
|
||||
if ($remoteDigest === $runningDigest || $remoteDigest === null || $runningDigest === null) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function sendNotification(Container $container, string $subject, string $message)
|
||||
public function sendNotification(Container $container, string $subject, string $message) : void
|
||||
{
|
||||
if ($this->GetContainerStartingState($container) instanceof RunningState) {
|
||||
|
||||
@@ -396,7 +460,7 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function DisconnectContainerFromNetwork(Container $container)
|
||||
public function DisconnectContainerFromNetwork(Container $container) : void
|
||||
{
|
||||
|
||||
$url = $this->BuildApiUrl(
|
||||
@@ -414,10 +478,11 @@ class DockerActionManager
|
||||
]
|
||||
);
|
||||
} catch (RequestException $e) {
|
||||
error_log('Could not disconnect container from network ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function ConnectContainerIdToNetwork(string $id)
|
||||
private function ConnectContainerIdToNetwork(string $id) : void
|
||||
{
|
||||
$url = $this->BuildApiUrl('networks/create');
|
||||
try {
|
||||
@@ -460,17 +525,17 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function ConnectMasterContainerToNetwork()
|
||||
public function ConnectMasterContainerToNetwork() : void
|
||||
{
|
||||
$this->ConnectContainerIdToNetwork('nextcloud-aio-mastercontainer');
|
||||
}
|
||||
|
||||
public function ConnectContainerToNetwork(Container $container)
|
||||
public function ConnectContainerToNetwork(Container $container) : void
|
||||
{
|
||||
$this->ConnectContainerIdToNetwork($container->GetIdentifier());
|
||||
}
|
||||
|
||||
public function StopContainer(Container $container) {
|
||||
public function StopContainer(Container $container) : void {
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/stop?t=%s', urlencode($container->GetIdentifier()), $container->GetMaxShutdownTime()));
|
||||
try {
|
||||
$this->guzzleClient->post($url);
|
||||
@@ -504,6 +569,29 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function GetDatabasecontainerExitCode() : int
|
||||
{
|
||||
$containerName = 'nextcloud-aio-database';
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($containerName)));
|
||||
try {
|
||||
$response = $this->guzzleClient->get($url);
|
||||
} catch (RequestException $e) {
|
||||
if ($e->getCode() === 404) {
|
||||
return -1;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$responseBody = json_decode((string)$response->getBody(), true);
|
||||
|
||||
$exitCode = $responseBody['State']['ExitCode'];
|
||||
if (is_int($exitCode)) {
|
||||
return $exitCode;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public function isLoginAllowed() : bool {
|
||||
$id = 'nextcloud-aio-apache';
|
||||
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
@@ -512,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,63 +16,163 @@
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h1>Nextcloud AIO Beta v0.3.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 updpate currently running. It will restart the mastercontainer soon which will make it unavailable for a moment. Please wait until thats 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 == "" %}
|
||||
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 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>
|
||||
<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 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 %}
|
||||
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 %}
|
||||
|
||||
@@ -81,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>
|
||||
@@ -99,18 +199,28 @@
|
||||
</ul>
|
||||
|
||||
{% if has_update_available == true %}
|
||||
⚠ Container updates are available. Click on `Stop Containers` and `Start Containers` to update them. You should consider creating a backup first. The mastercontainer gets updated with a different procedure though and has its own update button which is visible if an update is available.<br><br>
|
||||
{% 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>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if is_mastercontainer_update_available == false %}
|
||||
Your containers are up-to-date.<br><br>
|
||||
{% else %}
|
||||
Your containers are up-to-date. (Except the mastercontainer. See the section below.)<br><br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if isAnyRunning == true %}
|
||||
{% if isApacheStarting != true %}
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
⚠ A mastercontainer update is available. Please click on the button below to stop your containers in order to 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}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
@@ -126,53 +236,48 @@
|
||||
{% if was_start_button_clicked == false %}
|
||||
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 was_start_button_clicked == false or has_update_available == false %}
|
||||
<form method="POST" action="/api/docker/start" class="xhr">
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
⚠ 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="Start containers" />
|
||||
<input class="button" type="submit" value="Update mastercontainer" />
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="POST" action="/api/docker/start" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button " type="submit" value="Start and update containers" onclick="return confirm('Start and update containers? You should consider creating a backup first.')" />
|
||||
</form>
|
||||
{% if was_start_button_clicked == false or has_update_available == false %}
|
||||
<form method="POST" action="/api/docker/start" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Start containers" />
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="POST" action="/api/docker/start" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button " type="submit" value="Start and update containers" onclick="return confirm('Start and update containers? You should consider creating a backup first.')" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
{% if isBackupOrRestoreRunning == false %}
|
||||
<h2>Mastercontainer update</h2>
|
||||
|
||||
⚠ A mastercontainer update is available. Please click on the button below to update it. All other containers get updated independently from the mastercontainer by simply clicking on `Stop containers` and clicking on `Start containers` if a new update is available.<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>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if was_start_button_clicked == true %}
|
||||
|
||||
|
||||
{% 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 %}
|
||||
@@ -184,14 +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.
|
||||
|
||||
{% 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}}">
|
||||
@@ -199,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}}">
|
||||
@@ -206,40 +320,89 @@
|
||||
<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>
|
||||
|
||||
Click on the button below to restore the last backup from {{ last_backup_time }}. This will overwrite all your files with the state of the backup. It 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">
|
||||
<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}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Restore last backup" onclick="return confirm('Restore last backup? Are you sure that you want to restore the last backup? This will stop all running containers and restore the last backup from {{ last_backup_time }}. You might want to check the backup integrity first.')" />
|
||||
<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" onclick="return confirm('Restore the selected backup? Are you sure that you want to restore the selected backup? This will stop all running containers and restore the selected backup. It is recommended to create a backup first. You might also want to check the backup integrity.')" />
|
||||
</form>
|
||||
{% 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 has_backup_run_once == false %}
|
||||
<br /><br />
|
||||
{% else %}
|
||||
</details><br /><br />
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% 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 %}
|
||||
{% 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>
|
||||
|
||||
228
readme.md
228
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,30 +53,52 @@ 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>
|
||||
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>
|
||||
https://your-domain-that-points-to-this-server.tld:8443
|
||||
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 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`
|
||||
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?
|
||||
Nextcloud AIO is inspired by projects like Portainer that allow to manage the docker daemon by talking to the docker socket directly. This concept allows to install only one container with a single command that does the heavy lifting of creating and managing all containers that are needed in order to provide a Nextcloud installation with most features included. It also makes updating a breeze and is not bound to the host system (and its slow updates) anymore as everything is in containers. Additionally, it is very easy to handle from a user perspective because a simple interface for managing your Nextcloud AIO installation is provided.
|
||||
|
||||
### Are reverse proxies supported?
|
||||
Reverse proxies are currently because of the above mentioned architecture not supported.<br>
|
||||
You might investigate yourself though how it could made work behind reverse proxies. If you open a PR with that we might consider it then :)
|
||||
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 Nextcloud container
|
||||
- `3478/TCP` and `3478/UPD` for the Talk container
|
||||
- `443/TCP` for the Apache container
|
||||
- `3478/TCP` and `3478/UDP` for the Talk container
|
||||
|
||||
### 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 Nextcloud container later on and needs to be open
|
||||
- `3478/TCP` and `3478/UPD`: 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,11 +123,166 @@ 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.
|
||||
|
||||
Backups can be created and restored in the AIO interface using the buttons `Create Backup` and `Restore last backup`. Additionally, a backup check is provided that checks the integrity of your backups but it shouldn't be needed in most situations.
|
||||
<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.
|
||||
|
||||
Note that this implementation does not provide remote backups, for this you can use the [backup app](https://apps.nextcloud.com/apps/backup).
|
||||
Be aware that this solution does not back up files and folders that are mounted into Nextcloud using the external storage app.
|
||||
|
||||
Note that this implementation does not provide remote backups, for this you can use the [backup app](https://apps.nextcloud.com/apps/backup).
|
||||
|
||||
---
|
||||
|
||||
#### Failure of the backup container in LXC containers
|
||||
If you are running AIO in a LXC container, you need to make sure that FUSE is enabled in the LXC container settings. Otherwise the backup container will not be able to start as FUSE is required for it to work.
|
||||
|
||||
---
|
||||
|
||||
#### Pro-tip: Backup archives access
|
||||
You can open the BorgBackup archives on your host by following these steps:<br>
|
||||
(instructions for Ubuntu Desktop)
|
||||
```bash
|
||||
# Install borgbackup on the host
|
||||
sudo apt update && sudo apt install borgbackup
|
||||
|
||||
# Mount the archives to /tmp/borg (if you are using the default backup location /mnt/backup/borg)
|
||||
sudo mkdir -p /tmp/borg && sudo borg mount "/mnt/backup/borg" /tmp/borg
|
||||
|
||||
# After entering your repository key successfully, you should be able to access all archives in /tmp/borg
|
||||
# You can now do whatever you want by syncing them to a different place using rsync or doing other things
|
||||
# E.g. you can open the file manager on that location by running:
|
||||
xhost +si:localuser:root && sudo nautilus /tmp/borg
|
||||
|
||||
# When you are done, simply close the file manager and run the following command to unmount the backup archives:
|
||||
sudo umount /tmp/borg
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Delete backup archives manually
|
||||
You can delete BorgBackup archives on your host manually by following these steps:<br>
|
||||
(instructions for Debian based OS' like Ubuntu)
|
||||
```bash
|
||||
# Install borgbackup on the host
|
||||
sudo apt update && sudo apt install borgbackup
|
||||
|
||||
# List all archives (if you are using the default backup location /mnt/backup/borg)
|
||||
sudo borg list "/mnt/backup/borg"
|
||||
|
||||
# After entering your repository key successfully, you should now see a list of all backup archives
|
||||
# An example backup archive might be called 20220223_174237-nextcloud-aio
|
||||
# Then you can simply delete the archive with:
|
||||
sudo borg delete --stats --progress "/mnt/backup/borg::20220223_174237-nextcloud-aio"
|
||||
```
|
||||
|
||||
After doing so, make sure to update the backup archives list in the AIO interface!<br>
|
||||
You can do so by clicking on the `Check backup integrity` button or `Create backup` button.
|
||||
|
||||
---
|
||||
|
||||
#### Sync the backup regularly to another drive
|
||||
For increased backup security, you might consider syncing the backup repository regularly to another drive.
|
||||
|
||||
To do that, first add the drive to `/etc/fstab` so that it is able to get automatically mounted and then create a script that does all the things automatically. Here is an example for such a script:
|
||||
|
||||
<details>
|
||||
<summary>Click here to expand</summary>
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Please modify all variables below to your needings:
|
||||
SOURCE_DIRECTORY="/mnt/backup/borg"
|
||||
DRIVE_MOUNTPOINT="/mnt/backup-drive"
|
||||
TARGET_DIRECTORY="/mnt/backup-drive/borg"
|
||||
|
||||
########################################
|
||||
# Please do NOT modify anything below! #
|
||||
########################################
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Please run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -d "$SOURCE_DIRECTORY" ]; then
|
||||
echo "The source directory does not exist."
|
||||
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
|
||||
fi
|
||||
|
||||
if ! grep -q " $DRIVE_MOUNTPOINT " /etc/fstab; then
|
||||
echo "Could not find the drive mountpoint in the fstab file. Did you add it there?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "$DRIVE_MOUNTPOINT"; then
|
||||
mount "$DRIVE_MOUNTPOINT"
|
||||
if ! mountpoint -q "$DRIVE_MOUNTPOINT"; then
|
||||
echo "Could not mount the drive. Is it connected?"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$SOURCE_DIRECTORY/lock.roster" ]; then
|
||||
echo "Cannot run the script as the backup archive is currently changed. Please try again later."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$TARGET_DIRECTORY"
|
||||
if ! [ -d "$TARGET_DIRECTORY" ]; then
|
||||
echo "Could not create target directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! rsync --stats --archive --human-readable --delete "$SOURCE_DIRECTORY/" "$TARGET_DIRECTORY"; then
|
||||
echo "Failed to sync the backup repository to the target directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
umount "$DRIVE_MOUNTPOINT"
|
||||
|
||||
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
|
||||
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
You can simply copy and past the script into a file e.g. named `backup-script.sh` e.g. here: `/root/backup-script.sh`. Do not forget to modify the variables to your needings though!
|
||||
|
||||
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/`, `/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/`, `/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/
|
||||
@@ -134,6 +299,9 @@ You can move the whole docker library and all its files including all Nextcloud
|
||||
### How to edit Nextclouds config.php file with a texteditor?
|
||||
You can edit Nextclouds config.php file directly from the host with your favorite text editor. E.g. like this: `sudo nano /var/lib/docker/volumes/nextcloud_aio_nextcloud/_data/config/config.php`. Make sure to not break the file though which might corrupt your Nextcloud instance otherwise. In best case, create a backup using the built-in backup solution before editing the file.
|
||||
|
||||
### Custom skeleton directory
|
||||
If you want to define a custom skeleton directory, you can do so by putting your skeleton files into `/var/lib/docker/volumes/nextcloud_aio_nextcloud_data/_data/skeleton/`, applying the correct permissions with `sudo chown -R 33:0 /var/lib/docker/volumes/nextcloud_aio_nextcloud_data/_data/skeleton` and setting the skeleton directory option with `sudo docker exec -it nextcloud-aio-nextcloud php occ config:system:set skeletondirectory --value="/mnt/ncdata/skeleton"`. You can read further on this option here: [click here](https://docs.nextcloud.com/server/stable/admin_manual/configuration_server/config_sample_php_parameters.html?highlight=skeletondir#:~:text=adding%20%3Fdirect%3D1-,'skeletondirectory',-%3D%3E%20'%2Fpath%2Fto%2Fnextcloud)
|
||||
|
||||
### LDAP
|
||||
It is possible to connect to an existing LDAP server. You need to make sure that the LDAP server is reachable from the Nextcloud container. Then you can enable the LDAP app and configure LDAP in Nextcloud manually. If you don't have a LDAP server yet, recommended is to use this docker container: https://hub.docker.com/r/osixia/openldap/. Make sure here as well that Nextcloud can talk to the LDAP server. The easiest way is by adding the LDAP docker container to the docker network `nextcloud-aio`. Then you can connect to the LDAP container by its name from the Nextcloud container. **Pro-tip**: You will probably find this app useful: https://apps.nextcloud.com/apps/ldap_write_support
|
||||
|
||||
|
||||
123
reverse-proxy.md
Normal file
123
reverse-proxy.md
Normal file
@@ -0,0 +1,123 @@
|
||||
## 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.
|
||||
|
||||
### Reverse proxy config examples
|
||||
|
||||
#### Caddy
|
||||
|
||||
<details>
|
||||
|
||||
<summary>click here to expand</summary>
|
||||
<br>
|
||||
Add this to your Caddyfile:
|
||||
|
||||
```
|
||||
https://<your-nc-domain>:443 {
|
||||
header Strict-Transport-Security max-age=31536000;
|
||||
reverse_proxy localhost:11000
|
||||
}
|
||||
```
|
||||
|
||||
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 \
|
||||
--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>
|
||||
|
||||
<summary>Command for arm64 CPUs like the Raspberry Pi 4</summary>
|
||||
|
||||
```
|
||||
# For arm64 CPUs:
|
||||
sudo 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-arm64
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
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
|
||||
|
||||
If you want to also access your AIO interface publicly with a valid certificate, you can add e.g. the following config to your Caddyfile:
|
||||
|
||||
```
|
||||
https://<your-nc-domain>:8443 {
|
||||
reverse_proxy https://localhost:8080 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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