mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-05-21 10:50:10 +00:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85b445d576 | ||
|
|
52651559de | ||
|
|
36fd28da6f | ||
|
|
77979aaa4a | ||
|
|
5f753665ac | ||
|
|
e7ec998913 | ||
|
|
91c7f13171 | ||
|
|
d170feb1e7 | ||
|
|
1a55b94b93 | ||
|
|
a0656364b1 | ||
|
|
20c46a3809 | ||
|
|
866519be88 | ||
|
|
cfc157f672 | ||
|
|
8b813fe950 | ||
|
|
c1a5262769 | ||
|
|
5b8de658c7 | ||
|
|
0b51eab553 | ||
|
|
c8854ab1e3 | ||
|
|
7a18cf766d | ||
|
|
213de472a6 | ||
|
|
c9be73601d | ||
|
|
e2a6231257 | ||
|
|
b929d57a77 | ||
|
|
0168b29882 | ||
|
|
8836a884fb | ||
|
|
6adae6db3e | ||
|
|
0071703a24 | ||
|
|
3af23d5a5c | ||
|
|
17eb732a89 | ||
|
|
68ddc72e9b | ||
|
|
a03478c5d0 | ||
|
|
6e8aea3aeb | ||
|
|
2caa883453 | ||
|
|
1edcc4ef5f | ||
|
|
10f62ac401 | ||
|
|
f8f50e9186 | ||
|
|
a3e3dd4534 | ||
|
|
a6286a291f | ||
|
|
2dbd3a5f71 | ||
|
|
c1e2446d22 | ||
|
|
6232000e31 | ||
|
|
7c20d54dd0 | ||
|
|
8ce55a1334 | ||
|
|
8149c0de75 | ||
|
|
34660f3d17 | ||
|
|
d360031f12 |
@@ -22,25 +22,13 @@
|
||||
|
||||
# Collabora
|
||||
route /browser/* {
|
||||
reverse_proxy https://{$COLLABORA_HOST}:9980 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
reverse_proxy {$COLLABORA_HOST}:9980
|
||||
}
|
||||
route /hosting/* {
|
||||
reverse_proxy https://{$COLLABORA_HOST}:9980 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
reverse_proxy {$COLLABORA_HOST}:9980
|
||||
}
|
||||
route /cool/* {
|
||||
reverse_proxy https://{$COLLABORA_HOST}:9980 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
reverse_proxy {$COLLABORA_HOST}:9980
|
||||
}
|
||||
|
||||
# Nextcloud
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:bullseye-20220125-slim
|
||||
FROM debian:bullseye-20220228-slim
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# From a file located probably somewhere here: https://github.com/CollaboraOnline/online/tree/master/docker
|
||||
FROM collabora/code:21.11.2.2.1
|
||||
FROM collabora/code:21.11.2.4.1
|
||||
@@ -6,5 +6,7 @@ while true; do
|
||||
sudo -u www-data php /var/www/docker-aio/php/src/Cron/cron.php
|
||||
# Remove dangling images
|
||||
sudo -u www-data docker image prune -f
|
||||
# Remove sessions older than 24h
|
||||
find "/mnt/docker-aio-config/session/" -mindepth 1 -mmin +1440 -delete
|
||||
sleep 1d
|
||||
done
|
||||
|
||||
@@ -62,7 +62,29 @@ else
|
||||
sleep 10
|
||||
fi
|
||||
|
||||
# Check if startup command was executed correctly
|
||||
if ! docker ps | grep -q "nextcloud-aio-mastercontainer"; then
|
||||
echo "It seems like you did not give the mastercontainer the correct name?"
|
||||
exit 1
|
||||
elif ! docker volume ls | grep -q "nextcloud_aio_mastercontainer"; then
|
||||
echo "It seems like you did not give the mastercontainer volume the correct name?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for other options
|
||||
if [ -n "$NEXTCLOUD_DATADIR" ]; then
|
||||
if ! echo "$NEXTCLOUD_DATADIR" | grep -q "^/mnt/" \
|
||||
&& ! echo "$NEXTCLOUD_DATADIR" | grep -q "^/media/"
|
||||
then
|
||||
echo "You've set NEXTCLOUD_DATADIR but not to an allowed value.
|
||||
The string must start with '/mnt/' or '/media/'. E.g. '/mnt/ncdata'"
|
||||
exit 1
|
||||
elif [ "$NEXTCLOUD_DATADIR" = "/mnt/" ] || [ "$NEXTCLOUD_DATADIR" = "/media/" ]; then
|
||||
echo "You've set NEXTCLOUD_DATADIR but not to an allowed value.
|
||||
The string must start with '/mnt/' or '/media/' and not be equal to these."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -n "$NEXTCLOUD_MOUNT" ]; then
|
||||
if ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/mnt/" \
|
||||
&& ! echo "$NEXTCLOUD_MOUNT" | grep -q "^/media/" \
|
||||
@@ -76,6 +98,12 @@ The string must be equal to/start with '/mnt/' or '/media/' or be equal to '/var
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -n "$NEXTCLOUD_DATADIR" ] && [ -n "$NEXTCLOUD_MOUNT" ]; then
|
||||
if [ "$NEXTCLOUD_DATADIR" = "$NEXTCLOUD_MOUNT" ]; then
|
||||
echo "NEXTCLOUD_DATADIR and NEXTCLOUD_MOUNT are not allowed to be equal."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -n "$APACHE_PORT" ]; then
|
||||
if ! check_if_number "$APACHE_PORT"; then
|
||||
echo "You provided an Apache port but did not only use numbers"
|
||||
|
||||
@@ -21,6 +21,15 @@ redis.session.lock_retries = -1
|
||||
redis.session.lock_wait_time = 10000
|
||||
REDIS_CONF
|
||||
|
||||
# Check permissions in ncdata
|
||||
touch "/mnt/ncdata/this-is-a-test-file"
|
||||
if ! [ -f "/mnt/ncdata/this-is-a-test-file" ]; then
|
||||
echo "The www-data user doesn't seem to have access rights in /mnt/ncdata.
|
||||
Did you maybe change the datadir and did forget to apply the correct permissions?"
|
||||
exit 1
|
||||
fi
|
||||
rm "/mnt/ncdata/this-is-a-test-file"
|
||||
|
||||
if [ -f /var/www/html/version.php ]; then
|
||||
# shellcheck disable=SC2016
|
||||
installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
|
||||
@@ -223,6 +232,13 @@ if ! [ -f "/mnt/ncdata/skip.update" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if appdata is present
|
||||
# If not, something broke (e.g. changing ncdatadir after aio was first started)
|
||||
if [ -z "$(find "/mnt/ncdata/" -maxdepth 1 -mindepth 1 -type d -name "appdata_*")" ]; then
|
||||
echo "Appdata is not present. Did you maybe change the datadir after aio was first started?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Apply one-click-instance settings
|
||||
echo "Applying one-click-instance settings..."
|
||||
php /var/www/html/occ config:system:set one-click-instance --value=true --type=bool
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:focal-20220113
|
||||
FROM ubuntu:focal-20220302
|
||||
|
||||
EXPOSE 3478
|
||||
|
||||
|
||||
12
php/composer.lock
generated
12
php/composer.lock
generated
@@ -1437,7 +1437,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.24.0",
|
||||
"version": "v1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
@@ -1499,7 +1499,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1519,7 +1519,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.24.0",
|
||||
"version": "v1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
@@ -1582,7 +1582,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1602,7 +1602,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.24.0",
|
||||
"version": "v1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
@@ -1661,7 +1661,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
"writeable": true
|
||||
},
|
||||
{
|
||||
"name": "nextcloud_aio_nextcloud_data",
|
||||
"name": "%NEXTCLOUD_DATADIR%",
|
||||
"location": "/mnt/ncdata",
|
||||
"writeable": true
|
||||
},
|
||||
@@ -156,7 +156,8 @@
|
||||
"9980"
|
||||
],
|
||||
"environmentVariables": [
|
||||
"domain=%NC_DOMAIN%"
|
||||
"domain=%NC_DOMAIN%",
|
||||
"extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:logging.level=warning"
|
||||
],
|
||||
"volumes": [],
|
||||
"secrets": [],
|
||||
@@ -214,7 +215,7 @@
|
||||
"writeable": true
|
||||
},
|
||||
{
|
||||
"name": "nextcloud_aio_nextcloud_data",
|
||||
"name": "%NEXTCLOUD_DATADIR%",
|
||||
"location": "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data",
|
||||
"writeable": true
|
||||
},
|
||||
|
||||
@@ -22,11 +22,6 @@ ini_set('session.save_path', $dataConst->GetSessionDirectory());
|
||||
// Auto logout on browser close
|
||||
ini_set('session.cookie_lifetime', '0');
|
||||
|
||||
// Make sure to delete all stale sessions after at least one day
|
||||
ini_set('session.gc_maxlifetime', '86400');
|
||||
ini_set('session.gc_probability', '1');
|
||||
ini_set('session.gc_divisor', '1');
|
||||
|
||||
// Create app
|
||||
AppFactory::setContainer($container);
|
||||
$app = AppFactory::create();
|
||||
@@ -88,6 +83,7 @@ $app->get('/containers', function ($request, $response, $args) use ($container)
|
||||
'has_update_available' => $dockerActionManger->isAnyUpdateAvailable(),
|
||||
'last_backup_time' => $configurationManager->GetLastBackupTime(),
|
||||
'backup_times' => $configurationManager->GetBackupTimes(),
|
||||
'current_channel' => $dockerActionManger->GetCurrentChannel(),
|
||||
]);
|
||||
})->setName('profile');
|
||||
$app->get('/login', function ($request, $response, $args) use ($container) {
|
||||
|
||||
@@ -136,7 +136,7 @@ input {
|
||||
padding: 20px;
|
||||
max-width: 100%;
|
||||
word-break: break-word;
|
||||
max-width: 450px;
|
||||
max-width: 470px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,11 @@ class ContainerDefinitionFetcher
|
||||
if($value['name'] === '') {
|
||||
continue;
|
||||
}
|
||||
} elseif ($value['name'] === '%NEXTCLOUD_DATADIR%') {
|
||||
$value['name'] = $this->configurationManager->GetNextcloudDatadirMount();
|
||||
if ($value['name'] === '') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if($value['location'] === '%NEXTCLOUD_MOUNT%') {
|
||||
$value['location'] = $this->configurationManager->GetNextcloudMount();
|
||||
|
||||
@@ -25,6 +25,12 @@ class ConfigurationController
|
||||
$this->configurationManager->SetDomain($request->getParsedBody()['domain']);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['current-master-password']) || isset($request->getParsedBody()['new-master-password'])) {
|
||||
$currentMasterPassword = $request->getParsedBody()['current-master-password'] ?? '';
|
||||
$newMasterPassword = $request->getParsedBody()['new-master-password'] ?? '';
|
||||
$this->configurationManager->ChangeMasterPassword($currentMasterPassword, $newMasterPassword);
|
||||
}
|
||||
|
||||
if (isset($request->getParsedBody()['borg_backup_host_location'])) {
|
||||
$this->configurationManager->SetBorgBackupHostLocation($request->getParsedBody()['borg_backup_host_location']);
|
||||
}
|
||||
|
||||
@@ -117,8 +117,8 @@ class ConfigurationManager
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function SetDomain(string $domain) : void {
|
||||
// Validate URL
|
||||
if (!filter_var('http://' . $domain, FILTER_VALIDATE_URL)) {
|
||||
// Validate domain
|
||||
if (!filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
|
||||
throw new InvalidSettingConfigurationException("Domain is not in a valid format!");
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ class ConfigurationManager
|
||||
$response = str_replace("\n", "", $response);
|
||||
|
||||
if($response !== $instanceID) {
|
||||
throw new InvalidSettingConfigurationException("Domain does not point to this server.");
|
||||
throw new InvalidSettingConfigurationException("Domain does not point to this server or reverse proxy not configured correctly.");
|
||||
}
|
||||
|
||||
// Write domain
|
||||
@@ -236,6 +236,34 @@ class ConfigurationManager
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSettingConfigurationException
|
||||
*/
|
||||
public function ChangeMasterPassword(string $currentPassword, string $newPassword) : void {
|
||||
if ($currentPassword === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter your current password.");
|
||||
}
|
||||
|
||||
if ($currentPassword !== $this->GetPassword()) {
|
||||
throw new InvalidSettingConfigurationException("The entered current password is not correct.");
|
||||
}
|
||||
|
||||
if ($newPassword === '') {
|
||||
throw new InvalidSettingConfigurationException("Please enter a new password.");
|
||||
}
|
||||
|
||||
if (strlen($newPassword) < 24) {
|
||||
throw new InvalidSettingConfigurationException("New passwords must be >= 24 digits.");
|
||||
}
|
||||
|
||||
if (!preg_match("#^[a-zA-Z0-9 ]+$#", $newPassword)) {
|
||||
throw new InvalidSettingConfigurationException('Not allowed characters in the new password.');
|
||||
}
|
||||
|
||||
// All checks pass so set the password
|
||||
$this->SetPassword($newPassword);
|
||||
}
|
||||
|
||||
public function GetApachePort() : string {
|
||||
$port = getenv('APACHE_PORT');
|
||||
if ($port === false) {
|
||||
@@ -309,4 +337,27 @@ class ConfigurationManager
|
||||
return $mount;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetNextcloudDatadirMount() : string {
|
||||
$mount = getenv('NEXTCLOUD_DATADIR');
|
||||
if ($mount === false) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['nextcloud_datadir']) || $config['nextcloud_datadir'] === '') {
|
||||
$config['nextcloud_datadir'] = 'nextcloud_aio_nextcloud_data';
|
||||
}
|
||||
return $config['nextcloud_datadir'];
|
||||
} else {
|
||||
if(file_exists(DataConst::GetConfigFile())) {
|
||||
$config = $this->GetConfig();
|
||||
if (!isset($config['nextcloud_datadir'])) {
|
||||
$config['nextcloud_datadir'] = '';
|
||||
}
|
||||
if ($mount !== $config['nextcloud_datadir']) {
|
||||
$config['nextcloud_datadir'] = $mount;
|
||||
$this->WriteConfig($config);
|
||||
}
|
||||
}
|
||||
return $mount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ class DockerActionManager
|
||||
$runningDigest = $this->GetRepoDigestOfContainer($container->GetIdentifier());
|
||||
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($container->GetContainerName(), $tag);
|
||||
|
||||
if ($runningDigest === $remoteDigest) {
|
||||
if ($runningDigest === $remoteDigest || $remoteDigest === null || $runningDigest === null) {
|
||||
return new VersionEqualState();
|
||||
} else {
|
||||
return new VersionDifferentState();
|
||||
@@ -261,11 +261,19 @@ class DockerActionManager
|
||||
|
||||
public function PullContainer(Container $container) : void
|
||||
{
|
||||
$url = $this->BuildApiUrl(sprintf('images/create?fromImage=%s', urlencode($this->BuildImageName($container))));
|
||||
try {
|
||||
$this->guzzleClient->post($url);
|
||||
} catch (RequestException $e) {
|
||||
throw $e;
|
||||
$pullcontainer = true;
|
||||
if ($container->GetIdentifier() === 'nextcloud-aio-database') {
|
||||
if ($this->GetDatabasecontainerExitCode() > 0) {
|
||||
$pullcontainer = false;
|
||||
}
|
||||
}
|
||||
if ($pullcontainer) {
|
||||
$url = $this->BuildApiUrl(sprintf('images/create?fromImage=%s', urlencode($this->BuildImageName($container))));
|
||||
try {
|
||||
$this->guzzleClient->post($url);
|
||||
} catch (RequestException $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +354,7 @@ class DockerActionManager
|
||||
$runningDigest = $this->GetRepoDigestOfContainer($containerName);
|
||||
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($imageName, $tag);
|
||||
|
||||
if ($remoteDigest === $runningDigest) {
|
||||
if ($remoteDigest === $runningDigest || $remoteDigest === null || $runningDigest === null) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@@ -507,6 +515,29 @@ class DockerActionManager
|
||||
}
|
||||
}
|
||||
|
||||
public function GetDatabasecontainerExitCode() : int
|
||||
{
|
||||
$containerName = 'nextcloud-aio-database';
|
||||
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($containerName)));
|
||||
try {
|
||||
$response = $this->guzzleClient->get($url);
|
||||
} catch (RequestException $e) {
|
||||
if ($e->getCode() === 404) {
|
||||
return -1;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$responseBody = json_decode((string)$response->getBody(), true);
|
||||
|
||||
$exitCode = $responseBody['State']['ExitCode'];
|
||||
if (is_int($exitCode)) {
|
||||
return $exitCode;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public function isLoginAllowed() : bool {
|
||||
$id = 'nextcloud-aio-apache';
|
||||
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h1>Nextcloud AIO Beta v0.6.0</h1>
|
||||
<h1>Nextcloud AIO Beta v0.7.0</h1>
|
||||
This is beta software and not production ready.<br><br>
|
||||
|
||||
{% set isAnyRunning = false %}
|
||||
@@ -77,6 +77,7 @@
|
||||
|
||||
{% if isAnyRunning == true %}
|
||||
{% if isApacheStarting != true %}
|
||||
Your initial Nextcloud credentials:<br><br />
|
||||
Initial Nextcloud username: admin<br />
|
||||
Initial Nextcloud password: {{ nextcloud_password }}<br /><br/>
|
||||
<a href="https://{{ domain }}" class="button" target="_blank" rel="noopener">Open your Nextcloud ↗</a><br/>
|
||||
@@ -159,24 +160,43 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
{% if isBackupOrRestoreRunning == false %}
|
||||
<h2>Mastercontainer update</h2>
|
||||
{% 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 %}
|
||||
|
||||
{% if was_start_button_clicked == true %}
|
||||
|
||||
{% if isBackupOrRestoreRunning == false %}
|
||||
<h2>Mastercontainer</h2>
|
||||
You are currently running the {{ current_channel }} channel.<br><br>
|
||||
|
||||
{% if is_mastercontainer_update_available == true %}
|
||||
{% if isAnyRunning == false %}
|
||||
⚠ A mastercontainer update is available. Please click on the button below to update it.<br><br>
|
||||
<form method="POST" action="/api/docker/watchtower" class="xhr">
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Update mastercontainer" />
|
||||
</form>
|
||||
{% else %}
|
||||
⚠ A mastercontainer update is available. Please stop your containers in order to be able to update the mastercontainer.<br><br>
|
||||
{% endif %}
|
||||
{% if current_channel starts with 'latest' %}
|
||||
You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases/latest">here</a><br><br>
|
||||
{% elseif current_channel starts with 'beta' %}
|
||||
You can find the changelog <a href="https://github.com/nextcloud/all-in-one/releases">here</a><br><br>
|
||||
{% elseif current_channel starts with 'develop' %}
|
||||
You can find all changes <a href="https://github.com/nextcloud-releases/all-in-one/commits/main">here</a><br><br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if isApacheStarting == false %}
|
||||
You can change your AIO password below:<br><br />
|
||||
<form method="POST" action="/api/configuration" class="xhr">
|
||||
<input type="text" autocomplete="current-password" name="current-master-password" placeholder="your current aio password"/>
|
||||
<input type="text" autocomplete="new-password" name="new-master-password" placeholder="your new aio password"/>
|
||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||
<input class="button" type="submit" value="Submit" />
|
||||
</form>
|
||||
The new password needs to be at least 24 characters long. Allowed characters are the <a href="https://en.wikipedia.org/wiki/Latin_alphabet#/media/File:Abecedarium.png">latin characters</a> 'a-z', 'A-Z', '0-9' and spaces.<br><br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if isBackupOrRestoreRunning == false and borg_backup_host_location == "" and isApacheStarting != true %}
|
||||
<h2>Backup and restore</h2>
|
||||
@@ -247,6 +267,10 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<h2>Optional</h2>
|
||||
In this section, you will find optional addons in the future.
|
||||
It will disable the ability to change them when any containers are running and allow to change them when they are stopped.
|
||||
Also, it will display possible sections for optional addons. (which itself will be displayed when enabled and running).
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
85
readme.md
85
readme.md
@@ -168,6 +168,91 @@ sudo borg delete --stats --progress "/mnt/backup/borg::20220223_174237-nextcloud
|
||||
After doing so, make sure to update the backup archives list in the AIO interface!<br>
|
||||
You can do so by clicking on the `Check backup integrity` button or `Create backup` button.
|
||||
|
||||
---
|
||||
|
||||
#### Sync the backup regularly to another drive
|
||||
For increased backup security, you might consider syncing the backup repository regularly to another drive.
|
||||
|
||||
To do that, first add the drive to `/etc/fstab` so that it is able to get automatically mounted and then create a script that does all the things automatically. Here is an example for such a script:
|
||||
|
||||
<details>
|
||||
<summary>Click here to expand</summary>
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Please modify all variables below to your needings:
|
||||
SOURCE_DIRECTORY="/mnt/backup/borg"
|
||||
DRIVE_MOUNTPOINT="/mnt/backup-drive"
|
||||
TARGET_DIRECTORY="/mnt/backup-drive/borg"
|
||||
|
||||
########################################
|
||||
# Please do NOT modify anything below! #
|
||||
########################################
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Please run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -d "$SOURCE_DIRECTORY" ]; then
|
||||
echo "The source directory does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -d "$DRIVE_MOUNTPOINT" ]; then
|
||||
echo "The drive mountpoint must be an existing directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q " $DRIVE_MOUNTPOINT " /etc/fstab; then
|
||||
echo "Could not find the drive mountpoint in the fstab file. Did you add it there?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "$DRIVE_MOUNTPOINT"; then
|
||||
mount "$DRIVE_MOUNTPOINT"
|
||||
if ! mountpoint -q "$DRIVE_MOUNTPOINT"; then
|
||||
echo "Could not mount the drive. Is it connected?"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$SOURCE_DIRECTORY/lock.roster" ]; then
|
||||
echo "Cannot run the script as the backup archive is currently changed. Please try again later."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$TARGET_DIRECTORY"
|
||||
if ! [ -d "$TARGET_DIRECTORY" ]; then
|
||||
echo "Could not create target directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! rsync --stats --archive --human-readable --delete "$SOURCE_DIRECTORY/" "$TARGET_DIRECTORY"; then
|
||||
echo "Failed to sync the backup repository to the target directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
umount "$DRIVE_MOUNTPOINT"
|
||||
if mountpoint -q "$DRIVE_MOUNTPOINT"; then
|
||||
echo "Synced the backup repository successfully but failed to unmount the target drive."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Synced the backup repository successfully and unmounted the target drive."
|
||||
exit 0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
You can simply copy and past the script into a file e.g. named `backup-script.sh` e.g. here: `/root/backup-script.sh`. Do not forget to modify the variables to your needings though!
|
||||
|
||||
Afterwards apply the correct permissions with `sudo chown root:root /root/backup-script.sh` and `sudo chmod 700 /root/backup-script.sh`. Then you can create a cronjob that runs e.g. at `20:00` each week on sundays like this: `crontab -u root -l | { cat; echo "0 20 * * 7 /root/backup-script.sh"; } | crontab -u root -`. Make sure that it does not collidate with the daily backups from AIO (if configured) since the target backup repository might get into an inconsistent state. (There is no check in place that checks this.)
|
||||
|
||||
### How to change the default location of Nextcloud's Datadir?
|
||||
You can configure the Nextcloud container to use a specific directory on your host as data directory. You can do so by adding the environmental variable `NEXTCLOUD_DATADIR` to the initial startup of the mastercontainer. Allowed values for that variable are strings that start with `/mnt/` or `/media/`. An example for this is `-e NEXTCLOUD_DATADIR="/mnt/ncdata"`. Please make sure to apply the correct permissions to the chosen directory before starting Nextcloud the first time. In this example would the command for this be: `sudo chown -R 33:0 /mnt/ncdata`. **Attention:** It is very important to change the datadir **before** Nextcloud is installed/started the first time and not to change it afterwards!
|
||||
|
||||
### 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!
|
||||
|
||||
|
||||
Reference in New Issue
Block a user