AFFiNEをセルフホストする方法と必要なメモリ
Docker ComposeでAFFiNEを1台のVPSに構築する方法を解説します。4つのコンテナ、固定するイメージタグ、データの保存先、バックアップ、2 GB RAMでできることを確認できます。
セルフホストで AFFiNE を運用すると得られるもの
AFFiNE をセルフホストすると、自分で管理するサーバー上で Notion 形式のワークスペースを利用できます。構成は、アプリケーション、1 回だけ実行するマイグレーションジョブ、Postgres、Redis の 4 つのコンテナです。リアルタイム共同編集にも対応しており、セルフホストのワークスペースではデフォルトで最大 10 ユーザーが利用できます。インストールに必要なのは、1 つの compose ファイルと 1 つの JSON 設定ファイルだけです。検討が必要なのは、イメージタグ、ディスク構成、メモリ上限、そして前段に配置するプロキシです。
AFFiNE では、ドキュメントエディターと無限キャンバスを同じワークスペースで利用できます。そのため、1 つのページをドキュメントとして読むことも、ホワイトボードのように広げて使うこともできます。まだ導入するものを決めていない場合は、先に セルフホスト可能な Notion 代替サービスの比較を読んでください。このガイドでは導入するサービスは決まっているものとし、比較を繰り返すのではなく、AFFiNE を適切に運用する方法を説明します。
ここに記載する内容は、2026 年 8 月 8 日時点の AFFiNE のセルフホスト向けドキュメントと公開リリースファイルに基づいて確認しています。その時点での最新の安定版は 0.27.3 で、2026 年 7 月 23 日に公開されました。
4 つのコンテナが実際に行う処理
affine は、サーバーと Web クライアントを 1 つのイメージにまとめたものです。3010 番ポートで待ち受けます。
affine_migration は、node ./scripts/self-host-predeploy.js を実行してデータベースのマイグレーションを適用した後、終了する 1 回限りのジョブです。アプリケーションはこのジョブに対する condition: service_completed_successfully を宣言しているため、マイグレーションが 0 以外のステータスで終了すると、affine はまったく起動しません。Web インターフェースが起動しない場合は、まずこのジョブのログを確認します。
postgres には、ドキュメント、ユーザー、ワークスペース、権限が保存されます。提供されるイメージは pgvector/pgvector:pg16 です。pgvector 拡張機能を組み込んだ通常の Postgres 16 です。pgvector は Postgres に vector 型を追加します。これは埋め込みベクトルの保存に使用する数値形式で、テキストを意味に基づいて検索できます。
redis は必須の依存先です。サーバーとマイグレーションジョブは、どちらも起動前にそのヘルスチェックが成功するまで待機します。提供される compose ファイルで Redis に付与されていないものが、ボリュームです。その内部の内容は docker compose down 後も何も保持されません。つまり、そこにはあなたのデータが保存されておらず、バックアップも必要ないことが明確に分かります。
Postgres イメージが標準の postgres ではなく pgvector である理由
この要件は設定の好みではなく、AFFiNE のスキーマに由来します。schema.prisma ではデータソースが extensions = [pgvector(map: "vector")] を宣言しており、4 つのテーブルに embedding 列があり、その型は vector(1024) です。マイグレーションジョブは AI 機能を一度も有効にしない場合でも、これらのテーブルを作成します。そのため、マイグレーションが完了する前に、データベースに拡張機能が存在していなければなりません。postgres:16 に置き換えると拡張機能がなくなり、マイグレーションでこれらの列を作成できません。その結果、サーバーは失敗したジョブを待ち続けます。
AFFiNE はバージョン 0.21 で pgvector イメージに移行しました。それより前のバージョンからのインストールでは、イメージの行を編集するだけではアップグレードできません。何かを pull する前に、AFFiNE のセルフホストドキュメントにあるアップグレードページを確認してください。
このタグについて、もう 1 つ注意点があります。pg16 は Postgres 16 を意味します。Postgres のメジャーバージョンは、数字を変更するだけでは更新できません。既存のデータディレクトリに対して pg17 に変更すると、Postgres は起動を拒否し、docker compose logs postgres に The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17 のような行を出力します。メジャーバージョンを移行するには、ダンプを作成し、新しいデータディレクトリにリストアする必要があります。
自己ホスト AFFiNE に必要な CPU と RAM
AFFiNE の要件ページでは、最低 4 CPU コアと 2 GB の RAM が必要とされています。ドキュメントが 10,000 語を超えると、必要なメモリは 4 GB に増えます。同じページには、メモリを消費する処理として同期システムとドキュメントのマージが挙げられています。覚えておくべき数値は、10,000 件の変更を含むドキュメントのマージで、使用メモリが 1 GB に達することがあるという点です。
これを、2 GB プランで 2 人が編集する場合に当てはめて考えてください。平均的な使用量なら問題ありません。Postgres と Node プロセスは、余裕を残して上限内に収まります。問題はピーク時です。1 回の大規模なマージで、すでに使用中のメモリに加えて 1 GB が必要になることがあります。swap がない 2 GB のサーバーでは、カーネルの out-of-memory (OOM) killer がこの要求に対応するため、最大のプロセスである AFFiNE サーバーを強制終了します。
同僚にはエラーが表示されません。restart: unless-stopped が数秒以内にコンテナを復旧するため、ページが再読み込みされたように見えます。推測せず、次のコマンドで確認してください。
docker inspect affine_server --format '{{.State.OOMKilled}} {{.RestartCount}}'
sudo dmesg -T | grep -i -E 'out of memory|killed process'最初のコマンドの true、または 2 番目のコマンドに node を示す Killed process 行があれば、バグではなくメモリ不足です。両方の側から対処します。まず swap を追加し、メモリの急増を致命的な障害ではなく、処理速度の低下に変えます。
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -hfree -h の結果には、2.0Gi の swap 合計が表示されるはずです。swap によって AFFiNE が高速になるわけではなく、その目的でもありません。1 秒間のメモリ急増を、コンテナの停止ではなく、一時的な低速化に変えます。もう一方の対策は、マージ時にアプリケーションが必要とする領域まで Postgres がキャッシュを拡大しないようにすることです。そのために使用するのが、Compose サービスのメモリ制限です。
ストレージの必要量は、はるかに予測しやすいものです。AFFiNE は同じページで次の数値を公開しています。
The data behind this chart
[
{
"label": "Server install",
"gb": 1.5
},
{
"label": "Postgres per 1,000 docs",
"gb": 0.1
},
{
"label": "Blob store per 1,000 uploads",
"gb": 10
}
]サーバーのインストールに 1.5 GB 必要です。約 1,000 語のドキュメントを 1,000 件追加しても、Postgres のデータは 0.1 GB 増えるだけで、ほとんど無視できます。一方、アップロードしたファイルを 1,000 件追加すると 10 GB 増加し、こちらがストレージ使用量の大部分を占めます。これらは稼働中のインスタンスで測定した値ではなく、公開されている計画用の数値です。そのため、厳密な保証ではなく、傾向を示す目安として扱ってください。重要なのは傾向です。データベースは小さいままですが、ディスク使用量はアップロードしたファイルで決まります。
タグを固定して compose ファイルを自分で作成する
公式ドキュメントのインストール手順では、curl -L -o docker-compose.yml https://github.com/toeverything/AFFiNE/releases/latest/download/docker-compose.yml を使って完成済みのファイルをダウンロードします。これは動作します。ただし、このファイルに依存する前に知っておくべき点があります。2026年8月8日時点で、release 0.27.3 に添付されたファイルは .env ファイルからパスを読み込み、${UPLOAD_LOCATION}、${CONFIG_LOCATION}、${DB_DATA_LOCATION} を使用します。一方、ドキュメントのリファレンスページには、すべてを ./data 配下に置き、.env をまったく必要としない新しい構成が示されています。どちらも実在する構成です。ファイルを自分で作成すれば、この違いを気にする必要がなくなります。いずれにしても、イメージを固定し、データベースのパスワードを設定するために編集が必要です。
mkdir -p ~/affine/config ~/affine/data
cd ~/affine
printf 'DB_PASSWORD=%s\n' "$(openssl rand -hex 24)" > .env
chmod 600 .envCompose はプロジェクトディレクトリから .env を自動的に読み込み、${DB_PASSWORD} を自動的に置換します。そのため、サポートスレッドに貼り付けるファイル内にパスワードが表示されることはありません。この習慣は、運用するすべてのスタックで維持してください。その理由は compose ファイルから Secret を除外する に記載しています。
次に ~/affine/docker-compose.yml を作成します。
name: affine
services:
affine:
image: ghcr.io/toeverything/affine:stable
container_name: affine_server
ports:
- '127.0.0.1:3010:3010'
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
affine_migration:
condition: service_completed_successfully
volumes:
- ./data/storage:/root/.affine/storage
- ./config:/root/.affine/config
environment:
- REDIS_SERVER_HOST=redis
- DATABASE_URL=postgresql://affine:${DB_PASSWORD}@postgres:5432/affine
- AFFINE_INDEXER_ENABLED=false
restart: unless-stopped
affine_migration:
image: ghcr.io/toeverything/affine:stable
container_name: affine_migration_job
command: ['sh', '-c', 'node ./scripts/self-host-predeploy.js']
volumes:
- ./data/storage:/root/.affine/storage
- ./config:/root/.affine/config
environment:
- REDIS_SERVER_HOST=redis
- DATABASE_URL=postgresql://affine:${DB_PASSWORD}@postgres:5432/affine
- AFFINE_INDEXER_ENABLED=false
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
redis:
image: redis:8-alpine
container_name: affine_redis
healthcheck:
test: ['CMD', 'redis-cli', '--raw', 'incr', 'ping']
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
postgres:
image: pgvector/pgvector:pg16
container_name: affine_postgres
volumes:
- ./data/postgres:/var/lib/postgresql/data
environment:
POSTGRES_USER: affine
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: affine
POSTGRES_INITDB_ARGS: '--data-checksums'
healthcheck:
test: ['CMD', 'pg_isready', '-U', 'affine', '-d', 'affine']
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped上流で提供されるファイルとの違いは4つあります。それぞれに理由があります。
127.0.0.1:3010:3010はループバックアドレスにのみポートを公開します。そのため、公開方法を決めるまで、サーバー外部から AFFiNE に接続できません。上流の'3010:3010'はすべてのインターフェースにバインドされます。多くの VPS イメージでは、これにパブリックインターフェースも含まれます。POSTGRES_HOST_AUTH_METHOD: trustを削除し、代わりにパスワードを設定しています。Trust 認証では、パスワードなしで、そのデータベースへの接続をaffineユーザーとして受け入れます。接続元はプライベートな Compose ネットワークに限られるため、追加のコンテナをそのネットワークに接続したり、デバッグ中に 5432 を公開したりしない限り問題ありません。- 裸の
redisをredis:8-alpineに置き換えています。裸のredisはlatestに解決されます。2026年8月時点では Redis 8 であるため、この固定によりテスト済みのメジャーバージョンを維持でき、無関係なdocker compose pullの実行中に将来の Redis 9 が導入されることを防げます。 pgvector/pgvector:pg16は、上記の理由により、上流の設定から変更していません。
POSTGRES_PASSWORD が読み込まれるのは、Postgres が初回にデータディレクトリを作成するときだけです。既存のインスタンスでは、docker compose exec postgres psql -U affine -c "ALTER USER affine WITH PASSWORD 'yourpassword'" でパスワードを設定し、DATABASE_URL も同じ値に更新してください。
Configuration は config/config.json に保存されます
AFFiNE は config/config.json から設定を読み込みます。これは /root/.affine/config にマウントしたディレクトリです。このファイルは自動作成されないため、初回起動前に作成してください。エディターで ~/affine/config/config.json を開き、例のドメインを自分のドメインに置き換えて、次の内容を記述します。
{
"$schema": "https://github.com/toeverything/affine/releases/latest/download/config.schema.json",
"server": {
"name": "Team workspace",
"externalUrl": "https://affine.example.com"
},
"copilot": {
"enabled": false,
"byok": {
"enabled": false
}
}
}server.externalUrl には、ユーザーが実際にブラウザーで開くアドレスを指定する必要があります。AFFiNE はこの値を基に共有リンクとワークスペースへの招待を作成します。http://localhost:3010 のままにすると、送信した招待の宛先が受信者自身のマシンになり、そこで失敗します。初回起動前に公開 HTTPS アドレスを設定してください。これにより、ファイルと管理パネルの値が一致します。
copilot は AI 機能を制御します。copilot.byok.enabled は自分の API key を使用するための切り替えです。これを有効にすると、ワークスペースの所有者はワークスペース設定に自分のモデルプロバイダーの key を入力できます。AFFiNE をセルフホストしても、AI サブスクリプションは付属しません。AI 機能が不要な場合は、false のままにしてください。
スタックを起動します。
docker compose up -d
docker compose psdocker compose ps には affine_postgres と affine_redis が healthy、affine_server が running、affine_migration_job が状態 exited (0) と表示されるはずです。migration job が別の終了コードを返した場合は、その原因を調査してください。ログには停止したステップが記録されます。
docker compose logs affine_migration忘れる前にイメージを固定する
stable は更新されるタグです。AFFiNE のリリースワークフローでは、各安定版ビルドに複数のタグを付けています。ここで重要なのは 2 つです。stable はリリースごとに付け替えられます。stable- に git の短いハッシュを続けたタグは付け替えられません。stable のままにすると、6 か月後に実行した docker compose pull は別のイメージを取得し、意図しないタイミングでそのイメージのマイグレーションをデータベースに適用します。テスト済みの正確なイメージを固定してください。
docker compose pull
docker image inspect ghcr.io/toeverything/affine:stable --format '{{index .RepoDigests 0}}'これは、ghcr.io/toeverything/affine@sha256: に続いて長いハッシュが表示される形式の行を出力します。文字列全体を、affine と affine_migration の両方の image: 行に貼り付けてください。この 2 つは同じイメージを別の役割で使用するため、常に一致している必要があります。一致しない場合、一方のスキーマへデータベースをマイグレーションしながら、別のスキーマを想定するイメージでサービスを提供することになります。アップグレードは、予期せぬ変更ではなく、意図的な編集として実施できます。ダイジェストを変更し、バックアップを作成して、docker compose pull、docker compose up -d を実行してください。
他のユーザーより先に管理者アカウントを作成する
新しいインスタンスで /admin を開くと、AFFiNE はアカウント作成ページに移動します。サーバーに管理者がまだ存在しないためです。この手順に招待コードやセットアップトークンはありません。そのページを最初に読み込んだユーザーがサーバーの管理者になります。そのため、登録が完了するまでポートを閉じておく必要があります。
これが、上記の compose ファイルで 127.0.0.1 にバインドしている理由です。自分のマシンから SSH トンネル経由でアクセスします。
ssh -L 3010:127.0.0.1:3010 you@your-server-ipこの状態で SSH トンネルを実行したままにし、ローカルブラウザーで http://127.0.0.1:3010/admin を開きます。登録してログインしたら、トンネルを閉じます。この時点で初めて、インスタンスを公開名でアクセスできるようにしても安全です。
AFFiNE がデータを保持する場所
3 つのパスにすべてのデータが保存されます。これらはすべて、作成したディレクトリ内にあります。
./data/postgresは Postgres のデータディレクトリです。ドキュメント、ユーザー、ワークスペース、権限が保存されます。./data/storageはコンテナ内の/root/.affine/storageにマウントされ、アップロードされたすべてのファイルを保持します。./configは/root/.affine/configにマウントされ、config.jsonを保持します。
ここでは、Upstream は名前付きボリュームではなく bind mount を使用しています。この選択には明確な理由があります。Docker がデータをどこに配置したかを確認しなくても、通常のコマンドでこれらのパスを tar でまとめてコピーできます。その代わり、ホスト上のファイル所有権は自分で管理する必要があります。これは、bind mount と名前付きボリュームで説明するトレードオフです。
AFFiNE のバックアップ方法
バックアップが必要なものは2つあり、それぞれ方法が異なります。データベースは稼働中のサーバーであるため、稼働中にファイルをコピーすると破損したコピーになります。代わりにダンプを取得します。
mkdir -p ~/affine/backup
cd ~/affine
docker compose exec -T postgres pg_dump --format c --username affine affine \
> backup/affine-$(date +%F).dump
ls -lh backup/ダンプはコンテナ内でローカルソケットを使用して実行されるため、パスワードの入力を求められません。ls の出力でサイズを確認してください。数百バイト程度のファイルは、シェルがファイルだけを作成し、ダンプ自体は失敗したことを示します。この問題は6か月後に発覚することがあります。-T も重要です。これがないと Compose が端末を割り当て、バイナリストリームを破損させる可能性があります。
アップロードされたファイルは通常のファイルなので、tar でアーカイブします。
tar czf backup/storage-$(date +%F).tgz -C data storage
cp config/config.json backup/config-$(date +%F).jsonconfig.json は手動でバックアップに含めてください。2026年8月時点で、AFFiNE のドキュメントには管理パネルからの設定エクスポートが未実装と記載されています。そのため、ディスク上のファイルが設定の唯一のコピーです。3つのファイルをすべてサーバーの外部にコピーしてください。保護対象と同じディスク上にあるバックアップは、バックアップとはいえません。
公開手順の復元方法と、注意すべき落とし穴
必要になる前に公式の復元手順を読み、内容をよく確認してください。2026 年 8 月時点の公開手順では、affine.backup という名前のファイルをコンテナにコピーしてから、./pg.backup から復元します。しかし、この 2 つは異なる名前です。また、現在の compose ファイルではデータを ./data/postgres に保持しているにもかかわらず、./postgres ディレクトリを削除します。スニペットに記載されたパスではなく、実際に使用したパスに従ってください。このガイドの構成に対する手順は次のとおりです。
cd ~/affine
docker compose down
sudo mv data/postgres data/postgres.old
docker compose up -d postgres
docker compose cp backup/affine-2026-08-08.dump postgres:/tmp/affine.dump
docker compose exec postgres pg_restore --format c --username affine \
--dbname affine --verbose /tmp/affine.dump
docker compose up -drm ではなく mv である点に注意してください。コピーを保持していないデータベースに復元すると、1 つの誤ったコマンドがデータの完全な損失につながります。古いディレクトリを別の場所へ移動しておけば、そのリスクを避けられます。tar xzf backup/storage-2026-08-08.tgz -C data を使用してアップロードファイルも復元してください。復元しないと、すべてのドキュメントで添付ファイルが壊れて表示されます。その後、ログインして画像を含むドキュメントを開きます。これがテストです。ブラウザーで開いて確認していない復元データは、バックアップではなく単なるファイルです。
すでに運用しているプロキシの背後に AFFiNE を配置する
AFFiNE は WebSocket を使用し、これは無効化できません。ドキュメントにも明記されているとおり、WebSocket は AFFiNE の同期およびコラボレーションシステムの基盤です。そのため、接続をアップグレードしないプロキシを使用すると、編集内容の同期だけが停止するワークスペースになります。ページの読み込みとログインは成功しますが、一方のブラウザーで行った編集がもう一方に届きません。ブラウザーの開発者ツールで Network タブを開き、WS に絞り込みます。接続が何度も開いては閉じる場合、プロキシがアップグレードを転送していません。
すでに他のコンテナで Traefik を運用している場合、AFFiNE も通常のサービスとして追加できます。affine サービスから ports: ブロックを削除し、次を追加します。
networks:
- default
- proxy
labels:
- 'traefik.enable=true'
- 'traefik.docker.network=proxy'
- 'traefik.http.routers.affine.rule=Host(`affine.example.com`)'
- 'traefik.http.routers.affine.entrypoints=websecure'
- 'traefik.http.routers.affine.tls.certresolver=letsencrypt'
- 'traefik.http.services.affine.loadbalancer.server.port=3010'ファイルの末尾で、services: と同じ位置に次を追加します。
networks:
proxy:
external: true証明書リゾルバー名は、Traefik の設定で定義した名前と一致させる必要があります。また、loadbalancer.server.port はコンテナのポート 3010 であり、ホストポートではありません。Traefik は追加設定なしで WebSocket 接続をプロキシするため、ほかに追加する項目はありません。1 つの Traefik インスタンスで複数のアプリを背後に配置する方法については、複数のアプリの前段に 1 つの Traefik を配置する を参照してください。
nginx では、アップグレードを明示的に指定する必要があります。
location / {
proxy_pass http://127.0.0.1:3010;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 100m;
}nginx の client_max_body_size のデフォルト値は 1 MB です。この行がないと、小さな写真を超えるサイズのアップロードはすべて 413 ステータスで失敗します。リクエストが到達していないため、AFFiNE のログには何も記録されません。Caddy では reverse_proxy http://127.0.0.1:3010 の 1 行が必要で、証明書と WebSocket のアップグレードは Caddy 自身が処理します。
セルフホスト構成に含まれないもの
チームを移行する前に、この点を正しく把握してください。
リアルタイムコラボレーションは利用できます。サイジングに関する説明の中心となっている機能です。AFFiNE の公式ドキュメントでは、メモリ使用量の主な要因として同期システムとドキュメントのマージを挙げています。オフライン編集は、ローカルファーストのツールを求める人が多い理由です。デスクトップアプリケーションでは、セルフホストサーバーをワークスペース一覧に追加し、そのサーバーに対してログインできます。導入を決める前に、チームが依存するオフライン動作を正確にテストしてください。デスクトップアプリケーションでネットワークを切断した状態で編集し、再接続してから、2 台目のデバイスで結果を確認します。機能一覧は根拠になりません。この一覧も例外ではありません。
サーバー側の全文検索は、提供される compose ファイルでは無効になっています。AFFINE_INDEXER_ENABLED=false はサーバーとマイグレーションジョブで設定されています。有効にするには Manticore Search コンテナを追加する必要があります。5 つ目のサービスが増え、メモリ使用量も増加します。2 GB のサーバーでは、この変更によってメモリ上限を超えます。クライアント内の検索は、現在開いているワークスペースでは引き続き利用できます。
ユーザーを招待する前に、2 つの制限を把握しておいてください。セルフホストのワークスペースに付与できるシート数は最大 10 です。これを超える場合は、AFFiNE の Team ライセンスが必要です。セルフホストインスタンスの無制限の BLOB ストレージと BLOB サイズは、ドキュメントでは予定されている機能と説明されていますが、2026 年 8 月時点ではまだ完全には実装されていません。家庭や小規模チームでは、これらは問題になりません。40 人を移行する予定であれば、どちらも問題になります。
アップグレード
最初にリリースノートを確認してください。特に 0.26 から 0.27 への更新のようなマイナーバージョンの変更では、後方互換性のない変更が入ることがあります。作業を始める前に、データベースとストレージディレクトリをバックアップしてください。次回の起動時にマイグレーションジョブがスキーマを変更し、元に戻せないためです。その後、固定しているダイジェストを変更し、docker compose pull に続けて docker compose up -d を実行します。docker compose logs -f affine_migration が正常に終了するまで監視してください。完了後、docker image prune で古いレイヤーを削除します。非常に古いインストール環境を使用している場合は、次の点にも注意してください。バージョン 0.23.0 から、イメージ名が affine-graphql から affine に変更されました。そのため、それより前の compose ファイルでは、pull でイメージを取得できるように image の行を書き換える必要があります。
FAQ
AFFiNE コンテナがまったく起動しないのはなぜですか?
affine サービスは affine_migration ジョブで condition: service_completed_successfully を宣言しています。そのため、マイグレーションが 0 以外のステータスで終了すると、サーバーは起動せず、Web インターフェースも表示されません。どのステップで停止したかを確認するには docker compose logs affine_migration を実行します。手作業で編集した compose ファイルで最も多い原因は、pgvector/pgvector:pg16 の代わりに標準の postgres イメージを指定していることです。AFFiNE のスキーマは pgvector 拡張機能を宣言し、通常の Postgres では作成できない vector(1024) 型のカラムを持つテーブルを作成するためです。
自己ホスト型 AFFiNE にはどの程度の RAM が必要ですか?
AFFiNE の要件ページでは、最低 4 CPU コアと 2 GB の RAM を求めています。ドキュメントが 10,000 語を超える場合は 4 GB が必要になり、10,000 件の変更を含むドキュメントをマージすると 1 GB に達する可能性があると記載されています。2 GB のサーバーでは、問題になるのはアイドル時の負荷ではなく、このピークです。カーネルの out-of-memory killer が AFFiNE プロセスを停止し、restart: unless-stopped が再起動するため、ユーザーにはエラーではなくページの再読み込みとして見えます。docker inspect affine_server --format '{{.State.OOMKilled}}' と sudo dmesg -T | grep -i 'out of memory' で確認し、2 GB の swap ファイルを追加してください。スパイクが発生しても致命的な停止ではなく、処理の低下で済むようになります。
AFFiNE はデータをどこに保存しますか?何をバックアップすればよいですか?
compose ディレクトリ配下の 3 つのパスにすべてのデータが保存されます。データベースは ./data/postgres、アップロードファイルは ./data/storage、config.json は ./config に保存されます。データベースはファイルをコピーせず、docker compose exec -T postgres pg_dump --format c --username affine affine > affine.dump でバックアップしてください。稼働中の Postgres は安全にコピーできないためです。アップロードファイルについては ./data/storage を tar でアーカイブし、config.json のコピーを手動で保管してください。2026 年 8 月時点では、管理パネルからの設定エクスポートは未実装と記載されているためです。
自己ホスト型 AFFiNE でリアルタイム共同編集は利用できますか?
はい。利用にあたって有効化が必要な設定はありません。必要なのはリバースプロキシの設定です。同期には WebSocket 接続を使用するためです。nginx では proxy_http_version 1.1 に加えて Upgrade ヘッダーと Connection: upgrade ヘッダーが必要です。Traefik と Caddy では、追加設定なしでこれらの接続が通過します。プロキシが WebSocket 接続をアップグレードしない場合、ワークスペースは正常に読み込まれてログインもできますが、1 つのブラウザーで行った編集が別のブラウザーに表示されません。
標準の Postgres イメージで AFFiNE を実行できますか?
いいえ。AFFiNE の schema.prisma は extensions = [pgvector(map: "vector")] を宣言し、vector(1024) 型の embedding カラムを持つ 4 つのテーブルを定義しています。AI 機能を無効にしていても、マイグレーションジョブはこれらのテーブルを作成します。pgvector/pgvector:pg16 を使用してください。これは、その拡張機能を組み込んだ Postgres 16 です。外部の Postgres サーバーを AFFiNE に指定する場合は、そのサーバーに pgvector をインストールし、マイグレーションを実行する前に対象データベースで拡張機能を作成してください。