mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-05-22 03:10:16 +00:00
Compare commits
200 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
853a880c9d | ||
|
|
0ecd2c8f78 | ||
|
|
24d1451325 | ||
|
|
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 | ||
|
|
46d898e196 | ||
|
|
7f034e5109 | ||
|
|
3029b277f1 | ||
|
|
46c754759e | ||
|
|
1339be5045 | ||
|
|
53f5b4ae11 | ||
|
|
de7f47e973 | ||
|
|
b08a06573d | ||
|
|
44d491cc5b | ||
|
|
96b381bcab | ||
|
|
7b40e6b733 | ||
|
|
ed56f37c4c | ||
|
|
baa5f5635b | ||
|
|
ff59c30604 | ||
|
|
1a6253ee4c | ||
|
|
8af877f048 | ||
|
|
02c8b57d4e | ||
|
|
0052582003 | ||
|
|
7bb0c3b164 | ||
|
|
ddd01be82f | ||
|
|
c585548c07 | ||
|
|
3de828034a | ||
|
|
bb3bcad752 | ||
|
|
0748ee9fbf | ||
|
|
a2f01c2fcf | ||
|
|
4b28a6a7d7 | ||
|
|
0bf050a51f | ||
|
|
b9ab319357 | ||
|
|
46c5c59e5b | ||
|
|
ad5e3c3f51 | ||
|
|
98cb4e9494 | ||
|
|
37f219300b | ||
|
|
d934629889 | ||
|
|
285e093e57 | ||
|
|
2be5cb255b | ||
|
|
7159cd387a | ||
|
|
3041e51b04 | ||
|
|
4e852761d9 | ||
|
|
20d631b600 | ||
|
|
b4c58941ed | ||
|
|
d7b7a013fd | ||
|
|
d65ffed5b1 | ||
|
|
3ea0799eb5 | ||
|
|
c48a0de6d2 | ||
|
|
7a6ed91a3e | ||
|
|
8bdcba11e6 | ||
|
|
d19069c8e3 | ||
|
|
095fc6de2b | ||
|
|
f8ac6bb865 | ||
|
|
400e575972 | ||
|
|
61bd306416 | ||
|
|
d27c33cdce | ||
|
|
a95f36d673 | ||
|
|
0c543c0ad4 | ||
|
|
2a3eab9ea6 | ||
|
|
aa1e4d3eef | ||
|
|
6dd9e06a5f | ||
|
|
3d8d7f0d79 | ||
|
|
1b73df060a | ||
|
|
282592f9aa | ||
|
|
225038b904 | ||
|
|
c44f4088ca | ||
|
|
06283bdf21 | ||
|
|
7c8b9c454a | ||
|
|
645b1654e5 | ||
|
|
6b6c9dfbc7 | ||
|
|
5ad1efde2e | ||
|
|
92a7b156a7 | ||
|
|
2733f115ec | ||
|
|
343eebbbcd | ||
|
|
9823e6400d | ||
|
|
ee124bf894 | ||
|
|
0837ac9670 | ||
|
|
bfc8526ddd | ||
|
|
49cf819f2f | ||
|
|
4603becc1c | ||
|
|
9b4de8e098 | ||
|
|
8659ae6a08 | ||
|
|
857ce36e88 | ||
|
|
268c5407be | ||
|
|
5b51bcc5e7 | ||
|
|
d7a0e961e9 | ||
|
|
46a566d237 | ||
|
|
a636e36c89 | ||
|
|
6222fd88c7 | ||
|
|
035d22cbcf | ||
|
|
5c3b1e0b45 | ||
|
|
7902e2e75b | ||
|
|
d02096a1f3 | ||
|
|
dadbc4d43d | ||
|
|
ddcd56b6de | ||
|
|
63193810e9 | ||
|
|
d1c6e27795 | ||
|
|
e68fffb30c | ||
|
|
20d02fb83f | ||
|
|
cb58c7604c | ||
|
|
afad8462be | ||
|
|
24d73ae80d | ||
|
|
412a5d8af7 | ||
|
|
178aeb80d2 | ||
|
|
fe99c3bc78 | ||
|
|
94e56757dd | ||
|
|
f6fc87354d | ||
|
|
be19428e81 | ||
|
|
0010a6cfa3 |
105
.github/dependabot.yml
vendored
105
.github/dependabot.yml
vendored
@@ -3,10 +3,107 @@ updates:
|
||||
- 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
|
||||
|
||||
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
|
||||
43
.github/workflows/dependency-updates.yml
vendored
Normal file
43
.github/workflows/dependency-updates.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: dependency-updates
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '00 12 * * *'
|
||||
|
||||
jobs:
|
||||
dependency_updates:
|
||||
name: Run dependency update script
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: nanasess/setup-php@master
|
||||
with:
|
||||
php-version: '8.0'
|
||||
- name: Run dependency update script
|
||||
run: |
|
||||
set -x
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
mv composer.phar /usr/local/bin/composer
|
||||
chmod +x /usr/local/bin/composer
|
||||
cd ./php
|
||||
composer update
|
||||
set +e
|
||||
ALL_LINES="$(composer outdated | grep -v "psr/container")"
|
||||
set -e
|
||||
while [ -n "$ALL_LINES" ]; do
|
||||
CURRENT_LINE="$(echo "$ALL_LINES" | head -1)"
|
||||
composer require "$(echo "$CURRENT_LINE" | awk '{print $1}')" "^$(echo "$CURRENT_LINE" | awk '{print $4}')"
|
||||
ALL_LINES="$(echo "$ALL_LINES" | sed '1d')"
|
||||
done
|
||||
echo "outdated dependencies:
|
||||
$(composer outdated)"
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
commit-message: dependency updates
|
||||
signoff: true
|
||||
title: Dependency updates
|
||||
body: Automated dependency updates since dependabot does not support grouped updates
|
||||
labels: dependencies, enhancement
|
||||
milestone: next
|
||||
branch: aio-dependency-update
|
||||
1
.github/workflows/nextcloud-update.yml
vendored
1
.github/workflows/nextcloud-update.yml
vendored
@@ -72,3 +72,4 @@ jobs:
|
||||
body: Automated Nextcloud container update
|
||||
labels: dependencies, enhancement
|
||||
milestone: next
|
||||
branch: nextcloud-container-update
|
||||
|
||||
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@v2
|
||||
- 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@v2
|
||||
- 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@v2
|
||||
|
||||
- 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@v3
|
||||
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
|
||||
18
.github/workflows/shellcheck.yml
vendored
Normal file
18
.github/workflows/shellcheck.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Shellcheck
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
shellcheck:
|
||||
name: Github Actions
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run Shellcheck
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
with:
|
||||
check_together: 'yes'
|
||||
env:
|
||||
SHELLCHECK_OPTS: --shell bash
|
||||
19
.github/workflows/spellcheck.yml
vendored
Normal file
19
.github/workflows/spellcheck.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: 'Spellcheck'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
spellcheck:
|
||||
name: Check spelling
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: spelling or typos
|
||||
uses: actions/checkout@v2
|
||||
- name: misspell
|
||||
uses: reviewdog/action-misspell@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
locale: "US"
|
||||
fail_on_error: true
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
https://{$NC_DOMAIN}:443 {
|
||||
{$PROTOCOL}://{$NC_DOMAIN}:{$APACHE_PORT} {
|
||||
|
||||
# Notify Push
|
||||
route /push/* {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:bullseye
|
||||
FROM debian:bullseye-20220125-slim
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
@@ -17,10 +17,12 @@ RUN set -ex; \
|
||||
ca-certificates \
|
||||
openssl \
|
||||
netcat \
|
||||
dpkg-dev \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN wget "https://caddyserver.com/api/download?os=linux&arch=amd64" -O "/usr/bin/caddy" \
|
||||
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
|
||||
|
||||
@@ -57,7 +59,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
|
||||
|
||||
@@ -19,4 +19,8 @@
|
||||
<Files ".ht*">
|
||||
Require all denied
|
||||
</Files>
|
||||
|
||||
# Fix zero file sizes
|
||||
# See https://github.com/nextcloud/server/issues/3056#issuecomment-954209565
|
||||
SetEnv proxy-sendcl 1
|
||||
</VirtualHost>
|
||||
|
||||
@@ -23,6 +23,19 @@ while ! nc -z "$COLLABORA_HOST" 9980; do
|
||||
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
|
||||
FROM debian:bullseye-20220125-slim
|
||||
|
||||
RUN set -ex; \
|
||||
\
|
||||
|
||||
@@ -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"
|
||||
@@ -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,17 +160,20 @@ 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
|
||||
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/"** \
|
||||
/tmp/borg/nextcloud_aio_volumes/ /nextcloud_aio_volumes; then
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
#!/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."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export BORG_PASSWORD
|
||||
# Export defaults
|
||||
export BORG_PASSPHRASE="$BORG_PASSWORD"
|
||||
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
|
||||
@@ -24,6 +30,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
|
||||
|
||||
@@ -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.2.2.1
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine
|
||||
FROM alpine:3.15.0
|
||||
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,8 @@
|
||||
# Docker CLI is a requirement
|
||||
FROM docker:20.10.12-dind-alpine3.15 as dind
|
||||
|
||||
# From https://github.com/docker-library/php/blob/master/8.0/bullseye/apache/Dockerfile
|
||||
FROM php:8.0-apache-bullseye
|
||||
FROM php:8.0.16-apache-bullseye
|
||||
|
||||
EXPOSE 80
|
||||
EXPOSE 8080
|
||||
@@ -19,22 +22,28 @@ RUN apt-get update; \
|
||||
supervisor \
|
||||
openssl \
|
||||
sudo \
|
||||
dpkg-dev \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl "https://caddyserver.com/api/download?os=linux&arch=amd64" -o "/usr/bin/caddy" \
|
||||
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=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 -e && \
|
||||
curl -sS https://getcomposer.org/installer | php && \
|
||||
mv composer.phar /usr/local/bin/composer && \
|
||||
chmod +x /usr/local/bin/composer && \
|
||||
cd /var/www/docker-aio; \
|
||||
git clone https://github.com/nextcloud/all-in-one.git --depth 1 .; \
|
||||
git clone https://github.com/nextcloud-releases/all-in-one.git --depth 1 .; \
|
||||
cd php; \
|
||||
composer install --no-dev; \
|
||||
composer clearcache; \
|
||||
@@ -67,16 +76,11 @@ RUN rm /etc/apache2/ports.conf; \
|
||||
|
||||
RUN a2dissite 000-default && \
|
||||
a2dissite default-ssl && \
|
||||
a2ensite mastercontainer.conf && \
|
||||
service apache2 restart
|
||||
a2ensite mastercontainer.conf
|
||||
|
||||
RUN mkdir /var/log/supervisord; \
|
||||
mkdir /var/run/supervisord;
|
||||
|
||||
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
|
||||
|
||||
COPY Caddyfile /
|
||||
COPY start.sh /usr/bin/
|
||||
COPY cron.sh /
|
||||
|
||||
@@ -44,3 +44,7 @@ ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
SSLEngine on
|
||||
SSLProtocol -all +TLSv1.2 +TLSv1.3
|
||||
</VirtualHost>
|
||||
|
||||
# Increase timeout in case e.g. the initial download takes a long time
|
||||
Timeout 7200
|
||||
ProxyTimeout 7200
|
||||
|
||||
@@ -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,10 +43,15 @@ 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
|
||||
echo "Cannot connect to the docker socket. Cannot proceed."
|
||||
exit 1
|
||||
fi
|
||||
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)"
|
||||
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="$(curl -s --unix-socket /var/run/docker.sock http://"$API_VERSION"/version | sed 's/,/\n/g' | grep ApiVersion | grep -oP [0-9]+.[0-9]+ | head -1 | sed 's/\.//')"
|
||||
LOCAL_API_VERSION_NUMB="$(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."
|
||||
@@ -49,6 +62,30 @@ else
|
||||
sleep 10
|
||||
fi
|
||||
|
||||
# Check for other options
|
||||
if [ -n "$NEXTCLOUD_MOUNT" ]; then
|
||||
if ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/mnt/" \
|
||||
&& ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/media/" \
|
||||
&& ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/var/backups$"
|
||||
then
|
||||
echo "You've set NEXCLOUD_MOUNT but not to an allowed value.
|
||||
The string must be equal to/start with '/mnt/' or '/media/' or be equal to '/var/backups'."
|
||||
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 "$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/
|
||||
@@ -67,12 +104,12 @@ chown root:root -R /mnt/docker-aio-config/certs/
|
||||
GENERATED_CERTS="/mnt/docker-aio-config/certs"
|
||||
TMP_CERTS="/etc/apache2/certs"
|
||||
mkdir -p "$GENERATED_CERTS"
|
||||
cd "$GENERATED_CERTS"
|
||||
cd "$GENERATED_CERTS" || exit 1
|
||||
if ! [ -f ./ssl.crt ] && ! [ -f ./ssl.key ]; then
|
||||
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj "/C=DE/ST=BE/L=Local/O=Dev/CN=nextcloud.local" -keyout ./ssl.key -out ./ssl.crt
|
||||
fi
|
||||
if [ -f ./ssl.crt ] && [ -f ./ssl.key ]; then
|
||||
cd "$TMP_CERTS"
|
||||
cd "$TMP_CERTS" || exit 1
|
||||
rm ./ssl.crt
|
||||
rm ./ssl.key
|
||||
cp "$GENERATED_CERTS/ssl.crt" ./
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
# From https://github.com/nextcloud/docker/blob/master/22/fpm/Dockerfile
|
||||
FROM php:8.0-fpm-bullseye
|
||||
# From https://github.com/nextcloud/docker/blob/master/23/fpm-alpine/Dockerfile
|
||||
FROM php:8.0.16-fpm-alpine3.15
|
||||
|
||||
# Custom: change id of www-data user as it needs to be the same like on old installations
|
||||
RUN set -ex; \
|
||||
apk add --no-cache shadow; \
|
||||
deluser www-data; \
|
||||
groupmod -g 333 xfs; \
|
||||
usermod -u 333 -g 333 xfs; \
|
||||
addgroup -g 33 -S www-data; \
|
||||
adduser -u 33 -D -S -G www-data www-data
|
||||
|
||||
# entrypoint.sh and cron.sh dependencies
|
||||
RUN set -ex; \
|
||||
\
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
apk add --no-cache \
|
||||
rsync \
|
||||
bzip2 \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*;
|
||||
;
|
||||
|
||||
# install the PHP extensions we need
|
||||
# see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html
|
||||
@@ -17,30 +23,28 @@ ENV PHP_MEMORY_LIMIT 512M
|
||||
ENV PHP_UPLOAD_LIMIT 10G
|
||||
RUN set -ex; \
|
||||
\
|
||||
savedAptMark="$(apt-mark showmanual)"; \
|
||||
\
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
libcurl4-openssl-dev \
|
||||
apk add --no-cache --virtual .build-deps \
|
||||
$PHPIZE_DEPS \
|
||||
autoconf \
|
||||
freetype-dev \
|
||||
icu-dev \
|
||||
libevent-dev \
|
||||
libfreetype6-dev \
|
||||
libicu-dev \
|
||||
libjpeg-dev \
|
||||
libldap2-dev \
|
||||
libjpeg-turbo-dev \
|
||||
libmcrypt-dev \
|
||||
libmemcached-dev \
|
||||
libpng-dev \
|
||||
libpq-dev \
|
||||
libmemcached-dev \
|
||||
libxml2-dev \
|
||||
libmagickwand-dev \
|
||||
libzip-dev \
|
||||
openldap-dev \
|
||||
pcre-dev \
|
||||
postgresql-dev \
|
||||
imagemagick-dev \
|
||||
libwebp-dev \
|
||||
libgmp-dev \
|
||||
gmp-dev \
|
||||
; \
|
||||
\
|
||||
debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \
|
||||
docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \
|
||||
docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \
|
||||
docker-php-ext-configure ldap; \
|
||||
docker-php-ext-install -j "$(nproc)" \
|
||||
bcmath \
|
||||
exif \
|
||||
@@ -58,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.5; \
|
||||
pecl install redis-5.3.7; \
|
||||
pecl install imagick-3.7.0; \
|
||||
\
|
||||
docker-php-ext-enable \
|
||||
@@ -69,29 +73,21 @@ RUN set -ex; \
|
||||
; \
|
||||
rm -r /tmp/pear; \
|
||||
\
|
||||
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
|
||||
apt-mark auto '.*' > /dev/null; \
|
||||
apt-mark manual $savedAptMark; \
|
||||
ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \
|
||||
| awk '/=>/ { print $3 }' \
|
||||
| sort -u \
|
||||
| xargs -r dpkg-query -S \
|
||||
| cut -d: -f1 \
|
||||
| sort -u \
|
||||
| xargs -rt apt-mark manual; \
|
||||
\
|
||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
runDeps="$( \
|
||||
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
|
||||
| tr ',' '\n' \
|
||||
| sort -u \
|
||||
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
|
||||
)"; \
|
||||
apk add --virtual .nextcloud-phpext-rundeps $runDeps; \
|
||||
apk del .build-deps
|
||||
|
||||
# set recommended PHP.ini settings
|
||||
# see https://docs.nextcloud.com/server/stable/admin_manual/configuration_server/server_tuning.html#enable-php-opcache
|
||||
RUN { \
|
||||
echo 'opcache.enable=1'; \
|
||||
echo 'opcache.interned_strings_buffer=8'; \
|
||||
echo 'opcache.max_accelerated_files=10000'; \
|
||||
echo 'opcache.memory_consumption=128'; \
|
||||
echo 'opcache.interned_strings_buffer=16'; \
|
||||
echo 'opcache.save_comments=1'; \
|
||||
echo 'opcache.revalidate_freq=1'; \
|
||||
echo 'opcache.revalidate_freq=60'; \
|
||||
} > /usr/local/etc/php/conf.d/opcache-recommended.ini; \
|
||||
\
|
||||
echo 'apc.enable_cli=1' >> /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini; \
|
||||
@@ -109,15 +105,13 @@ RUN { \
|
||||
VOLUME /var/www/html
|
||||
|
||||
|
||||
ENV NEXTCLOUD_VERSION 23.0.0
|
||||
ENV NEXTCLOUD_VERSION 23.0.2
|
||||
|
||||
RUN set -ex; \
|
||||
fetchDeps=" \
|
||||
apk add --no-cache --virtual .fetch-deps \
|
||||
bzip2 \
|
||||
gnupg \
|
||||
dirmngr \
|
||||
"; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends $fetchDeps; \
|
||||
; \
|
||||
\
|
||||
curl -fsSL -o nextcloud.tar.bz2 \
|
||||
"https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2"; \
|
||||
@@ -125,7 +119,7 @@ RUN set -ex; \
|
||||
"https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2.asc"; \
|
||||
export GNUPGHOME="$(mktemp -d)"; \
|
||||
# gpg key from https://nextcloud.com/nextcloud.asc
|
||||
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \
|
||||
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \
|
||||
gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2; \
|
||||
tar -xjf nextcloud.tar.bz2 -C /usr/src/; \
|
||||
gpgconf --kill all; \
|
||||
@@ -134,9 +128,7 @@ RUN set -ex; \
|
||||
mkdir -p /usr/src/nextcloud/data; \
|
||||
mkdir -p /usr/src/nextcloud/custom_apps; \
|
||||
chmod +x /usr/src/nextcloud/occ; \
|
||||
\
|
||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
apk del .fetch-deps
|
||||
|
||||
COPY *.sh upgrade.exclude /
|
||||
COPY config/* /usr/src/nextcloud/config/
|
||||
@@ -144,31 +136,28 @@ COPY config/* /usr/src/nextcloud/config/
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["php-fpm"]
|
||||
|
||||
# Template from https://github.com/nextcloud/docker/blob/master/.examples/dockerfiles/full/fpm/Dockerfile
|
||||
# Template from https://github.com/nextcloud/docker/blob/master/.examples/dockerfiles/full/fpm-alpine/Dockerfile
|
||||
|
||||
RUN set -ex; \
|
||||
\
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
apk add --no-cache \
|
||||
ffmpeg \
|
||||
libmagickcore-6.q16-6-extra \
|
||||
imagemagick \
|
||||
procps \
|
||||
smbclient \
|
||||
samba-client \
|
||||
supervisor \
|
||||
# libreoffice \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
;
|
||||
|
||||
RUN set -ex; \
|
||||
\
|
||||
savedAptMark="$(apt-mark showmanual)"; \
|
||||
\
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
libbz2-dev \
|
||||
libc-client-dev \
|
||||
libkrb5-dev \
|
||||
libsmbclient-dev \
|
||||
apk add --no-cache --virtual .build-deps \
|
||||
$PHPIZE_DEPS \
|
||||
imap-dev \
|
||||
krb5-dev \
|
||||
openssl-dev \
|
||||
samba-dev \
|
||||
bzip2-dev \
|
||||
; \
|
||||
\
|
||||
docker-php-ext-configure imap --with-kerberos --with-imap-ssl; \
|
||||
@@ -179,19 +168,14 @@ RUN set -ex; \
|
||||
pecl install smbclient; \
|
||||
docker-php-ext-enable smbclient; \
|
||||
\
|
||||
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
|
||||
apt-mark auto '.*' > /dev/null; \
|
||||
apt-mark manual $savedAptMark; \
|
||||
ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \
|
||||
| awk '/=>/ { print $3 }' \
|
||||
| sort -u \
|
||||
| xargs -r dpkg-query -S \
|
||||
| cut -d: -f1 \
|
||||
| sort -u \
|
||||
| xargs -rt apt-mark manual; \
|
||||
\
|
||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
runDeps="$( \
|
||||
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
|
||||
| tr ',' '\n' \
|
||||
| sort -u \
|
||||
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
|
||||
)"; \
|
||||
apk add --virtual .nextcloud-phpext-rundeps $runDeps; \
|
||||
apk del .build-deps
|
||||
|
||||
RUN mkdir -p \
|
||||
/var/log/supervisord \
|
||||
@@ -207,13 +191,13 @@ CMD ["/usr/bin/supervisord", "-c", "/supervisord.conf"]
|
||||
# Custom:
|
||||
RUN set -ex; \
|
||||
\
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
netcat \
|
||||
apk add --no-cache \
|
||||
bash \
|
||||
netcat-openbsd \
|
||||
openssl \
|
||||
gnupg \
|
||||
dirmngr \
|
||||
git \
|
||||
postgresql-client \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -224,14 +208,16 @@ RUN set -ex; \
|
||||
sed -i 's/^pm.min_spare_servers =.*/pm.min_spare_servers = 25/' /usr/local/etc/php-fpm.d/www.conf; \
|
||||
sed -i 's/^pm.max_spare_servers =.*/pm.max_spare_servers = 75/' /usr/local/etc/php-fpm.d/www.conf
|
||||
|
||||
RUN rm -rf /tmp/nextcloud-aio && \
|
||||
RUN set -ex; \
|
||||
rm -rf /tmp/nextcloud-aio && \
|
||||
mkdir -p /tmp/nextcloud-aio && \
|
||||
cd /tmp/nextcloud-aio && \
|
||||
git clone https://github.com/nextcloud/all-in-one.git .; \
|
||||
git clone https://github.com/nextcloud-releases/all-in-one.git --depth 1 .; \
|
||||
mkdir -p /usr/src/nextcloud/apps/nextcloud-aio; \
|
||||
cp -r ./app/* /usr/src/nextcloud/apps/nextcloud-aio/
|
||||
|
||||
RUN chown www-data:root -R /usr/src && \
|
||||
RUN set -ex; \
|
||||
chown www-data:root -R /usr/src && \
|
||||
chown www-data:root -R /usr/local/etc/php/conf.d && \
|
||||
chown www-data:root -R /var/log/supervisord/ && \
|
||||
chown www-data:root -R /var/run/supervisord/ && \
|
||||
@@ -241,14 +227,16 @@ RUN chown www-data:root -R /usr/src && \
|
||||
|
||||
COPY start.sh /
|
||||
COPY notify.sh /
|
||||
RUN chmod +x /start.sh && \
|
||||
RUN set -ex; \
|
||||
chmod +x /start.sh && \
|
||||
chmod +r /supervisord.conf && \
|
||||
chmod +x /entrypoint.sh && \
|
||||
chmod +r /upgrade.exclude && \
|
||||
chmod +x /cron.sh && \
|
||||
chmod +x /notify.sh
|
||||
|
||||
RUN mkdir /mnt/ncdata; \
|
||||
RUN set -ex; \
|
||||
mkdir /mnt/ncdata; \
|
||||
chown www-data:www-data /mnt/ncdata;
|
||||
|
||||
VOLUME /mnt/ncdata
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ if ! [ -f "/mnt/ncdata/skip.update" ]; then
|
||||
NEXT_MAJOR="$((INSTALLED_MAJOR + 1))"
|
||||
curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/latest-${NEXT_MAJOR}.tar.bz2"
|
||||
curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/latest-${NEXT_MAJOR}.tar.bz2.asc"
|
||||
export GNUPGHOME="$(mktemp -d)"
|
||||
GNUPGHOME="$(mktemp -d)"
|
||||
export GNUPGHOME
|
||||
# gpg key from https://nextcloud.com/nextcloud.asc
|
||||
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A
|
||||
gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2
|
||||
@@ -83,6 +84,7 @@ if ! [ -f "/mnt/ncdata/skip.update" ]; then
|
||||
break
|
||||
else
|
||||
echo "Curl didn't produce a 200 status, is appstore reachable?"
|
||||
sleep 5
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -96,6 +98,11 @@ if ! [ -f "/mnt/ncdata/skip.update" ]; then
|
||||
fi
|
||||
|
||||
php /var/www/html/occ app:update --all
|
||||
|
||||
# Fix removing the updatenotification for old instances
|
||||
if [ -d "/var/www/html/apps/updatenotification" ]; then
|
||||
php /var/www/html/occ app:disable updatenotification
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Initializing nextcloud $image_version ..."
|
||||
@@ -176,6 +183,14 @@ if ! [ -f "/mnt/ncdata/skip.update" ]; then
|
||||
# Not needed anymore with the removal of the updatenotification app:
|
||||
# php /var/www/html/occ config:app:set updatenotification notify_groups --value="[]"
|
||||
|
||||
# Install some apps by default
|
||||
php /var/www/html/occ app:install twofactor_totp
|
||||
php /var/www/html/occ app:install deck
|
||||
php /var/www/html/occ app:install tasks
|
||||
php /var/www/html/occ app:install calendar
|
||||
php /var/www/html/occ app:install contacts
|
||||
php /var/www/html/occ app:install apporder
|
||||
|
||||
#upgrade
|
||||
else
|
||||
while [ -n "$(pgrep -f cron.php)" ]
|
||||
@@ -235,6 +250,7 @@ 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
|
||||
@@ -247,6 +263,8 @@ else
|
||||
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
|
||||
|
||||
@@ -6,9 +6,29 @@ 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
|
||||
fi
|
||||
|
||||
# Correctly set CPU_ARCH for notify_push
|
||||
CPU_ARCH="$(uname -m)"
|
||||
export CPU_ARCH
|
||||
if [ -z "$CPU_ARCH" ]; then
|
||||
echo "Could not get processor architecture. Exiting."
|
||||
exit 1
|
||||
elif [ "$CPU_ARCH" != "x86_64" ]; then
|
||||
export CPU_ARCH="aarch64"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -27,4 +27,4 @@ stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
command=/var/www/html/custom_apps/notify_push/bin/x86_64/notify_push /var/www/html/config/config.php --port 7867 --redis-url redis://:%(ENV_REDIS_HOST_PASSWORD)s@%(ENV_REDIS_HOST)s
|
||||
command=/var/www/html/custom_apps/notify_push/bin/%(ENV_CPU_ARCH)s/notify_push /var/www/html/config/config.php --port 7867 --redis-url redis://:%(ENV_REDIS_HOST_PASSWORD)s@%(ENV_REDIS_HOST)s
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
# From https://github.com/docker-library/postgres/blob/master/13/bullseye/Dockerfile
|
||||
FROM postgres:13-bullseye
|
||||
# From https://github.com/docker-library/postgres/blob/master/13/alpine/Dockerfile
|
||||
FROM postgres:14.2-alpine3.15
|
||||
|
||||
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; \
|
||||
\
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
openssl \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
deluser postgres; \
|
||||
groupmod -g 9999 ping; \
|
||||
addgroup -g 999 -S postgres; \
|
||||
adduser -u 999 -S -D -G postgres -H -h /var/lib/postgresql -s /bin/sh postgres
|
||||
|
||||
# Fix default permissions
|
||||
RUN set -ex; \
|
||||
chown -R postgres:postgres /var/lib/postgresql; \
|
||||
chown -R postgres:postgres /var/run/postgresql; \
|
||||
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,9 +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."
|
||||
@@ -38,10 +47,10 @@ 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/"*
|
||||
rm -rf "${DATADIR:?}/"*
|
||||
|
||||
# Change database port to a random port temporarily
|
||||
export PGPORT=11000
|
||||
@@ -49,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
|
||||
|
||||
@@ -63,13 +92,13 @@ 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
|
||||
if ! [ -f "$DATADIR/PG_VERSION" ] && ! [ -f "$DUMP_FILE" ]; then
|
||||
# Remove old database files if somehow there should be some
|
||||
rm -rf "$DATADIR/"*
|
||||
rm -rf "${DATADIR:?}/"*
|
||||
fi
|
||||
|
||||
# Catch docker stop attempts
|
||||
@@ -91,6 +120,6 @@ if pg_dump --username "$POSTGRES_USER" "$POSTGRES_DB" > "$DUMP_FILE.temp"; then
|
||||
exit 0
|
||||
else
|
||||
pg_ctl stop -m fast
|
||||
echo "Database dump unsucessful!"
|
||||
echo "Database dump unsuccessful!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
# From https://github.com/docker-library/redis/blob/master/6.2/Dockerfile
|
||||
FROM redis:6.2-bullseye
|
||||
# From https://github.com/docker-library/redis/blob/master/6.2/alpine/Dockerfile
|
||||
FROM redis:6.2.6-alpine3.15
|
||||
|
||||
RUN set -ex; \
|
||||
\
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
openssl \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
RUN apk add --update --no-cache openssl bash
|
||||
|
||||
COPY start.sh /usr/bin/
|
||||
RUN chmod +x /usr/bin/start.sh
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:focal
|
||||
FROM ubuntu:focal-20220113
|
||||
|
||||
EXPOSE 3478
|
||||
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
# 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 debian:bullseye
|
||||
|
||||
RUN set -ex; \
|
||||
\
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
FROM alpine:3.15.0
|
||||
|
||||
RUN apk add --update --no-cache bash
|
||||
COPY --from=watchtower /watchtower /
|
||||
|
||||
COPY start.sh /
|
||||
|
||||
@@ -16,5 +16,4 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## How to develope the app?
|
||||
## How to develop the app?
|
||||
|
||||
Please note that in order to check if an app is already downloaded
|
||||
Nextcloud will look for a folder with the same name as the app.
|
||||
|
||||
28
develop.md
28
develop.md
@@ -14,27 +14,11 @@ nextcloud/all-in-one:develop
|
||||
And you are done :)
|
||||
It will now also select the developer channel for all other containers automatically.
|
||||
|
||||
## How to build new containers
|
||||
|
||||
Go to https://github.com/nextcloud-releases/all-in-one/actions/workflows/repo-sync.yml and run the workflow that will first sync the repo and then build new container that automatically get published to `develop` and `develop-arm64`.
|
||||
|
||||
## How to promote builds from develop to latest
|
||||
|
||||
You can use the Docker CLI to promote builds from develop to latest. Make sure to adjust:
|
||||
|
||||
- $name
|
||||
- $digest
|
||||
|
||||
```shell
|
||||
export AIO_NAME=$name
|
||||
export AIO_DIGEST=$digest
|
||||
docker pull nextcloud/$AIO_NAME@sha256:$AIO_DIGEST
|
||||
docker tag nextcloud/$AIO_NAME@sha256:$AIO_DIGEST nextcloud/$AIO_NAME\:latest
|
||||
docker push nextcloud/$AIO_NAME\:latest
|
||||
```
|
||||
|
||||
To automatically promoted the latest develop version you can use the following script:
|
||||
|
||||
**WARNING:** Make sure to verify that the latest develop tag is what you really want to deploy since someone could have pushed to main and created a new container in between.
|
||||
```shell
|
||||
export AIO_NAME=$name
|
||||
docker pull nextcloud/$AIO_NAME\:develop
|
||||
docker tag nextcloud/$AIO_NAME\:develop nextcloud/$AIO_NAME\:latest
|
||||
docker push nextcloud/$AIO_NAME\:latest
|
||||
```
|
||||
1. Verify that no job is running here: https://github.com/nextcloud-releases/all-in-one/actions/workflows/build_images.yml
|
||||
2. Go to https://github.com/nextcloud-releases/all-in-one/actions/workflows/promote-to-latest.yml, click on `Run workflow` and enter your desired container image name that you want to publish from develop to latest. Available image names are listed here: https://github.com/nextcloud-releases/all-in-one/blob/main/.github/workflows/build_images.yml#L21-L30
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: "3.1"
|
||||
version: "3.8"
|
||||
|
||||
volumes:
|
||||
nextcloud_aio_mastercontainer:
|
||||
|
||||
@@ -6,7 +6,7 @@ There are basically two ways how to migrate from an already existing Nextcloud i
|
||||
1. Migrate the files and the database which is much more complicated
|
||||
|
||||
### Migrate only the files
|
||||
**Please note**: If you used groupfolders before, you will need to restore the database, as well!
|
||||
**Please note**: If you used groupfolders or encrypted your files before, you will need to restore the database, as well!
|
||||
|
||||
The procedure for migrating only the files works like this:
|
||||
1. Take a backup of your former instance (especially from your datadirectory)
|
||||
@@ -20,7 +20,7 @@ The procedure for migrating only the files works like this:
|
||||
|
||||
### Migrate the files and the database
|
||||
**Please note**: this is much more complicated than migrating only the files and also not as failproof so be warned!<br>
|
||||
Also, some special apps that e.g. implement custom user backends like the `user_sql` app will most likely not work in Nextcloud AIO. Additionally, you will currently not be able to use local external storage in Nextcloud AIO since that is not supported, yet. See https://github.com/nextcloud/all-in-one/issues/76
|
||||
Also, you will currently not be able to use local external storage in Nextcloud AIO since that is not supported, yet. See https://github.com/nextcloud/all-in-one/issues/76
|
||||
|
||||
The procedure for migrating the files and the database works like this:
|
||||
1. Make sure that your old instance is on exactly the same version like the version used in Nextcloud AIO. (e.g. 23.0.0) If not, simply upgrade your former installation to that version or wait until the version used in Nextcloud AIO got updated to the same version of your former installation or the other way around.
|
||||
@@ -37,12 +37,12 @@ The procedure for migrating the files and the database works like this:
|
||||
export PG_DATABASE="nextcloud_db"
|
||||
sudo -u postgres psql <<END
|
||||
CREATE USER $PG_USER WITH PASSWORD '$PGDB_PASS';
|
||||
CREATE DATABASE $PG_DATABASE WITH OWNER $NCUSER TEMPLATE template0 ENCODING 'UTF8';
|
||||
CREATE DATABASE $PG_DATABASE WITH OWNER $PG_USER TEMPLATE template0 ENCODING 'UTF8';
|
||||
END
|
||||
```
|
||||
1. Run the following command to start the conversion:
|
||||
```
|
||||
occ db:convert-type --all-apps pgsql "$PG_USER" 127.0.0.1 "$PG_DATABASE"
|
||||
occ db:convert-type --all-apps --password "$PGDB_PASS" pgsql "$PG_USER" 127.0.0.1 "$PG_DATABASE"
|
||||
```
|
||||
**Please note:** You might need to change the ip-address `127.0.0.1` based on your exact installation.<br>
|
||||
Further information on the conversion is additionally available here: https://docs.nextcloud.com/server/stable/admin_manual/configuration_database/db_conversion.html#converting-database-type
|
||||
|
||||
@@ -5,16 +5,21 @@
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"ext-json": "*",
|
||||
"ext-sodium": "*",
|
||||
"ext-curl": "*",
|
||||
"slim/slim": "4.*",
|
||||
"php-di/slim-bridge": "^3.1",
|
||||
"guzzlehttp/guzzle": "^7.3",
|
||||
"guzzlehttp/psr7": "^1.8",
|
||||
"guzzlehttp/psr7": "^2.1.0",
|
||||
"http-interop/http-factory-guzzle": "^1.2",
|
||||
"slim/twig-view": "^3.2",
|
||||
"slim/csrf": "^1.2",
|
||||
"ext-apcu": "*"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"psalm": "psalm --threads=1",
|
||||
"psalm:update-baseline": "psalm --threads=1 --update-baseline"
|
||||
}
|
||||
}
|
||||
|
||||
577
php/composer.lock
generated
577
php/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -10,17 +10,18 @@
|
||||
"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%"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -98,6 +99,11 @@
|
||||
"name": "nextcloud_aio_nextcloud_data",
|
||||
"location": "/mnt/ncdata",
|
||||
"writeable": true
|
||||
},
|
||||
{
|
||||
"name": "%NEXTCLOUD_MOUNT%",
|
||||
"location": "%NEXTCLOUD_MOUNT%",
|
||||
"writeable": true
|
||||
}
|
||||
],
|
||||
"environmentVariables": [
|
||||
@@ -114,7 +120,6 @@
|
||||
"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%"
|
||||
@@ -194,7 +199,8 @@
|
||||
"internalPorts": [],
|
||||
"environmentVariables": [
|
||||
"BORG_PASSWORD=%BORGBACKUP_PASSWORD%",
|
||||
"BORG_MODE=%BORGBACKUP_MODE%"
|
||||
"BORG_MODE=%BORGBACKUP_MODE%",
|
||||
"SELECTED_RESTORE_TIME=%SELECTED_RESTORE_TIME%"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
@@ -271,11 +277,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": [
|
||||
|
||||
113
php/psalm-baseline.xml
Normal file
113
php/psalm-baseline.xml
Normal file
@@ -0,0 +1,113 @@
|
||||
<?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>
|
||||
<PossiblyInvalidArrayAccess occurrences="2">
|
||||
<code>$request->getParsedBody()['borg_backup_host_location']</code>
|
||||
<code>$request->getParsedBody()['domain']</code>
|
||||
</PossiblyInvalidArrayAccess>
|
||||
<PossiblyNullArgument occurrences="2">
|
||||
<code>$request->getParsedBody()['borg_backup_host_location']</code>
|
||||
<code>$request->getParsedBody()['domain']</code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullArrayAccess occurrences="2">
|
||||
<code>$request->getParsedBody()['borg_backup_host_location']</code>
|
||||
<code>$request->getParsedBody()['domain']</code>
|
||||
</PossiblyNullArrayAccess>
|
||||
</file>
|
||||
<file src="src/Controller/DockerController.php">
|
||||
<MissingParamType occurrences="7">
|
||||
<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>
|
||||
<PossiblyNullArgument occurrences="1">
|
||||
<code>$container</code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullArrayAccess occurrences="1">
|
||||
<code>$request->getParsedBody()['selected_restore_time']</code>
|
||||
</PossiblyNullArrayAccess>
|
||||
<PossiblyNullReference occurrences="5">
|
||||
<code>GetDependsOn</code>
|
||||
<code>GetDependsOn</code>
|
||||
<code>GetIdentifier</code>
|
||||
<code>GetIdentifier</code>
|
||||
<code>GetRunningState</code>
|
||||
</PossiblyNullReference>
|
||||
</file>
|
||||
<file src="src/Controller/LoginController.php">
|
||||
<MissingParamType occurrences="3">
|
||||
<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/Cron/cron.php">
|
||||
<PossiblyNullArgument occurrences="2">
|
||||
<code>$nextcloudContainer</code>
|
||||
<code>$nextcloudContainer</code>
|
||||
</PossiblyNullArgument>
|
||||
</file>
|
||||
<file src="src/Docker/DockerActionManager.php">
|
||||
<InvalidReturnType occurrences="1">
|
||||
<code>IContainerState</code>
|
||||
</InvalidReturnType>
|
||||
<InvalidScalarArgument occurrences="1">
|
||||
<code>$internalPort</code>
|
||||
</InvalidScalarArgument>
|
||||
<PossiblyFalseOperand occurrences="1">
|
||||
<code>strpos($fullDigest, "@")</code>
|
||||
</PossiblyFalseOperand>
|
||||
<PossiblyNullArgument occurrences="1">
|
||||
<code>$apacheContainer</code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullReference occurrences="1">
|
||||
<code>GetUpdateState</code>
|
||||
</PossiblyNullReference>
|
||||
<RedundantCondition occurrences="1">
|
||||
<code>$container->GetInternalPorts() !== null</code>
|
||||
</RedundantCondition>
|
||||
</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>
|
||||
@@ -87,11 +87,16 @@ $app->get('/containers', function ($request, $response, $args) use ($container)
|
||||
'was_start_button_clicked' => $configurationManager->wasStartButtonClicked(),
|
||||
'has_update_available' => $dockerActionManger->isAnyUpdateAvailable(),
|
||||
'last_backup_time' => $configurationManager->GetLastBackupTime(),
|
||||
'backup_times' => $configurationManager->GetBackupTimes(),
|
||||
]);
|
||||
})->setName('profile');
|
||||
$app->get('/login', function ($request, $response, $args) {
|
||||
$app->get('/login', function ($request, $response, $args) use ($container) {
|
||||
$view = Twig::fromRequest($request);
|
||||
return $view->render($response, 'login.twig');
|
||||
/** @var \AIO\Docker\DockerActionManager $dockerActionManger */
|
||||
$dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
|
||||
return $view->render($response, 'login.twig', [
|
||||
'is_login_allowed' => $dockerActionManger->isLoginAllowed(),
|
||||
]);
|
||||
});
|
||||
$app->get('/setup', function ($request, $response, $args) use ($container) {
|
||||
$view = Twig::fromRequest($request);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,11 +51,17 @@ class ContainerDefinitionFetcher
|
||||
foreach ($data['production'] as $entry) {
|
||||
$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 +73,18 @@ class ContainerDefinitionFetcher
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if($value['name'] === '%NEXTCLOUD_MOUNT%') {
|
||||
$value['name'] = $this->configurationManager->GetNextcloudMount();
|
||||
if($value['name'] === '') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if($value['location'] === '%NEXTCLOUD_MOUNT%') {
|
||||
$value['location'] = $this->configurationManager->GetNextcloudMount();
|
||||
if($value['location'] === '') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$volumes->AddVolume(
|
||||
new ContainerVolume(
|
||||
$value['name'],
|
||||
|
||||
@@ -26,7 +26,7 @@ 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) {
|
||||
@@ -83,6 +83,7 @@ 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;
|
||||
@@ -125,14 +126,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,7 +146,7 @@ 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() != '') {
|
||||
@@ -165,7 +167,7 @@ class DockerController
|
||||
$this->PerformRecursiveContainerStart($id);
|
||||
}
|
||||
|
||||
private function StopDomaincheckContainer()
|
||||
private function StopDomaincheckContainer() : void
|
||||
{
|
||||
$id = 'nextcloud-aio-domaincheck';
|
||||
$this->PerformRecursiveContainerStop($id);
|
||||
|
||||
@@ -12,12 +12,17 @@ use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
class LoginController
|
||||
{
|
||||
private AuthManager $authManager;
|
||||
private DockerActionManager $dockerActionManager;
|
||||
|
||||
public function __construct(AuthManager $authManager) {
|
||||
public function __construct(AuthManager $authManager, DockerActionManager $dockerActionManager) {
|
||||
$this->authManager = $authManager;
|
||||
$this->dockerActionManager = $dockerActionManager;
|
||||
}
|
||||
|
||||
public function TryLogin(Request $request, Response $response, $args) : Response {
|
||||
if (!$this->dockerActionManager->isLoginAllowed()) {
|
||||
return $response->withHeader('Location', '/')->withStatus(302);
|
||||
}
|
||||
$password = $request->getParsedBody()['password'];
|
||||
if($this->authManager->CheckCredentials($password)) {
|
||||
$this->authManager->SetAuthState(true);
|
||||
|
||||
@@ -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,28 @@ 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];
|
||||
}
|
||||
}
|
||||
|
||||
return $backupTimes;
|
||||
}
|
||||
|
||||
public function wasStartButtonClicked() : bool {
|
||||
if (isset($this->GetConfig()['wasStartButtonClicked'])) {
|
||||
return true;
|
||||
@@ -100,6 +122,11 @@ class ConfigurationManager
|
||||
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,10 +144,18 @@ 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);
|
||||
|
||||
@@ -152,6 +187,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'])) {
|
||||
@@ -172,14 +216,18 @@ class ConfigurationManager
|
||||
|
||||
$isValidPath = false;
|
||||
foreach($allowedPrefixes as $allowedPrefix) {
|
||||
if(str_starts_with($location, $allowedPrefix)) {
|
||||
if(str_starts_with($location, $allowedPrefix) && !str_ends_with($location, '/')) {
|
||||
$isValidPath = true;
|
||||
break;
|
||||
}
|
||||
if ($location === '/var/backups') {
|
||||
$isValidPath = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$isValidPath) {
|
||||
throw new InvalidSettingConfigurationException("Path must start with /mnt/ or /media/.");
|
||||
throw new InvalidSettingConfigurationException("The path must start with '/mnt/' or '/media/' or be equal to '/var/backups'.");
|
||||
}
|
||||
|
||||
|
||||
@@ -188,6 +236,29 @@ class ConfigurationManager
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
public function GetApachePort() : string {
|
||||
$port = getenv('APACHE_PORT');
|
||||
if ($port === false) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['apache_port']) || $config['apache_port'] === '') {
|
||||
$config['apache_port'] = '443';
|
||||
}
|
||||
return $config['apache_port'];
|
||||
} else {
|
||||
if(file_exists(DataConst::GetConfigFile())) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['apache_port'])) {
|
||||
$config['apache_port'] = '';
|
||||
}
|
||||
if ($port !== $config['apache_port']) {
|
||||
$config['apache_port'] = $port;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
}
|
||||
return $port;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
@@ -215,4 +286,27 @@ class ConfigurationManager
|
||||
|
||||
return $config['backup-mode'];
|
||||
}
|
||||
|
||||
public function GetNextcloudMount() : string {
|
||||
$mount = getenv('NEXTCLOUD_MOUNT');
|
||||
if ($mount === false) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['nextcloud_mount'])) {
|
||||
$config['nextcloud_mount'] = '';
|
||||
}
|
||||
return $config['nextcloud_mount'];
|
||||
} else {
|
||||
if(file_exists(DataConst::GetConfigFile())) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['nextcloud_mount'])) {
|
||||
$config['nextcloud_mount'] = '';
|
||||
}
|
||||
if ($mount !== $config['nextcloud_mount']) {
|
||||
$config['nextcloud_mount'] = $mount;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
}
|
||||
return $mount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ use AIO\Container\State\VersionDifferentState;
|
||||
use AIO\Container\State\StoppedState;
|
||||
use AIO\Container\State\VersionEqualState;
|
||||
use AIO\Data\ConfigurationManager;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use GuzzleHttp\Exception\ServerException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use AIO\ContainerDefinitionFetcher;
|
||||
use http\Env\Response;
|
||||
|
||||
@@ -47,12 +46,7 @@ class DockerActionManager
|
||||
}
|
||||
|
||||
private function BuildImageName(Container $container) : string {
|
||||
$channel = $this->GetCurrentChannel();
|
||||
if ($channel === 'develop') {
|
||||
return $container->GetContainerName() . ':develop';
|
||||
} else {
|
||||
return $container->GetContainerName() . ':latest';
|
||||
}
|
||||
return $container->GetContainerName() . ':' . $this->GetCurrentChannel();
|
||||
}
|
||||
|
||||
public function GetContainerRunningState(Container $container) : IContainerState
|
||||
@@ -60,12 +54,11 @@ class DockerActionManager
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
|
||||
try {
|
||||
$response = $this->guzzleClient->get($url);
|
||||
} catch (ClientException $ex) {
|
||||
if($ex->getCode() === 404) {
|
||||
} catch (RequestException $e) {
|
||||
if ($e->getCode() === 404) {
|
||||
return new ImageDoesNotExistState();
|
||||
}
|
||||
|
||||
throw $ex;
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$responseBody = json_decode((string)$response->getBody(), true);
|
||||
@@ -79,12 +72,7 @@ class DockerActionManager
|
||||
|
||||
public function GetContainerUpdateState(Container $container) : IContainerState
|
||||
{
|
||||
$channel = $this->GetCurrentChannel();
|
||||
if ($channel === 'develop') {
|
||||
$tag = 'develop';
|
||||
} else {
|
||||
$tag = 'latest';
|
||||
}
|
||||
$tag = $this->GetCurrentChannel();
|
||||
|
||||
$runningDigest = $this->GetRepoDigestOfContainer($container->GetIdentifier());
|
||||
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($container->GetContainerName(), $tag);
|
||||
@@ -121,11 +109,11 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function DeleteContainer(Container $container) {
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s', urlencode($container->GetIdentifier())));
|
||||
public function DeleteContainer(Container $container) : void {
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s?v=true', urlencode($container->GetIdentifier())));
|
||||
try {
|
||||
$this->guzzleClient->delete($url);
|
||||
} catch (\GuzzleHttp\Exception\RequestException $e) {
|
||||
} catch (RequestException $e) {
|
||||
if ($e->getCode() !== 404) {
|
||||
throw $e;
|
||||
}
|
||||
@@ -154,12 +142,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) {
|
||||
@@ -182,7 +170,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;
|
||||
@@ -224,6 +212,10 @@ 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();
|
||||
} else {
|
||||
$replacements[1] = $this->configurationManager->GetSecret($out[1]);
|
||||
}
|
||||
@@ -267,13 +259,13 @@ class DockerActionManager
|
||||
);
|
||||
}
|
||||
|
||||
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 (ClientException $ex) {
|
||||
throw $ex;
|
||||
} catch (RequestException $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,10 +283,9 @@ class DockerActionManager
|
||||
return $updateAvailable;
|
||||
}
|
||||
|
||||
public function isAnyUpdateAvailable() {
|
||||
public function isAnyUpdateAvailable() : bool {
|
||||
$id = 'nextcloud-aio-apache';
|
||||
|
||||
|
||||
if ($this->isContainerUpdateAvailable($id) !== "") {
|
||||
return true;
|
||||
} else {
|
||||
@@ -339,7 +330,7 @@ class DockerActionManager
|
||||
$tag = $tagArray[1];
|
||||
apcu_add($cacheKey, $tag);
|
||||
return $tag;
|
||||
} catch (\Exception $ex) {
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
return 'latest';
|
||||
@@ -350,12 +341,7 @@ class DockerActionManager
|
||||
$imageName = 'nextcloud/all-in-one';
|
||||
$containerName = 'nextcloud-aio-mastercontainer';
|
||||
|
||||
$channel = $this->GetCurrentChannel();
|
||||
if ($channel === 'develop') {
|
||||
$tag = 'develop';
|
||||
} else {
|
||||
$tag = 'latest';
|
||||
}
|
||||
$tag = $this->GetCurrentChannel();
|
||||
|
||||
$runningDigest = $this->GetRepoDigestOfContainer($containerName);
|
||||
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($imageName, $tag);
|
||||
@@ -367,7 +353,7 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -413,7 +399,7 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function DisconnectContainerFromNetwork(Container $container)
|
||||
public function DisconnectContainerFromNetwork(Container $container) : void
|
||||
{
|
||||
|
||||
$url = $this->BuildApiUrl(
|
||||
@@ -430,10 +416,11 @@ class DockerActionManager
|
||||
],
|
||||
]
|
||||
);
|
||||
} catch (\GuzzleHttp\Exception\RequestException $e) {}
|
||||
} catch (RequestException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
private function ConnectContainerIdToNetwork(string $id)
|
||||
private function ConnectContainerIdToNetwork(string $id) : void
|
||||
{
|
||||
$url = $this->BuildApiUrl('networks/create');
|
||||
try {
|
||||
@@ -448,8 +435,9 @@ class DockerActionManager
|
||||
]
|
||||
]
|
||||
);
|
||||
} catch (ClientException $e) {
|
||||
if($e->getCode() !== 409) {
|
||||
} catch (RequestException $e) {
|
||||
// 409 is undocumented and gets thrown if the network already exists.
|
||||
if ($e->getCode() !== 409) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
@@ -467,28 +455,29 @@ class DockerActionManager
|
||||
]
|
||||
]
|
||||
);
|
||||
} catch (ClientException $e) {
|
||||
if($e->getCode() !== 403) {
|
||||
} catch (RequestException $e) {
|
||||
// 403 is undocumented and gets thrown if a specific container is already part of a network
|
||||
if ($e->getCode() !== 403) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
} catch (\GuzzleHttp\Exception\RequestException $e) {
|
||||
} catch (RequestException $e) {
|
||||
if ($e->getCode() !== 404 && $e->getCode() !== 304) {
|
||||
throw $e;
|
||||
}
|
||||
@@ -501,11 +490,11 @@ class DockerActionManager
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($containerName)));
|
||||
try {
|
||||
$response = $this->guzzleClient->get($url);
|
||||
} catch (ClientException $ex) {
|
||||
if ($ex->getCode() === 404) {
|
||||
} catch (RequestException $e) {
|
||||
if ($e->getCode() === 404) {
|
||||
return -1;
|
||||
}
|
||||
throw $ex;
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$responseBody = json_decode((string)$response->getBody(), true);
|
||||
@@ -517,4 +506,13 @@ class DockerActionManager
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public function isLoginAllowed() : bool {
|
||||
$id = 'nextcloud-aio-apache';
|
||||
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
if ($this->GetContainerStartingState($apacheContainer) instanceof RunningState) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h1>Nextcloud AIO Beta v0.1.0</h1>
|
||||
<h1>Nextcloud AIO Beta v0.6.0</h1>
|
||||
This is beta software and not production ready.<br><br>
|
||||
|
||||
{% set isAnyRunning = false %}
|
||||
@@ -48,19 +48,29 @@
|
||||
{% 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 />
|
||||
Mastercontainer update currently running. It will restart the mastercontainer soon which will make it unavailable for a moment. Please wait until that's done.<br /><br />
|
||||
<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-adress, you can use e.g. <a href="https://ddclient.net/">DDclient</a> with a compatible domain provider for DNS updates.
|
||||
{% 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 %}
|
||||
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.
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if domain != "" %}
|
||||
@@ -99,18 +109,21 @@
|
||||
</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 />
|
||||
{% 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,18 +139,22 @@
|
||||
{% 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">
|
||||
<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>
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
⚠ Please update your mastercontainer. Afterwards, you will be able to start your containers again.<br><br>
|
||||
{% 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 %}
|
||||
@@ -145,13 +162,16 @@
|
||||
{% 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>
|
||||
{% if isAnyRunning == false %}
|
||||
⚠ A mastercontainer update is available. Please click on the button below to update it.<br><br>
|
||||
<form method="POST" action="/api/docker/watchtower" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Update mastercontainer" />
|
||||
</form>
|
||||
{% else %}
|
||||
⚠ A mastercontainer update is available. Please stop your containers in order to be able to update the mastercontainer.
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -167,7 +187,7 @@
|
||||
<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 /mnt/ or /media/ so e.g. /mnt/backup
|
||||
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>
|
||||
{% endif %}
|
||||
|
||||
{% if borg_backup_host_location != "" %}
|
||||
@@ -177,9 +197,9 @@
|
||||
<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 %}
|
||||
{% if borg_backup_mode == "backup" %}
|
||||
<span class="status success"></span> Last {{ borg_backup_mode }} succesful on {{ last_backup_time }}! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
<span class="status success"></span> Last {{ borg_backup_mode }} successful on {{ last_backup_time }}! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
{% else %}
|
||||
<span class="status success"></span> Last {{ borg_backup_mode }} succesful! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
<span class="status success"></span> Last {{ borg_backup_mode }} successful! (<a href="/api/docker/logs?id=nextcloud-aio-borgbackup">Logs</a>)<br /><br />
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -190,6 +210,7 @@
|
||||
Backed up will get all important data of your Nextcloud AIO instance like the database, your files and configuration files of the mastercontainer and else. <br /><br/>
|
||||
The backup itself will use a tool that is called <a href="https://github.com/borgbackup/borg#what-is-borgbackup">BorgBackup<a/> which is a well-known server backup tool that efficiently backs up your files and encrypts them on the fly. <br /><br/>
|
||||
Backups get created in the following directory on the host: {{ borg_backup_host_location }}/borg <br /><br/>
|
||||
Be aware that this solution does not back up files and folders that are mounted into Nextcloud using the external storage app. <br /><br/>
|
||||
|
||||
{% if isApacheStarting != true %}
|
||||
<form method="POST" action="/api/docker/backup" class="xhr">
|
||||
@@ -206,11 +227,16 @@
|
||||
<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">
|
||||
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 %}
|
||||
|
||||
@@ -5,13 +5,18 @@
|
||||
<div class="login">
|
||||
<img src="/img/logo-blue.svg" style="margin-left: auto;margin-right: auto;display: block;">
|
||||
<h1>Nextcloud AIO Login</h1>
|
||||
<p>Log in using your Nextcloud AIO password. If you don't have it, you can also use the automatic login from your Nextcloud.</p>
|
||||
<form method="POST" action="/api/auth/login">
|
||||
<input type="text" name="password" placeholder="Password" />
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" class="button" value="Login" />
|
||||
</form>
|
||||
{% if is_login_allowed == true %}
|
||||
<p>Log in using your Nextcloud AIO password.</p>
|
||||
<form method="POST" action="/api/auth/login">
|
||||
<input type="text" name="password" placeholder="Password" />
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input type="submit" class="button" value="Login" />
|
||||
</form>
|
||||
{% else %}
|
||||
<p>The login is blocked since Nextcloud is running. Please use the automatic login from your Nextcloud.<br><br>
|
||||
You can unblock the login by running 'sudo docker stop nextcloud-aio-apache'.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
149
readme.md
149
readme.md
@@ -15,53 +15,80 @@ Included are:
|
||||
**Found a bug?** Please file an issue at https://github.com/nextcloud/all-in-one
|
||||
|
||||
## How to use this?
|
||||
1. Install Docker on your Linux installations using:
|
||||
|
||||
```
|
||||
curl -fsSL get.docker.com | sudo sh
|
||||
```
|
||||
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>
|
||||
|
||||
```
|
||||
sudo docker pull nextcloud/all-in-one:latest
|
||||
```
|
||||
3. Run the following command in order to start the container:
|
||||
```
|
||||
# For x64 CPUs:
|
||||
sudo 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>
|
||||
<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 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-arm64
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
```
|
||||
sudo 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
|
||||
```
|
||||
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>
|
||||
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
|
||||
`https://your-domain-that-points-to-this-server.tld:8443`
|
||||
5. Please do not forget to open port `3478/TCP` and `3478/UDP` for the Talk container!
|
||||
|
||||
## 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?
|
||||
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
|
||||
- `443/TCP`: will be used by the Apache container later on and needs to be open
|
||||
- `3478/TCP` and `3478/UDP`: will be used by the Turnserver inside the Talk container and needs to be open
|
||||
|
||||
### 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.
|
||||
@@ -86,11 +113,66 @@ 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.
|
||||
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.
|
||||
|
||||
### How to allow the Nextcloud container to access directories on the host?
|
||||
By default, the Nextcloud container is confined and cannot access directories on the host OS. You might want to change this when you are planning to use local external storage in Nextcloud to store some files outside the data directory and can do so by adding the environmental variable `NEXTCLOUD_MOUNT` to the initial startup of the mastercontainer. Allowed values for that variable are strings that are equal to or start with `/mnt/` or `/media/` or are equal to `/var/backups` and unequal to `/mnt/ncdata`. Two examples for this are: `-e NEXTCLOUD_MOUNT="/mnt/"` or `-e NEXTCLOUD_MOUNT="/media/"`. After doing so, please make sure to apply the correct permissions to the directories that you want to use in Nextcloud. E.g. `sudo chown -R 33:0 /mnt/your-drive-mountpoint` should make it work. You can then navigate to the apps management page, activate the external storage app, navigate to `https://your-nc-domain.com/settings/admin/externalstorages` and add a local external storage directory that will be accessible inside the container at the same place that you've entered. E.g. `/mnt/your-drive-mountpoint` will be mounted to `/mnt/your-drive-mountpoint` inside the container, etc. Be aware though that these locations will not be covered by the built-in backup solution!
|
||||
|
||||
### 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/
|
||||
|
||||
### Access/Edit Nextcloud files/folders manually
|
||||
The files and folders that you add to Nextcloud are by default stored in the following directory: `/var/lib/docker/volumes/nextcloud_aio_nextcloud_data/_data/` on the host. If needed, you can modify/add/delete files/folders there but **ATTENTION**: be very careful when doing so because you might corrupt your AIO installation! Best is to create a backup using the built-in backup solution before editing/changing files/folders in there because you will then be able to restore your instance to the backed up state.
|
||||
@@ -104,5 +186,14 @@ 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
|
||||
|
||||
### USER_SQL
|
||||
If you want to use the user_sql app, the easiest way is to create an additional database container and add it to the docker network `nextcloud-aio`. Then the Nextcloud container should be able to talk to the database container using its name.
|
||||
|
||||
### How to migrate from an already existing Nextcloud installation to Nextcloud AIO?
|
||||
Please see the following documentation on this: [migration.md](https://github.com/nextcloud/all-in-one/blob/main/migration.md)
|
||||
|
||||
68
reverse-proxy.md
Normal file
68
reverse-proxy.md
Normal file
@@ -0,0 +1,68 @@
|
||||
## Reverse Proxy Config
|
||||
|
||||
Basically, you need to specify the port that the apache container shall use and modify the startup command a bit.
|
||||
|
||||
All examples below will use port `11000` as example apache port. Also it is supposed that the reverse proxy runs on the same server like AIO, hence `localhost` is used and not an internal ip-address to point to the AIO instance. Modify both to your needings.
|
||||
|
||||
### Caddy reverse proxy config example
|
||||
|
||||
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.
|
||||
|
||||
### Startup command
|
||||
|
||||
```
|
||||
# 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>
|
||||
|
||||
After doing so, you should be able to access the AIO Interface via `https://internal.ip.of.this.server:8080`. Enter your domain that you've entered in the reverse proxy config and you should be done. Please do not forget to open port `3478/TCP` and `3478/UDP` for the Talk container!
|
||||
|
||||
### 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`.
|
||||
Reference in New Issue
Block a user