docs(history): раскладка HISTORY по тематическим папкам (75 файлов)
Было: 41 файл в корне HISTORY/ + авторские папки OPUS/ и SONNET/ (34 файла). Стало — тематическая нумерация в стиле NOTES/ (10_, 20_, …): 10_reviews/ ревью кода и разборы от LLM (2) 20_releases/ заливки версий в реестр, чистки реестра, нумерация версий (8) 30_provider/ ядро провайдера: архитектура, модификаторы, UUID, nested (6) 40_generator/ генератор YAML/спеки, формат MAN (3) 50_docs/ пайплайн документации, навигация, публикация, хостинг S3 (9) 60_stands/ стенды и примеры: CRUD, FullPipe, Штурвал, TEST_STAND (7) 70_infra/ реестр, API Gateway, DDoS-Guard, VPN/213, зеркала (4) 90_llm/ диалоги и промпты с LLM вне тематики: OPUS/, SONNET/, gemini/ (34) OPUS/ и SONNET/ перенесены как есть в 90_llm/ — чтобы не рвать пары «бриф → ответ» внутри диалогов. Все переносы — через git mv (история сохранена). Перед правкой: TMP/backup_2026-10-02/HISTORY_before_restructure.tar.gz. Перекрёстные ссылки обновляются следующим коммитом.
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
# 2026-07-01 — DDoS-Guard 403 + Registry Fix
|
||||
|
||||
## Проблема 1: 403 от DDoS-Guard при вызове ColdFusion API
|
||||
|
||||
### Симптомы
|
||||
Terraform provider возвращал `HTTP статус 403` при создании ресурса `nubes_s3bucket`.
|
||||
|
||||
### Причина
|
||||
5 мест в коде делали HTTP-запросы к API без заголовка `User-Agent`. DDoS-Guard блокирует запросы без User-Agent.
|
||||
|
||||
### Исправление (v5.0.75)
|
||||
|
||||
| Файл | Строка | Функция |
|
||||
|---|---|---|
|
||||
| `universal_rebuild/internal/core/client.go` | ~522 | `FindExistingInstances` (пагинированный поиск) |
|
||||
| `universal_rebuild/internal/core/client.go` | ~597 | `GetInstanceState` |
|
||||
| `universal_rebuild/internal/core/client.go` | ~644 | `GetInstanceStateRaw` |
|
||||
| `universal_rebuild/internal/core/client.go` | ~865 | `doRequest` |
|
||||
| `universal_rebuild/internal/resources_core/domain_collision.go` | ~99 | проверка коллизий доменов |
|
||||
|
||||
Все прямые HTTP-вызовы теперь добавляют `req.Header.Set("User-Agent", "Mozilla/5.0")`.
|
||||
Пакетная константа `userAgent` вынесена на уровень пакета в `client.go`.
|
||||
|
||||
### Другие условия обхода DDoS-Guard (уже были настроены):
|
||||
- `TLSNextProto = make(map[string]func(...))` — отключение HTTP/2 ALPN
|
||||
- `?endpoint=` формат с rawQuery (без %2F)
|
||||
- `req.Close = true` (свежий TCP на каждый запрос)
|
||||
- `InsecureSkipVerify = true`
|
||||
- Fresh Transport (не клон DefaultTransport)
|
||||
|
||||
---
|
||||
|
||||
## Проблема 2: Registry-server не отдавал API
|
||||
|
||||
### Симптомы
|
||||
```bash
|
||||
curl https://terra.k8c.ru/v1/providers/nubes-test/nubes/versions
|
||||
# → "Not Found"
|
||||
|
||||
terraform init
|
||||
# → "provider registry terra.k8c.ru does not have a provider named terra.k8c.ru/nubes-test/nubes"
|
||||
```
|
||||
|
||||
### Причина
|
||||
Две ошибки в коде registry-server (`/home/naeel/terra/registry/operator/cmd/registry/main.go` на ВМ 5.172.178.213):
|
||||
|
||||
1. **Неполный ID в ответе `listVersions`:**
|
||||
```go
|
||||
// Было:
|
||||
ID: fmt.Sprintf("%s/%s", namespace, pType) // "nubes-test/nubes"
|
||||
// Стало:
|
||||
ID: fmt.Sprintf("%s/%s/%s", hostname, namespace, pType) // "terra.k8c.ru/nubes-test/nubes"
|
||||
```
|
||||
Terraform сверяет `id` из ответа с `source` в конфигурации. Без hostname — mismatch.
|
||||
|
||||
2. **Docker-сборка исключала модуль `registrykeys/`:**
|
||||
В `.dockerignore` была строка `registrykeys/`. Модуль содержит GPG-ключ, необходимый для сборки.
|
||||
Убрал из `.dockerignore` + добавил `COPY registrykeys ./registrykeys` в Dockerfile.
|
||||
|
||||
3. **GPG-ключ не совпадал:**
|
||||
Registry-server публиковал ключ `CB3A0DF161ECC416` (tazet@narod.ru), а SHA256SUMS был подписан ключом `3EC4673EB798238A` (Nubes Provider).
|
||||
Обновил `registrykeys/public_key.go` на ключ `Nubes Provider`.
|
||||
|
||||
### Хронология фиксов реестра
|
||||
|
||||
| Тег Docker-образа | Что исправлено |
|
||||
|---|---|
|
||||
| `router-fix` | Индексы в роутере (ошибочно — terraform шлёт URL без hostname) |
|
||||
| `router-fix-v2` | ID в listVersions (добавлен hostname) |
|
||||
| `router-fix-v3` | Откат роутера + только ID fix |
|
||||
| `gpg-fix` | Обновлён GPG ключ на Nubes Provider |
|
||||
|
||||
### Финальный образ
|
||||
`naeel/terraform-registry-server:gpg-fix` — работает в k8s (namespace: terra, deployment: registry-server).
|
||||
|
||||
### Важное замечание про URL
|
||||
Terraform шлёт запросы БЕЗ hostname в пути:
|
||||
```
|
||||
GET /v1/providers/{namespace}/{type}/versions
|
||||
GET /v1/providers/{namespace}/{type}/{version}/download/{os}/{arch}
|
||||
```
|
||||
(не `/v1/providers/{hostname}/{namespace}/{type}/...`)
|
||||
|
||||
Роутер в registry-server корректно парсит такой формат.
|
||||
|
||||
---
|
||||
|
||||
## Проблема 3: Медленное скачивание с локальной машины
|
||||
|
||||
### Симптомы
|
||||
`curl` с локальной машины (Krupski) качает 12 МБ zip ~30 секунд (600 байт/сек).
|
||||
|
||||
### Причина
|
||||
Локальная машина не в VPN/не в ЦОДе. Трафик идёт через DDoS-Guard, который режет скорость.
|
||||
|
||||
### Решение
|
||||
Работать с ВМ (5.172.178.213), которая в том же ЦОДе:
|
||||
```bash
|
||||
# С ВМ — 1.4 секунды на 12 МБ
|
||||
ssh naeel@5.172.178.213
|
||||
cd /home/naeel/terra/terraform/TEST_STAND/buck0
|
||||
terraform init # ~2 сек
|
||||
terraform apply # ~34 сек
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Результат
|
||||
|
||||
```
|
||||
✅ terraform init — v5.0.75 загружен из реестра
|
||||
✅ terraform apply — buck0 создан (RUNNING, id: 7ef02214-c334-40a1-ac4d-bc0123183cc0)
|
||||
✅ S3 пути — terraform-registry/terra.k8c.ru/nubes-test/nubes/5.0.75/
|
||||
✅ S3 пути (old) — terraform-registry/terra.k8c.ru/nubes/nubes/5.0.75/
|
||||
```
|
||||
|
||||
## Структура S3 для провайдера
|
||||
|
||||
```
|
||||
terraform-registry/terra.k8c.ru/{namespace}/nubes/{version}/
|
||||
terraform-provider-nubes_{version}_SHA256SUMS
|
||||
terraform-provider-nubes_{version}_SHA256SUMS.sig
|
||||
terraform-provider-nubes_{version}_linux_amd64.zip
|
||||
```
|
||||
|
||||
## Ключевые пути
|
||||
|
||||
| Что | Где |
|
||||
|---|---|
|
||||
| Исходники registry-server | `/home/naeel/terra/registry/` (ВМ) |
|
||||
| Dockerfile | `operator/build/Dockerfile.registry` |
|
||||
| GPG ключ (pub) | `operator/registrykeys/public_key.go` |
|
||||
| Registry образ | `naeel/terraform-registry-server:gpg-fix` |
|
||||
| k8s deployment | `terra/registry-server` |
|
||||
| S3 credentials | k8s secret `terra/s3-credentials` |
|
||||
| Provider source | `universal_rebuild/` |
|
||||
@@ -0,0 +1,174 @@
|
||||
# 2026-07-02 — Миграция с deck-api на API Gateway (lk-api-gateway)
|
||||
|
||||
## Контекст
|
||||
|
||||
Старый API: `https://deck-api-{stand}.ngcloud.ru/api/v1/index.cfm?endpoint=/services/123`
|
||||
Новый API Gateway: `https://lk-api-gateway-{stand}.ngcloud.ru/api/v1/svc/services/123`
|
||||
|
||||
Ответы JSON идентичны. Различается только формат URL:
|
||||
- Старый: proxy через `index.cfm?endpoint=`
|
||||
- Новый: прямые REST-пути
|
||||
|
||||
Цель: перевести TEST-стенд на новый Gateway, сохранив совместимость со старым для dev/prod.
|
||||
|
||||
## Архитектурное решение
|
||||
|
||||
Авто-детект режима по наличию `index.cfm` в URL:
|
||||
- Есть `index.cfm` → старый proxy (`?endpoint=`)
|
||||
- Нет `index.cfm` → новый REST (прямая конкатенация пути)
|
||||
|
||||
Один env-параметр `NUBES_API_ENDPOINT` управляет всем.
|
||||
|
||||
## Изменения (11 файлов)
|
||||
|
||||
### 1. Генератор YAML: `universal_rebuild/tools/service_spec_gen/generate_service_spec.go`
|
||||
- `normalizeAPIEndpoint()` — убрано принудительное добавление `/index.cfm`, теперь только trim trailing slash
|
||||
- `getViaProxy()` → `callAPI()` — авто-детект: если `index.cfm` в URL → `?endpoint=`, иначе → прямая конкатенация `{base}{path}`
|
||||
- Добавлен метод `isProxyAPI()` для детекта
|
||||
- Обновлён комментарий с документированием двух режимов
|
||||
|
||||
### 2. Ядро провайдера: `universal_rebuild/internal/core/client.go`
|
||||
- Добавлены `isProxyAPI()` и `buildURL(path string) string` — единая точка конструирования URL
|
||||
- Заменены все 4 места с хардкодом `?endpoint=`:
|
||||
- `FindExistingInstances` (пагинированный поиск, строка ~515)
|
||||
- `GetInstanceState` (строка ~590)
|
||||
- `GetInstanceStateRaw` (строка ~637)
|
||||
- `doRequest` (POST/PUT/GET, строки ~838-853)
|
||||
|
||||
### 3. Оркестратор YAML: `devops/01_generate_yamls.sh`
|
||||
- Убрана принудительная нормализация `if [[ "$API_ENDPOINT" != */index.cfm ]]` → автоматическая
|
||||
- Python-скрипт: авто-детект `"index.cfm" in endpoint` → `?endpoint=` vs прямой путь
|
||||
|
||||
### 4. Генератор документации: `devops/02_generate_resources_and_docs_v2.sh`
|
||||
- Добавлена передача `-api-endpoint "$DOCS_API_ENDPOINT"` в `docs_template_gen_v2`
|
||||
- Нормализация: если нет ни `index.cfm`, ни `/svc` → дописать `/index.cfm` (обратная совместимость)
|
||||
|
||||
### 5. Публикация доков: `devops/04_build_and_publish_docs.sh`
|
||||
- `normalize_api_endpoint()` — убрано принудительное `/index.cfm`, только trim
|
||||
|
||||
### 6. Корневой скрипт: `01_generate_yamls.sh` (корень)
|
||||
- Python-скрипт: такой же авто-детект, как в devops/01
|
||||
|
||||
### 7-8. Шаблоны документации: `docs_template_gen_v2/main.go` + `docs_template_gen/main.go`
|
||||
- Добавлен флаг `-api-endpoint` (default: старый deck-api)
|
||||
- Все хардкоды `api_endpoint = "https://deck-api...index.cfm"` заменены на `fmt.Sprintf`
|
||||
- Проброшено через `writeResourceDocs` → `buildExamplePage` → `exampleBlock` → `buildSubresourceExamplePage`
|
||||
|
||||
### 9-10. Провайдеры: `internal/provider/provider.go` + `universal_rebuild/internal/provider/provider.go`
|
||||
- Добавлен `TODO(api-gateway)` комментарий над дефолтным `apiEndpoint`
|
||||
- Сам дефолт не менялся (runtime провайдера теперь использует `core.buildURL()`)
|
||||
|
||||
### 11. Профиль TEST: `devops/profiles/test/profile.env`
|
||||
- `NUBES_API_ENDPOINT` → `https://lk-api-gateway-test.ngcloud.ru/api/v1/svc`
|
||||
|
||||
### Бонус: версия в бинарник
|
||||
- `devops/build-provider.sh`: `go build` теперь с `-ldflags "-X main.version=${VERSION}"` — версия из профиля вшивается в бинарник (раньше всегда была из main.go)
|
||||
|
||||
## Анализ пайплайна (попутно)
|
||||
|
||||
Полный пайплайн: `services_list.txt` → `01_generate_yamls.sh` → `02_generate_resources_and_docs_v2.sh` → `03_build_and_upload_provider.sh` → `04_build_and_publish_docs.sh`.
|
||||
|
||||
Найденные проблемы (не исправлялись, зафиксированы):
|
||||
- `main.go` Address = `nubes-test` (только для test, для prod нужно `nubes`)
|
||||
- Нет сборки под `darwin/arm64` (Apple Silicon)
|
||||
- Корневой `01_generate_yamls.sh` ссылается на несуществующий `service_params_gen`
|
||||
- Кросс-стадийная валидация отсутствует (сбои 01 не видны в 02)
|
||||
|
||||
## Оставшиеся `deck-api` в коде
|
||||
|
||||
Только как **значения по умолчанию** (переопределяются через `NUBES_API_ENDPOINT`):
|
||||
- `service_spec_gen/generate_service_spec.go:150` — `getenvDefault("NUBES_API_ENDPOINT", "https://deck-api...")`
|
||||
- `devops/01_generate_yamls.sh:108` — `${NUBES_API_ENDPOINT:-https://deck-api...}`
|
||||
- `devops/02_generate_resources_and_docs_v2.sh:95` — аналогично
|
||||
- `devops/04_build_and_publish_docs.sh:13,87` — аналогично
|
||||
- `docs_template_gen_v2/main.go:91` — flag default
|
||||
- `docs_template_gen/main.go:81` — flag default
|
||||
- `internal/provider/provider.go:105` + `universal_rebuild/...` — с TODO
|
||||
|
||||
Хардкодов в теле функций/примеров больше нет.
|
||||
|
||||
## Для перехода dev/prod
|
||||
|
||||
Достаточно поменять одну строку в `profile.env`:
|
||||
```
|
||||
NUBES_API_ENDPOINT="https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc" # dev
|
||||
NUBES_API_ENDPOINT="https://lk-api-gateway.ngcloud.ru/api/v1/svc" # prod
|
||||
```
|
||||
|
||||
Всё остальное — авто-детект.
|
||||
|
||||
---
|
||||
|
||||
## Доступ к СТАРОМУ deck-api (DDoS-Guard 403)
|
||||
|
||||
Старый API **жив**, но DDoS-Guard усилил фильтрацию. Просто `User-Agent: Mozilla/5.0` уже недостаточно.
|
||||
|
||||
### Рабочие заголовки для curl:
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
-H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36" \
|
||||
-H "Referer: https://deck-test.ngcloud.ru/" \
|
||||
"https://deck-api-test.ngcloud.ru/api/v1/index.cfm?endpoint=/services/90"
|
||||
```
|
||||
|
||||
**Ключевое**: `Referer` с доменом того же стенда. Без него — 403.
|
||||
|
||||
### Без токена (публичные эндпоинты):
|
||||
|
||||
```bash
|
||||
curl -H "User-Agent: Mozilla/5.0" \
|
||||
"https://deck-api-test.ngcloud.ru/api/v1"
|
||||
# → 200 (OK)
|
||||
```
|
||||
|
||||
### Что изменилось с июля 2026
|
||||
|
||||
DDoS-Guard ужесточил правила:
|
||||
- Старый `User-Agent: Mozilla/5.0` + `Accept: */*` → 403
|
||||
- Новый: нужен полный браузерный User-Agent + Referer
|
||||
- Провайдер (v5.0.75) использовал старые заголовки — при следующем билде надо обновить
|
||||
- Новый Gateway (`lk-api-gateway`) — 403 не выдаёт, работает с любым User-Agent
|
||||
|
||||
---
|
||||
|
||||
## Проблема map-fixed параметров и dataDescriptor
|
||||
|
||||
### Суть
|
||||
|
||||
Новый Gateway группирует плоские параметры в map-fixed JSON-блоки. Sub-поля (`dataDescriptor`) не видны в `/serviceOperation/{id}` — появляются только в ответе уже выполненной операции `/instanceOperations/{uid}`.
|
||||
|
||||
### Как получить sub-поля (на примере postgres)
|
||||
|
||||
```bash
|
||||
# 1. Найти любой успешный инстанс postgres
|
||||
curl ... "https://deck-api-test.ngcloud.ru/api/v1/index.cfm?endpoint=/instances?serviceId=90&page=1&size=1"
|
||||
|
||||
# 2. Взять instanceUid → запросить операции → взять create-операцию
|
||||
curl ... "https://deck-api-test.ngcloud.ru/api/v1/index.cfm?endpoint=/instances/{uid}"
|
||||
|
||||
# 3. Запросить операцию — в cfsParams будет dataDescriptor с sub-полями
|
||||
curl ... "https://deck-api-test.ngcloud.ru/api/v1/index.cfm?endpoint=/instanceOperations/{opUid}"
|
||||
```
|
||||
|
||||
### Правильные JSON-ключи для postgres (из dataDescriptor)
|
||||
|
||||
| Блок | Поля |
|
||||
|---|---|
|
||||
| `startupConfiguration` | `resourceRealm` |
|
||||
| `clusterConfiguration` | `cpu`, `memory`, `replicas`, `disk` |
|
||||
| `accessConfiguration` | `masterIpSpace`, `masterAccessList`, `slaveIpSpace`, `slaveAccessList` |
|
||||
| `postgresConfiguration` | `version`, `sslRequired`, `poolerMaster`, `poolerSlave` |
|
||||
| `postgresConf` | `paramName`, `paramValue` (массив) |
|
||||
| `backupConfiguration` | `s3Uid`, `retain`, `schedule` |
|
||||
| `autoscaleConfiguration` | `enabled`, `schedule`, `quota`, `percent` |
|
||||
|
||||
### Обсуждение с девопсами (02.07.2026)
|
||||
|
||||
- Плоские параметры **не вернутся** — map-fixed остаётся (нужно для групп ключей, нод, учёток)
|
||||
- Структуру блоков обещают давать в API, но пока не придумали формат
|
||||
- Пока единственный источник структуры — Jenkins-конфиги
|
||||
|
||||
### CMDB backend bug
|
||||
|
||||
При run операции бэкенд `/app/cmdb` падает с `ValidationError: InstanceState: version, instanceUid, dtState, isTest, instanceOperationUid — can't be blank`. Это баг в Gateway→CMDB, не в провайдере.
|
||||
@@ -0,0 +1,166 @@
|
||||
# VPN transit via VM 213 and Vultr
|
||||
|
||||
Date: 2026-09-27 to 2026-09-28
|
||||
|
||||
## Goal
|
||||
|
||||
Provide access from Russian residential/mobile networks to services restricted by Russian network filtering, while retaining the existing foreign egress on Vultr.
|
||||
|
||||
## Verified network facts
|
||||
|
||||
- Test host `3060`: `46.39.251.163`, connection from Khimki / Iskratelecom.
|
||||
- Transit VM `213`: `5.172.178.213`, public egress observed as `5.172.178.65`; hosted in NUBES data centre.
|
||||
- Vultr addresses: primary `95.179.252.111`; secondary `104.238.177.67`.
|
||||
- `3060 -> 213`: ICMP approximately 3 ms, 0% loss.
|
||||
- `213 -> Vultr`: ICMP approximately 34 ms, 0% loss; HTTPS response returned in about 0.07-0.11 s.
|
||||
- Direct `213 -> Vultr` test file transfer: 10 MiB in 1.59 s, about 6.27 MiB/s / 50.2 Mbit/s.
|
||||
- Direct `3060 -> Vultr` test file transfer timed out / was throttled.
|
||||
- Direct `213 -> OVH proof endpoint`: 10 MiB in 1.18 s, about 8.5 MiB/s.
|
||||
- Direct access from `213` to YouTube and Telegram failed with `HTTP=000` and timeout/SSL errors, while OVH and Google returned HTTP 200. Therefore a foreign egress remains required for those services.
|
||||
|
||||
## Persistent changes on VM 213
|
||||
|
||||
- Created backup:
|
||||
- `/etc/nginx/sites-available/check.kube5s.ru.bak_vpn`
|
||||
- Modified:
|
||||
- `/etc/nginx/sites-available/check.kube5s.ru`
|
||||
- Added an Nginx `/ws` reverse-proxy location with:
|
||||
- upstream `https://95.179.252.111:443`
|
||||
- SNI `vipien.kube5s.ru`
|
||||
- upstream Host header `vipien.kube5s.ru`
|
||||
- WebSocket upgrade headers
|
||||
- 3600-second proxy timeouts
|
||||
- Ran `nginx -t` successfully and reloaded Nginx.
|
||||
- Existing unrelated Nginx warnings about duplicate `contracts.kube5s.ru` server names remained.
|
||||
|
||||
## Persistent/previously existing changes on Vultr
|
||||
|
||||
The following configuration was read or used during validation:
|
||||
|
||||
- `/etc/nginx/conf.d/vipien.conf`: TLS/WebSocket endpoint for `vipien.kube5s.ru`.
|
||||
- `/etc/v2ray-agent/xray/conf/08_VLESS_ws_inbound.json`: VLESS WebSocket inbound on `127.0.0.1:10086`, path `/ws`.
|
||||
- `/etc/systemd/system/hysteria-server.service`: Hysteria service was stopped and disabled; it was not changed in this work.
|
||||
- Xray service was confirmed active.
|
||||
- Nginx service was confirmed active.
|
||||
- Cloudflared tunnel configuration was inspected earlier, but it is not used by the final working route.
|
||||
- A temporary 10 MiB test file was created on Vultr and removed after testing.
|
||||
|
||||
## Temporary files on test VM 3060
|
||||
|
||||
The following temporary client files were created under `/tmp/xray-test/` for validation and are not repository files:
|
||||
|
||||
- `client-cf.json`
|
||||
- `client-213.json`
|
||||
- `client-directip.json`
|
||||
- temporary log/test artifacts where applicable
|
||||
|
||||
The files contained test Xray client configurations. They were used only to verify the route from `3060`; no permanent system service was installed there.
|
||||
|
||||
## Final tested route
|
||||
|
||||
`client in Russia -> 5.172.178.213:443 -> Nginx WebSocket proxy -> 95.179.252.111:443 -> Xray -> Internet`
|
||||
|
||||
Final test from `3060` through the route:
|
||||
|
||||
- observed outbound IP: `95.179.252.111`
|
||||
- 10 MiB OVH download: 1.76-1.91 s
|
||||
- measured speed: approximately 5.5-6.0 MiB/s
|
||||
|
||||
## Final client parameters
|
||||
|
||||
- Address: `5.172.178.213`
|
||||
- Port: `443`
|
||||
- UUID: existing UUID used by the Vultr Xray inbound
|
||||
- TLS SNI: `check.kube5s.ru`
|
||||
- WebSocket path: `/ws`
|
||||
- WebSocket Host: `vipien.kube5s.ru`
|
||||
|
||||
The final direct-IP test used Xray 26.3.27. The client-side `allowInsecure` option was not used because this Xray version reports that the option was removed.
|
||||
|
||||
## Secondary Vultr IP
|
||||
|
||||
Before removal, the Nginx upstream on VM 213 was switched from `104.238.177.67` to `95.179.252.111`. A post-switch end-to-end test succeeded, with outbound IP `95.179.252.111` and approximately 6.0 MiB/s.
|
||||
|
||||
No Vultr IP deletion was performed in this work. The secondary address was only confirmed as no longer referenced by the transit configuration.
|
||||
|
||||
## Scope audit
|
||||
|
||||
- No repository source/configuration files were edited before this record.
|
||||
- `git status` was clean before this documentation file was created.
|
||||
- This documentation file is the only workspace file created by the current documentation action.
|
||||
- Server-side files were changed on VM 213 and earlier on Vultr; temporary test files were also created on VM 3060.
|
||||
- No commit was created for this record.
|
||||
|
||||
## Important limitations
|
||||
|
||||
The measurements prove the route worked at test time. They do not guarantee permanent availability: NUBES, Vultr, upstream providers, or network filtering policy can change independently.
|
||||
|
||||
## Later the same day: optimisation attempt and its outcome
|
||||
|
||||
### Automation created
|
||||
|
||||
A reusable, idempotent tool was created outside this repository:
|
||||
|
||||
```text
|
||||
/home/naeel/nubes/HowTo/vpn-transit/vpn-setup.sh check | apply | verify | passthrough | verify-passthrough | client-config | rollback
|
||||
/home/naeel/nubes/HowTo/vpn-transit/client-config.json generated client config (chmod 600, contains UUID)
|
||||
/home/naeel/nubes/HowTo/vpn-transit/README.md description, measurements, rollback
|
||||
/home/naeel/nubes/HowTo/howto-vpn-transit-213-vultr-2026-09-28.md full report
|
||||
```
|
||||
|
||||
Every change is preceded by a timestamped backup and followed by a config test (`nginx -t`, `xray run -test`) with automatic rollback on failure.
|
||||
|
||||
### Changes applied
|
||||
|
||||
| Host | File | Change | Backup |
|
||||
|---|---|---|---|
|
||||
| 213 | `/etc/nginx/sites-available/check.kube5s.ru` | `proxy_buffering off;` added inside `location /ws`, marked `# vpn-transit: proxy_buffering off` | `check.kube5s.ru.bak.1790601681` |
|
||||
| Vultr | `/etc/v2ray-agent/xray/conf/00_log.json` | `loglevel`: `debug` → `warning` (log had grown to 76 MB), service restarted | `00_log.json.bak.1790601723` |
|
||||
| 213 | `/usr/local/sbin/vpn-transit-dnat.sh`, `/etc/systemd/system/vpn-transit-dnat.service` | DNAT `213:8443 → 95.179.252.111:443` plus FORWARD rules, enabled at boot | none (rules tagged `vpn-transit`) |
|
||||
|
||||
### Measurements after the changes
|
||||
|
||||
- Outbound IP: `95.179.252.111`
|
||||
- Throughput: `5.6–7.3 MiB/s` (10 MiB in 1.4–1.9 s)
|
||||
- Per-connection latency: `0.23–0.37 s`
|
||||
- WebSocket upgrade success rate on 213: `14569 / 14573` (99.97%), one `upstream timed out` error
|
||||
|
||||
### Hypothesis that was disproved: mux
|
||||
|
||||
`verify` compared the tunnel with and without `"mux": {"enabled": true, "concurrency": 8}`:
|
||||
|
||||
| Mode | 10 MiB download | Connection behaviour |
|
||||
|---|---|---|
|
||||
| without mux | 7.32 MiB/s in 1.43 s | stable |
|
||||
| with mux | **0 B/s, failed** | after 4 requests connections hang for 15 s |
|
||||
|
||||
Conclusion: mux is harmful in the `VLESS + WebSocket behind nginx` combination. It is excluded from the client config. The test remains in the script for re-checking on future Xray versions.
|
||||
|
||||
### Optimisation that could not be delivered: removing the second TLS layer
|
||||
|
||||
The intended speed fix was to drop one TLS handshake (`client → 213`, then `213 → Vultr`) by forwarding TCP straight through to Vultr.
|
||||
|
||||
- `ngx_stream_module.so` is absent on 213, so nginx cannot do SNI-based passthrough without installing `libnginx-mod-stream`.
|
||||
- Kernel-level DNAT on port 8443 was installed instead, but **does not work**: from outside, port 8443 returns `Connection refused` and the DNAT counter on 213 stays at 0 packets — traffic never reaches the machine.
|
||||
- Cause: the provider firewall in front of 213 exposes only ports 80 and 443. Measured from `3060`: `3001, 8080, 8443, 8766, 8767, 8888, 18080, 40229` are closed.
|
||||
- Therefore the second TLS layer can only be removed after the provider opens an additional port. The rules are already installed and would start working immediately once that happens.
|
||||
|
||||
### Errors made during this work
|
||||
|
||||
1. **Recommended `mux` before measuring it.** The recommendation was given as the main fix and was later disproved by measurement. Correct order: measure first, recommend after.
|
||||
2. **Changed server configuration before measuring the benefit.** `proxy_buffering off` has no effect on a WebSocket connection after the `101 Switching Protocols` upgrade, and `loglevel` affects only log size. Neither change improves speed, so from the user's point of view nothing changed.
|
||||
3. **Changed the client config to port 8443 before verifying the port was reachable from outside.** The config was regenerated back to port 443 immediately.
|
||||
|
||||
### Net result for the user
|
||||
|
||||
Nothing changed for the client: address `5.172.178.213`, port `443`, SNI `check.kube5s.ru`, path `/ws` and the UUID are unchanged, and the previously used link still works. No client-side reconfiguration is required.
|
||||
|
||||
The only actionable finding is client-side: the Xray log on Vultr contained **331** `connect: connection refused` to `127.0.0.1:45987`, i.e. the client requested a loopback address, plus Telegram advertises AAAA records while the tunnel is IPv4-only. The generated `client-config.json` addresses both (remote DNS, `queryStrategy: UseIPv4`), but the device itself was not modified.
|
||||
|
||||
Separately: **10170** `reset by peer` entries to `157.240.0.13` (Meta infrastructure) are blocking by those sites, unrelated to the transit.
|
||||
|
||||
### Scope audit (this action)
|
||||
|
||||
- Repository files changed: this document only. `git status` also showed unrelated pre-existing changes (`DEV_STAND/FullPipe/shturval.tf` deletion, `TMP/*` files) that were **not** touched or committed.
|
||||
- Server-side files changed: as listed in the table above.
|
||||
- Temporary test files on 3060: `/tmp/xray-test/*` (no permanent service installed).
|
||||
@@ -0,0 +1,71 @@
|
||||
# 2026-10-01 — Полное зеркалирование локального `~/TF` на сервер 213
|
||||
|
||||
> Команда владельца: «чтобы на 213 сервере вся папка ~/TF была такой же как здесь в локали…
|
||||
> не надо слепка!!! ДЕЛАЙ».
|
||||
|
||||
## Команда
|
||||
|
||||
```bash
|
||||
rsync -a --delete --info=stats2,progress2 \
|
||||
-e "ssh -i /home/naeel/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=accept-new" \
|
||||
/home/naeel/TF/ vps:/home/naeel/TF/
|
||||
```
|
||||
|
||||
Направление: **локально → 213** (`vps` = `5.172.178.213`, alias из `~/.ssh/config`,
|
||||
ключ `naeel_vm_id_ed25519`). Режим `--delete` — точное зеркало: лишнее на 213 удаляется.
|
||||
|
||||
## Что было на 213 до синхронизации
|
||||
|
||||
| | Значение |
|
||||
|---|---|
|
||||
| HEAD `tf_provider` | `33672e05` (2026-09-19) |
|
||||
| Последняя правка файлов | 2026-09-20 21:25 |
|
||||
| Рабочее дерево | 19 изменённых файлов (4 untracked: `modifier.go`, спека модификаторов, `docs/CHAT_RESUME_2026-09-20.md`, `.github/copilot-instructions.md1`) |
|
||||
| Stash | 3 |
|
||||
| `PLAN_regenerate_providers_0.0.1.md` | изменён 20.09 (локально файла нет) |
|
||||
|
||||
Проверено: **ничего новее 20.09 там не было** — изменения датировались 19–20 сентября
|
||||
и по темам совпадали с уже закоммиченным локально позже.
|
||||
|
||||
## Результат rsync
|
||||
|
||||
```
|
||||
Number of files: 10,778 (reg: 8,808, dir: 1,970)
|
||||
Number of created files: 3,987 (reg: 3,803, dir: 184)
|
||||
Number of deleted files: 139 (reg: 104, dir: 35)
|
||||
Number of regular files transferred: 4,430
|
||||
Total transferred file size: 341,729,329 bytes
|
||||
sent 296,056,942 bytes received 521,370 bytes в 4.9 MB/s (≈1 мин)
|
||||
```
|
||||
|
||||
## Проверки после синхронизации
|
||||
|
||||
| Проверка | Локально | На 213 |
|
||||
|---|---|---|
|
||||
| HEAD `tf_provider` | `db9d93e` (2026-10-01 07:37) | **`db9d93e`** ✅ |
|
||||
| `git status --short` | 2 | 2 ✅ |
|
||||
| Ветки | 6 | 6 (`api-gateway`, `master`, `pre-modifier-state`, `save/state-before-modify-resources-2026-09-24`, `snapshot/2026-09-25-shturval-freeze-state`, `snapshot/2026-09-30-master-state`) ✅ |
|
||||
| Stash | 2 | 2 ✅ |
|
||||
| Всего файлов в `~/TF` | 8 808 | 8 808 ✅ |
|
||||
| `diff` списков файлов (LC_ALL=C) | — | **0 строк** ✅ |
|
||||
|
||||
> Нюанс проверки: первичный `diff` показывал 5 911 «расхождений» — это артефакт разных
|
||||
> локалей `sort` на локальной машине и на 213 (файлы одни и те же, порядок разный).
|
||||
> С `LC_ALL=C` для обеих сторон списки совпадают полностью.
|
||||
|
||||
## Удалено на 213 (осознанно, слепок не делался — по указанию владельца)
|
||||
|
||||
- 3 stash сентябрьской сессии;
|
||||
- черновики, которых локально нет: `docs/CHAT_RESUME_2026-09-20.md`,
|
||||
`PLAN_regenerate_providers_0.0.1.md`, `.github/copilot-instructions.md1`;
|
||||
- итого 139 объектов (104 файла + 35 каталогов) — всё, чего не существует в локальной `~/TF`.
|
||||
|
||||
## Замечания
|
||||
|
||||
- Размер каталога на 213 больше локального (`~/TF` = 514 МиБ против ~357 МиБ у `tf_provider`
|
||||
локально) — из-за journal/hardlink-эффектов: `rsync -a` сохраняет `*.tfstate`-бэкапы
|
||||
и создаёт отдельные копии там, где локально были жёсткие ссылки; на состав файлов
|
||||
(8 808 = 8 808) это не влияет.
|
||||
- Синхронизация выполнена **без предварительного слепка** по прямому указанию владельца.
|
||||
- Правки, затронутые во время зеркалирования: `TOOLS/config/dev/profile.env`
|
||||
(VERSION `2.0.1` → `2.0.0`, коммит `chore(dev): VERSION 2.0.1 -> 2.0.0 …`).
|
||||
Reference in New Issue
Block a user