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
- 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 - Delete-on-trash policy
- External public pad policy
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. - If Nextcloud and Etherpad are on the same registrable domain, Etherpad's default
SameSite: Laxsession cookie usually works. - If they are on different registrable domains, set Etherpad
cookie.sameSiteto"None"and keep HTTPS +trustProxy: true.
Example:
cloud.example.org+pad.example.org-> usually works with defaultSameSite: "Lax"cloud.example.org+pad.otherdomain.example-> usually requiresSameSite: "None"and HTTPS
- 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)
- 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
Health checkinSettings -> Administration -> Pads
- Check Etherpad cookie settings:
- same registrable domain: default
SameSite: "Lax"is usually enough - different registrable domains: use
cookie.sameSite: "None"andtrustProxy: true
- same registrable domain: default
- HTTPS is required when using
SameSite=None - Some hosting domains that look related are still treated as cross-site by browsers
- 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 (see THIRD_PARTY_NOTICES.md)
- Thanks to the Ownpad project for the groundwork, ideas, and lessons learned that inspired and shaped this plugin.
- Thanks to the Nextcloud and Etherpad communities for the underlying platforms and documentation.
- This project is not affiliated with, endorsed by, or operated by the Ownpad, Nextcloud, or Etherpad projects.