mirror of
https://github.com/tiennm99/composes.git
synced 2026-10-12 14:14:52 +00:00
Compare commits
5
Commits
87604a2bd7
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a0a5384ee | ||
|
|
5b42dc2505 | ||
|
|
fedff373fc | ||
|
|
b3861f4c2f | ||
|
|
8b33bd9135 |
No files matched your search
@@ -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
|
||||
|
||||
@@ -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 — `<software>-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
|
||||
|
||||
@@ -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.
|
||||
@@ -4,6 +4,9 @@ Personal docker compose collection. One directory per service, each holding
|
||||
`compose.yml`, its own `README.md`, a committed `.env.example`, and a
|
||||
gitignored `.env`.
|
||||
|
||||
Only common, well-known third-party services belong here. Our own tools
|
||||
ship their compose file in their own repo and deploy from there.
|
||||
|
||||
Topic rules live in `.claude/rules/` and load with this file:
|
||||
|
||||
- `naming.md` — file, directory, service, volume and network names, with
|
||||
|
||||
@@ -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 |
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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:
|
||||
@@ -8,6 +8,17 @@ RUN apt-get update \
|
||||
build-essential bubblewrap unzip zip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Command-line utilities: network and DNS, search and review, lint,
|
||||
# database clients, and backup and maintenance.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
iproute2 lsof bind9-dnsutils netcat-openbsd socat mtr-tiny whois \
|
||||
tree fd-find fzf git-delta bat \
|
||||
shellcheck shfmt yamllint \
|
||||
postgresql-client sqlite3 redis-tools \
|
||||
ncdu tmux restic rclone age hyperfine entr 7zip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Workspace directory, owned by the container user.
|
||||
RUN mkdir -p /workspace && chown 1000:1000 /workspace
|
||||
|
||||
|
||||
+18
-2
@@ -4,8 +4,8 @@
|
||||
official `codercom/code-server` image.
|
||||
|
||||
The image ships code-server on Debian with `git`, `zsh`, `curl`, `sudo` and a
|
||||
few editors. The `Dockerfile` adds `build-essential`, `bubblewrap`, `zip` and
|
||||
`unzip`, and wraps the entrypoint so it starts in `/workspace` and `coder` can
|
||||
few editors. The `Dockerfile` adds `build-essential`, `bubblewrap`, `zip`,
|
||||
`unzip` and a set of command-line utilities, and wraps the entrypoint so it starts in `/workspace` and `coder` can
|
||||
use the Docker socket. Language toolchains and CLIs are installed into home,
|
||||
below.
|
||||
|
||||
@@ -231,6 +231,22 @@ image ships none of them. `build-essential` supplies the `gcc` and `make` that
|
||||
native builds expect: the linker `cargo` calls, node-gyp addons and Python
|
||||
sdists.
|
||||
|
||||
The command-line utilities are Debian packages too, kept in the image as a
|
||||
baseline every fresh deploy has without a setup step:
|
||||
|
||||
| Group | Packages |
|
||||
| --- | --- |
|
||||
| Network and DNS | `iproute2` (`ss`, `ip`), `lsof`, `bind9-dnsutils` (`dig`), `netcat-openbsd` (`nc`), `socat`, `mtr-tiny`, `whois` |
|
||||
| Search and review | `tree`, `fd-find`, `fzf`, `git-delta`, `bat` |
|
||||
| Lint | `shellcheck`, `shfmt`, `yamllint` |
|
||||
| Database clients | `postgresql-client` (`psql`), `sqlite3`, `redis-tools` (`redis-cli`) |
|
||||
| Maintenance | `ncdu`, `tmux`, `restic`, `rclone`, `age`, `hyperfine`, `entr`, `7zip` (`7z`) |
|
||||
|
||||
Debian installs `fd` as `fdfind` and `bat` as `batcat`. They track Debian 13's
|
||||
versions, which lag upstream: `rclone` is 1.60, and `postgresql-client` is 17,
|
||||
whose `pg_dump` refuses to dump a newer server. Install a newer copy into home
|
||||
when one of these falls short.
|
||||
|
||||
Everything else lives in home rather than the image, so the image build stays
|
||||
small and a redeploy does not reinstall or upgrade tools behind your back;
|
||||
upgrading is the same commands run again.
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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}
|
||||
+8
-4
@@ -6,7 +6,7 @@ Self-hosted [Gitea](https://about.gitea.com/) backed by PostgreSQL.
|
||||
|
||||
| Service | Image | Internal port | Domain |
|
||||
| --- | --- | --- | --- |
|
||||
| `db` | `postgres:16-alpine` | 5432 | none |
|
||||
| `db` | `postgres:18-alpine` | 5432 | none |
|
||||
| `gitea` | `gitea/gitea:28` | 3000 | `GITEA_ROOT_URL` |
|
||||
|
||||
In Coolify, give `gitea` a domain on port 3000 matching `GITEA_ROOT_URL`.
|
||||
@@ -35,8 +35,12 @@ itself.
|
||||
this long.
|
||||
- **`gitea/gitea:28`.** Gitea publishes major tags; the major pin takes
|
||||
updates without a surprise major upgrade.
|
||||
- **`postgres:16-alpine`** stays on 16: a new Postgres major cannot read the
|
||||
existing data directory without a dump and restore.
|
||||
- **`postgres:18-alpine`**, the newest Postgres major; Gitea needs 12 or
|
||||
later. The major stays pinned because a new major cannot read an existing
|
||||
data directory without a dump and restore. From 18 the image keeps its data
|
||||
in `/var/lib/postgresql/18/docker`, so `db-data` mounts at
|
||||
`/var/lib/postgresql`, which lets a later major sit beside it on the same
|
||||
volume.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -48,5 +52,5 @@ token for any tool that mirrors into it.
|
||||
|
||||
| Volume | Holds |
|
||||
| --- | --- |
|
||||
| `db-data` | PostgreSQL data |
|
||||
| `db-data` | PostgreSQL data, under `18/docker` |
|
||||
| `gitea-data` | Repositories, Gitea config and state |
|
||||
+2
-2
@@ -1,13 +1,13 @@
|
||||
services:
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
image: postgres:18-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-gitea}
|
||||
POSTGRES_USER: gitea
|
||||
POSTGRES_DB: gitea
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
- db-data:/var/lib/postgresql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U gitea -d gitea"]
|
||||
interval: 5s
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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:
|
||||
+25
-8
@@ -1,6 +1,6 @@
|
||||
# owncloud
|
||||
|
||||
[ownCloud](https://doc.owncloud.com/server/10.16/admin_manual/installation/docker/)
|
||||
[ownCloud](https://doc.owncloud.com/server/11.0/admin_manual/installation/installing_with_docker.html)
|
||||
Server: file sync and share, with web, desktop and mobile clients.
|
||||
|
||||
Three containers: `owncloud`, `db` (MariaDB) for metadata, users and shares, and
|
||||
@@ -15,7 +15,11 @@ Three containers: `owncloud`, `db` (MariaDB) for metadata, users and shares, and
|
||||
3. Log in with `OWNCLOUD_ADMIN_USERNAME` / `OWNCLOUD_ADMIN_PASSWORD`.
|
||||
|
||||
Health check: `/usr/bin/healthcheck`, the image's own script, also the compose
|
||||
healthcheck.
|
||||
healthcheck. It requests `/status.php` on port `8080`.
|
||||
|
||||
Every start runs `occ upgrade` when `config.php` on `owncloud-data` says
|
||||
ownCloud is installed, and a fresh install otherwise. A new image version is
|
||||
therefore migrated on the next deploy, against whatever database `db` holds.
|
||||
|
||||
## Environment
|
||||
|
||||
@@ -29,6 +33,10 @@ healthcheck.
|
||||
`OWNCLOUD_DOMAIN` also fills `OWNCLOUD_TRUSTED_DOMAINS`; ownCloud rejects
|
||||
requests for any host not on that list.
|
||||
|
||||
TLS ends at the proxy, so ownCloud sees plain HTTP. `OWNCLOUD_OVERWRITE_PROTOCOL`
|
||||
makes the URLs it generates `https`, and `OWNCLOUD_PROTOCOL` does the same for
|
||||
the URL `occ` and cron jobs use in links.
|
||||
|
||||
The admin variables are read only by the first-start install. Changing them
|
||||
later does not change the account; use the web UI or `occ user:resetpassword`.
|
||||
|
||||
@@ -50,10 +58,19 @@ named one Docker creates an anonymous volume on every recreate.
|
||||
|
||||
## Images
|
||||
|
||||
`owncloud/server:10` tracks the 10.x line. `latest` points at the same
|
||||
release today, but ownCloud now also publishes 11.x, and a move to a new major
|
||||
should be a deliberate upgrade with a backup, not a side effect of a pull.
|
||||
`owncloud/server:11` tracks the 11.x line, so patch releases arrive on the next
|
||||
deploy and a move to a new major stays a deliberate upgrade. ownCloud's own
|
||||
compose pins a full version instead.
|
||||
|
||||
`mariadb:12` and `redis:6` track their major versions. A MariaDB data
|
||||
directory cannot move back to an older major, so back up the database volume
|
||||
before changing it.
|
||||
`mariadb:10.11` is the release ownCloud 11's compose uses and the top of the
|
||||
MariaDB range ownCloud supports (10.2 to 10.11); a newer major is outside it.
|
||||
`MARIADB_AUTO_UPGRADE=1`, also from ownCloud's compose, runs `mariadb-upgrade`
|
||||
when the server version changes. A MariaDB data directory cannot move back to
|
||||
an older major, so going down a version means a dump and restore into an empty
|
||||
volume, not an image change. Back up `db-data` before changing the tag.
|
||||
|
||||
`redis:7` is the version ownCloud's compose uses.
|
||||
|
||||
ownCloud 11 runs on PHP 8. Apps installed into `/mnt/data/apps` from the
|
||||
marketplace under 10.x were built for PHP 7, so they are removed or replaced
|
||||
with PHP 8 versions before moving a 10.x install to 11.
|
||||
@@ -1,10 +1,12 @@
|
||||
services:
|
||||
owncloud:
|
||||
image: owncloud/server:10
|
||||
image: owncloud/server:11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- OWNCLOUD_DOMAIN=${OWNCLOUD_DOMAIN:?required}
|
||||
- OWNCLOUD_TRUSTED_DOMAINS=${OWNCLOUD_DOMAIN:?required}
|
||||
- OWNCLOUD_PROTOCOL=https
|
||||
- OWNCLOUD_OVERWRITE_PROTOCOL=https
|
||||
- OWNCLOUD_ADMIN_USERNAME=${OWNCLOUD_ADMIN_USERNAME:-admin}
|
||||
- OWNCLOUD_ADMIN_PASSWORD=${OWNCLOUD_ADMIN_PASSWORD:?required}
|
||||
- OWNCLOUD_DB_TYPE=mysql
|
||||
@@ -30,7 +32,7 @@ services:
|
||||
|
||||
# MariaDB for file metadata, users and shares.
|
||||
db:
|
||||
image: mariadb:12
|
||||
image: mariadb:10.11
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- --character-set-server=utf8mb4
|
||||
@@ -42,6 +44,7 @@ services:
|
||||
- MYSQL_DATABASE=${DB_NAME:-owncloud}
|
||||
- MYSQL_USER=${DB_USER:-owncloud}
|
||||
- MYSQL_PASSWORD=${DB_PASSWORD:?required}
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
volumes:
|
||||
- db-data:/var/lib/mysql
|
||||
healthcheck:
|
||||
@@ -52,7 +55,7 @@ services:
|
||||
|
||||
# Redis for file locking and the distributed cache.
|
||||
cache:
|
||||
image: redis:6
|
||||
image: redis:7
|
||||
restart: unless-stopped
|
||||
command: ["--databases", "1"]
|
||||
volumes:
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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:
|
||||
Reference in new issue
Block a user