Social intermediate ⏱ 60 minutes

Discourse: Modern Forum Platform

Full-featured community forum software. Email integration, plugins, and moderation tools.

By Homelab Team • 2025-01-15
#discourse#forum#community#discussion#docker

Introduction

Discourse represents the evolution of forum software for the modern web. Unlike traditional forums that feel stuck in the 2000s, Discourse delivers a fast, mobile-friendly experience that encourages healthy community discussions. Used by communities ranging from developer forums to product support sites, it combines the best of traditional forums with modern social features.

What you’ll learn:

  • Deploy Discourse using the official Docker container
  • Configure email for notifications and user registration
  • Set up SSL/TLS with automatic certificate renewal
  • Customize appearance and branding
  • Configure moderation tools and spam protection
  • Integrate with external authentication providers
  • Optimize performance for high traffic
  • Implement backup and recovery procedures

Prerequisites:

  • Linux server (Ubuntu 22.04+ recommended) with 2GB+ RAM, 2+ CPU cores
  • Root or sudo access
  • Domain name with DNS configured
  • Port 80 and 443 available and accessible
  • Basic Linux command line knowledge
  • Email service (SMTP) for sending notifications
  • At least 40GB storage space

Why Discourse?

The Traditional Forum Problem

Traditional forum software (phpBB, vBulletin, SMF) suffers from:

  • Outdated UX: Interfaces designed for desktop browsers from 15 years ago
  • Poor Mobile Support: Not responsive, difficult to use on phones
  • Complex Administration: Convoluted admin panels with hundreds of settings
  • Security Issues: Frequent vulnerabilities due to old codebases
  • Slow Performance: Page reloads for every action
  • Limited Engagement: No real-time notifications or modern social features

How Discourse Solves This

Discourse is built from the ground up for modern web standards:

FeatureDiscourseTraditional Forums
Mobile ExperienceNative-quality responsive designBasic mobile version
Real-time UpdatesLive notifications, infinite scrollPage refreshes
Markdown SupportFull Markdown, code syntax highlightingBBCode or HTML
Spam ProtectionAkismet, trust levels, auto-moderationManual moderation
SEOExcellent (single-page app with server rendering)Good
PerformanceRedis cache, Ember.js frontendDatabase-heavy
UpdatesSimple Docker-based updatesComplex manual process
Email IntegrationReply to posts via emailBasic notifications

Key Features

For Users:

  • Clean, intuitive interface that works perfectly on any device
  • Real-time notifications and live updates
  • Rich text editing with Markdown and emoji support
  • User mentions, quotes, and threaded discussions
  • Powerful search with filters and categories
  • User profiles with badges and trust levels
  • Private messaging between users

For Moderators:

  • Automated spam detection and filtering
  • Trust level system that grants permissions as users participate
  • Flag system for community-driven moderation
  • Detailed moderation queue and audit logs
  • User silencing, suspension, and ban tools
  • Rate limiting and flood prevention

For Administrators:

  • Single Docker container deployment
  • Automatic security updates
  • Built-in CDN and image optimization
  • Plugin system for extensibility
  • SSO integration (OAuth2, SAML, LDAP)
  • Comprehensive analytics dashboard

Architecture Overview

Discourse uses a simplified architecture built around Docker:

Internet → Reverse Proxy (built-in) → Discourse Rails App → PostgreSQL
                ↓                            ↓                    ↓
           HTTPS (Let's Encrypt)        Sidekiq Workers        Redis Cache
                                             ↓
                                        Email Queue (SMTP)

Components:

  • Discourse App: Ruby on Rails backend + Ember.js frontend
  • PostgreSQL: Database for all content and users
  • Redis: Cache and message queue for background jobs
  • Sidekiq: Background job processor for emails, notifications
  • Nginx: Built-in reverse proxy with automatic SSL
  • Docker: All components run in a single managed container

Installation

Discourse uses a unique launcher script that manages Docker deployment. This approach simplifies updates and configuration.

Step 1: Prepare the Server

# Update system packages
sudo apt update && sudo apt upgrade -y

# Install Docker if not already installed
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Start and enable Docker
sudo systemctl start docker
sudo systemctl enable docker

# Create discourse directory
sudo mkdir -p /var/discourse
cd /var/discourse

Step 2: Download Discourse

# Clone the official Discourse Docker repository
sudo git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse

# Make launcher executable
sudo chmod +x launcher

Step 3: Configure Discourse

Run the setup wizard to create your configuration:

# Start interactive setup
sudo ./discourse-setup

The setup wizard will ask you for:

1. Hostname:

Hostname for your Discourse? [discourse.example.com]: forum.yourdomain.com

Enter your actual domain name.

2. Email address for admin:

Email address for admin account: [email protected]

This will be your admin account.

3. SMTP settings:

SMTP server address? [smtp.example.com]: smtp.sendgrid.net
SMTP port? [587]: 587
SMTP user name? [[email protected]]: apikey
SMTP password? [pa$$word]: YOUR_SENDGRID_API_KEY

Common SMTP providers:

  • SendGrid: smtp.sendgrid.net:587 (100 emails/day free)
  • Mailgun: smtp.mailgun.org:587 (5,000 emails/month free)
  • Gmail: smtp.gmail.com:587 (use App Password)
  • AWS SES: email-smtp.region.amazonaws.com:587
  • Self-hosted: your-mail-server.com:587

4. Let’s Encrypt email:

Let's Encrypt account email? [[email protected]]: [email protected]

Used for SSL certificate notifications.

5. Optional CDN:

Optional Maxmind License key: [press enter to skip]

Press Enter to skip for now.

Step 4: Review Configuration

Before building, review the generated config:

# Edit configuration if needed
sudo nano containers/app.yml

Key sections in app.yml:

## Email Settings
env:
  DISCOURSE_SMTP_ADDRESS: smtp.sendgrid.net
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: apikey
  DISCOURSE_SMTP_PASSWORD: "YOUR_API_KEY"
  DISCOURSE_SMTP_ENABLE_START_TLS: true

## Site Settings
  DISCOURSE_HOSTNAME: forum.yourdomain.com
  DISCOURSE_DEVELOPER_EMAILS: [email protected]

## Database and Redis (managed automatically)
  DISCOURSE_DB_HOST: ""
  DISCOURSE_REDIS_HOST: ""

## Let's Encrypt SSL
  LETSENCRYPT_ACCOUNT_EMAIL: [email protected]

## Expose ports
expose:
  - "80:80"   # HTTP (redirects to HTTPS)
  - "443:443" # HTTPS

## Resource limits
resources:
  memory: 2G
  cpu: 2

Step 5: Build and Launch

# Build the container (takes 10-15 minutes)
sudo ./launcher bootstrap app

# Start Discourse
sudo ./launcher start app

# Check status
sudo ./launcher logs app

After building completes, visit https://forum.yourdomain.com to see your forum!

Step 6: Complete Admin Setup

  1. Check your email for the admin account creation link
  2. Click the activation link and set your password
  3. Complete the setup wizard in the browser:
    • Set site title and description
    • Choose homepage style
    • Configure categories
    • Customize colors and logo

Email Configuration

Email is critical for Discourse. Without working email, users cannot register or receive notifications.

Testing Email Configuration

# Enter the Rails console
sudo ./launcher enter app
rails c

# Test email sending
Email.test_email('[email protected]').deliver_now

# Exit console
exit
exit

Check your inbox for the test email. If it doesn’t arrive:

# Check logs for email errors
sudo ./launcher logs app | grep -i mail
sudo ./launcher logs app | grep -i smtp

Common Email Providers Setup

SendGrid (Recommended for beginners):

  1. Sign up at sendgrid.com (100 emails/day free)
  2. Create an API key (Settings → API Keys)
  3. Use these settings:
DISCOURSE_SMTP_ADDRESS: smtp.sendgrid.net
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: apikey
DISCOURSE_SMTP_PASSWORD: YOUR_SENDGRID_API_KEY
DISCOURSE_SMTP_AUTHENTICATION: plain
DISCOURSE_SMTP_ENABLE_START_TLS: true

Mailgun:

  1. Sign up at mailgun.com
  2. Add and verify your domain
  3. Get SMTP credentials from dashboard
DISCOURSE_SMTP_ADDRESS: smtp.mailgun.org
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: postmaster@your-domain.mailgun.org
DISCOURSE_SMTP_PASSWORD: YOUR_MAILGUN_PASSWORD

Gmail (For testing only):

  1. Enable 2FA on your Google account
  2. Generate an App Password (Security → App Passwords)
  3. Use these settings:
DISCOURSE_SMTP_ADDRESS: smtp.gmail.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: your-[email protected]
DISCOURSE_SMTP_PASSWORD: YOUR_APP_PASSWORD
DISCOURSE_SMTP_AUTHENTICATION: plain
DISCOURSE_SMTP_ENABLE_START_TLS: true

Note: Gmail has sending limits and may flag your forum emails as spam.

Self-Hosted Mail Server:

DISCOURSE_SMTP_ADDRESS: mail.yourdomain.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: [email protected]
DISCOURSE_SMTP_PASSWORD: YOUR_PASSWORD
DISCOURSE_SMTP_AUTHENTICATION: plain
DISCOURSE_SMTP_ENABLE_START_TLS: true

Receiving Email (Reply by Email)

Enable users to reply to topics via email:

# Edit app.yml
sudo nano containers/app.yml

Add these environment variables:

env:
  # Receiving email settings
  DISCOURSE_REPLY_BY_EMAIL_ADDRESS: "replies+%{reply_key}@yourdomain.com"
  DISCOURSE_POP3_POLLING_ENABLED: "true"
  DISCOURSE_POP3_POLLING_HOST: "mail.yourdomain.com"
  DISCOURSE_POP3_POLLING_PORT: "995"
  DISCOURSE_POP3_POLLING_USERNAME: "[email protected]"
  DISCOURSE_POP3_POLLING_PASSWORD: "YOUR_PASSWORD"
  DISCOURSE_POP3_POLLING_SSL: "true"

Rebuild after changes:

sudo ./launcher rebuild app

Customization and Branding

Appearance Settings

Navigate to Admin → Customize → Themes

Upload Logo:

  • Admin → Settings → Required → logo
  • Recommended size: 250x60 pixels, transparent PNG
  • Small logo for mobile: 36x36 pixels

Colors and Styling:

  1. Go to Admin → Customize → Colors
  2. Create a new color scheme or edit default
  3. Customize primary, secondary, tertiary colors
  4. Preview changes in real-time

Custom CSS:

/* Add in Admin → Customize → Themes → Edit CSS */

/* Custom header background */
.d-header {
  background-color: #2c3e50;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

/* Category badges */
.badge-category {
  font-weight: 600;
  border-radius: 4px;
}

/* Custom button colors */
.btn-primary {
  background-color: #3498db;
  border-color: #2980b9;
}

/* Mobile-friendly spacing */
@media (max-width: 768px) {
  .topic-body {
    padding: 10px;
  }
}

Site Settings

Essential settings to configure:

General:

  • Admin → Settings → Basic Setup
    • Site name: “Your Community Forum”
    • Site description: “A place for…”
    • Contact email: ”[email protected]”
    • Homepage style: Categories, Latest, or Custom

Users:

  • Admin → Settings → Users
    • Enable user registration
    • Require approval for new accounts (for private communities)
    • Min password length: 10+ recommended
    • Enable user profiles

Content:

  • Admin → Settings → Posting
    • Min post length: 20 characters
    • Max post length: 32000 characters
    • Allow uploads: Enable
    • Max attachment size: 10MB (adjust as needed)

Categories and Structure

Creating Categories

Categories organize your forum content:

  1. Go to Admin → Categories
  2. Click “New Category”
  3. Configure:
    • Name: “General Discussion”
    • Color: Choose from palette
    • Description: “General topics and chat”
    • Parent category: None (or select parent)
    • Permissions: Everyone can create/reply/see

Example Category Structure:

📢 Announcements (Read-only for members, post by staff)
💬 General Discussion
  ├── 🎯 Getting Started
  └── 💡 Ideas and Suggestions
🛠️ Technical Support
  ├── 🐛 Bug Reports
  └── ❓ How-To Questions
📚 Resources
  ├── 📖 Documentation
  └── 🎓 Tutorials
🎮 Off-Topic

Category Permissions

Fine-tune who can access what:

  1. Edit category → Security
  2. Set permissions for groups:
    • See: Who can view the category
    • Create: Who can start new topics
    • Reply: Who can reply to topics

Example permissions:

Announcements:
  Everyone: See, Reply
  Staff: Create, Reply, See

Private Staff Category:
  Staff: Create, Reply, See
  Moderators: Create, Reply, See

User Management and Trust Levels

Trust Level System

Discourse uses trust levels to automatically grant privileges:

Trust Level 0 (New User):

  • Limited posts per day
  • Links are nofollow
  • Cannot upload images
  • Cannot send private messages

Trust Level 1 (Basic User):

  • Earned after: Reading posts, time on site
  • Can upload images
  • Can send private messages
  • More likes per day

Trust Level 2 (Member):

  • Earned after: Days visited, posts read, topics created
  • Can invite users
  • Edit wiki posts
  • More daily actions

Trust Level 3 (Regular):

  • Earned after: Sustained participation over 100 days
  • Can recategorize topics
  • Can rename topics
  • First line of community moderation

Trust Level 4 (Leader):

  • Manually granted by admins
  • Can edit any post
  • Can pin/unpin topics
  • Can close/archive topics
  • Full moderation powers

Managing Users

Create User Manually:

# Via Rails console
sudo ./launcher enter app
rails c

# Create admin user
User.create!(
  email: '[email protected]',
  username: 'newadmin',
  password: 'secure_password_here',
  active: true,
  approved: true,
  admin: true
)

exit
exit

Promote User to Admin:

  • Admin → Users → Find user → Expand
  • Click “Grant Admin” or “Grant Moderator”

Suspend User:

  • Visit user profile → Admin → Suspend
  • Set duration and reason
  • User cannot log in during suspension

Silence User:

  • User profile → Admin → Silence
  • User can browse but cannot post/reply
  • Less severe than suspension

Moderation Tools

Automated Moderation

Enable Spam Protection:

  1. Admin → Settings → Security
  2. Enable “use spam filter”
  3. Add Akismet API key (get from akismet.com)
# In app.yml, add:
env:
  DISCOURSE_AKISMET_API_KEY: YOUR_AKISMET_KEY

Configure Auto-Moderation:

  • Admin → Settings → Spam
    • New user spam host threshold: 3
    • Unique posts minimum: 2
    • Auto silence first post suspects: Enable

Manual Moderation

Review Queue:

  • Admin → Review → Queued posts
  • Approve or reject flagged content
  • See reasons for flags

Flag System: Users can flag inappropriate content:

  • Spam
  • Inappropriate
  • Off-topic
  • Something else (custom reason)

Flags appear in moderation queue for staff review.

Common Moderation Actions:

# Hide post (remove from view)
Post → ... → Hide → Reason

# Delete user and all posts
User → Admin → Delete User → Also delete posts

# Merge duplicate topics
Topic → Wrench → Select posts → Move to

# Split topic
Topic → Wrench → Select posts → Create new topic

Plugins and Extensions

1. Discourse Chat (Official): Real-time chat alongside forum topics

# Enable in Admin → Plugins → Chat
# Or rebuild with plugin in app.yml

2. Discourse Calendar: Events and meeting scheduling

# Add to app.yml under hooks:
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/discourse-calendar.git

# Rebuild
sudo ./launcher rebuild app

3. Solved Plugin: Mark topics as solved (great for support forums)

# Add plugin
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/discourse-solved.git

sudo ./launcher rebuild app

4. Voting Plugin: Allow voting on topics (feature requests)

# Add plugin
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/discourse-voting.git

sudo ./launcher rebuild app

Installing Plugins

General process:

  1. Edit containers/app.yml
  2. Add plugin to hooks section:
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/PLUGIN-NAME.git
  1. Rebuild: sudo ./launcher rebuild app
  2. Enable in Admin → Plugins

Performance Optimization

Resource Requirements

Minimum (Small forum, 100 active users):

  • 2GB RAM
  • 2 CPU cores
  • 40GB storage
  • 10Mbps network

Recommended (Medium forum, 1000+ active users):

  • 4GB RAM
  • 4 CPU cores
  • 100GB storage
  • 100Mbps network

Caching Configuration

Discourse uses Redis extensively. Increase cache if needed:

# In app.yml
env:
  DISCOURSE_REDIS_MAXMEMORY: "256mb"
  DISCOURSE_REDIS_MAXMEMORY_POLICY: "allkeys-lru"

Database Optimization

# Enter PostgreSQL
sudo ./launcher enter app
su - postgres
psql discourse

# Vacuum and analyze
VACUUM ANALYZE;

# Check database size
SELECT pg_size_pretty(pg_database_size('discourse'));

# Exit
q
exit
exit

CDN Setup

Use a CDN for static assets:

  1. Admin → Settings → Files
  2. Enable “use s3 cdn”
  3. Configure S3 bucket or CloudFlare CDN
  4. Set CDN URL

Backup and Recovery

Automatic Backups

Enable automatic backups:

  1. Admin → Backups
  2. Enable “automatic backups enabled”
  3. Set frequency: Daily recommended
  4. Set retention: Keep 7 days
  5. Backup location: Local or S3

S3 Backup Configuration:

# In app.yml
env:
  DISCOURSE_S3_BACKUP_BUCKET: "discourse-backups"
  DISCOURSE_S3_ACCESS_KEY_ID: "YOUR_ACCESS_KEY"
  DISCOURSE_S3_SECRET_ACCESS_KEY: "YOUR_SECRET_KEY"
  DISCOURSE_S3_REGION: "us-east-1"

Manual Backup

# Create backup via command line
sudo ./launcher enter app
discourse backup

# Backups stored in /var/discourse/shared/standalone/backups/default/
exit

# Copy backup to local machine
sudo scp /var/discourse/shared/standalone/backups/default/BACKUP-FILE.tar.gz user@local:/backups/

Restore from Backup

# Copy backup to server
sudo scp backup-file.tar.gz user@server:/var/discourse/shared/standalone/backups/default/

# Restore via web UI
# Admin → Backups → Upload → Select file → Restore

# Or via command line
sudo ./launcher enter app
discourse restore BACKUP-FILE.tar.gz
exit

Troubleshooting

Common Issues

Issue: Email not sending

# Check SMTP settings
sudo ./launcher logs app | grep -i smtp

# Test email
sudo ./launcher enter app
rails c
Email.test_email('[email protected]').deliver_now
exit
exit

Issue: Can’t access admin account

# Reset admin password
sudo ./launcher enter app
rails c
u = User.find_by_email('[email protected]')
u.password = 'newpassword123'
u.save!
exit
exit

Issue: Container won’t start

# Check logs
sudo ./launcher logs app

# Check Docker status
sudo docker ps -a

# Rebuild container
sudo ./launcher rebuild app

Issue: Out of memory

# Check memory usage
free -h

# Increase swap space
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Issue: Slow performance

# Rebuild with updated configs
sudo ./launcher rebuild app

# Check database
sudo ./launcher enter app
rails c
ActiveRecord::Base.connection.execute("VACUUM ANALYZE")
exit
exit

Debug Mode

Enable debug logging:

# In app.yml
env:
  DISCOURSE_LOG_LEVEL: "debug"

Rebuild and check detailed logs:

sudo ./launcher rebuild app
sudo ./launcher logs app

Updating Discourse

Discourse updates frequently with security patches and features.

Update Process

# Navigate to discourse directory
cd /var/discourse

# Pull latest launcher
sudo git pull

# Rebuild container (includes updates)
sudo ./launcher rebuild app

The rebuild process:

  1. Backs up current version
  2. Pulls latest Discourse code
  3. Runs database migrations
  4. Compiles assets
  5. Restarts with new version

Typically takes 10-15 minutes.

Version Pinning

To pin a specific version:

# In app.yml
templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"

# Add version
env:
  version: v3.1.3

Conclusion

You now have a fully functional Discourse forum with:

  • Secure HTTPS with automatic certificate renewal
  • Working email notifications
  • Customized branding and appearance
  • Moderation tools configured
  • Automated backups enabled
  • Performance optimizations applied

Next Steps

  1. Create your category structure based on your community needs
  2. Invite initial members to seed discussions
  3. Set up integrations (Slack, Discord, webhooks)
  4. Install useful plugins for your use case
  5. Monitor performance and adjust resources
  6. Regular backups - test restoration process

Resources

Your forum is ready to build and engage your community!