Add help-osk-docs stack: Zensical instructions site for 05-osk
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 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# Build output — generated by `zensical build`, not tracked.
|
||||
/public/
|
||||
.DS_Store
|
||||
@@ -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/ <docker-host>:/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: ``
|
||||
(size with `{ 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
|
||||
```
|
||||
@@ -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/<id>/...), 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
|
||||
@@ -0,0 +1,2 @@
|
||||
# Положите сюда картинки для инструкций (png/jpg/svg).
|
||||
# Ссылка из Markdown: 
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
icon: lucide/book-open
|
||||
---
|
||||
|
||||
# Инструкции
|
||||
|
||||
Добро пожаловать в базу инструкций. Выберите нужный раздел в меню слева
|
||||
или воспользуйтесь поиском вверху страницы.
|
||||
|
||||
## Разделы
|
||||
|
||||
- [Пример инструкции](primer-instrukcii.md) — шаблон страницы с картинками и подсказками.
|
||||
|
||||
!!! tip "Как добавить новую инструкцию"
|
||||
|
||||
Создайте Markdown-файл в папке `docs/`, добавьте его в `nav` в файле
|
||||
`zensical.toml`, положите картинки в `docs/assets/` — и пересоберите сайт.
|
||||
Подробнее — в `README.md` этого репозитория.
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
icon: lucide/file-text
|
||||
---
|
||||
|
||||
# Пример инструкции
|
||||
|
||||
Эта страница — шаблон. Скопируйте её, переименуйте и наполните своим текстом.
|
||||
|
||||
## Шаги
|
||||
|
||||
1. Откройте нужное приложение.
|
||||
2. Выполните действие.
|
||||
3. Проверьте результат.
|
||||
|
||||
## Картинки
|
||||
|
||||
Положите изображение в `docs/assets/` и вставьте его так:
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
Картинку можно масштабировать (включено расширение `attr_list`):
|
||||
|
||||
```markdown
|
||||
{ width="500" }
|
||||
```
|
||||
|
||||
<!-- Когда добавите файл docs/assets/primer.png, раскомментируйте строку ниже:
|
||||
{ width="600" }
|
||||
-->
|
||||
|
||||
## Подсказки и предупреждения
|
||||
|
||||
!!! note "Заметка"
|
||||
|
||||
Используйте блоки-заметки для важной информации.
|
||||
|
||||
!!! warning "Внимание"
|
||||
|
||||
Так выделяются предупреждения.
|
||||
|
||||
??? info "Нажмите, чтобы развернуть"
|
||||
|
||||
Скрытый блок — удобно для длинных пояснений или частых вопросов.
|
||||
|
||||
## Сочетания клавиш
|
||||
|
||||
Скопировать: ++ctrl+c++ Вставить: ++ctrl+v++
|
||||
|
||||
## Чек-лист
|
||||
|
||||
- [x] Открыть приложение
|
||||
- [ ] Выполнить настройку
|
||||
- [ ] Проверить результат
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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]
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user