VPS Tutorials
Building a Discourse Forum on a VPS (2026): Docker, Domain HTTPS, SMTP, Backups and Upgrades
Build a community forum on an Ubuntu VPS using the official Discourse Docker installer, covering configuration choices, domain and automatic HTTPS, SMTP email delivery, Cloudflare, backup and restore, security hardening, upgrades and common troubleshooting.

Discourse is well suited to building product communities, user forums, knowledge Q&A sites and paid membership communities. It ships with categories, tags, full-text search, trust levels, moderation, notifications and a mobile PWA, making it more complete than assembling WordPress forum plugins from scratch, but it also places higher demands on memory, email deliverability and day-to-day maintenance.
This article uses the officially supported Docker installation method for Discourse to complete domain setup, automatic HTTPS, admin registration, SMTP, backups, upgrades and common troubleshooting on a fresh Ubuntu VPS. The current official minimum requirement is 1 core, 1GB of memory plus Swap, and 10GB of disk; for production, starting from 2 cores, 2GB and 20GB SSD is recommended.
| Scenario | Suitable | Notes |
|---|---|---|
| Product support communities, user forums | Suitable | Complete categories, tags, search, moderation and notifications |
| Course student communities, member discussions | Suitable | Can restrict registration, invite users and integrate third-party login |
| Pure content blogs | Not a priority | Publishing systems such as WordPress and Ghost are more direct |
| Only a few dozen static Q&A pages | Possibly overkill | Discourse runs Rails, PostgreSQL, Redis and Sidekiq simultaneously |
| Need a mailing-list mode | Suitable, but email must be configured | SMTP, bounce handling and sending domains must all be reliable |
Discourse is not an ordinary PHP program, and it does not support uploading source code to a site created with the BaoTa panel to complete installation. The official support is Docker-based deployment only, and a dedicated, clean 64-bit Linux VPS is recommended.
The official installer automatically adjusts Unicorn Workers and PostgreSQL Shared Buffers based on CPU and memory. The minimum configuration can be used for testing, but public operation should reserve headroom for the database, image processing, search and upgrade builds.
| Usage scale | Recommended configuration | Applicable situation |
|---|---|---|
| Testing, migration drills | 1 core 1GB, 2GB Swap, 20GB SSD | Only suitable for a small number of users and short-term validation |
| Small public community | 2 cores 2-4GB, 40GB SSD | Low daily active users, few attachments |
| Medium community | 4 cores 8GB, 80GB+ NVMe | More plugins, search, images and concurrency |
| Large community | Separate Web, database and Redis | Requires monitoring, object storage, CDN and professional capacity planning |
Disk size cannot be calculated from program size alone. User uploads, automatic backups, Docker images, logs and temporary files during upgrades all keep growing. If you have not settled on specifications yet, you can start with the VPS configuration selection guide.
Prepare the following:
- A fresh Ubuntu 24.04 LTS or Debian VPS;
- root SSH access and a public IPv4 address;
- A domain already pointed to the VPS, for example
forum.example.com; - A usable transactional email service, or temporarily use Discourse ID login;
- A provider snapshot or another rollback option.
Add an A record for the domain:
forum.example.com A 203.0.113.10
Check DNS resolution and port usage:
dig +short forum.example.com A
sudo ss -lntp | grep -E ':(80|443)\b' || true
free -h
df -h
80 and 443 must be available. If Nginx, Apache, Caddy, BaoTa or another panel is already running on the server, do not run the installer directly; port conflicts will cause connection checks and HTTPS issuance to fail.
The cloud firewall only needs to open:
| Port | Purpose | Recommendation |
|---|---|---|
| 22/TCP | SSH management | Restricting to admin IPs is safer |
| 80/TCP | HTTP, certificate validation | Allow public access |
| 443/TCP | HTTPS forum | Allow public access |
PostgreSQL and Redis should not be exposed directly to the public internet.
A 1GB or 2GB VPS can easily run out of memory when building images, upgrading and rebuilding containers. The official installer can create Swap on low-memory machines, or you can configure it manually in advance:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/30-discourse-swap.conf
sudo sysctl --system
free -h
Swap only reduces the probability of sudden OOM; it cannot replace physical memory. When the forum frequently uses Swap or responds noticeably slower, you should upgrade the configuration rather than keep enlarging Swap.
The current official quick install command for Discourse is:
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bash
If you want to inspect the script before executing it, you can split it into two steps:
curl -fsSL https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse -o install-discourse
less install-discourse
sudo bash install-discourse
The installer checks system resources, installs Docker and Git, downloads the /var/discourse configuration, and enters an interactive wizard. The wizard mainly asks about:
- The admin email;
- Your own domain or a free
discourse.diysubdomain; - Whether to skip SMTP configuration;
- DNS, ports 80/443 and Swap settings.
After confirmation it builds the app container, which usually takes several minutes. Do not interrupt SSH just because the terminal temporarily shows no new output. You can open another window to observe resources:
docker ps
docker stats --no-stream
df -h
Check after installation completes:
cd /var/discourse
sudo ./launcher logs app
curl -I https://forum.example.com
Normally, the Let's Encrypt certificate is configured automatically by the installation process, and you do not need to install Certbot on the host again.
Open https://forum.example.com in a browser and register with the admin email entered during installation. Only the account matching DISCOURSE_DEVELOPER_EMAILS can obtain admin privileges after the first registration.
After first entering the admin panel, complete:
- Set the site name, description, logo and default language;
- Decide whether registration is open, invite-only, or users are created only by admins;
- Create categories, forum rules, privacy policy and terms of service;
- Enable sensitive-word filtering, the moderation queue and new-user posting limits;
- Create an ordinary test account to verify registration, posting and notification flows.
Do not test only with the admin account. Ordinary user permissions, email verification, image uploads and trust-level issues usually only surface when you actually walk through the registration flow.
The new official installer allows skipping SMTP and enabling Discourse ID login. This lets you complete testing first, and also use email or Google, GitHub, Apple and other login methods through the unified identity service.
However, production communities should still configure dedicated transactional email. Without SMTP, traditional registration verification, digest emails, private message notifications, email replies and some account recovery flows will be limited. Do not temporarily install Postfix on the same VPS to send mail directly; deliverability, PTR, SPF, DKIM and bounce handling will noticeably increase maintenance costs.
Common SMTP parameters are as follows:
SMTP 地址:smtp.example.net
SMTP 端口:587
SMTP 用户名:provider-user
SMTP 密码:独立 SMTP Key
发件地址:[email protected]
To modify the installation configuration, edit:
sudo nano /var/discourse/containers/app.yml
Example fields:
env:
DISCOURSE_HOSTNAME: 'forum.example.com'
DISCOURSE_DEVELOPER_EMAILS: '[email protected]'
DISCOURSE_SMTP_ADDRESS: 'smtp.example.net'
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: 'provider-user'
DISCOURSE_SMTP_PASSWORD: 'replace-with-smtp-key'
DISCOURSE_NOTIFICATION_EMAIL: '[email protected]'
YAML is sensitive to indentation, and when the password contains characters such as #, :, $ it must be quoted. Rebuild the container after modifying:
cd /var/discourse
sudo ./launcher rebuild app
Then send a test email from the admin panel and check SPF, DKIM, DMARC and the bounce webhook. The sending subdomain should be verified according to the email provider's requirements; do not assume users will receive mail just because the admin panel says "sent".
During the first installation, it is recommended to set the Cloudflare record to DNS Only, ensuring the Discourse installer can directly detect the origin and issue certificates. After successful installation, enable the proxy and set the SSL/TLS mode to Full (strict).
Do not use Flexible mode, otherwise Cloudflare connects to the origin over HTTP, which easily causes redirect loops and login cookie anomalies. When HTTPS loops occur, you can refer to VPS HTTPS redirect loop troubleshooting.
After enabling Cloudflare, check:
curl -I http://forum.example.com
curl -I https://forum.example.com
curl -sS https://forum.example.com/srv/status
Forum login, posting, uploads and real-time notifications all need full testing; do not stop at the homepage returning 200.
Enable automatic backups in Admin → Backups and set the frequency and retention count. Backups should include the database and user uploads, but local backups will still be lost together with the VPS, so they must be copied to off-site storage.
Default persistent data is located at:
/var/discourse/shared/standalone/
Common backup files are located at:
/var/discourse/shared/standalone/backups/default/
Check recent backups:
sudo find /var/discourse/shared/standalone/backups -type f -printf '%TY-%Tm-%Td %TH:%TM %s %p\n' | sort
It is recommended to keep three layers at once:
- Discourse admin automatic backups;
- VPS provider snapshots, for quick rollback when upgrades fail;
- Off-site copies on S3, object storage or another server.
Perform at least one test restore. Backups that are only created and never verified cannot prove they are usable after database corruption or accidental deletion. For the complete method, see the VPS backup and restore drill guide.
Minor version updates can be performed from the admin panel under /admin/upgrade. When base images, Docker templates or major version changes are involved, rebuilding from the command line makes it easier to retain complete logs:
cd /var/discourse
sudo ./launcher rebuild app
Before updating, run:
free -h
df -h
docker ps
sudo ./launcher logs app
Make sure you have a recent backup and snapshot, then schedule a maintenance window. rebuild destroys the old container and rebuilds from the configuration; persistent data is kept in /shared, but configuration errors, insufficient disk or download failures can still cause downtime.
After updating, check the homepage, login, posting, search, image uploads, email and background jobs. Do not end maintenance just because the container status shows Up.
- Use key-based SSH login and restrict management sources;
- Open only 22, 80 and 443, and do not expose PostgreSQL or Redis;
- Enable two-factor authentication for admins, and use an ordinary account for daily posting;
- Limit links, attachments, private messages and posting frequency for new users;
- Install Discourse security updates promptly;
- Install plugins only from trusted repositories, and record versions and purposes;
- Do not write SMTP keys, OAuth secrets or object storage keys into public repositories;
- Configure off-site backups, disk alerts and site availability monitoring.
Discourse has built-in application-layer rate limiting, but it cannot replace cloud firewalls, CDNs and capacity monitoring. When a public community suffers a CC attack, you can handle it with the Cloudflare WAF and Nginx rate limiting troubleshooting checklist.
sudo ss -lntp | grep -E ':(80|443)\b'
docker ps --format 'table {{.Names}}\t{{.Ports}}'
Confirm which service is occupying the port before deciding to migrate or stop it. Do not directly kill production processes you do not recognize.
dig +short forum.example.com A
curl -4 ifconfig.me
The two IPs must match. Also check for incorrect AAAA records, Cloudflare proxy, cloud firewalls and DNS caching.
free -h
swapon --show
dmesg -T | grep -i -E 'out of memory|killed process'
If there is no Swap, configure 2GB Swap first; if OOM still occurs frequently during long-term operation, upgrade to 2GB or 4GB of memory.
cd /var/discourse
sudo ./launcher logs app
docker ps -a
curl -I http://127.0.0.1
sudo tail -n 100 /var/discourse/shared/standalone/log/rails/production.log
Focus on checking DNS, certificates, disk space, database startup, Rails logs and port mapping.
Verify the SMTP address, port, username, key, TLS mode and sending domain. Cloud providers may block port 25; transactional email usually uses 587 or a provider-specified port. Changes to app.yml only take effect after a rebuild.
First check the complete build log to confirm whether the plugin supports the current Discourse version. Do not delete the persistent directory just to let the upgrade continue. You should roll back the snapshot or temporarily remove the incompatible plugin from app.yml, then rebuild and verify the data.
- The domain A record points to the current VPS, and 80/443 are accessible
- Both the main site and the admin panel use valid HTTPS
- Ordinary users can register, log in, post, search and upload images
- SMTP test emails are delivered, and SPF, DKIM and DMARC are correct
- Two-factor authentication is enabled for admins
- Automatic backups are enabled and copied to off-site storage
- A backup restore drill has been completed
- A snapshot exists before updates, and email and background jobs are checked after updates
- PostgreSQL, Redis and admin credentials are not exposed to the public internet
- Alerts exist for disk, memory, certificates and site availability
The real deployment cost of Discourse is not in getting the homepage open the first time, but in email deliverability, moderation, attachment growth, backup and restore, and continuous upgrades. Small communities starting from 2 cores, 2GB, dedicated transactional email and off-site backups usually save more time than repeatedly dealing with OOM, full disks and email failures on a 1GB VPS.