LibrePortal/containers/rocketchat/docker-compose.yml
librelad 5835fa09d7 fix(auth): only generate an admin password where something creates the account
Answers "should we stop creating an admin/pass on start" with the split the
catalog actually has, rather than one way for everything.

Ten apps need it: adguard, authelia, bookstack, matrix, nextcloud, owncloud,
pihole, rocketchat, stalwart, speedtest and headscale either pass the generated
password into the container or hand it to an install hook that creates the
account. There the password IS the working credential — dropping it would lock
you out. Left alone.

Three do not create an account at all: gitea, invidious and mattermost seed no
user (the first one comes from their own signup flow or the Create Account tool),
so the password minted at install named nothing. The WebUI credentials card
showed a password that could not log in. They now match linkding — an empty,
unslotted ADMIN_PASSWORD the auth adapter fills when the operator makes the first
admin, and keeps in step on later resets. Unslotted because the slot number marks
a value the installer generates.

mattermost's adapter also had linkding's bug: it persists ADMIN_PASSWORD but the
config declared only ADMIN_EMAIL, so the write was a no-op.

WebUI: rocketchat's generated admin password had no field mapping, so the card
could not show it. Added, plus a generic ADMIN_USER entry — six apps record an
admin username the card had no way to display.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 21:31:05 +01:00

114 lines
6.8 KiB
YAML

networks:
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
external: true
services:
rocketchat-service: #LIBREPORTAL|SERVICE_TAG_1|rocketchat-service
container_name: rocketchat-service
image: rocketchat/rocket.chat:8.7.0 #LIBREPORTAL|ROCKETCHAT_VERSION_TAG|8.7.0
# The image runs as uid 65533 and writes uploads into /app/uploads, so
# it hits the same rootless bind-mount ownership problem as vikunja and
# mattermost. USER_TAG resolves to whoever actually owns the mounts.
user: "USER_DATA" #LIBREPORTAL|USER_TAG|USER_DATA
# Rocket.Chat exits — rather than waits — when Mongo has no elected
# primary, and on a fresh install the replica set is only initiated by
# the post-start hook. `unless-stopped` is what carries it through those
# first few seconds of crash-looping.
restart: unless-stopped
# GLUETUN_OFF_BEGIN
ports:
- "PORTS_DATA_1" #LIBREPORTAL|PORTS_TAG_1|PORTS_DATA_1
# GLUETUN_OFF_END
volumes:
- ./uploads:/app/uploads
environment:
- TZ=TIMEZONE_DATA #LIBREPORTAL|TIMEZONE_TAG|TIMEZONE_DATA
- PORT=PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
# ROOT_URL is what Rocket.Chat puts in invite links, OAuth redirect
# URLs and the websocket origin check. Get it wrong and the client
# loads but never connects.
- ROOT_URL=APP_URL_DATA #LIBREPORTAL|APP_URL_TAG|APP_URL_DATA
# ?replicaSet=rs0 is mandatory, not decorative: Rocket.Chat tails
# the Mongo oplog for realtime updates, and the oplog only exists on
# a replica set. Single-node is fine — it just has to be a set.
- MONGO_URL=mongodb://rocketchat-db:27017/rocketchat?replicaSet=rs0
- MONGO_OPLOG_URL=mongodb://rocketchat-db:27017/local?replicaSet=rs0
- DEPLOY_METHOD=docker
# Seed the first admin instead of leaving a setup wizard for someone
# to click through. These are honoured only while no admin exists, so
# they are inert on every boot after the first — and marking the
# wizard completed is what stops Rocket.Chat asking anyway.
#
# It also gives LibrePortal a credential to drive the REST API with,
# which is what the Tools tab needs; without a seeded admin there is
# no account to authenticate as.
- OVERWRITE_SETTING_Show_Setup_Wizard=completed
- ADMIN_USERNAME=ROCKETCHAT_ADMIN_USERNAME_DATA #LIBREPORTAL|ROCKETCHAT_ADMIN_USERNAME_TAG|ROCKETCHAT_ADMIN_USERNAME_DATA
- ADMIN_PASS=ROCKETCHAT_ADMIN_PASSWORD_1_DATA #LIBREPORTAL|ROCKETCHAT_ADMIN_PASSWORD_1_TAG|ROCKETCHAT_ADMIN_PASSWORD_1_DATA
- ADMIN_EMAIL=ROCKETCHAT_ADMIN_EMAIL_DATA #LIBREPORTAL|ROCKETCHAT_ADMIN_EMAIL_TAG|ROCKETCHAT_ADMIN_EMAIL_DATA
depends_on:
- rocketchat-db
labels:
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
libreportal.title: "TITLE_DATA" #LIBREPORTAL|TITLE_TAG|TITLE_DATA
libreportal.backup.db: "mongo:rocketchat-db:mongo_data:"
libreportal.backup.files: "rocketchat-service:/app/uploads:uploads"
traefik.enable: TRAEFIK_ENABLE_DATA #LIBREPORTAL|TRAEFIK_ENABLE_TAG|TRAEFIK_ENABLE_DATA
# TRAEFIK_PORT_1_BEGIN
traefik.http.routers.rocketchat-service.entrypoints: web,websecure
traefik.http.routers.rocketchat-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
traefik.http.routers.rocketchat-service.tls: true
traefik.http.routers.rocketchat-service.tls.certresolver: production
traefik.http.services.rocketchat-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
traefik.http.routers.rocketchat-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
# TRAEFIK_PORT_1_END
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
healthcheck:
disable: HEALTHCHECK_DATA #LIBREPORTAL|HEALTHCHECK_TAG|HEALTHCHECK_DATA
# GLUETUN_OFF_BEGIN
networks:
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
ipv4_address: IP_DATA_1 #LIBREPORTAL|IP_TAG_1|IP_DATA_1
# GLUETUN_OFF_END
# GLUETUN_ON_BEGIN
# network_mode: "container:gluetun-service"
# GLUETUN_ON_END
# Official mongo image rather than bitnami/mongodb (which upstream's own
# compose uses): Bitnami moved its catalog behind a paid registry in 2025
# and the free tags are no longer dependable for a long-lived install. The
# cost is that the replica set is not auto-initiated, so
# rocketchat_install_post_start runs rs.initiate() once, by hand.
#
# No authentication: enabling it on a replica set additionally requires a
# shared keyfile for member-to-member auth, which is a lot of moving parts
# for a database that is never published outside the docker network. The
# backup driver's mongo path works either way — it adds credential flags
# only when MONGO_INITDB_ROOT_USERNAME is set.
#
# No `user:` override: the entrypoint starts as root, chowns /data/db and
# then drops to the mongodb user. Under rootless Docker container-root is
# the install user on the host, which owns the bind mount, so that works.
rocketchat-db: #LIBREPORTAL|SERVICE_TAG_2|rocketchat-db
image: mongo:8.0 #LIBREPORTAL|ROCKETCHAT_MONGO_VERSION_TAG|8.0
container_name: rocketchat-db
restart: unless-stopped
command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
volumes:
- ./mongo_data:/data/db
- ./mongo_config:/data/configdb
environment:
- TZ=TIMEZONE_DATA #LIBREPORTAL|TIMEZONE_TAG|TIMEZONE_DATA
# Required on Linux 6.19 and newer. The TCMalloc bundled with
# MongoDB 8.x registers restartable sequences in a way the newer
# kernel rejects; mongod then aborts on startup with "Linux kernel
# versions 6.19 and newer has a known incompatibility"
# (SERVER-121912). Letting glibc own the rseq registration avoids
# the conflict. Harmless once upstream ships a patched TCMalloc —
# this only sets a glibc tunable — so it can be dropped then rather
# than urgently.
- GLIBC_TUNABLES=glibc.pthread.rseq=1
networks:
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
ipv4_address: IP_DATA_2 #LIBREPORTAL|IP_TAG_2|IP_DATA_2