Skip to main content
Entwickler Themen
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

7.3.1. Nextcloud ExApps

ExApps, Glossar, öffnet in neuem Tab sind Nextcloud-Apps, die nicht im PHP-Server laufen, sondern als eigener Container. AppAPI, Glossar, öffnet in neuem Tab steuert Deploy und Lebenszyklus; HaRP, Glossar, öffnet in neuem Tab ist der Deploy Daemon, Glossar, öffnet in neuem Tab und der Proxy unter /exapps/. Die Go-Libraries darunter kapseln Auth, OCS, Glossar, öffnet in neuem Tab und Dateizugriff – Lifecycle-Routen und UI-Registrierung bleiben in der ExApp.

Englische Fachbegriffe sind im Glossar erklärt.

Strukturierung mit HaRP

HaRP übernimmt zwei Rollen:

  1. Deploy Daemon – AppAPI baut aus info.xml und den Deploy-Optionen eine Container-Anfrage und POSTet sie an HaRP. HaRP spricht mit dem Docker Engine (containers/create, dann start).
  2. Proxy unter /exapps/ – Browser und AppAPI erreichen die ExApp über denselben Pfad. Der Tunnel zur ExApp läuft über FRP, Glossar, öffnet in neuem Tab (Standardport 8782).

AppAPI entscheidet, was deployed wird. Bei einem Daemon vom Typ docker-install startet HaRP einen Container aus dem einen Image in <docker-install>. Es gibt kein Feld in info.xml für Compose-Dateien, Sidecars oder ein zweites Image.

flowchart LR
  Browser --> Proxy
  Proxy -->|"/exapps/"| HaRP
  HaRP -->|FRP| ExApp
  ExApp -->|"OCS / WebDAV<br/>AppAPI-Header"| Nextcloud
  ExApp -->|"Authorization: Bearer<br/>User Token"| Microservice

ExApp vs. Microservice

ExApp Microservice, Glossar, öffnet in neuem Tab
Registriert bei Nextcloud ja (AppAPI) nein
Erreichbar über HaRP /exapps/ ja nein
Sieht AUTHORIZATION-APP-API ja nein
Auth zum Aufrufer AppAPI-Header mit User-Id und APP_SECRET kurzlebiger User Token, Glossar, öffnet in neuem Tab (go-usertoken)

Die ExApp ist die Nextcloud-Seite. Microservices (Datenbanken, Fachdienste) liegen in einem eigenen Compose und hängen am selben Docker-Netz wie der Daemon (--net).

Nextcloud-Schnittstellen

AppAPI-Auth

Der Nutzer ist bereits in Nextcloud eingeloggt. Der Browser kommt über HaRP zur ExApp. AppAPI setzt die Header:

Header Inhalt
AA-VERSION AppAPI-Protokollversion
EX-APP-ID ExApp-Id
EX-APP-VERSION ExApp-Version
AUTHORIZATION-APP-API Base64 von userId:secret

userId ist die Nextcloud-Login-Id – der Requesting User, Glossar, öffnet in neuem Tab . secret ist APP_SECRET der ExApp. Gruppen, Anzeigename und Dateirechte stecken nicht im Header – die ExApp holt sie mit Folgeaufrufen als dieser Nutzer.

Ausgehende Aufrufe nach Nextcloud nutzen dieselbe Header-Form (Credentials.AuthHeaders, WithUser). Wer APP_SECRET hat, kann als beliebige User-Id sprechen; der Secret bleibt daher nur auf der ExApp.

Details und Prüfungsschritte: go-nc-exapp.

OCS

Über OCS (JSON) typisch:

WebDAV / Dateien

Dateizugriff als Requesting User läuft über Nextcloud Files (WebDAV). Dafür: go-nc-files (hängt an go-nc-exapp für die AppAPI Credentials, Glossar, öffnet in neuem Tab ).

UI-Registrierung

Beim Enable registriert die ExApp per OCS Top-Menü und Script, z. B.:

// PUT /enabled?enabled=1
ocsJSON(http.MethodPost, "/ocs/v2.php/apps/app_api/api/v1/ui/top-menu", map[string]any{
    "name":          "checkdns",
    "displayName":   "CheckDNS",
    "icon":          "img/app.svg",
    "adminRequired": adminRequired, // "0" oder "1"
})
ocsJSON(http.MethodPost, "/ocs/v2.php/apps/app_api/api/v1/ui/script", map[string]any{
    "type": "top_menu",
    "name": "checkdns",
    "path": "js/checkdns-main",
})

adminRequired steuert die Top Menu Visibility, Glossar, öffnet in neuem Tab (wer das Icon sieht). go-nc-exapp liefert TopMenuAdminRequired aus der Deploy-Env TOP_MENU_ADMIN_REQUIRED; die OCS-Registrierung selbst bleibt in der ExApp. Optional gibt es eine Files-ähnliche App Navigation, Glossar, öffnet in neuem Tab in go-nc-exapp.

Lifecycle-Routen

AppAPI spricht die ExApp direkt an (nicht der Browser-Nutzer):

Route Rolle
GET /heartbeat Health; AppAPI wartet bis zu ~90 s nach dem Start
POST /init Initialisierung; Fortschritt bis 100
PUT /enabled?enabled=1|0 UI registrieren bzw. abmelden

Access Gate, Glossar, öffnet in neuem Tab und Gruppenprüfungen (Required Groups, Glossar, öffnet in neuem Tab ) überspringen diese Pfade. Die Secret-Prüfung auf User-Routen bleibt davon unberührt. go-nc-exapp implementiert die Lifecycle-Handler nicht – die ExApp tut das selbst.

ExApp → Microservice

Microservices sehen keine AppAPI-Header. Die ExApp mintet nach erfolgreicher AppAPI-Prüfung einen kurzlebigen RS256-Token (sub = User-Id, optional groups) und schickt Authorization: Bearer …. Siehe go-usertoken.

Setup mit Pfaden

Zwei Nextcloud-URLs – oft verwechselt:

Name Wo gesetzt Wer ruft an
Daemon Nextcloud URL app_api:daemon:register Argument nextcloud_url AppAPI → {URL}/exapps/… (Heartbeat, Steuerung)
NC_INSTANCE_URL HaRP-Environment ExApp-Container → Nextcloud (OCS, WebDAV)

Sie sind gleich, wenn derselbe Host Nextcloud ausliefert und /exapps/ an HaRP weiterleitet. Sie differieren, wenn ein Reverse Proxy /exapps/ besitzt.

Docker-Netz und Reverse Proxy

Typisches Shared-Network-Layout (Platzhalter anpassen):

Dienst Rolle
Reverse Proxy (z. B. Caddy) Öffentlicher Einstieg: / → Nextcloud, /exapps/ → HaRP
Nextcloud PHP-Instanz, oft ohne eigenen Host-Port
HaRP Hostname z. B. appapi-harp; Docker-Socket gemountet; NC_INSTANCE_URL zeigt auf Nextcloud im Netz
Netz gemeinsames Docker-Netz, z. B. YOUR_NETWORK

ExApps stehen nicht in diesem Compose – AppAPI/HaRP startet sie auf derselben Docker-Engine.

Caddy hinter einem öffentlichen Host:

