User Tools

Site Tools


wiki:discourse

This is an old revision of the document!


Discourse

Discourse is a modern, open-source discussion platform built for the next decade of the Internet. It functions as a mailing list, discussion forum, and long-form chat room, designed from the ground up to address the challenges of community management and online discussion.

Overview

Discourse is written in Ruby on Rails with an Ember.js frontend. It runs inside Docker containers, which simplifies deployment but creates opacity when deviating from the standard configuration. The platform emphasizes civilized discussion through features like trust levels, flagging systems, and moderation tools.

Key Characteristics:

  • Container-based deployment via Docker
  • Built-in PostgreSQL and Redis
  • Real-time updates via WebSockets
  • Plugin architecture for extensibility
  • Comprehensive backup/restore functionality

System Requirements

Component Minimum Recommended
RAM 1 GB 2+ GB
CPU 1 core 2+ cores
Storage 10 GB 20+ GB
OS Ubuntu 20.04+ Ubuntu 24.04 LTS

Architecture

Discourse ships as a monolithic Docker container containing:

  • PostgreSQL database
  • Redis for caching and background jobs
  • Sidekiq for job processing
  • Nginx (internal) for request handling
  • Ruby on Rails application server

The container exposes ports for HTTP/HTTPS traffic and handles TLS termination internally by default. However, production deployments frequently place Discourse behind a reverse proxy for flexibility in certificate management, load balancing, or multi-application hosting.

Installation

This section documents installation on a fresh Ubuntu server with backup restoration and nginx reverse proxy configuration.

Prerequisites

  • Fresh Ubuntu Server installation (24.04 LTS recommended)
  • Root or sudo access
  • Existing Discourse backup file (.tar.gz) if restoring
  • Domain name with DNS A record pointed to server IP
  • SMTP credentials for outbound email

Initial System Setup

sudo -s
apt-get update && apt-get install -y git

Clone Discourse Docker Repository

git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
chmod 700 containers

Configure for Reverse Proxy

Before running the setup script, create the container configuration. This step is critical—configuring after initial build requires a full rebuild.

Create /var/discourse/containers/app.yml with reverse proxy settings:

Comment out SSL templates:

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  ## SSL templates - COMMENTED OUT for reverse proxy setup
  # - "templates/web.ssl.template.yml"
  # - "templates/web.letsencrypt.ssl.template.yml"

Modify port exposure:

expose:
  - "8080:80"   # expose container port 80 on host port 8080
  # - "443:443" # https - commented out

<WRAP important> The 8080:80 mapping is not well-documented. The reverse proxy (nginx) handles TLS termination and forwards plaintext HTTP to port 8080. </WRAP>

Run Discourse Setup

./discourse-setup --skip-connection-test

The setup wizard prompts for configuration values:

Parameter Example Value Notes
Hostname forum.example.com Must match your DNS record
Developer Email admin@example.com Receives admin notifications
SMTP Server smtp.provider.com Your mail provider
SMTP Port 587 TLS submission port
SMTP Username smtp-user Provider credentials
SMTP Password smtp-pass Provider credentials
Notification Email noreply@example.com From address for emails
Let's Encrypt Email OFF Critical: Enter OFF for reverse proxy

<WRAP tip> The build process takes 5-15 minutes depending on hardware. </WRAP>

Restore from Backup

If restoring from an existing Discourse instance:

Transfer backup file to server:

scp -P 22 discourse-backup.tar.gz user@server:/var/discourse/shared/standalone/backups/default/

<WRAP info> Adjust the port (-P), username, and hostname to match your environment. Do NOT change the name of the file, as it is metadata necessary for the restore. </WRAP>

Restore via Admin Panel:

  1. Access Discourse at http://server-ip:8080 (or domain if DNS configured)
  2. Navigate to Admin → Backups
  3. Locate the uploaded backup file
  4. Click Restore and confirm

The restoration restarts Discourse and may take several minutes depending on backup size.

Install and Configure Nginx

apt-get install -y nginx

Create site configuration at /etc/nginx/sites-available/forum.example.com:

server {
    listen 80;
    server_name forum.example.com;
 
    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
 
        # WebSocket support (required for Discourse)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
 
        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
 
        # Buffering
        proxy_buffering off;
        proxy_redirect off;
    }
 
    client_max_body_size 10m;
}

Required headers for Discourse:

  • X-Forwarded-For and X-Forwarded-Host - Discourse uses these for client IP detection
  • WebSocket headers - Real-time updates require Upgrade and Connection headers
  • proxy_buffering off - Prevents response buffering issues

Enable the configuration:

rm /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/forum.example.com /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx

Configure TLS with Certbot

snap install --classic certbot
certbot

Certbot automatically:

  • Detects the nginx configuration
  • Prompts for domain selection
  • Generates Let's Encrypt certificates
  • Modifies nginx for HTTPS
  • Configures automatic renewal

Reload nginx after certificate installation:

systemctl reload nginx

Configuration

Environment Variables

Key environment variables in app.yml:

Variable Purpose
DISCOURSE_HOSTNAME Primary domain name
DISCOURSE_DEVELOPER_EMAILS Admin notification recipients
DISCOURSE_SMTP_ADDRESS Mail server hostname
DISCOURSE_SMTP_PORT Mail server port
DISCOURSE_SMTP_USER_NAME SMTP authentication user
DISCOURSE_SMTP_PASSWORD SMTP authentication password
DISCOURSE_DB_SHARED_BUFFERS PostgreSQL memory allocation

Rebuild Container

After modifying app.yml:

cd /var/discourse
./launcher rebuild app

Maintenance

Common Commands

# Enter container shell
./launcher enter app
 
# View logs
./launcher logs app
 
# Stop/start container
./launcher stop app
./launcher start app
 
# Full rebuild
./launcher rebuild app

Backup Configuration

Backups can be configured in Admin → Backups → Settings:

  • Enable automatic backups
  • Set retention period
  • Configure S3 upload (optional)

Troubleshooting

Nginx Shows Default Page

  • Verify default site removed: ls /etc/nginx/sites-enabled/
  • Confirm symlink exists: ls -la /etc/nginx/sites-enabled/forum.example.com
  • Test configuration: nginx -t
  • Reload: systemctl reload nginx

SSL Certificate Errors

  • Run nginx test with sudo: sudo nginx -t
  • Check for configs referencing non-existent certificates
  • Ensure only HTTP config exists before running certbot

Backup Not Visible

  • Verify file location: /var/discourse/shared/standalone/backups/default/
  • Check permissions: ls -la /var/discourse/shared/standalone/backups/default/
  • Confirm filename ends in .tar.gz

SCP Syntax

  • Port flag is capital -P (not lowercase -p)
  • Syntax: scp -P <port> <source> <user>@<host>:<destination>

API

<WRAP center round important 60%> AUTO-GENERATED DOCUMENTATION

This section was automatically generated and is subject to change upon human review. Last updated: 2026-01-19 </WRAP>

Discourse Chat API Endpoints

Channel Operations

  • List channels: GET /chat/api/channels
  • Get specific channel: GET /chat/api/channels/{channel_id}
  • Send message: POST /chat/api/channels/{channel_id}/messages
  • List messages: GET /chat/api/channels/{channel_id}/messages

Authentication Headers

All API requests require the following headers:

Api-Key: {your_api_key}
Api-Username: {username}
Content-Type: application/json

Webhook Endpoints

Configured Webhooks

hobbiesync webhook:

https://meant2be.me/chat/hooks/5531852aa82a4943640bf3e1

general webhook:

https://meant2be.me/chat/hooks/e46b530c26a076349724421c

Webhook Event Types

Available webhook triggers include:

  • Chat message created
  • Chat message edited
  • Chat message trashed
  • Chat message restored
  • Post events (for forum integration)
  • User events (login/logout/created)

Avatar URL Extraction

Avatar URLs are provided in the avatar_template field of user objects in API responses.

Response Structure

{
  "user": {
    "id": 2,
    "username": "Chelsea",
    "name": "Chelsea Lee ᶘ ᵒᴥᵒᶅ",
    "avatar_template": "/user_avatar/meant2be.me/chelsea/{size}/3_2.png"
  }
}

Building Avatar URLs

Pattern:

{base_url}{avatar_template with {size} replaced}

Example:

https://meant2be.me/user_avatar/meant2be.me/chelsea/48/3_2.png

Supported sizes: 20, 25, 32, 45, 48, 60, 90, 120, 135, 240, 360, 480

Recommended for Discord: 128 or 256

Python Implementation

def get_avatar_url(user_obj, size=48):
    """Extract and construct full avatar URL from Discourse user object"""
    template = user_obj['avatar_template']
    avatar_path = template.replace('{size}', str(size))
    return f"https://meant2be.me{avatar_path}"
 
# Usage:
avatar_url = get_avatar_url(message['user'], size=128)

Bridge Architecture

Data Flow

Discourse → Discord (via webhooks):

  1. Webhook events trigger on chat message actions
  2. Webhook receiver endpoints process incoming events
  3. Forward to Discord via webhook or bot API

Discord → Discourse (via API):

  1. Discord bot listens for message events
  2. POST to /chat/api/channels/{channel_id}/messages
  3. Payload: {“message”: “text content”}

Implementation Considerations

  • Message ID mapping: Track Discourse ↔ Discord message IDs to prevent echo loops
  • User mapping: Map Discourse usernames to Discord user representations
  • Avatar sync: Use extracted avatar URLs for Discord webhooks
  • Category filtering: Configure webhooks for specific categories/channels
  • Loop prevention: Maintain state to avoid infinite message echoes between platforms

Chat Messages Response

{
  "messages": [
    {
      "id": 77045,
      "message": ":eyes:",
      "created_at": "2025-12-23T00:30:23Z",
      "chat_channel_id": 1,
      "user": {
        "id": 2,
        "username": "Chelsea",
        "name": "Chelsea Lee ᶘ ᵒᴥᵒᶅ",
        "avatar_template": "/user_avatar/meant2be.me/chelsea/{size}/3_2.png",
        "moderator": true,
        "admin": true,
        "staff": true
      }
    }
  ],
  "meta": {
    "can_load_more_future": false,
    "can_load_more_past": false
  }
}

References

See Also

wiki/discourse.1768897649.txt.gz · Last modified: by chelsea · Currently locked by: 216.73.216.38