AFFiNE
About
AFFiNE is a workspace for docs, whiteboards and databases. It combines a block-based editor with an infinite canvas and real-time collaboration.
- Questions? Ask in the Cloudron Forum - AFFiNE
- AFFiNE Website
- AFFiNE Docs
- AFFiNE issue tracker
The first account registered on the instance becomes the server administrator.
Admin panel
The admin panel is available at https://<app-domain>/admin. Use it to manage users and to edit the server settings that AFFiNE exposes in the UI.
Settings saved in the admin panel are stored in the database and take effect immediately. They also take precedence over /app/data/config.json - a value edited in the admin panel keeps winning after a restart.
Custom config
Set custom configuration in /app/data/config.json using the File manager. Restart the app for changes to take effect.
The package copies this file into place on every start, so /app/data/config.json is the durable location and is part of the app's backup.
AFFiNE resolves settings in this order, with later sources overriding earlier ones:
- Built-in defaults.
- Environment variables (set by the package).
/app/data/config.json.- Values saved in the admin panel.
The complete list of options lives in the config schema. Keep the $schema key at the top of the file to get validation and completion in editors:
{
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
"server": {
"name": "AFFiNE"
}
}
The package automatically configures the following:
- Database
- Redis
- The external URL
- The server private key
- Local file storage
- OIDC
through environment variables and through the generated runtime config.
Since config.json overrides environment variables, setting mailer, server.externalUrl, server.port, crypto or storages yourself breaks the integration.
Disable public access
Without a session, AFFiNE offers a guest demo workspace that lives in the browser's local storage. The workspace holds no server data, but the editor is reachable without logging in. See this forum topic for the original report.
Turn the demo workspace off to send every visitor to the login screen:
{
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
"flags": {
"allowGuestDemoWorkspace": false
}
}
Registration
New accounts are allowed by default. Restrict registration with the auth module:
{
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
"auth": {
"allowSignup": false,
"allowSignupForOauth": false,
"requireEmailVerification": true,
"passwordRequirements": {
"min": 12,
"max": 128
}
}
}
allowSignup- allow registration with email and password.allowSignupForOauth- allow a first-time login through a configured OAuth provider to create an account. Set this tofalseon a Cloudron instance only after every user has logged in once, otherwise Cloudron users cannot sign in.
Existing members can still be invited into a workspace when signup is disabled.
Single sign-on
AFFiNE supports optional SSO. The choice is made at installation time and cannot be changed later.
With SSO enabled, the package registers Cloudron as an OIDC provider and adds a login button for it. Do not add an oauth.providers.oidc block to config.json - the package writes one on every start and your block gets ignored.
With user management left to the app, users register with email and password instead.
Email
Email is delivered through the Cloudron mail server. Change the sender display name in the app's Email settings in the Cloudron dashboard.
Session lifetime
Sessions last 15 days by default. Adjust the lifetime in seconds:
{
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
"auth": {
"session": {
"ttl": 604800,
"ttr": 86400
}
}
}
ttl is the expiration time; ttr is the interval after which an active session gets refreshed.
Doc history
A history snapshot is created at most once every 10 minutes per doc. Shorten the interval (in milliseconds) for more granular version history at the cost of database size:
{
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
"doc": {
"history": {
"interval": 120000
}
}
}
AI features
AI is disabled by default. Enable the copilot module and let workspace owners add their own provider keys under Workspace Settings -> Integrations -> AI BYOK:
{
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
"copilot": {
"enabled": true,
"byok": {
"enabled": true,
"allowedProviders": ["openai", "anthropic", "gemini"]
}
}
}
Storage for copilot attachments is already pointed at the app's data directory by the package.
Full-text search
Server-side full-text search requires an external Manticore Search or Elasticsearch instance. The package does not bundle one. Point AFFiNE at an existing instance to enable it:
{
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
"indexer": {
"enabled": true,
"provider": {
"type": "elasticsearch",
"endpoint": "https://elasticsearch.example.com",
"username": "affine",
"password": "SECRET"
}
}
}
Rate limiting
Requests are throttled to 120 per minute per client, and 20 per minute for sensitive endpoints like authentication. Raise the limits for large teams:
{
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
"throttle": {
"throttlers": {
"default": { "ttl": 60000, "limit": 300 },
"strict": { "ttl": 60000, "limit": 40 }
}
}
}
Server private key
A private key is generated at /app/data/private.key on first start. It signs tokens and encrypts stored secrets. The key is part of the app's backup - restoring an app without it invalidates all sessions and stored credentials. Do not delete or replace the file.