feat(app-api): add HaRP container

Signed-off-by: Oleksander Piskun <oleksandr2088@icloud.com>
Signed-off-by: bigcat88 <bigcat88@icloud.com>
This commit is contained in:
Oleksander Piskun 2026-01-20 15:42:06 +02:00 committed by bigcat88
parent 88a45d1a80
commit a18ef97ab4
13 changed files with 126 additions and 7 deletions

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

@ -75,9 +75,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

@ -567,6 +567,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

@ -126,6 +126,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"
@ -146,6 +160,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"></script>
<script type="text/javascript" src="disable-onlyoffice.js"></script>