# app/discourse

> 使用 Pigsty 托管的 PostgreSQL 部署 Discourse 社区论坛，应用容器内嵌 Redis

---

LLMS 索引： [llms.txt](/llms.txt)

---

`app/discourse` 配置模板提供 Discourse 社区论坛的单节点参考配置：PostgreSQL 由 Pigsty 托管，Redis 内嵌在应用容器中，经 Pigsty Nginx 与 Unix Socket 对外提供服务。

该模板在 v4.5.0 发布后加入，需配套同版本的 `app/discourse/` 与 `files/discourse.sql`，不能只复制下方 YAML。

更多细节，请参考 **[Discourse 部署教程](/docs/app/discourse/)**


--------

## 配置概览

- 配置名称： `app/discourse`
- 节点数量： 单节点
- 配置说明：使用 Pigsty 托管的 PostgreSQL 部署 Discourse 论坛，Redis 内嵌在应用容器中
- 适用系统：`el8`, `el9`, `el10`, `d12`, `d13`, `u22`, `u24`, `u26`
- 适用架构：`x86_64`（上游 Launcher 将 ARM64 支持描述为实验性）
- 相关配置：[`app/odoo`](/docs/conf/odoo/)、[`app/mattermost`](/docs/conf/mattermost/)

启用方式：

```bash
./configure -c app/discourse [-i <primary_ip>]
vi pigsty.yml              # 修改密码、域名与 SMTP
./deploy.yml
./docker.yml
./app.yml -l discourse
```


--------

## 配置内容

源文件地址：[`pigsty/conf/app/discourse.yml`](https://github.com/pgsty/pigsty/blob/main/conf/app/discourse.yml)

```yaml
---
#==============================================================#
# File      :   discourse.yml
# Desc      :   Pigsty Discourse with external PostgreSQL / embedded Redis
# Ctime     :   2026-10-14
# Mtime     :   2026-10-14
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)
#==============================================================#
# Fresh host: ./configure -c app/discourse; edit pigsty.yml (passwords + SMTP)
# ./deploy.yml; ./docker.yml; ./app.yml -l discourse
# Existing Pigsty: merge the app/user/database/portal sections; do NOT replace
# the running inventory or initialize an existing PostgreSQL cluster again.
# ask.pigsty -> Pigsty Nginx :80/:443 -> Unix socket -> Discourse + Redis.

all:
  children:
    discourse:
      hosts: { 10.10.10.10: {} }
      vars:
        app: discourse
        apps:
          discourse:
            dest: /data/app/discourse
            file:
              - { path: /data/app/discourse                    ,state: directory ,mode: '0755' }
              - { path: /data/app/discourse/shared             ,state: directory ,mode: '0755' }
              - { path: /data/app/discourse/shared/log/var-log ,state: directory ,mode: '0755' }
            conf:
              DISCOURSE_DATA: /data/app/discourse
              DISCOURSE_HOSTNAME: ask.pigsty
              DISCOURSE_VERSION: tests-passed
              DISCOURSE_DOCKER_REF: 945d491ee62ac0d6e5d9076c173073c3f795d978
              PG_HOST: 10.10.10.10
              PG_PORT: 5432
              PG_DBNAME: discourse
              PG_USERNAME: discourse
              PG_PASSWORD: DBUser.Discourse
              UNICORN_WORKERS: 2
              UNICORN_SIDEKIQS: 1
              DISCOURSE_SIDEKIQ_WORKERS: 5
              DISCOURSE_DB_POOL: 8
              REDIS_MAX_MEMORY: 512mb
              DISCOURSE_FORCE_HTTPS: false  # set true with a trusted HTTPS portal
              DISCOURSE_DEVELOPER_EMAILS: admin@example.com  # CHANGE ME
              DISCOURSE_SMTP_ADDRESS: smtp.example.com       # CHANGE ME
              DISCOURSE_SMTP_PORT: 587
              DISCOURSE_SMTP_USER_NAME: ''
              DISCOURSE_SMTP_PASSWORD: ''
              DISCOURSE_SMTP_ENABLE_START_TLS: true
              DISCOURSE_SMTP_FORCE_TLS: false
              DISCOURSE_NOTIFICATION_EMAIL: noreply@example.com  # CHANGE ME

    pg-discourse:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-discourse
        pg_extensions: [ pgvector ]
        pg_users:
          - name: discourse
            password: DBUser.Discourse  # CHANGE ME, same as PG_PASSWORD above
            pgbouncer: false
            roles: [{ name: dbrole_admin, state: revoke }]
            comment: Discourse database owner
        pg_databases:
          - name: discourse
            owner: discourse
            encoding: UTF8
            revokeconn: true
            pgbouncer: false
            baseline: discourse.sql
            extensions: [ hstore, pg_trgm, unaccent, vector ]
            comment: Discourse forum
        pg_hba_rules:
          - { user: discourse ,db: discourse ,addr: 172.16.0.0/12 ,auth: pwd ,title: 'Discourse from local Docker bridges' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

  vars:
    version: v4.5.0
    admin_ip: 10.10.10.10
    region: default
    node_tune: oltp
    pg_conf: oltp.yml
    pg_version: 18
    docker_enabled: true
    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    node_etc_hosts: ['${admin_ip} i.pigsty ask.pigsty']
    infra_portal:
      home: { domain: i.pigsty }
      discourse:
        domain: ask.pigsty
        endpoint: unix:/data/app/discourse/shared/nginx.http.sock
        websocket: true
        config: |
          client_max_body_size 10m;

    # CHANGE these demo credentials before any public deployment.
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    etcd_root_password: Etcd.Root
...
```


--------

## 配置解读

此单节点模板使用官方经典 Launcher 在本地构建 Discourse 镜像，由 Docker Compose 运行，PostgreSQL 由 Pigsty 管理。

**关键特性**：

- `apps.discourse.dest` 为 `/data/app/discourse`，管理文件与 `shared/` 下的持久化数据位于同一目录
- `DISCOURSE_DOCKER_REF` 固定 Launcher 提交，`DISCOURSE_VERSION` 默认跟随官方 `tests-passed` 通道
- 独立的 `pg-discourse` 集群使用 PostgreSQL 18，安装 `pgvector`；`discourse` 数据库启用 `hstore`、`pg_trgm`、`unaccent`、`vector` 扩展，并应用 `discourse.sql` 基线
- `discourse` 用户撤销 `dbrole_admin`，用户与数据库均不接入 PgBouncer
- HBA 只允许 `discourse` 用户从 `172.16.0.0/12` Docker 网段访问 `discourse` 数据库
- Nginx 门户 `ask.pigsty` 转发到 `unix:/data/app/discourse/shared/nginx.http.sock`，启用 WebSocket，并设置 `client_max_body_size 10m`
- 内嵌 Redis 的内存上限为 `REDIS_MAX_MEMORY: 512mb`
- 每天凌晨 1 点执行一次全量备份

**访问方式**：

```bash
http://ask.pigsty
```

模板通过 `node_etc_hosts` 在本机将 `ask.pigsty` 解析到管理节点；其他客户端需自行将该域名解析到 Nginx 主机。

**注意事项**：

- 部署前修改 `PG_PASSWORD` 与 `pg_users` 中的密码（两处保持一致），以及管理员邮箱与 SMTP 参数；示例 SMTP 主机会使构建失败
- 公开部署使用真实域名与可信证书，并设置 `DISCOURSE_FORCE_HTTPS: true`
- Discourse 使用 advisory lock，需直连 PostgreSQL，不能使用 PgBouncer 事务池；高可用部署改用只指向主库的直连入口
- 已有 Pigsty 环境只合并应用、用户、数据库与门户定义，不要重新运行 `configure` 或重复初始化集群
- Redis 持久化需要 `vm.overcommit_memory=1`，而 `node_tune: oltp` 对应的 Tuned 配置为 `0`，模板尚未处理，需自行配置持久化覆盖
