diff --git a/.github/workflows/deb-package.yml b/.github/workflows/deb-package.yml deleted file mode 100644 index 81f64f61eaf..00000000000 --- a/.github/workflows/deb-package.yml +++ /dev/null @@ -1,161 +0,0 @@ -name: Debian package -on: - push: - tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-*' - workflow_dispatch: - inputs: - ref: - description: 'Git ref to package (defaults to current)' - required: false - -permissions: - contents: write # attach release assets - -env: - NFPM_VERSION: v2.43.0 - -jobs: - build: - name: Build .deb (${{ matrix.arch }}) - runs-on: ${{ matrix.runner }} - strategy: - fail-fast: false - matrix: - include: - - arch: amd64 - runner: ubuntu-latest - - arch: arm64 - runner: ubuntu-24.04-arm - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.ref || github.ref }} - - - name: Resolve version - id: v - run: | - if [ "${GITHUB_REF_TYPE}" = "tag" ]; then - VERSION="${GITHUB_REF_NAME#v}" - else - VERSION="$(node -p "require('./package.json').version")" - fi - echo "version=${VERSION}" >>"$GITHUB_OUTPUT" - echo "Packaging version: ${VERSION}" - - - uses: pnpm/action-setup@v6 - with: - version: 10 - - - name: Setup Node - uses: actions/setup-node@v6 - with: - node-version: '22' - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build UI + admin - run: pnpm run build:etherpad - - - name: Install nfpm - run: | - set -e - NFPM_ARCH=amd64 - [ "${{ matrix.arch }}" = "arm64" ] && NFPM_ARCH=arm64 - curl -fsSL -o /tmp/nfpm.deb \ - "https://github.com/goreleaser/nfpm/releases/download/${NFPM_VERSION}/nfpm_${NFPM_VERSION#v}_${NFPM_ARCH}.deb" - sudo dpkg -i /tmp/nfpm.deb - - - name: Stage tree for packaging - run: | - set -eux - STAGE=staging/opt/etherpad-lite - mkdir -p "${STAGE}" - - # Production footprint = src/ + bin/ + node_modules/ + metadata. - cp -a src bin package.json pnpm-workspace.yaml README.md LICENSE \ - node_modules "${STAGE}/" - - # Make pnpm-workspace.yaml production-only (same trick Dockerfile uses). - printf 'packages:\n - src\n - bin\n' > "${STAGE}/pnpm-workspace.yaml" - - mkdir -p packaging/etc - cp settings.json.template packaging/etc/settings.json.dist - - # Purge test fixtures and dev caches from node_modules to shrink size. - find "${STAGE}/node_modules" -type d \ - \( -name test -o -name tests -o -name '__tests__' \ - -o -name example -o -name examples -o -name docs \) \ - -prune -exec rm -rf {} + 2>/dev/null || true - find "${STAGE}/node_modules" -type f \ - \( -name '*.md' -o -name '*.ts.map' -o -name '*.map' \ - -o -name 'CHANGELOG*' -o -name 'HISTORY*' \) \ - -delete 2>/dev/null || true - - - name: Build .deb - env: - VERSION: ${{ steps.v.outputs.version }} - ARCH: ${{ matrix.arch }} - run: | - mkdir -p dist - nfpm package --packager deb -f packaging/nfpm.yaml --target dist/ - - - name: Smoke-test the package (amd64 only) - if: matrix.arch == 'amd64' - run: | - set -eux - sudo apt-get update - sudo apt-get install -y nodejs - sudo dpkg -i dist/*.deb || sudo apt-get install -f -y - test -x /usr/bin/etherpad-lite - test -f /etc/etherpad-lite/settings.json - test -L /opt/etherpad-lite/settings.json - id etherpad - systemctl cat etherpad-lite.service - sudo systemctl start etherpad-lite - ok= - for i in $(seq 1 30); do - if curl -fsS http://127.0.0.1:9001/health; then - ok=1 - break - fi - sleep 2 - done - if [ -z "${ok}" ]; then - # Attach logs so the failing run is diagnosable. - sudo journalctl -u etherpad-lite --no-pager -n 200 || true - exit 1 - fi - sudo systemctl stop etherpad-lite - sudo dpkg --purge etherpad-lite - ! id etherpad 2>/dev/null - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: etherpad-lite-${{ steps.v.outputs.version }}-${{ matrix.arch }}-deb - path: dist/*.deb - if-no-files-found: error - - release: - name: Attach to GitHub Release - needs: build - if: startsWith(github.ref, 'refs/tags/v') - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/download-artifact@v4 - with: - path: dist - pattern: etherpad-lite-*-deb - merge-multiple: true - - name: Attach .deb files to release - uses: softprops/action-gh-release@v2 - with: - files: dist/*.deb - fail_on_unmatched_files: true diff --git a/packaging/README.md b/packaging/README.md deleted file mode 100644 index 20b5b5f7beb..00000000000 --- a/packaging/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# Etherpad Debian / RPM packaging - -Produces native `.deb` (and, with the same manifest, `.rpm` / `.apk`) -packages for Etherpad using [nfpm](https://nfpm.goreleaser.com). - -## Layout - -``` -packaging/ - nfpm.yaml # nfpm package manifest - bin/etherpad-lite # /usr/bin launcher - scripts/ # preinst / postinst / prerm / postrm - systemd/etherpad-lite.service - systemd/etherpad-lite.default - etc/settings.json.dist # populated in CI from settings.json.template -``` - -Built artefacts land in `./dist/`. - -## Building locally - -Prereqs: Node 22, pnpm 10+, nfpm. - -```sh -pnpm install --frozen-lockfile -pnpm run build:etherpad - -# Stage the tree the way CI does: -STAGE=staging/opt/etherpad-lite -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/ -``` - -## Installing - -```sh -sudo apt install ./dist/etherpad-lite_2.6.1_amd64.deb -sudo systemctl start etherpad-lite -curl http://localhost:9001/health -``` - -`apt` will pull in `nodejs (>= 20)`; on Ubuntu 22.04 add NodeSource first: - -```sh -curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - -``` - -## Configuration - -- Edit `/etc/etherpad-lite/settings.json`, then - `sudo systemctl restart etherpad-lite`. -- Environment overrides: `/etc/default/etherpad-lite`. -- Logs: `journalctl -u etherpad-lite -f`. -- Data (dirty-DB default): `/var/lib/etherpad-lite/`. - -## Upgrading - -`dpkg --install etherpad-lite_.deb` (or `apt install`) replaces the -app tree under `/opt/etherpad-lite` while preserving -`/etc/etherpad-lite/*` and `/var/lib/etherpad-lite/*`. The service is -restarted automatically. - -## Removing - -- `sudo apt remove etherpad-lite` — keeps config and data. -- `sudo apt purge etherpad-lite` — 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-lite/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. diff --git a/packaging/bin/etherpad-lite b/packaging/bin/etherpad-lite deleted file mode 100755 index 20143154ef8..00000000000 --- a/packaging/bin/etherpad-lite +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -# /usr/bin/etherpad-lite - thin wrapper that runs Etherpad in production mode. -# Invoked by the etherpad-lite.service systemd unit. -set -e - -APP_DIR="${ETHERPAD_DIR:-/opt/etherpad-lite}" -cd "${APP_DIR}" - -: "${NODE_ENV:=production}" -export NODE_ENV -export ETHERPAD_PRODUCTION=true - -# Run the server through tsx's ESM loader (shipped in node_modules). -# No pnpm needed at runtime. -exec node \ - --import "file://${APP_DIR}/src/node_modules/tsx/dist/esm/index.mjs" \ - "${APP_DIR}/src/node/server.ts" \ - "$@" diff --git a/packaging/nfpm.yaml b/packaging/nfpm.yaml deleted file mode 100644 index eaf8ffce8c9..00000000000 --- a/packaging/nfpm.yaml +++ /dev/null @@ -1,117 +0,0 @@ -# nfpm configuration for etherpad-lite Debian/RPM/APK packages. -# Build with: nfpm package --packager deb --target dist/ -# See: https://nfpm.goreleaser.com/configuration/ - -name: etherpad-lite -arch: ${ARCH} # amd64 | arm64 (exported by CI) -platform: linux -version: ${VERSION} # e.g. 2.6.1, stripped of leading "v" -version_schema: semver -release: "1" -section: web -priority: optional -maintainer: "Etherpad Foundation " -description: | - Etherpad is a real-time collaborative editor for the web. - This package installs Etherpad as a systemd service running - from /opt/etherpad-lite with configuration in /etc/etherpad-lite. -vendor: "Etherpad Foundation" -homepage: https://etherpad.org -license: Apache-2.0 - -depends: - - nodejs (>= 20) - - adduser - - ca-certificates - -recommends: - - libreoffice # enables DOC/DOCX/PDF/ODT export - - curl - -suggests: - - postgresql-client - - mariadb-client - -conflicts: - - etherpad # legacy bin/buildDebian.sh package name - -replaces: - - etherpad - -provides: - - etherpad - -# --------------------------------------------------------------------------- -# Contents. staging/ is populated by CI before invoking nfpm: -# staging/opt/etherpad-lite/ -- source + node_modules + built assets -# --------------------------------------------------------------------------- -contents: - - src: ./staging/opt/etherpad-lite - dst: /opt/etherpad-lite - type: tree - file_info: - mode: 0755 - owner: root - group: root - - - src: ./packaging/systemd/etherpad-lite.service - dst: /lib/systemd/system/etherpad-lite.service - file_info: - mode: 0644 - - # Default environment file (conffile: preserved on upgrade). - # Mode 0640 + group=etherpad so passwords/secrets admins drop in here - # are only readable by root and the etherpad service user — /etc/default - # is world-readable by default (0644), which would leak DB creds etc. - - src: ./packaging/systemd/etherpad-lite.default - dst: /etc/default/etherpad-lite - type: config|noreplace - file_info: - mode: 0640 - owner: root - group: etherpad - - - src: ./packaging/bin/etherpad-lite - dst: /usr/bin/etherpad-lite - file_info: - mode: 0755 - - # Template used by postinstall to seed /etc/etherpad-lite/settings.json. - # Intentionally NOT a conffile: postinstall creates the real settings.json - # once on first install and never touches it again, so upgrades don't - # prompt with dpkg merge dialogs. - - src: ./packaging/etc/settings.json.dist - dst: /usr/share/etherpad-lite/settings.json.dist - file_info: - mode: 0644 - - - dst: /etc/etherpad-lite - type: dir - file_info: - mode: 0755 - - dst: /var/lib/etherpad-lite - type: dir - file_info: - mode: 0750 - - dst: /var/log/etherpad-lite - type: dir - file_info: - mode: 0750 - -scripts: - preinstall: ./packaging/scripts/preinstall.sh - postinstall: ./packaging/scripts/postinstall.sh - preremove: ./packaging/scripts/preremove.sh - postremove: ./packaging/scripts/postremove.sh - -overrides: - deb: - depends: - - nodejs (>= 20) - - adduser - - ca-certificates - rpm: - depends: - - nodejs >= 20 - - shadow-utils - - ca-certificates diff --git a/packaging/scripts/postinstall.sh b/packaging/scripts/postinstall.sh deleted file mode 100755 index 9ae2d122b2c..00000000000 --- a/packaging/scripts/postinstall.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/sh -# postinstall - runs after files have been unpacked. -# Debian actions: configure | abort-upgrade | abort-remove | abort-deconfigure -set -e - -ETC_DIR=/etc/etherpad-lite -VAR_DIR=/var/lib/etherpad-lite -LOG_DIR=/var/log/etherpad-lite -APP_DIR=/opt/etherpad-lite -DIST_SETTINGS=/usr/share/etherpad-lite/settings.json.dist -ACTIVE_SETTINGS="${ETC_DIR}/settings.json" - -case "$1" in - configure) - mkdir -p "${ETC_DIR}" "${VAR_DIR}" "${LOG_DIR}" - chown root:etherpad "${ETC_DIR}" - chmod 0750 "${ETC_DIR}" - chown etherpad:etherpad "${VAR_DIR}" "${LOG_DIR}" - chmod 0750 "${VAR_DIR}" "${LOG_DIR}" - - if [ ! -e "${ACTIVE_SETTINGS}" ]; then - cp "${DIST_SETTINGS}" "${ACTIVE_SETTINGS}" - # Point the default dirty-DB at /var/lib so ProtectSystem=strict works. - sed -i \ - 's|"filename": "var/dirty.db"|"filename": "/var/lib/etherpad-lite/dirty.db"|' \ - "${ACTIVE_SETTINGS}" - chown root:etherpad "${ACTIVE_SETTINGS}" - chmod 0640 "${ACTIVE_SETTINGS}" - fi - - # Etherpad reads settings.json from CWD (/opt/etherpad-lite). Expose - # the /etc copy there via symlink. - ln -sfn "${ACTIVE_SETTINGS}" "${APP_DIR}/settings.json" - - if [ -d "${APP_DIR}/var" ]; then - chown -R etherpad:etherpad "${APP_DIR}/var" || true - fi - - if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then - systemctl daemon-reload || true - # Enable on first install; leave state alone on upgrade. - if [ -z "$2" ]; then - systemctl enable etherpad-lite.service >/dev/null 2>&1 || true - fi - # Restart on upgrade to pick up new code (skip on fresh install -- - # admin may want to configure first). - if [ -n "$2" ]; then - systemctl try-restart etherpad-lite.service >/dev/null 2>&1 || true - fi - fi - - cat <&2 - exit 1 - ;; -esac - -exit 0 diff --git a/packaging/scripts/postremove.sh b/packaging/scripts/postremove.sh deleted file mode 100755 index b9ed40808d6..00000000000 --- a/packaging/scripts/postremove.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# postremove - runs after files are removed. -# Debian actions: remove | purge | upgrade | failed-upgrade | abort-install | -# abort-upgrade | disappear -set -e - -APP_DIR=/opt/etherpad-lite - -case "$1" in - remove) - [ -L "${APP_DIR}/settings.json" ] && rm -f "${APP_DIR}/settings.json" || true - if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then - systemctl daemon-reload || true - fi - ;; - - purge) - rm -rf /etc/etherpad-lite - rm -rf /var/lib/etherpad-lite - rm -rf /var/log/etherpad-lite - - if getent passwd etherpad >/dev/null 2>&1; then - deluser --system etherpad >/dev/null 2>&1 || true - fi - if getent group etherpad >/dev/null 2>&1; then - delgroup --system etherpad >/dev/null 2>&1 || true - fi - - if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then - systemctl daemon-reload || true - fi - ;; - - upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) - ;; - - *) - echo "postremove called with unknown argument: $1" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/packaging/scripts/preinstall.sh b/packaging/scripts/preinstall.sh deleted file mode 100755 index d85c69054d9..00000000000 --- a/packaging/scripts/preinstall.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# preinstall - runs before files are unpacked. -# Debian actions: install | upgrade | abort-upgrade -set -e - -case "$1" in - install|upgrade) - if ! getent group etherpad >/dev/null 2>&1; then - addgroup --system etherpad - fi - if ! getent passwd etherpad >/dev/null 2>&1; then - adduser --system --ingroup etherpad \ - --home /var/lib/etherpad-lite \ - --no-create-home \ - --shell /usr/sbin/nologin \ - --gecos "Etherpad service user" \ - etherpad - fi - ;; - abort-upgrade) - ;; - *) - echo "preinstall called with unknown argument: $1" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/packaging/scripts/preremove.sh b/packaging/scripts/preremove.sh deleted file mode 100755 index 851fbb8b864..00000000000 --- a/packaging/scripts/preremove.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -# preremove - runs before files are removed. -# Debian actions: remove | upgrade | deconfigure | failed-upgrade -set -e - -case "$1" in - remove|upgrade|deconfigure) - if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then - systemctl stop etherpad-lite.service >/dev/null 2>&1 || true - fi - ;; - failed-upgrade) - ;; - *) - echo "preremove called with unknown argument: $1" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/packaging/systemd/etherpad-lite.default b/packaging/systemd/etherpad-lite.default deleted file mode 100644 index 3ad92b0cd44..00000000000 --- a/packaging/systemd/etherpad-lite.default +++ /dev/null @@ -1,7 +0,0 @@ -# /etc/default/etherpad-lite -# Environment overrides for the etherpad-lite systemd service. -# Any variable referenced by ${VAR:default} in settings.json can be set here. - -NODE_ENV=production -# PORT=9001 -# NODE_OPTIONS=--max-old-space-size=2048 diff --git a/packaging/systemd/etherpad-lite.service b/packaging/systemd/etherpad-lite.service deleted file mode 100644 index f13d7d6c6ca..00000000000 --- a/packaging/systemd/etherpad-lite.service +++ /dev/null @@ -1,48 +0,0 @@ -[Unit] -Description=Etherpad - real-time collaborative editor -Documentation=https://etherpad.org https://github.com/ether/etherpad-lite -After=network-online.target -Wants=network-online.target - -[Service] -Type=simple -User=etherpad -Group=etherpad -WorkingDirectory=/opt/etherpad-lite -EnvironmentFile=-/etc/default/etherpad-lite -ExecStart=/usr/bin/etherpad-lite -Restart=on-failure -RestartSec=5s -TimeoutStopSec=20s - -StandardOutput=journal -StandardError=journal -SyslogIdentifier=etherpad-lite - -# --- Sandboxing --------------------------------------------------------- -NoNewPrivileges=true -ProtectSystem=strict -ProtectHome=true -PrivateTmp=true -PrivateDevices=true -ProtectKernelTunables=true -ProtectKernelModules=true -ProtectKernelLogs=true -ProtectControlGroups=true -ProtectHostname=true -ProtectClock=true -RestrictRealtime=true -RestrictSUIDSGID=true -RestrictNamespaces=true -LockPersonality=true -MemoryDenyWriteExecute=false # Node's JIT needs W+X mappings -SystemCallArchitectures=native -RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK -UMask=0027 - -ReadWritePaths=/var/lib/etherpad-lite /var/log/etherpad-lite /etc/etherpad-lite - -LimitNOFILE=65536 - -[Install] -WantedBy=multi-user.target