Files
computer-playbook/roles/web-app-nextcloud/meta/services.yml
kevinveenbirkenbachandClaude Opus 5.5 b17807faa3 fix(web-app-nextcloud): probe the Context Agent without curl
Context Agent 2.10.0 (bumped in #1219) moved to a multi-stage image whose
runtime stage ships no curl ("no vim, no git, no curl, no pipx/poetry",
nextcloud/context_agent Dockerfile at v2.10.0). The curl healthcheck then
fails with `exec: "curl": executable file not found in $PATH`, the task
never leaves `starting`, and the swarm converge wait gives up on
nextcloud_context_agent (main run 40401200083, Nextcloud#2).

Switch to the http_status flavor, which speaks HTTP over bash's
/dev/tcp and still requires a 2xx/3xx answer from /heartbeat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:35:30 +01:00

388 lines
13 KiB
YAML

---
sso:
bond: 1
enabled: "{{ 'web-app-keycloak' in group_names }}"
shared: "{{ 'web-app-keycloak' in group_names }}"
flavor: oidc
oidc:
plugin: ""
# nocheck: playwright-service-flag: infrastructural sub-component (TURN/STUN)
coturn:
bond: 1
enabled: "{{ 'web-svc-coturn' in group_names }}"
shared: "{{ 'web-svc-coturn' in group_names }}"
logout:
bond: 1
enabled: "{{ 'web-svc-logout' in group_names }}"
shared: "{{ 'web-svc-logout' in group_names }}"
ldap:
bond: 1
enabled: "{{ 'svc-db-openldap' in group_names }}"
shared: "{{ 'svc-db-openldap' in group_names }}"
dashboard:
bond: 1
enabled: "{{ 'web-app-dashboard' in group_names }}"
shared: "{{ 'web-app-dashboard' in group_names }}"
matomo:
bond: 1
enabled: "{{ 'web-app-matomo' in group_names }}"
shared: "{{ 'web-app-matomo' in group_names }}"
email:
bond: 1
enabled: "{{ MAIL_PROVIDER in group_names }}"
shared: "{{ MAIL_PROVIDER in group_names }}"
# nocheck: shared
# nocheck: dynamic-flag
# nocheck: playwright-service-flag: DB engine, covered by role-local integration tests
redis:
bond: 1
backup:
disabled: true
enabled: true # nocheck: dynamic-flag
shared: "{{ 'svc-db-redis' in group_names }}"
cpus: "1"
mem_reservation: 256m
mem_limit: 1g
pids_limit: 512
name: "{{ 'web-app-nextcloud' | get_entity_name }}-redis"
# nocheck: playwright-service-flag: DB engine, covered by role-local integration tests
mariadb:
bond: 1
enabled: true # nocheck: dynamic-flag
shared: "{{ 'svc-db-mariadb' in group_names }}"
cpus: "0.75"
mem_reservation: 512m
mem_limit: 1.5g
pids_limit: 512
# nocheck: playwright-service-flag self-provider
nextcloud:
enabled: true
shared: true
bond: 1
modes:
compose:
enabled: true
swarm:
enabled: true
name: nextcloud
image: nextcloud
# nocheck: docker-version integration_openproject v3.2.0 caps at Nextcloud 34; only its v3.3.0 nightlies declare 35, lift once 3.3.0 is stable
version: 34-fpm-alpine
custom: true
min_storage: 553MB
backup:
no_stop_required: true
cpus: "2.0"
mem_reservation: 2g
mem_limit: 3g
pids_limit: 512
# danger: lifts Nextcloud's SSRF guard for EVERY outbound client -- federated shares,
# external storage, webcal, previews -- and Nextcloud offers no per-host allowlist.
allow_local_remote_servers:
enabled: "{{ ((ENVIRONMENT | lower) == 'development') | lower }}"
default_quota: "1000000000"
legacy_login_mask:
enabled: "{{ not (lookup('config', 'web-app-nextcloud', 'services.sso.enabled') | bool) }}"
performance:
php:
upload_limit: 5G
fpm:
max_children: 16
start_servers: 4
min_spare_servers: 4
max_spare_servers: 8
request_terminate_timeout: 900s
plugins_enabled: true
proxy:
service_key: proxy
ports:
local:
http: 8001
internal:
http: 80
fpm: 9000
public:
stun_turn: 3480
stun_turn_tls: 5350
relay:
start: 50000
end: 59999
run_after:
- web-app-keycloak
- web-app-matomo
- web-app-gitlab
- web-app-mattermost
- web-app-openproject
- web-app-zammad
lifecycle: beta
proxy:
name: nextcloud-proxy
healthcheck:
flavor: curl
# nocheck: healthcheck-timing-override a sidecar of a stack whose main service alone takes minutes; the value predates this default and has not been measured against it
start_period: 20m
image: nginx
version: 1.31.8-alpine
backup:
no_stop_required: true
cpus: "0.5"
mem_reservation: 64m
mem_limit: 256m
pids_limit: 512
min_storage: 226MB
ports:
internal:
http: 80
# nocheck: playwright-service-flag
# nocheck: dynamic-flag the container serves this role's MCP surface, so it tracks the role's own mcp flag rather than one client's presence
context_agent:
bond: 1
enabled: "{{ lookup('config', 'web-app-nextcloud', 'mcp.enabled') | bool }}"
shared: "{{ lookup('config', 'web-app-nextcloud', 'mcp.enabled') | bool }}"
name: nextcloud-context-agent
image: ghcr.io/nextcloud/context_agent
version: 2.10.0
backup:
no_stop_required: true
# nocheck: single-replica
replicas: 1
cpus: "1.0"
mem_reservation: 512m
mem_limit: 1g
pids_limit: 512
min_storage: 512MB
ports:
internal:
http: 23000
healthcheck:
flavor: http_status
path: heartbeat
# nocheck: healthcheck-timing-override a sidecar of a stack whose main service alone takes minutes; the value predates this default and has not been measured against it
start_period: 20m
# nocheck: playwright-service-flag MCP sidecar, no browser surface
# nocheck: dynamic-flag the sidecar fronts this role's MCP surface, so it tracks the role's own mcp flag rather than one client's presence
contextagentmcp:
enabled: "{{ lookup('config', 'web-app-nextcloud', 'mcp.enabled') | bool }}"
shared: false
image: python
# nocheck: docker-version base of the self-built stdlib adapter, not the served application
version: "3.13.15-slim"
custom: true
name: contextagentmcp
cpus: "0.25"
mem_reservation: 16m
mem_limit: 24m
pids_limit: 64
healthcheck:
flavor: http_status
path: health
ports:
internal:
http: 8080
cron:
# nocheck: single-replica singleton cron.sh; replicas double-run background jobs on the shared data volume
replicas: 1
name: nextcloud-cron
cpus: "0.25"
mem_reservation: 128m
mem_limit: 512m
pids_limit: 256
min_storage: 1GB
# nocheck: dynamic-flag
# nocheck: playwright-service-flag: infrastructural sub-component (real-time communication)
talk:
bond: 1
enabled: "{{ 'web-svc-coturn' in group_names }}"
shared: "{{ 'web-svc-coturn' in group_names }}"
name: nextcloud-talk
image: nextcloud/aio-talk
# nocheck: docker-version -- all 174 tags upstream publishes are AIO build stamps, none is a version
version: latest
backup:
no_stop_required: false
turn_server:
onboard_enabled: "{{ not ( 'web-svc-coturn' in group_names ) }}"
standalone_enabled: "{{ 'web-svc-coturn' in group_names }}"
network_mode: bridge
cpus: "2.0"
mem_reservation: 1g
mem_limit: 2g
pids_limit: 1024
min_storage: 274MB
ports:
internal:
signaling: 8081
healthcheck:
flavor: tcp
port_key: signaling
# nocheck: healthcheck-timing-override a sidecar of a stack whose main service alone takes minutes; the value predates this default and has not been measured against it
start_period: 20m
whiteboard:
name: nextcloud-whiteboard
image: ghcr.io/nextcloud-releases/whiteboard
version: v1.5.9
custom: nextcloud-whiteboard
backup:
no_stop_required: true
cpus: "1"
mem_reservation: 128m
mem_limit: 1g
pids_limit: 1024
min_storage: 683MB
ports:
internal:
http: 3002
healthcheck:
flavor: nc
# nocheck: healthcheck-timing-override a sidecar of a stack whose main service alone takes minutes; the value predates this default and has not been measured against it
start_period: 20m
# nocheck: playwright-service-flag: infrastructural sub-component (collaborative editing)
onlyoffice:
bond: 0.5
enabled: "{{ 'web-svc-onlyoffice' in group_names }}"
shared: "{{ 'web-svc-onlyoffice' in group_names }}"
# nocheck: playwright-service-flag: infrastructural sub-component (collaborative editing)
collabora:
bond: 1
enabled: "{{ 'web-svc-collabora' in group_names }}"
shared: "{{ 'web-svc-collabora' in group_names }}"
# nocheck: playwright-service-flag: bridged web-conferencing partner, covered by partner role spec
bigbluebutton:
bond: 0.5
enabled: "{{ 'web-app-bigbluebutton' in group_names }}"
shared: "{{ 'web-app-bigbluebutton' in group_names }}"
# nocheck: playwright-service-flag: bridged wiki partner, covered by partner role spec
xwiki:
bond: 0.5
enabled: "{{ 'web-app-xwiki' in group_names }}"
shared: "{{ 'web-app-xwiki' in group_names }}"
# nocheck: playwright-service-flag: object store, no Playwright surface
minio:
enabled: false # nocheck: dynamic-flag
shared: false # nocheck: dynamic-flag
seaweedfs:
bond: 1
enabled: "{{ 'web-app-seaweedfs' in group_names }}"
shared: "{{ 'web-app-seaweedfs' in group_names }}"
# nocheck: playwright-service-flag internal recording server, reachable only from the Talk signaling backend
# nocheck: dynamic-flag the recording server is part of the Talk deployment, so it follows the talk entry rather than a role's presence
talk_recording:
enabled: "{{ lookup('config', 'web-app-nextcloud', 'services.talk.enabled') | bool }}"
shared: false
name: nextcloud-talk-recording
image: nextcloud/aio-talk-recording
# nocheck: docker-version -- all 104 tags upstream publishes are AIO build stamps, none is a version
version: latest
backup:
no_stop_required: true
cpus: "2.0"
mem_reservation: 1g
mem_limit: 3g
pids_limit: 1024
min_storage: 507MB
ports:
internal:
recording: 1234
# nocheck: playwright-service-flag: verified by web-svc-css provider spec
css:
bond: 1
enabled: "{{ 'web-svc-css' in group_names }}"
shared: "{{ 'web-svc-css' in group_names }}"
# nocheck: dynamic-flag
# nocheck: playwright-service-flag: captcha backend, infrastructural
hcaptcha:
enabled: "{{ HCAPTCHA_ENABLED | bool }}"
prometheus:
bond: 1
enabled: "{{ 'web-app-prometheus' in group_names }}"
shared: "{{ 'web-app-prometheus' in group_names }}"
# nocheck: playwright-service-flag
tor:
bond: 0.5
enabled: "{{ 'svc-net-tor' in group_names }}"
shared: true # nocheck: dynamic-flag
# nocheck: playwright-service-flag: bridged openproject partner, covered by partner role spec
openproject:
bond: 0.5
enabled: "{{ 'web-app-openproject' in group_names }}"
shared: "{{ 'web-app-openproject' in group_names }}"
# nocheck: playwright-service-flag: bridged gitlab partner, covered by partner role spec
gitlab:
bond: 0.5
enabled: "{{ 'web-app-gitlab' in group_names }}"
shared: "{{ 'web-app-gitlab' in group_names }}"
# nocheck: playwright-service-flag: bridged discourse partner, covered by partner role spec
discourse:
bond: 0.3
enabled: "{{ 'web-app-discourse' in group_names }}"
shared: "{{ 'web-app-discourse' in group_names }}"
# nocheck: playwright-service-flag: bridged mattermost partner, covered by partner role spec
mattermost:
bond: 0.5
enabled: "{{ 'web-app-mattermost' in group_names }}"
shared: "{{ 'web-app-mattermost' in group_names }}"
# nocheck: playwright-service-flag: bridged matrix partner, covered by partner role spec
matrix:
bond: 0.5
enabled: "{{ 'web-app-matrix' in group_names }}"
shared: "{{ 'web-app-matrix' in group_names }}"
# nocheck: playwright-service-flag: bridged zammad partner, covered by partner role spec
zammad:
bond: 0.5
enabled: "{{ 'web-app-zammad' in group_names }}"
shared: "{{ 'web-app-zammad' in group_names }}"
# nocheck: playwright-service-flag: bridged openwebui partner, covered by partner role spec
openwebui:
bond: 0.5
enabled: "{{ 'web-app-openwebui' in group_names }}"
shared: "{{ 'web-app-openwebui' in group_names }}"
# nocheck: playwright-service-flag, dynamic-flag - bridged litellm gateway partner, covered by partner role spec, and a single shared instance
litellm:
bond: 0.5
enabled: "{{ LITELLM_USABLE }}"
shared: true
# nocheck: playwright-service-flag: bridged mastodon partner, covered by partner role spec
mastodon:
bond: 0.5
enabled: "{{ 'web-app-mastodon' in group_names }}"
shared: "{{ 'web-app-mastodon' in group_names }}"
# nocheck: playwright-service-flag: bridged peertube partner, covered by partner role spec
peertube:
bond: 0.5
enabled: "{{ 'web-app-peertube' in group_names }}"
shared: "{{ 'web-app-peertube' in group_names }}"
# TODO(bridge): no nc-33-compatible integration_moodle on the app store (absent for nc 30/32/33).
# Re-enable enabled/shared (back to the "web-app-moodle in group_names" form) once a plugin ships.
# nocheck: playwright-service-flag: bridged moodle partner, covered by partner role spec
moodle:
enabled: false # nocheck: dynamic-flag
shared: false # nocheck: dynamic-flag
# TODO(bridge): integration_suitecrm requires nc <= 24 (see meta/addons/integration_suitecrm.yml).
# Re-enable enabled/shared (back to the "web-app-suitecrm in group_names" form) once a plugin ships.
# nocheck: playwright-service-flag: bridged suitecrm partner, covered by partner role spec
suitecrm:
enabled: false # nocheck: dynamic-flag
shared: false # nocheck: dynamic-flag
# nocheck: dynamic-flag
# nocheck: playwright-service-flag, dynamic-flag infrastructure backup consumer
container_backup: # nocheck: bond-baseline backup host joins outside the variant topology
bond: 1
enabled: "{{ 'svc-bkp-volume-2-local' in group_names }}"
shared: true
# nocheck: playwright-service-flag: MCP pairing is proven by the role's own MCP spec, not by a per-consumer gate
hermes:
bond: 0.5
enabled: "{{ 'web-app-hermes' in group_names }}"
shared: "{{ 'web-app-hermes' in group_names }}"
# nocheck: playwright-service-flag: MCP pairing is proven by the role's own MCP spec, not by a per-consumer gate
openclaw:
bond: 0.5
enabled: "{{ 'web-app-openclaw' in group_names }}"
shared: "{{ 'web-app-openclaw' in group_names }}"
# nocheck: playwright-service-flag: MCP pairing is proven by the role's own MCP spec, not by a per-consumer gate
# nocheck: dynamic-flag the entry refuses this client, so the link is off on every host and no group_names gate can decide it
flowise:
enabled: false
shared: false
mcp_consumer: false