MAATRIX / Блог / Как установить и настроить AFFiNE на VPS

Как установить и настроить AFFiNE на VPS

MAATRIX

Notion удобен, пока не упираешься в цену подписки за команду, лимиты блоков на бесплатном плане и мысль о том, что все заметки и документы лежат на чужих серверах в другой юрисдикции. AFFiNE — открытый инструмент, который пытается закрыть ту же нишу: документы, канбан-доски и базы данных в одном рабочем пространстве, но развёрнутом на вашем VPS, где данные принадлежат только вам. Разберём, как поставить его через Docker Compose, настроить домен с HTTPS и не потерять данные при первом обновлении.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое AFFiNE и когда он оправдан вместо Notion

AFFiNE — open-source редактор рабочего пространства, который объединяет три инструмента сразу: блочный документ-редактор (как в Notion), канбан-доски для задач и bidirectional-ссылки между страницами (как в Obsidian). Один и тот же контент можно переключать между режимом документа и режимом визуального холста — это фирменная фишка проекта, которой нет ни у Notion, ни у Outline.

Из практических отличий, которые важны при выборе self-host варианта:

  • вход по обычному email и паролю работает из коробки — не нужен внешний OAuth-провайдер, как в Outline, первый зарегистрированный пользователь становится администратором рабочего пространства;
  • есть локальный режим без сервера вовсе (данные в браузере/десктоп-приложении) и облачный self-host режим с синхронизацией между устройствами — статья про второй, он и даёт смысл держать VPS;
  • редактор написан на CRDT (Yjs) — это тот же класс технологий, что у Google Docs для совместного редактирования, конфликтов при одновременной правке практически не возникает;
  • проект молодой и активно меняется: между релизами бывают миграции схемы базы и правки формата хранения, поэтому бэкапы перед обновлением — не формальность, а необходимость (подробнее — в разделе про бэкапы).

Из ограничений: по сравнению с Notion экосистема интеграций и готовых шаблонов заметно скромнее, а сообщество self-host пользователей меньше, чем у зрелых проектов вроде Outline или Wiki.js — если что-то ломается на нестандартной конфигурации, ответ на форуме можно ждать дольше. Для команды или соло-пользователя, который хочет держать заметки и канбан под своим контролем и готов иногда следить за обновлениями руками, это разумный компромисс.

Требования к серверу и подготовка VPS

AFFiNE в self-host режиме — это сам сервер плюс PostgreSQL и Redis, то есть по составу стек похож на Outline, но интерфейс заметно тяжелее по фронтенду (полноценный canvas-редактор в браузере), поэтому закладывайте запас по CPU для рендеринга у клиентов, а не только по памяти сервера.

Стартовая конфигурация для соло-пользователя или небольшой команды до 10-15 человек:

  • 2 vCPU, 4 ГБ RAM — меньше тоже запустится, но при активной синхронизации нескольких клиентов сервер начинает подтормаживать;
  • 20-30 ГБ SSD — сам сервис лёгкий, место съедают вложения (картинки, файлы в документах) и дампы базы для бэкапов;
  • Ubuntu 24.04 LTS или Debian 12;
  • домен или поддомен, направленный на IP сервера, например notes.example.com — без HTTPS часть функций (загрузка вложений, PWA-режим) работает нестабильно.

Обновите систему и, если Docker ещё не установлен, поставьте его — порядок с нуля для Ubuntu и Debian разобран в статье установка Docker с нуля:

apt update && apt upgrade -y
adduser deploy
usermod -aG sudo,docker deploy

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Установка AFFiNE через Docker Compose

Официальный self-host вариант AFFiNE состоит из трёх контейнеров: сам сервер, PostgreSQL для данных и Redis для очередей и кэша сессий. Создайте директорию проекта:

mkdir -p /opt/affine/{config,storage,pgdata}
cd /opt/affine

Файл docker-compose.yml:

