docs(history): находки по хостингу документации на S3 static website + версии развития
Новый файл HISTORY/2026-10-02_s3_static_website_docs_hosting.md:
- итог живой проверки: у Nubes включён static website на Ceph RGW (Squid),
сайт целиком работает из S3 без ВМ; незакрыт только домен/TLS (принадлежит Nubes);
- единственное изменение состояния: PUT Bucket website (IndexDocument=index.html)
на бакете terraform-registry + команда отката; статус — оставлено, решения владельца нет;
- найдено уже настроенным у Nubes: NoSuchWebsiteConfiguration до PUT (значит API есть),
wildcard DNS *.s3-website.msk-1.ngcloud.ru -> 89.169.61.167, валидный TLS,
порт 80 закрыт, bucket policy PublicReadGetObject (Principal *);
- проверки: анонимные 200 с размерами, совпадающими с index.html (148758/139835/150021),
фактическая раскладка ключей docs/{nubes,nubes-dev,nubes-test}/nubes/…,
объектный эндпоинт каталоги не умеет (403) — резолвинг только на website-эндпоинте;
- зафиксирована моя ошибка: 403 приходили на НЕСУЩЕСТВУЮЩИЙ ключ docs/nubes/index.html;
уроки — сначала list-objects-v2, потом URL; сверять размеры и проверять анонимно+подписанно;
- побочные находки: list-buckets видит бакеты других тенантов; в secrets/.s3cfg_registry
лежат чужие ключи (tazet@narod.ru, ntazetdinov@nubes.ru);
- версии развития V0 (213+nginx) -> V1 (website-эндпоинт, проверена) -> V2 (origin их фронта),
отклонённые V3a/V3b/V3c и чек-лист дальнейших изменений.
This commit is contained in:
@@ -0,0 +1,167 @@
|
|||||||
|
# 2026-10-02 — Хостинг документации: S3 static website на RGW (находки и версии развития)
|
||||||
|
|
||||||
|
> Команда владельца: «**То е ТАК ПРОВЕРЬ !**» → «документируй всё это как находки
|
||||||
|
> и версии развития, для дальнейших изменений».
|
||||||
|
|
||||||
|
Документ фиксирует **результат живой проверки** S3-эндпоинтов Nubes и **варианты развития**
|
||||||
|
схемы публикации документации. Ничего, кроме явно указанного в разделе «Изменения состояния»,
|
||||||
|
не менялось.
|
||||||
|
|
||||||
|
## Итог в одном абзаце
|
||||||
|
|
||||||
|
У Nubes **включён режим S3 static website** на объектном хранилище (Ceph RGW, релиз **Squid**),
|
||||||
|
и сайт документации **уже полностью работает прямо из S3** — без ВМ, без nginx, без зеркал и без
|
||||||
|
костылей с URL. Проверено анонимными запросами: каталог отдаётся как `index.html` байт в байт.
|
||||||
|
Единственный незакрытый элемент — **домен и TLS на нём** (`tf-docs.nodejsk8s.dev.nubes.ru`),
|
||||||
|
которые принадлежат Nubes, а не нам.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Изменения состояния (единственное, что я сделал)
|
||||||
|
|
||||||
|
| Что | Команда | Результат |
|
||||||
|
|---|---|---|
|
||||||
|
| Включён `IndexDocument` на бакете `terraform-registry` | `aws s3api put-bucket-website --bucket terraform-registry --website-configuration file:///tmp/ws.json` где `{"IndexDocument":{"Suffix":"index.html"}}` | HTTP **200**, пустое тело |
|
||||||
|
|
||||||
|
Проверка после:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
aws --endpoint-url https://s3.msk-1.ngcloud.ru s3api get-bucket-website --bucket terraform-registry
|
||||||
|
```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"IndexDocument": {
|
||||||
|
"Suffix": "index.html"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Откат (одна команда):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
aws --endpoint-url https://s3.msk-1.ngcloud.ru s3api delete-bucket-website --bucket terraform-registry
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ Статус на 2026-10-02: `IndexDocument` **оставлен** (владелец ещё не давал команду ни оставить,
|
||||||
|
> ни откатить — см. последний вопрос в диалоге). Содержимое бакета не изменялось.
|
||||||
|
|
||||||
|
## 2. Находки: что уже настроено у Nubes (не нами)
|
||||||
|
|
||||||
|
| Находка | Доказательство |
|
||||||
|
|---|---|
|
||||||
|
| Static website **реализован** в RGW | `get-bucket-website` до нашего PUT отвечал `404` с телом `<?xml…><Error><Code>NoSuchWebsiteConfiguration</Code>` — это ответ «фича есть, конфига нет», а не `NotImplemented` |
|
||||||
|
| Служба — **Ceph Object Gateway (squid)** | заголовок `server: Ceph Object Gateway (squid)` в ответах |
|
||||||
|
| **DNS wildcard для website-эндпоинта существует** | `terraform-registry.s3-website.msk-1.ngcloud.ru` → `89.169.61.167`; `terraform-registry.website.s3.msk-1.ngcloud.ru` → `89.169.61.166`; `s3-website.msk-1.ngcloud.ru` → `89.169.61.167` |
|
||||||
|
| **TLS на website-эндпоинте валиден** | `curl https://terraform-registry.s3-website.msk-1.ngcloud.ru/…` отдаёт HTTP-код, а не ошибку сертификата |
|
||||||
|
| На **порту 80** website-эндпоинт не отвечает | `curl http://…` → код `000` (соединение не устанавливается); работает только `https://` |
|
||||||
|
| Публичное чтение **уже разрешено политикой бакета** | `get-bucket-policy` → `{"Sid":"PublicReadGetObject","Effect":"Allow","Principal":"*","Action":["s3:GetObject","s3:GetObjectVersion"],"Resource":"arn:aws:s3:::terraform-registry/*"}` |
|
||||||
|
| ACL бакета — только владелец | `get-bucket-acl` → один грант `CanonicalUser … FULL_CONTROL` |
|
||||||
|
| Объектный эндпоинт каталоги **не умеет** | `/…/docs/nubes-dev/nubes/30_registry/` на `s3.msk-1.ngcloud.ru` → `403`; index-резолвинг делает **только** website-эндпоинт |
|
||||||
|
| Ключи бакета видны шире нашего тенанта | `list-buckets` нашими кредами вернул также `backup-mongo`, `karta`, `trino`, `technicals3backup-*`, `bucket2406`… — **требует уточнения у Nubes** (либо так настроен RGW, либо креды с расширенными правами) |
|
||||||
|
| `secrets/.s3cfg_registry` содержит **чужие** ключи | в файле, помимо `[default]`, лежат блоки `tazet@narod.ru PROD` и `ntazetdinov@nubes.ru PROD` (значения не приводим). Файл — рабочий, но его содержимое стоит разделить/почистить |
|
||||||
|
|
||||||
|
## 3. Проверки (воспроизводимые)
|
||||||
|
|
||||||
|
Подготовка окружения (ключи — из `secrets/.s3cfg_registry`, раздел `[default]`; секреты в команду не пишем):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
set -a
|
||||||
|
eval "$(awk -F' = ' '/^access_key = /{print "AWS_ACCESS_KEY_ID="$2} \
|
||||||
|
/^secret_key = /{print "AWS_SECRET_ACCESS_KEY="$2}' secrets/.s3cfg_registry)"
|
||||||
|
set +a
|
||||||
|
export AWS_DEFAULT_REGION=us-east-1 EP=https://s3.msk-1.ngcloud.ru
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.1 Фактическая раскладка документации в бакете
|
||||||
|
|
||||||
|
```bash
|
||||||
|
aws --endpoint-url $EP s3api list-objects-v2 --bucket terraform-registry \
|
||||||
|
--prefix docs/ --delimiter "/" --query 'CommonPrefixes[].Prefix' --output text
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/nubes-dev/
|
||||||
|
docs/nubes-test/
|
||||||
|
docs/nubes/
|
||||||
|
```
|
||||||
|
|
||||||
|
Внутри — ещё сегмент `nubes/`, например:
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/nubes-dev/nubes/index.html 148758
|
||||||
|
docs/nubes-dev/nubes/30_registry/index.html 139835
|
||||||
|
docs/nubes-dev/nubes/30_registry/guides/glossary/index.html 150021
|
||||||
|
docs/nubes-dev/nubes/30_registry/assets/extra.css 13999
|
||||||
|
```
|
||||||
|
|
||||||
|
Полный путь сайта стенда: **`docs/<namespace>/nubes/…`**, где `<namespace>` ∈ {`nubes`, `nubes-dev`, `nubes-test`}.
|
||||||
|
Сегмента версии в ключах **нет** (это расходится с текстом справочного `DOCS_PIPELINE/publish-docs.sh:27`,
|
||||||
|
где в TARGET есть `${VERSION}` — на практике грузит `TOOLS/scripts/04_build_and_publish_docs.sh`).
|
||||||
|
|
||||||
|
### 3.2 Работа website-эндпоинта (анонимно, без авторизации)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
W=https://terraform-registry.s3-website.msk-1.ngcloud.ru
|
||||||
|
for p in "/docs/nubes-dev/nubes/" \
|
||||||
|
"/docs/nubes-dev/nubes/30_registry/" \
|
||||||
|
"/docs/nubes-dev/nubes/30_registry/guides/glossary/"; do
|
||||||
|
echo -n "$p -> "; curl -s -o /dev/null -w '%{http_code} %{size_download}\n' --max-time 15 "$W$p"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
| URL (каталог) | Код | Размер | Совпадает с `index.html` каталога |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `/docs/nubes-dev/nubes/` | **200** | 148758 | ✅ |
|
||||||
|
| `/docs/nubes-dev/nubes/30_registry/` | **200** | 139835 | ✅ |
|
||||||
|
| `/docs/nubes-dev/nubes/30_registry/guides/glossary/` | **200** | 150021 | ✅ |
|
||||||
|
|
||||||
|
Для сравнения — тот же каталог на объектном эндпоинте: `403`; анонимный GET **существующего**
|
||||||
|
объекта `https://s3.msk-1.ngcloud.ru/terraform-registry/docs/nubes-dev/nubes/index.html` → `200` 148758.
|
||||||
|
|
||||||
|
## 4. Моя ошибка в ходе проверки (фиксирую)
|
||||||
|
|
||||||
|
На предыдущем шаге я утверждал, что бакет «отдаёт `index.html` → 200, а каталоги → 403»,
|
||||||
|
проверяя URL `…/docs/nubes/index.html`. **Такого ключа не существует** — реальная раскладка
|
||||||
|
`docs/<ns>/nubes/…`. Все «403» в той серии были ответом на **несуществующие** ключи,
|
||||||
|
а не отказом в доступе.
|
||||||
|
|
||||||
|
Уроки (для дальнейших проверок S3/RGW):
|
||||||
|
|
||||||
|
1. Перед выводами о 403/404 **сначала** получить фактический список ключей
|
||||||
|
(`list-objects-v2 --delimiter "/"`), а уже потом пробовать URL.
|
||||||
|
2. `403 AccessDenied` у RGW может означать «нет политики **или** ключа», а `400`/`403` на каталоге
|
||||||
|
объектного эндпоинта — норма, index-резолвинг живёт на website-эндпоинте.
|
||||||
|
3. Проверять двумя независимыми способами: анонимный `curl` **и** подписанный `aws s3api`
|
||||||
|
(через `--aws-sigv4` / `aws --endpoint-url`), и **сверять размеры** с `index.html`.
|
||||||
|
|
||||||
|
## 5. Версии развития схемы хостинга документации
|
||||||
|
|
||||||
|
| Версия | Схема | Статус | Что требуется |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **V0** (текущая эксплуатация) | Публикация в S3 + **ВМ 213**: `nginx` :80/:443 → `/var/www/tf-docs/{nubes,nubes-dev,nubes-test}`, плюс зеркало `~/TF` на 213; внешний фронт `tf-docs.nodejsk8s.dev.nubes.ru` → `185.247.187.151` → `http://5.172.178.213/…` | работает, **но избыточна** | — |
|
||||||
|
| **V1** (проверена 2026-10-02, рабочая) | S3 website-эндпоинт как **единственный** источник: `https://terraform-registry.s3-website.msk-1.ngcloud.ru/docs/<ns>/nubes/…` | ✅ проверено анонимно (200, размеры совпадают) | `IndexDocument` (поставлен) + публичная политика (уже есть). ВМ, nginx, зеркало, `fix-slash.js`, `use_directory_urls: false` — **не нужны** |
|
||||||
|
| **V2** (целевая, «красивый домен») | Их фронт-прокси ставит origin на `terraform-registry.s3-website.msk-1.ngcloud.ru`; домен и TLS остаются их | ⏳ требует решения Nubes | запрос в Nubes: разрешить upstream на website-эндпоинт (порт HTTPS). Сохраняет текущий URL `https://tf-docs.nodejsk8s.dev.nubes.ru/…` |
|
||||||
|
| **V3a** (отклонён как ненужный) | `use_directory_urls: false` — плоские `*.html` | не требуется | при V1/V2 pretty-URL работает штатно; правка `mkdocs.yml` не нужна |
|
||||||
|
| **V3b** (отклонён как ненужный) | Ключи-«каталоги»: копия тела под ключом `…/foo/` | не требуется | RGW сам резолвит каталог в `index.html` на website-эндпоинте |
|
||||||
|
| **V3c** (невозможен) | Свой домен напрямую на S3 | — | домен и сертификат принадлежат Nubes, а не нам |
|
||||||
|
|
||||||
|
## 6. Чек-лист для дальнейших изменений
|
||||||
|
|
||||||
|
- [ ] Решить судьбу `IndexDocument` на `terraform-registry`: **оставить** (нужен для V1/V2) или откатить.
|
||||||
|
- [ ] При желании — добавить `ErrorDocument` (например, `404.html`), чтобы не отдавать стандартную
|
||||||
|
HTML-страницу RGW `NoSuchKey`.
|
||||||
|
- [ ] Запросить у Nubes (V2): upstream их фронта на `terraform-registry.s3-website.msk-1.ngcloud.ru`.
|
||||||
|
- [ ] Уточнить у Nubes: почему `list-buckets` нашими кредами показывает бакеты других тенантов.
|
||||||
|
- [ ] Разделить/почистить `secrets/.s3cfg_registry` (чужие ключи `tazet@narod.ru`, `ntazetdinov@nubes.ru`).
|
||||||
|
- [ ] Зафиксировать в `TOOLS/scripts/04_build_and_publish_docs.sh` целевую схему пути `docs/<ns>/nubes/`
|
||||||
|
и сверить с текстом `DOCS_PIPELINE/publish-docs.sh` (там есть `${VERSION}`, на практике его нет).
|
||||||
|
- [ ] При переходе на V1/V2 — отдельной командой вывести из эксплуатации: публикацию docs через nginx
|
||||||
|
на 213, зеркало `~/TF` (если оно нужно только для docs), костыль `docs/30_registry/javascripts/fix-slash.js`.
|
||||||
|
- [ ] Если 213 остаётся публичной — ограничить доступ (`allow <IP фронта>; deny all;`) на :80.
|
||||||
|
|
||||||
|
## 7. Связанные документы
|
||||||
|
|
||||||
|
- `HISTORY/2026-10-01_sync_tf_to_213_mirror.md` — зеркалирование `~/TF` на 213 (схема V0);
|
||||||
|
- `HISTORY/2026-09-30_yaml_pipeline_hardening.md` — пайплайн генерации YAML;
|
||||||
|
- `DOCS_PIPELINE/publish-docs.sh` — справочная копия заливки сайта в S3;
|
||||||
|
- `TOOLS/scripts/04_build_and_publish_docs.sh` — рабочий сборщик и публикатор документации.
|
||||||
Reference in New Issue
Block a user