diff --git a/AI.md b/AI.md index 94eff98..e972c0a 100644 --- a/AI.md +++ b/AI.md @@ -1,310 +1,697 @@ -# OpenCloud All-in-One Docker Container +# CasjaysDev Docker Application Image Specification (casjaysdevdocker) -## Overview +**Name**: {name} -This is a comprehensive all-in-one Docker container for OpenCloud, a Go-based file sync and share platform (successor to ownCloud). The container includes all integrated services required for a full-featured deployment. +**About this file:** This is the complete, authoritative specification for a CasjaysDev +Docker **application image** repository (`casjaysdevdocker/{name}`). It is a master +template — copied into an app image repo as that repo's `AI.md`. It is **permanent** — +never delete it from a repo that carries it. -## Included Services +**Note:** `{name}` in this file is a reference token, not setup-time replacement text. Its +value is always the repo directory basename (`basename "$PWD"`). -| Service | Port | Purpose | -|---------|------|---------| -| ClamAV | Socket | Antivirus scanning for uploaded files | -| Apache Tika | 9998 | Full-text search and document extraction | -| Radicale | 5232 | CalDAV/CardDAV for Calendar and Contacts | -| Collabora CODE | 9980 | Document collaboration (LibreOffice Online) | -| OpenCloud | 9200 | Core file sync/share platform | -| Nginx | 80 | Reverse proxy (external-facing) | +**Maintenance procedure:** The bootstrap/update runbook (regenerating files after upstream +template changes, creating new repos) is NOT in this file — it lives in the +`dockersrc-bootstrap` agent (it handles both repo families via `REPO_TYPE` detection). +This file defines the standards that procedure enforces. -## Architecture +--- + +# PART INDEX + +| PART | Title | +|------|-------| +| 0 | Critical rules | +| 1 | Repository model & structure | +| 2 | Template system reference | +| 3 | Tooling — gen-dockerfile & gen-script | +| 4 | `.env.scripts` reference | +| 5 | Runtime system — setup scripts, entrypoint, init.d | +| 6 | README.md standard layout | +| 7 | CI/CD workflows | +| 8 | Verification & commit | + +--- + +# PART 0: CRITICAL RULES + +## Org mapping + +| System | Org | Example | +|--------|-----|---------| +| GitHub (source) | `casjaysdevdocker` | `https://github.com/casjaysdevdocker/{name}` | +| Docker Hub (push) | `casjaysdevdocker` | `casjaysdevdocker/{name}` | + +`casjaysdevdocker` repos are **applications** (gitea, opengist, super-productivity, +ampache, aria2, …). They always build FROM the pre-built, multi-arch `casjaysdev/*` base +images — never directly from upstream distro images. The bases themselves live in the +separate `dockersrc` org (GitHub `dockersrc/{base}` → Docker Hub `casjaysdev/{base}`) — +see the base specification (`DOCKERSRC.md`). + +## Non-negotiable rules + +1. **`AI.md` is permanent** — never delete it from the repo. +2. **Generated files are owned by the template system** — never hand-tune content that + `gen-dockerfile` regenerates (see PART 1 ownership table); fix the upstream + `gen-dockerfile` template instead, then regenerate. +3. **Hand-crafted files are owned by the repo** — `gen-dockerfile` must never overwrite + app-specific init.d scripts, custom bin scripts, a `05-custom.sh` with real content, or + a hand-crafted README (PART 6). +4. **Removed OCI labels stay removed** (PART 2) — never re-add `base.name`, + `schema-version`, or duplicate `authors`/`source` entries. +5. **`image.url` is a browsable page** — `https://hub.docker.com/r/casjaysdevdocker/{name}`. + `docker.io` is only a registry pull host; it is never a label URL. +6. **`image.source` and `image.documentation` are the GitHub repo** — + `https://github.com/casjaysdevdocker/{name}`. +7. **One Dockerfile, one file set** — app repos build one image (`latest` + date tag); + version variants (`Dockerfile.{ver}`) belong to base repos only. +8. **Always `FROM casjaysdev/`** — never pull an upstream distro image directly; + the base repos exist so every app shares one patched, multi-arch foundation. +9. **Only `root/`, `tmp/`, and `usr/` may exist at `rootfs/` top level** (PART 1). +10. **Maintenance runs through the `dockersrc-bootstrap` agent** — do not improvise the + update procedure from memory. + +--- + +# PART 1: REPOSITORY MODEL & STRUCTURE + +## What an app image repo is + +A `casjaysdevdocker/{name}` repo containerizes one application on top of a +`casjaysdev/*` base. It publishes a single image (`casjaysdevdocker/{name}:latest` plus a +date tag) — no per-version Dockerfile variants. The application itself is installed in +`05-custom.sh` and started by one or more init.d service scripts. + +## Standard tree ``` - +------------------+ - | Nginx | - | (Port 80) | - +--------+---------+ - | - +--------------------+--------------------+ - | | | | | - +----v----+ +---v---+ +---v---+ +---v---+ +---v---+ - |OpenCloud| |Collabora| |Radicale| | Tika | |ClamAV | - | (9200) | | (9980) | | (5232) | |(9998)| |(sock) | - +---------+ +---------+ +--------+ +------+ +-------+ +{name}/ +├── AI.md # This specification (permanent) +├── Dockerfile # [generated] single build file +├── .dockerignore # [generated] +├── .env.scripts # [generated] build config +├── .gitattributes # [generated] +├── .gitea/workflows/ +│ └── build.yml # [generated] gen-dockerfile actions +├── .gitignore # [generated] +├── LICENSE.md # License (WTFPL / app's own license) +├── README.md # [generated*] standard layout (PART 6) +└── rootfs/ # Container filesystem overlay + ├── root/docker/setup/ # [generated*] build-time setup scripts 00–07 + ├── tmp/ # staged files installed at build time (optional) + └── usr/local/ + ├── bin/ # [generated*] entrypoint.sh, pkmgr, symlink, copy, + │ # healthcheck + [hand-crafted] app-specific scripts + └── etc/docker/ + ├── env/ # [hand-crafted] build/runtime env fragments (optional) + ├── functions/ + │ └── entrypoint.sh # [generated] entrypoint function library + └── init.d/ # [hand-crafted] runtime init scripts (one per service) ``` -## Service Startup Order +`[generated]` — safe to regenerate; local edits will be lost. +`[generated*]` — regenerated from the template, EXCEPT files carrying repo-specific +content (`05-custom.sh` with a real body, extra bin scripts, a hand-crafted README) — +those follow the hand-crafted rules in PARTs 5 and 6. +`[hand-crafted]` — never overwritten by the template system. -Services start in this order to ensure dependencies are available: +App repos may additionally carry project files (`IDEA.md`, `CLAUDE.md`, `TODO.AI.md`) +per the global project conventions — they are repo-owned and never touched by tooling. -1. **01-clamav.sh** - Antivirus daemon (other services depend on scanning) -2. **02-tika.sh** - Search indexing service -3. **03-radicale.sh** - Calendar/Contacts (CalDAV/CardDAV) -4. **04-collabora.sh** - Document collaboration -5. **05-opencloud.sh** - Main OpenCloud server -6. **06-nginx.sh** - Reverse proxy (last, needs all backends) +## rootfs top-level policy -## Environment Variables +The only valid directories at the `rootfs/` root are `root/`, `tmp/`, and `usr/`. +Anything else is a leftover from old patterns. Migration map: -### Domain Configuration +| Old rootfs path | Correct rootfs path | +|-----------------|---------------------| +| `rootfs/etc/{path}` | `rootfs/tmp/etc/{path}` | +| `rootfs/config/{path}` | `rootfs/tmp/etc/{path}` | +| `rootfs/data/{path}` | `rootfs/tmp/var/{path}` | +| `rootfs/var/{path}` | `rootfs/tmp/var/{path}` | +| `rootfs/opt/{path}` | `rootfs/tmp/opt/{path}` | +| `rootfs/share/{path}` | `rootfs/usr/local/share/{path}` | -| Variable | Default | Description | -|----------|---------|-------------| -| `DOMAIN` | `$HOSTNAME` | Primary domain for all services | -| `OC_DOMAIN` | `${DOMAIN:-$HOSTNAME}` | OpenCloud domain (for URL generation) | -| `COLLABORA_SERVER_NAME` | `collabora.${DOMAIN:-$HOSTNAME}` | Collabora server identifier for WOPI | +`rootfs/usr/local/share/template-files/` is retired — the `DEFAULT_TEMPLATE_DIR`, +`DEFAULT_FILE_DIR`, `DEFAULT_DATA_DIR`, and `DEFAULT_CONF_DIR` variables were removed +from the template system; the entrypoint installs staged files from `rootfs/tmp/etc/` +at container start instead. -### URL Structure +## Repo type detection -Services are accessed via subdomains: -- `${DOMAIN}` → OpenCloud (main application) -- `collabora.${DOMAIN}` → Collabora CODE (document editing) -- `radicale.${DOMAIN}` → Radicale (CalDAV/CardDAV) - -### OpenCloud Configuration - -| Variable | Default | Description | -|----------|---------|-------------| -| `ADMIN_PASSWORD` | (auto-generated) | Admin user password | -| `OC_CONFIG_DIR` | `/config/opencloud` | Configuration directory | -| `OC_DATA_DIR` | `/data/opencloud` | Data storage directory | -| `OC_LOG_LEVEL` | `info` | Logging verbosity | -| `OC_INSECURE` | `true` | Allow insecure connections | -| `PROXY_HTTP_ADDR` | `0.0.0.0:9200` | HTTP listen address | -| `PROXY_TLS` | `false` | Disable TLS (behind reverse proxy) | - -### Service Integration - -| Variable | Default | Description | -|----------|---------|-------------| -| `COLLABORATION_WOPI_SRC` | `http://localhost:9980` | Collabora WOPI endpoint | -| `COLLABORATION_APP_ADDR` | `http://localhost:9980` | Collabora app address | -| `SEARCH_EXTRACTOR_TYPE` | `tika` | Search extraction engine | -| `SEARCH_EXTRACTOR_TIKA_TIKA_URL` | `http://localhost:9998` | Tika server URL | -| `ANTIVIRUS_SCANNER_TYPE` | `clamav` | Antivirus scanner type | -| `ANTIVIRUS_CLAMAV_SOCKET` | `/run/clamav/clamd.sock` | ClamAV socket path | - -### User Configuration - -| Variable | Default | Description | -|----------|---------|-------------| -| `OPENCLOUD_USER` | `opencloud` | System user for OpenCloud | -| `OPENCLOUD_UID` | `1000` | User ID | -| `OPENCLOUD_GID` | `1000` | Group ID | - -## Directory Structure - -``` -/config/ -├── opencloud/ # OpenCloud configuration -├── radicale/ # Radicale CalDAV/CardDAV config -├── clamav/ # ClamAV configuration -├── collabora/ # Collabora configuration -└── nginx/ # Nginx reverse proxy config - -/data/ -├── opencloud/ # User files and data -├── radicale/ # Calendar/Contact collections -├── clamav/ # ClamAV data -├── collabora/ # Collabora data -└── logs/ # All service logs - ├── opencloud/ - ├── radicale/ - ├── clamav/ - ├── tika/ - ├── collabora/ - └── nginx/ -``` - -## Usage - -### Basic Run +A repo is an **app** repo when no `Dockerfile.*` variant files exist: ```bash -docker run -d \ - --name opencloud \ - -p 80:80 \ - -v opencloud-config:/config \ - -v opencloud-data:/data \ - casjaysdevdocker/opencloud:latest start +if find . -maxdepth 1 -name 'Dockerfile.*' -type f | grep -q -- .; then + REPO_TYPE="base" +else + REPO_TYPE="app" +fi ``` -### With Custom Admin Password +--- + +# PART 2: TEMPLATE SYSTEM REFERENCE + +Templates ship with `gen-dockerfile`, installed at +`/usr/local/share/CasjaysDev/scripts/templates/dockerfiles/` +(`$CASJAYSDEVDIR/templates/dockerfiles/` in a dev checkout). To inspect what the current +templates produce, generate a fresh reference tree in a temp dir: ```bash -docker run -d \ - --name opencloud \ - -p 80:80 \ - -e ADMIN_PASSWORD=mysecurepassword \ - -v opencloud-config:/config \ - -v opencloud-data:/data \ - casjaysdevdocker/opencloud:latest start +gen-dockerfile /tmp/gen-dockerfile/{org}/{repo} {distro} ``` -### Docker Compose +See `gen-dockerfile --help` for supported distros/types. Keep this PART in sync whenever +the templates change. + +## Template inventory + +The template name selects the base OS family; for an app repo the resulting pull URL is +always the matching `casjaysdev/*` image: + +| Template | Final stage | Init / PID 1 | App pulls FROM | +|----------|-------------|--------------|----------------| +| `alpine.template` | `scratch.template` | tini | `casjaysdev/alpine` | +| `debian.template` | `scratch.template` | tini | `casjaysdev/debian` | +| `ubuntu.template` | `scratch.template` | tini | `casjaysdev/ubuntu` | +| `rhel.template` | `scratch.template` | tini | `casjaysdev/almalinux` | +| `archlinux.template` | `scratch.template` | tini | `casjaysdev/archlinux` (multi-arch manifest) | +| `web.template` | `systemd.template` | `/sbin/init` | `casjaysdev/web` | +| `xorg.template` | `systemd.template` | `/sbin/init` | `casjaysdev/xorg` | + +Default template for app repos is `alpine` unless the application needs systemd, a GUI +stack, or a distro-specific package. + +## Final-stage templates + +`scratch.template` — all non-GUI templates. +- `ENTRYPOINT [ "tini", "-p", "SIGTERM","--", "/usr/local/bin/entrypoint.sh" ]` +- `STOPSIGNAL SIGRTMIN+3` + +`systemd.template` — `web` and `xorg` (systemd is PID 1; tini is redundant). +- `ENTRYPOINT [ "/sbin/init" ]` +- `STOPSIGNAL SIGRTMIN+3` +- No `tini_provider` stage, no `COPY --from=tini_provider` line. + +Both are identical apart from `ENTRYPOINT`. OCI labels, `ENV HOSTNAME`, and +`VOLUME`/`EXPOSE`/`HEALTHCHECK` are the same in both. + +## OCI label standard + +Both final-stage templates emit these labels (no others): + +``` +LABEL maintainer="${GEN_DOCKERFILE_MAINTAINER}" +LABEL org.opencontainers.image.vendor="${GEN_DOCKERFILE_VENDOR:-CasjaysDev}" +LABEL org.opencontainers.image.authors="${GEN_DOCKERFILE_AUTHOR:-CasjaysDev}" +LABEL org.opencontainers.image.licenses="${LICENSE}" +LABEL org.opencontainers.image.title="${IMAGE_NAME}" +LABEL org.opencontainers.image.description="Containerized version of ${IMAGE_NAME}" +LABEL org.opencontainers.image.created="${BUILD_DATE}" +LABEL org.opencontainers.image.version="${BUILD_VERSION}" +LABEL org.opencontainers.image.revision="${GIT_COMMIT}" +LABEL org.opencontainers.image.url="${GEN_DOCKERFILE_HUB_REPO}" +LABEL org.opencontainers.image.source="${GEN_DOCKERFILE_GIT_REPO}" +LABEL org.opencontainers.image.documentation="${GEN_DOCKERFILE_GIT_REPO}" +LABEL org.opencontainers.image.vcs-type="Git" +LABEL com.github.containers.toolbox="false" +``` + +Shell-expanded values (no `\`) are evaluated at template-render time by `gen-dockerfile`. +Dollar-escaped values (`\${...}`) become literal Docker `ARG`/`ENV` references in the +generated `Dockerfile`. + +Resolved values for a `casjaysdevdocker` repo pushing to Docker Hub: + +| Label | Value | +|-------|-------| +| `url` | `https://hub.docker.com/r/casjaysdevdocker/{name}` — browsable Hub page; `gen-dockerfile` derives it from the registry host (`docker.io` → `hub.docker.com/r/`) | +| `source` | `https://github.com/casjaysdevdocker/{name}` | +| `documentation` | `https://github.com/casjaysdevdocker/{name}` | + +Older app repos may still carry `url="https://docker.io/casjaysdevdocker/{name}"` — that +is the stale form; regeneration corrects it. Removed labels (never re-add): +- `org.opencontainers.image.base.name` — belongs on the base image, not this image +- `org.opencontainers.image.schema-version` — non-spec; redundant with `version` +- Any duplicate `authors` or `source` entries + +## HOSTNAME convention + +All templates set `ENV HOSTNAME="casjaysdevdocker-${IMAGE_NAME}"` in every stage that +declares it. The prefix is always `casjaysdevdocker-`, never `casjaysdev-`. + +## `GEN_DOCKERFILE_APP_DIR` and pull URL logic + +`GEN_DOCKERFILE_APP_DIR` is auto-detected by `gen-dockerfile` from the parent directory +of `$PWD` (the org the checkout lives in): + +```bash +GEN_DOCKERFILE_APP_DIR="${GEN_DOCKERFILE_APP_DIR:-$(basename -- "$(dirname -- "$PWD")")}" +``` + +It selects the `GEN_DOCKER_SPECIFY_IMAGE_SOURCE_*` defaults: + +- `casjaysdevdocker/*` repos → `FROM casjaysdev/:latest` (pre-built, multi-arch) +- `dockersrc/*` and all other orgs → `FROM :latest` (upstream official images) + +App repos must resolve to the `casjaysdev/*` branch — a checkout outside +`~/Projects/*/casjaysdevdocker/` needs `GEN_DOCKERFILE_APP_DIR="casjaysdevdocker"` +exported before calling `gen-dockerfile`, or the regenerated Dockerfile silently reverts +to upstream distro pulls (rule 8 violation). + +## Arch Linux apps + +`casjaysdev/archlinux` is a multi-arch manifest (`linux/amd64` + `linux/arm64`), so app +repos use a single `FROM ${PULL_URL}:${DISTRO_VERSION} AS build` — the three-stage +`base-${TARGETARCH}` FROM block belongs to the base repo only. + +## `web.template` / `xorg.template` notes + +`web` apps inherit the systemd + noVNC stack (`SERVICE_PORT="5800"`, +`EXPOSE_PORTS="5800 5900"` defaults); `xorg` apps inherit the systemd + Xorg stack. App +packages go in `ENV_PACKAGES` / `02-packages.sh`, never by editing the template's stack +list. + +## `debian.template` / `ubuntu.template` — RUN continuation + +The first `RUN` block must have `; \` after the `echo` line so +`export DEBIAN_FRONTEND=noninteractive` executes before `apt-get`: + +```dockerfile +RUN set -e; \ + echo "Updating the system"; \ + export DEBIAN_FRONTEND=noninteractive; \ + apt-get update && apt-get upgrade -yy && apt-get dist-upgrade -yy +``` + +Without the `; \` the export is a no-op and `apt-get` may prompt interactively. + +## Template resolution order + +1. `$GEN_DOCKERFILE_CONFIG_DIR/templates/.template` (user override) +2. `/usr/local/share/CasjaysDev/scripts/templates/dockerfiles/.template` + (installed; `$CASJAYSDEVDIR/templates/dockerfiles/` in a dev checkout) + +`template_options.source` is sourced after `__set_variables`, allowing template-specific +variable overrides. + +--- + +# PART 3: TOOLING — gen-dockerfile & gen-script + +## `gen-dockerfile` + +``` +Usage: gen-dockerfile [options] [dir] [template] [repo-name] [git-repo-url] +``` + +| Flag | Meaning | +|------|---------| +| `--update` | Rewrite `.env.scripts` (add/drop vars against the current template) and update ARG/LABEL lines in the `Dockerfile`. Touches no other file. | +| `--nogit` | Do not init or commit a git repo — required inside an existing repo. | +| `--dir PATH` | Operate on / write output to PATH instead of `$PWD`. | +| `--template NAME` | Template to use (`alpine`, `debian`, `ubuntu`, `rhel`, `archlinux`, `scratch`, `web`, `xorg`). Defaults to `alpine`. | +| `--repo NAME` | Registry repo name (image basename). Defaults to the directory name. | +| `--org NAME` | Registry owner / GitHub org (`--user` is an alias). Prefix `git:` or `reg:` to scope to one system; bare value sets both. For app repos both are `casjaysdevdocker`. | +| `--registry URL` | Registry provider URL (e.g. `https://docker.io`). | +| `--tag VERSION` | Image version tag (default `latest`). | +| `--add-tags TAGS` | Comma-separated additional tags (`USE_DATE` = auto date tag). | +| `--distro-name IMG` | Base image pull URL (overrides `ENV_PULL_URL`). | +| `--distro-version T` | Base image tag (overrides `ENV_DISTRO_TAG`). | +| `--startup FILE` | Generate an init.d service script at `rootfs/usr/local/etc/docker/init.d/FILE` via `gen-script other/start-service`. | +| `--dockerfile` | Regenerate the Dockerfile only. | +| `--force` | Overwrite existing files without prompting. | + +Resolution order when a value is not given by a flag: flags → git remote → project dirs → +defaults. + +Special subcommand — `gen-dockerfile actions` writes `.gitea/workflows/build.yml` from +the existing `Dockerfile` (PART 7). App repos have no versioned `build.{ver}.yml` files. + +## `gen-script` + +``` +Usage: gen-script [options] [template] [filename] +``` + +| Flag / env var | Meaning | +|----------------|---------| +| `--dir PATH` | Write the generated file to `PATH/filename`. | +| `-n` / `--name VALUE` | Service name substituted into the template — fills `REPLACE_SERVICE_NAME` in `other/start-service`, pre-populating `SERVICE_NAME=` without a sed step. | +| `GEN_SCRIPT_OVERWRITE="Y"` | Overwrite the output without prompting (default `"A"` = ask). Required when the target exists, even with `GEN_SCRIPT_EDITFILE="N"`. | +| `GEN_SCRIPT_EDITFILE="N"` | Suppress the interactive editor after generation. `-e`/`--no` sets BOTH this AND `GEN_SCRIPT_OVERWRITE="Y"`; the env var alone does not. | +| `other/start-service` | Template path — positional arg 1, slash-joined words, matching the `@@Template` header. | +| `filename` | Output basename — positional arg 2, combined with `--dir`. | + +Other flags: `-k`/`--keep` (never overwrite), `--replace` (new header replaces old), +`-d`/`--desc` (header description), `-p`/`--prev` (copy header metadata from a file). + +--- + +# PART 4: `.env.scripts` REFERENCE + +Generated at the repo root; sourced by `gen-dockerfile` and by CI at build time. App +repos carry exactly one. It is a pure `KEY="value"` file — no logic. + +## Variables + +| Variable | Purpose | +|----------|---------| +| `ENV_DOCKERFILE` | Dockerfile to build (`Dockerfile`) | +| `ENV_REGISTRY_REPO` | Image name in the registry (`{name}`) | +| `ENV_REGISTRY_ORG` | Registry namespace — `casjaysdevdocker` for app repos | +| `ENV_REGISTRY_URL` | Registry base URL (`https://docker.io`) — pull/push host, never a label URL | +| `ENV_REGISTRY_PUSH` | Full push path `org/repo` (`casjaysdevdocker/{name}`) | +| `ENV_ADD_IMAGE_PUSH` | Extra push destinations | +| `ENV_GIT_REPO_URL` | Full Git repo URL — `https://github.com/casjaysdevdocker/{name}`; feeds the `source`/`documentation` labels, so a wrong value here regresses labels on regeneration | +| `ENV_USE_TEMPLATE` | Template name (`alpine`, `debian`, …) — the authoritative record of which base family the app builds on | +| `ENV_PULL_URL` | Base image to pull FROM (`casjaysdev/`) | +| `ENV_DISTRO_TAG` | Tag for the pull image (`latest`) | +| `ENV_IMAGE_TAG` | Default image tag (`latest`) | +| `ENV_ADD_TAGS` | Additional comma-separated tags; `USE_DATE` auto-generates a date tag | +| `ENV_PACKAGES` | Space-separated package list | +| `ENV_VENDOR` / `ENV_AUTHOR` / `ENV_MAINTAINER` | Label metadata | +| `SERVICE_PORT` | Primary exposed port — apps normally set this | +| `EXPOSE_PORTS` | Additional exposed ports | +| `PHP_VERSION` / `NODE_VERSION` / `NODE_MANAGER` | Runtime versions (`system` default) | +| `WWW_ROOT_DIR` | Web root (`/usr/local/share/httpd/default`) | +| `DOCKER_ENTYPOINT_PORTS_WEB` / `DOCKER_ENTYPOINT_PORTS_SRV` | Ports passed to the entrypoint | +| `DOCKER_ENTYPOINT_HEALTH_APPS` / `DOCKER_ENTYPOINT_HEALTH_ENDPOINTS` | Healthcheck targets | + +## Legacy variable auto-migration + +`gen-dockerfile` calls `__migrate_env_script` on every run, renaming old variables: + +| Old name | Current name | +|----------|-------------| +| `ENV_IMAGE_NAME` | `ENV_REGISTRY_REPO` | +| `ENV_IMAGE_PUSH` | `ENV_REGISTRY_PUSH` | +| `ENV_HUB_BASE` | `ENV_REGISTRY_URL` | +| `ENV_ORG_NAME` | `ENV_REGISTRY_ORG` | + +Never use the old names in new files. Retired variables that must not reappear anywhere: +`DEFAULT_TEMPLATE_DIR`, `DEFAULT_FILE_DIR`, `DEFAULT_DATA_DIR`, `DEFAULT_CONF_DIR`. + +--- + +# PART 5: RUNTIME SYSTEM — SETUP SCRIPTS, ENTRYPOINT, INIT.D + +## Build-time setup scripts (`rootfs/root/docker/setup/`) + +Run in order inside the build stage: + +| Script | Role | +|--------|------| +| `00-init.sh` | Initialize base directory structure and environment | +| `01-system.sh` | Repos, locales, timezone, system settings | +| `02-packages.sh` | App-specific packages, package managers, language runtimes | +| `03-files.sh` | Install staged files (`rootfs/tmp/etc/*` → `/etc/*`), permissions, symlinks | +| `04-users.sh` | Create service users/groups | +| `05-custom.sh` | Application install logic — the heart of an app repo | +| `06-post.sh` | Post-install configuration | +| `07-cleanup.sh` | Remove build deps, caches, temp files | + +**`05-custom.sh` ownership:** the upstream template ships an empty stub. An app repo's +`05-custom.sh` carries the application install (download/build, users, default config) — +that content exists only in the repo's git history, never in the template. On +regeneration, keep the existing body and pull forward only boilerplate (version-stamp +header, `set` line, shellcheck-disable line). The same rule applies to any other `0*.sh` +found to contain real logic beyond the stub. + +## Entrypoint flow + +``` +tini → /usr/local/bin/entrypoint.sh +├─ Load /usr/local/etc/docker/functions/entrypoint.sh +├─ Source env: /root/env.sh, /usr/local/etc/docker/env/*.sh, /config/env/*.sh +├─ Seed /config and /data on first run +├─ __start_init_scripts — source every init.d/*.sh in sort order +├─ Handle `healthcheck` command +└─ Execute main application +``` + +`rootfs/usr/local/bin/` generated set: `entrypoint.sh`, `pkmgr`, `symlink`, `copy`, +`healthcheck`. `pkmgr` wraps the native package manager (`apk`, `apt-get`, `dnf`, +`pacman`) behind `pkmgr update|install|remove|clean`. + +## App-specific bin scripts + +Extra scripts in `rootfs/usr/local/bin/` that `gen-dockerfile` does not generate are +repo-owned. Their `@@Template` header governs maintenance: + +- `@@Template : shell/sh` — boilerplate synced from `$TEMPLATE_DIR/scripts/shell/sh`; + `#!/usr/bin/env sh`, `set -e` only (`pipefail` is a bashism — must NOT appear) +- `@@Template : shell/bash` — synced from `shell/bash`; `set -eo pipefail` required +- No `@@Template` header — hand-written; never modified by tooling + +## init.d scripts — critical rules + +**Each service gets its own numbered init.d script. Never merge or remove services.** +`__start_init_scripts` sources every `*.sh` in sort order — multi-process apps have one +script per daemon (e.g. gitea: `05-dockerd.sh`, `08-gitea.sh`, `zz-act_runner.sh`). + +init.d scripts are **regenerated, never patched in place** — old copies may call functions +removed from the current `functions/entrypoint.sh`. Generate fresh via +`gen-script other/start-service` (or `gen-dockerfile --startup`), then restore the +app-specific values. They are `#!/usr/bin/env bash` with `set -eo pipefail`. + +Required variables in every init.d script: + +```bash +SERVICE_NAME="myapp" +EXEC_CMD_BIN='myapp' +EXEC_CMD_ARGS='' +EXEC_PRE_SCRIPT='' +SERVICE_USES_PID='' +IS_WEB_SERVER="no" +IS_DATABASE_SERVICE="no" +USES_DATABASE_SERVICE="no" +DATABASE_SERVICE_TYPE="sqlite" +RUNAS_USER="root" +``` + +Directory variables: + +```bash +DATA_DIR="/data/$SERVICE_NAME" +CONF_DIR="/config/$SERVICE_NAME" +ETC_DIR="/etc/$SERVICE_NAME" +LOG_DIR="/data/logs/$SERVICE_NAME" +TMP_DIR="/tmp/$SERVICE_NAME" +RUN_DIR="/run/$SERVICE_NAME" +ROOT_FILE_PREFIX="/config/secure/auth/root" +USER_FILE_PREFIX="/config/secure/auth/user" +``` + +## Hook functions + +The `start-service` template generates all outer hooks fully implemented — customise via +the matching `*_local()` stub, which each outer hook calls automatically if defined: + +| Outer hook (do not redefine) | Customise via | +|------------------------------|---------------| +| `__run_precopy` | `__run_precopy_local` | +| `__execute_prerun` | `__execute_prerun_local` | +| `__run_pre_execute_checks` | `__run_pre_execute_checks_local` | +| `__update_conf_files` | `__update_conf_files_local` | +| `__pre_execute` | `__pre_execute_local` | +| `__post_execute` | `__post_execute_local` | +| `__pre_message` | `__pre_message_local` | +| `__update_ssl_conf` | `__update_ssl_conf_local` | +| `__create_service_env` | — | +| `__run_start_script` | — | +| `__run_secure_function` | — | + +## PID sentinel guard + +Every init.d script must guard on exactly this sentinel — leading dot, no underscores in +the filename portion; any other form silently skips the guard: + +```bash +if [ ! -f "/run/.start_init_scripts.pid" ]; then + echo "__start_init_scripts function hasn't been Initialized" >&2 + SERVICE_IS_RUNNING="no" + __script_exit 1 +fi +``` + +## Volumes + +- `/config` — persistent configuration +- `/data` — persistent application data + +--- + +# PART 6: README.md STANDARD LAYOUT + +App image layout (`casjaysdevdocker/{name}` → `casjaysdevdocker/{name}`). Substitute +`{name}` and `{port}` (the value of `SERVICE_PORT`); omit all `-p`/`ports:` sections only +in the rare case `SERVICE_PORT` is empty. + +**Hand-crafted README exception:** a repo whose README deliberately diverges from this +layout (full env-var tables, app-specific quick-start flags — e.g. gitea) owns its README. +Update its facts (image name, org, ports, URLs), never rewrite its structure back to the +generated layout. + +````markdown +## 👋 Welcome to {name} 🚀 + +{name} README + + +## Install my system scripts + +```shell + sudo bash -c "$(curl -q -LSsf "https://github.com/systemmgr/installer/raw/main/install.sh")" + sudo systemmgr --config && sudo systemmgr install scripts +``` + +## Automatic install/update + +```shell +dockermgr update {name} +``` + +## Install and run container + +```shell +dockerHome="/srv/$USER/docker/casjaysdevdocker/{name}/latest/volumes" +mkdir -p "$dockerHome" +git clone "https://github.com/dockermgr/{name}" "$HOME/.local/share/CasjaysDev/dockermgr/{name}" +cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/{name}/volumes/." "$dockerHome/" +docker run -d \ +--restart always \ +--privileged \ +--name casjaysdevdocker-{name}-latest \ +--hostname {name} \ +-e TZ=${TIMEZONE:-America/New_York} \ +-v "$dockerHome/data:/data:z" \ +-v "$dockerHome/config:/config:z" \ +-p {port}:{port} \ +casjaysdevdocker/{name}:latest +``` + +## via docker-compose ```yaml -version: '3.8' - services: - opencloud: - image: casjaysdevdocker/opencloud:latest - container_name: opencloud - command: start - ports: - - "80:80" + ProjectName: + image: casjaysdevdocker/{name} + container_name: casjaysdevdocker-{name} environment: - - ADMIN_PASSWORD=changeme - - OC_LOG_LEVEL=info + - TZ=America/New_York + - HOSTNAME={name} volumes: - - opencloud-config:/config - - opencloud-data:/data - restart: unless-stopped - -volumes: - opencloud-config: - opencloud-data: + - "/srv/$USER/docker/casjaysdevdocker/{name}/latest/volumes/data:/data:z" + - "/srv/$USER/docker/casjaysdevdocker/{name}/latest/volumes/config:/config:z" + ports: + - {port}:{port} + restart: always ``` -## Nginx Proxy Configuration +## Get source files -The built-in Nginx proxies requests to all services: +```shell +dockermgr download src casjaysdevdocker/{name} +``` -- `/` → OpenCloud (port 9200) -- `/cool/` → Collabora WebSocket -- `/hosting/discovery` → Collabora discovery -- `/hosting/capabilities` → Collabora capabilities -- `/radicale/` → Radicale CalDAV/CardDAV +OR -## Building +```shell +git clone "https://github.com/casjaysdevdocker/{name}" "$HOME/Projects/github/casjaysdevdocker/{name}" +``` -```bash -# Generate Dockerfile from template -gen-dockerfile +## Build container -# Build for current platform +```shell +cd "$HOME/Projects/github/casjaysdevdocker/{name}" buildx - -# Build for specific platform -buildx --platform linux/amd64 ``` -## Technical Notes +## Authors -### Base Image +🤖 casjay: [Github](https://github.com/casjay) 🤖 +⛵ casjaysdevdocker: [Github](https://github.com/casjaysdevdocker) [Docker](https://hub.docker.com/u/casjaysdevdocker) ⛵ +```` -Uses Debian-based image (not Alpine) because Collabora CODE requires glibc. +--- -### SSL/TLS +# PART 7: CI/CD WORKFLOWS -SSL is disabled by default (`PROXY_TLS=false`) as the container is designed to run behind a reverse proxy that handles TLS termination. +## Generated workflow (`gen-dockerfile actions`) -### ClamAV Virus Definitions +`gen-dockerfile actions` writes `.gitea/workflows/build.yml` from the current +`Dockerfile`. App repos get the single `build.yml` only — no versioned variants. All +actions are SHA-pinned — never tag-pinned. -Virus definitions are downloaded during image build to reduce container startup time. Updates can be performed by restarting the container or running `freshclam` manually. +- **Triggers:** `push` to `main`, monthly schedule, `workflow_dispatch` +- **Registry strategy:** always logs in to the Gitea registry via the auto-provided + `GITEA_TOKEN`; conditionally logs in to Docker Hub when `vars.DOCKER_USERNAME` is set + (`vars.DOCKER_USERNAME` + `secrets.DOCKER_PASSWORD`; `vars.DOCKER_REGISTRY` overrides + the registry, `vars.DOCKER_ORG` the namespace) +- **Platforms:** `linux/amd64,linux/arm64` +- **build-args:** only `BUILD_DATE`, `GIT_COMMIT`, `BUILD_VERSION` +- **Tags pushed:** date tag (`yymm`) + `latest` to both registries +- **Annotations:** mirror the OCI label standard (PART 2), with `url`/`source`/ + `documentation` set to the workflow's repository URL -### Collabora User +## Legacy workflow (`docker.yaml`) -Collabora CODE must run as the `cool` user (not root) for security reasons. +A hand-crafted `.gitea/workflows/docker.yaml` may exist in older repos — reference copy in +the org-level `.github` repo. **Never overwrite it, and never use it as a template for new +work** — it uses tag-pinned actions and retired secret names. All new/updated workflows +come from `gen-dockerfile actions`. -### Admin Password +--- -If `ADMIN_PASSWORD` is not set, a random 16-character password is generated and saved to `/config/secure/auth/root/opencloud_admin_pass`. +# PART 8: VERIFICATION & COMMIT -## Troubleshooting +## Syntax gates -### Check Service Status +Every touched script must pass before commit: ```bash -docker logs opencloud-test 2>&1 | grep -E "completed|Error|Starting" +for f in rootfs/usr/local/bin/*; do + [ -f "$f" ] || continue + case "$(head -1 "$f")" in + *bash*) bash -n "$f" || exit 1 ;; + *sh*) sh -n "$f" || exit 1 ;; + esac +done + +bash -n rootfs/usr/local/etc/docker/functions/entrypoint.sh + +for f in rootfs/root/docker/setup/0*.sh rootfs/usr/local/etc/docker/init.d/*.sh; do + [ -f "$f" ] || continue + bash -n "$f" || exit 1 +done ``` -### Access Container Shell +## Dead-reference gates + +After any regeneration: + +1. No script references an env var removed from `.env.scripts` (diff-driven check). +2. No script calls a function absent from both the current + `functions/entrypoint.sh` and the script itself. +3. No `__copy_templates` calls remain (retired with `DEFAULT_TEMPLATE_DIR`). +4. `Dockerfile` still pulls `FROM casjaysdev/*` (rule 8) — an upstream distro pull means + `GEN_DOCKERFILE_APP_DIR` resolved wrong during regeneration. + +## Commit ```bash -docker exec -it opencloud /bin/bash +git status --porcelain +git diff --stat ``` -### Check Running Processes +Write `.git/COMMIT_MESS` from the actual diff — subject ≤64 chars, body as +`- path: change` bullets covering every changed file. Then: ```bash -docker exec opencloud ps aux +gitcommit --dir "$(git rev-parse --show-toplevel)" all ``` -### View Service Logs - -```bash -# OpenCloud -docker exec opencloud cat /data/logs/opencloud/opencloud.log - -# Nginx -docker exec opencloud cat /data/logs/nginx/access.log - -# Collabora -docker exec opencloud cat /data/logs/collabora/collabora.log -``` - -## Files Structure - -### Setup Scripts (`/root/docker/setup/`) - -- `02-packages.sh` - Base package installation info (actual packages in ENV_PACKAGES) -- `03-files.sh` - Downloads OpenCloud binary, Tika JAR, ClamAV definitions -- `04-users.sh` - Creates opencloud user and group - -### Init Scripts (`/usr/local/etc/docker/init.d/`) - -- `01-clamav.sh` - ClamAV antivirus daemon -- `02-tika.sh` - Apache Tika search service -- `03-radicale.sh` - Radicale CalDAV/CardDAV -- `04-collabora.sh` - Collabora CODE -- `05-opencloud.sh` - OpenCloud server -- `06-nginx.sh` - Nginx reverse proxy - -### Configuration Templates - -- `/usr/local/share/template-files/config/` - Default configurations -- `/etc/radicale/config` - Radicale default config - -## Package List - -Packages installed via `ENV_PACKAGES`: - -- Core: ca-certificates, curl, wget, bash, tini, gnupg, apt-transport-https, tzdata, procps, netcat-openbsd, nginx -- Java: default-jre-headless (for Tika) -- Python: python3, python3-pip, python3-venv (for Radicale) -- Antivirus: clamav, clamav-daemon, clamav-freshclam - -Additional packages installed in `03-files.sh`: -- Collabora: coolwsd, code-brand (from Collabora repository) -- Radicale: installed via pip - -## Version Information - -- OpenCloud: Latest from GitHub releases (auto-detected) -- Apache Tika: 2.9.1 -- Radicale: Latest from pip -- Collabora CODE: Latest from official repository - -## Known Limitations - -1. Single container deployment - not suitable for high-availability setups -2. ClamAV definitions are from build time - consider periodic updates -3. No built-in SSL - requires external reverse proxy for HTTPS -4. Memory intensive due to Java (Tika) and Collabora -5. Collabora CODE may require additional configuration for production use - check `/usr/bin/discovery.xml` - -## Current Service Status - -- **ClamAV**: Working -- **Apache Tika**: Working -- **Radicale**: Working -- **Collabora CODE**: Requires additional configuration (may fail on first run) -- **OpenCloud**: Dependent on Collabora for document editing features -- **Nginx**: Working (serves as reverse proxy) - -## Related Links - -- [OpenCloud GitHub](https://github.com/opencloud-eu/opencloud) -- [Collabora CODE](https://www.collaboraoffice.com/code/) -- [Apache Tika](https://tika.apache.org/) -- [Radicale](https://radicale.org/) -- [ClamAV](https://www.clamav.net/) +`git commit` / `git push` directly are forbidden. Never commit with a failing syntax +gate. diff --git a/IDEA.md b/IDEA.md new file mode 100644 index 0000000..94eff98 --- /dev/null +++ b/IDEA.md @@ -0,0 +1,310 @@ +# OpenCloud All-in-One Docker Container + +## Overview + +This is a comprehensive all-in-one Docker container for OpenCloud, a Go-based file sync and share platform (successor to ownCloud). The container includes all integrated services required for a full-featured deployment. + +## Included Services + +| Service | Port | Purpose | +|---------|------|---------| +| ClamAV | Socket | Antivirus scanning for uploaded files | +| Apache Tika | 9998 | Full-text search and document extraction | +| Radicale | 5232 | CalDAV/CardDAV for Calendar and Contacts | +| Collabora CODE | 9980 | Document collaboration (LibreOffice Online) | +| OpenCloud | 9200 | Core file sync/share platform | +| Nginx | 80 | Reverse proxy (external-facing) | + +## Architecture + +``` + +------------------+ + | Nginx | + | (Port 80) | + +--------+---------+ + | + +--------------------+--------------------+ + | | | | | + +----v----+ +---v---+ +---v---+ +---v---+ +---v---+ + |OpenCloud| |Collabora| |Radicale| | Tika | |ClamAV | + | (9200) | | (9980) | | (5232) | |(9998)| |(sock) | + +---------+ +---------+ +--------+ +------+ +-------+ +``` + +## Service Startup Order + +Services start in this order to ensure dependencies are available: + +1. **01-clamav.sh** - Antivirus daemon (other services depend on scanning) +2. **02-tika.sh** - Search indexing service +3. **03-radicale.sh** - Calendar/Contacts (CalDAV/CardDAV) +4. **04-collabora.sh** - Document collaboration +5. **05-opencloud.sh** - Main OpenCloud server +6. **06-nginx.sh** - Reverse proxy (last, needs all backends) + +## Environment Variables + +### Domain Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `DOMAIN` | `$HOSTNAME` | Primary domain for all services | +| `OC_DOMAIN` | `${DOMAIN:-$HOSTNAME}` | OpenCloud domain (for URL generation) | +| `COLLABORA_SERVER_NAME` | `collabora.${DOMAIN:-$HOSTNAME}` | Collabora server identifier for WOPI | + +### URL Structure + +Services are accessed via subdomains: +- `${DOMAIN}` → OpenCloud (main application) +- `collabora.${DOMAIN}` → Collabora CODE (document editing) +- `radicale.${DOMAIN}` → Radicale (CalDAV/CardDAV) + +### OpenCloud Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `ADMIN_PASSWORD` | (auto-generated) | Admin user password | +| `OC_CONFIG_DIR` | `/config/opencloud` | Configuration directory | +| `OC_DATA_DIR` | `/data/opencloud` | Data storage directory | +| `OC_LOG_LEVEL` | `info` | Logging verbosity | +| `OC_INSECURE` | `true` | Allow insecure connections | +| `PROXY_HTTP_ADDR` | `0.0.0.0:9200` | HTTP listen address | +| `PROXY_TLS` | `false` | Disable TLS (behind reverse proxy) | + +### Service Integration + +| Variable | Default | Description | +|----------|---------|-------------| +| `COLLABORATION_WOPI_SRC` | `http://localhost:9980` | Collabora WOPI endpoint | +| `COLLABORATION_APP_ADDR` | `http://localhost:9980` | Collabora app address | +| `SEARCH_EXTRACTOR_TYPE` | `tika` | Search extraction engine | +| `SEARCH_EXTRACTOR_TIKA_TIKA_URL` | `http://localhost:9998` | Tika server URL | +| `ANTIVIRUS_SCANNER_TYPE` | `clamav` | Antivirus scanner type | +| `ANTIVIRUS_CLAMAV_SOCKET` | `/run/clamav/clamd.sock` | ClamAV socket path | + +### User Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `OPENCLOUD_USER` | `opencloud` | System user for OpenCloud | +| `OPENCLOUD_UID` | `1000` | User ID | +| `OPENCLOUD_GID` | `1000` | Group ID | + +## Directory Structure + +``` +/config/ +├── opencloud/ # OpenCloud configuration +├── radicale/ # Radicale CalDAV/CardDAV config +├── clamav/ # ClamAV configuration +├── collabora/ # Collabora configuration +└── nginx/ # Nginx reverse proxy config + +/data/ +├── opencloud/ # User files and data +├── radicale/ # Calendar/Contact collections +├── clamav/ # ClamAV data +├── collabora/ # Collabora data +└── logs/ # All service logs + ├── opencloud/ + ├── radicale/ + ├── clamav/ + ├── tika/ + ├── collabora/ + └── nginx/ +``` + +## Usage + +### Basic Run + +```bash +docker run -d \ + --name opencloud \ + -p 80:80 \ + -v opencloud-config:/config \ + -v opencloud-data:/data \ + casjaysdevdocker/opencloud:latest start +``` + +### With Custom Admin Password + +```bash +docker run -d \ + --name opencloud \ + -p 80:80 \ + -e ADMIN_PASSWORD=mysecurepassword \ + -v opencloud-config:/config \ + -v opencloud-data:/data \ + casjaysdevdocker/opencloud:latest start +``` + +### Docker Compose + +```yaml +version: '3.8' + +services: + opencloud: + image: casjaysdevdocker/opencloud:latest + container_name: opencloud + command: start + ports: + - "80:80" + environment: + - ADMIN_PASSWORD=changeme + - OC_LOG_LEVEL=info + volumes: + - opencloud-config:/config + - opencloud-data:/data + restart: unless-stopped + +volumes: + opencloud-config: + opencloud-data: +``` + +## Nginx Proxy Configuration + +The built-in Nginx proxies requests to all services: + +- `/` → OpenCloud (port 9200) +- `/cool/` → Collabora WebSocket +- `/hosting/discovery` → Collabora discovery +- `/hosting/capabilities` → Collabora capabilities +- `/radicale/` → Radicale CalDAV/CardDAV + +## Building + +```bash +# Generate Dockerfile from template +gen-dockerfile + +# Build for current platform +buildx + +# Build for specific platform +buildx --platform linux/amd64 +``` + +## Technical Notes + +### Base Image + +Uses Debian-based image (not Alpine) because Collabora CODE requires glibc. + +### SSL/TLS + +SSL is disabled by default (`PROXY_TLS=false`) as the container is designed to run behind a reverse proxy that handles TLS termination. + +### ClamAV Virus Definitions + +Virus definitions are downloaded during image build to reduce container startup time. Updates can be performed by restarting the container or running `freshclam` manually. + +### Collabora User + +Collabora CODE must run as the `cool` user (not root) for security reasons. + +### Admin Password + +If `ADMIN_PASSWORD` is not set, a random 16-character password is generated and saved to `/config/secure/auth/root/opencloud_admin_pass`. + +## Troubleshooting + +### Check Service Status + +```bash +docker logs opencloud-test 2>&1 | grep -E "completed|Error|Starting" +``` + +### Access Container Shell + +```bash +docker exec -it opencloud /bin/bash +``` + +### Check Running Processes + +```bash +docker exec opencloud ps aux +``` + +### View Service Logs + +```bash +# OpenCloud +docker exec opencloud cat /data/logs/opencloud/opencloud.log + +# Nginx +docker exec opencloud cat /data/logs/nginx/access.log + +# Collabora +docker exec opencloud cat /data/logs/collabora/collabora.log +``` + +## Files Structure + +### Setup Scripts (`/root/docker/setup/`) + +- `02-packages.sh` - Base package installation info (actual packages in ENV_PACKAGES) +- `03-files.sh` - Downloads OpenCloud binary, Tika JAR, ClamAV definitions +- `04-users.sh` - Creates opencloud user and group + +### Init Scripts (`/usr/local/etc/docker/init.d/`) + +- `01-clamav.sh` - ClamAV antivirus daemon +- `02-tika.sh` - Apache Tika search service +- `03-radicale.sh` - Radicale CalDAV/CardDAV +- `04-collabora.sh` - Collabora CODE +- `05-opencloud.sh` - OpenCloud server +- `06-nginx.sh` - Nginx reverse proxy + +### Configuration Templates + +- `/usr/local/share/template-files/config/` - Default configurations +- `/etc/radicale/config` - Radicale default config + +## Package List + +Packages installed via `ENV_PACKAGES`: + +- Core: ca-certificates, curl, wget, bash, tini, gnupg, apt-transport-https, tzdata, procps, netcat-openbsd, nginx +- Java: default-jre-headless (for Tika) +- Python: python3, python3-pip, python3-venv (for Radicale) +- Antivirus: clamav, clamav-daemon, clamav-freshclam + +Additional packages installed in `03-files.sh`: +- Collabora: coolwsd, code-brand (from Collabora repository) +- Radicale: installed via pip + +## Version Information + +- OpenCloud: Latest from GitHub releases (auto-detected) +- Apache Tika: 2.9.1 +- Radicale: Latest from pip +- Collabora CODE: Latest from official repository + +## Known Limitations + +1. Single container deployment - not suitable for high-availability setups +2. ClamAV definitions are from build time - consider periodic updates +3. No built-in SSL - requires external reverse proxy for HTTPS +4. Memory intensive due to Java (Tika) and Collabora +5. Collabora CODE may require additional configuration for production use - check `/usr/bin/discovery.xml` + +## Current Service Status + +- **ClamAV**: Working +- **Apache Tika**: Working +- **Radicale**: Working +- **Collabora CODE**: Requires additional configuration (may fail on first run) +- **OpenCloud**: Dependent on Collabora for document editing features +- **Nginx**: Working (serves as reverse proxy) + +## Related Links + +- [OpenCloud GitHub](https://github.com/opencloud-eu/opencloud) +- [Collabora CODE](https://www.collaboraoffice.com/code/) +- [Apache Tika](https://tika.apache.org/) +- [Radicale](https://radicale.org/) +- [ClamAV](https://www.clamav.net/)