This plugin lets you surface pads from an Etherpad instance inside Nextcloud and organize them there like other files.
- Each Etherpad pad is represented by a
.padfile inside Nextcloud .padfiles live in normal Nextcloud folders and integrate with sharing, trash, restore, and file organization- Opening a
.padfile in Nextcloud opens the linked Etherpad pad inside the native Nextcloud file viewer in an iframe - Protected and public pad modes
- Public folder/file share support for
.pad - Periodic sync from Etherpad into
.padsnapshots - Trash deletes on Etherpad (with deferred retry when Etherpad is temporarily unavailable)
- Restore recreates pads from
.padsnapshot data
Create a pad straight from the Files app with + New:
Open a .pad file and the linked Etherpad pad loads in the native Nextcloud viewer, with real-time collaboration and per-author colours:
Pads live alongside your other files and behave like any other Nextcloud file:
- Nextcloud
30to33(see appinfo/info.xml) - Etherpad reachable from Nextcloud server
- Etherpad API key
- HTTPS for production deployments
- For protected pads in the embedded viewer: Nextcloud and Etherpad must allow iframe embedding and send compatible cookies.
- Recommended: run Nextcloud and Etherpad on the same registrable domain, for example
cloud.example.org+pad.example.org.
- Works with different Etherpad releases via API version detection (fallback supported).
- This plugin requires Etherpad API key mode (
authenticationMethod: "apikey"). - OAuth-only Etherpad setups are not supported by this plugin.
- Running this app and Ownpad at the same time is not supported.
- Both apps hook into
.padMIME/viewer handling, which leads to ambiguous file-type resolution and open-action conflicts.
- Both apps hook into
- Legacy Ownpad
.padfiles ([InternetShortcut]+URL=...) are automatically migrated to this app's binding-and-.padmodel the first time a user opens them. The migration branches on the source URL's origin and the embedded pad-id:- Same Etherpad server, free-form pad-id → re-bound as a managed public pad.
- Same Etherpad server, group pad-id (
g.<group>$<name>) → re-bound as a managed protected pad. - Different Etherpad server → converted to an external (
ext.*) public pad pointing at the original URL.
- If two Ownpad
.padfiles point at the same pad, only the first one to be opened gets the binding; the second is treated like a copied pad (no second binding row, the existing copy-of-a-pad flow handles open from there). Seedocs/legacy-ownpad-migration.mdfor the full state table, audit-log shape, and the security rationale.
The repository contains Vite-built frontend assets in js/. If you change
files in src/, rebuild before copying the app:
npm install
npm run buildPlace this repository as:
<nextcloud-root>/apps/etherpad_nextcloud
php occ app:enable etherpad_nextcloudRun this if .pad icons/actions do not appear correctly after install/upgrade:
php occ maintenance:mimetype:update-js
php occ maintenance:mimetype:update-dbGo to:
Settings -> Administration -> Pads
and configure:
- Etherpad Base URL
- Etherpad API URL (optional; defaults to Base URL)
- Etherpad API key (OAuth is not required; Etherpad API key auth is used)
- Copy content to
.padfile interval - Which pad types users may create (see below)
- Delete-on-trash policy
- External public pad policy
Two settings control which pad types the app offers, both enabled by default:
- Protected pads — only people who can open the
.padfile in Nextcloud can open the pad. Created as Etherpad group pads, which require a session issued by Nextcloud. - Public pads — anyone with the pad link can open the pad, without a Nextcloud account.
Switching a type off hides its + New entries and refuses new pads of that
type on the API create endpoints. Pads that already exist keep working either
way.
Two paths fall back rather than refuse, so nothing gets stranded: a template
carrying the disabled mode, and the first-open initialisation of a .pad
that arrived outside the app (over WebDAV, say). Both create the pad in the
enabled mode; only with both types off is creation refused outright. Note
that this can widen access — a protected template becomes a public pad when
protected pads are off.
The setting decides what the app offers; it is not a hard boundary against a
user who crafts .pad files by hand. Recovering an orphaned .pad from its
snapshot still re-provisions the mode recorded in that file, because rescuing
existing content takes precedence.
Linking external public pads is governed separately by the external pad policy and is unaffected by these two settings.
If protected pads should open inside the Nextcloud viewer iframe:
-
Etherpad responses must allow embedding from your Nextcloud origin.
-
Reverse proxies must not enforce a conflicting
X-Frame-Optionspolicy. -
A
Content-Security-Policy: frame-ancestors ...header on the Etherpad side is the most reliable modern setup. Protected pads additionally require Nextcloud and Etherpad to share a parent domain, unless both run on the same host. Nextcloud issues the Etherpad session cookie from its own response, and a browser only accepts aDomain=that covers the host which sent it. A response fromcloud.example.orgcan therefore never set a cookie that reachespad.otherdomain.example, andSameSite=Nonedoes not change that — it governs whether an already valid cookie is sent cross-site, not which domain may be set. -
Same host for both: nothing to configure, a host-only cookie covers it.
-
Shared parent domain: the cookie domain is derived automatically, and Etherpad's default
SameSite: Laxusually works. -
Unrelated registrable domains: protected pads cannot work with the current session model. If a reverse proxy already serves Etherpad under the Nextcloud domain, put that address in the base URL — pad links use it, so the cookie follows. Otherwise move one host, or switch protected pads off and offer public pads instead.
The check compares the Nextcloud host with the host in the base URL, which is exactly the address the browser loads a pad from. A proxy alias therefore counts as soon as it is the configured base URL, and does not need to be detected separately.
Example:
cloud.example.org+pad.example.org-> works, cookie domain.example.orgcloud.example.org+cloud.example.org-> works, host-only cookiecloud.example.org+pad.otherdomain.example-> not supported for protected pads
Test Etherpad connection reports this alongside the connection result, and the
settings page shows it without running the test.
- Replace app files in
apps/etherpad_nextcloud - Run:
php occ app:disable etherpad_nextcloud
php occ app:enable etherpad_nextcloud
php occ maintenance:mimetype:update-js
php occ maintenance:mimetype:update-dbFor deployment, copy the app to apps/etherpad_nextcloud and exclude development-only content such as .git/, node_modules/, tests/, docs/, .phpunit.cache/, and local temp files. Keep the built js/ assets in the deployed app.
Frontend source lives in src/ and is built into js/ with Vite.
npm test
npm run buildPHP checks and optional E2E checks are described in docs/release-process.md.
+ New -> New pad+ New -> Public pad(internal public pad on the configured Etherpad instance, or external public pad by URL)
An administrator can add shared templates under
Settings -> Administration -> Pads: upload a .pad file and it appears as a
tile for everyone. Its content becomes the new pad and placeholders such as
{{date}} are resolved on creation. The pad type of the template is used when
that type is enabled; otherwise the pad is created with the type that is
available, which can turn a protected template into a public pad.
Shared templates live in the instance's appdata directory, not in any user's
files. They are covered by a full backup of the data directory, but not by a
per-user export, and they have no file versioning or trash — uploading over an
existing name asks for confirmation because the previous file is gone for good.
- Click
.padfile in Files app - App uses Nextcloud native viewer flow (
openfile=true)
- One-way sync only: content is copied from Etherpad into the
.padfile snapshot. - No automatic reverse sync from
.padfile content back into Etherpad. - Automatic while viewer is open (interval from admin settings) and on viewer hide / page unload.
- Backend endpoint
POST /api/v1/pads/sync/{fileId}remains available for programmatic syncs.
- When a
.padfile is moved to the Nextcloud trash, the linked Etherpad pad is deleted. - If Etherpad is temporarily unavailable, delete is deferred and retried.
- When the
.padfile is restored from the Nextcloud trash, a new pad is recreated and the snapshot from the.padfile is replayed.
- Ensure app is enabled:
php occ app:list | grep etherpad_nextcloud
- Rebuild mimetype caches:
php occ maintenance:mimetype:update-jsphp occ maintenance:mimetype:update-db
- Reload browser with hard refresh
- Re-run mimetype update commands above
- Check that app CSS loads
- Confirm app migration alias is applied (app re-enable usually handles this)
- Hard refresh browser once
- Confirm Files app JS loaded without fatal errors in browser console
- Verify Etherpad API key and Etherpad auth mode
- Run admin
Test Etherpad connectioninSettings -> Administration -> Pads
- First check the domain relationship: Nextcloud and Etherpad must share a
parent domain, or run on the same host.
Test Etherpad connectionnames both hostnames when they do not. - Check Etherpad cookie settings:
- shared parent domain: default
SameSite: "Lax"is usually enough - across subdomains behind a proxy:
cookie.sameSite: "None"andtrustProxy: true
- shared parent domain: default
- HTTPS is required when using
SameSite=None - A shared parent that is a public suffix (
co.uk,github.io) does not count: browsers reject it as a cookie domain
- Check response headers on the Etherpad side and in the reverse proxy
- Remove or relax conflicting
X-Frame-Optionsrules - Prefer a
Content-Security-Policy: frame-ancestors 'self' https://your-nextcloud.exampleheader that explicitly allows your Nextcloud origin
- Usually caused by small editor/form font sizes inside Etherpad, not by the outer Nextcloud shell
- For the default
colibrisskin, adjustsrc/static/skins/colibris/pad.css, for example in the mobile@media (max-width: 768px)section, and raise the effective pad/editor font size from15pxto16px - Test in a private Safari tab or after clearing website data because Etherpad CSS is cached aggressively
- Architecture: docs/architecture.md
- API routes: docs/api-reference.md
- Etherpad integration details: docs/etherpad-integration.md
.padformat: docs/pad-format.md- I18N: docs/i18n.md
- UI icons: docs/ui-icons.md
- Testing and release checks: docs/release-process.md
- App code: AGPL-3.0-or-later (full text: LICENSES/AGPL-3.0.txt)
- Etherpad logo assets in
img/etherpad-icon-*.svg: Apache-2.0 (full text: LICENSES/Apache-2.0.txt)
- Thanks to the Ownpad project for the groundwork, ideas, and lessons learned that inspired and shaped this plugin.


