Новый файл 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 и чек-лист дальнейших изменений.
13 KiB
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, пустое тело |
Проверка после:
aws --endpoint-url https://s3.msk-1.ngcloud.ru s3api get-bucket-website --bucket terraform-registry
{
"IndexDocument": {
"Suffix": "index.html"
}
}
Откат (одна команда):
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]; секреты в команду не пишем):
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 Фактическая раскладка документации в бакете
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-эндпоинта (анонимно, без авторизации)
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):
- Перед выводами о 403/404 сначала получить фактический список ключей
(
list-objects-v2 --delimiter "/"), а уже потом пробовать URL. 403 AccessDeniedу RGW может означать «нет политики или ключа», а400/403на каталоге объектного эндпоинта — норма, index-резолвинг живёт на website-эндпоинте.- Проверять двумя независимыми способами: анонимный
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-страницу RGWNoSuchKey. - Запросить у 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— рабочий сборщик и публикатор документации.