SeaTable на сервере: частые ошибки и решения
Разворачиваете SeaTable через docker-compose, а вместо рабочей таблицы-базы получаете белый экран, «Can't connect to MySQL server» или контейнер, который падает через десять минут после старта. SeaTable — self-hosted альтернатива Airtable: таблицы с типами полей, связями между строками, представлениями и автоматизациями, но собранная не из одного приложения, а из связки сервисов — веб-часть, MySQL, memcached, опционально Elasticsearch для поиска. Любая нестыковка между ними и ломает установку. Ниже — конкретные ошибки, с которыми чаще всего сталкиваются при self-hosted развёртывании SeaTable, и рабочие решения для каждой.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Установка: типовые ошибки на старте
SeaTable Community Edition ставится либо официальным install-скриптом (генерирует docker-compose.yml и seatable.env в отдельной директории вроде /opt/seatable-server), либо вручную из готового docker-compose.yml. Половина проблем возникает ещё до первого запуска:
- Мало ресурсов. Для community-инсталляции с реальной нагрузкой нужно минимум 2 vCPU и 4 ГБ RAM — на 1 ГБ приложение стартует, но при первой синхронизации таблиц или экспорте контейнер уходит в OOM. Проверьте перед установкой:
free -h
df -h /opt
nproc
- Заняты порты 80/443. Если на сервере уже висит nginx или другой веб-сервер, скрипт установки SeaTable (который поднимает свой reverse-proxy контейнер) не сможет забиндиться на порт и упадёт с ошибкой
bind: address already in use. Проверка:
ss -tlnp | grep -E ':80|:443'
Либо останавливайте системный nginx на время установки, либо ставьте SeaTable за уже существующим reverse-proxy, вручную прописывая проксирование на внутренний порт контейнера.
- Старая версия Docker. SeaTable активно использует
healthcheckиdepends_on: condition: service_healthyв compose-файле — это синтаксис Compose V2. На старомdocker-compose(обёртка на Python 1.x) конфиг может просто не подняться с невнятной ошибкой парсинга YAML. Ставьте актуальный Docker Engine с плагиномdocker compose(без дефиса), а не отдельный пакетdocker-compose.
Если ставите SeaTable «с нуля» на голый VPS, полезно сначала свериться с общей схемой продакшен-развёртывания через Compose — там разобраны сети, volume и порядок запуска сервисов, актуальные для любого многоконтейнерного приложения: Docker Compose для продакшена: частые ошибки и решения.
«Can't connect to MySQL server» и проблемы с базой
Самая частая ошибка на первом запуске. Причины делятся на три группы.
1. Контейнер с приложением стартует раньше, чем MySQL готов принимать соединения. MySQL внутри контейнера может уже отвечать на пинг, но ещё не завершил инициализацию (создание таблиц, применение прав). Если в вашем docker-compose.yml нет healthcheck для сервиса db или depends_on не использует condition: service_healthy, приложение просто не дождётся базы. Минимальный рабочий вариант:
services:
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWD}
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 12
volumes:
- ./mysql-data:/var/lib/mysql
seatable:
image: seatable/seatable-server:latest
depends_on:
db:
condition: service_healthy
env_file: seatable.env
2. Пароль в .env изменили после первого запуска. Переменные вида DB_ROOT_PASSWD и пароль пользователя БД читаются образом MySQL только при инициализации пустого volume — то есть один раз, при первом старте контейнера. Если вы позже поменяли пароль в seatable.env и перезапустили стек, приложение будет стучаться с новым паролем в базу, где всё ещё действует старый. Решение — либо зайти в контейнер и сменить пароль штатным способом MySQL, либо (если данные ещё не жалко) удалить volume базы и поднять с нуля:
docker compose exec db mysql -uroot -p
# внутри: ALTER USER 'root'@'%' IDENTIFIED BY 'новый_пароль';
3. База на внешнем сервере, а не в контейнере. Если вы намеренно выносите MySQL на отдельный сервер (разумно при заметной нагрузке), проверьте, что в seatable.env хост базы указывает на реальный IP или DNS-имя, а не на db (алиас докер-сети, который работает только между контейнерами одного compose-стека), и что на стороне MySQL пользователю разрешён доступ не с localhost, а с IP вашего SeaTable-сервера (GRANT ... TO 'user'@'10.0.0.5'). Общие принципы диагностики MySQL — прав, bind-address, лимитов соединений — разобраны отдельно: MySQL на сервере: частые ошибки и решения.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать сервер502 Bad Gateway и белый экран после открытия домена
Установка прошла без ошибок в логах, контейнеры «healthy», но по адресу сервера — 502 или пустая белая страница. Разбирайте по шагам.
DNS ещё не указывает на сервер. SeaTable при первом запуске (если используется встроенный Caddy для автоматического SSL) пытается получить сертификат Let's Encrypt для домена из SEATABLE_SERVER_HOSTNAME. Если A-запись домена ещё не обновилась или указывает на другой IP, выпуск сертификата падает, а вместе с ним и весь reverse-proxy слой. Проверка:
dig +short ваш-домен.ru
curl -I https://ваш-домен.ru
Если IP не совпадает с адресом сервера — сначала чините DNS, потом перезапускайте стек.
SEATABLE_SERVER_HOSTNAME не совпадает с реальным доменом. SeaTable подставляет это значение во внутренние ссылки (API, ссылки для шаринга, вебхуки). Если в браузере вы открываете seatable.example.com, а в .env прописан 192.168.1.10 или старый домен — получите белый экран или бесконечные редиректы, потому что фронтенд обращается к API по неверному хосту. После правки переменной обязательно пересоздайте контейнеры, а не просто перезапустите:
docker compose down
docker compose up -d
Логи как источник истины. Не гадайте — смотрите логи прокси-слоя и приложения:
docker compose logs -f caddy
docker compose logs -f seatable
Если используете собственный nginx перед SeaTable вместо встроенного Caddy, убедитесь, что заголовки Host, X-Forwarded-Proto и X-Forwarded-For прокидываются — без них внутренние редиректы SeaTable уходят на http:// вместо https://, и браузер блокирует mixed content. Про выбор и настройку инструмента выпуска сертификатов — отдельно: Certbot или acme.sh: что выбрать для сервера.
Ошибки загрузки файлов и вложений
Таблицы с вложениями и картинками в ячейках — то, ради чего многие и выбирают SeaTable вместо голой БД. Загрузка файлов ломается по трём типовым причинам.
Лимит размера тела запроса в reverse-proxy. Если перед SeaTable стоит свой nginx, а не встроенный Caddy, по умолчанию client_max_body_size в nginx — 1 МБ. Любое вложение крупнее падает с 413 Request Entity Too Large:
location / {
proxy_pass http://127.0.0.1:8000;
client_max_body_size 200m;
}
Кончилось место на диске под данные. Файлы и вложения SeaTable хранит в volume приложения (обычно /opt/seatable-server/shared или аналогичный путь, заданный в compose-файле), и при заполнении диска загрузка молча обрывается или падает с ошибкой 500. Проверяйте регулярно, не только когда что-то сломалось:
df -h
du -sh /opt/seatable-server/shared/* | sort -rh | head -10
Права на директорию данных. После ручного переноса данных между серверами (например, rsync с сохранением владельца) файлы могут остаться с чужим UID, а процесс внутри контейнера пишет от другого пользователя. Результат — вложения загружаются, но не открываются, либо загрузка падает с правами доступа. Проверьте владельца каталога данных снаружи контейнера и синхронизируйте с тем, что ожидает образ (обычно это описано в документации конкретной версии образа, но чаще всего достаточно chown -R 999:999 либо того UID, что показывает docker compose exec seatable id).
Память заканчивается, контейнеры перезапускаются
SeaTable Community — это связка веб-приложения, MySQL, memcached и, если включён полнотекстовый поиск, Elasticsearch — а он один способен съедать 1-2 ГБ на пустом месте. На VPS с 2-4 ГБ RAM это частая причина циклических перезапусков контейнеров.
Диагностика — кто именно съедает память:
docker stats --no-stream
dmesg -T | grep -i "killed process"
Если в dmesg видите Out of memory: Killed process рядом с именем контейнера — это стопроцентно OOM, а не баг приложения. Варианты решения:
- Отключить Elasticsearch, если полнотекстовый поиск по вложениям и большим таблицам не критичен — уберите соответствующий сервис из
docker-compose.ymlи связанные переменные из.env. Это самая заметная экономия памяти на маленьком сервере. - Добавить своп — не панацея для постоянной нагрузки, но снимает пиковые всплески при импорте больших таблиц или генерации отчётов:
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
- Ограничить память контейнеров явно, чтобы один прожорливый сервис не убивал соседей через общий OOM killer хоста:
services:
seatable:
deploy:
resources:
limits:
memory: 1500M
- Апгрейднуть сервер, если реально работаете с большими таблицами и десятками пользователей — для community-инсталляции с полным стеком (приложение + MySQL + Elasticsearch) комфортный минимум — 4 vCPU и 8 ГБ RAM, это ориентир, а не гарантированная цифра под вашу нагрузку.
Ошибки при обновлении версии
Обновление SeaTable — обычно запуск скрипта апгрейда поверх существующей установки, который прогоняет миграции базы данных. Здесь два правила, которые экономят нервы.
Бэкап перед любым обновлением — обязателен, не опционален. Миграция базы может упасть на середине из-за нехватки места, обрыва соединения или несовместимости данных, и откатить состояние без бэкапа будет нечем. Минимальный набор перед апгрейдом:
docker compose exec db mysqldump -uroot -p --all-databases > seatable-backup-$(date +%F).sql
tar czf seatable-data-$(date +%F).tar.gz /opt/seatable-server/shared
Пиновайте версию образа, а не latest. Если в compose-файле указано seatable/seatable-server:latest, обычный docker compose pull && docker compose up -d может утащить вас на мажорную версию с несовместимой схемой БД без предупреждения. Указывайте конкретный тег версии и обновляйтесь осознанно, читая release notes перед апгрейдом, а не постфактум разбирая, что сломалось.
Если миграция всё же упала посреди процесса — не пытайтесь «долечить» текущее состояние вручную правкой таблиц в БД. Разворачивайте бэкап на чистом volume и повторяйте апгрейд уже с пониманием, на каком шаге он ломается — обычно это видно прямо в логе миграционного контейнера.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько RAM нужно для SeaTable?
Для теста хватает 2 ГБ, для рабочей инсталляции с несколькими пользователями и Elasticsearch комфортнее 4-8 ГБ — ориентир, реальная цифра зависит от объёма таблиц и числа одновременных пользователей.
Можно ли использовать внешний MySQL вместо контейнера из compose-файла?
Да. Укажите в .env хост, порт и учётные данные внешней базы вместо алиаса db, и создайте пользователя с правами на IP вашего SeaTable-сервера, а не только на localhost.
Нужен ли Elasticsearch для работы SeaTable вообще?
Нет, базовая работа с таблицами и автоматизациями его не требует — он нужен только для полнотекстового поиска по вложениям. На маленьком сервере его разумно отключить.
Чем SeaTable отличается от NocoDB и Baserow как self-hosted решение?
Архитектурно SeaTable тяжелее (больше сервисов в стеке), но сильнее в работе с большими таблицами и автоматизациями «из коробки». Сравнение по требованиям к ресурсам и функциональности: NocoDB или Baserow: что выгоднее и когда.
Как быстро проверить, что именно упало, если сайт недоступен?
Начните с docker compose ps — сразу видно, какой контейнер не healthy, а дальше docker compose logs -f <имя_сервиса> для конкретного сервиса.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →