33 Commits

Author SHA1 Message Date
bd5f181737 fix(db): bump DB_ENTRYPOINT_VERSION to v3 so the entrypoint config reloads
The install-user fix changed the entrypoint content; swarm configs are
immutable, so the config name (which embeds DB_ENTRYPOINT_VERSION) must change
for a redeploy to pick up the new script.
2026-06-16 18:04:05 +00:00
57f5ee2531 fix(db): run pg_upgrade as the old cluster's real install user
pg_upgrade must run as the old cluster's bootstrap superuser (oid 10), and the
new cluster must be initialised with that same user, otherwise it fails the
"database user is the install user" consistency check. The install user is not
necessarily $POSTGRES_USER: clusters created with the default "postgres"
superuser plus a separate app role (e.g. discourse) are common.

Detect it from the old cluster by briefly starting it and reading pg_roles
(oid = 10) as the known app role, then use it for both the new cluster's initdb
and the pg_upgrade -U argument.
2026-06-16 17:59:26 +00:00
101ffe1964 fix(db): make pg_upgrade migration idempotent & crash-safe
The postgres major-version migration in the db entrypoint was not safe to
re-run. If the container was killed mid-migration it could crash-loop forever
("mkdir: cannot create directory .../old_data: File exists") or silently initdb
a fresh empty cluster over the live data once PG_VERSION had been moved out of
$PGDATA but before the in-progress marker was written.

Replace the marker file with a state-driven guard keyed on the scratch dirs:
empty old_data/new_data means the run was interrupted before any data moved, so
discard and retry (idempotent); non-empty means data may only live there, so
stop for manual recovery. Bump DB_ENTRYPOINT_VERSION v1->v2 so swarm picks up
the new (immutable) config.
2026-06-16 17:00:16 +00:00
433ce12dbc Merge pull request 'chore: upgrade to 0.10.0+3.5.0' (#2) from upgrade-0.8.0+3.5.0 into main
Reviewed-on: https://git.autonomic.zone/recipe-maintainers/discourse/pulls/2
2026-06-15 17:37:14 +00:00
b7d8a244d7 chore: upgrade to 0.10.0+3.5.0 (redis 8.0->8.8-alpine) 2026-06-11 22:52:37 +00:00
7ae7b0f76e chore: upgrade to 0.9.0+3.5.0 2026-06-05 02:03:34 +00:00
b0f9ae743a fix(db): switch postgres image to pgvector/pgvector:pg17 + bump PG_BACKUP_VERSION
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/tag Build is passing
2026-06-02 20:07:06 +00:00
5091fd999e improved comments
Some checks failed
continuous-integration/drone/pr Build is failing
2026-06-02 19:10:27 +00:00
ec7bbdf786 fix(backup): add pg_backup.sh + proper backup/restore hooks, 20m start_period 2026-06-02 19:10:27 +00:00
0f873433ba chore: upgrade to 0.8.0+3.5.0 2026-06-02 19:10:27 +00:00
7d53d4ec39 Merge pull request 'Update README.md corrected url to bitnami/discourse' (#12) from jeppebundsgaard/discourse:main into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #12
Reviewed-by: decentral1se <decentral1se@noreply.git.coopcloud.tech>
2025-12-28 09:32:18 +00:00
ee2381c3b7 Update README.md
Some checks failed
continuous-integration/drone/pr Build is failing
2025-12-28 02:04:01 +00:00
63d3801060 Update .drone.yml
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-08 10:09:12 -08:00
3wc
fee61883ed Fix CI, add auto recipe catalogue generation
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-02 15:44:50 -04:00
3wc
eb96de947b chore: publish 0.7.0+3.3.1 release
Some checks failed
continuous-integration/drone/push Build is failing
2024-10-02 15:42:31 -04:00
ddda5da6bc chore: publish new release
Some checks failed
continuous-integration/drone/push Build is failing
2023-10-20 15:54:13 +02:00
3wc
304468b8f4 chore: publish 0.6.2+3.1.1 release
Some checks failed
continuous-integration/drone/push Build is failing
2023-10-19 11:04:19 +01:00
3wc
0ccf1d7a6c Fix healthcheck, sidekiq on proxy network
Some checks failed
continuous-integration/drone/push Build is failing
2023-10-19 11:03:42 +01:00
3wc
1049c27c35 chore: publish 0.6.1+3.1.1 release
Some checks failed
continuous-integration/drone/push Build is failing
2023-10-08 18:41:20 +01:00
3wc
03dc80d073 Add healthcheck for app container
Some checks failed
continuous-integration/drone/push Build is failing
2023-10-08 18:40:49 +01:00
3wc
300f374af9 chore: publish 0.6.0+3.1.1 release
Some checks failed
continuous-integration/drone/push Build is failing
2023-10-03 19:13:06 +01:00
3wc
ec72949bfa chore: publish 0.5.0+3.0.6 release
Some checks failed
continuous-integration/drone/push Build is failing
2023-08-21 15:57:39 +02:00
3wc
6a5f20bc8a Add postgres major version upgrade script 2023-08-21 15:56:57 +02:00
3wc
3b5d789390 chore: publish 0.4.1+3.0.6 release
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-21 14:20:29 +02:00
3wc
22b8f8f265 Drop separate Sidekiq vol, it should use the main one
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-20 13:35:04 -04:00
5868b83948 docs: events plugin
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-09 12:58:47 +01:00
5bef03aabd chore: publish 0.4.0+3.0.1 release
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-09 12:57:24 +01:00
0c7847ac15 fix: sort + PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY = 0 2023-02-09 12:56:48 +01:00
3wc
7fc57c52a5 Switch to self-hosted stack-ssh-deploy image [mass update]
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 11:49:55 -08:00
3wc
fd24d4a328 Update abra syntax in examples (finally) [mass update]
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-19 16:02:27 -08:00
3wc
1240106d4d Add rudimentary database backup, and Postgres upgrade misery
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-22 18:42:42 -08:00
3wc
add7b1e240 Clarify DISCOURSE_DATABASE_HOST
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-22 18:16:10 -08:00
3wc
802a22886c Remove vim swapfile 2022-11-22 13:34:06 -08:00
7 changed files with 207 additions and 30 deletions

Binary file not shown.

View File

@ -3,7 +3,7 @@ kind: pipeline
name: deploy to swarm-test.autonomic.zone
steps:
- name: deployment
image: decentral1se/stack-ssh-deploy:latest
image: git.coopcloud.tech/coop-cloud/stack-ssh-deploy:latest
settings:
host: swarm-test.autonomic.zone
stack: discourse
@ -18,6 +18,23 @@ steps:
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

View File

@ -7,7 +7,7 @@ A platform for community discussion
<!-- metadata -->
* **Category**: Apps
* **Status**:
* **Image**: [`bitnami/discourse`](https://hub.docker.com/r/bitname/discourse)
* **Image**: [`bitnami/discourse`](https://hub.docker.com/r/bitnami/discourse)
* **Healthcheck**: yes
* **Backups**: no
* **Email**: yes
@ -21,15 +21,15 @@ A platform for community discussion
2. Deploy [`coop-cloud/traefik`]
3. `abra app new discourse --secrets` (optionally with `--pass` if you'd like
to save secrets in `pass`)
4. `abra app YOURAPPDOMAIN config` - be sure to change `$DOMAIN` to something that resolves to
4. `abra app config YOURAPPDOMAIN` - be sure to change `$DOMAIN` to something that resolves to
your Docker swarm box
5. `abra app YOURAPPDOMAIN deploy`
5. `abra app deploy YOURAPPDOMAIN`
6. Open the configured domain in your browser to finish set-up
[`abra`]: https://git.autonomic.zone/autonomic-cooperative/abra
[`coop-cloud/traefik`]: https://git.autonomic.zone/coop-cloud/traefik
## To add a new Admin user
## To add a new admin user
1. Login to the instance `abra app run APPNAME app sh`
2. `cd /opt/bitnami/discourse`
@ -39,9 +39,34 @@ A platform for community discussion
1. Login to instance `abra app run APPNAME app sh`
2. `cd /bitnami/discourse/plugins/`
3. `git clone plugingit` for example `https://github.com/discourse/discourse-openid-connect.git`
4. `abra app restart APPNAME app`
3. `git clone plugin.git` for example `https://github.com/discourse/discourse-openid-connect.git`
4. `abra app restart YOURAPPDOMAIN app`
### Events / calendar plugin
We've had some luck running [discourse-events](https://github.com/paviliondev/discourse-events).
## Setup Notes
Until issue #1 is fixed, the default user is `user` and the default password is `bitnami123`
## Postgres major version upgrades
Welcome to hell.
1. `abra app run YOURAPPDOMAIN db pg_dumpall -U discourse | gzip > YOURAPPDOMAIN_db_DATE.sql.gz`
2. `abra app volume ls YOURAPPDOMAIN`, find the name of the Postgres data volume
3. `scp` the backup to your VPS
4. `abra app undeploy YOURAPPDOMAIN`
5. `abra app volume rm YOURAPPDOMAIN`, choose the Postgres data volume
6. `abra app deploy YOURAPPDOMAIN`, then `abra app undeploy YOURAPPDOMAIN`
7. `ssh` to the VPS, run (replacing `13-alpine` with the new Postgres version)
`docker run -v YOURDATAVOLUME:/var/lib/postgresql/data -e POSTGRES_HOST_AUTH_METHOD=trust -it postgres:13-alpine`
8. In another SSH session on the server, run `docker ps` to find the ID of the
new Postgres container, then `docker exec -it CONTAINERID bash`
9. In the shell you just launched, run `dropdb -U discourse discourse`, then
`createdb -U discourse discourse`, then Ctrl+D or run `exit`
10. In the second SSH session, run `zcat YOURAPPDOMAIN_db_DATE.sql.gz | docker exec -it CONTAINERID psql -U discourse`
11. Exit the second SSH session
12. Back in the first SSH session, Ctrl+C to shut down the database
13. `abra app deploy YOURAPPDOMAIN`

2
abra.sh Normal file
View File

@ -0,0 +1,2 @@
export DB_ENTRYPOINT_VERSION=v3
export PG_BACKUP_VERSION=v2

View File

@ -3,24 +3,25 @@ version: "3.8"
services:
app:
image: bitnami/discourse:2.8.9
image: bitnamilegacy/discourse:3.5.0
networks:
- proxy
- internal
# entrypoint: ['tail', '-f', '/dev/null']
environment:
- ALLOW_EMPTY_PASSWORD=yes
- DISCOURSE_HOST=${DOMAIN}
- DISCOURSE_DATABASE_HOST=db
- DISCOURSE_DATABASE_USER=discourse
- DISCOURSE_DATABASE_HOST=${STACK_NAME}_db
- DISCOURSE_DATABASE_NAME=discourse
- DISCOURSE_DATABASE_PASSWORD_FILE=/run/secrets/db_password
- DISCOURSE_DATABASE_USER=discourse
- DISCOURSE_HOST=${DOMAIN}
- DISCOURSE_NOTIFICATION_EMAIL
- DISCOURSE_SMTP_AUTH
- DISCOURSE_SMTP_HOST
- DISCOURSE_SMTP_PORT
- DISCOURSE_SMTP_USER
- DISCOURSE_SMTP_PROTOCOL
- DISCOURSE_SMTP_AUTH
- DISCOURSE_NOTIFICATION_EMAIL
- DISCOURSE_SMTP_USER
- PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0
volumes:
- 'discourse_data:/bitnami/discourse'
secrets:
@ -42,60 +43,76 @@ services:
#- "traefik.http.routers.${STACK_NAME}.middlewares=${STACK_NAME}-redirect"
#- "traefik.http.middlewares.${STACK_NAME}-redirect.headers.SSLForceHost=true"
#- "traefik.http.middlewares.${STACK_NAME}-redirect.headers.SSLHost=${DOMAIN}"
- "coop-cloud.${STACK_NAME}.version=0.3.1+2.8.9"
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:3000"]
# interval: 30s
# timeout: 10s
# retries: 10
# start_period: 1m
- "coop-cloud.${STACK_NAME}.version=0.10.0+3.5.0"
healthcheck:
test: "ruby -e \"require 'uri'; require 'net/http'; uri = URI('http://localhost:3000/srv/status'); res = Net::HTTP.get_response(uri); if res.is_a?(Net::HTTPSuccess) then exit (0) else exit (1) end\""
interval: 30s
timeout: 10s
retries: 6
start_period: 20m
db:
image: postgres:13-alpine
image: pgvector/pgvector:pg17
networks:
- internal
secrets:
- db_password
volumes:
- 'postgresql_data:/var/lib/postgresql/data'
configs:
- source: db_entrypoint
target: /docker-entrypoint.sh
mode: 0555
- source: pg_backup
target: /pg_backup.sh
mode: 0555
entrypoint: /docker-entrypoint.sh
environment:
- POSTGRES_HOST_AUTH_METHOD=trust
- POSTGRES_USER=discourse
- POSTGRES_DB=discourse
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
deploy:
labels:
backupbot.backup: "true"
backupbot.backup.pre-hook: "/pg_backup.sh backup"
backupbot.backup.volumes.postgresql_data.path: "backup.sql"
backupbot.restore.post-hook: "/pg_backup.sh restore"
redis:
image: redis:7.0-alpine
image: redis:8.8-alpine
networks:
- internal
volumes:
- 'redis_data:/data'
sidekiq:
image: bitnami/discourse:2.8.9
image: bitnamilegacy/discourse:3.5.0
networks:
- proxy
- internal
depends_on:
- discourse
volumes:
- 'sidekiq_data:/bitnami/discourse'
- 'discourse_data:/bitnami/discourse'
command: /opt/bitnami/scripts/discourse-sidekiq/run.sh
secrets:
- db_password
environment:
- ALLOW_EMPTY_PASSWORD=yes
- DISCOURSE_HOST=${DOMAIN}
- DISCOURSE_DATABASE_HOST=db
- DISCOURSE_DATABASE_NAME=discourse
- DISCOURSE_DATABASE_PASSWORD_FILE=/run/secrets/db_password
- DISCOURSE_DATABASE_PORT_NUMBER=5432
- DISCOURSE_DATABASE_USER=discourse
- DISCOURSE_DATABASE_NAME=discourse
- DISCOURSE_HOST=${DOMAIN}
- DISCOURSE_REDIS_HOST=redis
- DISCOURSE_REDIS_PORT_NUMBER=6379
- DISCOURSE_DATABASE_PASSWORD_FILE=/run/secrets/db_password
- DISCOURSE_SMTP_HOST
- DISCOURSE_SMTP_PORT
- DISCOURSE_SMTP_USER
- DISCOURSE_SMTP_PROTOCOL
- DISCOURSE_SMTP_USER
- PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0
- DISCOURSE_SMTP_AUTH
secrets:
@ -107,9 +124,17 @@ volumes:
postgresql_data:
redis_data:
discourse_data:
sidekiq_data:
networks:
proxy:
external: true
internal:
configs:
db_entrypoint:
name: ${STACK_NAME}_db_entrypoint_${DB_ENTRYPOINT_VERSION}
file: entrypoint.postgres.sh.tmpl
template_driver: golang
pg_backup:
name: ${STACK_NAME}_pg_backup_${PG_BACKUP_VERSION}
file: pg_backup.sh

View File

@ -0,0 +1,64 @@
#!/bin/bash
set -e
OLDDATA=$PGDATA/old_data
NEWDATA=$PGDATA/new_data
echo "Running as $(id)"
# The migration uses $OLDDATA/$NEWDATA as scratch and removes them when it
# finishes; a leftover *empty* one means a run was interrupted before any data
# moved (data still intact at $PGDATA) so we clear it and retry, while a
# *non-empty* one means data may live only there, so we stop for manual recovery.
for scratch in $OLDDATA $NEWDATA; do
if [ -d "$scratch" ] && [ -n "$(ls -A "$scratch")" ]; then
echo "FATAL: $scratch exists and is not empty - a previous migration did not"
echo "complete and the data may only exist there. manual recovery necessary."
exit 1
fi
done
rm -rf $OLDDATA $NEWDATA
if [ -f $PGDATA/PG_VERSION ]; then
DATA_VERSION=$(cat $PGDATA/PG_VERSION)
if [ -n "$DATA_VERSION" -a "$PG_MAJOR" != "$DATA_VERSION" ]; then
echo "postgres data version $DATA_VERSION found, but need $PG_MAJOR. Starting migration"
echo "Installing postgres $DATA_VERSION"
sed -i "s/$/ $DATA_VERSION/" /etc/apt/sources.list.d/pgdg.list
apt-get update && apt-get install -y --no-install-recommends \
postgresql-$DATA_VERSION \
&& rm -rf /var/lib/apt/lists/*
# pg_upgrade must run as the old cluster's bootstrap superuser (the "install
# user", oid 10), and the new cluster must be initialised with that same
# user. It is not necessarily $POSTGRES_USER (e.g. clusters created with the
# default "postgres" superuser and a separate app role), so read it from the
# old cluster: briefly start it and ask, connecting as the app role we know.
PGBIN=/usr/lib/postgresql/$DATA_VERSION/bin
gosu postgres $PGBIN/pg_ctl -D $PGDATA -w \
-o "-c listen_addresses= -c unix_socket_directories=/tmp" start
INSTALL_USER=$(gosu postgres psql -h /tmp -U "$POSTGRES_USER" -d postgres -tAc \
"select rolname from pg_roles where oid = 10")
gosu postgres $PGBIN/pg_ctl -D $PGDATA -w stop
echo "old cluster install user: $INSTALL_USER"
echo "shuffling around"
gosu postgres mkdir $OLDDATA $NEWDATA
chmod 700 $OLDDATA $NEWDATA
mv $PGDATA/* $OLDDATA/ || true
echo "running initdb"
# abuse entrypoint script for initdb by making server error out; initialise
# the new cluster with the same superuser as the old one so pg_upgrade matches
gosu postgres bash -c "export PGDATA=$NEWDATA POSTGRES_USER=$INSTALL_USER ; /usr/local/bin/docker-entrypoint.sh --invalid-arg || true"
echo "running pg_upgrade"
cd /tmp
gosu postgres pg_upgrade --link -b /usr/lib/postgresql/$DATA_VERSION/bin -d $OLDDATA -D $NEWDATA -U $INSTALL_USER
cp $OLDDATA/pg_hba.conf $NEWDATA/
mv $NEWDATA/* $PGDATA
rm -rf $OLDDATA
rmdir $NEWDATA
echo "migration complete"
fi
fi
/usr/local/bin/docker-entrypoint.sh postgres

44
pg_backup.sh Executable file
View File

@ -0,0 +1,44 @@
#!/bin/bash
# Postgres backup/restore hook for the discourse `db` service.
set -e
BACKUP_FILE='/var/lib/postgresql/data/backup.sql'
export PGPASSWORD=$(cat "${POSTGRES_PASSWORD_FILE:-/run/secrets/db_password}")
DB_USER="${POSTGRES_USER:-discourse}"
DB_NAME="${POSTGRES_DB:-discourse}"
function backup {
pg_dump -U "$DB_USER" "$DB_NAME" | gzip > "$BACKUP_FILE"
}
function restore {
cd /var/lib/postgresql/data/
# Block all non-local connections so the running discourse app + sidekiq cannot reconnect and
# interfere with the drop/recreate/reimport. Restored on exit.
restore_hba() {
cat pg_hba.conf.bak > pg_hba.conf
rm -f pg_hba.conf.bak
su postgres -c 'pg_ctl reload'
}
cp pg_hba.conf pg_hba.conf.bak
echo 'local all all trust' > pg_hba.conf
su postgres -c 'pg_ctl reload'
trap restore_hba EXIT INT TERM
# terminate any lingering local sessions before recreate
# see https://stackoverflow.com/questions/5108876/kill-a-postgresql-session-connection
psql -U "$DB_USER" -d postgres -c \
"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='${DB_NAME}' AND pid<>pg_backend_pid();"
# drop database and then recreate it
psql -U "$DB_USER" -d postgres -c "DROP DATABASE ${DB_NAME} WITH (FORCE);"
createdb -U "$DB_USER" "$DB_NAME"
# reimport data
gunzip -c "$BACKUP_FILE" | psql -U "$DB_USER" -d "$DB_NAME" -1 -v ON_ERROR_STOP=1 -f -
}
$@