https://cloud.example {
	handle /exapps/* {
		reverse_proxy appapi-harp:8780 {
			transport http {
				read_timeout 1800s
			}
		}
	}

	handle {
		reverse_proxy nextcloud:80
	}
}

1800s entspricht dem HaRP-Default HP_TIMEOUT_SERVER. Im Docker-Netz ist der Upstream appapi-harp:8780 (oder der Hostname deines HaRP-Containers).

Nur lokal ohne TLS, Port am Proxy:

:8080 {
	handle /exapps/* {
		reverse_proxy appapi-harp:8780 {
			transport http {
				read_timeout 1800s
			}
		}
	}

	handle {
		reverse_proxy nextcloud:80
	}
}

FRP und Ports

  • HaRP HTTP (ExApps): 8780 (HP_EXAPPS_ADDRESS)
  • FRP: 8782 – ExApp-Container müssen den erreichen
  • Im Shared-Network-Layout bleiben 8780/8782 oft unveröffentlicht auf dem Host; nur der Reverse Proxy publiziert den Einstieg
  • Lab ohne TLS vor FRP: HP_FRP_DISABLE_TLS=true
  • Hinter einem Proxy: HP_TRUSTED_PROXY_IPS setzen (z. B. dein Proxy-Subnetz)

Beispiel-Zuordnung der beiden URLs:

  • Daemon Nextcloud URL = http://proxy.example:8080 (nur der Proxy leitet /exapps/ an HaRP)
  • HaRP NC_INSTANCE_URL = http://nextcloud (ExApp → Nextcloud im Docker-Netz)

Heartbeat-Fehler nach „Test deploy“ bedeuten meist: die Daemon-URL zeigt nicht auf die Front, die /exapps/ an HaRP schickt.

ExApp mit HaRP installieren

AppAPI ist ab Nextcloud 30.0.1 dabei. Falls aus:

# Host / klassisch
sudo -E -u www-data php occ app:enable app_api

# Nextcloud im Container
docker exec -u www-data nextcloud php occ app:enable app_api

Daemon registrieren

Generisches Beispiel (Shared Network, Platzhalter ersetzen):

docker exec -u www-data nextcloud php occ app_api:daemon:register \
  harp_proxy_docker "HaRP Proxy (Docker)" docker-install http \
  appapi-harp:8780 "https://cloud.example" \
  --net YOUR_NETWORK \
  --harp \
  --harp_frp_address "appapi-harp:8782" \
  --harp_shared_key "YOUR_HARP_SHARED_KEY" \
  --set-default

Klassisch auf dem Host (ohne docker exec):

sudo -E -u www-data php occ app_api:daemon:register \
  harp_proxy_docker "HaRP Proxy (Docker)" docker-install http \
  appapi-harp:8780 "https://cloud.example" \
  --net YOUR_NETWORK \
  --harp \
  --harp_frp_address "appapi-harp:8782" \
  --harp_shared_key "YOUR_HARP_SHARED_KEY" \
  --set-default

Wichtige Argumente: accepts-deploy-id = docker-install, Host = HaRP von Nextcloud aus erreichbar, --harp plus --harp_shared_key und --harp_frp_address, --set-default für Installs ohne expliziten Daemon-Namen. Shared Key = HP_SHARED_KEY in der HaRP-Umgebung.

docker exec -u www-data nextcloud php occ app_api:daemon:list

UI: Administration → AppAPI → Deploy daemons. Vorlage HaRP Proxy (Docker) für Shared Network; HaRP Proxy (Host) bei publizierten Ports. Danach Test deploy.

docker-install ohne --harp ist deprecated (Entfernung vorgesehen in Nextcloud 35). Neue Daemons mit --harp.

ExApp registrieren und verwalten

Image-Koordinaten stehen in appinfo/info.xml. Beispiel CheckDNS:

<external-app>
    <docker-install>
        <registry>gitea.neitzel.de</registry>
        <image>konrad/checkdns</image>
        <image-tag>0.1.14</image-tag>
    </docker-install>
</external-app>

Das Image muss für die Engine unter HaRP pullbar sein (oder lokal unter genau diesem Namen getaggt).

# Registrieren (Pfad zu info.xml muss im Nextcloud-Container existieren,
# oder https://-URL). App-Id und Daemon-Name anpassen.
docker exec -u www-data nextcloud php occ app_api:app:register your-app-id harp_proxy_docker \
  --info-xml /path/inside/container/appinfo/info.xml \
  --wait-finish \
  --env NAME=VALUE

docker exec -u www-data nextcloud php occ app_api:app:list
docker exec -u www-data nextcloud php occ app_api:app:disable your-app-id
docker exec -u www-data nextcloud php occ app_api:app:enable your-app-id
docker exec -u www-data nextcloud php occ app_api:app:update your-app-id \
  --info-xml /path/inside/container/appinfo/info.xml
docker exec -u www-data nextcloud php occ app_api:app:unregister your-app-id
# unregister behält das Persistenz-Volume; --rm-data löscht es; --force bei Cleanup-Fehlern

--env und --mount wiederholen; sie gelten für Optionen, die die ExApp in info.xml deklariert. UI: Apps → ExApp → Install; Deploy options setzen Env/Mounts vor dem Deploy.

Daemon entfernen erst, wenn keine ExApps mehr daran hängen: app_api:daemon:unregister <daemon-config-name>.

Allgemeine Hinweise

App-Icon fürs Menü

Das Top-Menü-Feld icon ist ein Pfad relativ zur ExApp (z. B. img/app.svg). Die ExApp liefert die Datei selbst (GET /img/app.svg). Für Navigations-Einträge in der optionalen App-Shell kann go-nc-exapp Core-SVGs unter /core/img/… referenzieren (NextcloudIcons) – das sind Nextcloud-Core-Pfade, keine eingebetteten Bytes in der Library.

info.xml und Image-Koordinaten

<registry>, <image>, <image-tag> bilden den Pull-Namen, z. B. gitea.neitzel.de/konrad/{exapp-id} mit explizitem Tag (kein automatisches latest). Lokal denselben Namen taggen, dann kann AppAPI ohne Push deployen.

Deploy-Env von AppAPI

AppAPI setzt u. a. auf dem Container:

Variable Bedeutung
AA_VERSION AppAPI-Protokollversion
APP_SECRET Shared Secret für AUTHORIZATION-APP-API
APP_ID / APP_DISPLAY_NAME / APP_VERSION Identität
APP_HOST / APP_PORT Listen-Ziel aus Sicht AppAPI
APP_PERSISTENT_STORAGE Volume über Updates hinweg
NEXTCLOUD_URL Nextcloud-URL für die ExApp

Zusätzliche Produkt-Variablen deklarierst du unter <environment-variables> und setzt sie per --env oder Deploy options (REQUIRED_GROUPS, TOP_MENU_ADMIN_REQUIRED, …). Env-Änderungen wirken nach Container-Neustart; Top-Menü zusätzlich nach Disable/Enable bzw. Update, weil die Registrierung bei PUT /enabled läuft.

Andere Dienste: separates Compose

Datenbanken, Caches und Microservices gehören in ein eigenes docker-compose.yml, Netz external: true mit dem Daemon---net (z. B. YOUR_NETWORK). Die ExApp bekommt die URL als deklarierte Deploy-Variable, z. B. --env LISTS_URL=http://lists:8080. info.xml beschreibt das nicht.

Libraries darunter

Klonen über SSH-Port 2222, z. B. ssh://git@gitea.neitzel.de:2222/konrad/go-nc-exapp.git. Für go get ohne öffentlichen Proxy: GOPRIVATE=gitea.neitzel.de.