Skip to content

ether/etherpad-integration-for-nextcloud

Repository files navigation

Etherpad Integration for Nextcloud

This plugin lets you surface pads from an Etherpad instance inside Nextcloud and organize them there like other files.

Core Features

  • Each Etherpad pad is represented by a .pad file inside Nextcloud
  • .pad files live in normal Nextcloud folders and integrate with sharing, trash, restore, and file organization
  • Opening a .pad file 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 .pad snapshots
  • Trash deletes on Etherpad (with deferred retry when Etherpad is temporarily unavailable)
  • Restore recreates pads from .pad snapshot data

Requirements

  • Nextcloud 30 to 33 (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.

Etherpad Compatibility

  • 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.

Ownpad Compatibility

  • Running this app and Ownpad at the same time is not supported.
    • Both apps hook into .pad MIME/viewer handling, which leads to ambiguous file-type resolution and open-action conflicts.
  • Legacy Ownpad .pad files ([InternetShortcut] + URL=...) are automatically migrated to this app's binding-and-.pad model 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 .pad files 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). See docs/legacy-ownpad-migration.md for the full state table, audit-log shape, and the security rationale.

Install

The repository contains Vite-built frontend assets in js/. If you change files in src/, rebuild before copying the app:

npm install
npm run build

1) Copy app into Nextcloud

Place this repository as:

<nextcloud-root>/apps/etherpad_nextcloud

2) Enable app

php occ app:enable etherpad_nextcloud

3) (If needed) rebuild mimetype caches

Run this if .pad icons/actions do not appear correctly after install/upgrade:

php occ maintenance:mimetype:update-js
php occ maintenance:mimetype:update-db

4) Open admin settings

Go 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 .pad file interval
  • Delete-on-trash policy
  • External public pad policy

5) Check iframe and cookie setup for protected pads

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-Options policy.
  • 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: Lax session cookie usually works.
  • If they are on different registrable domains, set Etherpad cookie.sameSite to "None" and keep HTTPS + trustProxy: true.

Example:

  • cloud.example.org + pad.example.org -> usually works with default SameSite: "Lax"
  • cloud.example.org + pad.otherdomain.example -> usually requires SameSite: "None" and HTTPS

Upgrade

  1. Replace app files in apps/etherpad_nextcloud
  2. Run:
php occ app:disable etherpad_nextcloud
php occ app:enable etherpad_nextcloud
php occ maintenance:mimetype:update-js
php occ maintenance:mimetype:update-db

For 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.

Development Checks

Frontend source lives in src/ and is built into js/ with Vite.

npm test
npm run build

PHP checks and optional E2E checks are described in docs/release-process.md.

Usage

Create pads

  • + New -> New pad
  • + New -> Public pad (internal public pad on the configured Etherpad instance, or external public pad by URL)

Open pads

  • Click .pad file in Files app
  • App uses Nextcloud native viewer flow (openfile=true)

Sync

  • One-way sync only: content is copied from Etherpad into the .pad file snapshot.
  • No automatic reverse sync from .pad file 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.

Trash/Restore

  • When a .pad file is moved to the Nextcloud trash, the linked Etherpad pad is deleted.
  • If Etherpad is temporarily unavailable, delete is deferred and retried.
  • When the .pad file is restored from the Nextcloud trash, a new pad is recreated and the snapshot from the .pad file is replayed.

Troubleshooting

.pad downloads instead of opening in viewer

  • Ensure app is enabled:
    • php occ app:list | grep etherpad_nextcloud
  • Rebuild mimetype caches:
    • php occ maintenance:mimetype:update-js
    • php occ maintenance:mimetype:update-db
  • Reload browser with hard refresh

Wrong .pad icon (fallback/red icon)

  • Re-run mimetype update commands above
  • Check that app CSS loads
  • Confirm app migration alias is applied (app re-enable usually handles this)

+ New entries missing

  • Hard refresh browser once
  • Confirm Files app JS loaded without fatal errors in browser console

Protected pad permission errors

  • Verify Etherpad API key and Etherpad auth mode
  • Run admin Test Etherpad connection in Settings -> Administration -> Pads

Protected pads fail because of cookies / iframe auth

  • Check Etherpad cookie settings:
    • same registrable domain: default SameSite: "Lax" is usually enough
    • different registrable domains: use cookie.sameSite: "None" and trustProxy: true
  • HTTPS is required when using SameSite=None
  • Some hosting domains that look related are still treated as cross-site by browsers

Etherpad is blocked inside the Nextcloud viewer iframe

  • Check response headers on the Etherpad side and in the reverse proxy
  • Remove or relax conflicting X-Frame-Options rules
  • Prefer a Content-Security-Policy: frame-ancestors 'self' https://your-nextcloud.example header that explicitly allows your Nextcloud origin

iPhone / iOS Safari zooms when focusing the embedded editor

  • Usually caused by small editor/form font sizes inside Etherpad, not by the outer Nextcloud shell
  • For the default colibris skin, adjust src/static/skins/colibris/pad.css, for example in the mobile @media (max-width: 768px) section, and raise the effective pad/editor font size from 15px to 16px
  • Test in a private Safari tab or after clearing website data because Etherpad CSS is cached aggressively

Documentation

License

Acknowledgements

  • Thanks to the Ownpad project for the groundwork, ideas, and lessons learned that inspired and shaped this plugin.

About

Etherpad plugin for Nextcloud with .pad viewer flows, lifecycle handling, and one-way snapshot sync

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors