Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
# Remove abandoned temporary upload objects after 30 minutes.
|
||||||
|
*/5 * * * * root find /var/www/contracts-upload/ -type f -mmin +30 -delete
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Temporary HTTP-only vhost for the initial Let's Encrypt HTTP-01 challenge.
|
||||||
|
# Install as /etc/nginx/sites-enabled/contracts-upload.conf, issue the
|
||||||
|
# certificate, then replace it with nginx-contracts-upload.conf.
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name contracts-upload.sinefo.ru;
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/acme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
# Dedicated WebDAV upload buffer for Contracts on VM213.
|
||||||
|
# Install as /etc/nginx/sites-enabled/contracts-upload.conf.
|
||||||
|
|
||||||
|
# sites-enabled is included from Nginx's http context, where map is valid.
|
||||||
|
map $http_origin $contracts_upload_cors_origin {
|
||||||
|
default "";
|
||||||
|
~^https://contractor\.pythonk8s\.dev\.nubes\.ru$ $http_origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name contracts-upload.sinefo.ru;
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/acme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name contracts-upload.sinefo.ru;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/contracts-upload.sinefo.ru/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/contracts-upload.sinefo.ru/privkey.pem;
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||||
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||||
|
|
||||||
|
# Match the app's 50 MiB per-file limit; uploads are raw PUT bodies.
|
||||||
|
client_max_body_size 50m;
|
||||||
|
|
||||||
|
location /contracts-upload/ {
|
||||||
|
alias /var/www/contracts-upload/;
|
||||||
|
dav_methods PUT DELETE;
|
||||||
|
create_full_put_path on;
|
||||||
|
client_max_body_size 50m;
|
||||||
|
add_header Access-Control-Allow-Origin $contracts_upload_cors_origin always;
|
||||||
|
add_header Access-Control-Allow-Methods "PUT, GET, OPTIONS, DELETE" always;
|
||||||
|
add_header Access-Control-Allow-Headers "Content-Type" always;
|
||||||
|
add_header Access-Control-Max-Age 86400 always;
|
||||||
|
if ($request_method = OPTIONS) { return 204; }
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -92,22 +92,6 @@ server {
|
|||||||
client_max_body_size 100m;
|
client_max_body_size 100m;
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── VM-буфер загрузки contracts (паттерн drhider) ──────────────
|
|
||||||
# Браузер кладёт файл сюда PUT (мимо шлюза кластера ~64КБ), бэк тянет сам.
|
|
||||||
# Файлы: /var/www/contracts-upload/ (нужно создать, chown www-data).
|
|
||||||
# CORS: origin фронтенда = contractor.pythonk8s.dev.nubes.ru (ingress, подтверждено).
|
|
||||||
location /contracts-upload/ {
|
|
||||||
alias /var/www/contracts-upload/;
|
|
||||||
dav_methods PUT DELETE;
|
|
||||||
create_full_put_path on;
|
|
||||||
client_max_body_size 1024m;
|
|
||||||
add_header Access-Control-Allow-Origin https://contractor.pythonk8s.dev.nubes.ru always;
|
|
||||||
add_header Access-Control-Allow-Methods 'PUT, GET, OPTIONS, DELETE' always;
|
|
||||||
add_header Access-Control-Allow-Headers 'Content-Type' always;
|
|
||||||
add_header Access-Control-Max-Age 86400 always;
|
|
||||||
if ($request_method = OPTIONS) { return 204; }
|
|
||||||
}
|
|
||||||
|
|
||||||
listen 443 ssl; # managed by Certbot
|
listen 443 ssl; # managed by Certbot
|
||||||
ssl_certificate /etc/letsencrypt/live/contracts.kube5s.ru/fullchain.pem; # managed by Certbot
|
ssl_certificate /etc/letsencrypt/live/contracts.kube5s.ru/fullchain.pem; # managed by Certbot
|
||||||
ssl_certificate_key /etc/letsencrypt/live/contracts.kube5s.ru/privkey.pem; # managed by Certbot
|
ssl_certificate_key /etc/letsencrypt/live/contracts.kube5s.ru/privkey.pem; # managed by Certbot
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
# Инцидент: ошибки загрузки файлов через 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`](../site/static/app.js) содержит
|
||||||
|
`VM_UPLOAD_URL = 'https://contracts.kube5s.ru/contracts-upload/'`.
|
||||||
|
- [`site/config.py`](../site/config.py) задаёт тот же домен для `VM_UPLOAD_URL`
|
||||||
|
и `VM_UPLOAD_PREFIX`. Backend регистрирует `upload_refs` с этим
|
||||||
|
`VM_UPLOAD_PREFIX` через [`site/routes/__init__.py`](../site/routes/__init__.py).
|
||||||
|
- [`deploy/nginx-contracts.conf`](../deploy/nginx-contracts.conf) содержит
|
||||||
|
WebDAV location `/contracts-upload/` с каталогом
|
||||||
|
`/var/www/contracts-upload/` и CORS origin
|
||||||
|
`https://contractor.pythonk8s.dev.nubes.ru`. Этот location находится в
|
||||||
|
virtual host `contracts.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 origin
|
||||||
|
`https://drhider.pythonk8s.dev.nubes.ru`, не для Контрактора.
|
||||||
|
- На `obfuscator-upload.sinefo.ru/obfuscator-upload/` маршрут существует, но
|
||||||
|
`Access-Control-Allow-Origin` возвращается только для Obfuscator origin
|
||||||
|
`https://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 host `contracts.kube5s.ru`. Наличие каталога само по себе не
|
||||||
|
делает его доступным по другому hostname.
|
||||||
|
|
||||||
|
## Почему прямое исправление URL недостаточно
|
||||||
|
|
||||||
|
Замена только домена в Контракторе не решит проблему:
|
||||||
|
|
||||||
|
1. `/contracts-upload/` на `upload.sinefo.ru` сейчас не настроен и отвечает
|
||||||
|
`404`.
|
||||||
|
2. Существующий `/drhider-upload/` предназначен для DrHider и не разрешает
|
||||||
|
origin Контрактора в CORS.
|
||||||
|
3. Буфер Obfuscator имеет отдельные hostname и путь, отдельную конфигурацию и
|
||||||
|
allowlist origin. Он не является готовым Contracts endpoint.
|
||||||
|
4. URL на фронтенде и доверенный префикс backend должны совпадать. Иначе браузер
|
||||||
|
может загрузить объект, но `upload_refs` отклонит URL при SSRF-проверке либо
|
||||||
|
backend будет пытаться забрать объект с другого адреса.
|
||||||
|
5. 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`](../../../drhider/OBFUSCATOR/README.md) и
|
||||||
|
настроено в
|
||||||
|
[`obfuscator-upload.conf`](../../../drhider/OBFUSCATOR/deploy/vm213/nginx/obfuscator-upload.conf).
|
||||||
|
Контрактор должен получить аналогично согласованный endpoint, а не использовать
|
||||||
|
Obfuscator/DrHider путь без изменения и проверки его конфигурации.
|
||||||
|
|
||||||
|
## План исправления
|
||||||
|
|
||||||
|
Первоначальный план обновлён после предоставления DNS-записи
|
||||||
|
`contracts-upload.sinefo.ru`. Код и source Nginx изменены локально; VM213 и
|
||||||
|
развёрнутое приложение ещё не обновлялись.
|
||||||
|
|
||||||
|
1. **Hostname и DNS — выполнено.** Выбран `contracts-upload.sinefo.ru`;
|
||||||
|
публичные DNS `1.1.1.1` и `8.8.8.8` возвращают `5.172.178.213`.
|
||||||
|
2. **Настроить VM213 — выполнено.** Проверен отдельный каталог
|
||||||
|
`/var/www/contracts-upload/` и права пользователя Nginx. Для первоначального
|
||||||
|
выпуска сертификата установить
|
||||||
|
[`deploy/nginx-contracts-upload-acme.conf`](../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`](../deploy/nginx-contracts-upload.conf),
|
||||||
|
снова выполнить `nginx -t` и reload. Полный vhost задаёт отдельный WebDAV
|
||||||
|
путь, `PUT`/`GET`/`DELETE`, `OPTIONS`, ограничение тела 50 MiB и CORS allowlist
|
||||||
|
через `map` для точного origin `https://contractor.pythonk8s.dev.nubes.ru`.
|
||||||
|
Предел `50m` соответствует backend-лимиту 50 MiB; не копировать 1024 MiB из
|
||||||
|
Obfuscator, поскольку Contracts не принимает файлы такого размера. Установить
|
||||||
|
[`deploy/contracts-upload-cleanup.cron`](../deploy/contracts-upload-cleanup.cron)
|
||||||
|
как `/etc/cron.d/contracts-upload-cleanup`, чтобы удалять оставшиеся объекты
|
||||||
|
старше 30 минут. Cron установлен в `/etc/cron.d/contracts-upload-cleanup`.
|
||||||
|
Не менять маршруты DrHider или Obfuscator и не объединять их каталоги с Contracts.
|
||||||
|
3. **Код приложения — выполнено локально, deploy ожидает выполнения.**
|
||||||
|
Frontend `VM_UPLOAD_URL` и backend `VM_UPLOAD_PREFIX` default приведены к
|
||||||
|
`https://contracts-upload.sinefo.ru/contracts-upload/`; обновлены
|
||||||
|
frontend/backend defaults, пример конфига и default URL нагрузочного теста.
|
||||||
|
Версия приложения поднята до `2.0.24`. Проверить переменные окружения
|
||||||
|
развёртывания: `VM_UPLOAD_PREFIX` не должен переопределять новый endpoint
|
||||||
|
старым значением.
|
||||||
|
4. **Синхронизировать конфигурацию VM — выполнено.** Источник Nginx вынесен в
|
||||||
|
отдельные bootstrap- и TLS-конфиги; старый upload location удалён из
|
||||||
|
[`deploy/nginx-contracts.conf`](../deploy/nginx-contracts.conf). Конфигурация
|
||||||
|
TLS-vhost и cron установлена на VM213; Nginx config test/reload успешны.
|
||||||
|
Деплой приложения Контрактора — отдельная операция, ещё не выполнена.
|
||||||
|
5. **Проверить endpoint до обработки документов — выполнено.**
|
||||||
|
- DNS разрешается в `5.172.178.213`; TLS сертификат валиден.
|
||||||
|
- `OPTIONS` с origin Контрактора отвечает `204` и содержит точный
|
||||||
|
`Access-Control-Allow-Origin`, разрешённые методы и заголовки. С
|
||||||
|
посторонним origin `Access-Control-Allow-Origin` не отправляется.
|
||||||
|
- Синтетический объект прошёл `PUT` (`201`) → `GET` (байты совпали) →
|
||||||
|
`DELETE` (`204`). Объект удалён.
|
||||||
|
6. **Проверить путь через приложение безопасно.** В тестовой сессии/батче
|
||||||
|
загрузить синтетический небольшой файл, убедиться в успешном
|
||||||
|
`POST /api/upload_refs` и очистить созданную тестовую запись/объект. Не
|
||||||
|
использовать пользовательские документы для проверки, пока синтетический
|
||||||
|
тест не пройден.
|
||||||
|
7. **Только после успешной проверки** проверить обычную загрузку и последующие
|
||||||
|
этапы обработки выбранных документов.
|
||||||
|
|
||||||
|
## Статус
|
||||||
|
|
||||||
|
- Причина исходной сетевой ошибки подтверждена: используемый 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 Контрактора и обработка документов ещё не проверены.
|
||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
"""Конфигурация приложения — все настройки в одном месте."""
|
"""Конфигурация приложения — все настройки в одном месте."""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
VERSION = "2.0.23"
|
VERSION = "2.0.24"
|
||||||
|
|
||||||
LLM_URL = os.getenv("LLM_API_URL", "https://api.aillm.ru/v1/chat/completions")
|
LLM_URL = os.getenv("LLM_API_URL", "https://api.aillm.ru/v1/chat/completions")
|
||||||
LLM_KEY = os.getenv("LLM_API_KEY", "")
|
LLM_KEY = os.getenv("LLM_API_KEY", "")
|
||||||
@@ -14,9 +14,9 @@ CONVERT_SERVICE_URL = os.getenv("CONVERT_SERVICE_URL", "http://containerk8s.df36
|
|||||||
# ── VM-буфер загрузки (паттерн drhider) ──────────────────────────────
|
# ── VM-буфер загрузки (паттерн drhider) ──────────────────────────────
|
||||||
# Браузер кладёт файл на ВМ через WebDAV (мимо шлюза кластера ~64КБ),
|
# Браузер кладёт файл на ВМ через WebDAV (мимо шлюза кластера ~64КБ),
|
||||||
# бэк сам тянет его исходящим GET (egress без лимита).
|
# бэк сам тянет его исходящим GET (egress без лимита).
|
||||||
VM_UPLOAD_URL = os.getenv("VM_UPLOAD_URL", "https://contracts.kube5s.ru/contracts-upload/")
|
VM_UPLOAD_URL = os.getenv("VM_UPLOAD_URL", "https://contracts-upload.sinefo.ru/contracts-upload/")
|
||||||
# SSRF-защита: тянуть можно ТОЛЬКО с этого префикса.
|
# SSRF-защита: тянуть можно ТОЛЬКО с этого префикса.
|
||||||
VM_UPLOAD_PREFIX = os.getenv("VM_UPLOAD_PREFIX", "https://contracts.kube5s.ru/contracts-upload/")
|
VM_UPLOAD_PREFIX = os.getenv("VM_UPLOAD_PREFIX", "https://contracts-upload.sinefo.ru/contracts-upload/")
|
||||||
# Лимит на один файл (совпадает с фронтом).
|
# Лимит на один файл (совпадает с фронтом).
|
||||||
VM_UPLOAD_MAX_BYTES = int(os.getenv("VM_UPLOAD_MAX_BYTES", str(50 * 1024 * 1024)))
|
VM_UPLOAD_MAX_BYTES = int(os.getenv("VM_UPLOAD_MAX_BYTES", str(50 * 1024 * 1024)))
|
||||||
# Ретраи pull с ВМ (разовые DNS/сетевые сбои не роняют загрузку).
|
# Ретраи pull с ВМ (разовые DNS/сетевые сбои не роняют загрузку).
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
var VM_API = '';
|
var VM_API = '';
|
||||||
// ВМ-буфер загрузки (паттерн drhider): браузер кладёт файл сюда (WebDAV, мимо шлюза),
|
// ВМ-буфер загрузки (паттерн drhider): браузер кладёт файл сюда (WebDAV, мимо шлюза),
|
||||||
// бэк сам тянет его по /api/upload_refs. Origin должен быть в CORS на nginx ВМ.
|
// бэк сам тянет его по /api/upload_refs. Origin должен быть в CORS на nginx ВМ.
|
||||||
var VM_UPLOAD_URL = 'https://contracts.kube5s.ru/contracts-upload/';
|
var VM_UPLOAD_URL = 'https://contracts-upload.sinefo.ru/contracts-upload/';
|
||||||
// SITE_URL удалён (Фаза 4) — не использовался
|
// SITE_URL удалён (Фаза 4) — не использовался
|
||||||
|
|
||||||
// state.files — теперь в state.js (Фаза 0: state + render)
|
// state.files — теперь в state.js (Фаза 0: state + render)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import httpx
|
|||||||
def main():
|
def main():
|
||||||
ap = argparse.ArgumentParser(description="HTTP-стресс contracts-flask")
|
ap = argparse.ArgumentParser(description="HTTP-стресс contracts-flask")
|
||||||
ap.add_argument("--url", default="http://127.0.0.1:5000")
|
ap.add_argument("--url", default="http://127.0.0.1:5000")
|
||||||
ap.add_argument("--vm-url", default="https://contracts.kube5s.ru/contracts-upload/", help="ВМ WebDAV-буфер (PUT файла)")
|
ap.add_argument("--vm-url", default="https://contracts-upload.sinefo.ru/contracts-upload/", help="ВМ WebDAV-буфер (PUT файла)")
|
||||||
ap.add_argument("--n", type=int, default=1000, help="число запросов")
|
ap.add_argument("--n", type=int, default=1000, help="число запросов")
|
||||||
ap.add_argument("--threads", type=int, default=32, help="параллельных потоков")
|
ap.add_argument("--threads", type=int, default=32, help="параллельных потоков")
|
||||||
ap.add_argument("--size", type=int, default=100000, help="размер файла в байтах (если не задан --file)")
|
ap.add_argument("--size", type=int, default=100000, help="размер файла в байтах (если не задан --file)")
|
||||||
|
|||||||
@@ -154,3 +154,20 @@ store_result(res.session, result_zip) # если нужно отдать
|
|||||||
|
|
||||||
- Слой 3 — логика приложения (обработка файлов из сессии, SSE-прогресс) у каждого своя.
|
- Слой 3 — логика приложения (обработка файлов из сессии, SSE-прогресс) у каждого своя.
|
||||||
- CORS на ВМ-буфере — если домен приложения другой, правится nginx на ВМ, а не код модуля.
|
- CORS на ВМ-буфере — если домен приложения другой, правится nginx на ВМ, а не код модуля.
|
||||||
|
|
||||||
|
## Инцидент Contracts VM-буфера (2026-10-30)
|
||||||
|
|
||||||
|
Контрактор использовал `contracts.kube5s.ru/contracts-upload/`, но DNS для
|
||||||
|
`contracts.kube5s.ru` возвращал `NXDOMAIN`. DNS-запись для отдельного hostname
|
||||||
|
`contracts-upload.sinefo.ru` теперь добавлена и проверена на публичных
|
||||||
|
резолверах. Переключение только на существующий
|
||||||
|
DrHider или Obfuscator endpoint недостаточно: у них другие пути и CORS allowlist,
|
||||||
|
и тестовый путь `/contracts-upload/` на этих хостах отвечал `404`. Новый
|
||||||
|
hostname теперь настроен на VM213 с отдельным TLS-сертификатом, Nginx vhost и
|
||||||
|
cron-очисткой временных файлов. Проверены HTTPS, CORS для Контрактора и прямой
|
||||||
|
синтетический цикл PUT/GET/DELETE.
|
||||||
|
|
||||||
|
Код приложения и source Nginx настроены локально; Nginx-конфиг буфера уже
|
||||||
|
установлен на VM213, но само приложение пока не redeployed. Причина, результаты
|
||||||
|
DNS/CORS/TLS-проверок и дальнейший план описаны в
|
||||||
|
[отчёте об инциденте](../docs/upload-buffer-incident-2026-10-30.md).
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ PULL_RETRIES = 3
|
|||||||
PULL_RETRY_DELAY = 2 # секунды между попытками
|
PULL_RETRY_DELAY = 2 # секунды между попытками
|
||||||
|
|
||||||
# Доверенный префикс ВМ-буфера — валидация URL при pull (защита от SSRF)
|
# Доверенный префикс ВМ-буфера — валидация URL при pull (защита от SSRF)
|
||||||
VM_UPLOAD_PREFIX = "https://contracts.kube5s.ru/drhider-upload/"
|
VM_UPLOAD_PREFIX = "https://contracts-upload.sinefo.ru/contracts-upload/"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"vmUploadUrl": "https://contracts.kube5s.ru/drhider-upload/",
|
"vmUploadUrl": "https://contracts-upload.sinefo.ru/contracts-upload/",
|
||||||
"allowedExt": [".pdf", ".doc", ".docx", ".txt", ".md"],
|
"allowedExt": [".pdf", ".doc", ".docx", ".txt", ".md"],
|
||||||
"maxFileBytes": 52428800,
|
"maxFileBytes": 52428800,
|
||||||
"maxSessionBytes": 524288000,
|
"maxSessionBytes": 524288000,
|
||||||
"apiPrefix": "/api",
|
"apiPrefix": "/api",
|
||||||
"vmUploadPrefix": "https://contracts.kube5s.ru/drhider-upload/",
|
"vmUploadPrefix": "https://contracts-upload.sinefo.ru/contracts-upload/",
|
||||||
"pullRetries": 3,
|
"pullRetries": 3,
|
||||||
"pullRetryDelay": 2,
|
"pullRetryDelay": 2,
|
||||||
"pullTimeout": 120,
|
"pullTimeout": 120,
|
||||||
|
|||||||
Reference in New Issue
Block a user