Compare commits

..
5 Commits
Author SHA1 Message Date
notplants ede639916c docs: clarify install-user check (postgres = no env needed) 2026-06-22 19:31:27 +00:00
notplants 5f50022bb4 docs: drop healthcheck comment; rephrase release note POSTGRES_USER warning + check command 2026-06-22 19:24:49 +00:00
notplants a5a3b36755 feat(db): use POSTGRES_USER in pg_backup; document it in release note
- pg_backup.sh: use the db service's POSTGRES_USER (default postgres) for the
  dump/drop/recreate instead of detecting the superuser at runtime, since the
  recipe now sets that env var; one-line the constants comment
- release note: explain the in-place pg_upgrade + the POSTGRES_USER override
- bump PG_BACKUP_VERSION v4

Verified on cctest: backup + restore via the hooks round-trips with POSTGRES_USER.
2026-06-22 18:46:17 +00:00
notplants a081d1dba0 Update pg_backup.sh 2026-06-22 18:37:15 +00:00
notplants f783d9988b feat(db): switch to discourse/postgres image (auto-upgrade, no custom entrypoint file)
Replace the bitnami-era pgvector:pg17 db + hand-rolled pg_upgrade entrypoint
with discourse/postgres:pg18 (pgvector + discourse's auto-upgrade layer, as
suggested on coop-cloud/discourse#16). The image runs the in-place major-version
pg_upgrade itself on boot, so the recipe just configures it via env:

- the db password secret is read into $DB_PASSWORD by a small inline entrypoint
  (the image expects it in the env, no *_FILE support; the base image's
  POSTGRES_PASSWORD_FILE can't be used because run-postgres.sh pre-generates
  POSTGRES_PASSWORD). No separate entrypoint file/config any more.
- POSTGRES_USER (the install user pg_upgrade must match) defaults to the image's
  'postgres' -- correct for fresh installs and bitnami-origin clusters -- and is
  overridable from the app .env for a cluster bootstrapped with another superuser.
- POSTGRES_INITDB_ARGS=--no-data-checksums so the new pg18 cluster matches the
  pre-18 clusters (pg18 initdb enables checksums by default; pg_upgrade needs a
  match).

- mount postgresql_data at /var/lib/postgresql (versioned PGDATA .../18/docker)
- pg_backup.sh: detect the superuser at runtime; fix paths for the new layout
- document POSTGRES_USER override in .env.sample and README
- bump PG_BACKUP_VERSION v3; drop DB_ENTRYPOINT_VERSION + entrypoint.postgres.sh.tmpl

Verified on cctest: pg17->pg18 upgrade (install user 'postgres', checksums off)
preserves data and serves over HTTPS; fresh install also works.
2026-06-22 18:23:22 +00:00
8 changed files with 175 additions and 24 deletions
+40
View File
@@ -0,0 +1,40 @@
---
kind: pipeline
name: deploy to swarm-test.autonomic.zone
steps:
- name: deployment
image: git.coopcloud.tech/coop-cloud/stack-ssh-deploy:latest
settings:
host: swarm-test.autonomic.zone
stack: discourse
generate_secrets: true
purge: true
deploy_key:
from_secret: drone_ssh_swarm_test
networks:
- proxy
environment:
DOMAIN: discourse.swarm-test.autonomic.zone
STACK_NAME: discourse
LETS_ENCRYPT_ENV: production
SECRET_DB_PASSWORD_VERSION: v1
DB_ENTRYPOINT_VERSION: v1
trigger:
branch:
- main
---
kind: pipeline
name: generate recipe catalogue
steps:
- name: release a new version
image: plugins/downstream
settings:
server: https://build.coopcloud.tech
token:
from_secret: drone_abra-bot_token
fork: true
repositories:
- toolshed/auto-recipes-catalogue-json
trigger:
event: tag
+29
View File
@@ -0,0 +1,29 @@
TYPE=discourse
DOMAIN=discourse.example.com
## Domain aliases
#EXTRA_DOMAINS=', `www.discourse.example.com`'
LETS_ENCRYPT_ENV=production
# Admin / developer accounts (comma-separated); these become admins on signup
DISCOURSE_DEVELOPER_EMAILS=admin@example.com
# Outgoing email (official discourse/discourse env names)
#DISCOURSE_SMTP_ADDRESS=
#DISCOURSE_SMTP_PORT=587
#DISCOURSE_SMTP_USER_NAME=
#DISCOURSE_SMTP_AUTHENTICATION=login
#DISCOURSE_SMTP_ENABLE_START_TLS=true
# Set this if you send e-mail from a different address than noreply@$DOMAIN
#DISCOURSE_NOTIFICATION_EMAIL=
# SMTP password as a secret
#SECRET_SMTP_PASSWORD_VERSION=v1
SECRET_DB_PASSWORD_VERSION=v1
# Postgres bootstrap superuser (the cluster's "install user"). Defaults to
# `postgres`, which matches fresh installs and bitnami-origin clusters. Only set
# this if you are upgrading a cluster that was bootstrapped with a different
# superuser (e.g. `discourse`) — a postgres major upgrade fails unless it matches.
#POSTGRES_USER=postgres
-1
View File
@@ -1 +0,0 @@
.env
+63 -12
View File
@@ -1,24 +1,75 @@
# Discourse
Wiki Cafe's configuration for a Discourse deployment. Originally slimmed down from an `abra` [recipe](https://git.coopcloud.tech/coop-cloud/discourse) by [Co-op Cloud](https://coopcloud.tech/).
[![Build Status](https://build.coopcloud.tech/api/badges/coop-cloud/discourse/status.svg?ref=refs/heads/main)](https://build.coopcloud.tech/coop-cloud/discourse)
A platform for community discussion
## Deploying the app with Docker Swarm
<!-- metadata -->
* **Category**: Apps
* **Status**: 3, experimental
* **Image**: [`discourse/discourse`](https://hub.docker.com/r/discourse/discourse), 4, upstream
* **Healthcheck**: yes
* **Backups**: yes
* **Email**: yes
* **Tests**: yes
* **SSO**: no
<!-- endmetadata -->
Set the environment variables from the .env file during the shell session.
> **Note**: this recipe runs the official, **experimental** `discourse/discourse`
> image. Upstream does not yet recommend it for production — see
> <https://meta.discourse.org/t/380646>. Use with care.
## Basic usage
1. Set up Docker Swarm and [`abra`]
2. Deploy [`coop-cloud/traefik`]
3. `abra app new discourse --secrets`
4. `abra app config YOURAPPDOMAIN` — set `DOMAIN` and `DISCOURSE_DEVELOPER_EMAILS`
5. `abra app deploy YOURAPPDOMAIN`
6. Open the configured domain in your browser to finish set-up. The first account
that registers with an address listed in `DISCOURSE_DEVELOPER_EMAILS` becomes
an admin.
[`abra`]: https://docs.coopcloud.tech/abra/
[`coop-cloud/traefik`]: https://git.coopcloud.tech/coop-cloud/traefik
The app serves plain HTTP on port 80; Traefik terminates TLS in front of it. The
image's built-in nginx/Let's Encrypt is disabled by the recipe (`install-ssl`
override) so it works behind the reverse proxy.
## Add an admin user
```
set -a && source .env && set +a
abra app run YOURAPPDOMAIN app discourse admin create
```
Set the secrets.
## Postgres major version upgrades
Handled automatically by the [`discourse/postgres`] image (pgvector + an
auto-upgrade layer). On deploy it finds an older cluster, installs the old
binaries and runs `pg_upgrade` into the new versioned data directory. No manual
dump/restore needed.
`pg_upgrade` must run as the old cluster's bootstrap superuser (its "install
user"). The recipe uses `POSTGRES_USER`, which defaults to `postgres` — the right
value for fresh installs and for clusters that came from the old bitnami recipe.
If your cluster was bootstrapped with a different superuser (e.g. `discourse`),
set `POSTGRES_USER` in the app `.env` before upgrading, otherwise `pg_upgrade`
will refuse with an install-user mismatch.
[`discourse/postgres`]: https://github.com/discourse/discourse-postgres
## Migrating from the previous (bitnami) recipe
The official image stores uploads under `/shared` rather than bitnami's
`/bitnami/discourse`. On first boot the recipe copies uploads + backups from the
old bitnami volume (mounted read-only at `/legacy`) into `/shared`, once,
idempotently. The Postgres database is reused as-is. After a successful migration
a later recipe version will drop the transitional `/legacy` mount.
If you are upgrading from the bitnami recipe, also remove the now-unused sidekiq
service that swarm leaves behind (sidekiq runs inside the app container now):
```
printf "SECRET_HERE" | docker secret create SECRET_NAME -
```
Deploy using the `-c` flag to specify one or multiple compose files.
```
docker stack deploy discourse --detach=true -c compose.yaml -c compose.smtpauth.yaml
docker service rm YOURSTACK_sidekiq
```
+4
View File
@@ -0,0 +1,4 @@
export PG_BACKUP_VERSION=v4
export APP_ENTRYPOINT_VERSION=v2
export APP_INSTALL_SSL_VERSION=v1
export APP_MIGRATE_UPLOADS_VERSION=v1
@@ -1,3 +1,6 @@
---
version: "3.8"
services:
app:
# the wrapper entrypoint reads /run/secrets/smtp_password and exports
@@ -8,4 +11,4 @@ services:
secrets:
smtp_password:
external: true
name: ${STACK_NAME}_smtp_password
name: ${STACK_NAME}_smtp_password_${SECRET_SMTP_PASSWORD_VERSION}
+16 -10
View File
@@ -1,7 +1,9 @@
---
version: "3.8"
services:
app:
image: discourse/discourse:2026.7.4
image: discourse/discourse:3.5.3
networks:
- proxy
- internal
@@ -25,6 +27,8 @@ services:
- DISCOURSE_NOTIFICATION_EMAIL
volumes:
- 'discourse_shared:/shared'
# transition only: legacy bitnami volume, read-only, for one-time upload migration
- 'discourse_data:/legacy:ro'
secrets:
- db_password
configs:
@@ -50,9 +54,7 @@ services:
- "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})"
- "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure"
- "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}"
- "caddy=${DOMAIN}"
- "caddy.reverse_proxy={{upstreams 80}}"
- "caddy.tls.on_demand="
- "coop-cloud.${STACK_NAME}.version=1.0.0+3.5.3"
healthcheck:
test: "curl -fsS http://localhost/srv/status || exit 1"
interval: 30s
@@ -97,6 +99,9 @@ services:
# `postgres` matches fresh installs and bitnami-origin clusters. Override in
# the app .env (POSTGRES_USER=...) only for a cluster bootstrapped differently.
- POSTGRES_USER=${POSTGRES_USER:-postgres}
# pg18's initdb enables data checksums by default, but pg13-17 clusters here
# have them off and pg_upgrade requires a match -> initialise without them.
- POSTGRES_INITDB_ARGS=--no-data-checksums
healthcheck:
test: "pg_isready -U discourse -d discourse"
interval: 30s
@@ -111,7 +116,7 @@ services:
backupbot.restore.post-hook: "/pg_backup.sh restore"
redis:
image: redis:8.10-alpine
image: redis:7.4-alpine
networks:
- internal
volumes:
@@ -126,12 +131,13 @@ services:
secrets:
db_password:
external: true
name: ${STACK_NAME}_db_password
name: ${STACK_NAME}_db_password_${SECRET_DB_PASSWORD_VERSION}
volumes:
postgresql_data:
redis_data:
discourse_shared:
discourse_data:
networks:
proxy:
@@ -140,14 +146,14 @@ networks:
configs:
app_entrypoint:
name: ${STACK_NAME}_app_entrypoint
name: ${STACK_NAME}_app_entrypoint_${APP_ENTRYPOINT_VERSION}
file: cc-app-entrypoint.sh
app_install_ssl:
name: ${STACK_NAME}_app_install_ssl
name: ${STACK_NAME}_app_install_ssl_${APP_INSTALL_SSL_VERSION}
file: app-install-ssl.sh
app_migrate_uploads:
name: ${STACK_NAME}_app_migrate_uploads
name: ${STACK_NAME}_app_migrate_uploads_${APP_MIGRATE_UPLOADS_VERSION}
file: migrate-uploads.sh
pg_backup:
name: ${STACK_NAME}_pg_backup
name: ${STACK_NAME}_pg_backup_${PG_BACKUP_VERSION}
file: pg_backup.sh
+19
View File
@@ -0,0 +1,19 @@
This release switches from the bitnami image to the official discourse/discourse
image. Some env vars need to be renamed for this migration; everything else
should happen automatically.
Rename these in your app's .env (the values carry over):
DISCOURSE_SMTP_HOST --> DISCOURSE_SMTP_ADDRESS
DISCOURSE_SMTP_USER --> DISCOURSE_SMTP_USER_NAME
DISCOURSE_SMTP_AUTH --> DISCOURSE_SMTP_AUTHENTICATION
DISCOURSE_SMTP_PROTOCOL --> DISCOURSE_SMTP_ENABLE_START_TLS (takes a boolean true/false, not the old tls/ssl value, so translate it rather than copying it straight across)
WARNING: if your deployment's database has an "install user" other than `postgres`
(some older deployments do), you must set the POSTGRES_USER env var in your .env
for this migration, otherwise the postgres upgrade aborts with an install-user
mismatch.
Check your old deployment's install user before upgrading (if this command returns postgres, then you do not need to set this env):
abra app run YOURAPPDOMAIN db -- psql -U discourse -tAc 'select rolname from pg_roles where oid = 10'