Colloq в вузе ставят двумя способами — выберите тот, что подходит вашей инфраструктуре.

Кратко для ИТ-службы

Что этоColloq — совместные тетради Jupyter для занятий: веб-приложение и отдельный контейнер с ядром Python для каждой комнаты. Открытый код, лицензия MIT.
МашинаОдна выделенная VM x86-64 с Ubuntu 22.04 или 24.04 и Docker Engine 28 или новее. Приложение управляет Docker, а это права root на VM, поэтому других служб на ней не держите.
РесурсыДля начала 16 vCPU, 64 ГБ памяти, 250 ГБ NVMe, без GPU. Этого хватает на группу из 30 человек с личными тетрадями или с соревнованием и на лекцию на 100 человек; расчёт — в разделе «Машина и ресурсы».
ВходящиеТолько HTTPS от браузеров пользователей к вашему обратному прокси; прокси обращается к приложению по 127.0.0.1:3000. Если пользователи в сети вуза или в VPN, из интернета не нужно ничего.
ИсходящиеВо время работы основным функциям не нужно ничего: нет ни телеметрии, ни проверки обновлений, ни CDN. Для установки и обновления нужен ghcr.io — или ваше зеркало реестра, или перенос образов файлом. По желанию: модель ИИ (OpenAI или своя внутри сети), импорт тетрадей с GitHub, PyPI или внутреннее зеркало для пакетов соревнований, интернет для кода студентов.
ДанныеВсё на этой VM в /workspace/colloq: база SQLite, файлы комнат, данные соревнований, резервные копии. Настройки — в /etc/colloq/colloq.env.
Резервные копииcolloq-host backup вручную или colloq-host backup-timer on — каждую ночь. Уносить копии с машины нужно вашими средствами.

Как это устроено

Браузеры студентов и преподавателейОбратный прокси вуза, TLSКонтейнер Colloq
Ядро комнаты AЯдро комнаты BПосылка соревнования

Обратный прокси вуза принимает HTTPS и передаёт запросы приложению. Приложение — один контейнер colloq из образа ghcr.io/colloq-edu/colloq-server: сервер на Node.js, собранный веб-интерфейс и база SQLite. Его порт 3000 опубликован только на 127.0.0.1 этой VM. Запускает и обновляет контейнер colloq-host — небольшой скрипт на хосте, который ставится из того же образа.

Для каждой комнаты приложение запускает на том же Docker свой контейнер с ядром Jupyter: свои пределы памяти, процессора и числа процессов, смонтирована только папка этой комнаты, uid 1000, без Linux capabilities. Личные тетради студентов считаются во втором контейнере занятия, посылка соревнования — в двух одноразовых контейнерах без сети. Приложение и ядра комнат делят сеть Docker colloq.

Каталог состояния — /workspace/colloq: data/ (база и ключи), workspace/<комната>/ (файлы комнат), environments/ (окружения, созданные в панели), backups/. Он смонтирован в контейнер по тому же пути. Настройки лежат в /etc/colloq/colloq.env (права 0600), выбранный образ — в /etc/colloq/image. Подключите под /workspace/colloq отдельный диск или раздел: тогда переполнение не заденет систему.

Машина и ресурсы

Отправная точка: 16 vCPU, 64 ГБ памяти, 250 ГБ NVMe, x86-64 (образ собирается только для amd64), Ubuntu 22.04 или 24.04, Docker Engine 28 или новее, GPU не нужен. Часы машины должны синхронизироваться по NTP (без интернета — с внутренним сервером): от времени зависят ссылки входа, cookies и сертификаты. Docker должен сам управлять iptables: сетевой запрет комнат встаёт в его цепочку DOCKER-USER, поэтому не подходят "iptables": false в daemon.json и nftables-бэкенд Docker 29. Память и процессор машины уходят на ядра комнат и посылки; цифры для них ниже выведены из пределов в коде. Само приложение лёгкое, это замерено.

СценарийvCPUПамятьДиск
(a) 30 студентов, одна общая тетрадь48 ГБ60 ГБ
(b) 30 студентов, у каждого личная тетрадь1664 ГБ (не меньше 48 ГБ)100 ГБ
(c) 30 студентов и соревнование, посылка 2 ядра / 2 ГБ16 (авто даёт 7 слотов)32 ГБ100 ГБ
(d) три занятия как (c) в один час32 (около 15 слотов)64 ГБ; 160–192 ГБ, если у всех трёх личные тетради200 ГБ
(e) 100 человек в лекционной комнате4 (8, если студенты запускают ячейки)8 ГБ60 ГБ

Отправная точка покрывает (a), (b), (c) и (e), а (d) — с более медленной очередью посылок. Предположения: pandas и scikit-learn с настройками по умолчанию, посылка идёт около двух минут.

Замер приложения (30.09.2026, VM 21 vCPU / 49 ГБ, nginx перед приложением, make load): 500 человек вошли в одну комнату за минуту без единого отказа, вход — 7 мс в середине распределения. Процесс приложения держал 243 МБ памяти и 20 % одного ядра в покое и 50 % ядра, когда двадцать человек печатали одновременно; правка доходила до остальных за 0,17 с (p95). На 300 человек — 198 МБ и те же доли ядра.

Память считайте так: около 3 ГБ на систему и приложение + пределы комнат (4 ГБ на комнату по умолчанию) + пределы контейнеров личных тетрадей + слоты × (память посылки + 0,25 ГБ) + 1,6 ГБ на время подготовки пакетов. Docker ничего не резервирует, поэтому Colloq сам не запустит ядро, если его предел вместе с пределами уже работающих контейнеров не помещается в память машины за вычетом 1 ГБ. Процессор делится, а не резервируется: у комнаты потолок в 2 ядра.

  • Личные тетради: около 1–1,5 ГБ и 0,25 ядра на студента. Все личные тетради занятия живут в одном контейнере и по умолчанию получают на всех столько же, сколько комната, — 4 ГБ. Для группы поднимите «Память на класс» в панели: «Ресурсы» → «Личные тетради студентов» (или в правилах конкретного занятия).
  • Соревнования: сколько посылок идёт одновременно («Исполнителей одновременно» во вкладке «Ресурсы»), по умолчанию считается само: меньшее из (ядра − 2) / ядра посылки и (память − 2 ГБ) / (память посылки + 0,25 ГБ), но не больше 32. 30 посылок по две минуты проходят примерно за 9 минут на 7 слотах и примерно за 20 минут на 3 слотах (машина 8 vCPU / 16 ГБ).
  • Комната держит память, пока в ней кто-то есть, и ещё 2 часа после того, как все ушли: конец пары ядро не останавливает. Поэтому занятия подряд накладываются друг на друга.
  • Диск: образ kaggle-base занимает около 1 ГБ, base-gpu — около 9 ГБ; дальше растут файлы комнат, посылки соревнований и резервные копии. Страницы занятий держат свои копии опубликованных тетрадей и файлов в data/page-files/: около 0,3–0,8 ГБ на курс из 33 занятий, одинаковый файл в разных страницах хранится один раз. Квоты на комнату нет, см. наблюдение.
  • GPU необязателен. Он нужен только окружениям с GPU (base-gpu): по одной карте, 16 ГБ памяти и около 10 ГБ диска на каждую одновременно работающую GPU-комнату, плюс драйвер NVIDIA и NVIDIA Container Toolkit (colloq-host ставит его сам через apt). Личные тетради и посылки соревнований GPU не получают никогда.

Во вкладке «Ресурсы» есть шкала памяти: работающие комнаты, личные тетради и слоты соревнований против памяти машины за вычетом 1 ГБ; если памяти не хватает, шкала так и пишет. Там же показан свободный диск раздела с данными, с предупреждением, когда свободно меньше 15 % или 10 ГБ; GPU шкала не показывает.

Входящие и исходящие соединения

Входящие соединения:

Откуда и кудаПортЗачем
Браузеры пользователей → обратный прокси443/TCP; 80 — только для перенаправления на HTTPSВсё приложение: страницы, API, WebSocket, server-sent events.
Обратный прокси → приложение127.0.0.1:3000, если прокси на этой же VM; иначе внутренний адрес VM, порт 3000 (COLLOQ_BIND)HTTP без TLS внутри машины или доверенного сегмента.
Администраторы → VM22/TCPSSH и colloq-host; только из сети ИТ-службы.
Интернет → VM—Не нужен, если пользователи в сети вуза или в VPN. Порты 80/443 из интернета нужны, только если прокси сам получает сертификат Let's Encrypt.

Jupyter ядер и остальные служебные порты не публикуются: они живут внутри сети Docker. Сторонних обращений нет: шрифты, просмотрщик PDF и plotly приложение отдаёт само, и браузеры обращаются только к адресу Colloq.

Исходящие соединения:

КудаЗачем и когдаНужноМожно ли заменить
ghcr.io, pkg-containers.githubusercontent.comОбраз приложения colloq-server и образы ядер colloq-kernel: установка и обновлениеДа, если не переносить образы файломДа: зеркало реестра в COLLOQ_IMAGE и KERNEL_IMAGE_REPO; без сети — перенос файлом
get.docker.com, download.docker.comУстановка Docker, если его нет на машинеНет, если Docker уже стоитСтавьте Docker из своего репозитория
Docker Hub (registry-1.docker.io, auth.docker.io, production.cloudflare.docker.com), deb.debian.org, pypi.org, files.pythonhosted.orgСборка образа ядра на месте: окружение из панели или опубликованный образ, который не удалось скачатьНетЧастично: строки --index-url в списке пакетов окружения; готовые образы ядер из реестра
nvidia.github.ioNVIDIA Container Toolkit при первой установке на машине с GPUТолько для GPUПоставьте пакет заранее
Модель ИИ, по умолчанию api.openai.comОракул — когда его спрашиваютНетДа: OPENAI_BASE_URL или панель — Ollama, vLLM или другой совместимый с OpenAI адрес внутри сети
api.github.com, raw.githubusercontent.comИмпорт тетради с GitHub в панели — по кнопкеНетНет, только github.com
pypi.org, files.pythonhosted.org«Свои пакеты» участников соревнований — при подготовке набораНетДа: DEPENDENCY_INDEX_URL, DEPENDENCY_FILES_HOSTS
Интернет из ядер комнатpip install, датасеты и API в коде студентов — во время занятияНетМожно отключить: COLLOQ_ROOM_NETWORK=none, см. ниже

Сеть для кода студентов

  • Посылки соревнований исполняются вовсе без сети.
  • Комнаты и личные тетради по умолчанию выходят в интернет (pip install, датасеты, API), а частные адреса для них закрыты: 10/8, 172.16/12, 192.168/16, 100.64/10, 169.254/16 с метаданными облака, 127/8, multicast, сама VM и соседние комнаты. Соединение туда сразу получает отказ; открытым для любого адреса остаётся только DNS, порт 53. Правила ставит само приложение — в собственные цепочки iptables COLLOQ-ROOMS-*, в которые ведут DOCKER-USER и INPUT. Если поставить их не удалось, комнаты не запускаются.
  • Публичные диапазоны вуза. Код студентов выходит в сеть с адреса VM, и службы, которые доверяют адресам вуза (подписки библиотеки, внутренние сайты на публичных адресах), примут его за своего. Перечислите такие диапазоны: KERNEL_BLOCKED_CIDRS=192.0.2.0/24,198.51.100.0/24.
  • COLLOQ_ROOM_NETWORK=none — у ядер комнат и личных тетрадей совсем нет исходящей сети, до них доходит только сервер Colloq. pip install в ячейке тогда не работает: нужные библиотеки заранее кладите в окружение (панель → «Окружения»).
  • COLLOQ_ROOM_NETWORK=open снимает запрет частных адресов — только для доверенных групп, которым нужна локальная сеть.

Исходящий прокси, внутренний CA и зеркало PyPI

Если наружу можно выйти только через прокси, задайте HTTPS_PROXY, HTTP_PROXY и NO_PROXY (понимаются и в нижнем регистре). Через прокси идут все исходящие HTTP-запросы сервера — к модели ИИ и к GitHub, — и те же значения получает pip при подготовке пакетов. Частные адреса и внутренние имена Colloq (ядра, контейнеры) идут мимо прокси сами; в NO_PROXY перечислите внутренние домены, например своей модели и зеркала PyPI. NODE_EXTRA_CA_CERTS — путь к файлу PEM с сертификатами внутреннего CA на хосте: colloq-host монтирует его в контейнер по тому же пути, и его тоже получает pip. Тот же файл положите и в системное хранилище: образы скачивает сам Docker, и ему нужны и этот CA, и свой прокси.

cp campus-ca.pem /usr/local/share/ca-certificates/campus-ca.crt
update-ca-certificates          # для скачивания образов самим Docker

# вместе с остальными настройками colloq-host up, см. «Установка»
HTTPS_PROXY=http://proxy.example.edu:3128
HTTP_PROXY=http://proxy.example.edu:3128
NO_PROXY=localhost,127.0.0.1,.example.edu
NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/campus-ca.crt

Прокси для Docker задаёт ключ proxies в /etc/docker/daemon.json (или drop-in systemd для docker.service); после этой правки и после update-ca-certificates перезапустите Docker.

{
  "proxies": {
    "http-proxy": "http://proxy.example.edu:3128",
    "https-proxy": "http://proxy.example.edu:3128",
    "no-proxy": "localhost,127.0.0.1,.example.edu"
  }
}

Зеркало PyPI для «своих пакетов» соревнований задаёт DEPENDENCY_INDEX_URL=https://pypi.example.edu/simple — подойдёт любой индекс, совместимый с PyPI по Simple API (по умолчанию https://pypi.org/simple). Если сами файлы пакетов отдаёт другой хост, перечислите его в DEPENDENCY_FILES_HOSTS. Адреса зеркала могут быть частными; адрес индекса — только https и без учётных данных, то есть зеркало должно отдавать пакеты анонимно.

Установка без интернета

  1. На машине с интернетом и Docker возьмите colloq-host нужной версии и соберите комплект: образ приложения, образы ядер и сам colloq-host в одном файле. Ядра в нём — для окружения по умолчанию (base), другие перечислите в KERNEL_PRELOAD. Пока файл пишется, свободного места нужно примерно вдвое больше его размера.
  2. Перенесите файл на VM вуза и поставьте на ней Docker Engine 28 или новее из пакетов дистрибутива или внутреннего зеркала: без сети colloq-host его не установит.
  3. Достаньте из файла colloq-host, загрузите образы и запустите Colloq. load кладёт colloq-host в /usr/local/sbin, запоминает образ и записывает COLLOQ_OFFLINE=1: дальше ничего не скачивается, не ставится и не собирается из сети.
# на машине с интернетом
docker run --rm -v "$PWD:/host" ghcr.io/colloq-edu/colloq-server:X.Y.Z install-host /host
KERNEL_PRELOAD=base,kaggle-base ./colloq-host bundle colloq-X.Y.Z.tar ghcr.io/colloq-edu/colloq-server:X.Y.Z

