* docs: migrate useful wiki content into the VitePress manual (#7990) The GitHub wiki is being retired; documentation should ship with the software. This migrates the still-accurate, non-duplicate wiki pages into the published VitePress site (doc/**/*.md + the sidebar in doc/.vitepress/config.mts) so they are versioned, searchable and portable: - deployment.md: reverse-proxy configs (Nginx/Apache/Caddy/Traefik/ HAProxy) with the WebSocket-upgrade rules, subdirectory hosting via X-Proxy-Path, native HTTPS via the ssl block, a systemd unit, and the Istio manifest (with the Redis-adapter multi-replica caveat). - accessibility.md: editor keyboard shortcuts (verified against ace2_inner.ts / broadcast_slider.ts / pad_editbar.ts), toolbar navigation, NVDA notes. - faq.md: install methods, URL-path reference, listing/deleting pads (API-first), backup/restore, and history pruning. - development.md: source-tree tour, the pad<->format conversion pipeline, the internal DB API, and the Fontello toolbar-icon workflow. - database.md: the key/value schema plus connecting MySQL/PostgreSQL/Redis backends and a pgloader MySQL->PostgreSQL migration (database docs were previously absent from the VitePress site). Every page was checked against the current source before inclusion: corrected the apt instructions to the live signed repo (stable/main, signed-by key), dropped the unpublished snap, fixed the Redis dbSettings (flat host/port/password or url, not the obsolete client_options), dropped charset from the PostgreSQL example, and removed a phantom getEtherpad API reference. The VitePress site builds cleanly (pnpm run docs:build) with the dead-link checker enabled. Closes #7990 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: add verified hands-on changeset/atext walkthrough (#7990) Migrate the practical Changeset-library tutorial from the wiki into changeset_library.md, rewritten against the current API: unpack(), deserializeOps() (replacing the deprecated opIterator) and new AttributePool() (replacing the removed AttributePoolFactory). Every example output was produced by running the code against the current Changeset.ts / AttributePool.ts, not copied from the wiki. Also fixes a stale ether/etherpad-lite source link. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.8 KiB
Database structure
Keys and their values
groups
A list of all existing groups (a JSON object with groupIDs as keys and 1 as values).
pad:$PADID
Contains all information about pads
- atext - the latest attributed text
- pool - the attribute pool
- head - the number of the latest revision
- chatHead - the number of the latest chat entry
- public - flag that disables security for this pad
- passwordHash - string that contains a salted sha512 sum of this pad's password
pad:$PADID:revs:$REVNUM
Saves a revision $REVNUM of pad $PADID
- meta
- author - the autorID of this revision
- timestamp - the timestamp of when this revision was created
- changeset - the changeset of this revision
pad:$PADID:chat:$CHATNUM
Saves a chat entry with num $CHATNUM of pad $PADID
- text - the text of this chat entry
- userId - the authorID of this chat entry
- time - the timestamp of this chat entry
pad2readonly:$PADID
Translates a padID to a readonlyID
readonly2pad:$READONLYID
Translates a readonlyID to a padID
token2author:$TOKENID
Translates a token to an authorID
globalAuthor:$AUTHORID
Information about an author
- name - the name of this author as shown in the pad
- colorID - the colorID of this author as shown in the pad
mapper2group:$MAPPER
Maps an external application identifier to an internal group
mapper2author:$MAPPER
Maps an external application identifier to an internal author
group:$GROUPID
a group of pads
- pads - object with pad names in it, values are 1
session:$SESSIONID
a session between an author and a group
- groupID - the groupID the session belongs too
- authorID - the authorID the session belongs too
- validUntil - the timestamp until this session is valid
author2sessions:$AUTHORID
saves the sessions of an author
- sessionsIDs - object with sessionIDs in it, values are 1
group2sessions:$GROUPID
- sessionsIDs - object with sessionIDs in it, values are 1
Connecting to a database backend
Etherpad stores everything in a single key/value table through
ueberDB, so the same data model works
across many backends. The backend is selected with dbType in settings.json,
and backend-specific connection options go in dbSettings.
The default dirty backend writes to a local file (var/dirty.db) and needs no
setup, which is convenient for development but not recommended for production.
For a production instance, point Etherpad at a real database such as MySQL/MariaDB,
PostgreSQL or Redis. Etherpad creates its own table on first run; you only need
to provision an empty database and a user with access to it.
MySQL / MariaDB
Create the database and a user, then grant access:
CREATE DATABASE `etherpad` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE USER 'etherpad'@'localhost' IDENTIFIED BY 'a-secure-password';
GRANT CREATE,ALTER,SELECT,INSERT,UPDATE,DELETE ON `etherpad`.* TO 'etherpad'@'localhost';
Then configure settings.json:
"dbType": "mysql",
"dbSettings": {
"user": "etherpad",
"host": "localhost",
"port": 3306,
"password": "a-secure-password",
"database": "etherpad",
"charset": "utf8mb4"
}
Setting charset to utf8mb4 is strongly recommended so that the full range of
Unicode (including emoji) is stored correctly. To connect over a local socket
instead of TCP, replace host/port with "socketPath": "/var/run/mysqld/mysqld.sock".
PostgreSQL
Create the user and a database owned by it:
CREATE USER etherpad WITH PASSWORD 'a-secure-password';
CREATE DATABASE etherpad OWNER etherpad;
Then configure settings.json:
"dbType": "postgres",
"dbSettings": {
"user": "etherpad",
"host": "localhost",
"port": 5432,
"password": "a-secure-password",
"database": "etherpad"
}
The dbSettings object is passed straight to the node-postgres connection
pool, so any option it accepts (including a single "connectionString") works.
On Debian/Ubuntu you can use peer authentication over the local socket by
setting "host": "/var/run/postgresql" and an empty password, provided the
operating-system user that runs Etherpad matches the PostgreSQL role.
Redis
Install Redis and make sure it persists data to disk. Configure settings.json
with either discrete fields or a single connection URL:
"dbType": "redis",
"dbSettings": {
"host": "localhost",
"port": 6379,
"password": "a-secure-redis-password"
}
"dbType": "redis",
"dbSettings": {
"url": "redis://:a-secure-redis-password@localhost:6379"
}
Migrating from MySQL to PostgreSQL
pgloader can copy an existing Etherpad database from MySQL to PostgreSQL. Stop Etherpad first so the source database is quiescent.
sudo apt-get install postgresql pgloader
# Create the target role and database
sudo -u postgres createuser etherpad
sudo -u postgres createdb -O etherpad etherpad
# Describe and run the migration
cat > pgloader.load <<'EOF'
LOAD DATABASE
FROM mysql://etherpad:MYSQL_PASSWORD@127.0.0.1/etherpad
INTO postgresql:///etherpad
WITH preserve index names, prefetch rows = 100
ALTER SCHEMA 'etherpad' RENAME TO 'public';
EOF
pgloader --verbose pgloader.load
Afterwards set the PostgreSQL user's password and make sure it can read and write the migrated table:
ALTER USER etherpad WITH PASSWORD 'a-secure-password';
GRANT pg_read_all_data TO etherpad;
GRANT pg_write_all_data TO etherpad;
Then point settings.json at PostgreSQL as shown above and start Etherpad.
::: tip
To move data between any two backends supported by ueberDB, you can also
use the migrateDB CLI tool, which reads every record from a source database
descriptor and writes it to a target one. See the CLI chapter.
:::