Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
12 KiB
Инцидент: ошибки загрузки файлов через VM-буфер — 2026-10-30
Краткий вывод
Контрактор отправлял выбранные файлы на https://contracts.kube5s.ru/contracts-upload/.
На момент проверки 2026-10-30 имя contracts.kube5s.ru возвращало NXDOMAIN у
публичных DNS-резолверов 1.1.1.1 и 8.8.8.8. Поэтому браузер не мог разрешить
адрес назначения и показывал общую ошибку «Сетевая ошибка при отправке файла в
буфер». Запрос не доходил до Nginx и WebDAV.
Форматы и содержимое выбранных документов не были причиной этого сбоя. Реальные
файлы из пользовательской папки не отправлялись; проверки upload-инфраструктуры
ограничились DNS, чтением конфигураций и безопасными HTTP OPTIONS-запросами.
Подтверждённые факты
Настройка Контрактора
- Развёрнутая страница Контрактора показывала версию
2.0.23. - Загруженный браузером
site/static/app.jsсодержитVM_UPLOAD_URL = 'https://contracts.kube5s.ru/contracts-upload/'. site/config.pyзадаёт тот же домен дляVM_UPLOAD_URLиVM_UPLOAD_PREFIX. Backend регистрируетupload_refsс этимVM_UPLOAD_PREFIXчерезsite/routes/__init__.py.deploy/nginx-contracts.confсодержит WebDAV location/contracts-upload/с каталогом/var/www/contracts-upload/и CORS originhttps://contractor.pythonk8s.dev.nubes.ru. Этот location находится в virtual hostcontracts.kube5s.ru.
DNS и доступные буферы
- Запросы к
1.1.1.1и8.8.8.8дляcontracts.kube5s.ru AвернулиNXDOMAIN. - После первоначальной диагностики владелец DNS добавил
contracts-upload.sinefo.ru A -> 5.172.178.213. Повторная проверка обоих публичных резолверов подтвердила эту запись. - При первой проверке до настройки Nginx новый hostname отдавал чужой TLS-
сертификат. После установки HTTP challenge vhost сертификат Let's Encrypt
выпущен для
contracts-upload.sinefo.ru; срок действия до 2027-01-28. - Nginx virtual host для нового hostname теперь установлен на VM213, а
nginx -tи reload прошли успешно. upload.sinefo.ruразрешался в5.172.178.213, ноhttps://upload.sinefo.ru/contracts-upload/...отвечал404.- На
upload.sinefo.ru/drhider-upload/WebDAV-маршрут существует, ноAccess-Control-Allow-Originвозвращается только для DrHider originhttps://drhider.pythonk8s.dev.nubes.ru, не для Контрактора. - На
obfuscator-upload.sinefo.ru/obfuscator-upload/маршрут существует, ноAccess-Control-Allow-Originвозвращается только для Obfuscator originhttps://obfuscator.pythonk8s.services.ngcloud.ru, не для Контрактора. - Запросы
OPTIONSдля origin Контрактора к обоим существующим маршрутам возвращали204, но безAccess-Control-Allow-Origin. Такой ответ не разрешает браузерный запрос; кроме того, путь/contracts-upload/на этих хостах не настроен. - На VM213 (
5.172.178.213) при проверке существовали каталог/var/www/contracts-upload/и старый Nginx location/contracts-upload/внутри virtual hostcontracts.kube5s.ru. Наличие каталога само по себе не делает его доступным по другому hostname.
Почему прямое исправление URL недостаточно
Замена только домена в Контракторе не решит проблему:
/contracts-upload/наupload.sinefo.ruсейчас не настроен и отвечает404.- Существующий
/drhider-upload/предназначен для DrHider и не разрешает origin Контрактора в CORS. - Буфер Obfuscator имеет отдельные hostname и путь, отдельную конфигурацию и allowlist origin. Он не является готовым Contracts endpoint.
- URL на фронтенде и доверенный префикс backend должны совпадать. Иначе браузер
может загрузить объект, но
upload_refsотклонит URL при SSRF-проверке либо backend будет пытаться забрать объект с другого адреса. - Backend
VM_UPLOAD_PREFIXможет быть переопределён переменной окружения и должен совпадать с URL буфера. URL браузерной загрузки задаётся константойVM_UPLOAD_URLвsite/static/app.js; переменная окружения с таким именем сама по себе статический JavaScript не меняет.
Отличие от Obfuscator
Актуальный Obfuscator использует согласованную отдельную конфигурацию:
- hostname
obfuscator-upload.sinefo.ru; - путь
/obfuscator-upload/; - отдельный каталог
/var/www/obfuscator-upload/; - CORS allowlist для
https://obfuscator.pythonk8s.services.ngcloud.ru; - один и тот же URL-префикс на фронтенде и backend.
Это описано в OBFUSCATOR/README.md и
настроено в
obfuscator-upload.conf.
Контрактор должен получить аналогично согласованный endpoint, а не использовать
Obfuscator/DrHider путь без изменения и проверки его конфигурации.
План исправления
Первоначальный план обновлён после предоставления DNS-записи
contracts-upload.sinefo.ru. Код и source Nginx изменены локально; VM213 и
развёрнутое приложение ещё не обновлялись.
- Hostname и DNS — выполнено. Выбран
contracts-upload.sinefo.ru; публичные DNS1.1.1.1и8.8.8.8возвращают5.172.178.213. - Настроить VM213 — выполнено. Проверен отдельный каталог
/var/www/contracts-upload/и права пользователя Nginx. Для первоначального выпуска сертификата установитьdeploy/nginx-contracts-upload-acme.confкак/etc/nginx/sites-enabled/contracts-upload.conf, выполнитьnginx -tи только при успехе reload. Первая попытка Certbot завершилась временным CAA DNS timeout; повторная попытка выпустила сертификат. После этого временный конфиг заменён полнымdeploy/nginx-contracts-upload.conf, снова выполнитьnginx -tи reload. Полный vhost задаёт отдельный WebDAV путь,PUT/GET/DELETE,OPTIONS, ограничение тела 50 MiB и CORS allowlist черезmapдля точного originhttps://contractor.pythonk8s.dev.nubes.ru. Предел50mсоответствует backend-лимиту 50 MiB; не копировать 1024 MiB из Obfuscator, поскольку Contracts не принимает файлы такого размера. Установитьdeploy/contracts-upload-cleanup.cronкак/etc/cron.d/contracts-upload-cleanup, чтобы удалять оставшиеся объекты старше 30 минут. Cron установлен в/etc/cron.d/contracts-upload-cleanup. Не менять маршруты DrHider или Obfuscator и не объединять их каталоги с Contracts. - Код приложения — выполнено локально, deploy ожидает выполнения.
Frontend
VM_UPLOAD_URLи backendVM_UPLOAD_PREFIXdefault приведены кhttps://contracts-upload.sinefo.ru/contracts-upload/; обновлены frontend/backend defaults, пример конфига и default URL нагрузочного теста. Версия приложения поднята до2.0.24. Проверить переменные окружения развёртывания:VM_UPLOAD_PREFIXне должен переопределять новый endpoint старым значением. - Синхронизировать конфигурацию VM — выполнено. Источник Nginx вынесен в
отдельные bootstrap- и TLS-конфиги; старый upload location удалён из
deploy/nginx-contracts.conf. Конфигурация TLS-vhost и cron установлена на VM213; Nginx config test/reload успешны. Деплой приложения Контрактора — отдельная операция, ещё не выполнена. - Проверить endpoint до обработки документов — выполнено.
- DNS разрешается в
5.172.178.213; TLS сертификат валиден. OPTIONSс origin Контрактора отвечает204и содержит точныйAccess-Control-Allow-Origin, разрешённые методы и заголовки. С посторонним originAccess-Control-Allow-Originне отправляется.- Синтетический объект прошёл
PUT(201) →GET(байты совпали) →DELETE(204). Объект удалён.
- DNS разрешается в
- Проверить путь через приложение безопасно. В тестовой сессии/батче
загрузить синтетический небольшой файл, убедиться в успешном
POST /api/upload_refsи очистить созданную тестовую запись/объект. Не использовать пользовательские документы для проверки, пока синтетический тест не пройден. - Только после успешной проверки проверить обычную загрузку и последующие этапы обработки выбранных документов.
Статус
- Причина исходной сетевой ошибки подтверждена: используемый hostname
contracts.kube5s.ruвернулNXDOMAIN. - DNS, TLS, Nginx vhost, CORS и прямой синтетический WebDAV цикл проверены успешно.
- Причина установлена до этапов HTTP/WebDAV, CORS и обработки документов.
- URL/defaults, версия приложения и source Nginx обновлены локально.
- Конфигурация буфера и cron уже установлены на VM213.
- Изменения приложения ещё не запушены и не redeployed; end-to-end загрузка через UI Контрактора и обработка документов ещё не проверены.