From 5b42dc250518f8f162099b33540761586620a9cf Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Mon, 12 Oct 2026 11:28:51 +0700 Subject: [PATCH] chore: remove code-server-lsio, collabora, onlyoffice and seafile Drop the four service directories and their rows from the root index, and replace code-server-lsio in the naming, workspace and environment rules with a generic example. --- .claude/rules/environment-and-secrets.md | 2 +- .claude/rules/naming.md | 14 ++-- .claude/rules/workspace-services.md | 4 +- README.md | 4 - code-server-lsio/.env.example | 18 ----- code-server-lsio/Dockerfile | 4 - code-server-lsio/README.md | 87 --------------------- code-server-lsio/compose.yml | 28 ------- collabora/.env.example | 18 ----- collabora/README.md | 82 -------------------- collabora/compose.yml | 11 --- onlyoffice/.env.example | 10 --- onlyoffice/README.md | 60 --------------- onlyoffice/compose.yml | 24 ------ seafile/.env.example | 21 ----- seafile/README.md | 98 ------------------------ seafile/compose.yml | 93 ---------------------- 17 files changed, 10 insertions(+), 568 deletions(-) delete mode 100644 code-server-lsio/.env.example delete mode 100644 code-server-lsio/Dockerfile delete mode 100644 code-server-lsio/README.md delete mode 100644 code-server-lsio/compose.yml delete mode 100644 collabora/.env.example delete mode 100644 collabora/README.md delete mode 100644 collabora/compose.yml delete mode 100644 onlyoffice/.env.example delete mode 100644 onlyoffice/README.md delete mode 100644 onlyoffice/compose.yml delete mode 100644 seafile/.env.example delete mode 100644 seafile/README.md delete mode 100644 seafile/compose.yml diff --git a/.claude/rules/environment-and-secrets.md b/.claude/rules/environment-and-secrets.md index 3873738..e9e0b4b 100644 --- a/.claude/rules/environment-and-secrets.md +++ b/.claude/rules/environment-and-secrets.md @@ -52,7 +52,7 @@ Compose interpolation reads the deploying shell's environment before the `.env` file, so a variable must not share a name with anything the shell already exports. `HOSTNAME` is the trap: it is set inside every container, including the one Coolify itself runs in, and would silently win. Hence -`SERVICE_HOSTNAME` in `code-server`, `code-server-lsio` and `paseo`. +`SERVICE_HOSTNAME` in `code-server` and `paseo`. A value stored in the Coolify app's environment, including its preview copy, beats the `${VAR:-default}` default in `compose.yml`. Changing a default in the diff --git a/.claude/rules/naming.md b/.claude/rules/naming.md index 9664e9f..9587a50 100644 --- a/.claude/rules/naming.md +++ b/.claude/rules/naming.md @@ -9,7 +9,7 @@ shorter one. Not `docker-compose.yml`. A service directory is named after the software it runs. When two services package the same software, the one that is not upstream's own image takes a -suffix naming its source — `code-server-lsio` for LinuxServer's code-server — +suffix naming its source — `-lsio` for a LinuxServer image — so both can coexist. The suffix is a directory name only, forced by the conflict; it is not a name to copy anywhere else. @@ -19,12 +19,12 @@ is a starting point, not a spec: adapt it to the conventions in these rules rather than copying its layout and names as they are. Inside `compose.yml`, the main service is named after its image — -`code-server`, not `code-server-lsio`. The exception is an image whose name -is not a good identifier on its own — too generic, or longer than it needs to -be. Use a short name that still says which software it is: `owncloud` for -`owncloud/server`, since `server` alone could be anything; `traffmonetizer` -for `traffmonetizer/cli_v2`; `hermes` for `nousresearch/hermes-agent`. A -supporting container is named for its +`code-server` for any code-server image, never a suffixed directory name. The +exception is an image whose name is not a good identifier on its own — too +generic, or longer than it needs to be. Use a short name that still says +which software it is: `owncloud` for `owncloud/server`, since `server` alone +could be anything; `traffmonetizer` for `traffmonetizer/cli_v2`; `hermes` +for `nousresearch/hermes-agent`. A supporting container is named for its role, so the software behind it can be swapped without renaming: `db` for any database, `cache` for Redis, Valkey or Memcached, and a short role name such as `dockerproxy` for anything else (see the examples below). Swapping Redis for diff --git a/.claude/rules/workspace-services.md b/.claude/rules/workspace-services.md index b105df4..3b41948 100644 --- a/.claude/rules/workspace-services.md +++ b/.claude/rules/workspace-services.md @@ -6,7 +6,7 @@ directory, one mounted at `/workspace`. The home volume holds settings, credentials and CLI logins; `/workspace` holds the code. Point whatever variable selects the working directory at `/workspace`. -`code-server`, `code-server-lsio`, `paseo` and `webtop` all follow this. A service with no +`code-server`, `paseo` and `webtop` all follow this. A service with no human inside it does not — an agent such as `hermes` or `openclaw` keeps the volume layout of its official Docker guide. @@ -16,5 +16,5 @@ your extensions and logins. Check who owns `/workspace` on a fresh volume. Docker creates it `root:root` unless the image ships the directory, and an image that drops to a non-root -user will not be able to write there. `code-server`, `code-server-lsio` and `webtop` need an +user will not be able to write there. `code-server` and `webtop` need an explicit `chown` for this reason; `paseo` does not. diff --git a/README.md b/README.md index 453398e..410a9ae 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,6 @@ Each links to its own README for variables, ports, and storage. | --- | --- | | [alloy](alloy/README.md) | Grafana Alloy shipping host and Docker telemetry to Grafana Cloud | | [code-server](code-server/README.md) | VS Code in the browser from the official image | -| [code-server-lsio](code-server-lsio/README.md) | VS Code in the browser from the LinuxServer image, as a remote dev box | -| [collabora](collabora/README.md) | Collabora Online CODE, an online office suite for WOPI hosts | | [couchbase](couchbase/README.md) | Couchbase Server | | [diun](diun/README.md) | Image-update notifier, reading the Docker API through a read-only proxy | | [gitea](gitea/README.md) | Gitea backed by PostgreSQL | @@ -88,13 +86,11 @@ Each links to its own README for variables, ports, and storage. | [hermes](hermes/README.md) | Hermes Agent with its built-in web dashboard | | [litellm](litellm/README.md) | LiteLLM proxy in front of many LLM providers, with PostgreSQL and Redis | | [nextcloud](nextcloud/README.md) | Nextcloud file sync and share, with PostgreSQL, Redis and a cron container | -| [onlyoffice](onlyoffice/README.md) | ONLYOFFICE Docs Community Edition, an online document editor | | [open-webui](open-webui/README.md) | Open WebUI chat interface for OpenAI-compatible and Ollama providers | | [openclaw](openclaw/README.md) | OpenClaw AI agent gateway, with built-in browser automation | | [opencloud](opencloud/README.md) | OpenCloud file sync and share, single container with built-in identity provider | | [owncloud](owncloud/README.md) | ownCloud file sync and share, with MariaDB and Redis | | [paseo](paseo/README.md) | Paseo coding-agent daemon and web UI | -| [seafile](seafile/README.md) | Seafile CE file sync and share, with MariaDB, Redis and the notification server | | [traffmonetizer](traffmonetizer/README.md) | TraffMonetizer bandwidth-sharing client | | [webtop](webtop/README.md) | Ubuntu XFCE desktop in the browser | diff --git a/code-server-lsio/.env.example b/code-server-lsio/.env.example deleted file mode 100644 index 6738d00..0000000 --- a/code-server-lsio/.env.example +++ /dev/null @@ -1,18 +0,0 @@ -# Copy to .env and fill in. Never commit .env. -# -# cp .env.example .env - -# Container hostname, also passed in as HOST -- the name zsh's prompt shows. -SERVICE_HOSTNAME=code-server-lsio - -# Web UI login password. Required. -# Also used for SUDO_PASSWORD inside the container. -# Generate one with: openssl rand -base64 24 -PASSWORD= - -# Git identity baked into the container (author + committer). -GIT_NAME= -GIT_EMAIL= - -# Name of the installed web app. -# PWA_APPNAME=code-server diff --git a/code-server-lsio/Dockerfile b/code-server-lsio/Dockerfile deleted file mode 100644 index 74aa411..0000000 --- a/code-server-lsio/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM lscr.io/linuxserver/code-server:latest - -# Workspace directory, owned by the container user. -RUN mkdir -p /workspace && chown 1000:1000 /workspace diff --git a/code-server-lsio/README.md b/code-server-lsio/README.md deleted file mode 100644 index 564bad9..0000000 --- a/code-server-lsio/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# code-server-lsio - -[VS Code in the browser](https://github.com/linuxserver/docker-code-server), -from the LinuxServer image, set up as a full remote dev box. - -Comes with Go, Node.js 24, Python 3 and zsh via LinuxServer mods, the -`code-server-npmglobal` mod so `npm install -g` lands under `/config` and persists, -plus `bubblewrap`, `gh`, `git`, `glab`, `unzip` and `zip` through -`INSTALL_PACKAGES`. Git author/committer identity is injected from `.env`. - -## Docker access - -The `universal-docker` mod installs the Docker CLI but no daemon, so the host -socket is bind-mounted at `/var/run/docker.sock` to give it something to talk -to. Containers started from inside are siblings on the host, not children -- -bind mounts in them resolve against host paths, so a path under `/config` will -not exist unless the same path exists on the host. - -The socket is owned by the host's `docker` group. At startup the mod reads the -socket's GID, creates a group with it if none exists and adds `abc` to it, so -`docker` works without `sudo`. Handing a container the -socket is equivalent to giving it root on the host — that is accepted here -because this is a single-user dev box. - -The mount carries `:ro`, which is not a security boundary: it only marks the -socket file read-only, while the Docker API is reached by connecting to the -socket, which a read-only mount does not stop. Full API access, and with it -root on the host, remains. Restricting that would need a socket proxy or a -separate rootless daemon. - -## Environment - -| Variable | Purpose | -| --- | --- | -| `SERVICE_HOSTNAME` | Container hostname, and the name the shell prompt shows. | -| `PASSWORD` | Web UI login, also the in-container sudo password. Required. | -| `GIT_NAME` / `GIT_EMAIL` | Git author and committer identity | -| `PWA_APPNAME` | Optional. Name of the installed web app; defaults to `code-server`. | - -Generate a password with `openssl rand -base64 24`. - -The compose file refuses to start when `PASSWORD` is unset or blank. The image -itself would start anyway and serve code-server with no authentication, on a -container that holds the Docker socket. - -`SERVICE_HOSTNAME` is used twice: as the container's `hostname:` and as the -`HOST` variable inside it. Coolify injects `HOST=0.0.0.0` into every compose -app, and zsh seeds `$HOST` and the `%m`/`%M` prompt escapes from that variable -rather than calling `gethostname()` — so the prompt reads `0`, the first -dot-separated field of `0.0.0.0`. code-server itself never reads `HOST` — it -binds `[::]:8443` — so overriding it only affects the prompt. bash is -unaffected; its `\h` uses the real hostname. - -`PUID`/`PGID` are pinned to `1000` in `compose.yml`; the `Dockerfile` depends -on that (see [Storage](#storage)). - -## Networking - -Listens on `8443`; point the domain at it. - -## Storage - -| Volume | Mount | Holds | -| --- | --- | --- | -| `code-server-config` | `/config` | Home directory: settings, extensions, shell history, CLI logins | -| `code-server-workspace` | `/workspace` | Code you work on | - -`DEFAULT_WORKSPACE` points at `/workspace`. It only chooses the folder -code-server opens; it does not move anything. - -The `Dockerfile` exists only to make `/workspace` writable. The image -hard-codes what it hands to the `abc` user — `init-adduser` takes `/app`, -`/config` and `/defaults`, `init-code-server` takes `/config/workspace` by -literal path — and reads `DEFAULT_WORKSPACE` only to decide which folder to -open. A named volume on `/workspace` is therefore never chowned, comes up -`root:root`, and the editor cannot write a single file into it. - -Creating the directory in the image, owned by `1000:1000`, fixes it without any -runtime step: Docker seeds an empty named volume from the image directory, -ownership included, so `/workspace` arrives owned by `abc`. - -The alternative was a `chown` script in `/custom-cont-init.d`, the image's own -init hook. It was rejected because it needs a bind mount from the repository -into the container, and because the hook silently skips any script that has -lost its executable bit — a read-only workspace with nothing obvious to blame. -Baking `1000:1000` into the image costs the ability to change `PUID` at -runtime, which is free here because `compose.yml` pins it. diff --git a/code-server-lsio/compose.yml b/code-server-lsio/compose.yml deleted file mode 100644 index d6a9279..0000000 --- a/code-server-lsio/compose.yml +++ /dev/null @@ -1,28 +0,0 @@ -services: - code-server: - build: . - restart: unless-stopped - hostname: ${SERVICE_HOSTNAME} - environment: - - PUID=1000 - - PGID=1000 - - PASSWORD=${PASSWORD:?required} - - SUDO_PASSWORD=${PASSWORD} - - 'DOCKER_MODS=linuxserver/mods:universal-package-install|linuxserver/mods:universal-docker|linuxserver/mods:code-server-golang|linuxserver/mods:code-server-nodejs|linuxserver/mods:code-server-npmglobal|linuxserver/mods:code-server-python3|linuxserver/mods:code-server-zsh' - - INSTALL_PACKAGES=bubblewrap|gh|git|glab|unzip|zip - - NODEJS_MOD_VERSION=24 - - TZ=Asia/Ho_Chi_Minh - - DEFAULT_WORKSPACE=/workspace - - GIT_AUTHOR_NAME=${GIT_NAME} - - GIT_AUTHOR_EMAIL=${GIT_EMAIL} - - GIT_COMMITTER_NAME=${GIT_NAME} - - GIT_COMMITTER_EMAIL=${GIT_EMAIL} - - HOST=${SERVICE_HOSTNAME} - # - PWA_APPNAME=${PWA_APPNAME:-code-server} - volumes: - - 'code-server-config:/config' - - 'code-server-workspace:/workspace' - - '/var/run/docker.sock:/var/run/docker.sock:ro' -volumes: - code-server-config: - code-server-workspace: diff --git a/collabora/.env.example b/collabora/.env.example deleted file mode 100644 index 9afaba8..0000000 --- a/collabora/.env.example +++ /dev/null @@ -1,18 +0,0 @@ -# Copy to .env and fill in. Never commit .env. -# -# cp .env.example .env - -# WOPI host allowed to open documents, as scheme://host:port. Further -# comma-separated entries are aliases of the same host. -COLLABORA_ALIASGROUP1=https://cloud.example.com:443 - -# Admin console login, at /browser/dist/admin/admin.html. -# Generate a password with: openssl rand -base64 24 -COLLABORA_ADMIN_USERNAME=admin -COLLABORA_ADMIN_PASSWORD= - -# Public hostname, without scheme. -COLLABORA_SERVER_NAME=office.example.com - -# Spell-check languages loaded at start. -# COLLABORA_DICTIONARIES=de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru diff --git a/collabora/README.md b/collabora/README.md deleted file mode 100644 index 8e3f6df..0000000 --- a/collabora/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# collabora - -[Collabora Online](https://www.collaboraonline.com/code/) Development Edition -(CODE): an online office suite for documents, spreadsheets and presentations. -It holds no files itself; a WOPI host, a file server with Collabora -integration, opens documents in it. - -One container: `collabora`. - -## Setup - -1. Set `COLLABORA_ALIASGROUP1` to the WOPI host's URL, - `COLLABORA_ADMIN_PASSWORD` and `COLLABORA_SERVER_NAME`. -2. Map the domain to port `9980` and deploy. -3. In the WOPI host, set the Collabora server URL to the public `https://` - address of this domain. - -Discovery: `GET /hosting/discovery` returns XML once the server is up. The -image ships its own health check (`coolwsd --probe`, against `/livez`), so the -compose file declares none. - -WebSocket editing sessions go through Traefik's default routing; no extra -labels are needed. - -## Environment - -| Variable | Default | Purpose | -| --- | --- | --- | -| `COLLABORA_ALIASGROUP1` | — | Allowed WOPI host, `scheme://host:port`; later comma-separated entries are aliases of it | -| `COLLABORA_ADMIN_USERNAME` / `COLLABORA_ADMIN_PASSWORD` | `admin` / — | Admin console at `/browser/dist/admin/admin.html` | -| `COLLABORA_SERVER_NAME` | empty | Public hostname; empty derives it from each request | -| `COLLABORA_DICTIONARIES` | optional | Space-separated spell-check languages; upstream's default list when unset | - -`aliasgroup1` is the only access control on document editing: with no group -set, CODE trusts whichever host connects first after each start. Entries are -regular expressions, so `https://.*\.example\.com:443` allows a whole domain. -A second, unrelated WOPI host needs its own `aliasgroup2` line in -`compose.yml`. - -`extra_params` is fixed in `compose.yml`: `--o:ssl.enable=false` serves plain -HTTP on `9980` for Traefik to terminate TLS in front of it, and -`--o:ssl.termination=true` makes CODE build `https://` and `wss://` URLs -anyway. Without it the editor loads over HTTPS but fails on mixed-content -WebSocket URLs. - -The admin password fails fast if unset, because the console is served on the -public domain. - -## Storage - -None. Documents stay on the WOPI host; CODE's jails and cache are rebuilt on -every start. - -## Isolation - -CODE isolates each document process in a jail, choosing the first that works: -a mount namespace, then a chroot built by `coolforkit-caps`, then landlock. - -The compose file adds no capabilities and no `security_opt`. Docker's default -seccomp profile blocks the `unshare` a mount namespace needs, so CODE falls back -to the chroot. `coolforkit-caps` carries file capabilities `CAP_CHOWN`, -`CAP_FOWNER` and `CAP_SYS_CHROOT`, all in Docker's default set, so it works -unprivileged. `MKNOD`, which older CODE images needed, is no longer used. - -The price is speed, not safety: without `CAP_SYS_ADMIN` the `coolmount` helper -cannot bind-mount the system template, so each new jail copies it, and -opening a document takes a little longer. The alternatives cost more: -`cap_add: SYS_ADMIN` grants the container broad host-kernel powers, and -upstream's `cool-seccomp-profile.json`, Docker's default list plus the six -namespace and mount syscalls needed, must exist as a file on the host, which a Coolify compose deploy does -not place there. - -The startup log line `creating usernamespace for mount user failed` is this -fallback, not a fault. Do not set `no-new-privileges`: `coolforkit-caps` gains -its capabilities on exec, and without them CODE drops to the weaker landlock -jail. - -## Image - -`collabora/code:latest` is the only moving tag upstream publishes; releases are -versioned `YY.MM.x`. The container keeps no state, so a new release needs only -a redeploy. diff --git a/collabora/compose.yml b/collabora/compose.yml deleted file mode 100644 index 4bc354e..0000000 --- a/collabora/compose.yml +++ /dev/null @@ -1,11 +0,0 @@ -services: - collabora: - image: collabora/code:latest - restart: unless-stopped - environment: - - aliasgroup1=${COLLABORA_ALIASGROUP1:?required} - - extra_params=--o:ssl.enable=false --o:ssl.termination=true - - username=${COLLABORA_ADMIN_USERNAME:-admin} - - password=${COLLABORA_ADMIN_PASSWORD:?required} - - server_name=${COLLABORA_SERVER_NAME:-} - # - dictionaries=${COLLABORA_DICTIONARIES:-de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru} diff --git a/onlyoffice/.env.example b/onlyoffice/.env.example deleted file mode 100644 index a702d66..0000000 --- a/onlyoffice/.env.example +++ /dev/null @@ -1,10 +0,0 @@ -# Copy to .env and fill in. Never commit .env. -# -# cp .env.example .env - -# Shared secret for signing editor requests; the storage app must use the same. -# Generate one with: openssl rand -hex 32 -JWT_SECRET= - -# Allow downloads from and callbacks to private IP addresses. -# ALLOW_PRIVATE_IP_ADDRESS=false diff --git a/onlyoffice/README.md b/onlyoffice/README.md deleted file mode 100644 index 632d595..0000000 --- a/onlyoffice/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# onlyoffice - -[ONLYOFFICE Docs](https://github.com/ONLYOFFICE/Docker-DocumentServer) -Community Edition: an online editor for documents, spreadsheets and -presentations. It has no file storage or user accounts of its own; a storage -app opens files in it and receives the saved result. - -One container, `onlyoffice`. Map the domain to port `80`. - -## Setup - -1. Set `JWT_SECRET`. -2. Map the domain to port `80` and deploy. Every start regenerates the font - list, so the health check takes a minute or two to pass. -3. Give the storage app the public URL and the same `JWT_SECRET`. - -Health check: `GET /healthcheck`. It answers `200` with `false` when a -dependency is down, so the compose healthcheck matches the body `true` rather -than relying on the status code. - -## Environment - -| Variable | Default | Purpose | -| --- | --- | --- | -| `JWT_SECRET` | — | Secret for signing requests between the editor and the storage app | -| `ALLOW_PRIVATE_IP_ADDRESS` | `false` | Allow fetching files from, and calling back to, private IP addresses | - -`JWT_ENABLED` is fixed to `true`. `JWT_SECRET` fails fast if unset: the image -otherwise generates a random secret on every start, which breaks the storage -app's connection after each redeploy. - -`ALLOW_PRIVATE_IP_ADDRESS` is needed only when the storage app is reached over -a private network, such as a container hostname or a LAN address. The editor -refuses those addresses by default, so leave it off when the storage app uses -a public URL. - -## Storage - -| Volume | Mount | Holds | -| --- | --- | --- | -| `onlyoffice-data` | `/var/www/onlyoffice/Data` | Certificates and generated WOPI keys | -| `onlyoffice-lib` | `/var/lib/onlyoffice` | Document cache and converted files | -| `onlyoffice-logs` | `/var/log/onlyoffice` | Logs | - -Nothing here is the documents themselves; those stay in the storage app. The -volumes keep the cache and keys across redeploys. - -## Images - -`onlyoffice/documentserver:latest`: upstream publishes `X.Y` and `X.Y.Z` tags -but no major tag. Back up the volumes before a pull that crosses a major. - -The 9.x images up to 9.4 still run PostgreSQL, RabbitMQ and Redis inside the -container for the Community Edition, in volumes the image declares itself; -upstream's source has since dropped them from the Community build. Either way -no separate database, broker or cache container is needed, and none of their -connection variables are set. - -`stop_grace_period: 60s` follows upstream's compose, giving the editor time to -save open documents back to the storage app on shutdown. diff --git a/onlyoffice/compose.yml b/onlyoffice/compose.yml deleted file mode 100644 index afba3e7..0000000 --- a/onlyoffice/compose.yml +++ /dev/null @@ -1,24 +0,0 @@ -services: - onlyoffice: - image: onlyoffice/documentserver:latest - restart: unless-stopped - stop_grace_period: 60s - environment: - - JWT_ENABLED=true - - JWT_SECRET=${JWT_SECRET:?required} - # - ALLOW_PRIVATE_IP_ADDRESS=${ALLOW_PRIVATE_IP_ADDRESS:-false} - volumes: - - onlyoffice-data:/var/www/onlyoffice/Data - - onlyoffice-lib:/var/lib/onlyoffice - - onlyoffice-logs:/var/log/onlyoffice - healthcheck: - test: ["CMD-SHELL", "curl -fsS http://localhost/healthcheck | grep -qx true"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 120s - -volumes: - onlyoffice-data: - onlyoffice-lib: - onlyoffice-logs: diff --git a/seafile/.env.example b/seafile/.env.example deleted file mode 100644 index bab02d4..0000000 --- a/seafile/.env.example +++ /dev/null @@ -1,21 +0,0 @@ -# Copy to .env and fill in. Never commit .env. -# -# cp .env.example .env - -# Public hostname, without scheme. -SEAFILE_SERVER_HOSTNAME=seafile.example.com - -# Shared secret between Seafile and the notification server, 32+ characters. -# Generate one with: openssl rand -hex 32 -JWT_PRIVATE_KEY= - -# Admin account, created on first start only. -INIT_SEAFILE_ADMIN_EMAIL=admin@example.com -INIT_SEAFILE_ADMIN_PASSWORD= - -# MariaDB passwords. Seafile uses the root password on first start to create -# the seafile user and its three databases. -DB_PASSWORD= -DB_ROOT_PASSWORD= - -TIME_ZONE=Etc/UTC diff --git a/seafile/README.md b/seafile/README.md deleted file mode 100644 index c573762..0000000 --- a/seafile/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# seafile - -[Seafile](https://manual.seafile.com/13.0/) Community Edition 13: file sync -and share with libraries, web, desktop and mobile clients. Based on the -official 13.0 Docker compose, without its bundled Caddy; the platform proxy -terminates TLS. - -Four containers: `seafile` (Seahub web UI and file server), `notification` -(real-time change notifications over WebSocket), `db` (MariaDB) and `cache` -(Redis). - -## Setup - -1. Set `SEAFILE_SERVER_HOSTNAME`, `JWT_PRIVATE_KEY`, `INIT_SEAFILE_ADMIN_EMAIL`, - `INIT_SEAFILE_ADMIN_PASSWORD`, `DB_PASSWORD` and `DB_ROOT_PASSWORD`. -2. Map the domains, both on the same host: - - | Container | Domain | Port | - | --- | --- | --- | - | `seafile` | `https://seafile.example.com` | `80` | - | `notification` | `https://seafile.example.com/notification` | `8083` | - - Keep the app's strip-prefix setting on (the default), so the notification - server receives `/` rather than `/notification`. -3. Deploy. The first start creates the databases and the admin account; log in - with `INIT_SEAFILE_ADMIN_EMAIL` / `INIT_SEAFILE_ADMIN_PASSWORD`. - -Health check: `curl -f http://localhost:80` inside `seafile`, from the official -compose. Its start period is two minutes instead of the official ten seconds: -the first start creates the databases before Seahub answers, and -`notification` waits for `seafile` to be healthy. - -## Environment - -| Variable | Default | Purpose | -| --- | --- | --- | -| `SEAFILE_SERVER_HOSTNAME` | — | Public hostname, without scheme; also builds the notification URL | -| `JWT_PRIVATE_KEY` | — | Shared secret between `seafile` and `notification`, 32+ characters | -| `INIT_SEAFILE_ADMIN_EMAIL` / `INIT_SEAFILE_ADMIN_PASSWORD` | — | Admin account, first start only | -| `DB_PASSWORD` | — | Password of the `seafile` MariaDB user | -| `DB_ROOT_PASSWORD` | — | MariaDB root password, used by the first start to create the user and databases | -| `TIME_ZONE` | `Etc/UTC` | Server time zone | - -`SEAFILE_SERVER_PROTOCOL` is fixed to `https`: TLS ends at the proxy, but the -generated links, CSRF origins and notification URL must use the public scheme. - -The `INIT_*` variables and `DB_ROOT_PASSWORD` take effect only on the first -start. Changing them later does not change the admin account or the database -passwords. - -Logs go to stdout (`SEAFILE_LOG_TO_STDOUT=true`) so they show in the -platform's log view instead of only under `/shared/seafile/logs`. - -## Storage - -| Volume | Mount | Holds | -| --- | --- | --- | -| `seafile-data` | `/shared` | Libraries, config, logs | -| `db-data` | `/var/lib/mysql` | The ccnet, seafile and seahub databases | -| `cache-data` | `/data` | Redis cache | - -`notification` has no volume: it reads its settings from the environment and, -with `SEAFILE_LOG_TO_STDOUT=true`, writes no log file, so the log mount of the -official compose is not needed. - -The `redis` image declares `/data` a volume, so without a named one Docker -creates an anonymous volume on every recreate. - -## Left out - -- **SeaDoc** (`ENABLE_SEADOC=false`). It needs `/sdoc-server/` with the prefix - stripped and `/socket.io/` with it kept, on the same host. The proxy's - strip-prefix setting applies to the whole app, so both cannot be routed at - once. -- **Thumbnail server.** It needs `/thumbnail/` unstripped and - `/thumbnail/ping` rewritten to `/ping`, the same conflict. Without it, Seahub - generates thumbnails itself. -- **SeaSearch, Seafile AI, metadata server.** Not needed for file sync; - SeaSearch publishes no arm64 image. -- **Redis password.** The official compose passes an empty one by default; - Redis is reachable only on the app's internal network. - -## Images - -`seafileltd/seafile-mc:13.0-latest` and -`seafileltd/notification-server:13.0-latest` track the 13.0 line. Seafile -publishes no `:13` tag, `latest` has not moved since 2025, and 14 is still a -testing release. A Seafile major upgrade runs database migrations; back up -both volumes first. - -`mariadb:10.11` is the version the official 13.0 compose pins, and the tag -follows its patch releases. `MARIADB_AUTO_UPGRADE=1` (from the official compose) runs -`mariadb-upgrade` after a minor update. A MariaDB data directory cannot move -back to an older major. - -`redis:8` is the major the official compose's unpinned `redis` resolves to -today; the tag keeps it there instead of following a future major with no -review. Redis holds only cache, so a version change loses nothing. diff --git a/seafile/compose.yml b/seafile/compose.yml deleted file mode 100644 index 58c31d3..0000000 --- a/seafile/compose.yml +++ /dev/null @@ -1,93 +0,0 @@ -services: - seafile: - image: seafileltd/seafile-mc:13.0-latest - restart: unless-stopped - environment: - - SEAFILE_SERVER_HOSTNAME=${SEAFILE_SERVER_HOSTNAME:?required} - - SEAFILE_SERVER_PROTOCOL=https - - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY:?required} - - INIT_SEAFILE_ADMIN_EMAIL=${INIT_SEAFILE_ADMIN_EMAIL:?required} - - INIT_SEAFILE_ADMIN_PASSWORD=${INIT_SEAFILE_ADMIN_PASSWORD:?required} - - SEAFILE_MYSQL_DB_HOST=db - - SEAFILE_MYSQL_DB_PORT=3306 - - SEAFILE_MYSQL_DB_USER=seafile - - SEAFILE_MYSQL_DB_PASSWORD=${DB_PASSWORD:?required} - - INIT_SEAFILE_MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:?required} - - SEAFILE_MYSQL_DB_CCNET_DB_NAME=ccnet_db - - SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=seafile_db - - SEAFILE_MYSQL_DB_SEAHUB_DB_NAME=seahub_db - - CACHE_PROVIDER=redis - - REDIS_HOST=cache - - REDIS_PORT=6379 - - ENABLE_NOTIFICATION_SERVER=true - - INNER_NOTIFICATION_SERVER_URL=http://notification:8083 - - NOTIFICATION_SERVER_URL=https://${SEAFILE_SERVER_HOSTNAME:?required}/notification - - ENABLE_SEADOC=false - - TIME_ZONE=${TIME_ZONE:-Etc/UTC} - - SEAFILE_LOG_TO_STDOUT=true - volumes: - - seafile-data:/shared - depends_on: - db: - condition: service_healthy - cache: - condition: service_healthy - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 2m - - # Notification server: pushes library changes to web and desktop clients over WebSocket. - notification: - image: seafileltd/notification-server:13.0-latest - restart: unless-stopped - environment: - - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY:?required} - - SEAFILE_MYSQL_DB_HOST=db - - SEAFILE_MYSQL_DB_PORT=3306 - - SEAFILE_MYSQL_DB_USER=seafile - - SEAFILE_MYSQL_DB_PASSWORD=${DB_PASSWORD:?required} - - SEAFILE_MYSQL_DB_CCNET_DB_NAME=ccnet_db - - SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=seafile_db - - SEAFILE_LOG_TO_STDOUT=true - depends_on: - db: - condition: service_healthy - seafile: - condition: service_healthy - - # MariaDB for the ccnet, seafile and seahub databases. - db: - image: mariadb:10.11 - restart: unless-stopped - environment: - - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:?required} - - MYSQL_LOG_CONSOLE=true - - MARIADB_AUTO_UPGRADE=1 - volumes: - - db-data:/var/lib/mysql - healthcheck: - test: ["CMD", "healthcheck.sh", "--connect", "--mariadbupgrade", "--innodb_initialized"] - interval: 20s - start_period: 30s - timeout: 5s - retries: 10 - - # Redis for the Seahub cache. - cache: - image: redis:8 - restart: unless-stopped - volumes: - - cache-data:/data - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - -volumes: - seafile-data: - db-data: - cache-data: