etherpad-lite/doc/database.md
John McLear 01d0b08a4e
docs: migrate useful wiki content into the manual (#7990) (#7994)
* 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>
2026-06-22 09:52:33 +01:00

204 lines
5.8 KiB
Markdown

# 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](https://www.npmjs.com/package/ueberdb2), 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:
```sql
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`:
```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:
```sql
CREATE USER etherpad WITH PASSWORD 'a-secure-password';
CREATE DATABASE etherpad OWNER etherpad;
```
Then configure `settings.json`:
```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:
```json
"dbType": "redis",
"dbSettings": {
"host": "localhost",
"port": 6379,
"password": "a-secure-redis-password"
}
```
```json
"dbType": "redis",
"dbSettings": {
"url": "redis://:a-secure-redis-password@localhost:6379"
}
```
## Migrating from MySQL to PostgreSQL
[pgloader](https://pgloader.io/) can copy an existing Etherpad database from
MySQL to PostgreSQL. Stop Etherpad first so the source database is quiescent.
```bash
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:
```sql
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](./cli.md).
:::