etherpad-lite/packaging
John McLear 9bdbb3ee95
fix(deb): bump nodejs Depends to >= 25; install Node 25 in smoke test (#7754)
Followup to #7752. That PR raised `src/package.json` engines.node to
>=25.0.0 (matching the workspace root) but missed three places that
still encoded the previous Node 22+ floor — so the deb-package CI
broke at sha 33b616b9:

  packaging/nfpm.yaml declared `Depends: nodejs (>= 22)`, so the deb
  installed cleanly on a Node 22-or-24 system. .github/workflows/
  deb-package.yml's smoke test then explicitly installed Node 24
  (`NODE_MAJOR=24`), `dpkg -i` succeeded, and `systemctl start
  etherpad` crashlooped with:

    [ERROR] settings - Running Etherpad on Node v24.15.0 is not
      supported. Please upgrade at least to Node 25.0.0

  (The misleading `ENOENT: ... lstat '/opt/etherpad/.git'` line above
  it is a benign WARN from getGitCommit(), wrapped in try/catch — not
  the cause.)

This commit aligns everything to Node 25:

- packaging/nfpm.yaml: `nodejs (>= 22)` → `nodejs (>= 25)` in the
  top-level `depends:` and the deb / rpm overrides (3 occurrences).
- .github/workflows/deb-package.yml: smoke-test `NODE_MAJOR=24` →
  `25`, comments updated to match.
- packaging/README.md: doc points users at `node_25.x` NodeSource
  apt repo (Node 25 isn't in most distro repos yet, so the
  `setup_lts.x` shortcut no longer suffices).
- packaging/bin/etherpad: comment about the apt declare updated to
  match.

No source code changes — Etherpad's own NodeVersion check already
reads engines.node from src/package.json and rejects anything older.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 11:57:27 +01:00
..
apt ci(packaging): publish signed apt repository to etherpad.org/apt (closes #7610) (#7624) 2026-04-29 00:20:00 +01:00
bin fix(deb): bump nodejs Depends to >= 25; install Node 25 in smoke test (#7754) 2026-05-15 11:57:27 +01:00
scripts feat(packaging): add Debian (.deb) build via nfpm with systemd unit (v2) (#7583) 2026-04-27 10:33:30 +01:00
systemd feat(packaging): add Debian (.deb) build via nfpm with systemd unit (v2) (#7583) 2026-04-27 10:33:30 +01:00
nfpm.yaml fix(deb): bump nodejs Depends to >= 25; install Node 25 in smoke test (#7754) 2026-05-15 11:57:27 +01:00
README.md fix(deb): bump nodejs Depends to >= 25; install Node 25 in smoke test (#7754) 2026-05-15 11:57:27 +01:00
test-local.sh feat(packaging): add Debian (.deb) build via nfpm with systemd unit (v2) (#7583) 2026-04-27 10:33:30 +01:00

Etherpad Debian / RPM packaging

Produces native .deb (and, with the same manifest, .rpm / .apk) packages for Etherpad using nfpm.

Layout

packaging/
  nfpm.yaml                # nfpm package manifest
  bin/etherpad             # /usr/bin launcher
  scripts/                 # preinst / postinst / prerm / postrm
  systemd/etherpad.service
  systemd/etherpad.default
  etc/settings.json.dist   # populated in CI from settings.json.template

Built artefacts land in ./dist/.

Building locally

Prereqs: Node 24 (current LTS; engines.node floor is 20), pnpm 10+, nfpm.

pnpm install --frozen-lockfile
pnpm run build:etherpad

# Stage the tree the way CI does:
STAGE=staging/opt/etherpad
mkdir -p "$STAGE"
cp -a src bin package.json pnpm-workspace.yaml README.md LICENSE \
      node_modules "$STAGE/"
printf 'packages:\n  - src\n  - bin\n' > "$STAGE/pnpm-workspace.yaml"
cp settings.json.template packaging/etc/settings.json.dist

VERSION=$(node -p "require('./package.json').version") \
ARCH=amd64 \
    nfpm package --packager deb -f packaging/nfpm.yaml --target dist/

End-to-end test (Docker, no real systemd needed)

packaging/test-local.sh builds the .deb and runs the same smoke test the CI workflow does, inside a throwaway systemd-enabled container:

packaging/test-local.sh                # build + smoke + purge
packaging/test-local.sh --shell        # leave the container up so you can poke around
packaging/test-local.sh --build-only   # just produce dist/*.deb

This is the fastest way to validate that the systemd hardening, plugin path symlinks, and tsx wrapper actually work together before pushing.

The release workflow publishes a signed apt repository at https://etherpad.org/apt/ on every tagged release. Three lines on any Debian/Ubuntu/Mint:

curl -fsSL https://etherpad.org/key.asc \
  | sudo gpg --dearmor -o /usr/share/keyrings/etherpad.gpg
echo "deb [signed-by=/usr/share/keyrings/etherpad.gpg] https://etherpad.org/apt stable main" \
  | sudo tee /etc/apt/sources.list.d/etherpad.list
sudo apt update && sudo apt install etherpad

apt upgrade works going forward. Repo metadata is signed with the GPG keypair documented in packaging/apt/key.asc (long key id AF0CD687D51A6E63).

Installing a single .deb directly

The release page publishes both versioned and stable filenames per arch:

# Stable URL — always points at the most recent release:
curl -fsSL -o etherpad-latest_amd64.deb \
  https://github.com/ether/etherpad/releases/latest/download/etherpad-latest_amd64.deb
sudo apt install ./etherpad-latest_amd64.deb

# Or pin to a specific version:
sudo apt install ./dist/etherpad_<version>_amd64.deb

sudo systemctl start etherpad
curl http://localhost:9001/health

apt will pull in nodejs (>= 25) (matches Etherpad's engines.node). Most distro repos don't yet ship Node.js 25, so on most systems you will need to add NodeSource's node_25.x apt repo before apt install:

KEYRING=/usr/share/keyrings/nodesource.gpg
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
  | sudo gpg --dearmor --yes -o "${KEYRING}"
echo "deb [signed-by=${KEYRING}] https://deb.nodesource.com/node_25.x nodistro main" \
  | sudo tee /etc/apt/sources.list.d/nodesource.list
sudo apt-get update

Configuration

  • Edit /etc/etherpad/settings.json, then sudo systemctl restart etherpad.
  • Environment overrides: /etc/default/etherpad.
  • Logs: journalctl -u etherpad -f.
  • Data (sqlite default): /var/lib/etherpad/etherpad.db.

The shipped settings template defaults to dbType: "dirty", which the template itself warns is for testing only. postinstall rewrites the seeded /etc/etherpad/settings.json to sqlite and points it at /var/lib/etherpad/etherpad.db so fresh installs get an ACID-safe DB out of the box. Existing /etc/etherpad/settings.json is never touched on upgrade.

Upgrading

dpkg --install etherpad_<new>.deb (or apt install) replaces the app tree under /opt/etherpad while preserving /etc/etherpad/* and /var/lib/etherpad/*. The service is restarted automatically.

Removing

  • sudo apt remove etherpad — keeps config and data.
  • sudo apt purge etherpad — also removes config, data, and the etherpad system user.

Publishing to an APT repository (follow-up)

Out of scope here — requires credentials and ownership decisions. Recipes once a repo is picked:

  • Cloudsmith (easiest, free OSS tier): cloudsmith push deb ether/etherpad/any-distro/any-version dist/*.deb
  • Launchpad PPA: requires signed source packages (a debian/ tree), which nfpm does not produce — use debuild separately.
  • Self-hosted reprepro: reprepro -b /srv/apt includedeb stable dist/*.deb

Wire the chosen option into .github/workflows/deb-package.yml after the release job.