AFFiNE в Docker Compose: готовый файл
Notion удобен, пока вы не упираетесь в облако: данные лежат на чужих серверах, платная подписка растёт с числом участников, а если сервис недоступен из России без VPN — рабочий процесс просто встаёт. AFFiNE закрывает тот же набор задач (документы, канбан-доски, простая база данных, whiteboard) как self-hosted альтернатива, которую вы поднимаете на своём сервере одной командой. Ниже — рабочий docker-compose.yml, разбор первого запуска с созданием администратора и настройка домена с HTTPS.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →AFFiNE: что это и чем отличается от Notion и Obsidian
AFFiNE — открытый проект (лицензия MIT), который с самого начала задумывался как «Notion + Miro в одном приложении»: один и тот же документ можно листать как обычный текстовый редактор с блоками (заголовки, списки, таблицы, код), а можно переключить в режим Edgeless — бесконечный холст, где те же блоки становятся карточками, которые двигают, соединяют стрелками и группируют, как в Miro или FigJam. Плюс к этому — встроенные базы данных с несколькими представлениями (таблица, канбан, галерея), близкие по духу к базам Notion.
Технически сервер AFFiNE — это Node.js-бэкенд с двумя внешними зависимостями: PostgreSQL (с расширением pgvector для векторного поиска, если включён AI-ассистент) и Redis для очередей и кэша. Клиенты — веб, десктоп (Windows/macOS/Linux) и мобильные приложения — синхронизируются с сервером через realtime-протокол на базе CRDT (Yjs), тот же класс технологий, что использует Google Docs для совместного редактирования без конфликтов.
| AFFiNE | Notion | Obsidian (self-hosted sync) | |
|---|---|---|---|
| Модель | документ + бесконечный холст в одном блоке | документ + база данных | markdown-файлы + плагины |
| Совместная работа | realtime, CRDT | realtime, облако | через сторонний sync-сервер |
| Хостинг | self-hosted или облако AFFiNE | только облако | локально или self-hosted sync |
| AI-ассистент | опционально, свой ключ (BYOK) | встроен, платно | через плагины |
| Whiteboard | встроен (Edgeless) | нет | через плагины |
Если нужна именно иерархическая база знаний с деревом заметок и клонированием, Trilium Notes организован строже. Если основная задача — канбан-доски и управление задачами команды без документов вокруг, проще смотреть в сторону Wekan или Focalboard. AFFiNE выигрывает там, где нужен именно гибрид: заметки, доски и произвольные визуальные схемы в одном рабочем пространстве, без переключения между разными сервисами.
Требования к серверу
Стек лёгкий по одиночным меркам, но постоянно работающий Node.js-процесс плюс PostgreSQL и Redis в сумме требуют больше памяти, чем однофайловые SQLite-приложения вроде Trilium.
| Сценарий | vCPU | RAM | Диск |
|---|---|---|---|
| личное использование, 1 пользователь | 2 | 2 ГБ | 20 ГБ |
| небольшая команда, 3-10 человек | 2-4 | 4 ГБ | 40 ГБ |
| команда с активным AI-ассистентом и большим объёмом вложений | 4 | 6-8 ГБ | от 80 ГБ |
Цифры ориентировочные: сильнее всего на потребление влияет, включены ли AI-функции (векторный поиск в pgvector нагружает PostgreSQL) и объём файлов, которые команда вкладывает в документы — они растут в отдельном volume независимо от самой базы. На 2 ГБ RAM инстанс запускается и работает, но под несколькими одновременными редакторами лучше закладывать 4 ГБ с запасом.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверГотовый docker-compose.yml
Официальный образ AFFiNE тянет актуальный docker-compose.yml прямо с GitHub Releases проекта — файл ниже собран на его основе с портом только на loopback (для работы через реверс-прокси, раздел ниже).
Структура каталогов на сервере:
/opt/affine/
├── data/
│ ├── postgres/ # данные PostgreSQL
│ └── storage/ # вложения, blob-хранилище документов
├── config/ # config.json сервера
└── docker-compose.yml
Создаём каталоги:
mkdir -p /opt/affine/data/postgres /opt/affine/data/storage /opt/affine/config
cd /opt/affine
nano docker-compose.yml
Содержимое файла:
name: affine
services:
affine:
image: ghcr.io/toeverything/affine:stable
container_name: affine_server
restart: unless-stopped
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@postgres:5432/affine
- AFFINE_INDEXER_ENABLED=false
affine_migration:
image: ghcr.io/toeverything/affine:stable
container_name: affine_migration_job
volumes:
- ./data/storage:/root/.affine/storage
- ./config:/root/.affine/config
command: ["sh", "-c", "node ./scripts/self-host-predeploy.js"]
environment:
- REDIS_SERVER_HOST=redis
- DATABASE_URL=postgresql://affine@postgres:5432/affine
- AFFINE_INDEXER_ENABLED=false
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
redis:
image: redis
container_name: affine_redis
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 10s
timeout: 5s
retries: 5
postgres:
image: pgvector/pgvector:pg16
container_name: affine_postgres
restart: unless-stopped
volumes:
- ./data/postgres:/var/lib/postgresql/data
environment:
POSTGRES_USER: affine
POSTGRES_DB: affine
POSTGRES_INITDB_ARGS: "--data-checksums"
POSTGRES_HOST_AUTH_METHOD: trust
healthcheck:
test: ["CMD", "pg_isready", "-U", "affine", "-d", "affine"]
interval: 10s
timeout: 5s
retries: 5
Обратите внимание на POSTGRES_HOST_AUTH_METHOD: trust — PostgreSQL здесь работает без пароля. Это безопасно ровно потому, что порт базы не публикуется наружу и доступен только внутри приватной сети Compose. Если планируете подключать к этому PostgreSQL что-то ещё, задайте пароль явно через POSTGRES_PASSWORD и пропишите его в DATABASE_URL обоих сервисов — affine и affine_migration.
Образ pgvector/pgvector:pg16 — PostgreSQL 16 с расширением pgvector, которое AFFiNE использует для векторного поиска при включённом AI-ассистенте. Если AI не нужен, AFFINE_INDEXER_ENABLED=false отключает полнотекстовую индексацию и снижает нагрузку — включается обратно сменой значения на true и перезапуском сервиса.
Поднимаем стек:
docker compose up -d
docker compose logs -f affine
Контейнер affine_migration отрабатывает один раз при каждом запуске (применяет миграции схемы БД) и завершается со статусом «успешно» — это штатное поведение service_completed_successfully, а не сбой. Сам сервер affine стартует только после того, как миграция закончена и PostgreSQL с Redis прошли healthcheck.
Первый запуск: администратор и рабочее пространство
Открываем http://<IP-сервера>:3010/admin (именно /admin, а не корень — это важно при первом заходе). AFFiNE предложит создать первую учётную запись — она автоматически становится администратором всего инстанса, отдельного флага «сделать админом» нет, это привязано к самому факту первой регистрации через /admin.
После входа в панель администратора доступны:
- Add User — добавление пользователей вручную по email. Публичной саморегистрации по умолчанию нет: доступ в инстанс получают только те, кого добавил администратор.
- Settings — имя сервера, лимиты на размер файлов, включение AI-функций.
- Workspaces — рабочие пространства на инстансе; по умолчанию одно, дополнительные заводятся под разные команды с изолированными данными.
Дальше заходим на http://<IP-сервера>:3010 под тем же логином — открывается обычный интерфейс. Переключение между режимом документа и Edgeless (холст) — кнопка в правом верхнем углу или Ctrl+Alt+E, весь контент общий для обоих режимов, просто отображается по-разному.
Desktop-клиент для Windows/macOS/Linux — с GitHub Releases проекта; при первом запуске в настройках аккаунта выбираем self-hosted и вводим адрес своего сервера вместо облака AFFiNE.
Домен, HTTPS и config.json
Для продакшена сервер должен знать свой внешний адрес — иначе ссылки на документы, приглашения и вебхуки AI-ассистента будут генерироваться с localhost. Настройка — через config/config.json:
{
"server": {
"name": "AFFiNE",
"externalUrl": "https://affine.your-domain.example"
}
}
После изменения файла контейнер нужно перезапустить, чтобы конфиг подхватился:
docker compose restart affine
Закрываем сервер HTTPS через Caddy — порт 3010 в файле выше уже отдаётся только на 127.0.0.1, наружу пускаем через реверс-прокси:
# /etc/caddy/Caddyfile
affine.your-domain.example {
reverse_proxy 127.0.0.1:3010
}
Если Caddy на сервере ещё не настроен, разбор установки с автоматическим Let's Encrypt есть в отдельной статье про Caddy с авто-SSL на VPS.
AI-ассистент (чат, помощь с текстом, генерация изображений в документе) в self-hosted версии работает по модели BYOK — «принеси свой ключ»: включается в config.json или через панель администратора, но фактические запросы к модели идут с вашим собственным API-ключом (OpenAI, Anthropic и другие поддерживаемые провайдеры). Без ключа фичи AI просто скрыты из интерфейса — базовый функционал документов и досок от этого никак не зависит и работает полностью офлайн от внешних AI-сервисов.
Бэкап и обновление
Состояние AFFiNE разложено по двум местам: содержимое документов и структура — в PostgreSQL, вложения (картинки, файлы) — в каталоге data/storage. Бэкапить нужно оба, и желательно консистентно друг с другом.
Дамп базы данных без остановки сервиса:
docker compose exec postgres pg_dump -U affine affine | gzip > /opt/affine/backups/affine-db-$(date +%F).sql.gz
Архив вложений:
tar czf /opt/affine/backups/affine-storage-$(date +%F).tar.gz -C /opt/affine data/storage
Оба шага стоит выполнять подряд, одной точкой во времени: если между дампом БД и архивом вложений пройдёт заметное время активной работы, теоретически возможна рассинхронизация — документ уже ссылается на вложение, которого ещё нет в архиве. Для регулярного автоматического бэкапа с ротацией и шифрованием удобнее не самописный cron-скрипт, а готовый пайплайн вроде BorgBackup в Docker Compose, настроенный на оба каталога сразу.
Обновление — стандартный pull + up, миграция схемы БД отрабатывает автоматически через контейнер affine_migration при следующем запуске:
docker compose pull
docker compose up -d
Перед обновлением на новую версию имеет смысл сделать свежий дамп базы — миграции схемы применяются автоматически и без подтверждения, штатного отката на предыдущую версию после неудачной миграции не предусмотрено.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли обойтись без PostgreSQL и Redis, оставить только SQLite?
Нет, это обязательные зависимости текущей архитектуры сервера. Нужен более лёгкий стек с однофайловой базой — смотрите Trilium Notes.
Как добавить нового пользователя в команду?
Через панель /admin → Add User, указав email. Публичной саморегистрации нет по умолчанию — доступ выдаёт администратор точечно.
Работает ли AFFiNE без интернета, полностью изолированно?
Документы, доски и совместное редактирование внутри локальной сети — да. Внешний доступ нужен только AI-ассистенту, если он включён: запросы идут к провайдеру модели по вашему ключу.
Что случится с данными при пересоздании контейнеров?
Ничего, пока не тронуты volumes data/postgres, data/storage и config — сами контейнеры состояние не хранят. docker compose down -v данные удаляет, обычный down/up -d — нет.
Чем AFFiNE отличается от связки Outline Wiki и Miro по отдельности?
Специализированные инструменты обычно сильнее в своей нише — Outline Wiki удобнее для чисто текстовой базы знаний. AFFiNE выигрывает тем, что документы и холст живут в одном приложении и одной базе.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →