From 1d6be15448ba379bd90009c1aa1cae1d678c4f8e Mon Sep 17 00:00:00 2001 From: pipistrello Date: Thu, 25 Jun 2026 14:55:21 +0300 Subject: [PATCH] Add help-osk-docs stack: Zensical instructions site for 05-osk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Static instructions site for client 05 served at help.osk.team. Markdown + images built by Zensical (zensical build) into public/, served by nginx behind Traefik. Content is bind-mounted from /mnt/containers/help-osk-docs (absolute host path — Portainer GitOps can't resolve relative mounts). Adds the help/help-osk router+service to traefik/dynamic/web.yml (TLS via Let's Encrypt, public/open). Co-Authored-By: Claude Opus 4.8 --- help-osk-docs/.gitignore | 3 + help-osk-docs/README.md | 69 ++++++++++++++++++++ help-osk-docs/docker-compose.yaml | 37 +++++++++++ help-osk-docs/docs/assets/.gitkeep | 2 + help-osk-docs/docs/index.md | 18 ++++++ help-osk-docs/docs/primer-instrukcii.md | 55 ++++++++++++++++ help-osk-docs/nginx.conf | 31 +++++++++ help-osk-docs/zensical.toml | 85 +++++++++++++++++++++++++ traefik/dynamic/web.yml | 11 ++++ 9 files changed, 311 insertions(+) create mode 100644 help-osk-docs/.gitignore create mode 100644 help-osk-docs/README.md create mode 100644 help-osk-docs/docker-compose.yaml create mode 100644 help-osk-docs/docs/assets/.gitkeep create mode 100644 help-osk-docs/docs/index.md create mode 100644 help-osk-docs/docs/primer-instrukcii.md create mode 100644 help-osk-docs/nginx.conf create mode 100644 help-osk-docs/zensical.toml diff --git a/help-osk-docs/.gitignore b/help-osk-docs/.gitignore new file mode 100644 index 0000000..a6d673b --- /dev/null +++ b/help-osk-docs/.gitignore @@ -0,0 +1,3 @@ +# Build output — generated by `zensical build`, not tracked. +/public/ +.DS_Store diff --git a/help-osk-docs/README.md b/help-osk-docs/README.md new file mode 100644 index 0000000..9736cf0 --- /dev/null +++ b/help-osk-docs/README.md @@ -0,0 +1,69 @@ +# help-osk-docs — instructions site for client 05 + +Public static site at **https://help.osk.team** with user instructions, written +in Markdown and built with [Zensical](https://github.com/zensical/zensical) +(static-site generator from the Material for MkDocs team). Served by `nginx` +behind the existing Traefik reverse proxy. + +## How it works + +- `docs/` — Markdown pages (+ `docs/assets/` for images). **This is the content.** +- `zensical.toml` — site config (name, nav, theme, Markdown extensions). +- `nginx.conf` — static web-server config. +- `docker-compose.yaml` — two services: + - `help-osk-build` — Zensical image, one-shot: runs `zensical build --clean`, + rendering `docs/` → `public/`, then exits. (The Zensical image is a + builder, **not** a host server — by design.) + - `help-osk` — `nginx:alpine`, serves `public/`, joins `reverseproxy-nw`. + Starts only after the build succeeds. +- Traefik terminates TLS for `help.osk.team` (Let's Encrypt) and proxies to the + `help-osk` container. Router/service live in + `../traefik/dynamic/web.yml` (`help` / `help-osk`). + +## Bind-mount / host-sync (important) + +Content is **bind-mounted**, and Portainer GitOps can't bind-mount the +repo checkout (relative paths resolve inside Portainer's container and become +empty dirs). So the project must exist on the host at an absolute path — +exactly like the Traefik config. This git repo is the **source of truth**. + +Sync the project to the host (excluding the generated `public/`): + +```sh +rsync -a --delete --exclude 'public/' \ + help-osk-docs/ :/mnt/containers/help-osk-docs/ +``` + +The `help-osk-build` container creates `/mnt/containers/help-osk-docs/public` +on the host during the build. + +## Deploy (Portainer) + +1. DNS: `help.osk.team` → public edge IP, reachable on :80 (Let's Encrypt + http-01). *(Done.)* +2. Sync this folder to `/mnt/containers/help-osk-docs/` on the docker host + (see above). +3. Make sure the Traefik `help` router/service in `../traefik/dynamic/web.yml` + is also synced to the host dynamic dir + (`/mnt/containers/traefik/container-data/dynamic/web.yml`). Traefik's file + provider (`watch: true`) picks it up live — no Traefik restart needed. +4. In Portainer, add a stack pointing at `help-osk-docs/docker-compose.yaml` + (or redeploy the existing stack). The builder runs, then nginx comes up. + +## Add or edit an instruction + +1. Add/edit a Markdown file in `docs/` (e.g. `docs/nastrojka-vpn.md`). +2. Put images in `docs/assets/`, reference them: `![alt](assets/file.png)` + (size with `![alt](assets/file.png){ width="600" }`). +3. Add the page to `nav` in `zensical.toml`. +4. Commit, re-sync to the host (step 2 above), redeploy the stack in Portainer + (re-runs the build; nginx serves the updated `public/`). + +## Local preview (optional) + +```sh +# Build and inspect output +docker run --rm -v "$PWD":/docs:Z zensical/zensical build --clean +# Live preview on http://localhost:8000 +docker run --rm -p 8000:8000 -v "$PWD":/docs zensical/zensical +``` diff --git a/help-osk-docs/docker-compose.yaml b/help-osk-docs/docker-compose.yaml new file mode 100644 index 0000000..5e48a29 --- /dev/null +++ b/help-osk-docs/docker-compose.yaml @@ -0,0 +1,37 @@ +services: + # One-shot builder. Zensical's official image is for builds/previews only + # (NOT a host server), so we use it to render docs/ -> public/, then exit. + help-osk-build: + image: zensical/zensical:latest + container_name: help-osk-build + working_dir: /docs + command: ["build", "--clean"] + restart: "no" + volumes: + # Whole project (zensical.toml + docs/ + writes public/) on the host. + # + # NOTE: absolute host path (NOT ./relative). Portainer GitOps runs compose + # with paths relative to its own container (/data/compose//...), which + # the Docker daemon can't resolve — relative mounts silently become empty + # dirs. Keep /mnt/containers/help-osk-docs in sync with this repo (source + # of truth), same as the traefik config. + - /mnt/containers/help-osk-docs:/docs:z + + # Static web server. Serves the generated public/ and joins the Traefik + # reverse-proxy network; Traefik terminates TLS for help.osk.team. + help-osk: + image: nginx:alpine + container_name: help-osk + restart: always + depends_on: + help-osk-build: + condition: service_completed_successfully + volumes: + - /mnt/containers/help-osk-docs/public:/usr/share/nginx/html:ro,z + - /mnt/containers/help-osk-docs/nginx.conf:/etc/nginx/conf.d/default.conf:ro,z + networks: + - reverseproxy-nw + +networks: + reverseproxy-nw: + external: true diff --git a/help-osk-docs/docs/assets/.gitkeep b/help-osk-docs/docs/assets/.gitkeep new file mode 100644 index 0000000..709de25 --- /dev/null +++ b/help-osk-docs/docs/assets/.gitkeep @@ -0,0 +1,2 @@ +# Положите сюда картинки для инструкций (png/jpg/svg). +# Ссылка из Markdown: ![alt](assets/имя-файла.png) diff --git a/help-osk-docs/docs/index.md b/help-osk-docs/docs/index.md new file mode 100644 index 0000000..0281641 --- /dev/null +++ b/help-osk-docs/docs/index.md @@ -0,0 +1,18 @@ +--- +icon: lucide/book-open +--- + +# Инструкции + +Добро пожаловать в базу инструкций. Выберите нужный раздел в меню слева +или воспользуйтесь поиском вверху страницы. + +## Разделы + +- [Пример инструкции](primer-instrukcii.md) — шаблон страницы с картинками и подсказками. + +!!! tip "Как добавить новую инструкцию" + + Создайте Markdown-файл в папке `docs/`, добавьте его в `nav` в файле + `zensical.toml`, положите картинки в `docs/assets/` — и пересоберите сайт. + Подробнее — в `README.md` этого репозитория. diff --git a/help-osk-docs/docs/primer-instrukcii.md b/help-osk-docs/docs/primer-instrukcii.md new file mode 100644 index 0000000..9d15092 --- /dev/null +++ b/help-osk-docs/docs/primer-instrukcii.md @@ -0,0 +1,55 @@ +--- +icon: lucide/file-text +--- + +# Пример инструкции + +Эта страница — шаблон. Скопируйте её, переименуйте и наполните своим текстом. + +## Шаги + +1. Откройте нужное приложение. +2. Выполните действие. +3. Проверьте результат. + +## Картинки + +Положите изображение в `docs/assets/` и вставьте его так: + +```markdown +![Описание картинки](assets/primer.png) +``` + +Картинку можно масштабировать (включено расширение `attr_list`): + +```markdown +![Описание](assets/primer.png){ width="500" } +``` + + + +## Подсказки и предупреждения + +!!! note "Заметка" + + Используйте блоки-заметки для важной информации. + +!!! warning "Внимание" + + Так выделяются предупреждения. + +??? info "Нажмите, чтобы развернуть" + + Скрытый блок — удобно для длинных пояснений или частых вопросов. + +## Сочетания клавиш + +Скопировать: ++ctrl+c++    Вставить: ++ctrl+v++ + +## Чек-лист + +- [x] Открыть приложение +- [ ] Выполнить настройку +- [ ] Проверить результат diff --git a/help-osk-docs/nginx.conf b/help-osk-docs/nginx.conf new file mode 100644 index 0000000..2eab53a --- /dev/null +++ b/help-osk-docs/nginx.conf @@ -0,0 +1,31 @@ +# Serves the static site built by Zensical (./public) for client 05. +# Mounted at /etc/nginx/conf.d/default.conf inside nginx:alpine. + +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # Zensical uses directory-style URLs (/page/ -> /page/index.html). + # Unknown paths fall through to the generated 404 page. + error_page 404 /404.html; + location / { + try_files $uri $uri/ =404; + } + + # Long-cache fingerprinted theme assets; keep HTML uncached so content + # updates show up immediately after a rebuild. + location /assets/ { + expires 7d; + add_header Cache-Control "public"; + } + location = /404.html { + internal; + } + + gzip on; + gzip_types text/css application/javascript application/json image/svg+xml; + gzip_min_length 1024; +} diff --git a/help-osk-docs/zensical.toml b/help-osk-docs/zensical.toml new file mode 100644 index 0000000..a934f1f --- /dev/null +++ b/help-osk-docs/zensical.toml @@ -0,0 +1,85 @@ +# Zensical configuration — client 05 (05-osk) instructions site. +# Docs: https://zensical.org/docs/setup/basics/ +# Build: `zensical build --clean` -> outputs static site to ./public + +[project] +site_name = "ОСК — Инструкции" +site_description = "Инструкции для пользователей (клиент 05)." +site_author = "ОСК" +site_url = "https://help.osk.team/" +copyright = """ +Copyright © 2026 ОСК +""" + +# Explicit navigation. Add a line per Markdown page you create under docs/. +# Remove this block to let Zensical derive the nav from the folder structure. +nav = [ + { "Главная" = "index.md" }, + { "Пример инструкции" = "primer-instrukcii.md" }, +] + +[project.theme] +language = "ru" +features = [ + "announce.dismiss", + "content.code.annotate", + "content.code.copy", + "content.tooltips", + "navigation.footer", + "navigation.indexes", + "navigation.instant", + "navigation.instant.prefetch", + "navigation.path", + "navigation.sections", + "navigation.top", + "navigation.tracking", + "search.highlight", +] + +# Optional: drop a logo at docs/assets/logo.png and uncomment. +#logo = "assets/logo.png" + +[[project.theme.palette]] +scheme = "default" +toggle.icon = "lucide/sun" +toggle.name = "Тёмная тема" + +[[project.theme.palette]] +scheme = "slate" +toggle.icon = "lucide/moon" +toggle.name = "Светлая тема" + +# ---------------------------------------------------------------------------- +# Markdown extensions — enables admonitions, image attributes (sizing/align), +# task lists, code highlighting, tabs, etc. Kept from Zensical's defaults. +# ---------------------------------------------------------------------------- +[project.markdown_extensions.abbr] +[project.markdown_extensions.admonition] +[project.markdown_extensions.attr_list] +[project.markdown_extensions.def_list] +[project.markdown_extensions.footnotes] +[project.markdown_extensions.md_in_html] +[project.markdown_extensions.toc] +permalink = true +[project.markdown_extensions.pymdownx.betterem] +[project.markdown_extensions.pymdownx.caret] +[project.markdown_extensions.pymdownx.details] +[project.markdown_extensions.pymdownx.emoji] +emoji_generator = "zensical.extensions.emoji.to_svg" +emoji_index = "zensical.extensions.emoji.twemoji" +[project.markdown_extensions.pymdownx.highlight] +anchor_linenums = true +line_spans = "__span" +pygments_lang_class = true +[project.markdown_extensions.pymdownx.inlinehilite] +[project.markdown_extensions.pymdownx.keys] +[project.markdown_extensions.pymdownx.magiclink] +[project.markdown_extensions.pymdownx.mark] +[project.markdown_extensions.pymdownx.smartsymbols] +[project.markdown_extensions.pymdownx.superfences] +[project.markdown_extensions.pymdownx.tabbed] +alternate_style = true +combine_header_slug = true +[project.markdown_extensions.pymdownx.tasklist] +custom_checkbox = true +[project.markdown_extensions.pymdownx.tilde] diff --git a/traefik/dynamic/web.yml b/traefik/dynamic/web.yml index c256a42..4aee2c5 100644 --- a/traefik/dynamic/web.yml +++ b/traefik/dynamic/web.yml @@ -15,6 +15,13 @@ http: tls: certResolver: le + help: # client 05 instructions site (public, open) + entryPoints: ["websecure"] + rule: "Host(`help.osk.team`)" + service: help-osk + tls: + certResolver: le + portainer: entryPoints: ["websecure"] rule: "Host(`portainer.osk.team`)" @@ -35,6 +42,10 @@ http: loadBalancer: servers: - url: "http://flame:5005" + help-osk: + loadBalancer: + servers: + - url: "http://help-osk:80" # nginx container on reverseproxy-nw portainer: # Portainer must share a network with Traefik. Either add the portainer # container to reverseproxy-nw, or point this at the host IP instead: