No description
Find a file
John McLear 02e37e0112
feat(packaging): publish Etherpad as a Snap (#7558)
* feat(packaging): publish Etherpad as a Snap

Adds first-class Snap packaging so Ubuntu / snapd users can install via
`sudo snap install etherpad-lite`.

- snap/snapcraft.yaml — core24, strict confinement, builds with pnpm
  against a pinned Node.js 22 runtime. Version is auto-derived from
  src/package.json so `snap info` tracks upstream release numbering.
- snap/local/bin/etherpad-service — launch wrapper that seeds
  $SNAP_COMMON/etc/settings.json on first run (rewriting the default
  dirty-DB path to a writable $SNAP_COMMON location) and execs Etherpad
  via `node --import tsx/esm`.
- snap/local/bin/etherpad-healthcheck-wrapper — HTTP probe for external
  supervisors, falling back to Node if curl isn't staged.
- snap/local/bin/etherpad-cli — thin passthrough to Etherpad's bin/
  scripts (importSqlFile, checkPad, etc.).
- snap/hooks/configure — exposes `snap set etherpad-lite port=<n>` and
  `ip=<addr>` with validation, restarts the service when running.
- snap/README.md — build / install / configure / publish instructions.
- .github/workflows/snap-publish.yml — builds on every v* tag, uploads
  a short-lived artifact, publishes to `edge`, and then promotes to
  `stable` through a manually-approved GitHub Environment. Requires a
  one-time `snapcraft register etherpad-lite` plus provisioning of the
  `SNAPCRAFT_STORE_CREDENTIALS` repo secret (instructions inline).

Pad data (dirty DB, logs) lives in /var/snap/etherpad-lite/common/ and
survives snap refreshes. The read-only $SNAP squashfs is never written
to at runtime.

Refs #7529

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(snap): pass --settings flag, env-subst ip/port, 2-space indent

Addresses Qodo review feedback on #7558:

1. Settings file ignored: Etherpad's Settings loader reads `argv.settings`,
   not the `EP_SETTINGS` env var. Without `--settings`, the launcher's
   seeded $SNAP_COMMON/etc/settings.json is never loaded; Etherpad falls
   back to <install-root>/settings.json, which lives on the read-only
   squashfs — so the default dirty-DB path ends up unwritable and the
   daemon fails to persist pads. Fix: pass `--settings "${SETTINGS}"` to
   node; drop the EP_SETTINGS export.

2. `snap set` overrides were no-ops: the seeded settings.json carries the
   template's literal `"ip": "0.0.0.0"` / `"port": 9001` values, which
   override the env-based defaults Etherpad exposes via ${…}
   substitution. Users following the README saw the listener stay put
   after `snap set etherpad-lite port=…`. Fix: after copying the
   template on first run, rewrite the top-level `ip` and `port` lines
   to `"${IP:0.0.0.0}"` / `"${PORT:9001}"`. Use `0,/…/` anchors so the
   `dbSettings.port` entry further down stays literal.

3. Indentation: reflow the new shell scripts from 4-space to 2-space to
   match the repo style rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(snap): default seeded settings to sqlite, not dirty

settings.json.template's own comment says dirty is for testing only.
A Snap install is the "not testing" case — shipping it by default
means every `sudo snap install etherpad-lite` starts on a DB the
project explicitly recommends against.

Rewrite the postinstall sed to switch dbType: "dirty" → "sqlite" and
point filename at $SNAP_COMMON/var/etherpad.db. sqlite is already
shipped in-tree via ueberdb2 → rusty-store-kv (prebuilt napi-rs
binary, no build deps), so this works under strict confinement with
zero snap.yaml changes.

Only affects first-run seeding; existing $SNAP_COMMON/etc/settings.json
is never touched on refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(snap): rename to "etherpad", glob tag filter, harden cli

- Snap is registered as `etherpad` (the project's only name) — drops the
  legacy `etherpad-lite` from the name, app, paths, install dir, configure
  hook, README and workflow artifact. The daemon app shares the snap name,
  so `snap install etherpad` exposes a bare `etherpad` command; the bin/
  passthrough is now `etherpad.cli`.
- snap-publish.yml: GitHub Actions tag filters use globs, not regex. The
  prior `v?[0-9]+.[0-9]+.[0-9]+` pattern would never match a real release
  tag (Qodo review). Replace with two glob entries covering `vX.Y.Z` and
  `X.Y.Z`.
- etherpad-cli: reject path-traversal in the `<bin-script>` arg (anything
  containing `/`, `..`, or empty) and add a default `*)` case so files
  with unsupported extensions fail loud instead of silently exiting 0
  (Qodo review).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(snap): unbreak build — refresh corepack, drop pnpm prune

Two issues hit on the first real `snapcraft pack` of this recipe:

- `corepack prepare pnpm@10.33.0 --activate` failed with
  `Cannot find matching keyid` because Node 22.12's bundled corepack
  ships a stale signing-key list and rejects newer pnpm releases
  (nodejs/corepack#612). Refresh corepack itself via npm before
  preparing pnpm.
- `pnpm prune --prod` is interactive on workspace projects: it asks
  "The modules directories will be removed and reinstalled from
  scratch. Proceed? (Y/n)" and deadlocks on stdin under sudo + tee.
  Replace it with the explicit "wipe node_modules + prod reinstall"
  pattern, which is non-interactive, faster (pnpm resolves the prod
  graph from its CAS cache), and byte-identical in result.

Verified locally: `snapcraft pack --destructive-mode` produces
`etherpad_2.6.1_amd64.snap` end-to-end in ~3 min.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(snap): unbreak runtime — tsx resolution, var/ writability, env

Three runtime crashes surfaced when actually installing the built snap
under strict confinement. Fixed each, plus a smoke-test script.

- `tsx` is in the `src` workspace's node_modules under pnpm hoisting,
  not at the snap install root. The wrapper now `cd "${APP_DIR}/src"`
  and uses bare `--import tsx` (matching `bin/cleanRun.sh`); the prior
  `--import tsx/esm` triggered ERR_REQUIRE_CYCLE on Etherpad's mixed
  CJS/ESM source tree.
- Etherpad's plugin installer writes `var/installed_plugins.json` via
  __dirname-relative paths, which resolve to absolute paths inside the
  read-only snap squashfs (EROFS). snap layouts can't intercept paths
  inside `$SNAP`, so replace the shipped `var/` dir with a symlink to
  `/var/snap/etherpad/common/etherpad-app-var/` (auto-created by the
  wrapper on first run). Persistent state survives `snap refresh`.
- Drop the unused `EP_SETTINGS` and `EP_DATA_DIR` env vars from the
  app's `environment:` block. Etherpad's settings loader doesn't read
  them — it reads `argv.settings`, which the wrapper already passes via
  `--settings`. They were producing `[WARN] settings - Unknown Setting`
  noise on every start.

Add `snap/tests/smoke.sh`: rebuild + install + configure test port 9003
+ assert listener + curl /health + tail logs. Local verified output:
  HTTP 200, body {"status":"pass","releaseId":"2.6.1"}, server logs
  `Etherpad is running` on `http://0.0.0.0:9003/`.

.gitignore now excludes destructive-mode build outputs (parts/, stage/,
prime/, .craft/, *.snap).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(snap): wrapper unit tests, PR CI build, expanded docs

Coverage in snap/tests/ (47 assertions, ~5s, no snapd/sudo/network):
- test-snapcraft-yaml.sh: required keys, name validity, daemon-app
  matches snap name, no etherpad-lite regression, env-var whitelist.
- test-cli.sh: path-traversal rejection, .ts/.sh dispatch, default-case
  rejection, no-args usage.
- test-configure.sh: port (1-65535) and ip (v4/v6) validation via
  mocked snapctl.
- test-service-bootstrap.sh: first-run seeding from
  settings.json.template, sed rewrite of dbType/filename/ip/port,
  writable-dir creation, snapctl override propagation to node env,
  idempotency on second run, default fallbacks.
- run-all.sh: bash -n syntax check on every wrapper + hook, then
  sources each test file and reports totals. All assertions use port
  9003 (project test convention).

CI in .github/workflows/snap-build.yml:
- Triggers on PR / push-to-develop touching snap/, settings.json.template,
  or the workflow itself.
- Job 1 wrapper-tests: runs run-all.sh.
- Job 2 snap-pack: snapcraft pack --destructive-mode, uploads .snap as
  PR artifact for sideload.
- Stays separate from snap-publish.yml (tag-triggered, store-bound).

snap/README.md fully rewritten:
- User-facing usage, install, configure
- Architecture: file layout, var/-symlink rationale, settings.json
  rewrite rationale, double-pnpm-install rationale, daemon-name-shares-
  snap-name rationale
- Three test layers with exactly when/why to run each
- Dev workflow loop
- Publishing maintainer setup
- Troubleshooting for every failure mode hit during this PR (EROFS,
  tsx not found, ERR_REQUIRE_CYCLE, snap-store-down, pnpm prune hang)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(snap): replace dead snapcraft.io/docs/releasing-to-the-snap-store link

That URL now 404s. Point at the canonical documentation.ubuntu.com
locations instead, broken out into the specific pages a maintainer
actually needs:

- Register a snap (to claim the name)
- snapcraft export-login (to generate the SNAPCRAFT_STORE_CREDENTIALS
  secret)
- Publishing how-to index (root index for everything else)

Same fix in the snap-publish.yml header comment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:19:10 +01:00
.github feat(packaging): publish Etherpad as a Snap (#7558) 2026-05-02 13:19:10 +01:00
admin i18n + a11y for admin disables warning (review feedback) (#7652) 2026-05-02 19:25:21 +08:00
bin fix(test): disables helper auto-detect must follow symlinks (#7654) 2026-05-02 19:25:16 +08:00
doc feat(test): feature tags + declared-disables contract for opt-out plugins (#7648) 2026-05-02 10:00:28 +01:00
docs/superpowers feat(gdpr): pad deletion controls (PR1 of #6701) (#7546) 2026-05-01 13:50:04 +01:00
local_plugins Fix installation of local plugins 2025-04-05 15:31:36 +02:00
packaging ci(packaging): publish signed apt repository to etherpad.org/apt (closes #7610) (#7624) 2026-04-29 00:20:00 +01:00
snap feat(packaging): publish Etherpad as a Snap (#7558) 2026-05-02 13:19:10 +01:00
src test: tag two chat-toggle pad_settings specs with @feature:chat (#7655) 2026-05-02 12:45:14 +01:00
ui feat!: replace Abiword with LibreOffice and add DOCX export (#7539) 2026-04-19 09:08:22 +01:00
var Use temporary directory for esbuild 2024-11-05 20:44:27 +01:00
.dockerignore Added new command to setup etherpad. Fixed Dockerfile 2024-07-23 17:43:32 +02:00
.editorconfig Added editorconfig configuration (#6347) 2024-04-23 07:04:30 +02:00
.env.default Fixed docker compose (#6337) 2024-04-17 20:50:21 +02:00
.env.dev.default Fixed docker compose (#6337) 2024-04-17 20:50:21 +02:00
.gitattributes tests: Microsoft Windows Server CI (#4791) 2021-02-18 18:49:43 +00:00
.gitignore feat(packaging): publish Etherpad as a Snap (#7558) 2026-05-02 13:19:10 +01:00
.npmrc fix: use hardlink package-import-method so the Docker build works on ZFS (#7342) (#7533) 2026-04-17 12:03:21 +01:00
.pr_agent.toml docs: add AGENTS.MD for AI and developer guidance (#7348) 2026-03-04 21:03:58 +00:00
AGENTS.MD chore: Rename some occurences of etherpad-lite to etherpad (#7552) 2026-04-19 16:53:57 +02:00
best_practices.md chore: Rename some occurences of etherpad-lite to etherpad (#7552) 2026-04-19 16:53:57 +02:00
CHANGELOG.md ci(docs): build on PRs and pin Node 22 (Qodo follow-up to #7640) (#7645) 2026-05-01 17:12:23 +01:00
CONTRIBUTING.md chore: Rename some occurences of etherpad-lite to etherpad (#7552) 2026-04-19 16:53:57 +02:00
docker-compose.dev.yml Update docker-compose.dev.yml (#6654) 2024-09-13 08:08:56 +02:00
docker-compose.yml security: run Etherpad container as non-root user (fixes #7134) (#7287) 2026-01-10 20:28:58 +01:00
Dockerfile chore: updated node to supported 22,24,25 (#7628) 2026-04-28 22:45:28 +02:00
LICENSE Update LICENSE 2013-06-26 23:34:35 +01:00
package.json ci(docs): build on PRs and pin Node 22 (Qodo follow-up to #7640) (#7645) 2026-05-01 17:12:23 +01:00
pnpm-lock.yaml build(deps-dev): bump lucide-react (#7632) 2026-05-01 20:27:20 +02:00
pnpm-workspace.yaml fix: downgrade ERR_PNPM_IGNORED_BUILDS to a warning (#7527) 2026-04-16 15:20:00 +01:00
README.md ci(docs): build on PRs and pin Node 22 (Qodo follow-up to #7640) (#7645) 2026-05-01 17:12:23 +01:00
SECURITY.md Create SECURITY.md 2020-07-07 10:36:17 +01:00
settings.json.docker feat(gdpr): pad deletion controls (PR1 of #6701) (#7546) 2026-05-01 13:50:04 +01:00
settings.json.template feat(gdpr): pad deletion controls (PR1 of #6701) (#7546) 2026-05-01 13:50:04 +01:00
tests restructure: move bin/ and tests/ to src/ 2021-02-04 17:15:08 -05:00

Etherpad — the editor for documents that matter

Real-time collaborative editing where authorship is the default, your server is the only server, and you decide what AI (if any) ever touches your text.

Demo Etherpad Animated Jif

About

Etherpad is a real-time collaborative editor for documents that matter.

Every keystroke is attributed to its author. Every revision is preserved. The timeslider lets you scrub through a document's entire history, character by character. Author colours make collaboration visible at a glance — not buried in a menu.

Etherpad runs on your server, under your governance. No telemetry. No upsells. AI is a plugin you install, pointed at the model you choose, running on infrastructure you control — not a feature decided for you in a boardroom you weren't in.

The code is Apache 2.0. The data format is open. It scales to thousands of simultaneous editors per pad. Translated into 105 languages. Extended through hundreds of plugins. Used by Wikimedia, governments, public-sector institutions, and self-hosters worldwide since 2009.

Full data export is built in. The history is yours.

Try it out

Try out a public Etherpad instance

Project Status

Etherpad has been doing the same thing — well — since 2009. No pivots, no acquisitions, no enshittification. Maintained by a small volunteer team.

We are actively looking for maintainers. If you have experience with Node.js, real-time systems, or institutional collaboration tooling and you want to work on infrastructure that thousands of organisations quietly depend on, please open an issue or contact John McLear.

Code Quality

Code Quality

Testing

Backend tests Simulated Load Rate Limit Docker file Frontend admin tests powered by Sauce Labs Frontend tests powered by Sauce Labs Sauce Test Status Windows Build

Engagement

Docker Pulls Discord Etherpad plugins Languages Translation Coverage

Who uses Etherpad

For more than a decade, Etherpad has quietly underpinned the documents that matter to:

  • Wikimedia Foundation — collaborative drafting across editor communities.
  • Public-sector institutions across the EU — including organisations that legally cannot use US-cloud SaaS for sovereignty and GDPR reasons.
  • Universities and schools worldwide — including jurisdictions where Google Workspace is no longer permitted in education.
  • Civic-tech and democratic-deliberation projects — citizen assemblies, participatory budgeting, public consultations.
  • Newsrooms and investigative journalism teams — where authorship and editing history matter for legal and editorial integrity.
  • Tens of thousands of self-hosted instances worldwide, run by IT teams who chose Etherpad because it is theirs.

If your organisation runs Etherpad and would be willing to be listed publicly, please add it to the wiki.

Installation

Quick install (one-liner)

The fastest way to get Etherpad running. Requires git and Node.js >= 22.

macOS / Linux / WSL:

curl -fsSL https://raw.githubusercontent.com/ether/etherpad/master/bin/installer.sh | sh

Windows (PowerShell):

irm https://raw.githubusercontent.com/ether/etherpad/master/bin/installer.ps1 | iex

Both installers clone Etherpad into ./etherpad-lite, install dependencies, and build the frontend. When the installer finishes, run:

cd etherpad-lite && pnpm run prod

Then open http://localhost:9001.

To install and start in one go:

# macOS / Linux / WSL
ETHERPAD_RUN=1 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ether/etherpad/master/bin/installer.sh)"
# Windows
$env:ETHERPAD_RUN=1; irm https://raw.githubusercontent.com/ether/etherpad/master/bin/installer.ps1 | iex

Docker-Compose

The official image is published to both Docker Hub (etherpad/etherpad) and GitHub Container Registry (ghcr.io/ether/etherpad) with identical tags. Use whichever suits your environment; GHCR avoids Docker Hub's anonymous pull rate limits.

services:
  app:
    user: "0:0"
    image: etherpad/etherpad:latest  # or: ghcr.io/ether/etherpad:latest
    tty: true
    stdin_open: true
    volumes:
      - plugins:/opt/etherpad-lite/src/plugin_packages
      - etherpad-var:/opt/etherpad-lite/var
    depends_on:
      - postgres
    environment:
      NODE_ENV: production
      ADMIN_PASSWORD: ${DOCKER_COMPOSE_APP_ADMIN_PASSWORD:-admin}
      DB_CHARSET: ${DOCKER_COMPOSE_APP_DB_CHARSET:-utf8mb4}
      DB_HOST: postgres
      DB_NAME: ${DOCKER_COMPOSE_POSTGRES_DATABASE:-etherpad}
      DB_PASS: ${DOCKER_COMPOSE_POSTGRES_PASSWORD:-admin}
      DB_PORT: ${DOCKER_COMPOSE_POSTGRES_PORT:-5432}
      DB_TYPE: "postgres"
      DB_USER: ${DOCKER_COMPOSE_POSTGRES_USER:-admin}
      # For now, the env var DEFAULT_PAD_TEXT cannot be unset or empty; it seems to be mandatory in the latest version of etherpad
      DEFAULT_PAD_TEXT: ${DOCKER_COMPOSE_APP_DEFAULT_PAD_TEXT:- }
      DISABLE_IP_LOGGING: ${DOCKER_COMPOSE_APP_DISABLE_IP_LOGGING:-false}
      SOFFICE: ${DOCKER_COMPOSE_APP_SOFFICE:-null}
      TRUST_PROXY: ${DOCKER_COMPOSE_APP_TRUST_PROXY:-true}
    restart: always
    ports:
      - "${DOCKER_COMPOSE_APP_PORT_PUBLISHED:-9001}:${DOCKER_COMPOSE_APP_PORT_TARGET:-9001}"

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: ${DOCKER_COMPOSE_POSTGRES_DATABASE:-etherpad}
      POSTGRES_PASSWORD: ${DOCKER_COMPOSE_POSTGRES_PASSWORD:-admin}
      POSTGRES_PORT: ${DOCKER_COMPOSE_POSTGRES_PORT:-5432}
      POSTGRES_USER: ${DOCKER_COMPOSE_POSTGRES_USER:-admin}
      PGDATA: /var/lib/postgresql/data/pgdata
    restart: always
    # Exposing the port is not needed unless you want to access this database instance from the host.
    # Be careful when other postgres docker container are running on the same port
    # ports:
    #   - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
  plugins:
  etherpad-var:

Requirements

Node.js >= 22.12.

Windows, macOS, Linux

  1. Download the latest Node.js runtime from nodejs.org.
  2. Install pnpm: npm install -g pnpm (Administrator privileges may be required).
  3. Clone the repository: git clone -b master
  4. Run pnpm i
  5. Run pnpm run build:etherpad
  6. Run pnpm run prod
  7. Visit http://localhost:9001 in your browser.

Docker container

Find here information on running Etherpad in a container.

Plugins

Etherpad is very customizable through plugins.

Basic install

Full Features

Available Plugins

For a list of available plugins, see the plugins site.

Plugin Installation

You can install plugins from the admin web interface (e.g., http://127.0.0.1:9001/admin/plugins).

Alternatively, you can install plugins from the command line:

cd /path/to/etherpad-lite
pnpm run plugins i ep_${plugin_name}

Also see the plugin wiki article.

Suggested Plugins

Run the following command in your Etherpad folder to get all of the features visible in the above demo gif:

pnpm run plugins i \
  ep_align \
  ep_comments_page \
  ep_embedded_hyperlinks2 \
  ep_font_color \
  ep_headings2 \
  ep_markdown \
  ep_webrtc

For user authentication, you are encouraged to run an OpenID Connect identity provider (OP) and install the following plugins:

  • ep_openid_connect to authenticate against your OP.
  • ep_guest to create a "guest" account that has limited access (e.g., read-only access).
  • ep_user_displayname to automatically populate each user's displayed name from your OP.
  • ep_stable_authorid so that each user's chosen color, display name, comment ownership, etc. is strongly linked to their account.

Upgrade Etherpad

Run the following command in your Etherpad folder to upgrade

  1. Stop any running Etherpad (manual, systemd ...)
  2. Get present version
git -P tag --contains
  1. List versions available
git -P tag --list "v*" --merged
  1. Select the version
git checkout v2.2.5
git switch -c v2.2.5
  1. Upgrade Etherpad
./bin/run.sh
  1. Stop with [CTRL-C]
  2. Restart your Etherpad service

Next Steps

Tweak the settings

You can modify the settings in settings.json. If you need to handle multiple settings files, you can pass the path to a settings file to bin/run.sh using the -s|--settings option: this allows you to run multiple Etherpad instances from the same installation. Similarly, --credentials can be used to give a settings override file, --apikey to give a different APIKEY.txt file and --sessionkey to give a non-default SESSIONKEY.txt. Each configuration parameter can also be set via an environment variable, using the syntax "${ENV_VAR}" or "${ENV_VAR:default_value}". For details, refer to settings.json.template. Once you have access to your /admin section, settings can be modified through the web browser.

If you are planning to use Etherpad in a production environment, you should use a dedicated database such as mysql, since the dirtyDB database driver is only for testing and/or development purposes.

Secure your installation

If you have enabled authentication in users section in settings.json, it is a good security practice to store hashes instead of plain text passwords in that file. This is especially advised if you are running a production installation.

Please install ep_hash_auth plugin and configure it. If you prefer, ep_hash_auth also gives you the option of storing the users in a custom directory in the file system, without having to edit settings.json and restart Etherpad each time.

Customize the style with skin variants

Open http://127.0.0.1:9001/p/test#skinvariantsbuilder in your browser and start playing!

Skin Variant

Helpful resources

The wiki is your one-stop resource for Tutorials and How-to's.

Documentation can be found in doc/.

Development

Things you should know

You can debug Etherpad using bin/debugRun.sh.

You can run Etherpad quickly launching bin/fastRun.sh. It's convenient for developers and advanced users. Be aware that it will skip the dependencies update, so remember to run bin/installDeps.sh after installing a new dependency or upgrading version.

If you want to find out how Etherpad's Easysync works (the library that makes it really realtime), start with this PDF (complex, but worth reading).

Contributing

Read our Developer Guidelines

HTTP API

Etherpad is designed to be easily embeddable and provides a HTTP API that allows your web application to manage pads, users and groups. It is recommended to use the available client implementations in order to interact with this API.

OpenAPI (previously swagger) definitions for the API are exposed under /api/openapi.json.

jQuery plugin

There is a jQuery plugin that helps you to embed Pads into your website.

Plugin Framework

Etherpad offers a plugin framework, allowing you to easily add your own features. By default your Etherpad is extremely light-weight and it's up to you to customize your experience. Once you have Etherpad installed you should visit the plugin page and take control.

Translations / Localizations (i18n / l10n)

Etherpad comes with translations into all languages thanks to the team at TranslateWiki.

If you require translations in plugins please send pull request to each plugin individually.

FAQ

Visit the FAQ.

Get in touch

The official channel for contacting the development team is via the GitHub issues.

For responsible disclosure of vulnerabilities, please write a mail to the maintainers (a.mux@inwind.it and contact@etherpad.org).

Join the official Etherpad Discord Channel.

License

Apache License v2