2026-07-20 15:59:15 +02:00
2026-07-25 21:05:27 +02:00
2026-07-23 13:47:17 +02:00
2026-07-25 22:13:53 +02:00
2026-07-24 15:30:53 +02:00
2026-07-26 09:36:23 +02:00
2026-07-26 15:59:23 +02:00
2026-07-24 15:30:53 +02:00
2026-07-25 22:13:53 +02:00
2026-07-24 15:30:53 +02:00
2026-07-26 15:59:23 +02:00
2026-07-26 15:59:23 +02:00
2026-07-24 11:22:44 +02:00
2026-07-25 22:17:16 +02:00
2026-07-20 20:49:18 +02:00
2026-07-20 15:59:15 +02:00
2026-07-25 22:13:53 +02:00

RustPad

RustPad is a collaborative Markdown editor with standalone notes and workspaces.

Development setup

./dev.sh

The script creates data/db and data/files, builds the project, and starts it with Cargo. If Cargo is unavailable, it runs docker compose up --build instead.

Workspace features

  • Real-time collaborative editing over WebSocket.
  • Nicknames stored in localStorage.
  • Change authors shown in history.
  • Line numbering enabled by default, with a persistent toggle.
  • Owner color displayed next to each line.
  • Image and file uploads to data/files/pads/<id>_<token>/ or data/files/notes/<id>_<token>/.
  • Automatic Markdown link insertion after upload.
  • Markdown and Mermaid diagram rendering.
  • History with snippets, previews, and version restore.
  • Alert blocks: success, info, warning, and danger.
  • Table of contents generated with [TOC].
  • Optional line numbers in fenced code blocks.

Fenced code blocks and language aliases

RustPad recognizes common language names and aliases, including:

  • JavaScript: js, javascript, jsx
  • TypeScript: ts, typescript, tsx
  • Python: py, python
  • PHP: php
  • Rust: rs, rust
  • Shell: sh, shell, bash, zsh
  • C and C++: c, h, cpp, c++, cxx, hpp
  • C#: cs, c#, csharp
  • Java, Kotlin, Go, Swift, Dart, Scala
  • HTML, XML, SVG, CSS, SCSS, Sass, Less
  • JSON, YAML, TOML, INI, SQL, GraphQL
  • Markdown, Dockerfile, Makefile, PowerShell
  • Lua, Perl, R, MATLAB, Nginx, Apache, Diff, and plain text

Standard code block:

```python
print("Hello")
```

Code block with line numbers starting from line 1:

```python=
print("Hello")
```

Code block with line numbers starting from a custom value:

```python=101
print("Hello")
```

The =number suffix is a RustPad extension and may not be supported by other Markdown renderers.

Data

  • SQLite database: data/db/rustpad.db
  • Attachments: data/files/pads/<id>_<token>/ and data/files/notes/<id>_<token>/
  • Public attachment URL: /f/<token>/<filename>

In Docker, both directories are located under /data.

Publishing a note as a page

Use the Page button in the editor. RustPad creates a permanent public /s/<token> URL, copies it to the clipboard, and opens it in a new tab. The page displays the current note and renders Markdown, images, links, and Mermaid diagrams.

Publishing a protected note requires its password, but the generated public page itself is accessible without that password.

Upload limit

Configure the maximum size of a single uploaded file with UPLOAD_MAX_SIZE_MB in .env, for example:

UPLOAD_MAX_SIZE_MB=50

The default limit is 20 MB. Restart the project with ./dev.sh after changing it.

Database selection

RustPad selects the database engine through DATABASE_URL:

  • SQLite: sqlite:///data/db/rustpad.db?mode=rwc&journal_mode=WAL&busy_timeout=5000
  • PostgreSQL: postgres://rustpad:rustpad@postgres:5432/rustpad
  • MySQL: mysql://rustpad:rustpad@mysql:3306/rustpad

SQLite remains the default for development and small installations. WAL mode allows reads during writes, but SQLite still performs only one write at a time. busy_timeout=5000 waits briefly instead of immediately returning a database is locked error. PostgreSQL or MySQL is recommended for many concurrent editors or multiple application instances.

Optional databases in Docker Compose:

# PostgreSQL
docker compose --profile postgres up -d postgres
DATABASE_URL=postgres://rustpad:rustpad@postgres:5432/rustpad docker compose up -d rustpad

# MySQL
docker compose --profile mysql up -d mysql
DATABASE_URL=mysql://rustpad:rustpad@mysql:3306/rustpad docker compose up -d rustpad

Migrations are stored in migrations/sqlite, migrations/postgres, and migrations/mysql. Runtime SQL statements are centralized in src/queries.rs, while src/database.rs selects the driver and configures the connection.

Optional user accounts and password reset

Nicknames can be used anonymously while they remain unregistered. Registering a nickname reserves it and requires a valid login session before it can be used in editor WebSocket connections.

Configure PUBLIC_URL, SMTP_HOST, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, and SMTP_FROM to enable password-reset emails. Reset links expire after 30 minutes and can be used only once.

Diagnostics and logging

Server logs use tracing. Configure verbosity with RUST_LOG, for example:

RUST_LOG=rustpad=debug,tower_http=info

Important lifecycle, database, authentication, password-reset, and WebSocket events are logged. Passwords, session tokens, reset tokens, SMTP credentials, and authorization headers are never logged.

Browser diagnostics are configured separately with FRONTEND_LOG_LEVEL. Supported values are off, error, warn, info, and debug; the default is warn. URL parameters cannot enable diagnostics. Use debug only in trusted development environments. Production should normally use warn or error.

Registration and SMTP

Set REGISTRATION_ENABLED=true to enable registration. After an account is created, the application sends an SMTP message containing the nickname and PUBLIC_URL.

Set ACCOUNT_CONFIRMATION_REQUIRED=true to require users to click a confirmation link before signing in. This option is disabled by default and requires SMTP configuration.

Attachment storage

RustPad supports two interchangeable attachment backends selected in .env:

  • STORAGE_DRIVER=local stores files under FILES_DIR and is the default.
  • STORAGE_DRIVER=s3 uses an S3-compatible service such as AWS S3, Garage, Ceph RGW, OpenStack, or MinIO.

Public application URLs remain /f/{token}/{filename} for both backends. RustPad validates access and streams objects through the API, so the bucket does not need to be public and existing database records do not require migration.

For the optional Docker Garage service, configure the S3 variables shown in .env.example, use strong unique credentials, and run:

docker compose --profile s3 up -d --build

Garage runs as a separate Compose service. Existing PostgreSQL and MySQL profiles remain unchanged. The included single-node setup is intended for local or self-hosted development without redundancy. Production Garage deployments should use a properly designed multi-node configuration.

Authentication: local, LDAP, LDAPS, or Active Directory

Choose exactly one authentication backend:

AUTHORIZATION_TYPE=local

Supported values:

  • local - built-in registration and password login
  • ldap - OpenLDAP-compatible directory
  • ad - Microsoft Active Directory defaults

For ldap and ad, RustPad searches the directory with the service account, validates the password by binding as the user, and automatically provisions a local account. Existing sessions, ownership, sharing, and other account functions continue to use the existing users table. Local registration and guest nickname access are disabled.

The nickname is generated as LDAP_ORGANIZATION/displayName, for example example/Mateusz Testowy. Directory accounts are stored using a stable entryUUID (LDAP) or objectGUID (AD), while e-mail, nickname, and DN are synchronized after every successful login.

OpenLDAP

AUTHORIZATION_TYPE=ldap
LDAP_URL=ldap://10.87.2.6:389
LDAP_STARTTLS=false
LDAP_BIND_DN=cn=admin,dc=example,dc=org
LDAP_BIND_PASSWORD=admin
LDAP_BASE_DN=ou=people,dc=example,dc=org
LDAP_ORGANIZATION=example

In ldap mode the defaults are:

LDAP_USER_FILTER=(uid={username})
LDAP_USERNAME_ATTRIBUTE=uid
LDAP_EMAIL_ATTRIBUTE=mail
LDAP_DISPLAY_NAME_ATTRIBUTE=displayName

Active Directory

AUTHORIZATION_TYPE=ad
LDAP_URL=ldaps://ad.example.org:636
LDAP_STARTTLS=false
LDAP_BASE_DN=DC=example,DC=org
LDAP_BIND_DN=CN=rustpad-bind,OU=Service Accounts,DC=example,DC=org
LDAP_BIND_PASSWORD=secret
LDAP_ORGANIZATION=example

In ad mode the defaults are:

LDAP_USER_FILTER=(|(sAMAccountName={username})(userPrincipalName={username}))
LDAP_USERNAME_ATTRIBUTE=sAMAccountName
LDAP_EMAIL_ATTRIBUTE=mail
LDAP_DISPLAY_NAME_ATTRIBUTE=displayName

All LDAP attributes and filters can still be overridden explicitly. By default TLS certificates are verified. For a trusted internal or test server using a self-signed certificate, LDAP_TLS_VERIFY=false keeps LDAPS/StartTLS encryption enabled without requiring a custom CA file. Do not disable verification on untrusted networks.

Additional directory options:

LDAP_EXTERNAL_ID_ATTRIBUTE=entryUUID
LDAP_EMAIL_REQUIRED=true
LDAP_LINK_EXISTING_BY_EMAIL=false
LDAP_TLS_VERIFY=true
LDAP_CONNECT_TIMEOUT_SECONDS=5
LDAP_OPERATION_TIMEOUT_SECONDS=10

For Active Directory, the default external identifier is objectGUID. Set LDAP_LINK_EXISTING_BY_EMAIL=true only during an intentional migration of existing local or legacy LDAP accounts; otherwise an e-mail collision is rejected.

Test LDAP on 10.87.2.6

cd docker/ldap
docker compose up -d

Test users:

  • mateusz / test1234
  • anna / test1234

phpLDAPadmin: http://10.87.2.6:8088

Administrator: cn=admin,dc=example,dc=org / admin

S
Description
No description provided
Readme
9 MiB
Languages
Rust 50.2%
JavaScript 28.6%
CSS 11.2%
Python 5.6%
HTML 3.9%
Other 0.5%