# Update packages and -weight: 500;">install prerequisites
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">upgrade -y
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install -y -weight: 500;">git -weight: 500;">curl -weight: 500;">wget # Discourse uses Docker, so -weight: 500;">install that
-weight: 500;">curl -fsSL https://get.-weight: 500;">docker.com -o get--weight: 500;">docker.sh
sh get--weight: 500;">docker.sh
# Update packages and -weight: 500;">install prerequisites
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">upgrade -y
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install -y -weight: 500;">git -weight: 500;">curl -weight: 500;">wget # Discourse uses Docker, so -weight: 500;">install that
-weight: 500;">curl -fsSL https://get.-weight: 500;">docker.com -o get--weight: 500;">docker.sh
sh get--weight: 500;">docker.sh
# Update packages and -weight: 500;">install prerequisites
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">upgrade -y
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install -y -weight: 500;">git -weight: 500;">curl -weight: 500;">wget # Discourse uses Docker, so -weight: 500;">install that
-weight: 500;">curl -fsSL https://get.-weight: 500;">docker.com -o get--weight: 500;">docker.sh
sh get--weight: 500;">docker.sh
# Clone the official Docker deployment repo
-weight: 600;">sudo -s
-weight: 500;">git clone https://github.com/discourse/discourse_docker.-weight: 500;">git /var/discourse
cd /var/discourse # Run the interactive setup
./discourse-setup
# Clone the official Docker deployment repo
-weight: 600;">sudo -s
-weight: 500;">git clone https://github.com/discourse/discourse_docker.-weight: 500;">git /var/discourse
cd /var/discourse # Run the interactive setup
./discourse-setup
# Clone the official Docker deployment repo
-weight: 600;">sudo -s
-weight: 500;">git clone https://github.com/discourse/discourse_docker.-weight: 500;">git /var/discourse
cd /var/discourse # Run the interactive setup
./discourse-setup
# /var/discourse/containers/app.yml
templates: - "templates/postgres.template.yml" - "templates/redis.template.yml" - "templates/web.template.yml" - "templates/web.ratelimited.template.yml" - "templates/web.socketed.template.yml" # add this if using a reverse proxy params: db_default_text_search_config: "pg_catalog.english" env: LC_ALL: en_US.UTF-8 LANG: en_US.UTF-8 LANGUAGE: en_US.UTF-8 DISCOURSE_DEFAULT_LOCALE: en DISCOURSE_HOSTNAME: 'forum.yourdomain.com' DISCOURSE_DEVELOPER_EMAILS: '[email protected]' DISCOURSE_SMTP_ADDRESS: smtp.yourmailprovider.com DISCOURSE_SMTP_PORT: 587 DISCOURSE_SMTP_USER_NAME: your-smtp-user DISCOURSE_SMTP_PASSWORD: your-smtp-password # Uncomment the next line if you're behind a reverse proxy # DISCOURSE_SMTP_ENABLE_START_TLS: true volumes: - volume: host: /var/discourse/shared/standalone guest: /shared - volume: host: /var/discourse/shared/standalone/log/var-log guest: /var/log
# /var/discourse/containers/app.yml
templates: - "templates/postgres.template.yml" - "templates/redis.template.yml" - "templates/web.template.yml" - "templates/web.ratelimited.template.yml" - "templates/web.socketed.template.yml" # add this if using a reverse proxy params: db_default_text_search_config: "pg_catalog.english" env: LC_ALL: en_US.UTF-8 LANG: en_US.UTF-8 LANGUAGE: en_US.UTF-8 DISCOURSE_DEFAULT_LOCALE: en DISCOURSE_HOSTNAME: 'forum.yourdomain.com' DISCOURSE_DEVELOPER_EMAILS: '[email protected]' DISCOURSE_SMTP_ADDRESS: smtp.yourmailprovider.com DISCOURSE_SMTP_PORT: 587 DISCOURSE_SMTP_USER_NAME: your-smtp-user DISCOURSE_SMTP_PASSWORD: your-smtp-password # Uncomment the next line if you're behind a reverse proxy # DISCOURSE_SMTP_ENABLE_START_TLS: true volumes: - volume: host: /var/discourse/shared/standalone guest: /shared - volume: host: /var/discourse/shared/standalone/log/var-log guest: /var/log
# /var/discourse/containers/app.yml
templates: - "templates/postgres.template.yml" - "templates/redis.template.yml" - "templates/web.template.yml" - "templates/web.ratelimited.template.yml" - "templates/web.socketed.template.yml" # add this if using a reverse proxy params: db_default_text_search_config: "pg_catalog.english" env: LC_ALL: en_US.UTF-8 LANG: en_US.UTF-8 LANGUAGE: en_US.UTF-8 DISCOURSE_DEFAULT_LOCALE: en DISCOURSE_HOSTNAME: 'forum.yourdomain.com' DISCOURSE_DEVELOPER_EMAILS: '[email protected]' DISCOURSE_SMTP_ADDRESS: smtp.yourmailprovider.com DISCOURSE_SMTP_PORT: 587 DISCOURSE_SMTP_USER_NAME: your-smtp-user DISCOURSE_SMTP_PASSWORD: your-smtp-password # Uncomment the next line if you're behind a reverse proxy # DISCOURSE_SMTP_ENABLE_START_TLS: true volumes: - volume: host: /var/discourse/shared/standalone guest: /shared - volume: host: /var/discourse/shared/standalone/log/var-log guest: /var/log
./launcher rebuild app
./launcher rebuild app
./launcher rebuild app
# Install Caddy
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install -y debian-keyring debian-archive-keyring -weight: 500;">apt-transport-https
-weight: 500;">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | -weight: 600;">sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
-weight: 500;">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | -weight: 600;">sudo tee /etc/-weight: 500;">apt/sources.list.d/caddy-stable.list
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install caddy
# Install Caddy
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install -y debian-keyring debian-archive-keyring -weight: 500;">apt-transport-https
-weight: 500;">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | -weight: 600;">sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
-weight: 500;">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | -weight: 600;">sudo tee /etc/-weight: 500;">apt/sources.list.d/caddy-stable.list
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install caddy
# Install Caddy
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install -y debian-keyring debian-archive-keyring -weight: 500;">apt-transport-https
-weight: 500;">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | -weight: 600;">sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
-weight: 500;">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | -weight: 600;">sudo tee /etc/-weight: 500;">apt/sources.list.d/caddy-stable.list
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install caddy
# /etc/caddy/Caddyfile
forum.yourdomain.com { reverse_proxy unix//var/discourse/shared/standalone/nginx.http.sock
}
# /etc/caddy/Caddyfile
forum.yourdomain.com { reverse_proxy unix//var/discourse/shared/standalone/nginx.http.sock
}
# /etc/caddy/Caddyfile
forum.yourdomain.com { reverse_proxy unix//var/discourse/shared/standalone/nginx.http.sock
}
# /etc/cron.d/discourse-backup
# Run backup daily at 3am, then sync to remote storage
0 3 * * * root /var/discourse/launcher run app discourse backup
30 3 * * * root rsync -avz /var/discourse/shared/standalone/backups/ backup-user@your-backup-server:/backups/discourse/
# /etc/cron.d/discourse-backup
# Run backup daily at 3am, then sync to remote storage
0 3 * * * root /var/discourse/launcher run app discourse backup
30 3 * * * root rsync -avz /var/discourse/shared/standalone/backups/ backup-user@your-backup-server:/backups/discourse/
# /etc/cron.d/discourse-backup
# Run backup daily at 3am, then sync to remote storage
0 3 * * * root /var/discourse/launcher run app discourse backup
30 3 * * * root rsync -avz /var/discourse/shared/standalone/backups/ backup-user@your-backup-server:/backups/discourse/ - Slack's free tier message limits have changed multiple times
- Discord servers get disabled with little warning or recourse
- Hosted forum platforms shut down and give you weeks to export
- API changes break integrations you depend on - Discourse — Ruby on Rails, PostgreSQL, Redis. The most fully-featured option. Great search, solid plugin ecosystem, handles large communities well. Heavier on resources.
- Flarum — PHP, MySQL. Lightweight, modern UI, easier to extend if you know PHP. Smaller community but active development.
- NodeBB — Node.js, MongoDB or Redis. Good real-time features, familiar stack if you're a JS developer. - Enable 2FA for all admin accounts immediately
- Set up fail2ban to block brute-force attempts on your SSH and any exposed services
- Configure unattended-upgrades so security patches apply automatically
- Restrict SSH to key-based auth only — -weight: 500;">disable password login
- Set up monitoring — even something simple like uptime checks so you know when things break - Updates: Discourse releases frequently. Run ./launcher rebuild app every few weeks. It takes about 5 minutes of downtime.
- Disk space: Uploaded images and attachments add up. Monitor your disk usage.
- Email reputation: If your SMTP setup isn't right, your forum's emails end up in spam. Check your SPF, DKIM, and DMARC records.
- Spam: It will come. Discourse has decent built-in anti-spam tools, but you'll still need to tune settings as your community grows. - Every discussion is searchable and indexed by search engines, bringing in new community members organically
- Knowledge doesn't disappear behind message limits
- I own the data and can export it in standard formats anytime
- The community feels more permanent, which encourages people to write longer, more thoughtful posts