Всем привет, с вами Низамов Илья. Ошибка системы взаимодействия 1С почти всегда выглядит одинаково: у пользователя «Нет соединения с сервером системы взаимодействия», у администратора служба, которая молча остановилась. Причин за этим симптомом с десяток, и почти каждая оставляет в журнале сервера взаимодействия 1С свою строку. Ниже собраны ошибки, которые я сам поймал, когда ставил сервер взаимодействия 30.0.42 руками на Windows, а потом упаковывал его в Docker. Каждая проверена перезапуском: текст ошибки, причина, команда исправления.
Если вам нужно не только починить штатный сервер, но и понять, как он устроен изнутри, а заодно написать свой WebSocket-сервер для уведомлений из 1С, это курс «Сервер взаимодействия 1С на Python».
Если сервер ещё не установлен, начните с обзора что такое сервер взаимодействия и из чего он состоит или с установки в Docker. Здесь речь только о поломках.
Почему сервер взаимодействия ломается молча?
Сервер взаимодействия — это не одна программа, а небольшой кластер из четырёх частей:
| Часть | Что делает | Порт |
|---|---|---|
сам сервер (1c-cs-server-small) |
WebSocket для 1С:Предприятия, REST обслуживания, точка подключения интеграций | 9999, 8087, 8443 |
| PostgreSQL | абоненты, приложения, беседы, сообщения | 5432 |
| Elasticsearch 5.6 | поиск по переписке | 9200, 9300 |
| Hazelcast 3.9 | доставка сообщений, счётчики непрочитанного, «собеседник печатает» | 5701 |
Сообщения не лежат в информационной базе. 1С:Предприятие подключается к серверу по WebSocket, и вся переписка живёт там. Поэтому любая из четырёх частей, упавшая или недоступная, для пользователя выглядит одинаково: обсуждения не работают.
Вторая причина «молчания»: сервер при старте сам накатывает схему базы (миграциями Flyway), сам подключается к поиску и к кэшу. Если на любом из этих шагов что-то не так, процесс останавливается, а в окне служб Windows остаётся просто «Остановлена». Причина при этом записана, но в файле, а не на экране.
Ещё одна практическая деталь: доставка нового сообщения клиентам идёт через Hazelcast, а не из базы. Сообщение, вставленное в PostgreSQL в обход сервера, не увидит никто, поэтому «починить переписку запросом в базу» не получится.
В каком порядке искать причину?
В моей инструкции к ручной установке есть фраза, которая сэкономила мне больше всего времени:
Порядок проверки: сначала статус службы, потом логи, и только потом curl.
curl сам по себе службу не роняет, он лишь показывает, что она уже не работает.
Соблазн обычно обратный: дёрнуть /rs/health, не получить ответа и начать гадать. Правильный маршрут такой:
- Служба или контейнер. Работает ли процесс, не перезапускается ли он по кругу. В Docker это
docker compose psи признак(healthy), а неRestarting (1) 5 seconds agoс растущим счётчиком. В Windows это службы1ce-*. - Журнал. Последняя строка перед падением.
/rs/health. Только когда процесс жив.- Что сервер принял. Журнал показывает, что вы серверу отправили, а
ring ... list-paramsпоказывает, что он применил. При разборе поломки спрашивать надо второе. - Сторона базы 1С. Регистрация, адрес, версия, сертификат.
Пройдите этот маршрут по шагам, отвечая на вопросы:
Команда из шага 4 в контейнере выглядит так:
docker compose exec cs bash -c 'R=$(echo /opt/1C/1CE/components/1c-enterprise-ring-*/ring); \
"$R" cs --instance cs_instance websocket list-params; \
"$R" cs --instance cs_instance maintenance list-params; \
"$R" cs --instance cs_instance elasticsearch list-params'
Response{hostname='0.0.0.0', port=19999, ... wss=false, ...}
Response{address=/0.0.0.0, port=8087}
Response{addresses='elasticsearch:9300', clusterName='1ce-cs', ...}
Осторожно с пулом JDBC: ring cs --instance cs_instance jdbc pools --name common list-params печатает пароль к базе открытым текстом. Прежде чем вставлять этот вывод в чат или в задачу, пароль нужно замазать.
Где лежат журналы сервера взаимодействия?
У каждого компонента свой каталог экземпляра (instance), в нём папка logs. У сервера там три файла, которые нужны при разборе:
server.log— главный журнал с причинами падений. Ищите строкиlevel=ERROR;launcher.log— вывод пусковика: как поднималась JVM;websocket.log— события канала до 1С:Предприятия. Пуст, пока ни одна база не подключена.
Файлы с суффиксами .1, .2 остаются от предыдущих запусков. Это полезно: причина вчерашнего падения никуда не делась.
На Windows каталог экземпляра тот, который вы указали в ring cs instance create --dir, например C:\cs\cs_instance\logs\. В Docker журнал пусковика идёт в docker compose logs, а файлы лежат на томе:
docker compose logs cs --tail 40
docker compose exec -T cs ls -la /var/lib/1ce/cs/logs/
docker compose exec -T cs grep "level=ERROR" /var/lib/1ce/cs/logs/server.log
Ошибки при запуске сервера
Если у вас на руках строка из журнала, вставьте её в поиск. В нём собраны все ошибки из статьи, плюс безвредные предупреждения, которые часто принимают за причину:
function uuid_generate_v4() does not exist
Самая известная ловушка. Сервер при первом старте накатывает схему, миграции нужна функция uuid_generate_v4() из расширения uuid-ossp, а расширения в базе нет. Сервер останавливается, и выглядит это как «не запускается без причины».
Коварство в том, что расширение обычно создали, но не там. Расширение PostgreSQL создаётся внутри конкретной базы: создали в postgres — в cs_db его нет. В моей инструкции предупреждение написано капслоком не случайно:
Для базы данных cs_db следует подключить расширения uuid-ossp.
ВАЖНО: расширение должно быть создано именно в базе cs_db, а не в базе postgres.
Исправление и проверка:
\c cs_db
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SELECT extname, extversion FROM pg_extension;
В Docker ошибиться нельзя, если положить скрипт в docker-entrypoint-initdb.d: штатный образ PostgreSQL выполняет его уже подключённым к базе из POSTGRES_DB. Скрипт заодно проверяет, что функция отвечает, и падает сразу, а не через минуту в чужом журнале:
psql -v ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --dbname "${POSTGRES_DB}" <<'SQL'
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SQL
psql -v ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --dbname "${POSTGRES_DB}" \
-At -c "SELECT uuid_generate_v4()" > /dev/null
Проверьте заодно пулы JDBC. Их два, common (рабочий) и privileged (для миграций), и оба должны смотреть в одну базу. Если они разъедутся, сервер поднимется, а схему не обновит.
BindException: Cannot assign requested address
SocketIO server start failed at port: 19999!
BindException: Cannot assign requested address
Параметр websocket.hostname — это адрес привязки сокета, а не имя, которое сервер сообщает клиенту. На Windows, где сервер работает на самой машине, там стоит адрес машины, и это работает. Я перенёс то же значение в контейнер и получил бесконечный перезапуск: такого адреса внутри контейнера нет. Разбирался три перезапуска.
ring cs --instance cs_instance websocket set-params --hostname 0.0.0.0
Адрес, по которому идёт клиент, задаётся публикацией порта, а не этим параметром.
С портом WebSocket есть и обратная ловушка: номер попадает в строку подключения, которую человек вводит при регистрации базы. Если опубликовать порт наружу под другим номером, чем внутри, однажды получите «сервер недоступен» без единой ошибки в журнале. Поэтому в compose у меня порт одинаковый с обеих сторон:
ports:
- "${AIP_CS_WS_PORT:-19999}:${AIP_CS_WS_PORT:-19999}"
PID file exists and the process with PID referenced there is running
Ошибка контейнерная, но показательная. Пусковик 1С хранит номер процесса в daemon.pid внутри каталога экземпляра, то есть на томе. Контейнер упал, файл остался. При следующем старте пусковик видит файл, проверяет процесс с этим номером и находит его живым: в контейнере номера начинаются с единицы, и вчерашний PID сегодня принадлежит самому скрипту запуска. Итог: отказ в цикле.
Лечится удалением файла перед стартом. Раз мы стартуем, нашего процесса в этом контейнере ещё нет, проверять нечего:
clear_stale_pid() {
local dir="$1"
if [ -f "${dir}/daemon.pid" ]; then
log "снимаю daemon.pid от прошлого запуска ($(cat "${dir}/daemon.pid" 2>/dev/null))"
rm -f "${dir}/daemon.pid"
fi
}
/rs/health не открывается с другой машины
REST обслуживания (/rs/health, /admin/**) по умолчанию слушает 127.0.0.1. Локально всё отвечает, снаружи соединение отклонено.
На версии 25.0.22 штатная команда ring cs ... maintenance set-params --address падала с ошибкой «невозможно найти соответствующее значение для поля java.net.InetAddress». Обход — записать адрес в файл config/maintenance.yml напрямую:
server:
address: 0.0.0.0
port: 8087
В 30.0.42 команда уже работает, я проверил: ring вернул 0 и записал тот же YAML. Файлом я адрес всё равно пишу: значение здесь не настройка, а свойство установки, и ради него не стоит поднимать ещё одну JVM. Каждый вызов ring занимает пару секунд. Не забудьте открыть порт 8087 в брандмауэре, если проверяете сервер с другой машины.
Ошибки Elasticsearch и Hazelcast
Если сервер и узлы поиска с кэшем живут на одной машине и слушают локальную петлю, этих ошибок вы не увидите. Они появляются, как только компоненты разнесены по машинам или контейнерам.
Боевой режим Elasticsearch: четыре отказа подряд
Сервер взаимодействия ходит в Elasticsearch не по HTTP (9200), а транспортным протоколом на порт 9300. Значит, узлу поиска нельзя слушать только петлю. А Elasticsearch 5.6, как только слушает не петлю, считает себя боевым и включает стартовые проверки. Каждая проверка — отдельный отказ запуска:
| Строка в журнале | Что нужно |
|---|---|
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144] |
параметр ядра хоста ≥ 262144 |
initial heap size [...] not equal to maximum heap size [...] |
-Xms равен -Xmx |
max file descriptors [4096] for elasticsearch process is too low |
дескрипторов ≥ 65536, потоков ≥ 2048 |
can not run elasticsearch as root |
запуск от отдельного пользователя |
vm.max_map_count — самое неудобное требование: параметр ядра общий на всю машину, контейнер его видит, но не меняет. Это самая частая поломка при переносе на новый Linux-сервер:
cat /proc/sys/vm/max_map_count # надо >= 262144
sudo sysctl -w vm.max_map_count=262144 # разово
echo 'vm.max_map_count=262144' | sudo tee /etc/sysctl.d/99-elasticsearch.conf
Размер кучи задаётся явно, двумя равными числами. Без этого JVM посчитает умолчания от памяти всей машины, и они разойдутся. Остальные два требования — пределы процесса:
elasticsearch:
ulimits:
nofile:
soft: 65536
hard: 65536
nproc: 4096
Отдельно про elasticsearchOk: false при живом узле: либо узел ещё поднимается (сервер делает повторные попытки), либо в параметрах сервера указан порт 9200 вместо 9300, либо не совпало имя кластера (cluster.name у узла и --cluster-name у сервера).
Hazelcast: Member [127.0.0.1]:5701
В hazelcast.xml из поставки адрес узла — 127.0.0.1. Это не только список для поиска соседей: по нему Hazelcast выбирает адрес, на котором слушает сам. Узел объявляет себя Member [127.0.0.1]:5701, порт вроде бы открыт, а сервер с другой машины или из соседнего контейнера до него не доходит. В /rs/health это видно как "hazelcast":{"available":false}.
Нужно подставить реальный адрес узла. Именно адрес, а не 0.0.0.0: Hazelcast сообщает свой адрес клиенту, и клиент идёт по нему следующим соединением. У меня это делает скрипт запуска:
ip="$(hostname -i | awk '{print $1}')"
sed -E -i \
-e "s#<interface>[0-9.]+</interface>#<interface>${ip}</interface>#" \
-e "s#<member>[0-9.]+</member>#<member>${ip}</member>#" \
"${dir}/config/hazelcast.xml"
Проверка на живом узле: grep -n "<member>" hazelcast.xml не должен показывать 127.0.0.1.
Как читать ответ /rs/health?
У исправного сервера ответ выглядит так:
{"status":"UP","mainDbOk":true,"allShardsOk":true,
"hazelcast":{"available":true,"members":["172.29.0.2:5701"]},
"elasticsearchOk":true,"mediaClusterOk":false,"mediaServers":{},"pushOk":false}
Да, два false у исправного сервера. mediaClusterOk и pushOk остаются ложными, пока не настроены MinIO для файлов и служба push-уведомлений. Я сверил это с ручной установкой на Windows: там ровно то же. Чинить их не нужно. Отсюда практический вывод: автоматическая проверка здоровья должна ждать только "status":"UP", иначе она будет вечно красной.
Переключите поля и посмотрите, что означает каждое:
Чаще всего после установки встречается allShardsOk: false. Сервер поднялся, но список серверов хранения разговоров пуст, и складывать переписку некуда. В инструкции производителя это отдельный ручной шаг после старта, и его легко пропустить:
curl -Sf -X POST -H "Content-Type: application/json" \
-u admin:<пароль> \
-d '{"url":"jdbc:postgresql://<хост>:5432/cs_db","username":"cs_user","password":"<пароль>","enabled":true}' \
http://localhost:8087/admin/bucket_server
Если в ответ пришёл 401, неверна учётка администратора. Прочитать текущий список можно тем же адресом через GET: одна запись со ссылкой на базу и даёт allShardsOk: true.
И про учётку: в поставке это admin/admin, а под ней лежит весь /admin/**, то есть регистрация баз, хранилище и настройки сервера. Пароль меняется командой ring cs ... http_security set-params --users "admin::<пароль>::ADMIN". Формат имя::пароль::роль через запятую, поэтому двоеточий и запятых в пароле быть не должно.
Ошибка протокола системы взаимодействия: не та версия
Самая обидная ошибка, потому что выглядит как поломка сети. База на платформе 8.3.27 регистрировалась на сервере 25.0.22. WebSocket-соединение устанавливалось, рукопожатие проходило, а в server.log сыпалось:
level=ERROR ... UnknownEventException: Unknown event: setOptions
level=ERROR ... UnknownEventException: Unknown event: createOrUpdateApplication
Платформа шлёт события, которых сервер старой линейки не знает. Версия сервера взаимодействия привязана к версии платформы 1С: для 8.3.25 ставится линейка 25.0.x, для 8.3.27 — 27.0.x и новее. Лечится только заменой сервера на подходящую линейку. Выбирать дистрибутив нужно под платформу баз, а не «какой посвежее».
Проверить со стороны базы можно встроенным языком:
| Вызов | Что должно вернуться |
|---|---|
СистемаВзаимодействия.ИнформационнаяБазаЗарегистрирована() |
Истина |
СистемаВзаимодействия.ИспользованиеДоступно() |
Истина |
СистемаВзаимодействия.АдресСервера() |
ws://<хост>:<порт> |
СистемаВзаимодействия.ВерсияСервера() |
30.0.42 (ваша версия) |
Если база подключена не к своему серверу, а к облачному серверу 1С, журналов сервера у вас нет. Из этой статьи тогда применимы только проверки на стороне клиента: версия платформы, сеть, сертификаты.
При обновлении сервера порядок такой: сначала останавливается сам сервер, потом Hazelcast и Elasticsearch, поднимаются они в обратном порядке. Отключать базы обработкой перед обновлением не нужно, производитель отдельно об этом предупреждает: клиенты на время покажут значок с восклицательным знаком и переподключатся сами. Отключение обработкой означало бы повторную регистрацию. Перед обновлением обязательна копия базы сервера:
pg_dump -U cs_user cs_db | gzip > cs_db-$(date +%Y%m%d).sql.gz
Нет соединения при регистрации: сертификаты и wss
Регистрация базы делается обработкой CollaborationSystemRegister.epf из поставки или через «Администрирование → Органайзер → Обсуждения». Нужна почта администратора и код из письма, адрес сервера — ws://<хост>:<порт>. Пока канал без шифрования, проблем здесь обычно нет. С wss на самоподписанном сертификате у меня было три поломки подряд.
Первая:
Client requested protocol TLSv1 is not enabled or supported in server context.
Ошибка при регистрации. Невозможно установить соединение с сервером системы
взаимодействия tlsv1 alert protocol version
Клиент попросил TLSv1, а Java на сервере его запретила. На моей установке помогло убрать TLSv1 из jdk.tls.disabledAlgorithms в файле conf\security\java.security каталога LibericaJDK и перезапустить службу. Это ослабляет шифрование, так что держите такой обход временным.
Вторая, сразу после первой:
Ошибка при регистрации. certificate verify failed
Сертификат сервера не в доверенных на машине, с которой регистрируют базу. Лечение: скопировать .cer и установить его в «Доверенные корневые центры сертификации» локального компьютера. Хранилище ключей и файл сертификата делаются утилитой из JDK:
keytool -genkey -alias websocket-keystore -keyalg RSA -keystore websocket-keystore.jks
keytool -export -alias websocket-keystore -file websocket-keystore.cer \
-keystore websocket-keystore.jks
Третья проявляется позже. Сертификат ставится на каждую машину, где запускается 1С с подключением к серверу. Десять рабочих мест — десять установок, и ещё раз при каждой смене сертификата. Самоподписанный сертификат годится, чтобы проверить механизм, но не как решение. В работе нужен сертификат домена, либо TLS снимает nginx перед сервером (proxy_pass на порт WebSocket с заголовком Upgrade).
Не путайте этот TLS с TLS точки подключения интеграций (Webhook, Telegram, VK и прочие внешние системы). Там требование другое: публичный адрес обязан начинаться с https, это константа в коде сервера, выключателя нет. Сам endpoint при этом слушает обычный http на 8443, так что сертификат нужен не серверу, а nginx перед ним:
Интернет ──https──► nginx ──http──► сервер взаимодействия :8443
Адрес обратного вызова сервер собирает как <publicUrl>/integration/webhook/<токен>/callback, поэтому publicUrl задаётся без пути, только схема и домен. Быстрая проверка, что точка на месте: GET на путь обратного вызова должен вернуть 405 Method Not Allowed. Путь существует, просто ждёт POST.
Какие предупреждения можно не чинить?
Эти строки появляются в журнале при каждом старте и регулярно попадают в поиск причины. Причиной они не являются:
WARNING: An illegal reflective access operation has occurred— библиотека Hazelcast внутри сервера собрана под Java 8, а работает на 11. Четыре строки при каждом старте, ни на что не влияют.Flyway upgrade recommended: ... 17.9 is newer than this version of Flyway and support has not been tested— Flyway 7.7.3 из поставки не знает PostgreSQL 17. УровеньWARN, всё работает, я проверил на двух установках с 17-й базой. Консервативный выбор — PostgreSQL 13, но если миграции поведут себя странно, вспомните об этом предупреждении первым.awk: function gensub never defined— пусковой скриптringзовётawkс функциейgensub, которой нет уmawkв урезанных Debian.ringпри этом работает. Строка исчезнет послеapt-get install gawk.mediaClusterOk: false,pushOk: false— разобраны выше, у исправного сервера так же.
Как не ловить эти ошибки второй раз
Почти все ошибки выше — следствие ручной настройки: команду забыли, выполнили в другой базе, перенесли значение с одной машины на другую. Ручную установку по инструкции повторяешь каждый раз немного иначе. Поэтому в Docker-версии я сделал так, что настройка раскладывается при каждом старте контейнера из переменных окружения, а не один раз при установке. Том с настроенным экземпляром можно удалить целиком, и стек поднимется таким же.
Что это даёт на практике:
uuid-osspсоздаётся скриптом инициализации в нужной базе и сразу проверяется;- адрес WebSocket, адрес REST и адрес узла Hazelcast выставляются под контейнер, а не копируются с машины;
daemon.pidснимается перед каждым стартом;- сервер хранения разговоров регистрируется фоном после
/rs/health, повторный запуск ничего не портит: сначала читается текущий список; - сервер не стартует, пока база, кэш и поиск не ответили «здоров» (
depends_onсcondition: service_healthy); - без пароля администратора стек отказывается запускаться, умолчания
admin/adminнет.
Проверка здоровья самого сервера ждёт только статус, по причине из раздела про /rs/health:
healthcheck:
test: ["CMD-SHELL", "curl -sf http://127.0.0.1:8087/rs/health | grep -q '\"status\":\"UP\"'"]
interval: 10s
timeout: 10s
retries: 30
start_period: 90s
Весь стек, четыре контейнера, поднимается до полного здоровья за 33 секунды. Цикл docker compose down / up проходит без единого ручного шага. Только не путайте down с down -v: второй удаляет тома, то есть всю переписку, индексы и настройки экземпляров.
Чего такая установка сама не закроет: копии базы cs_db по расписанию, внешнюю проверку /rs/health (метрики сервер уже отдаёт на /actuator/prometheus) и сертификат для wss. Первые две стоит сделать до первого живого клиента, иначе о падении узнает клиент, а не вы.
И отдельно про лицензию. Сервер взаимодействия производитель описывает как внутриорганизационный, бесплатное право на свой экземпляр получают организации с лицензиями уровня КОРП. Технически сервер лицензию не проверяет вовсе, так что «оно же запустилось» доводом не является. Если собираетесь подключать базы чужих юрлиц, это вопрос к партнёру 1С, а не к настройке.
Что дальше
- Установка с нуля: в Docker, на Ubuntu Server без контейнеров, на Windows Server.
- Перенос работающего сервера: переезд в Yandex Cloud.
- Вложения в переписке: обмен файлами через S3.
- Сервер взаимодействия из кода 1С: прогресс длительной операции в реальном времени.
Если не хотите разбираться с этим сами, настройку сервера взаимодействия можно заказать у нас.
А если хотите понимать систему взаимодействия изнутри — события, бота, свой WebSocket-сервер на Python для уведомлений и прогресса операций без облака 1С, — приходите на курс «Сервер взаимодействия 1С на Python». Сервер 1С:Предприятия, кластер и PostgreSQL на Linux разбираем на курсе «Сервер 1С:Предприятие».