AFFiNE на сервере: частые ошибки и решения
AFFiNE — это гибрид блокнота, канбан-доски и вики, который многие разворачивают как замену Notion, когда хочется держать данные у себя, а не в чужом облаке. Идея звучит просто: поднял контейнер — получил рабочее пространство. На практике self-hosted установка спотыкается о десяток мелких вещей — от неверных переменных окружения до путаницы между PostgreSQL и встроенным SQLite-режимом. Ниже — конкретные проблемы, с которыми чаще всего сталкиваются на собственном VPS, и как их закрыть без лишних танцев с бубном.
Содержание
- AFFiNE не стартует или контейнер постоянно перезапускается
- Приложение крутит "Loading" бесконечно или белый экран в браузере
- AFFiNE не открывается за реверс-прокси: обрывается синхронизация в реальном времени
- Ошибка подключения к PostgreSQL: `ECONNREFUSED` или `password authentication failed`
- Redis недоступен или синхронизация между вкладками работает через раз
- Документы, вложения или доски пропадают после обновления контейнера
- Медленная работа, зависания при открытии больших досок и высокая нагрузка на CPU
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →AFFiNE не стартует или контейнер постоянно перезапускается
Первое, что стоит сделать при падении — посмотреть логи самого приложения, а не полагаться на статус docker compose ps:
docker compose logs -f affine
Самая частая причина на этапе первого запуска — приложение поднялось раньше, чем PostgreSQL и Redis успели принять соединения. AFFiNE в отличие от некоторых движков не всегда умеет аккуратно ждать и ретраить подключение бесконечно, поэтому контейнер просто падает и уходит в цикл рестарта. Лечится через depends_on с проверкой здоровья зависимостей, а не просто фактом их запуска:
services:
postgres:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U affine"]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 10
affine:
image: ghcr.io/toeverything/affine:stable
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
Второй по частоте случай — нехватка памяти. AFFiNE тянет за собой сервер приложения на Node.js плюс рендеринг документов и синхронизацию, и на VPS с 1 ГБ RAM без свопа это заканчивается тем, что процесс убивает OOM-killer прямо во время старта или первой синхронизации большого документа:
sudo dmesg | grep -i "out of memory"
Если видите в выводе процесс node рядом с меткой контейнера AFFiNE — это не баг конфигурации, а вопрос ресурсов. Для комфортной работы с несколькими пользователями закладывайте от 2 ГБ RAM.
Приложение крутит "Loading" бесконечно или белый экран в браузере
Если контейнер по логам запустился штатно, а браузер показывает вечный спиннер или пустую страницу, почти всегда дело в несовпадении адреса, на который AFFiNE ссылается сама на себя, с тем, по которому вы реально заходите. AFFiNE использует переменную окружения для собственного публичного адреса, и если она указывает на localhost или на внутренний Docker-адрес, а не на реальный домен, фронтенд не может достучаться до API и WebSocket-эндпоинтов:
services:
affine:
environment:
- AFFINE_SERVER_HOST=affine.vash-domen.ru
- AFFINE_SERVER_HTTPS=true
- AFFINE_SERVER_PORT=3010
После смены этих переменных контейнер нужно пересоздать, а не просто перезапустить — часть настроек AFFiNE читает только при старте процесса:
docker compose up -d --force-recreate affine
Второй частый источник белого экрана — ошибки CORS или отказ WebSocket-соединения в консоли браузера. Это почти всегда симптом неправильно настроенного реверс-прокси, а не самого приложения — разбираем в следующем разделе.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверAFFiNE не открывается за реверс-прокси: обрывается синхронизация в реальном времени
AFFiNE активно использует WebSocket для совместного редактирования и живой синхронизации между вкладками и устройствами. Если страница загружается, но документы не синхронизируются между открытыми окнами, а в консоли браузера видна ошибка вида WebSocket connection failed, причина почти всегда в конфиге Nginx, который не пробрасывает заголовки апгрейда протокола:
server {
listen 443 ssl;
server_name affine.vash-domen.ru;
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;
proxy_read_timeout 86400;
}
}
Отдельно обратите внимание на proxy_read_timeout — по умолчанию Nginx закрывает "тихие" соединения через 60 секунд, а WebSocket-канал AFFiNE может подолгу простаивать без трафика, если вы читаете документ, не редактируя его. Без увеличенного таймаута соединение будет незаметно рваться каждую минуту. Общий подход к настройке заголовков разобран в статье Nginx как реверс-прокси на Ubuntu 24.04.
Ошибка подключения к PostgreSQL: `ECONNREFUSED` или `password authentication failed`
AFFiNE в self-hosted режиме умеет работать со встроенным SQLite для одиночного пользователя, но для полноценной командной работы (несколько аккаунтов, совместное редактирование, поиск) нужен внешний PostgreSQL — и именно на его подключении чаще всего спотыкаются при первой настройке.
Проверьте строку подключения в переменных окружения контейнера:
services:
affine:
environment:
- DATABASE_URL=postgresql://affine:ваш_пароль@postgres:5432/affine
Ключевой нюанс — хост в строке подключения должен совпадать с именем сервиса базы данных из docker-compose.yml (в примере выше postgres), а не быть localhost. Внутри контейнера AFFiNE localhost — это сам контейнер приложения, а не соседний контейнер базы. Как создать пользователя и базу с нужными правами — в статье как установить и настроить PostgreSQL на VPS.
Если PostgreSQL развёрнут отдельно от AFFiNE, не в одном docker-compose стеке, убедитесь, что база разрешает подключения по паролю в pg_hba.conf для подсети вашей Docker-сети (узнать её — docker network inspect <имя_сети>):
# /etc/postgresql/16/main/pg_hba.conf
host affine affine 172.18.0.0/16 md5
После правки конфигурации — обязательно перезагрузить PostgreSQL: sudo systemctl reload postgresql.
Redis недоступен или синхронизация между вкладками работает через раз
AFFiNE использует Redis для очередей задач и части realtime-синхронизации, и если он недоступен, симптомы бывают неочевидными: приложение вроде бы работает, но изменения в одном окне появляются в другом с большой задержкой или не появляются вовсе.
Проверьте, что переменная подключения к Redis указывает на имя сервиса, а не на localhost, по той же логике, что и с PostgreSQL:
services:
affine:
environment:
- REDIS_SERVER_HOST=redis
- REDIS_SERVER_PORT=6379
Быстрая диагностика — зайти в контейнер Redis и проверить, что он отвечает и не завален соединениями:
docker exec -it affine-redis-1 redis-cli ping
docker exec -it affine-redis-1 redis-cli info clients
Если Redis отвечает PONG, но проблема сохраняется, проверьте политику вытеснения ключей — allkeys-lru, удобная для кеша, для очереди задач AFFiNE не годится и может стереть ещё не обработанные задания синхронизации под нагрузкой:
maxmemory-policy noeviction
Документы, вложения или доски пропадают после обновления контейнера
Это самая болезненная ошибка, потому что обнаруживается не сразу — обычно через дни или недели, когда нужно открыть документ, а его нет. Причина почти всегда одна и та же: данные хранились не в именованном Docker volume, а в слое контейнера, и при пересоздании (обновление образа, docker compose up --force-recreate) всё, что не вынесено наружу, исчезает безвозвратно.
Убедитесь, что все каталоги с состоянием явно вынесены в volumes — это касается не только PostgreSQL, но и локального хранилища файлов и вложений AFFiNE, если вы не используете внешний S3-совместимый бакет:
services:
postgres:
volumes:
- affine-db:/var/lib/postgresql/data
affine:
volumes:
- affine-storage:/root/.affine/storage
- affine-config:/root/.affine/config
volumes:
affine-db:
affine-storage:
affine-config:
Проверить, что volume действительно используется, а не создаётся заново пустым: docker volume ls | grep affine и docker volume inspect affine-storage.
И даже с правильными volumes рекомендация простая — регулярный бэкап и базы, и файлового хранилища перед каждым обновлением образа, а не раз в месяц "на всякий случай":
docker exec affine-postgres-1 pg_dump -U affine affine > affine_backup_$(date +%F).sql
docker run --rm -v affine-storage:/data -v $(pwd):/backup alpine \
tar -czf /backup/affine_storage_$(date +%F).tar.gz -C /data .
Общий подход к бэкапу Docker-томов и типовые ошибки в этом процессе разобраны в статье бэкап Docker volume на сервере: частые ошибки и решения.
Медленная работа, зависания при открытии больших досок и высокая нагрузка на CPU
По мере роста базы документов и особенно при активном использовании whiteboard-режима с большим количеством элементов на одной доске AFFiNE может начать заметно тормозить — задержка при открытии документа, подвисания при скролле доски, рост нагрузки на CPU сервера.
Первое, что стоит проверить — не упирается ли PostgreSQL в ресурсы. Как и в любом приложении на реляционной базе, при недостатке RAM под shared_buffers и effective_cache_size запросы начинают чаще идти на диск, и это заметно на глаз именно как "тормозит интерфейс", хотя причина в базе:
docker exec -it affine-postgres-1 psql -U affine -c "SELECT state, count(*) FROM pg_stat_activity GROUP BY state;"
Много соединений в состоянии idle in transaction или завышенное число активных запросов — повод пересмотреть настройки PostgreSQL под доступную память, а не искать проблему в самом AFFiNE.
Второе — сами по себе очень большие доски (тысячи элементов в одном whiteboard-документе) нагружают в первую очередь браузер клиента при рендеринге, а не сервер, и апгрейд VPS тут не поможет — стоит разбивать такие доски на несколько связанных документов. Точный порог, при котором доска становится "тяжёлой", зависит от количества и типа элементов, это лишь ориентир.
Третье — если тормозит именно первая загрузка, а не работа с документами, проверьте, что контейнер не делит CPU с другими тяжёлыми сервисами на том же VPS: docker stats быстро покажет, кто реально ест ресурсы.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
AFFiNE бесплатная для self-hosted?
Да, основная функциональность распространяется под открытой лицензией, исходники доступны на GitHub. Часть облачных функций официального SaaS в self-hosted версии реализуется иначе — через ваш собственный Redis и PostgreSQL.
Можно ли обойтись без PostgreSQL и Redis?
Для одного пользователя AFFiNE может работать на встроенном SQLite без внешней базы, но для команды с совместным редактированием нужен полноценный стек с PostgreSQL и Redis — это официально поддерживаемая конфигурация.
Нужен ли обязательно SSL-сертификат?
Да — большая часть браузерных API для realtime-синхронизации корректно работает только по HTTPS. Проще всего через Let's Encrypt с автопродлением, типовые проблемы разобраны в статье Let's Encrypt SSL на сервере: частые ошибки и решения.
Сколько ресурсов нужно для команды из 5-10 человек?
Обычно достаточно 2 vCPU и 2-4 ГБ RAM при PostgreSQL и Redis на той же машине. Для большего числа пользователей и активной работы с whiteboard закладывайте больше — точная цифра зависит от объёма контента, это ориентир.
Как перенести AFFiNE на новый сервер без потери данных?
Переносится дамп PostgreSQL и содержимое volume с файловым хранилищем. Оба компонента обязательны — база без вложений или вложения без базы дадут неполный перенос.
AFFiNE поддерживает импорт из Notion?
Да, есть встроенный импорт workspace через экспортированный архив. На больших базах процесс может занять заметное время, стоит тестировать на копии перед переносом рабочей базы.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →