OpenCloud: https://cloud.km0digital.com · Web: https://km0.amvara.de · OS: Debian 13 (Trixie)
A developer-oriented overview of the full stack. Read
docs/runbook.mdfor day-to-day operations.
Browser → https://km0.amvara.de → Nginx (km0) → 127.0.0.1:9180 (web corporativa)
Browser → https://cloud.km0digital.com → Nginx (opencloud) → 127.0.0.1:9200 (OpenCloud)
Browser → https://collabora.km0digital.com → Nginx (collabora) → 127.0.0.1:9980 (Collabora CODE)
Collabora → https://wopi.km0digital.com → Nginx (wopi) → 127.0.0.1:9300 (WOPI bridge)
OpenCloud path in detail:
Browser
│ HTTPS :443 cloud.km0digital.com (Let's Encrypt)
▼
Nginx (/etc/nginx/sites-available/opencloud)
│ HTTP http://127.0.0.1:9200 (loopback only)
▼
OpenCloud container (opencloudeu/opencloud-rolling:7.0.0, UID 1000:1000)
│ internal gRPC + HTTP on 127.0.0.1 (ports 9140–9300 range, inside container only)
▼
Docker volumes (opencloud_opencloud-data / opencloud_opencloud-config)
UFW enforces: 22, 80, 443 open to the Internet. Port 9200 is loopback-only — not reachable externally. Fail2ban (sshd jail) bans IPs after repeated SSH login failures (see runbook).
/opt/opencloud/ # Git: km0-opencloud (este repo)
├── overrides/opencloud-compose/ # Parches KM0 sobre upstream (no fork)
├── opencloud-compose/ # Clon local upstream (gitignored; ver overrides/)
├── dex/ # OIDC Dex + tema KM0
├── nginx/ # Plantillas → /etc/nginx/
├── host-www/opencloud-auth/ # Plantillas → /var/www/opencloud-auth/
├── scripts/ # Backups y apply-opencloud-compose-overrides.sh
└── docs/
├── runbook.md
└── REPOSITORY.md # Qué se versiona y qué no
| File | Purpose |
|---|---|
/opt/opencloud/opencloud-compose/.env |
Single source of truth for deployment variables. chmod 600. |
/etc/nginx/sites-available/opencloud |
Active Nginx vhost (TLS termination + reverse proxy). |
/etc/nginx/sites-available/km0 |
Web corporativa (km0.amvara.de → :9180) |
/etc/letsencrypt/live/km0.amvara.de/ |
Certificado web |
/etc/letsencrypt/live/cloud.km0digital.com/ |
Certificado OpenCloud |
/var/www/certbot |
ACME HTTP-01 webroot for certificate renewal |
/etc/docker/daemon.json |
Docker log rotation policy (json-file, max 10 MB × 3 files). |
/var/lib/docker/volumes/opencloud_opencloud-data/ |
All user data (files, search index, NATS state, IDM database). |
/var/lib/docker/volumes/opencloud_opencloud-config/ |
OpenCloud runtime config (opencloud.yaml with auto-generated secrets). |
La configuración activa está en opencloud-compose/.env (chmod 600, no en Git). Plantilla versionada:
overrides/opencloud-compose/.env.debian-collabora-external-proxy.example (or .env.debian-core-external-proxy.example for core-only)
Tras clonar upstream, copiar la plantilla y rellenar INITIAL_ADMIN_PASSWORD, OIDC y demás. Valores operativos del servidor (IP, contacto ACME, notas de contraseña) van documentados en comentarios del .env local.
COMPOSE_PROJECT_NAME=opencloud fija los volúmenes opencloud_opencloud-data y opencloud_opencloud-config.
All persistent data lives in two Docker volumes on the host:
/var/lib/docker/volumes/
├── opencloud_opencloud-data/_data/
│ ├── idm/ # Internal LDAP directory (idm.boltdb + TLS key pair for LDAP)
│ ├── idp/ # OIDC Identity Provider state
│ ├── nats/ # Embedded NATS JetStream (event bus between microservices)
│ ├── search/ # Full-text search index (Bleve)
│ ├── storage/
│ │ ├── metadata/ # CS3 metadata (shares, spaces, locks)
│ │ ├── ocm/ # Open Cloud Mesh federation data
│ │ └── users/ # Actual user files (one directory per user UUID)
│ │ └── users/<user-uuid>/
│ │ └── .oc-nodes/ # File nodes (decomposed storage driver)
│ └── web/ # Static web assets cache
└── opencloud_opencloud-config/_data/
├── opencloud.yaml # Auto-generated runtime config (secrets, service UUIDs)
├── csp.yaml # Content Security Policy overrides
└── banned-password-list.txt
User files are stored using the Decomposed Storage driver: each file is stored as a node (blob) referenced by UUID under storage/users/users/<user-uuid>/.oc-nodes/. There is no traditional directory tree on disk; the logical structure is reconstructed from metadata.
OpenCloud does not encrypt data at rest by default in the core deployment. Files are stored as plain blobs in the Docker volume. Options to add encryption:
- Disk-level: encrypt the host volume (
dm-crypt/LUKS) before Docker mounts it — transparent to OpenCloud. - Object storage: use S3 with server-side encryption (SSE-S3 or SSE-KMS) by adding the
storage/decomposeds3.ymloverlay. - Client-side: OpenCloud supports end-to-end encryption via the desktop/mobile clients (keys never leave the client).
Data in transit is encrypted:
- Browser → Nginx: TLS 1.2/1.3 (Let's Encrypt).
- Nginx → OpenCloud: plain HTTP on loopback (
127.0.0.1:9200). This is safe because it never leaves the host and is a standard pattern for reverse-proxied services. - Internal microservices (within the container): communicate over
127.0.0.1gRPC/HTTP. Not exposed outside the container. - IDM ↔ services: LDAP over TLS using the auto-generated cert pair in
idm/ldap.{crt,key}.
Nginx (host) OpenCloud container
─────────────────────────────────────────────────────
listen 443 ssl PROXY_HTTP_ADDR=0.0.0.0:9200
│ │
│ proxy_pass │ docker port mapping:
└──► http://127.0.0.1:9200 ──► 127.0.0.1:9200 → container:9200
▲ loopback only
Key Nginx directives and why they matter:
| Directive | Value | Reason |
|---|---|---|
proxy_buffering off |
off | Required for SSE (Server-Sent Events used by OpenCloud's real-time updates) |
proxy_request_buffering off |
off | Required for TUS resumable uploads (data must stream, not buffer) |
proxy_pass |
http://127.0.0.1:9200 |
Plain HTTP on loopback; TLS is terminated at Nginx |
X-Forwarded-Proto: $scheme |
https | Tells OpenCloud the client used HTTPS, so it generates correct redirect URLs |
Upgrade / Connection |
passthrough | Required for WebSocket connections (used by the web UI) |
proxy_read_timeout / proxy_send_timeout |
3600s | Long-running uploads and sync sessions |
client_max_body_size |
10G | Maximum single upload size |
http2 on |
on | HTTP/2 multiplexing (nginx ≥ 1.25 syntax; this server runs 1.26.3) |
PROXY_TLS=false in the container environment tells OpenCloud's internal proxy service that the external Nginx handles TLS — so OpenCloud does not attempt to wrap its own HTTP listener in TLS.
| Port | Listener | Accessible from | Purpose |
|---|---|---|---|
| 22 | host (sshd) |
Internet (UFW allow) | SSH admin access |
| 80 | host (nginx) |
Internet (UFW allow) | HTTP → HTTPS redirect only |
| 443 | host (nginx) |
Internet (UFW allow) | HTTPS — TLS termination + reverse proxy |
| 9200 | host → container | 127.0.0.1 only |
OpenCloud HTTP proxy service |
| 9980 | host → container | 127.0.0.1 only |
Collabora Online CODE (when enabled) |
| 9300 | host → container | 127.0.0.1 only |
WOPI collaboration service (when enabled) |
| 9140–9300 | container internal | Inside container only | OpenCloud microservices (gRPC + HTTP) |
# Status
cd /opt/opencloud/opencloud-compose
docker compose ps
# Logs (live)
docker compose logs -f opencloud
# Logs (errors only)
docker compose logs opencloud | grep '"level":"error"'
# Restart
docker compose restart opencloud
# Full stop / start
docker compose down
docker compose up -d
# Update image
docker compose pull && docker compose up -d
# Update upstream compose + re-apply KM0 overrides
git -C /opt/opencloud/opencloud-compose pull
/opt/opencloud/scripts/apply-opencloud-compose-overrides.sh
# Check open ports
ss -tulpn | grep -E ':22|:80|:443|:9200'
# Firewall status
ufw status verboseAutomated workflow for GitHub issues and task files under autoagents/. Uses cursor-agent (no Ollama).
cp autoagents/.env.example autoagents/.env # optional: GH_TOKEN
./scripts/setup-autoagents-gh.sh # authenticate gh as Luipy56
./autoagents/autoagents-loop.sh 001 # single step
./autoagents/autoagents-loop.sh # full loopSee docs/agent-loop.md and .cursor/skills/autoagents/SKILL.md.
- Web: https://km0.amvara.de (Nginx
km0→ puerto 9180) - OpenCloud: https://cloud.km0digital.com (Nginx
opencloud→ puerto 9200) - Collabora: https://collabora.km0digital.com (Nginx
collabora→ puerto 9980) - WOPI: https://wopi.km0digital.com (Nginx
wopi→ puerto 9300) - TLS: Let's Encrypt en ambos hostnames (
certbot.timer; contacto ACME en comentarios deopencloud-compose/.env). INSECURE=false: OpenCloud valida TLS en URLs públicas (OIDC requierehttps://enOC_URL).- Admin password:
INITIAL_ADMIN_PASSWORDen.envsolo en el primer arranque; después, UI (ver runbook). - Backups:
scripts/backup-volumes.shoscripts/backup-opencloud-installation.sh.
Repositorio Git: docs/REPOSITORY.md · Operaciones: docs/runbook.md.