Compare commits

..

2 Commits

Author SHA1 Message Date
Jean-Yves
0f69143531 Merge branch 'main' into enh/noid/overwrite 2024-09-28 20:26:14 +02:00
Jean-Yves
f2e71532e7 Add feature
Signed-off-by: Jean-Yves <7360784+docjyJ@users.noreply.github.com>
2024-08-25 17:21:38 +02:00
46 changed files with 418 additions and 278 deletions

View File

@@ -25,7 +25,7 @@ jobs:
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*APCu-\)[0-9.]*|\1$apcu_version|" ./Containers/nextcloud/Dockerfile
sed -i "s|pecl install APCu.*\;|pecl install APCu-$apcu_version\;|" ./Containers/nextcloud/Dockerfile
# Memcached
memcached_version="$(
@@ -36,7 +36,7 @@ jobs:
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*memcached-\)[0-9.]*|\1$memcached_version|" ./Containers/nextcloud/Dockerfile
sed -i "s|pecl install memcached.* |pecl install memcached-$memcached_version |" ./Containers/nextcloud/Dockerfile
# Redis
redis_version="$(
@@ -47,18 +47,18 @@ jobs:
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*redis-\)[0-9.]*|\1$redis_version|" ./Containers/nextcloud/Dockerfile
sed -i "s|pecl install redis.* |pecl install redis-$redis_version |" ./Containers/nextcloud/Dockerfile
# Imagick
imagick_version="$(
git ls-remote --tags https://github.com/Imagick/imagick.git \
git ls-remote --tags https://github.com/mkoppanen/imagick.git \
| cut -d/ -f3 \
| grep -viE '[a-z]' \
| tr -d '^{}' \
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*imagick-\)[0-9.]*|\1$imagick_version|" ./Containers/nextcloud/Dockerfile
sed -i "s|pecl install imagick.*\;|pecl install imagick-$imagick_version\;|" ./Containers/nextcloud/Dockerfile
# Igbinary
igbinary_version="$(
@@ -69,7 +69,7 @@ jobs:
| sort -V \
| tail -1
)"
sed -i "s|\(pecl install[^;]*igbinary-\)[0-9.]*|\1$igbinary_version|" ./Containers/nextcloud/Dockerfile
sed -i "s|pecl install igbinary.*\;|pecl install igbinary-$igbinary_version\;|" ./Containers/nextcloud/Dockerfile
# Nextcloud
NC_MAJOR="$(grep "ENV NEXTCLOUD_VERSION" ./Containers/nextcloud/Dockerfile | grep -oP '[23][0-9]')"

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest
# Probably from this file: https://github.com/Cisco-Talos/clamav-docker/blob/main/clamav/1.3/alpine/Dockerfile
FROM clamav/clamav:1.4.1-7
FROM clamav/clamav:1.4.1-5
COPY clamav.conf /clamav.conf
COPY --chmod=775 start.script /start.script

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest
# From a file located probably somewhere here: https://github.com/CollaboraOnline/online/tree/master/docker
FROM collabora/code:24.04.8.1.1
FROM collabora/code:24.04.7.2.1
USER root
ARG DEBIAN_FRONTEND=noninteractive

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest
# Probably from here https://github.com/elastic/elasticsearch/blob/main/distribution/docker/src/docker/Dockerfile
FROM elasticsearch:8.15.2
FROM elasticsearch:8.15.1
USER root

View File

@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:latest
FROM golang:1.23.2-alpine3.20 AS go
FROM golang:1.23.1-alpine3.20 AS go
ENV IMAGINARY_HASH=8f36a26c448be8c151a3878404b75fcd1cd3cf0c
ENV IMAGINARY_HASH=6cd9edd1d3fb151eb773c14552886e4fc8e50138
RUN set -ex; \
apk add --no-cache \

View File

@@ -6,7 +6,7 @@ FROM docker:27.3.1-cli AS docker
FROM caddy:2.8.4-alpine AS caddy
# From https://github.com/docker-library/php/blob/master/8.3/alpine3.20/fpm/Dockerfile
FROM php:8.3.12-fpm-alpine3.20
FROM php:8.3.11-fpm-alpine3.20
EXPOSE 80
EXPOSE 8080

View File

@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
FROM php:8.2.24-fpm-alpine3.20
FROM php:8.2.23-fpm-alpine3.20
ENV PHP_MEMORY_LIMIT=512M
ENV PHP_UPLOAD_LIMIT=10G
@@ -8,7 +8,7 @@ ENV SOURCE_LOCATION=/usr/src/nextcloud
ENV REDIS_DB_INDEX=0
# AIO settings start # Do not remove or change this line!
ENV NEXTCLOUD_VERSION=29.0.8
ENV NEXTCLOUD_VERSION=29.0.7
ENV AIO_TOKEN=123456
ENV AIO_URL=localhost
# AIO settings end # Do not remove or change this line!
@@ -78,10 +78,12 @@ RUN set -ex; \
; \
\
# pecl will claim success even if one install fails, so we need to perform each install separately
pecl install igbinary-3.2.16; \
pecl install igbinary-3.2.16; \
pecl install APCu-5.1.24; \
pecl install -D 'enable-memcached-igbinary="yes"' memcached-3.2.0; \
pecl install -D 'enable-redis-igbinary="yes" enable-redis-zstd="yes" enable-redis-lz4="yes"' redis-6.1.0; \
pecl install memcached-3.2.0 \
--configureoptions 'enable-memcached-igbinary="yes"'; \
pecl install redis-6.0.2 \
--configureoptions 'enable-redis-igbinary="yes" enable-redis-zstd="yes" enable-redis-lz4="yes"'; \
pecl install imagick-3.7.0; \
\
docker-php-ext-enable \

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest
# From https://github.com/docker-library/redis/blob/master/7.2/alpine/Dockerfile
FROM redis:7.2.6-alpine
FROM redis:7.2.5-alpine
COPY --chmod=775 start.sh /start.sh

View File

@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
FROM python:3.13.0-alpine3.20
FROM python:3.12.6-alpine3.20
COPY --chmod=775 start.sh /start.sh

View File

@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
FROM nats:2.10.21-scratch AS nats
FROM nats:2.10.20-scratch AS nats
FROM eturnal/eturnal:1.12.0 AS eturnal
FROM strukturag/nextcloud-spreed-signaling:2.0.0 AS signaling
FROM alpine:3.20.3 AS janus

View File

@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest
FROM ghcr.io/nextcloud-releases/whiteboard:v1.0.3
FROM ghcr.io/nextcloud-releases/whiteboard:v1.0.2
USER root
RUN set -ex; \

View File

@@ -17,11 +17,6 @@
"source": "%NEXTCLOUD_DATADIR%",
"destination": "/mnt/ncdata",
"writeable": false
},
{
"source": "%NEXTCLOUD_MOUNT%",
"destination": "%NEXTCLOUD_MOUNT%",
"writeable": false
}
],
"devices": [

View File

@@ -29,6 +29,7 @@ services:
# NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS: imagick # This allows to add additional php extensions to the Nextcloud container permanently. Default is imagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-php-extensions-permanently-to-the-nextcloud-container
# NEXTCLOUD_ENABLE_DRI_DEVICE: true # This allows to enable the /dev/dri device in the Nextcloud container. ⚠️⚠️⚠️ Warning: this only works if the '/dev/dri' device is present on the host! If it should not exist on your host, don't set this to true as otherwise the Nextcloud container will fail to start! See https://github.com/nextcloud/all-in-one#how-to-enable-hardware-transcoding-for-nextcloud
# NEXTCLOUD_KEEP_DISABLED_APPS: false # Setting this to true will keep Nextcloud apps that are disabled in the AIO interface and not uninstall them if they should be installed. See https://github.com/nextcloud/all-in-one#how-to-keep-disabled-apps
# DISABLE_OVERWRITE_URL: true # Setting this to true will disable the ability to overwrite the URL in the AIO interface. See https://github.com/nextcloud/all-in-one#can-i-use-aio-with-multiple-domains
# TALK_PORT: 3478 # This allows to adjust the port that the talk container is using. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-talk-port
# WATCHTOWER_DOCKER_SOCKET_PATH: /var/run/docker.sock # Needs to be specified if the docker socket on the host is not located in the default '/var/run/docker.sock'. Otherwise mastercontainer updates will fail. For macos it needs to be '/var/run/docker.sock'
# security_opt: ["label:disable"] # Is needed when using SELinux

View File

@@ -33,7 +33,6 @@ docker run \
--rm \
--name nextcloud-aio-mastercontainer \
--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
--volume /var/run/docker.sock:/var/run/docker.sock \
nextcloud/all-in-one:latest
```
@@ -56,7 +55,6 @@ Note: You can restart the server by preceding the command with other environment
|-----------------------------------------|----------------------------------------|
| `composer run dev` | Starts the development server |
| `composer run psalm` | Run Psalm static analysis |
| `composer run psalm:strict` | Run Psalm static analysis strict |
| `composer run psalm:update-baseline` | Run Psalm with `--update-baseline` arg |
| `composer run lint` | Run PHP Syntax check |
| `composer run lint:twig` | Run Twig Syntax check |

View File

@@ -1,36 +1,35 @@
{
"autoload": {
"psr-4": {
"AIO\\": ["src/"]
}
},
"require": {
"php": "8.3.*",
"ext-json": "*",
"ext-sodium": "*",
"ext-curl": "*",
"slim/slim": "^4.11",
"php-di/slim-bridge": "^3.3",
"guzzlehttp/guzzle": "^7.5",
"guzzlehttp/psr7": "^2.4",
"http-interop/http-factory-guzzle": "^1.2",
"slim/twig-view": "^3.3",
"slim/csrf": "^1.3",
"ext-apcu": "*"
},
"require-dev": {
"sserbin/twig-linter": "@dev",
"vimeo/psalm": "^5.25",
"wapmorgan/php-deprecation-detector": "dev-master"
},
"scripts": {
"dev": [
"Composer\\Config::disableProcessTimeout",
"php -S localhost:8080 -t public"
],
"autoload": {
"psr-4": {
"AIO\\": ["src/"]
}
},
"require": {
"php": "8.3.*",
"ext-json": "*",
"ext-sodium": "*",
"ext-curl": "*",
"slim/slim": "^4.11",
"php-di/slim-bridge": "^3.3",
"guzzlehttp/guzzle": "^7.5",
"guzzlehttp/psr7": "^2.4",
"http-interop/http-factory-guzzle": "^1.2",
"slim/twig-view": "^3.3",
"slim/csrf": "^1.3",
"ext-apcu": "*"
},
"require-dev": {
"sserbin/twig-linter": "@dev",
"vimeo/psalm": "^5.25",
"wapmorgan/php-deprecation-detector": "dev-master"
},
"scripts": {
"dev": [
"Composer\\Config::disableProcessTimeout",
"php -S localhost:8080 -t public"
],
"psalm": "psalm --threads=1",
"psalm:update-baseline": "psalm --threads=1 --monochrome --no-progress --output-format=text --update-baseline",
"psalm:strict": "psalm --threads=1 --show-info=true",
"lint": "php -l src/*.php src/**/*.php public/index.php",
"lint:twig": "twig-linter lint ./templates",
"php-deprecation-detector": "phpdd scan -n -t 8.3 src/*.php src/**/*.php public/index.php"

16
php/composer.lock generated
View File

@@ -2469,16 +2469,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.19.4",
"version": "v4.19.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2"
"reference": "0ed4c8949a32986043e977dbe14776c14d644c45"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2",
"reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ed4c8949a32986043e977dbe14776c14d644c45",
"reference": "0ed4c8949a32986043e977dbe14776c14d644c45",
"shasum": ""
},
"require": {
@@ -2487,7 +2487,7 @@
},
"require-dev": {
"ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
},
"bin": [
"bin/php-parse"
@@ -2519,9 +2519,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.2"
},
"time": "2024-09-29T15:01:53+00:00"
"time": "2024-09-17T19:36:00+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@@ -3742,6 +3742,6 @@
"ext-curl": "*",
"ext-apcu": "*"
},
"platform-dev": {},
"platform-dev": [],
"plugin-api-version": "2.6.0"
}

View File

@@ -188,15 +188,15 @@
"ADMIN_USER=admin",
"ADMIN_PASSWORD=%NEXTCLOUD_PASSWORD%",
"NEXTCLOUD_DATA_DIR=/mnt/ncdata",
"OVERWRITEHOST=%NC_DOMAIN%",
"OVERWRITEPROTOCOL=https",
"OVERWRITEHOST=%OVERWRITEHOST%",
"OVERWRITEPROTOCOL=%OVERWRITEPROTOCOL%",
"TURN_SECRET=%TURN_SECRET%",
"SIGNALING_SECRET=%SIGNALING_SECRET%",
"ONLYOFFICE_SECRET=%ONLYOFFICE_SECRET%",
"AIO_URL=%AIO_URL%",
"NEXTCLOUD_MOUNT=%NEXTCLOUD_MOUNT%",
"CLAMAV_ENABLED=%CLAMAV_ENABLED%",
"CLAMAV_HOST=nextcloud-aio-clamav",
"CLAMAV_HOST=nextcloud-aio-clamav.nextcloud-aio",
"ONLYOFFICE_ENABLED=%ONLYOFFICE_ENABLED%",
"COLLABORA_ENABLED=%COLLABORA_ENABLED%",
"COLLABORA_HOST=nextcloud-aio-collabora",
@@ -206,12 +206,12 @@
"TZ=%TIMEZONE%",
"TALK_PORT=%TALK_PORT%",
"IMAGINARY_ENABLED=%IMAGINARY_ENABLED%",
"IMAGINARY_HOST=nextcloud-aio-imaginary",
"IMAGINARY_HOST=nextcloud-aio-imaginary.nextcloud-aio",
"CLAMAV_MAX_SIZE=%APACHE_MAX_SIZE%",
"PHP_UPLOAD_LIMIT=%NEXTCLOUD_UPLOAD_LIMIT%",
"PHP_MEMORY_LIMIT=%NEXTCLOUD_MEMORY_LIMIT%",
"FULLTEXTSEARCH_ENABLED=%FULLTEXTSEARCH_ENABLED%",
"FULLTEXTSEARCH_HOST=nextcloud-aio-fulltextsearch",
"FULLTEXTSEARCH_HOST=nextcloud-aio-fulltextsearch.nextcloud-aio",
"PHP_MAX_TIME=%NEXTCLOUD_MAX_TIME%",
"TRUSTED_CACERTS_DIR=%NEXTCLOUD_TRUSTED_CACERTS_DIR%",
"STARTUP_APPS=%NEXTCLOUD_STARTUP_APPS%",
@@ -220,7 +220,7 @@
"INSTALL_LATEST_MAJOR=%INSTALL_LATEST_MAJOR%",
"TALK_RECORDING_ENABLED=%TALK_RECORDING_ENABLED%",
"RECORDING_SECRET=%RECORDING_SECRET%",
"TALK_RECORDING_HOST=nextcloud-aio-talk-recording",
"TALK_RECORDING_HOST=nextcloud-aio-talk-recording.nextcloud-aio",
"FULLTEXTSEARCH_PASSWORD=%FULLTEXTSEARCH_PASSWORD%",
"DOCKER_SOCKET_PROXY_ENABLED=%DOCKER_SOCKET_PROXY_ENABLED%",
"REMOVE_DISABLED_APPS=%REMOVE_DISABLED_APPS%",

View File

@@ -1,22 +1,17 @@
<?xml version="1.0"?>
<psalm
errorLevel="2"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
errorBaseline="psalm-baseline.xml"
xsi:schemaLocation="https://getpsalm.org/schema/config"
errorBaseline="psalm-baseline.xml"
findUnusedBaselineEntry="true"
findUnusedCode="false"
>
<projectFiles>
<directory name="templates"/>
<directory name="src"/>
<file name="public/index.php"/>
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
<extraFiles>
<directory name="vendor" />
</extraFiles>
<issueHandlers>
</issueHandlers>
</psalm>

View File

@@ -6,12 +6,12 @@ use AIO\Data\ConfigurationManager;
use AIO\Data\DataConst;
use \DateTime;
readonly class AuthManager {
class AuthManager {
private const string SESSION_KEY = 'aio_authenticated';
private ConfigurationManager $configurationManager;
public function __construct(
private ConfigurationManager $configurationManager
) {
public function __construct(ConfigurationManager $configurationManager) {
$this->configurationManager = $configurationManager;
}
public function CheckCredentials(string $password) : bool {

View File

@@ -2,42 +2,92 @@
namespace AIO\Container;
use AIO\Container\State\IContainerState;
use AIO\Data\ConfigurationManager;
use AIO\Docker\DockerActionManager;
use AIO\ContainerDefinitionFetcher;
readonly class Container {
class Container {
private string $identifier;
private string $displayName;
private string $containerName;
private string $restartPolicy;
private int $maxShutdownTime;
private ContainerPorts $ports;
private string $internalPorts;
private ContainerVolumes $volumes;
private ContainerEnvironmentVariables $containerEnvironmentVariables;
/** @var string[] */
private array $dependsOn;
/** @var string[] */
private array $secrets;
/** @var string[] */
private array $devices;
/** @var string[] */
private array $capAdd;
private int $shmSize;
private bool $apparmorUnconfined;
/** @var string[] */
private array $backupVolumes;
private array $nextcloudExecCommands;
private bool $readOnlyRootFs;
private array $tmpfs;
private bool $init;
private string $imageTag;
private AioVariables $aioVariables;
private string $documentation;
private DockerActionManager $dockerActionManager;
public function __construct(
private string $identifier,
private string $displayName,
private string $containerName,
private string $restartPolicy,
private int $maxShutdownTime,
private ContainerPorts $ports,
private string $internalPorts,
private ContainerVolumes $volumes,
private ContainerEnvironmentVariables $containerEnvironmentVariables,
/** @var string[] */
private array $dependsOn,
/** @var string[] */
private array $secrets,
/** @var string[] */
private array $devices,
/** @var string[] */
private array $capAdd,
private int $shmSize,
private bool $apparmorUnconfined,
/** @var string[] */
private array $backupVolumes,
private array $nextcloudExecCommands,
private bool $readOnlyRootFs,
private array $tmpfs,
private bool $init,
private string $imageTag,
private AioVariables $aioVariables,
private string $documentation,
private DockerActionManager $dockerActionManager
string $identifier,
string $displayName,
string $containerName,
string $restartPolicy,
int $maxShutdownTime,
ContainerPorts $ports,
string $internalPorts,
ContainerVolumes $volumes,
ContainerEnvironmentVariables $containerEnvironmentVariables,
array $dependsOn,
array $secrets,
array $devices,
array $capAdd,
int $shmSize,
bool $apparmorUnconfined,
array $backupVolumes,
array $nextcloudExecCommands,
bool $readOnlyRootFs,
array $tmpfs,
bool $init,
string $imageTag,
AioVariables $aioVariables,
string $documentation,
DockerActionManager $dockerActionManager
) {
$this->identifier = $identifier;
$this->displayName = $displayName;
$this->containerName = $containerName;
$this->restartPolicy = $restartPolicy;
$this->maxShutdownTime = $maxShutdownTime;
$this->ports = $ports;
$this->internalPorts = $internalPorts;
$this->volumes = $volumes;
$this->containerEnvironmentVariables = $containerEnvironmentVariables;
$this->dependsOn = $dependsOn;
$this->secrets = $secrets;
$this->devices = $devices;
$this->capAdd = $capAdd;
$this->shmSize = $shmSize;
$this->apparmorUnconfined = $apparmorUnconfined;
$this->backupVolumes = $backupVolumes;
$this->nextcloudExecCommands = $nextcloudExecCommands;
$this->readOnlyRootFs = $readOnlyRootFs;
$this->tmpfs = $tmpfs;
$this->init = $init;
$this->imageTag = $imageTag;
$this->aioVariables = $aioVariables;
$this->documentation = $documentation;
$this->dockerActionManager = $dockerActionManager;
}
public function GetIdentifier() : string {
@@ -112,19 +162,19 @@ readonly class Container {
return $this->volumes;
}
public function GetRunningState() : ContainerState {
public function GetRunningState() : IContainerState {
return $this->dockerActionManager->GetContainerRunningState($this);
}
public function GetRestartingState() : ContainerState {
public function GetRestartingState() : IContainerState {
return $this->dockerActionManager->GetContainerRestartingState($this);
}
public function GetUpdateState() : VersionState {
public function GetUpdateState() : IContainerState {
return $this->dockerActionManager->GetContainerUpdateState($this);
}
public function GetStartingState() : ContainerState {
public function GetStartingState() : IContainerState {
return $this->dockerActionManager->GetContainerStartingState($this);
}

View File

@@ -3,10 +3,17 @@
namespace AIO\Container;
class ContainerPort {
public string $port;
public string $ipBinding;
public string $protocol;
public function __construct(
public string $port,
public string $ipBinding,
public string $protocol
string $port,
string $ipBinding,
string $protocol
) {
$this->port = $port;
$this->ipBinding = $ipBinding;
$this->protocol = $protocol;
}
}

View File

@@ -1,12 +0,0 @@
<?php
namespace AIO\Container;
enum ContainerState: string {
case ImageDoesNotExist = 'image_does_not_exist';
case NotRestarting = 'not_restarting';
case Restarting = 'restarting';
case Running = 'running';
case Starting = 'starting';
case Stopped = 'stopped';
}

View File

@@ -3,10 +3,17 @@
namespace AIO\Container;
class ContainerVolume {
public string $name;
public string $mountPoint;
public bool $isWritable;
public function __construct(
public string $name,
public string $mountPoint,
public bool $isWritable
string $name,
string $mountPoint,
bool $isWritable
) {
$this->name = $name;
$this->mountPoint = $mountPoint;
$this->isWritable = $isWritable;
}
}

View File

@@ -0,0 +1,5 @@
<?php
namespace AIO\Container\State;
interface IContainerState {}

View File

@@ -0,0 +1,6 @@
<?php
namespace AIO\Container\State;
class ImageDoesNotExistState implements IContainerState
{}

View File

@@ -0,0 +1,6 @@
<?php
namespace AIO\Container\State;
class NotRestartingState implements IContainerState
{}

View File

@@ -0,0 +1,6 @@
<?php
namespace AIO\Container\State;
class RestartingState implements IContainerState
{}

View File

@@ -0,0 +1,6 @@
<?php
namespace AIO\Container\State;
class RunningState implements IContainerState
{}

View File

@@ -0,0 +1,6 @@
<?php
namespace AIO\Container\State;
class StartingState implements IContainerState
{}

View File

@@ -0,0 +1,6 @@
<?php
namespace AIO\Container\State;
class StoppedState implements IContainerState
{}

View File

@@ -0,0 +1,6 @@
<?php
namespace AIO\Container\State;
class VersionDifferentState implements IContainerState
{}

View File

@@ -0,0 +1,6 @@
<?php
namespace AIO\Container\State;
class VersionEqualState implements IContainerState
{}

View File

@@ -1,8 +0,0 @@
<?php
namespace AIO\Container;
enum VersionState: string {
case Different = 'different';
case Equal = 'equal';
}

View File

@@ -9,15 +9,23 @@ use AIO\Container\ContainerPort;
use AIO\Container\ContainerPorts;
use AIO\Container\ContainerVolume;
use AIO\Container\ContainerVolumes;
use AIO\Container\State\RunningState;
use AIO\Data\ConfigurationManager;
use AIO\Data\DataConst;
use AIO\Docker\DockerActionManager;
readonly class ContainerDefinitionFetcher {
class ContainerDefinitionFetcher
{
private ConfigurationManager $configurationManager;
private \DI\Container $container;
public function __construct(
private ConfigurationManager $configurationManager,
private \DI\Container $container
) {
ConfigurationManager $configurationManager,
\DI\Container $container
)
{
$this->configurationManager = $configurationManager;
$this->container = $container;
}
public function GetContainerById(string $id): Container
@@ -95,7 +103,7 @@ readonly class ContainerDefinitionFetcher {
$ports = new ContainerPorts();
if (isset($entry['ports'])) {
foreach ($entry['ports'] as $value) {
foreach ($entry['ports'] as $value) {
$ports->AddPort(
new ContainerPort(
$value['port_number'],
@@ -204,7 +212,7 @@ readonly class ContainerDefinitionFetcher {
$dependsOn[] = $value;
}
}
$variables = new ContainerEnvironmentVariables();
if (isset($entry['environment'])) {
foreach ($entry['environment'] as $value) {

View File

@@ -9,10 +9,14 @@ use AIO\Docker\DockerActionManager;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
readonly class ConfigurationController {
class ConfigurationController
{
private ConfigurationManager $configurationManager;
public function __construct(
private ConfigurationManager $configurationManager
ConfigurationManager $configurationManager
) {
$this->configurationManager = $configurationManager;
}
public function SetConfig(Request $request, Response $response, array $args) : Response {

View File

@@ -2,21 +2,28 @@
namespace AIO\Controller;
use AIO\Container\ContainerState;
use AIO\Container\State\RunningState;
use AIO\ContainerDefinitionFetcher;
use AIO\Docker\DockerActionManager;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use AIO\Data\ConfigurationManager;
readonly class DockerController {
class DockerController
{
private DockerActionManager $dockerActionManager;
private ContainerDefinitionFetcher $containerDefinitionFetcher;
private const string TOP_CONTAINER = 'nextcloud-aio-apache';
private ConfigurationManager $configurationManager;
public function __construct(
private DockerActionManager $dockerActionManager,
private ContainerDefinitionFetcher $containerDefinitionFetcher,
private ConfigurationManager $configurationManager
DockerActionManager $dockerActionManager,
ContainerDefinitionFetcher $containerDefinitionFetcher,
ConfigurationManager $configurationManager
) {
$this->dockerActionManager = $dockerActionManager;
$this->containerDefinitionFetcher = $containerDefinitionFetcher;
$this->configurationManager = $configurationManager;
}
private function PerformRecursiveContainerStart(string $id, bool $pullImage = true) : void {
@@ -28,7 +35,7 @@ readonly class DockerController {
// Don't start if container is already running
// This is expected to happen if a container is defined in depends_on of multiple containers
if ($container->GetRunningState() === ContainerState::Running) {
if ($container->GetRunningState() instanceof RunningState) {
error_log('Not starting ' . $id . ' because it was already started.');
return;
}
@@ -41,7 +48,7 @@ readonly class DockerController {
}
}
// Check if docker hub is reachable in order to make sure that we do not try to pull an image if it is down
// Check if docker hub is reachable in order to make sure that we do not try to pull an image if it is down
// and try to mitigate issues that are arising due to that
if ($pullImage) {
if (!$this->dockerActionManager->isDockerHubReachable($container)) {
@@ -254,10 +261,10 @@ readonly class DockerController {
$domaincheckContainer = $this->containerDefinitionFetcher->GetContainerById($id);
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById(self::TOP_CONTAINER);
// Don't start if apache is already running
if ($apacheContainer->GetRunningState() === ContainerState::Running) {
if ($apacheContainer->GetRunningState() instanceof RunningState) {
return;
// Don't start if domaincheck is already running
} elseif ($domaincheckContainer->GetRunningState() === ContainerState::Running) {
} elseif ($domaincheckContainer->GetRunningState() instanceof RunningState) {
$domaincheckWasStarted = apcu_fetch($cacheKey);
// Start domaincheck again when 10 minutes are over by not returning here
if($domaincheckWasStarted !== false && is_string($domaincheckWasStarted)) {

View File

@@ -9,11 +9,14 @@ use AIO\Docker\DockerActionManager;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
readonly class LoginController {
public function __construct(
private AuthManager $authManager,
private DockerActionManager $dockerActionManager,
) {
class LoginController
{
private AuthManager $authManager;
private DockerActionManager $dockerActionManager;
public function __construct(AuthManager $authManager, DockerActionManager $dockerActionManager) {
$this->authManager = $authManager;
$this->dockerActionManager = $dockerActionManager;
}
public function TryLogin(Request $request, Response $response, array $args) : Response {

View File

@@ -71,7 +71,7 @@ class ConfigurationManager
if (!file_exists(DataConst::GetBackupArchivesList())) {
return '';
}
$content = file_get_contents(DataConst::GetBackupArchivesList());
if ($content === '') {
return '';
@@ -91,7 +91,7 @@ class ConfigurationManager
if ($lastBackupTime === "") {
return '';
}
return $lastBackupTime;
}
@@ -99,7 +99,7 @@ class ConfigurationManager
if (!file_exists(DataConst::GetBackupArchivesList())) {
return [];
}
$content = file_get_contents(DataConst::GetBackupArchivesList());
if ($content === '') {
return [];
@@ -110,7 +110,7 @@ class ConfigurationManager
foreach($backupLines as $lines) {
if ($lines !== "") {
$backupTimesTemp = explode(',', $lines);
$backupTimes[] = $backupTimesTemp[1];
$backupTimes[] = $backupTimesTemp[1];
}
}
@@ -140,7 +140,7 @@ class ConfigurationManager
if (!$this->isx64Platform()) {
return false;
}
$config = $this->GetConfig();
if (isset($config['isClamavEnabled']) && $config['isClamavEnabled'] === 1) {
return true;
@@ -364,7 +364,7 @@ class ConfigurationManager
$testUrl = $protocol . $domain . ':443';
curl_setopt($ch, CURLOPT_URL, $testUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$response = (string)curl_exec($ch);
# Get rid of trailing \n
@@ -470,7 +470,7 @@ class ConfigurationManager
if ($location === '') {
throw new InvalidSettingConfigurationException("Please enter a path!");
}
$isValidPath = false;
if (str_starts_with($location, '/') && !str_ends_with($location, '/')) {
$isValidPath = true;
@@ -535,6 +535,10 @@ class ConfigurationManager
return $this->GetEnvironmentalVariableOrConfig($envVariableName, $configName, $defaultValue);
}
public function IsOverwriteEnable() : bool {
return getenv('DISABLE_OVERWRITE_URL') !== 'yes';
}
/**
* @throws InvalidSettingConfigurationException
*/
@@ -713,7 +717,7 @@ class ConfigurationManager
if (!preg_match("#^[0-1][0-9]:[0-5][0-9]$#", $time) && !preg_match("#^2[0-3]:[0-5][0-9]$#", $time)) {
throw new InvalidSettingConfigurationException("You did not enter a correct time! One correct example is '04:00'!");
}
if ($enableAutomaticUpdates === false) {
$time .= PHP_EOL . 'automaticUpdatesAreNotEnabled';
} else {

View File

@@ -4,11 +4,16 @@ namespace AIO\Data;
use AIO\Auth\PasswordGenerator;
readonly class Setup {
class Setup
{
private PasswordGenerator $passwordGenerator;
private ConfigurationManager $configurationManager;
public function __construct(
private PasswordGenerator $passwordGenerator,
private ConfigurationManager $configurationManager,
) {
PasswordGenerator $passwordGenerator,
ConfigurationManager $configurationManager) {
$this->passwordGenerator = $passwordGenerator;
$this->configurationManager = $configurationManager;
}
public function Setup() : string {

View File

@@ -3,24 +3,44 @@
namespace AIO\Docker;
use AIO\Container\Container;
use AIO\Container\VersionState;
use AIO\Container\ContainerState;
use AIO\Container\State\IContainerState;
use AIO\Container\State\ImageDoesNotExistState;
use AIO\Container\State\StartingState;
use AIO\Container\State\RunningState;
use AIO\Container\State\RestartingState;
use AIO\Container\State\NotRestartingState;
use AIO\Container\State\VersionDifferentState;
use AIO\Container\State\StoppedState;
use AIO\Container\State\VersionEqualState;
use AIO\Data\ConfigurationManager;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use AIO\ContainerDefinitionFetcher;
use http\Env\Response;
readonly class DockerActionManager {
class DockerActionManager
{
private const string API_VERSION = 'v1.41';
private Client $guzzleClient;
private \GuzzleHttp\Client $guzzleClient;
private ConfigurationManager $configurationManager;
private ContainerDefinitionFetcher $containerDefinitionFetcher;
private DockerHubManager $dockerHubManager;
public function __construct(
private ConfigurationManager $configurationManager,
private ContainerDefinitionFetcher $containerDefinitionFetcher,
private DockerHubManager $dockerHubManager
ConfigurationManager $configurationManager,
ContainerDefinitionFetcher $containerDefinitionFetcher,
DockerHubManager $dockerHubManager
) {
$this->guzzleClient = new Client(['curl' => [CURLOPT_UNIX_SOCKET_PATH => '/var/run/docker.sock']]);
$this->configurationManager = $configurationManager;
$this->containerDefinitionFetcher = $containerDefinitionFetcher;
$this->dockerHubManager = $dockerHubManager;
$this->guzzleClient = new \GuzzleHttp\Client(
[
'curl' => [
CURLOPT_UNIX_SOCKET_PATH => '/var/run/docker.sock',
],
]
);
}
private function BuildApiUrl(string $url) : string {
@@ -35,14 +55,14 @@ readonly class DockerActionManager {
return $container->GetContainerName() . ':' . $tag;
}
public function GetContainerRunningState(Container $container) : ContainerState
public function GetContainerRunningState(Container $container) : IContainerState
{
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
try {
$response = $this->guzzleClient->get($url);
} catch (RequestException $e) {
if ($e->getCode() === 404) {
return ContainerState::ImageDoesNotExist;
return new ImageDoesNotExistState();
}
throw $e;
}
@@ -50,20 +70,20 @@ readonly class DockerActionManager {
$responseBody = json_decode((string)$response->getBody(), true);
if ($responseBody['State']['Running'] === true) {
return ContainerState::Running;
return new RunningState();
} else {
return ContainerState::Stopped;
return new StoppedState();
}
}
public function GetContainerRestartingState(Container $container) : ContainerState
public function GetContainerRestartingState(Container $container) : IContainerState
{
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
try {
$response = $this->guzzleClient->get($url);
} catch (RequestException $e) {
if ($e->getCode() === 404) {
return ContainerState::ImageDoesNotExist;
return new ImageDoesNotExistState();
}
throw $e;
}
@@ -71,13 +91,13 @@ readonly class DockerActionManager {
$responseBody = json_decode((string)$response->getBody(), true);
if ($responseBody['State']['Restarting'] === true) {
return ContainerState::Restarting;
return new RestartingState();
} else {
return ContainerState::NotRestarting;
return new NotRestartingState();
}
}
public function GetContainerUpdateState(Container $container) : VersionState
public function GetContainerUpdateState(Container $container) : IContainerState
{
$tag = $container->GetImageTag();
if ($tag === '%AIO_CHANNEL%') {
@@ -86,26 +106,28 @@ readonly class DockerActionManager {
$runningDigests = $this->GetRepoDigestsOfContainer($container->GetIdentifier());
if ($runningDigests === null) {
return VersionState::Different;
return new VersionDifferentState();
}
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($container->GetContainerName(), $tag);
if ($remoteDigest === null) {
return VersionState::Equal;
return new VersionEqualstate();
}
foreach($runningDigests as $runningDigest) {
if ($runningDigest === $remoteDigest) {
return VersionState::Equal;
return new VersionEqualState();
}
}
return VersionState::Different;
return new VersionDifferentState();
}
public function GetContainerStartingState(Container $container) : ContainerState
public function GetContainerStartingState(Container $container) : IContainerState
{
$runningState = $this->GetContainerRunningState($container);
if ($runningState === ContainerState::Stopped || $runningState === ContainerState::ImageDoesNotExist) {
return $runningState;
if ($runningState instanceof StoppedState) {
return new StoppedState();
} elseif ($runningState instanceof ImageDoesNotExistState) {
return new ImageDoesNotExistState();
}
$containerName = $container->GetIdentifier();
@@ -120,12 +142,12 @@ readonly class DockerActionManager {
$connection = @fsockopen($containerName, (int)$internalPort, $errno, $errstr, 0.2);
if ($connection) {
fclose($connection);
return ContainerState::Running;
return new RunningState();
} else {
return ContainerState::Starting;
return new StartingState();
}
} else {
return ContainerState::Running;
return new RunningState();
}
}
@@ -275,6 +297,18 @@ readonly class DockerActionManager {
$replacements[1] = $this->configurationManager->GetApachePort();
} elseif ($out[1] === 'TALK_PORT') {
$replacements[1] = $this->configurationManager->GetTalkPort();
} elseif($out[1] === 'OVERWRITEHOST') {
if ($this->configurationManager->IsOverwriteEnable()) {
$replacements[1] = $this->configurationManager->GetDomain();
} else {
$replacements[1] = '';
}
} elseif($out[1] === 'OVERWRITEPROTOCOL') {
if ($this->configurationManager->IsOverwriteEnable()) {
$replacements[1] = 'https';
} else {
$replacements[1] = '';
}
} elseif ($out[1] === 'NEXTCLOUD_MOUNT') {
$replacements[1] = $this->configurationManager->GetNextcloudMount();
} elseif ($out[1] === 'BACKUP_RESTORE_PASSWORD') {
@@ -619,7 +653,7 @@ readonly class DockerActionManager {
$container = $this->containerDefinitionFetcher->GetContainerById($id);
$updateAvailable = "";
if ($container->GetUpdateState() === VersionState::Different) {
if ($container->GetUpdateState() instanceof VersionDifferentState) {
$updateAvailable = '1';
}
foreach ($container->GetDependsOn() as $dependency) {
@@ -780,7 +814,7 @@ readonly class DockerActionManager {
public function sendNotification(Container $container, string $subject, string $message, string $file = '/notify.sh') : void
{
if ($this->GetContainerStartingState($container) === ContainerState::Running) {
if ($this->GetContainerStartingState($container) instanceof RunningState) {
$containerName = $container->GetIdentifier();
@@ -964,7 +998,7 @@ readonly class DockerActionManager {
public function isLoginAllowed() : bool {
$id = 'nextcloud-aio-apache';
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById($id);
if ($this->GetContainerStartingState($apacheContainer) === ContainerState::Running) {
if ($this->GetContainerStartingState($apacheContainer) instanceof RunningState) {
return false;
}
return true;
@@ -973,7 +1007,7 @@ readonly class DockerActionManager {
public function isBackupContainerRunning() : bool {
$id = 'nextcloud-aio-borgbackup';
$backupContainer = $this->containerDefinitionFetcher->GetContainerById($id);
if ($this->GetContainerRunningState($backupContainer) === ContainerState::Running) {
if ($this->GetContainerRunningState($backupContainer) instanceof RunningState) {
return true;
}
return false;

View File

@@ -6,11 +6,12 @@ use AIO\ContainerDefinitionFetcher;
use AIO\Data\ConfigurationManager;
use GuzzleHttp\Client;
readonly class DockerHubManager {
class DockerHubManager
{
private Client $guzzleClient;
public function __construct(
) {
public function __construct()
{
$this->guzzleClient = new Client();
}
@@ -58,4 +59,4 @@ readonly class DockerHubManager {
return null;
}
}
}
}

View File

@@ -8,10 +8,12 @@ use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
readonly class AuthMiddleware {
public function __construct(
private AuthManager $authManager
) {
class AuthMiddleware
{
private AuthManager $authManager;
public function __construct(AuthManager $authManager) {
$this->authManager = $authManager;
}
public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface

View File

@@ -3,13 +3,17 @@
namespace AIO\Twig;
use Slim\Csrf\Guard;
use Twig\Extension\AbstractExtension;
use Twig\Extension\GlobalsInterface;
class CsrfExtension extends AbstractExtension implements GlobalsInterface {
public function __construct(
protected Guard $csrf
) {
class CsrfExtension extends \Twig\Extension\AbstractExtension implements \Twig\Extension\GlobalsInterface
{
/**
* @var Guard
*/
protected Guard $csrf;
public function __construct(Guard $csrf)
{
$this->csrf = $csrf;
}
public function getGlobals() : array
@@ -31,4 +35,4 @@ class CsrfExtension extends AbstractExtension implements GlobalsInterface {
]
];
}
}
}

View File

@@ -16,7 +16,7 @@
</header>
<main>
<h1>Nextcloud AIO v9.7.0</h1>
<h1>Nextcloud AIO v9.6.0</h1>
{# Add 2nd tab warning #}
<script type="text/javascript" src="second-tab-warning.js"></script>
@@ -40,19 +40,19 @@
{% endif %}
{% for container in containers %}
{% if container.GetDisplayName() != '' and container.GetRunningState().value == 'running' %}
{% if container.GetDisplayName() != '' and class(container.GetRunningState()) == 'AIO\\Container\\State\\RunningState' %}
{% set isAnyRunning = true %}
{% endif %}
{% if container.GetDisplayName() != '' and container.GetRestartingState().value == 'restarting' %}
{% if container.GetDisplayName() != '' and class(container.GetRestartingState()) == 'AIO\\Container\\State\\RestartingState' %}
{% set isAnyRestarting = true %}
{% endif %}
{% if container.GetIdentifier() == 'nextcloud-aio-watchtower' and container.GetRunningState().value == 'running' %}
{% if container.GetIdentifier() == 'nextcloud-aio-watchtower' and class(container.GetRunningState()) == 'AIO\\Container\\State\\RunningState' %}
{% set isWatchtowerRunning = true %}
{% endif %}
{% if container.GetIdentifier() == 'nextcloud-aio-domaincheck' and container.GetRunningState().value == 'running' %}
{% if container.GetIdentifier() == 'nextcloud-aio-domaincheck' and class(container.GetRunningState()) == 'AIO\\Container\\State\\RunningState' %}
{% set isDomaincheckRunning = true %}
{% endif %}
{% if container.GetIdentifier() == 'nextcloud-aio-apache' and container.GetStartingState().value == 'starting' %}
{% if container.GetIdentifier() == 'nextcloud-aio-apache' and class(container.GetStartingState()) == 'AIO\\Container\\State\\StartingState' %}
{% set isApacheStarting = true %}
{% endif %}
{% endfor %}
@@ -261,14 +261,14 @@
{% for container in containers %}
{% if container.GetDisplayName() != '' %}
<li>
{% if container.GetStartingState().value == 'starting' %}
{% if class(container.GetStartingState()) == 'AIO\\Container\\State\\StartingState' %}
<span class="status running"></span>
<span>{{ container.GetDisplayName() }} (<a href="/api/docker/logs?id={{ container.GetIdentifier() }}" target="_blank" rel="noopener">Starting</a>)
{% if container.GetDocumentation() != '' %}
(<a href="{{ container.GetDocumentation() }}">docs</a>)
{% endif %}
</span>
{% elseif container.GetRunningState().value == 'running' %}
{% elseif class(container.GetRunningState()) == 'AIO\\Container\\State\\RunningState' %}
<span class="status success"></span>
<span>{{ container.GetDisplayName() }} (<a href="/api/docker/logs?id={{ container.GetIdentifier() }}" target="_blank" rel="noopener">Running</a>)
{% if container.GetDocumentation() != '' %}
@@ -603,7 +603,7 @@
<p><input type="checkbox" id="whiteboard" name="whiteboard"><label for="whiteboard">Whiteboard</label></p>
{% endif %}
<input id="options-form-submit" type="submit" value="Save changes" />
<script type="text/javascript" src="options-form-submit.js?v2"></script>
<script type="text/javascript" src="options-form-submit.js"></script>
</form>
<p><strong>Minimal system requirements:</strong> When any optional container is enabled, at least 2GB RAM, a dual-core CPU and 40GB system storage are required. When enabling ClamAV, Nextcloud Talk Recording-server or Fulltextsearch, at least 3GB RAM are required. For Talk Recording-server additional 2 vCPUs are required. When enabling everything, at least 5GB RAM and a quad-core CPU are required. Recommended are at least 1GB more RAM than the minimal requirement. For further advices and recommendations see <strong><a href="https://github.com/nextcloud/all-in-one/discussions/1335">this documentation</a></strong></p>
{% if isAnyRunning == true or is_x64_platform == false %}

View File

@@ -81,21 +81,12 @@ Included are:
## How to use this?
The following instructions are meant for installations without a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) already being in place. If you want to run AIO behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), see the [reverse proxy documentation](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md). Also, the instructions below are especially meant for Linux. For macOS see [this](#how-to-run-aio-on-macos), for Windows see [this](#how-to-run-aio-on-windows) and for Synology see [this](#how-to-run-aio-on-synology-dsm).
1. Install Docker on your Linux installation by following the official documentation: https://docs.docker.com/engine/install/#supported-platforms.
>[!WARNING]
> You could use the convenience script below to install docker. However we recommend to not blindly download and execute scripts as sudo. But if you feel like it, you can of course use it. See below:
<details>
<summary>Using the convenience script</summary>
```sh
curl -fsSL https://get.docker.com | sudo sh
```
</details>
2. If you need ipv6 support, you should enable it by following https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md.
3. Run the command below in order to start the container on Linux and without a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) already in place:
1. Install Docker on your Linux installation by following the official documentation: https://docs.docker.com/engine/install/#supported-platforms. The easiest way is installing it by **using the convenience script**:
```sh
curl -fsSL https://get.docker.com | sudo sh
```
1. If you need ipv6 support, you should enable it by following https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md.
2. Run the command below in order to start the container on Linux and without a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) already in place:
```
# For Linux and without a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) already in place:
sudo docker run \
@@ -129,12 +120,12 @@ curl -fsSL https://get.docker.com | sudo sh
Note: You may be interested in adjusting Nextclouds datadir to store the files in a different location than the default docker volume. See [this documentation](https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir) on how to do it.
4. After the initial startup, you should be able to open the Nextcloud AIO Interface now on port 8080 of this server.<br>
3. After the initial startup, you should be able to open the Nextcloud AIO Interface now on port 8080 of this server.<br>
E.g. `https://ip.address.of.this.server:8080`<br>
⚠️ **Important:** do always use an ip-address if you access this port and not a domain as HSTS might block access to it later! (It is also expected that this port uses a self-signed certificate due to security concerns which you need to accept in your browser)<br><br>
If your firewall/router has port 80 and 8443 open/forwarded and you point a domain to your server, you can get a valid certificate automatically by opening the Nextcloud AIO Interface via:<br>
`https://your-domain-that-points-to-this-server.tld:8443`
5. Please do not forget to open port `3478/TCP` and `3478/UDP` in your firewall/router for the Talk container!
4. Please do not forget to open port `3478/TCP` and `3478/UDP` in your firewall/router for the Talk container!
## FAQ
### How does it work?
@@ -189,14 +180,12 @@ nextcloud/all-in-one:latest
Also, you may be interested in adjusting Nextcloud's Datadir to store the files on the host system. See [this documentation](https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir) on how to do it.
> [!NOTE]
> Almost all commands in this project's documentation use `sudo docker ...`. Since `sudo` is not available on Windows, you simply remove `sudo` from the commands and they should work.
⚠️ **Please note:** Almost all commands in this project's documentation use `sudo docker ...`. Since `sudo` is not available on Windows, you simply remove `sudo` from the commands and they should work.
### How to run AIO on Synology DSM
On Synology, there are two things different in comparison to Linux: instead of using `--volume /var/run/docker.sock:/var/run/docker.sock:ro`, you need to use `--volume /volume1/docker/docker.sock:/var/run/docker.sock:ro` to run it. You also need to add `--env WATCHTOWER_DOCKER_SOCKET_PATH="/volume1/docker/docker.sock"`to the docker run command of the mastercontainer (but before the last line `nextcloud/all-in-one:latest`). Apart from that it should work and behave the same like on Linux. Obviously the Synology Docker GUI will not work with that so you will need to either use SSH or create a user-defined script task in the task scheduler as the user 'root' in order to run the command.
> [!NOTE]
> It is possible that the docker socket on your Synology is located in `/var/run/docker.sock` like the default on Linux. Then you can just use the Linux command without having to change anything - you will notice this when you try to start the container and it says that the bind mount failed. E.g. `docker: Error response from daemon: Bind mount failed: '/volume1/docker/docker.sock' does not exists.`
⚠️ **Please note**: it is possible that the docker socket on your Synology is located in `/var/run/docker.sock` like the default on Linux. Then you can just use the Linux command without having to change anything - you will notice this when you try to start the container and it says that the bind mount failed. E.g. `docker: Error response from daemon: Bind mount failed: '/volume1/docker/docker.sock' does not exists.`
Also, you may be interested in adjusting Nextcloud's Datadir to store the files on the host system. See [this documentation](https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir) on how to do it.
@@ -270,7 +259,7 @@ No and they will not be. If you want to run it locally, without opening Nextclou
No and it will not be added. If you only want to run it locally, you may have a look at the following documentation: [local-instance.md](./local-instance.md)
### Can I use AIO with multiple domains?
No and it will not be added. However you can use [this feature](https://github.com/nextcloud/all-in-one/blob/main/multiple-instances.md) in order to create multiple AIO instances, one for each domain.
No and it will not be added. However you can use [this feature](https://github.com/nextcloud/all-in-one/blob/main/multiple-instances.md) in order to create multiple AIO instances, one for each domain. Also you can set the environment variable `DISABLE_OVERWRITE_URL` to `true`, however we cannot fix bugs that may be caused by network issues. At your own risk.
### Are other ports than the default 443 for Nextcloud supported?
No and they will not be. Please use a dedicated domain for Nextcloud and set it up correctly by following the [reverse proxy documentation](./reverse-proxy.md). If port 443 and/or 80 is blocked for you, you may use the a Cloudflare Tunnel if you want to publish it online. You could also use the ACME DNS-challenge to get a valid certificate. However in all cases the Nextcloud interface will redirect you to port 443.
@@ -338,8 +327,7 @@ AIO ships its own update notifications implementation. It checks if container up
If your Nextcloud is running and you are logged in as admin in your Nextcloud, you can easily log in to the AIO interface by opening `https://yourdomain.tld/settings/admin/overview` which will show a button on top that enables you to log in to the AIO interface by just clicking on this button. **Note:** You can change the domain/ip-address/port of the button by simply stopping the containers, visiting the AIO interface from the correct and desired domain/ip-address/port and clicking once on `Start containers`.
### How to change the domain?
> [!NOTE]
> Editing the configuration.json manually and making a mistake may break your instance so please create a backup first!
**⚠️ Please note:** Editing the configuration.json manually and making a mistake may break your instance so please create a backup first!
If you set up a new AIO instance, you need to enter a domain. Currently there is no way to change this domain afterwards from the AIO interface. So in order to change it, you need to edit the configuration.json manually using `sudo docker run -it --rm --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config:rw alpine sh -c "apk add --no-cache nano && nano /mnt/docker-aio-config/data/configuration.json"`, substitute each occurrence of your old domain with your new domain and save and write out the file. Afterwards restart your containers from the AIO interface and everything should work as expected if the new domain is correctly configured.<br>
If you are running AIO behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else), you need to obviously also change the domain in your reverse proxy config.
@@ -352,8 +340,7 @@ Additionally, after restarting the containers, you need to open the admin settin
### How to properly reset the instance?
If something goes unexpected routes during the initial installation, you might want to reset the AIO installation to be able to start from scratch.
> [!NOTE]
> If you already have it running and have data on your instance, you should not follow these instructions as it will delete all data that is coupled to your AIO instance.
**Please note**: if you already have it running and have data on your instance, you should not follow these instructions as it will delete all data that is coupled to your AIO instance.
Here is how to reset the AIO instance properly:
1. Stop all containers if they are running from the AIO interface
@@ -585,8 +572,7 @@ Afterwards apply the correct permissions with `sudo chown root:root /root/backup
1. save and close the crontab (when using nano are the shortcuts for this `Ctrl + o` -> `Enter` and close the editor with `Ctrl + x`).
### How to stop/start/update containers or trigger the daily backup from a script externally?
> [!WARNING]
> The below script will only work after the initial setup of AIO. So you will always need to first visit the AIO interface, type in your domain and start the containers the first time or restore an older AIO instance from its borg backup before you can use the script.
⚠️⚠️⚠️ **Warning**: The below script will only work after the initial setup of AIO. So you will always need to first visit the AIO interface, type in your domain and start the containers the first time or restore an older AIO instance from its borg backup before you can use the script.
You can do so by running the `/daily-backup.sh` script that is stored in the mastercontainer. It accepts the following environmental varilables:
- `AUTOMATIC_UPDATES` if set to `1`, it will automatically stop the containers, update them and start them including the mastercontainer. If the mastercontainer gets updated, this script's execution will stop as soon as the mastercontainer gets stopped. You can then wait until it is started again and run the script with this flag again in order to update all containers correctly afterwards.
@@ -597,15 +583,13 @@ You can do so by running the `/daily-backup.sh` script that is stored in the mas
One example for this would be `sudo docker exec -it --env DAILY_BACKUP=1 nextcloud-aio-mastercontainer /daily-backup.sh`, which you can run via a cronjob or put it in a script.
> [!NOTE]
> None of the option returns error codes. So you need to check for the correct result yourself.
⚠️ Please note that none of the option returns error codes. So you need to check for the correct result yourself.
### How to disable the backup section?
If you already have a backup solution in place, you may want to hide the backup section. You can do so by adding `--env AIO_DISABLE_BACKUP_SECTION=true` to the docker run command of the mastercontainer (but before the last line `nextcloud/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used).
### How to change the default location of Nextcloud's Datadir?
> [!WARNING]
> Do not set or adjust this value after the initial Nextcloud installation is done! If you still want to do it afterwards, see [this](https://github.com/nextcloud/all-in-one/discussions/890#discussioncomment-3089903) on how to do it.
⚠️⚠️⚠️ **Warning:** Do not set or adjust this value after the initial Nextcloud installation is done! If you still want to do it afterwards, see [this](https://github.com/nextcloud/all-in-one/discussions/890#discussioncomment-3089903) on how to do it.
You can configure the Nextcloud container to use a specific directory on your host as data directory. You can do so by adding the environmental variable `NEXTCLOUD_DATADIR` to the docker run command of the mastercontainer (but before the last line `nextcloud/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used). Allowed values for that variable are strings that start with `/` and are not equal to `/`. The chosen directory or volume will then be mounted to `/mnt/ncdata` inside the container.
@@ -626,7 +610,7 @@ You can configure the Nextcloud container to use a specific directory on your ho
### Can I use a CIFS/SMB share as Nextcloud's datadir?
Sure. Add this to the `/etc/fstab` file on the host system: <br>
Sure. Add this to the `/etc/fstab` file: <br>
`<your-storage-host-and-subpath> <your-mount-dir> cifs rw,mfsymlinks,seal,credentials=<your-credentials-file>,uid=33,gid=0,file_mode=0770,dir_mode=0770 0 0`<br>
(Of course you need to modify `<your-storage-host-and-subpath>`, `<your-mount-dir>` and `<your-credentials-file>` for your specific case.)
@@ -639,7 +623,7 @@ password=<password>
```
(Of course you need to modify `<smb/cifs username>` and `<password>` for your specific case.)
Now you can use `/mnt/storagebox` as Nextcloud's datadir like described in the section above this one.
Now you can use `/mnt/storagebox` as Nextcloud's datadir like described in the section above above this one.
### 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 docker run command of the mastercontainer (but before the last line `nextcloud/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used). Allowed values for that variable are strings that start with `/` and are not equal to `/`.
@@ -655,8 +639,7 @@ You can then navigate to `https://your-nc-domain.com/settings/apps/disabled`, ac
Be aware though that these locations will not be covered by the built-in backup solution - but you can add further Docker volumes and host paths that you want to back up after the initial backup is done.
> [!NOTE]
> If you can't see the type "local storage" in the external storage admin options, a restart of the containers from the AIO interface may be required.
**Please note:** If you can't see the type "local storage" in the external storage admin options, a restart of the containers from the AIO interface may be required.
### How to adjust the Talk port?
By default will the talk container use port `3478/UDP` and `3478/TCP` for connections. You can adjust the port by adding e.g. `--env TALK_PORT=3478` to the docker run command of the mastercontainer (but before the last line `nextcloud/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used) and adjusting the port to your desired value. Best is to use a port over 1024, so e.g. 3479 to not run into this: https://github.com/nextcloud/all-in-one/discussions/2517
@@ -702,15 +685,12 @@ You can do so by adding `--env NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS="imagick exte
The [facerecognition app](https://apps.nextcloud.com/apps/facerecognition) requires the pdlib PHP extension to be installed. Unfortunately, it is not available on PECL nor via PHP core, so there is no way to add this into AIO currently. However you can use [this community container](https://github.com/nextcloud/all-in-one/tree/main/community-containers/facerecognition) in order to run facerecognition.
### How to enable hardware-transcoding for Nextcloud?
> [!WARNING]
> This only works if the `/dev/dri` device is present on the host! If it does not exists on your host, don't proceed as otherwise the Nextcloud container will fail to start! If you are unsure about this, better do not proceed with the instructions below.
⚠️⚠️⚠️ Warning: this only works if the `/dev/dri` device is present on the host! If it does not exists on your host, don't proceed as otherwise the Nextcloud container will fail to start! If you are unsure about this, better do not proceed with the instructions below.
The [memories app](https://apps.nextcloud.com/apps/memories) allows to enable hardware transcoding for videos. In order to use that, you need to add `--env NEXTCLOUD_ENABLE_DRI_DEVICE=true` to the docker run command of the mastercontainer (but before the last line `nextcloud/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used) which will mount the `/dev/dri` device into the container. There is now a community container which allows to easily add the transcoding container of Memories to AIO: https://github.com/nextcloud/all-in-one/tree/main/community-containers/memories
### How to keep disabled apps?
In certain situations you might want to keep Nextcloud apps that are disabled in the AIO interface and not uninstall them if they should be installed in Nextcloud. You can do so by adding `--env NEXTCLOUD_KEEP_DISABLED_APPS=true` to the docker run command of the mastercontainer (but before the last line `nextcloud/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used).
> [!WARNING]
> Doing this might cause unintended problems in Nextcloud if an app that requires an external dependency is still installed but the external dependency not for example.
In certain situations you might want to keep Nextcloud apps that are disabled in the AIO interface and not uninstall them if they should be installed in Nextcloud. You can do so by adding `--env NEXTCLOUD_KEEP_DISABLED_APPS=true` to the docker run command of the mastercontainer (but before the last line `nextcloud/all-in-one:latest`! If it was started already, you will need to stop the mastercontainer, remove it (no data will be lost) and recreate it using the docker run command that you initially used). ⚠️⚠️⚠️ **Warning** doing this might cause unintended problems in Nextcloud if an app that requires an external dependency is still installed but the external dependency not for example.
### Huge docker logs
If you should run into issues with huge docker logs, you can adjust the log size by following https://docs.docker.com/config/containers/logging/local/#usage. However for the included AIO containers, this should usually not be needed because almost all of them have the log level set to warn so they should not produce many logs.

View File

@@ -353,9 +353,10 @@ server {
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Accept-Encoding "";
proxy_set_header Host $host;
proxy_request_buffering off;
client_body_buffer_size 512k;
proxy_read_timeout 86400s;
client_max_body_size 0;