wiki(concepts): ingest ocis-on-vds-deploy-recipe + entity refresh
New concept page documents the oCIS-on-VDS deploy pattern with the 4
non-obvious gotchas surfaced during owncloud-vds-deploy:
1. UID mismatch — image ocis-user is 1000, host vitya is 1001 →
compose `user: "1001:1001"` override (alt chown rejected as orphan-UID)
2. PROXY_TLS=false — explicit per docs when reverse proxy terminates HTTPS
3. PROXY_ENABLE_BASIC_AUTH=true — required for WebDAV/LibreGraph API
4. LibreGraph POST /graph/v1.0/users — only way to create users (no CLI)
Plus decomposedfs storage layout, atomic-revert recipe, backup integration
note. Source: .tasks/owncloud-vds-deploy.md.
entities/vds-kzntsv.md updated: stack table + hostnames + file layout
include owncloud row.
index.md catalog + log.md ingest entry refreshed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
180
.wiki/concepts/ocis-on-vds-deploy-recipe.md
Normal file
180
.wiki/concepts/ocis-on-vds-deploy-recipe.md
Normal file
@@ -0,0 +1,180 @@
|
||||
---
|
||||
title: oCIS на VDS — deploy recipe + non-obvious gotchas
|
||||
type: concept
|
||||
tags: [recipe, owncloud, ocis, docker, traefik, webdav, libregraph, decomposedfs]
|
||||
sources: [../../.tasks/owncloud-vds-deploy.md]
|
||||
updated: 2026-05-21
|
||||
---
|
||||
|
||||
# oCIS на VDS — deploy recipe + non-obvious gotchas
|
||||
|
||||
Recipe для разворачивания **ownCloud Infinite Scale** (oCIS) — Go-based замены classic ownCloud Server 10 — в Docker за traefik с LetsEncrypt. Применимо на [[vds-kzntsv]] и других хостах с тем же pattern'ом (`/opt/stacks/<name>/`, traefik network `proxy`, LE certresolver `letsEncrypt`).
|
||||
|
||||
Validated 2026-05-21 на image `owncloud/ocis:7.1.0`. Container запустился, traefik routes 200 OK, LibreGraph API + WebDAV работают, init создаёт admin + idm.json в `data/idm/`.
|
||||
|
||||
## Когда применять
|
||||
|
||||
- Личный personal-cloud для одного пользователя (single binary, no external DB)
|
||||
- Replace мёртвого / legacy ownCloud Server 10 (oCIS = main line от ownCloud GmbH, OC10 deprecating)
|
||||
- Files-only use-case (calendar/contacts не нужны — для тех нужен Nextcloud)
|
||||
- На хосте с уже работающим traefik + LE certresolver (recipe рассчитан на termination upstream)
|
||||
|
||||
## Когда **не** применять
|
||||
|
||||
- Multi-tenant корпоративная инсталляция → нужны external IDP, OIDC chain, не личный setup
|
||||
- Нужны calendar / contacts / mail / collabora → Nextcloud, не oCIS
|
||||
- Block-level dedup критичен → Seafile (oCIS использует file-level decomposedfs)
|
||||
- Host UID = 1000 (image uid 1000 matches → `user:` override **не** нужен)
|
||||
|
||||
## Compose recipe
|
||||
|
||||
`/opt/stacks/owncloud/docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
ocis:
|
||||
image: owncloud/ocis:7.1.0
|
||||
container_name: owncloud
|
||||
restart: unless-stopped
|
||||
user: "1001:1001" # ← gotcha 1, см. ниже
|
||||
entrypoint: /bin/sh
|
||||
command: ["-c", "ocis init || true; exec ocis server"]
|
||||
environment:
|
||||
OCIS_URL: https://owncloud.kzntsv.site
|
||||
OCIS_LOG_LEVEL: info
|
||||
OCIS_LOG_COLOR: "false"
|
||||
PROXY_TLS: "false" # ← gotcha 2
|
||||
PROXY_ENABLE_BASIC_AUTH: "true" # ← gotcha 3
|
||||
OCIS_INSECURE: "false"
|
||||
IDM_CREATE_DEMO_USERS: "false"
|
||||
IDM_ADMIN_PASSWORD: ${OCIS_ADMIN_PASSWORD}
|
||||
volumes:
|
||||
- ./data:/var/lib/ocis
|
||||
- ./config:/etc/ocis
|
||||
networks: [proxy]
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- "traefik.http.routers.owncloud.rule=Host(`owncloud.kzntsv.site`)"
|
||||
- traefik.http.routers.owncloud.entrypoints=websecure
|
||||
- traefik.http.routers.owncloud.tls.certresolver=letsEncrypt
|
||||
- traefik.http.services.owncloud.loadbalancer.server.port=9200
|
||||
|
||||
networks:
|
||||
proxy: { external: true }
|
||||
```
|
||||
|
||||
`/opt/stacks/owncloud/.env` (chmod 600):
|
||||
```
|
||||
OCIS_ADMIN_PASSWORD=<32+ random chars, store в pass owncloud/admin-password>
|
||||
```
|
||||
|
||||
## Gotcha 1: UID mismatch image vs host
|
||||
|
||||
Image `owncloud/ocis` runs as **UID 1000** (`ocis-user` внутри контейнера). Если host-side user-owner mounted dirs ≠ 1000 — контейнер падает в restart-loop с:
|
||||
|
||||
```
|
||||
Could not create config: open /etc/ocis/ocis.yaml: permission denied
|
||||
The jwt_secret has not been set properly in your config for ocis.
|
||||
```
|
||||
|
||||
«jwt_secret has not been set» — **обманка**, симптом сидит на ровном месте perm-deny при попытке записать ocis.yaml на первом `ocis init` пробеге.
|
||||
|
||||
**Fix:** `user: "<host-uid>:<host-gid>"` override в compose. На vds-kzntsv host user `vitya` = UID 1001 → `user: "1001:1001"`. Альтернатива (`chown 1000` host-dirs) **отвергнута**: создаёт orphan UID на хосте, путает auditing + backup tools.
|
||||
|
||||
**Diagnose UID:** `stat -c "%u:%g %U:%G" /opt/stacks/owncloud/config`.
|
||||
|
||||
## Gotcha 2: `PROXY_TLS=false` за reverse proxy
|
||||
|
||||
Дефолт oCIS — `PROXY_TLS=true` (HTTPS на proxy port 9200 self-signed). За traefik, который сам терминирует HTTPS, это даёт двойную TLS-обёртку — traefik пытается сделать backend TLS, не получается.
|
||||
|
||||
Per ownCloud docs: «If a reverse proxy is used to terminate HTTPS, `PROXY_TLS` can be set to false, though this means communication between the proxy and Infinite Scale will be unencrypted.» На том же хосте, в bridge network — acceptable.
|
||||
|
||||
## Gotcha 3: `PROXY_ENABLE_BASIC_AUTH=true` для WebDAV + admin API
|
||||
|
||||
Дефолтно oCIS — OIDC-only (browser-based login). Для **rclone / ownCloud-desktop / curl LibreGraph API** нужен basic auth — иначе 401 везде, включая `GET /graph/v1.0/me`.
|
||||
|
||||
**Trade-off:** basic auth не имеет MFA/refresh-tokens. Для personal use acceptable. Для shared deployment — обернуть LDAP / OIDC отдельно.
|
||||
|
||||
## Gotcha 4: User-create via LibreGraph API (нет CLI)
|
||||
|
||||
oCIS **не** имеет `ocis idm user add` или подобной CLI команды. Создание users — только через:
|
||||
|
||||
1. Web UI как admin → Settings → Users
|
||||
2. LibreGraph API: `POST /graph/v1.0/users` с basic auth admin'а
|
||||
|
||||
API recipe:
|
||||
```bash
|
||||
curl -u "admin:$ADMIN_PWD" -X POST \
|
||||
"https://owncloud.kzntsv.site/graph/v1.0/users" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"displayName": "Vitya",
|
||||
"onPremisesSamAccountName": "vitya",
|
||||
"mail": "vitya@kzntsv.site",
|
||||
"passwordProfile": {"password": "<random-32>"},
|
||||
"accountEnabled": true
|
||||
}'
|
||||
```
|
||||
→ HTTP 201 с user JSON (с `id` UUID).
|
||||
|
||||
List users: `GET /graph/v1.0/users`.
|
||||
|
||||
## Storage layout (decomposedfs)
|
||||
|
||||
После `ocis init` data dir выглядит так:
|
||||
|
||||
```
|
||||
/opt/stacks/owncloud/data/
|
||||
├── idm/ — internal IDM (LDAP-style) state
|
||||
├── idp/ — OIDC IdP private keys (private-key.pem etc)
|
||||
├── nats/ — internal pub-sub messaging
|
||||
├── search/ — indexer state (bleve)
|
||||
└── storage/
|
||||
├── metadata/spaces/<2>/<rest>/ — space metadata
|
||||
└── users/spaces/<2>/<rest>/ — actual user files (decomposedfs nodes)
|
||||
```
|
||||
|
||||
Каждый user space = `<2-char-prefix>/<26-char-rest-of-uuid>/` (split UUID для FS spread). Files внутри хранятся как **plain bytes** + sidecar metadata (xattrs / .meta.json). Backup-friendly: tar+rsync захватит всё корректно, восстановление = просто разархивировать обратно.
|
||||
|
||||
Internal KV-store (`storage/users/spaces/.../metadata/`, `idm/idm.json`, etc.) — **JSON files**, не БД. Это и есть «no external DB needed» — oCIS использует filesystem + NATS вместо Postgres/Redis.
|
||||
|
||||
## Backup integration
|
||||
|
||||
`/opt/stacks/owncloud` (whole dir) добавлен в rsync source list [[vds-backup-rsync-kreknin]]:
|
||||
|
||||
```diff
|
||||
/opt/stacks/backup \
|
||||
+ /opt/stacks/owncloud \
|
||||
/etc/ssh \
|
||||
```
|
||||
|
||||
Live container во время rsync — acceptable trade-off (decomposedfs использует atomic rename, отдельные node-files не corrupt'ятся). Если требуется strictly consistent snapshot — `docker stop owncloud` → rsync → `docker start` (downtime ~30s).
|
||||
|
||||
Первый full backup snapshot после import → +~25 GB на kreknin. Далее hardlink-incremental ≈ 1 GB/day.
|
||||
|
||||
## Connection chain
|
||||
|
||||
```
|
||||
DNS owncloud.kzntsv.site → 89.253.255.94 (VDS_IP)
|
||||
→ ufw 443
|
||||
→ traefik websecure (LE cert via letsEncrypt resolver)
|
||||
→ docker network proxy (172.18.0.0/16)
|
||||
→ container owncloud:9200 (oCIS proxy service)
|
||||
→ internal services: idp / idm / users / groups / proxy / storage-system / sharing / search ...
|
||||
```
|
||||
|
||||
## Atomic revert
|
||||
|
||||
```bash
|
||||
ssh vitya@89.253.255.94 'cd /opt/stacks/owncloud && docker compose down -v && cd .. && rm -rf owncloud'
|
||||
# rsync source list cleanup (revert):
|
||||
ssh vitya@89.253.255.94 "sed -i '\\|/opt/stacks/owncloud|d' /opt/stacks/backup/scripts/run.sh"
|
||||
# secrets cleanup:
|
||||
pass rm owncloud/admin-password owncloud/user-vitya && pass git push
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [[admin-infra-project]] — общий context для admin-infra repo
|
||||
- [[vds-kzntsv]] — host entity (owncloud стек добавлен в его software stack)
|
||||
- [[future-resilient-architecture-goals]] — RTO/RPO targets (oCIS — single-user, RTO/RPO defer)
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: VDS kzntsv — Rusonyx 160 NVMe cloud server
|
||||
type: entity
|
||||
tags: [hardware, vds, cloud, rusonyx, infrastructure, gitea, verdaccio, registry, postgres, mariadb, mongo, redis]
|
||||
tags: [hardware, vds, cloud, rusonyx, infrastructure, gitea, verdaccio, registry, postgres, mariadb, mongo, redis, owncloud, ocis]
|
||||
sources: [../sources/vds-kzntsv-bootstrap-2026-05-20.md]
|
||||
updated: 2026-05-20
|
||||
updated: 2026-05-21
|
||||
---
|
||||
|
||||
# VDS kzntsv
|
||||
@@ -51,6 +51,7 @@ Production CMS (MoreThenCms) **остаётся на** [`windows-recovery-host`]
|
||||
| Git | gitea | 1.25.5 | `/opt/stacks/gitea/` |
|
||||
| NPM | verdaccio | 6 | `/opt/stacks/verdaccio/` |
|
||||
| Docker registry | registry | 2.8.3 + joxit UI | `/opt/stacks/registry/` |
|
||||
| Personal cloud | ownCloud Infinite Scale (oCIS) | 7.1.0 | `/opt/stacks/owncloud/` |
|
||||
|
||||
## Docker networks (external)
|
||||
|
||||
@@ -67,6 +68,7 @@ Production CMS (MoreThenCms) **остаётся на** [`windows-recovery-host`]
|
||||
| `verdaccio.kzntsv.site` | Verdaccio | kreknin htpasswd (vitya) | Private npm |
|
||||
| `registry.kzntsv.site` | Docker Registry | vitya / Pryakhin9 (htpasswd) | Docker images |
|
||||
| `registry-ui.vds.kzntsv.site` | Joxit Registry UI | (proxied к registry, та же auth) | GUI cleanup |
|
||||
| `owncloud.kzntsv.site` | oCIS (ownCloud Infinite Scale) | admin + vitya (pass `owncloud/*`); basic auth enabled для WebDAV/LibreGraph | Personal cloud, replace мёртвой Synology ownCloud (см. [`ocis-on-vds-deploy-recipe`](../concepts/ocis-on-vds-deploy-recipe.md)) |
|
||||
| `postgres.vds.kzntsv.site:5432` | Postgres TLS | postgres / hex32 | Shared DB |
|
||||
| `mariadb.vds.kzntsv.site:3306` | MariaDB TLS | root / hex32 | Shared DB |
|
||||
| `mongo.vds.kzntsv.site:27017` | MongoDB TLS | root / hex32 | Shared DB |
|
||||
@@ -102,10 +104,15 @@ DB TLS: self-signed certs (CN matches hostname), клиент с `verify-none` /
|
||||
│ ├── config/{config.yaml,htpasswd}
|
||||
│ ├── plugins/
|
||||
│ └── docker-compose.yml
|
||||
└── registry/
|
||||
├── docker/ (registry blobs storage)
|
||||
├── auth/htpasswd
|
||||
└── docker-compose.yml (registry + registry-ui в одном compose)
|
||||
├── registry/
|
||||
│ ├── docker/ (registry blobs storage)
|
||||
│ ├── auth/htpasswd
|
||||
│ └── docker-compose.yml (registry + registry-ui в одном compose)
|
||||
└── owncloud/
|
||||
├── data/ (decomposedfs: idm/, idp/, nats/, search/, storage/{metadata,users}/spaces/...)
|
||||
├── config/ (ocis.yaml generated by `ocis init`)
|
||||
├── .env (chmod 600 — OCIS_ADMIN_PASSWORD)
|
||||
└── docker-compose.yml (oCIS 7.1.0 + traefik labels — recipe: [`ocis-on-vds-deploy-recipe`](../concepts/ocis-on-vds-deploy-recipe.md))
|
||||
```
|
||||
|
||||
## Что входит в backup pipeline (planned)
|
||||
|
||||
@@ -25,6 +25,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
||||
- [hyper-backup-structure-and-recovery](concepts/hyper-backup-structure-and-recovery.md) — Hyper Backup — структура репо и стратегия восстановления
|
||||
- [iis-migration-2026-05-19-postmortem](concepts/iis-migration-2026-05-19-postmortem.md) — post-mortem миграции CMS на нативный IIS, 2026-05-19
|
||||
- [mssql-container-data-restore](concepts/mssql-container-data-restore.md) — MSSQL контейнер с восстановленными production data — паттерн
|
||||
- [ocis-on-vds-deploy-recipe](concepts/ocis-on-vds-deploy-recipe.md) — oCIS на VDS — deploy recipe + non-obvious gotchas (UID 1001 vs 1000, basic auth, LibreGraph user-create)
|
||||
- [portainer-2.21-admin-password-regression](concepts/portainer-2.21-admin-password-regression.md) — Portainer 2.21 `--admin-password` regression + min 12-char policy
|
||||
- [recovery-architecture-snapshot](concepts/recovery-architecture-snapshot.md) — текущая recovery architecture (2026-05-19/21, attempt 2)
|
||||
- [registry-gc-mount-and-modify-flag](concepts/registry-gc-mount-and-modify-flag.md) — Docker Registry GC mount layout + `-m` flag
|
||||
|
||||
@@ -13,3 +13,5 @@ Append-only log of wiki operations (ingests, promotions, lints, migrations).
|
||||
## [2026-05-21] migrate | subtree-import 6 entities + 17 concepts + 3 sources from MoreThenCms (history preserved via subtree-split + temp-prefix merge)
|
||||
|
||||
## [2026-05-21] regen | index.md catalog refresh after subtree import
|
||||
|
||||
## [2026-05-21] ingest | concepts/ocis-on-vds-deploy-recipe — oCIS deploy recipe + gotchas (UID mismatch, PROXY_TLS, PROXY_ENABLE_BASIC_AUTH, LibreGraph user-create); updated entities/vds-kzntsv (added owncloud row to stack/hostnames/file-layout); source: .tasks/owncloud-vds-deploy.md
|
||||
|
||||
Reference in New Issue
Block a user