# /opt/affine/docker-compose.yml
services:
  affine:
    image: ghcr.io/toeverything/affine-graphql:stable
    container_name: affine
    restart: unless-stopped
    ports:
      - "3010:3010"
      - "5555:5555"
    volumes:
      - ./config:/root/.affine/config
      - ./storage:/root/.affine/storage
    environment:
      - REDIS_SERVER_HOST=redis
      - DATABASE_URL=postgresql://affine:${POSTGRES_PASSWORD}@postgres:5432/affine
      - AFFINE_SERVER_HOST=notes.example.com
      - AFFINE_SERVER_HTTPS=true
      - NODE_OPTIONS=--max-old-space-size=1024
    depends_on:
      redis:
        condition: service_started
      postgres:
        condition: service_healthy
      migration:
        condition: service_completed_successfully

  migration:
    image: ghcr.io/toeverything/affine-graphql:stable
    command: ["sh", "-c", "node ./scripts/self-host-predeploy.js"]
    environment:
      - REDIS_SERVER_HOST=redis
      - DATABASE_URL=postgresql://affine:${POSTGRES_PASSWORD}@postgres:5432/affine
    depends_on:
      redis:
        condition: service_started
      postgres:
        condition: service_healthy

  redis:
    image: redis:7-alpine
    container_name: affine_redis
    restart: unless-stopped

  postgres:
    image: postgres:16-alpine
    container_name: affine_postgres
    restart: unless-stopped
    environment:
      - POSTGRES_USER=affine
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=affine
    volumes:
      - ./pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U affine -d affine"]
      interval: 10s
      timeout: 5s
      retries: 5

Замените notes.example.com на реальный домен и сгенерируйте пароль базы в .env рядом с compose-файлом:

echo "POSTGRES_PASSWORD=$(openssl rand -base64 24)" > .env
chmod 600 .env

Запуск:

docker compose up -d
docker compose logs -f affine

Контейнер migration должен один раз отработать и завершиться со статусом Exited (0) — это нормально, он прогоняет миграции схемы и выходит. Если в логах affine видно, что сервер поднялся на порту 3010 без ошибок подключения к базе, можно переходить к первому запуску.

Важный нюанс с версиями: тег stable подтягивает последний стабильный релиз при каждом docker compose pull, что удобно для быстрого старта, но неудобно для предсказуемых обновлений — на проде разумнее зафиксировать конкретный тег образа из релизов проекта и обновлять его осознанно, а не при случайном pull.

Домен, TLS и реверс-прокси

AFFiNE слушает 3010 (веб-интерфейс и API) и 5555 (WebSocket для realtime-синхронизации документов) на самом сервере. Наружу оба порта нужно отдать через реверс-прокси с TLS-сертификатом — без этого совместное редактирование через WebSocket может не подниматься из-за смешанного контента (HTTPS-страница, но незашифрованный WS).

Проще всего — через Caddy, он сам получает и продлевает сертификат Let's Encrypt; подробности установки в статье установка и настройка Caddy с авто-SSL на VPS. Минимальный Caddyfile:

notes.example.com {
    reverse_proxy /graphql* 127.0.0.1:3010
    reverse_proxy /socket.io* 127.0.0.1:5555
    reverse_proxy 127.0.0.1:3010
}

Если вы уже используете Nginx под другие сайты на этом VPS, то же самое можно сделать классическим реверс-прокси с явным пробросом заголовков апгрейда для WebSocket — общий подход разобран в статье Nginx как реверс-прокси на VPS, для AFFiNE в блок location достаточно добавить proxy_set_header Upgrade $http_upgrade; и proxy_set_header Connection "upgrade"; для пути /socket.io/.

Перезапустите прокси-сервер, откройте https://notes.example.com — при первом заходе AFFiNE покажет форму создания администратора: email, пароль, название рабочего пространства. Это отличие от Outline, где нужен внешний OAuth ещё до первого входа, — здесь достаточно свежего сервера и открытого домена.

Первая настройка и переход с Notion

После создания администратора стоит сразу проверить несколько вещей:

  • регистрацию новых пользователей — по умолчанию в некоторых сборках она открыта всем, кто попадёт на домен, для приватного инстанса её стоит выключить в настройках рабочего пространства и добавлять участников по прямому приглашению;
  • SMTP для писем-приглашений и уведомлений — без него новые участники не получат ссылку на вход;
  • лимит на размер вложений — по умолчанию он рассчитан на разумные файлы, для сканов и больших PDF имеет смысл проверить настройку до того, как кто-то упрётся в отказ загрузки.

Перенос из Notion делается через экспорт рабочего пространства Notion в формате Markdown & CSV и последующий импорт в AFFiNE — структура страниц и вложенные документы переносятся достаточно надёжно, а вот сложные блоки (связанные базы данных, формулы, синхронизированные блоки) стоит проверить вручную после импорта: конвертация форматов между разными редакторами никогда не бывает стопроцентной.

Бэкап данных и обновление без потерь

Всё содержимое AFFiNE живёт в двух местах: PostgreSQL (структура документов, метаданные, права) и volume storage (бинарные вложения — картинки, файлы). Бэкапить нужно оба места согласованно.

Дамп базы:

docker compose exec postgres pg_dump -U affine affine > /opt/affine/backups/affine-$(date +%F).sql

Резервная копия вложений — обычный архив volume:

tar czf /opt/affine/backups/storage-$(date +%F).tar.gz -C /opt/affine storage

Обе команды стоит собрать в один cron-скрипт с ротацией старых копий и, желательно, выгрузкой архивов за пределы самого VPS — если диск сервера умрёт вместе с бэкапами на нём же, толку от такого бэкапа не будет.

Перед обновлением образа — особенно с учётом того, что проект активно развивается и между версиями случаются миграции схемы — обязательно снимайте свежий дамп прямо перед pull:

docker compose exec postgres pg_dump -U affine affine > pre-update-backup.sql
docker compose pull
docker compose up -d

Контейнер migration снова отработает при старте и применит накопившиеся изменения схемы автоматически. Если после обновления сервер не поднимается или в логах видны ошибки миграции — откатите тег образа на предыдущий рабочий и восстановите базу из дампа, снятого перед обновлением, а уже потом разбирайтесь с причиной на тестовом окружении.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Чем AFFiNE принципиально отличается от Outline и Notion?

AFFiNE совмещает документ-редактор, канбан и граф связей в одном приложении с переключением видов, тогда как Outline — специализированная вики для документации, а Notion — облачный сервис с похожим набором функций, но без self-host варианта.

Нужен ли OAuth-провайдер для входа, как в Outline?

Нет, у AFFiNE встроенная авторизация по email и паролю, внешний провайдер не обязателен — это упрощает первый запуск.

Можно ли запустить AFFiNE без Postgres и Redis, совсем просто?

Есть локальный режим (браузер или десктоп-приложение) без сервера вовсе, но там нет синхронизации между устройствами и совместной работы — для этого и нужен self-host стек, описанный выше.

Как перенести существующие заметки из Notion?

Экспортируйте рабочее пространство Notion в Markdown & CSV и импортируйте архив в AFFiNE — простые страницы и структура переносятся хорошо, сложные блоки (связанные базы, формулы) проверьте вручную после импорта.

Что делать, если после обновления сервер не стартует?

Проверьте логи контейнера migration на ошибки схемы, при необходимости откатите тег образа в docker-compose.yml на предыдущую рабочую версию и восстановите базу из дампа, снятого перед обновлением.

Сколько RAM нужно, если в команде 30-50 человек?

Точных цифр без вашей реальной нагрузки никто не даст — начните с 4 vCPU/8 ГБ RAM и следите за потреблением PostgreSQL и самого контейнера affine, при активной совместной работе именно они растут первыми.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →