MAATRIX / Блог / Focalboard на сервере: частые ошибки и решения

Focalboard на сервере: частые ошибки и решения

MAATRIX

Focalboard — канбан-доски, таблицы и календарь в одном self-hosted инструменте, без месячной платы за место в Trello или Asana. Разворачивается за десять минут через Docker, но именно на «после установки» приходится большинство вопросов: доска открывается, а карточки не обновляются в реальном времени, вложения исчезают после перезапуска, вход зависает на редиректе. Разбираем, откуда растут эти проблемы и как их закрыть на своём сервере.

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

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

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

Реальное время не работает: WebSocket и reverse proxy

Самая частая жалоба — доска открывается, но изменения коллег не появляются без ручного обновления страницы. Focalboard держит соединение с бэкендом через WebSocket, и если сервер стоит за nginx или Traefik без явного проброса апгрейда протокола, соединение откатывается на обычный HTTP-опрос или вовсе рвётся по таймауту.

Для nginx нужен блок с явным Upgrade/Connection и увеличенным таймаутом — дефолтные 60 секунд Focalboard превышает на любой более-менее «долгой» вкладке:

server {
    listen 443 ssl http2;
    server_name boards.example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        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 3600s;
        proxy_send_timeout 3600s;
    }
}

Если фронт — Traefik, аналогичный эффект даёт метка traefik.http.services.focalboard.loadbalancer.server.port плюс включённый по умолчанию проброс WebSocket (Traefik делает это сам, но проверьте, что перед ним нет промежуточного CDN или второго nginx, который режет Upgrade-заголовок — такое бывает, когда сервер арендован с уже настроенным edge-прокси провайдера). Проверить факт разрыва просто: откройте вкладку Network в браузере, найдите запрос к /ws — если статус не 101 Switching Protocols, а обрывается или уходит в polling, дело именно в прокси, а не в самом Focalboard.

Путаница между «личным сервером» и командным режимом

У Focalboard исторически было два режима работы: одиночный локальный экземпляр без логина (для личного использования на одной машине) и серверный режим с регистрацией пользователей и командами — именно его вы получаете, разворачивая Docker-образ на VPS. Часть проблем «не могу зарегистрироваться» или «после установки сразу просит логин, а я думал будет как в десктоп-версии» — следствие путаницы между этими сценариями: в серверном режиме первый зарегистрированный пользователь автоматически становится системным администратором, а следующие требуют либо открытой регистрации, либо приглашения.

Если регистрация выключена и админ не назначен заранее, разумный порядок такой:

  1. Поднимите контейнер, зайдите на https://ваш-домен/.
  2. Зарегистрируйте первого пользователя — он получит права системного администратора автоматически.
  3. В административной панели (/admin) включите или выключите открытую регистрацию в зависимости от того, нужен ли самостоятельный сайн-ап остальным членам команды.
  4. Для закрытой команды удобнее выключить регистрацию и рассылать инвайт-ссылки на конкретную команду (workspace) вручную.

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

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

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

SQLite упирается в потолок: миграция на PostgreSQL

По умолчанию Focalboard пишет в SQLite-файл — этого достаточно для одного-двух пользователей, но при параллельной работе нескольких человек с активным редактированием таблиц периодически всплывает database is locked: SQLite не рассчитан на конкурентную запись из нескольких горутин одновременно, а WebSocket-сессии Focalboard пишут в базу постоянно.

Решение — перевести бэкенд на PostgreSQL. Общая логика для docker-compose:

services:
  db:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_DB: focalboard
      POSTGRES_USER: focalboard
      POSTGRES_PASSWORD: замените-на-свой-пароль
    volumes:
      - ./data/postgres:/var/lib/postgresql/data

  focalboard:
    image: mattermost/focalboard:latest
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "127.0.0.1:8000:8000"
    volumes:
      - ./data/files:/opt/focalboard/files
      - ./config.json:/opt/focalboard/config.json

В config.json меняете dbtype на postgres, а dbconfig — на строку подключения вида postgres://focalboard:пароль@db:5432/focalboard?sslmode=disable. Точные ключи и пути внутри образа стоит свериться с README конкретного тега — с 2023 года проект Focalboard как отдельный репозиторий архивирован (функциональность перешла в состав Mattermost Boards), поэтому образы на Docker Hub с тех пор не обновляются активно, а структура конфига могла отличаться между последними релизами. Перед миграцией сделайте дамп текущей SQLite-базы (sqlite3 focalboard.db .dump > backup.sql) — так вы не потеряете данные, если строка подключения окажется неверной с первого раза.

Если поднимаете PostgreSQL заодно и для других сервисов на том же сервере, конфигурацию и типичные грабли самого PostgreSQL разумно сверить отдельно — например, в материале про PostgreSQL на сервере: частые ошибки и решения.

Вложения и файлы пропадают после рестарта контейнера

Классическая ошибка Docker-новичков — вложения к карточкам (картинки, документы) хранятся Focalboard в отдельной директории files, и если она не вынесена в volume, при пересоздании контейнера (например, после docker compose pull && docker compose up -d) все файлы теряются, хотя сами карточки и текст сохраняются — они лежат в базе данных, а не в файловой системе контейнера.

Проверьте, что в docker-compose явно проброшена директория файлов и она не совпадает по правам с пользователем внутри контейнера:

volumes:
  - ./data/files:/opt/focalboard/files

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

docker exec -it focalboard ls -la /opt/focalboard/files

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

mkdir -p data/files
chown -R 2000:2000 data/files   # UID/GID зависят от конкретного образа — сверьте в его документации

Отдельно стоит регулярно выносить и files, и дамп базы в общий бэкап — если сервер не бэкапится штатно провайдером, настройте это руками, как описано в общем гайде про бэкап и восстановление на сервере.

HTTPS, secure cookies и вечный редирект на страницу входа

Если Focalboard стоит за reverse proxy с SSL, а поле serverRoot в config.json указывает на http:// вместо https:// (или вообще на localhost), пользователи будут раз за разом попадать на страницу логина даже с правильным паролем — сессионная кука выставляется на неверный домен/схему, браузер её просто не принимает или не отправляет обратно.

Правило простое: serverRoot должен буква в букву совпадать с тем адресом, который пользователь вводит в браузере — с протоколом, доменом и без завершающего слэша, если остальная конфигурация его не подразумевает:

{
  "serverRoot": "https://boards.example.com",
  "useSSL": false
}

useSSL внутри самого Focalboard в большинстве схем оставляют выключенным — TLS терминируется на nginx/Traefik перед контейнером, а сам Focalboard слушает обычный HTTP на локальном порту. Включать useSSL в конфиге приложения имеет смысл, только если сертификаты монтируются прямо в контейнер и прокси перед ним нет вовсе — такая схема встречается реже и усложняет продление сертификатов Let's Encrypt. Если сертификаты в принципе не выпускаются или не обновляются, это уже отдельная тема — общие причины разобраны в статье про Let's Encrypt SSL на сервере.

Бэкап, перенос и обновления в условиях архивного репозитория

Раз апстрим Focalboard как отдельного продукта не развивается, тег latest в docker-compose — плохая идея: неизвестно, что именно он подтянет в следующий раз и подтянет ли вообще что-то новое. Зафиксируйте конкретный тег образа, который проверили сами, и обновляйте его осознанно, а не автоматически через docker compose pull по расписанию.

Минимальный набор для переноса на другой сервер или для холодного бэкапа:

# Бэкап
docker exec focalboard sqlite3 /opt/focalboard/data/focalboard.db ".backup /opt/focalboard/data/backup.db"
tar czf focalboard-backup.tar.gz data/files data/backup.db config.json

# Восстановление на новом сервере
tar xzf focalboard-backup.tar.gz
docker compose up -d

Если база уже на PostgreSQL, вместо sqlite3 используйте штатный pg_dump/pg_restore — это надёжнее при большом объёме данных и не требует останавливать контейнер приложения на время снятия дампа. Общую схему настройки самого сервера под такие сервисы — домен, firewall, базовые пакеты — стоит один раз пройти по чек-листу вроде настройки домена и DNS с нуля, а порты наружу закрыть штатным файрволом, оставив открытыми только 80/443, как описано в материале про UFW на сервере.

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

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

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

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

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

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

Focalboard ещё поддерживается разработчиком?

Как отдельный проект — нет, репозиторий архивирован, функциональность ушла в состав Mattermost Boards. Как standalone-сервис он по-прежнему работает и подходит для небольших команд, но не ждите новых версий и патчей безопасности от апстрима — обновляйте систему и Docker-рантайм сами, а образ приложения фиксируйте на проверенном теге.

Можно ли обойтись без reverse proxy и просто открыть порт 8000 наружу?

Технически да, но тогда трафик идёт без TLS, а браузеры и корпоративные политики всё активнее блокируют функциональность на незащищённых страницах. Даже для внутреннего инструмента разумнее поставить nginx с бесплатным сертификатом Let's Encrypt перед приложением.

Сколько ресурсов реально нужно серверу под Focalboard?

Для команды в 5-15 человек хватает 1-2 vCPU и 1-2 ГБ RAM с запасом под PostgreSQL — точные цифры зависят от объёма вложений и интенсивности одновременной работы, ориентируйтесь на этот диапазон и мониторьте нагрузку в первые недели.

Как перенести доски из Trello в Focalboard?

В интерфейсе есть штатный импорт из экспортированного JSON Trello-доски — экспортируйте доску из Trello (Меню → Ещё → Печать и экспорт → Экспорт в JSON) и загрузите файл через меню импорта в Focalboard. Часть метаданных (например, история активности) при этом не переносится.

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

Сначала откатитесь на предыдущий тег образа, который точно работал, и только потом разбирайтесь — поскольку новые версии официально не тестируются командой Mattermost под standalone-режим, миграции схемы базы между релизами иногда ломают совместимость назад.

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

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

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