Files
admin/.tasks/owncloud-vds-deploy.md
vitya c46e569908 tasks(owncloud-vds-deploy): file 🟡 — oCIS on VDS up + WebDAV verified
Deploy phase done: oCIS 7.1.0 в /opt/stacks/owncloud/ через traefik labels на
owncloud.kzntsv.site (LE cert valid), user 'vitya' создан через LibreGraph
API, WebDAV `/dav/files/vitya/` PROPFIND 200 OK.

Decisions in close-note: oCIS vs Seafile/Nextcloud chosen for drop-in
decomposedfs import + lightweight Go binary. user:1001:1001 override after
mount perms fail (host vitya UID 1001 ≠ image ocis-user UID 1000).
PROXY_ENABLE_BASIC_AUTH=true для WebDAV/LibreGraph admin API.

Backup integration: /opt/stacks/owncloud добавлен в rsync sources в
/opt/stacks/backup/scripts/run.sh (vds-backup-rsync-kreknin scope expanded).

Status 🟡 — pending user-side rclone copy 24.7GB → WebDAV (full copy лежит
на другом PC, не на этом).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:07:10 +03:00

8.1 KiB
Raw Blame History

owncloud-vds-deploy

Goal

Поднять owncloud-infinite-scale (oCIS 7.1.0) на vds-kzntsv в качестве замены мёртвого ownCloud сервера на Synology NAS (см. nas-recovery). После восстановления — импортировать 24.7 GB из off-VDS backup-копии. Сервис на owncloud.kzntsv.site, files-only (calendar/contacts не нужны).

Decisions log

  • 2026-05-21 — oCIS vs Seafile vs Nextcloud: oCIS выбран. Reasons: (1) drop-in миграция — decomposedfs storage по сути plain-files на диске (24.7 GB просто кладутся); (2) lightweight — single Go binary, не PHP-monstr classic ownCloud 10; (3) workflow continuity — user уже знаком с ownCloud UX; (4) тривиальный backup (tar data/ + конфиг); (5) future-proof — oCIS = main line от ownCloud GmbH, classic OC10 deprecating. Seafile отвергнут: block-storage = нет drop-in import, медленнее migration. Nextcloud отвергнут: только files нужны — calendar/contacts overhead не оправдан.

  • 2026-05-21 — user: "1001:1001" override: image owncloud/ocis runs as UID 1000 (ocis-user inside container) by default, но host vitya = UID 1001. Mount-target dirs (./data, ./config) owned by vitya → container не мог писать. Fix: добавил user: "1001:1001" в compose — container runs as host UID, owns mounted dirs. Альтернатива (chown 1000 хост-dirs) отвергнута — создаёт orphan UID на хосте.

  • 2026-05-21 — PROXY_ENABLE_BASIC_AUTH=true: дефолтно oCIS basic auth выключен (OIDC-only). Для WebDAV-клиентов (rclone, ownCloud desktop) и LibreGraph API admin-операций basic auth нужен → enabled. Trade-off: чуть слабее security (basic auth не имеет MFA/refresh tokens), но threat model personal use acceptable.

  • 2026-05-21 — PROXY_TLS=false: docs прямо разрешают, когда TLS термируется на reverse proxy (traefik certresolver letsEncrypt). Альтернатива — собственный self-signed cert внутри контейнера + traefik passthrough — overhead без выгоды.

  • 2026-05-21 — admin/user-vitya passwords в pass-store: owncloud/admin-password (32 chars random) + owncloud/user-vitya (32 chars random). Encrypted-at-rest, cross-machine sync через OpeItcLoc03/password-store-private. Закрывает риски secrets-manager-adopt.

  • 2026-05-21 — DNS surprise: ожидали, что user будет создавать A-запись owncloud.kzntsv.site → 89.253.255.94 вручную. Reality: запись уже была (видимо ранее создана при wildcard cleanup / dns prep), сразу резолвилась на VDS_IP. Wildcard *.kzntsv.site → 94.19.247.14 (NAS recovery host) overlay-ится specific записями.

  • 2026-05-21 — backup integration: добавил /opt/stacks/owncloud в rsync source list /opt/stacks/backup/scripts/run.sh (vds-backup-rsync-kreknin). После import 24.7GB первый full backup snapshot будет +24.7GB на kreknin, далее ~hardlink incremental. kreknin 5.6 TB free — comfortably fits.

Implementation sketch

/opt/stacks/owncloud/docker-compose.yml:

services:
  ocis:
    image: owncloud/ocis:7.1.0
    container_name: owncloud
    restart: unless-stopped
    user: "1001:1001"
    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"
      PROXY_ENABLE_BASIC_AUTH: "true"
      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-char-random — стор в pass owncloud/admin-password>

User creation via LibreGraph API (POST /graph/v1.0/users, basic auth as admin).

Completed steps

  • Compose написан, image owncloud/ocis:7.1.0 pulled (digest sha256:c75af880...b717b)
  • Dirs: /opt/stacks/owncloud/{data,config} (vitya:vitya 775)
  • Secrets: OCIS_ADMIN_PASSWORD в .env (chmod 600), originals в pass-store: owncloud/admin-password + owncloud/user-vitya (pushed to OpeItcLoc03/password-store-private)
  • Deploy: docker compose up -d через ssh (limited stack — Portainer auto-detects)
  • UID fix: user: "1001:1001" после первого "permission denied" на /etc/ocis/ocis.yaml
  • Basic auth fix: PROXY_ENABLE_BASIC_AUTH=true после 401 на LibreGraph API
  • Traefik integration: labels подхвачены, cert via letsEncrypt valid, HTTPS 200 OK
  • User vitya created через LibreGraph API (POST /graph/v1.0/users, id 58110e99-5e92-43f8-a077-9f2ec7f5562e)
  • WebDAV verified: PROPFIND /dav/files/vitya/ returns 200 multistatus с personal space "Vitya" + system space "Shares"
  • Backup integration: /opt/stacks/owncloud добавлен в rsync source list /opt/stacks/backup/scripts/run.sh (между /opt/stacks/backup и /etc/ssh). bash -n syntax OK. Next nightly run 05:00 MSK захватит config + (post-import) data.

Open

  • Import 24.7 GB — pending user-side action. User запускает rclone copy с PC где лежит full копия:

    rclone copy "<src>" :webdav: \
      --webdav-url https://owncloud.kzntsv.site/dav/files/vitya \
      --webdav-vendor owncloud \
      --webdav-user vitya \
      --webdav-pass $(rclone obscure "$(pass show owncloud/user-vitya)") \
      --progress --transfers 4 --checkers 4 --tpslimit 8 \
      --retries 5 --low-level-retries 10 --stats 30s
    

    Resumable. Прогресс мониторится с VDS: ssh vitya@VDS 'du -sh /opt/stacks/owncloud/data/spaces/'.

  • Post-import verify: size match (≈24.7 GB на data/) + spot-check файлов через web UI.

  • Pin image version — сейчас 7.1.0 явно (good). Consider tracking 7.x patch releases — но не auto-update на 8.x без manual verify (breaking config schema changes возможны).

  • API-key rotate? Portainer api-key в vds-kzntsv/full-env оказался invalid (401 "Invalid JWT token"). Не блокирует — admin user/pass работают. Follow-up: regenerate API key через Portainer UI + update pass-store. Отдельная chore-task если нужно.

Notes

  • Architecture: request flow → DNS owncloud.kzntsv.site → 89.253.255.94 → ufw 80/443 → traefik websecure → owncloud (172.18.0.14:9200) → decomposedfs storage в /var/lib/ocis mount → host /opt/stacks/owncloud/data/.
  • Storage layout: oCIS использует decomposedfs — каждый файл = node с metadata. Spaces (personal + Shares) живут в data/spaces/<space-uuid>/. Backup-friendly: plain files на диске, не block storage.
  • Atomic revert:
    ssh vitya@89.253.255.94 'cd /opt/stacks/owncloud && docker compose down -v && cd .. && rm -rf owncloud'
    # + remove /opt/stacks/owncloud line из run.sh
    # + pass rm owncloud/admin-password owncloud/user-vitya && pass git push
    
  • No external DB — oCIS использует internal KV-store (data/storage-users/, data/idm/) для metadata. Postgres/MariaDB на VDS не задействованы. Это снимает зависимость от shared-dbs network — owncloud только в proxy.