# на сервере вуза, от root
tar -xf colloq-X.Y.Z.tar colloq-host && ./colloq-host load colloq-X.Y.Z.tar
colloq-host doctor
COLLOQ_TUNNEL=none PUBLIC_URL=https://colloq.example.edu colloq-host up

Обновление — так же: новый комплект, colloq-host load, затем colloq-host update. Без интернета не работают импорт с GitHub, оракул (если внутри сети нет своей модели), «свои пакеты» соревнований (если нет зеркала PyPI) и сборка новых окружений из панели: ей нужны Docker Hub, Debian и PyPI.

Обратный прокси

Что должен делать прокси:

  • Обслуживать корень отдельного имени, например https://colloq.example.edu/. Настройки базового пути у приложения нет, из подкаталога оно работать не будет.
  • Пропускать WebSocket на /collab/, /control/ и /file/. Сервер шлёт ping каждые 25 с.
  • Не буферизовать server-sent events: /api/k/competitions/<адрес>/stream, /api/k/competitions/<адрес>/dependencies/<набор>/stream, /api/admin/competitions/<id>/stream, /api/admin/environments/<имя>/log. Приложение помечает эти ответы заголовком X-Accel-Buffering: no (nginx учитывает его сам) и раз в 20 с шлёт пульс.
  • Держать WebSocket и потоки часами: тайм-аут чтения — не меньше часа.
  • Принимать тело запроса не меньше 210 МБ: данные соревнования загружаются одним запросом до 200 МБ. Файл в комнату — до 50 МБ по умолчанию (MAX_UPLOAD_MB); подняли этот предел — поднимите и предел прокси.
  • Успевать передать загрузку приложению за 5 минут — это тайм-аут запроса в Node.js. nginx по умолчанию сначала принимает тело целиком и только потом быстро отдаёт его приложению, так что медленный клиент в этот предел не упирается; прокси, который передаёт тело потоком (Caddy), упирается.
  • Держать простаивающее соединение с приложением меньше 130 с: столько его держит само приложение, и прокси не должен отправлять запрос в соединение, которое приложение как раз закрывает.
  • Передавать Host таким, каким его прислал клиент: приложение сверяет с ним Origin, и иначе каждая запись под /api получит 403.
  • Записывать в X-Forwarded-For адрес клиента (заменять, а не дописывать), в X-Forwarded-Proto — https; заголовок CF-Connecting-IP удалять.

nginx (1.18 из Ubuntu 22.04 и 1.24 из 24.04), файл /etc/nginx/conf.d/colloq.conf. Если прокси на другой машине, в upstream укажите внутренний адрес VM.

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      '';
}

upstream colloq {
    server 127.0.0.1:3000;
    keepalive 32;
    keepalive_timeout 60s;          # меньше 130 с, которые держит приложение
}

server {
    listen 80;
    server_name colloq.example.edu;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;           # с nginx 1.25.1: listen 443 ssl; и http2 on;
    server_name colloq.example.edu;
    ssl_certificate     /etc/ssl/colloq/fullchain.pem;
    ssl_certificate_key /etc/ssl/colloq/privkey.pem;

    client_max_body_size 256m;      # данные соревнования: до 200 МБ одним запросом

    location / {
        proxy_pass http://colloq;
        proxy_http_version 1.1;
        proxy_set_header Host              $http_host;   # с портом, если он есть: с ним сверяется Origin
        proxy_set_header X-Forwarded-For   $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header CF-Connecting-IP  "";
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        $connection_upgrade;
        proxy_read_timeout 1h;          # WebSocket и server-sent events
        proxy_send_timeout 1h;
    }
}

Caddy, файл /etc/caddy/Caddyfile:

colloq.example.edu {
    # Сертификат вуза. Без этой строки Caddy получит сертификат Let's Encrypt,
    # и тогда имя должно быть доступно из интернета на портах 80 и 443.
    tls /etc/caddy/colloq.crt /etc/caddy/colloq.key

    request_body {
        max_size 256MB
    }

    # Host, X-Forwarded-For и X-Forwarded-Proto Caddy выставляет сам,
    # WebSocket и server-sent events пропускает без настройки,
    # а простаивающее соединение с приложением держит 2 минуты — меньше 130 с.
    reverse_proxy 127.0.0.1:3000 {
        header_up -CF-Connecting-IP
    }
}

Журналы доступа прокси содержат адреса комнат, ключи входа преподавателей (/admin/k/…, /admin/t/…) и токены комнат в адресах WebSocket (?token=…). Храните их так же закрыто, как базу, или пишите без адреса запроса.

Проверка: curl -sS https://colloq.example.edu/api/readyz, затем комната с двух устройств — совместная правка, запуск ячейки, загрузка файла. Потоки видны по журналу сборки окружения в панели: строки должны появляться по одной, а не одним куском в конце.

Адреса клиентов и HTTPS

