This commit is contained in:
Oleksandr Piskun 2026-01-28 10:37:39 +01:00 committed by GitHub
commit 3b262f84f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 126 additions and 7 deletions

View file

@ -58,6 +58,11 @@ http://{$APACHE_HOST}:23973, # For Collabora callback and WOPI requests, see con
reverse_proxy {$WHITEBOARD_HOST}:3002
}
# HaRP (ExApps)
route /exapps/* {
reverse_proxy {$HARP_HOST}:8780
}
# Nextcloud
route {
header Strict-Transport-Security max-age=31536000;

View file

@ -1022,13 +1022,13 @@ else
fi
fi
# Docker socket proxy
# Docker socket proxy / HaRP
# app_api is a shipped app
if [ -d "/var/www/html/custom_apps/app_api" ]; then
php /var/www/html/occ app:disable app_api
rm -r "/var/www/html/custom_apps/app_api"
fi
if [ "$DOCKER_SOCKET_PROXY_ENABLED" = 'yes' ]; then
if [ "$DOCKER_SOCKET_PROXY_ENABLED" = 'yes' ] || [ "$HARP_ENABLED" = 'yes' ]; then
if [ "$(php /var/www/html/occ config:app:get app_api enabled)" != "yes" ]; then
php /var/www/html/occ app:enable app_api
fi

View file

@ -12,7 +12,7 @@ You can run the containers that are build for AIO with docker-compose. This come
- You lose the AIO interface
- You lose update notifications and automatic updates
- You lose all AIO backup and restore features
- You lose the built-in [Docker Socket Proxy container](https://github.com/nextcloud/docker-socket-proxy#readme) (needed for [Nextcloud App API](https://github.com/nextcloud/app_api#nextcloud-appapi))
- You lose the built-in [Docker Socket Proxy container](https://github.com/nextcloud/docker-socket-proxy#readme) and [HaRP container](https://github.com/nextcloud/HaRP) (needed for [Nextcloud App API](https://github.com/nextcloud/app_api#nextcloud-appapi))
- You lose all community containers: https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers
- **You need to know what you are doing, especially when modifying the compose.yaml file**
- For updating, you need to strictly follow the at the bottom described update routine

View file

@ -27,6 +27,8 @@ OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "next
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-borgbackup"))')"
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-docker-socket-proxy"))')"
OUTPUT="$(echo "$OUTPUT" | jq '.services[] |= if has("depends_on") then .depends_on |= if contains(["nextcloud-aio-docker-socket-proxy"]) then del(.[index("nextcloud-aio-docker-socket-proxy")]) else . end else . end')"
OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-harp"))')"
OUTPUT="$(echo "$OUTPUT" | jq '.services[] |= if has("depends_on") then .depends_on |= if contains(["nextcloud-aio-harp"]) then del(.[index("nextcloud-aio-harp")]) else . end else . end')"
OUTPUT="$(echo "$OUTPUT" | jq '.services[] |= if has("depends_on") then .depends_on |= map({ (.): { "condition": "service_started", "required": false } }) else . end' | jq '.services[] |= if has("depends_on") then .depends_on |= reduce .[] as $item ({}; . + $item) else . end')"
sudo snap install yq
@ -45,6 +47,8 @@ sed -i 's|- ip_binding: |- |' containers.yml
sed -i '/AIO_TOKEN/d' containers.yml
sed -i '/AIO_URL/d' containers.yml
sed -i '/DOCKER_SOCKET_PROXY_ENABLED/d' containers.yml
sed -i '/HARP_ENABLED/d' containers.yml
sed -i '/HP_SHARED_KEY/d' containers.yml
sed -i '/ADDITIONAL_TRUSTED_PROXY/d' containers.yml
sed -i '/TURN_DOMAIN/d' containers.yml

View file

@ -10,6 +10,7 @@
"nextcloud-aio-talk",
"nextcloud-aio-notify-push",
"nextcloud-aio-whiteboard",
"nextcloud-aio-harp",
"nextcloud-aio-nextcloud"
],
"display_name": "Apache",
@ -49,7 +50,8 @@
"APACHE_MAX_SIZE=%APACHE_MAX_SIZE%",
"APACHE_MAX_TIME=%NEXTCLOUD_MAX_TIME%",
"NOTIFY_PUSH_HOST=nextcloud-aio-notify-push",
"WHITEBOARD_HOST=nextcloud-aio-whiteboard"
"WHITEBOARD_HOST=nextcloud-aio-whiteboard",
"HARP_HOST=nextcloud-aio-harp"
],
"volumes": [
{
@ -146,7 +148,8 @@
"nextcloud-aio-fulltextsearch",
"nextcloud-aio-talk-recording",
"nextcloud-aio-imaginary",
"nextcloud-aio-docker-socket-proxy"
"nextcloud-aio-docker-socket-proxy",
"nextcloud-aio-harp"
],
"display_name": "Nextcloud",
"image": "ghcr.io/nextcloud-releases/aio-nextcloud",
@ -172,7 +175,8 @@
"SIGNALING_SECRET",
"FULLTEXTSEARCH_PASSWORD",
"IMAGINARY_SECRET",
"WHITEBOARD_SECRET"
"WHITEBOARD_SECRET",
"HP_SHARED_KEY"
],
"volumes": [
{
@ -257,7 +261,9 @@
"THIS_IS_AIO=true",
"IMAGINARY_SECRET=%IMAGINARY_SECRET%",
"WHITEBOARD_SECRET=%WHITEBOARD_SECRET%",
"WHITEBOARD_ENABLED=%WHITEBOARD_ENABLED%"
"WHITEBOARD_ENABLED=%WHITEBOARD_ENABLED%",
"HARP_ENABLED=%HARP_ENABLED%",
"HP_SHARED_KEY=%HP_SHARED_KEY%"
],
"stop_grace_period": 600,
"restart": "unless-stopped",
@ -846,6 +852,51 @@
"NET_RAW"
]
},
{
"container_name": "nextcloud-aio-harp",
"image_tag": "release",
"display_name": "HaRP",
"image": "ghcr.io/nextcloud/nextcloud-appapi-harp",
"init": true,
"internal_port": "8780",
"expose": [
"8780"
],
"environment": [
"HP_SHARED_KEY=%HP_SHARED_KEY%",
"NC_INSTANCE_URL=https://%NC_DOMAIN%",
"HP_LOG_LEVEL=warning",
"HP_FRP_DISABLE_TLS=true",
"TZ=%TIMEZONE%"
],
"secrets": [
"HP_SHARED_KEY"
],
"volumes": [
{
"source": "%WATCHTOWER_DOCKER_SOCKET_PATH%",
"destination": "/var/run/docker.sock",
"writeable": false
},
{
"source": "nextcloud_aio_harp",
"destination": "/certs",
"writeable": true
}
],
"restart": "unless-stopped",
"read_only": true,
"tmpfs": [
"/tmp",
"/run/harp"
],
"cap_drop": [
"NET_RAW"
],
"backup_volumes": [
"nextcloud_aio_harp"
]
},
{
"container_name": "nextcloud-aio-whiteboard",
"image_tag": "%AIO_CHANNEL%",

View file

@ -120,9 +120,16 @@ document.addEventListener("DOMContentLoaded", function () {
}
}
function handleHarpWarning() {
if (document.getElementById("harp").checked) {
alert('⚠️ Warning! Enabling this container comes with possible Security problems since you are exposing the docker socket and all its privileges to the HaRP container. Enable this only if you are sure what you are doing!');
}
}
// Initialize event listeners for specific behaviors
document.getElementById("talk").addEventListener('change', handleTalkVisibility);
document.getElementById("docker-socket-proxy").addEventListener('change', handleDockerSocketProxyWarning);
document.getElementById("harp").addEventListener('change', handleHarpWarning);
// Initialize talk-recording visibility on page load
handleTalkVisibility(); // Ensure talk-recording is correctly initialized

View file

@ -0,0 +1,7 @@
document.addEventListener("DOMContentLoaded", function(event) {
// HaRP
let harp = document.getElementById("harp");
if (harp) {
harp.disabled = true;
}
});

View file

@ -136,6 +136,7 @@ $app->get('/containers', function (Request $request, Response $response, array $
'is_nvidia_gpu_enabled' => $configurationManager->isNvidiaGpuEnabled(),
'is_talk_recording_enabled' => $configurationManager->isTalkRecordingEnabled(),
'is_docker_socket_proxy_enabled' => $configurationManager->isDockerSocketProxyEnabled(),
'is_harp_enabled' => $configurationManager->isHarpEnabled(),
'is_whiteboard_enabled' => $configurationManager->isWhiteboardEnabled(),
'community_containers' => $configurationManager->listAvailableCommunityContainers(),
'community_containers_enabled' => $configurationManager->GetEnabledCommunityContainers(),

View file

@ -90,6 +90,10 @@ readonly class ContainerDefinitionFetcher {
if (!$this->configurationManager->isDockerSocketProxyEnabled()) {
continue;
}
} elseif ($entry['container_name'] === 'nextcloud-aio-harp') {
if (!$this->configurationManager->isHarpEnabled()) {
continue;
}
} elseif ($entry['container_name'] === 'nextcloud-aio-whiteboard') {
if (!$this->configurationManager->isWhiteboardEnabled()) {
continue;
@ -199,6 +203,10 @@ readonly class ContainerDefinitionFetcher {
if (!$this->configurationManager->isDockerSocketProxyEnabled()) {
continue;
}
} elseif ($value === 'nextcloud-aio-harp') {
if (!$this->configurationManager->isHarpEnabled()) {
continue;
}
} elseif ($value === 'nextcloud-aio-whiteboard') {
if (!$this->configurationManager->isWhiteboardEnabled()) {
continue;

View file

@ -119,6 +119,11 @@ readonly class ConfigurationController {
} else {
$this->configurationManager->SetDockerSocketProxyEnabledState(0);
}
if (isset($request->getParsedBody()['harp'])) {
$this->configurationManager->SetHarpEnabledState(1);
} else {
$this->configurationManager->SetHarpEnabledState(0);
}
if (isset($request->getParsedBody()['whiteboard'])) {
$this->configurationManager->SetWhiteboardEnabledState(1);
} else {

View file

@ -162,6 +162,21 @@ class ConfigurationManager
$this->WriteConfig($config);
}
public function isHarpEnabled() : bool {
$config = $this->GetConfig();
if (isset($config['isHarpEnabled']) && $config['isHarpEnabled'] === 1) {
return true;
} else {
return false;
}
}
public function SetHarpEnabledState(int $value) : void {
$config = $this->GetConfig();
$config['isHarpEnabled'] = $value;
$this->WriteConfig($config);
}
public function isWhiteboardEnabled() : bool {
$config = $this->GetConfig();
if (isset($config['isWhiteboardEnabled']) && $config['isWhiteboardEnabled'] === 0) {

View file

@ -582,6 +582,7 @@ readonly class DockerActionManager {
'IMAGINARY_ENABLED' => $this->configurationManager->isImaginaryEnabled() ? 'yes' : '',
'FULLTEXTSEARCH_ENABLED' => $this->configurationManager->isFulltextsearchEnabled() ? 'yes' : '',
'DOCKER_SOCKET_PROXY_ENABLED' => $this->configurationManager->isDockerSocketProxyEnabled() ? 'yes' : '',
'HARP_ENABLED' => $this->configurationManager->isHarpEnabled() ? 'yes' : '',
'NEXTCLOUD_UPLOAD_LIMIT' => $this->configurationManager->GetNextcloudUploadLimit(),
'NEXTCLOUD_MEMORY_LIMIT' => $this->configurationManager->GetNextcloudMemoryLimit(),
'NEXTCLOUD_MAX_TIME' => $this->configurationManager->GetNextcloudMaxTime(),

View file

@ -198,6 +198,20 @@
>
<label for="docker-socket-proxy">Docker Socket Proxy (needed for <a target="_blank" href="https://github.com/cloud-py-api/app_api#nextcloud-appapi">Nextcloud App API</a>)</label>
</p>
<p>
<input
type="checkbox"
id="harp"
name="harp"
{% if is_harp_enabled == true %}
checked="checked"
data-initial-state="true"
{% else %}
data-initial-state="false"
{% endif %}
>
<label for="harp">HaRP (High-availability Reverse Proxy for <a target="_blank" href="https://github.com/nextcloud/HaRP">Nextcloud ExApps</a>)</label>
</p>
<p>
<input
type="checkbox"
@ -218,6 +232,7 @@
{% if isAnyRunning == true %}
<script type="text/javascript" src="disable-clamav.js"></script>
<script type="text/javascript" src="disable-docker-socket-proxy.js"></script>
<script type="text/javascript" src="disable-harp.js"></script>
<script type="text/javascript" src="disable-talk.js"></script>
<script type="text/javascript" src="disable-collabora.js?v2"></script>
<script type="text/javascript" src="disable-onlyoffice.js?v2"></script>