Заголовку X-Forwarded-For приложение верит, только если соединение пришло с адреса из TRUSTED_PROXIES. Прокси на этой же VM приходит к приложению через проброс порта Docker, поэтому приложение видит не 127.0.0.1, а шлюз сети Docker colloq. Пока порт опубликован на loopback, а TRUSTED_PROXIES не задан, colloq-host сам доверяет loopback и этому шлюзу, так что прокси на той же машине ничего настраивать не нужно. Задаёте TRUSTED_PROXIES сами — это умолчание пропадает, и шлюз нужно вписать тоже. Без доверенного прокси вся группа выглядит одним адресом: 61-й новичок в комнате за 10 минут получит отказ 429, а оракул примет 20 вопросов в минуту на всех.

# шлюз сети colloq
docker network inspect colloq -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}'

Свои сети Docker по умолчанию берёт из 172.17.0.0–172.31.255.255 и 192.168.0.0/16. Если это пересекается с сетями кампуса, до установки задайте другие диапазоны в default-address-pools файла /etc/docker/daemon.json.

TRUSTED_PROXIES принимает адреса и подсети IPv4 и IPv6 через запятую или пробел, а также слова loopback, private (все частные диапазоны) и none. Клиентом считается самый правый адрес в X-Forwarded-For, который сам не входит в доверенные.

Прокси на другой машине. Опубликуйте порт на внутреннем адресе VM — COLLOQ_BIND=10.0.0.5 — и впишите адрес прокси в TRUSTED_PROXIES (например, TRUSTED_PROXIES=10.0.0.2); colloq-host запоминает оба значения. Порт 3000 закройте для всех, кроме прокси. Правила ufw и firewalld опубликованные порты Docker не видят: фильтруйте в цепочке DOCKER-USER или на сетевом экране перед VM.

Общие адреса. Если много людей приходят с одного адреса — через NAT Wi-Fi кампуса или концентратор VPN, — перечислите такие адреса: SHARED_ADDRESSES=198.51.100.7/32,10.20.0.0/16. Для них не действуют пределы на адрес: 60 новичков в комнате за 10 минут, 20 вопросов оракулу в минуту, входы и вступления в соревнования. Пределы на комнату и на человека остаются.

Адрес для ссылок. PUBLIC_URL=https://colloq.example.edu — внешний адрес без пути и без слеша в конце. Из него строятся все ссылки, которые раздаёт Colloq, в том числе ссылка владельца.

HTTPS. Когда прокси сообщает X-Forwarded-Proto: https, cookies получают флаг Secure, а приложение само отправляет Strict-Transport-Security (180 дней, без includeSubDomains); по обычному http этот заголовок не уходит. Если прокси уже добавляет свой, выключите заголовок приложения: HSTS=0.

Установка

Всё ниже выполняется от root на подготовленной VM: Ubuntu 22.04 или 24.04, Docker Engine 28 или новее из репозитория Docker или вашего зеркала, диск под /workspace/colloq. Номер версии возьмите на странице Releases.

# 1. colloq-host из образа выбранной версии и проверка машины
IMAGE=ghcr.io/colloq-edu/colloq-server:X.Y.Z
docker run --rm -v /usr/local/sbin:/host "$IMAGE" install-host /host
colloq-host doctor

# 2. Запуск за прокси на этой же VM
COLLOQ_TUNNEL=none \
PUBLIC_URL=https://colloq.example.edu \
COLLOQ_IMAGE="$IMAGE" \
colloq-host up

# 3. Ссылка владельца, готовность и ночные копии
colloq-host link
colloq-host status
colloq-host backup-timer on

doctor ничего не меняет: по строке PASS, WARN или FAIL на каждую проверку — архитектура, версия Docker и его сетевой экран, память и диск, порт 3000, DNS, синхронизация часов, доступ к ghcr.io, PUBLIC_URL и доверенные прокси. Исправьте каждую строку FAIL до первого занятия. up ставит недостающее, скачивает образ, записывает настройки в /etc/colloq/colloq.env и запускает контейнер colloq. Образ ядра по умолчанию (base) скачивается из ghcr.io/colloq-edu/colloq-kernel, а если не вышло — собирается на месте; это несколько минут в фоне, и панель тем временем уже работает. Если прокси на другой машине, добавьте к up COLLOQ_BIND и TRUSTED_PROXIES, см. «Адреса клиентов».

colloq-host link печатает адрес и, пока у сервера нет владельца, ссылку установки …/admin/t/…. Это ключ от сервера: не отправляйте его в общий чат. Откройте ссылку, введите имя и почту — и вы владелец. Преподавателей добавьте в панели, в разделе «Преподаватели»: каждый получит личную ссылку входа.

colloq-host status показывает /api/health, образы ядер и контейнеры комнат; сервер готов к занятию, когда в ответе "ok":true. Перед первой группой создайте две комнаты, откройте их с двух устройств из сети студентов, запустите ячейку, загрузите файл, а затем проверьте резервную копию и восстановление на запасной VM.

Настройки

colloq-host up записывает в /etc/colloq/colloq.env (права 0600) переменные из своего окружения: непустое значение заменяет прежнее, а отсутствующее ничего не стирает. Там же он запоминает и собственные настройки — COLLOQ_HOME, COLLOQ_BIND, — чтобы следующий update действовал так же. Чтобы убрать строку, отредактируйте файл. Изменения применяет повторный colloq-host up: контейнер приложения пересоздаётся, только если изменились настройки или образ, а ядра комнат при этом продолжают работать. Оракул, ресурсы комнат и слоты соревнований владелец меняет и в панели, без перезапуска; сохранённое в панели главнее файла.

ПеременнаяЧто задаётПо умолчанию
Адрес и прокси
COLLOQ_TUNNELnone — адрес даёт ваш прокси. Остальные режимы (relay, cloudflare, direct) — для аренды и публикации без своего прокси.auto; вне Vast без PUBLIC_URL — none с предупреждением
PUBLIC_URLВнешний адрес, из которого строятся ссылки.—
TRUSTED_PROXIESАдреса прокси, чей X-Forwarded-For принимается: IP, подсети, loopback, private, none.loopback; при порте на loopback colloq-host добавляет шлюз сети colloq
SHARED_ADDRESSESПодсети NAT, для которых не действуют пределы на адрес.пусто
HSTS0 — не отправлять Strict-Transport-Security.включено
TRUST_CF_CONNECTING_IP1 — принимать CF-Connecting-IP; только для туннелей Cloudflare самого Colloq, не за вашим прокси.выключено
COLLOQ_BINDГде хост публикует порт 3000; нужен, если прокси на другой машине. Читает только colloq-host.127.0.0.1
Исходящие соединения
HTTPS_PROXY, HTTP_PROXY, NO_PROXYИсходящий прокси для модели ИИ, импорта с GitHub и pip.—
NODE_EXTRA_CA_CERTSФайл PEM внутреннего CA (путь внутри контейнера).—
DEPENDENCY_INDEX_URLИндекс для «своих пакетов» соревнований.https://pypi.org/simple
DEPENDENCY_FILES_HOSTSХосты, которые отдают файлы пакетов, через запятую.—
COLLOQ_ROOM_NETWORKnone — у комнат нет сети; open — нет запрета частных адресов.пусто: интернет есть, частные адреса закрыты
KERNEL_BLOCKED_CIDRSДополнительные подсети, закрытые для комнат.—
COLLOQ_HELPER_IMAGEОбраз служебного контейнера, который ставит правила iptables.образ самого сервера
COLLOQ_OFFLINE1 — ничего не скачивать, образы приходят через colloq-host load; его и записывает load.выключено
Образы и резервные копии
COLLOQ_HOMEКаталог состояния; задаётся до первого up. Читает только colloq-host./workspace/colloq
COLLOQ_IMAGEОбраз первого up; дальше образ выбирает colloq-host update (/etc/colloq/image).—
KERNEL_IMAGE_REPOОткуда брать готовые образы ядер: <repo>:v<версия>-<окружение>; none — собирать все окружения на месте.ghcr.io/colloq-edu/colloq-kernel
COLLOQ_REGISTRY_USER, COLLOQ_REGISTRY_TOKENВход в закрытый реестр (токен только на чтение); читает только colloq-host.—
BACKUP_KEEPСколько последних копий хранить; 0 — все.14
BACKUP_AGE_RECIPIENTОткрытый ключ age: копии шифруются для него. Восстановление — с BACKUP_AGE_IDENTITY, путём к закрытому ключу.—
COLLOQ_ALLOW_SCHEMA_DOWNGRADE1 — открыть базу, которую записала более новая версия. Без него старый образ на такой базе не запускается; обычный откат — restore --image с копией до обновления.—
COLLOQ_BACKUP_ATВремя ежедневной копии; читает backup-timer on.03:30
COLLOQ_BACKUP_BEFORE_UPDATE0 — не делать копию перед update; читает update.1
COLLOQ_FREEZE_UPDATES1 — отключить автообновления системы и закрепить пакеты NVIDIA. Его ставит только on-start для Vast; на сервере вуза не задавайте.выключено
Занятия
INSTITUTIONНазвание рядом с логотипом.—
UI_LANGUAGEЯзык интерфейса (ru, en), пока владелец не выберет его в панели.ru
TZЧасовой пояс: границы дня для дневных норм, даты.Europe/Moscow
ADMIN_EMAILПочта, которую форма владельца предлагает заранее.—
MAX_UPLOAD_MBПредел одного файла, загружаемого в комнату.50
MAX_SESSION_MBПредел всех загрузок в одну комнату; это не квота диска.1024
KERNEL_MEMПамять ядра комнаты; KERNEL_MEM_<ОКРУЖЕНИЕ> — для одного окружения.4g, у GPU-окружений 16g
KERNEL_CPUSЯдра процессора на комнату.2
KERNEL_OWN_MAX, KERNEL_OWN_PIDS, KERNEL_OWN_IDLE_MINКонтейнер личных тетрадей: сколько в нём ядер, потолок процессов, минуты простоя до остановки ядра.60, 2048, 30
KERNEL_ENV, KERNEL_PRELOADОкружение по умолчанию; какие окружения подготовить при старте.base; как KERNEL_ENV
KERNEL_GPUSКарты для GPU-комнат.все найденные
OPEN_SEMINAR_CREATIONРазрешить создавать комнаты через API без входа преподавателя.false
SESSION_SECRETКлюч подписи ссылок; новое значение делает недействительными все выданные ссылки.создаётся сам, data/session-secret
Оракул
AI_PROVIDERopenai, ollama, vllm, openrouter или custom.openai
OPENAI_API_KEYКлюч модели; без него оракул выключен (Ollama и vLLM работают без ключа).—
OPENAI_BASE_URLАдрес модели.https://api.openai.com/v1
OPENAI_MODELМодель.gpt-4o-mini
Вход через прокси (SSO)
AUTH_JWT_JWKS_URL, AUTH_JWT_AUDIENCE, AUTH_JWT_ISSUER и другие AUTH_JWT_*Вход через Teleport или другой прокси, который подписывает JWT: преподаватели узнаются по почте, студенты входят под своим именем. Как это устроено и какие поля токена читаются — в руководстве для Kubernetes; на машине те же переменные передаются colloq-host up. Если приложение публикует Teleport на этой же машине: COLLOQ_TUNNEL=none, а PUBLIC_URL — адрес приложения в Teleport.выключено

Резервные копии

colloq-host backup                # копия сейчас
colloq-host backup-timer on       # каждый день в 03:30; другое время — COLLOQ_BACKUP_AT=02:00
colloq-host backup-timer status

Таймер — это служба systemd: копия делается по часовому поясу машины, а пропущенная, пока машина была выключена, — сразу после включения. Копия — это пара файлов в /workspace/colloq/backups/: согласованный снимок базы colloq-<время>.db и архив colloq-<время>-files.tar.gz с файлами комнат, картинками вывода, файлами страниц занятий, данными и посылками соревнований, наборами пакетов, ключом подписи ссылок, setup-token и списками пакетов своих окружений. Файлы копируются на ходу и у идущего занятия могут измениться во время копирования, поэтому таймер лучше ставить на ночь. Хранятся 14 последних копий (BACKUP_KEEP), более старые удаляются после успешной копии. Образов ядер в копии нет: их скачают или соберут заново.

Копия — это ключи от сервера: в ней ключ подписи, setup-token и база с ключами входа преподавателей и ключом ИИ, если его вводили в панели. Файлы создаются с правами 0600. Уносите их с машины своими средствами (rsync, restic или borg в хранилище вуза) и храните зашифрованными: диск VM — не резервная копия. Зашифровать копию может и сам Colloq: задайте BACKUP_AGE_RECIPIENT — открытый ключ age, и обе части копии запишутся как .age. Закрытый ключ держите вне машины; для восстановления укажите путь к нему: BACKUP_AGE_IDENTITY=/root/colloq-backup.key REPLACE=1 colloq-host restore ….

Восстановление: положите пару файлов в /workspace/colloq/backups/ и выполните команду ниже. colloq-host остановит Colloq, восстановит базу и файлы и запустит его снова; REPLACE=1 нужен, если на машине уже есть база. Проверяйте восстановление на запасной VM хотя бы раз в семестр.

REPLACE=1 colloq-host restore backups/colloq-20260930-033000.db

Обновление и откат

colloq-host update ghcr.io/colloq-edu/colloq-server:X.Y.Z
colloq-host status

update скачивает образ, делает резервную копию и печатает команду отката — и только потом пересоздаёт контейнер приложения, так что новый образ встречается с базой уже после копии. Данные остаются на диске, ядра комнат продолжают работать, и новый сервер снова подключается к ним; перерыв длится секунды, открытые комнаты переподключаются сами. И всё же обновляйтесь между занятиями. Выбранный образ записывается в /etc/colloq/image и переживает перезагрузку. Новый colloq-host из нового образа update ставит сам. Только при переходе с 0.8.x, где colloq-host этого ещё не умел, сначала поставьте новый вручную: docker run --rm -v /usr/local/sbin:/host ghcr.io/colloq-edu/colloq-server:X.Y.Z install-host /host.

Прежний образ на базе, которую новая версия могла изменить, не проверяется. Поэтому откат — это прежний образ вместе с копией, сделанной перед обновлением; всё, что сделано после обновления, пропадёт. Эту команду и печатает update:

REPLACE=1 colloq-host restore --image ghcr.io/colloq-edu/colloq-server:<прежняя версия> \
  backups/colloq-<время>.db

Перезапуск Docker — например, при его обновлении — останавливает ядра комнат: тетради и файлы остаются, переменные Python теряются. Обновляйте Docker в окно обслуживания. Автообновления Ubuntu colloq-host не отключает.

Наблюдение, журналы и перезагрузка

АдресЧто проверяет
/api/livezПроцесс жив.
/api/readyzБаза и рабочие файлы в порядке; от Docker и ядер не зависит. Подходит для балансировщика и внешней проверки.
/api/healthПолная проверка: база, Docker и образ ядра, рабочие файлы, версия; при сбое — 503. Тексты ошибок видят только преподаватели и colloq-host status. Сразу после установки отвечает 503, пока готовится образ ядра.

Преподавателям доступен GET /api/instance/operations: возраст очереди, повторы, сбои сохранения тетрадей, резервы памяти и свободный диск.

Диск. Квоты на комнату нет: база, файлы комнат, посылки и копии лежат на одном разделе, и студент, заполнивший диск, остановит сохранение тетрадей у всех. Следите за свободным местом и inode на разделе /workspace/colloq, например с тревогой при заполнении на 80 %; жёсткий предел дают отдельный раздел или проектные квоты XFS.

Журнал. colloq-host logs — это docker logs контейнера colloq; Docker хранит 5 файлов по 50 МБ. В журнале есть адреса комнат, а адрес комнаты — это ссылка для входа, поэтому доступ к журналу равен доступу к комнатам.

Перезагрузка. Docker сам поднимает контейнер приложения (--restart unless-stopped). Контейнеры ядер не поднимаются: комната запустит ядро снова, когда в неё войдут или запустят ячейку. Тетради и файлы на месте, а переменные Python пропадают.

Что смотреть регулярно: свободный диск; шкалу памяти во вкладке «Ресурсы»; что ночная копия сделана и унесена с машины; colloq-host status перед занятием.

Безопасность и персональные данные

Что хранится. Всё — на этой VM, в /workspace/colloq:

  • data/colloq.db — комнаты и тетради с историей правок; имена, которые участники ввели при входе; посещаемость и число запусков; преподаватели (имя, почта) и их ключи входа; настройки оракула, включая ключ, если его ввели в панели; учёт вопросов оракулу; участники соревнований (логин Telegram или почта), посылки и результаты.
  • В data/ лежат ещё ключ подписи ссылок, setup-token, картинки вывода, файлы страниц занятий (page-files/), данные и скрытые ответы соревнований, наборы пакетов; в workspace/<комната>/ — файлы комнат, в backups/ — копии. Ключ ИИ, заданный переменной, лежит в /etc/colloq/colloq.env.
  • Срока хранения нет: данные живут, пока комнату или соревнование не удалят. Текст, удалённый из ячейки, остаётся в истории правок, которую по умолчанию видят участники. Браузер получает cookie устройства на год.

Что уходит провайдеру ИИ. При вопросе оракулу — тетради комнаты целиком (ячейки и вывод), имена файлов комнаты, файл, открытый у спрашивающего, и сам вопрос. Имена участников — только если включён переключатель «Имена учащихся в запросах к модели» (панель → «Оракул»; по умолчанию включён); иначе провайдер видит «Студент 1», «Студент 2» по порядку входа в комнату и «Преподаватель» для ведущих; в консилиуме — метки S1…SN, имена вместо них подставляются уже в консоли преподавателя. Переключатель можно выключить для всей установки. Имена, которые студенты сами написали в решениях, уходят в любом случае. Для чувствительных курсов используйте модель внутри сети (Ollama, vLLM) или не включайте оракул.

Соревнования. На досках для студентов чужие адреса почты сокращены (abc…@example.edu), логины Telegram показаны как есть; свою строку участник видит целиком, преподаватели — все строки. В редакторе соревнования, в строке «Кто видит лидерборд», доску можно оставить только участникам. Участника можно удалить из соревнования; вместе с ним с диска сервера уходят его посылки.

Журнал действий. Владелец видит в панели «Журнал действий»: входы сотрудников, изменения состава преподавателей, удаления и настройки (GET /api/admin/audit-log, только владельцу).

Доступ преподавателей. Владелец и преподаватели входят по личным ссылкам /admin/k/…; владелец может перевыпустить ссылку преподавателя, и старая сразу перестаёт действовать. Входа через SSO, LDAP и второго фактора пока нет; панель может закрыть прокси — SSO или список разрешённых адресов на /admin и /api/admin, студентам эти пути не нужны. Любой преподаватель может вести любую комнату, курс и соревнование: одна установка — одна команда преподавателей, доверяющих друг другу.

Cookies и HTTPS. Все cookies — HttpOnly и SameSite=Lax, за HTTPS-прокси — ещё и Secure; про HSTS см. выше.

Честные ограничения:

  • нет SSO;
  • нет квоты диска на комнату;
  • комната — общее рабочее место: участники делят ядро, файлы, пользователя Linux и контейнер личных тетрадей, поэтому для индивидуально оцениваемых и конфиденциальных работ комнаты не подходят;
  • ссылку комнаты нельзя отозвать: кто её получил, тот войдёт и по умолчанию сможет запускать код;
  • загруженные файлы не проверяются антивирусом;
  • шрифт интерфейса HSE Sans принадлежит НИУ ВШЭ и не покрыт лицензией MIT: другому вузу его стоит заменить (THIRD_PARTY_NOTICES.md).

Kubernetes и одноузловой k3s

Если в организации уже есть кластер Kubernetes, ставьте Colloq Helm-чартом в пространство имён: это описано в разделе «Colloq в вашем Kubernetes» — отдельный под на комнату, приватный брокер, сетевые политики, образы по дайджестам. Скрипт, который сам ставит одноузловой k3s на голую VM («Установка на k3s»), остаётся предварительным путём для тех, у кого кластера нет: ни один опубликованный выпуск по 0.9.0 включительно не содержит его комплекта (release.json, colloq-deploy.tar.gz, SHA256SUMS), так что поставить его из опубликованного нельзя. Без кластера рекомендуемый путь — эта страница.