Self-hosted forum software compared
Discourse, Flarum, NodeBB and phpBB on a VPS: the RAM each really needs, the database it drags along, the spam story, and the migration path out.
Which self-hosted forum software should you run?
Self-hosted forum software comes down to four real choices you can run on a VPS (virtual private server) today: Discourse, Flarum, NodeBB and phpBB. Discourse is the right default if you can give it 4 GB of RAM and you have at least two people willing to moderate. With 1 GB and one moderator, run Flarum or phpBB instead. A quiet forum you can keep clean beats a better forum you cannot.
The install is the easy part. Every one of these is running in an afternoon. What decides whether the forum still exists in a year is the flag queue and the mail path, so read the moderation and email sections before you read the feature lists.
What does a forum actually need to run?
A forum is four moving parts, not one: an application process, a database that has to outlive it, a directory of uploaded avatars and attachments, and a working path to send mail. The application is replaceable. The database is not, because every post, every account and every private message lives inside it. That is why the database each project chose is the most important line in the sections below. It decides what your export looks like on the day you want to leave.
The second cost is human. Public registration plus public posting means bot signups, usually within the first week of the domain appearing in a crawl. All four can be locked down. Only one of them ships the workflow in core.
Discourse: the default, and what it really costs
Discourse is Ruby on Rails, with PostgreSQL for data, Redis for cache and job queues, and Sidekiq running background work. The supported install puts all of that inside one Docker container, built from a config file at /var/discourse/containers/app.yml. You do not install the pieces yourself.
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bashThat script installs git and Docker if they are missing, clones discourse_docker into /var/discourse, then hands over to the interactive discourse-setup wizard. The wizard asks for your hostname, an admin email address and SMTP (simple mail transfer protocol) details, writes app.yml, and builds the container. Ports 80 and 443 have to be free, because the container runs its own nginx and requests a Let's Encrypt certificate for you.
The published minimum is 1 GB of RAM with swap, plus 10 GB of disk. Read the swap part literally. The setup script creates a 2 GB swapfile with fallocate -l 2G /swapfile when the wizard decides the box needs one, and that swap is not decoration. The memory peak is not the running site. It is ./launcher rebuild app, which recompiles the JavaScript and CSS assets inside the container on every upgrade. On a 1 GB box with no swap that step is killed part way through, the rebuild ends with no useful error on screen, and dmesg | tail shows an Out of memory: Killed process line. Budget 2 GB to run it honestly, and 4 GB once the forum is busy.
Upgrades run from /admin/upgrade in the browser, or from the shell:
cd /var/discourse
./launcher rebuild apprebuild destroys the running container, bootstraps a new one from app.yml, and starts it, so the site is down for the several minutes that takes. There is no way around that on a single container. Splitting into two containers using the data.yml and web_only.yml samples keeps PostgreSQL up while the web container rebuilds, which becomes worth doing once you have users who notice.
Moderation is where Discourse earns its RAM. New accounts start at trust level 0 with hard limits on how many links they can post and how fast, then climb as they read and participate. Flags land in a review queue that records who handled what. Akismet and StopForumSpam integrations are official plugins. On the other three you assemble this from add-ons.
Migration into Discourse is its strongest feature. The script/import_scripts/ directory in the source tree carries more than sixty importers, including phpbb3.rb, vbulletin.rb, xenforo.rb, vanilla.rb, mybb.rb, flarum_import.rb, a nodebb directory and an mbox importer for mailing list archives. They are Ruby scripts you run inside the container against a copy of the old database. They are slow, and they are maintained.
Migration out is the weak side. ./launcher enter app followed by discourse backup writes a .tar.gz holding a PostgreSQL dump plus the uploads directory. Another Discourse restores it. Nothing else reads it, so leaving Discourse means writing SQL against that dump yourself. Decide you can live with that before you import 50,000 posts.
Flarum: the light PHP forum
Flarum is an ordinary PHP application: php-fpm behind nginx or Apache, a MySQL or MariaDB database, files on disk. The documented requirements are PHP 7.3 or newer with the curl, dom, fileinfo, gd, json, mbstring, openssl, pdo_mysql, tokenizer and zip extensions, plus MySQL 5.6+ (or 8.0.23+) or MariaDB 10.0.5+. Ubuntu 24.04 ships PHP 8.3, which is above that floor.
Notice pdo_mysql in that list. Flarum does not support PostgreSQL and does not support SQLite. If you wanted a single-file database, that is phpBB below.
sudo apt update
sudo apt install -y nginx mariadb-server composer php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip
sudo install -d -m 755 /srv/flarum
cd /srv/flarum
sudo COMPOSER_ALLOW_SUPERUSER=1 composer create-project flarum/flarum:^1.8.0 .
sudo chown -R www-data:www-data /srv/flarumPoint the web server at /srv/flarum/public, not at /srv/flarum. The application code, the config file and the database password all sit one directory above public, so a document root one level too high serves your credentials to anyone who asks for them. On Apache you also need mod_rewrite and AllowOverride All so the shipped .htaccess takes effect. On nginx you include the shipped .nginx.conf inside your server block. Then browse to the domain, and Flarum's own installer asks for the database and the admin account.
Versions, as of August 2026: 1.8.17 is the current stable release, published in June 2026, and 2.0 is at release candidate 5. Do not start a new community on the release candidate. When 2.0 arrives, extensions need updating before they will load, and that is the upgrade that costs you a weekend.
The footprint is small. A few php-fpm workers, MariaDB wanting a few hundred MB, and static files. A young community fits on 1 GB.
Moderation is the honest weakness. Core gives you reports and per-group permissions. Approval queues and spam blocking come from extensions, mostly the FriendsOfFlarum collection, installed with composer require and switched on in the admin panel. That works today. You are trusting a smaller volunteer ecosystem than phpBB or Discourse has, and an unmaintained extension blocks your next core upgrade, because composer refuses to resolve it against the new version.
Getting data out is easy: mysqldump the database and copy the assets directory. Getting data in is harder. Discourse ships flarum_import.rb for the Flarum to Discourse direction, which tells you which way traffic usually flows. Importing phpBB into Flarum is done by community extensions rather than anything first party, so test one against a copy before you trust it with the only copy.
NodeBB: realtime posting, and the tax that comes with it
NodeBB is Node.js. It pushes new posts to open browsers over websockets, so an active thread updates without a refresh. That is the reason to pick it. The README asks for Node.js 22 or newer and either MongoDB 5+ or Redis 7.2+, and a PostgreSQL driver ships in the source tree as a third option.
Redis as the primary database is the trap in that sentence. Redis holds the dataset in memory, so your RAM requirement grows with the forum instead of staying flat. MongoDB or PostgreSQL keep it on disk and cache what is hot. Choose Redis only if you can say why.
Ubuntu 24.04 packages Node.js 18, which is below the floor, so install a current runtime first.
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs git build-essential
sudo adduser --system --group --home /srv/nodebb nodebb
sudo -u nodebb git clone -b v4.x https://github.com/NodeBB/NodeBB.git /srv/nodebb
cd /srv/nodebb
sudo -u nodebb ./nodebb setup./nodebb setup is interactive. It asks which database to use and how to reach it, then creates the admin account and picks a port, which defaults to 4567. NodeBB does not start with npm start. The ./nodebb script is the interface, and ./nodebb log is where the output goes.
./nodebb start daemonises, which is wrong for a machine that reboots. Run the loader under systemd in the foreground instead.
[Unit]
Description=NodeBB
After=network.target
[Service]
Type=simple
User=nodebb
WorkingDirectory=/srv/nodebb
ExecStart=/usr/bin/env node loader.js --no-daemon
Restart=on-failure
[Install]
WantedBy=multi-user.target--no-daemon is the part people miss. Without it the loader forks and the parent exits, so systemctl status nodebb reports the unit as dead while curl localhost:4567 still answers, and systemctl stop nodebb then stops nothing. Behind a reverse proxy, the websocket upgrade headers have to be passed through. If proxy_set_header Upgrade $http_upgrade; and proxy_set_header Connection "upgrade"; are missing from the nginx block, the forum loads, the browser console fills with failed socket.io requests, and new posts stop appearing until the reader refreshes.
Moderation sits between Flarum and Discourse. There is a flag queue in the admin panel, per-category privileges and a reputation system. Anti-spam comes from community plugins such as nodebb-plugin-spam-be-gone, which wires in Akismet and StopForumSpam.
Backups are manual, and nobody mentions it until the day you need one. The ./nodebb CLI has no backup command. You dump the database yourself with mongodump or pg_dump, and you copy the public/uploads directory and config.json alongside it. config.json holds the database credentials and the site URL, so a restore without it is just a new install. There is no first-party importer either. nodebb-plugin-import is a community project that has not kept pace, while Discourse ships a NodeBB importer, so the exit door that definitely works leads to Discourse.
phpBB: the small, boring one that still works
phpBB is old, and that is the argument for it. The 3.3 line runs on PHP 7.2.0 up to and including PHP 8.3, and it speaks MySQL 4.1.3+, MariaDB 5.1+, PostgreSQL 8.3+, SQLite 3.6.15+, MS SQL Server and Oracle. It needs json, mbstring, XML support, and the getimagesize() function enabled.
SQLite is why it belongs in this list. With SQLite the forum is a directory of PHP files plus one database file. No database server, nothing to tune, nothing extra to back up. On a 1 GB VPS that already runs something else, that difference is real. Use SQLite for a small community and move to MySQL when concurrent posting picks up, because SQLite serialises writes and posts start queueing behind each other.
There is no composer step and no container. Install a web server with PHP, unpack the archive, and run the browser installer. The full stack setup is covered in a standard LAMP stack on Ubuntu 24.04.
sudo apt update
sudo apt install -y apache2 php libapache2-mod-php php-mysql php-mbstring php-xml php-gd unzipDownload the current 3.3 release from phpbb.com, unpack it into the directory your vhost serves, then make the paths the installer writes to writable by the web server user.
sudo chown -R www-data:www-data /srv/phpbb
sudo chmod 660 /srv/phpbb/config.php
sudo chmod -R 770 /srv/phpbb/store /srv/phpbb/cache /srv/phpbb/files /srv/phpbb/images/avatars/uploadThe official instructions say 666 and 777. Those numbers exist for shared hosting, where you do not control the user PHP runs as. On your own VPS you do control it, so give ownership to www-data and keep everyone else out. One Apache detail catches people: Ubuntu's config only grants access under its own default document root, so a vhost pointing at /srv/phpbb also needs a matching <Directory> block with Require all granted, or every request returns 403 Forbidden before phpBB is even reached. Finish in the browser at /install/index.php, then set config.php back to 640 and delete the install/ directory. phpBB keeps warning you about that directory until it is gone.
Spam is phpBB's known problem, and it is fixable. The registration form sits at a predictable URL (ucp.php?mode=register), so bots find it within days of the domain being crawled. The fix that holds is in the admin panel under Spambot countermeasures: set the anti-spam method to Question and Answer, and write a question only someone in your community can answer. Image CAPTCHAs (completely automated public Turing tests) are solved cheaply by services that charge by the thousand. A question about your own subject is not.
phpBB is also the best-supported source for a migration. Discourse's phpbb3.rb is the most travelled importer in this whole article, and twenty years of answers exist on the phpBB support forums. Getting out is mysqldump, or copying the SQLite file. What does not travel is your styles and your extensions.
Why do forum signup emails never arrive?
Registration on all four of these is gated on a confirmation email. If that mail does not arrive, the account is never activated, and your logs show a signup that simply stopped. Outbound deliverability decides whether the forum works at all, so treat it as part of the install.
- Outbound port 25 is blocked by most VPS providers by default, so a local Postfix trying to deliver directly goes nowhere. The mail log shows
connect to gmail-smtp-in.l.google.com[...]:25: Connection timed out. - A brand new IP address has no sending reputation, so even successful delivery lands in the spam folder. For a confirmation link, that is the same as not arriving.
- Without SPF (sender policy framework) and DKIM (domainkeys identified mail) records published in DNS, large providers reject the message outright. Google's rejection reads
550 5.7.26 Unauthenticated email from example.com is not accepted due to domain's DMARC policy. DMARC (domain-based message authentication, reporting and conformance) is now expected of anyone sending in volume.
The practical answer is a relay. Point the forum's SMTP settings at a transactional mail provider on port 587, publish the SPF, DKIM and DMARC records that provider gives you, and send from a subdomain such as mail.example.com so the forum's reputation stays separate from your personal mail. Running the mail server yourself is possible, and a full self-hosted mail server on a VPS covers it, but a forum launch is the wrong week to learn deliverability.
Test before you announce the forum. On Discourse, from inside the container:
cd /var/discourse
./launcher enter app
rake emails:test[you@example.com]That task checks the SMTP connection and sends a message, and it names the failure when credentials are wrong, usually as a Net::SMTPAuthenticationError. phpBB has an equivalent test in the admin panel under Client communication. For Flarum and NodeBB, register a throwaway account against a real mailbox at a large provider and read the raw headers of what arrives. spf=pass and dkim=pass in the Authentication-Results header is the result you are looking for.
One nuance for Discourse. As of August 2026 the setup wizard lets you skip SMTP and fall back to Discourse ID, which signs people in with an external account instead of an emailed link. That gets you launched without a relay. It does not give you notification mail or password resets, so configure SMTP anyway before the community grows.
How do you put the forum behind TLS?
Flarum and phpBB are ordinary virtual hosts, so certbot on the web server you already run is enough. NodeBB and Discourse are different: they are applications listening on local ports, and something in front has to terminate TLS (transport layer security) and route by hostname. If the forum shares the box with other services, put one reverse proxy in front of all of them, which is what Traefik in front of multiple Docker Compose apps is for.
Discourse defaults to owning ports 80 and 443 itself, using its own nginx and its own Let's Encrypt template. To place it behind an existing proxy you edit app.yml, remove the templates/web.letsencrypt.ssl.template.yml line, change the exposed ports so the container listens only on a local address, then run ./launcher rebuild app. Doing this after the fact costs a rebuild and a few minutes of downtime, so decide before you install rather than after.
Which forum fits your community size?
The decision rule is about people, not features.
- Under a few hundred members, one moderator, 1 GB of RAM: phpBB on SQLite, or Flarum if you want the modern interface and can run MariaDB. Each is a single PHP application to keep patched.
- A growing community, two or more moderators, 4 GB of RAM: Discourse. Trust levels and the review queue are worth the footprint the moment moderation stops fitting in one person's head.
- You want live conversation more than durable threads: NodeBB, or accept that it is chat and run Rocket.Chat on Docker Compose instead. A forum where nothing is worth reading a week later should have been a chat server.
- What you actually need is documentation rather than discussion: none of these. BookStack, Wiki.js or Outline answers that question better, and a forum full of repeated questions is usually a missing wiki.
- Still working out what belongs on the box at all: the wider self-hosting shortlist for 2026 is a better starting point, and the self-hosted Notion alternatives guide covers the overlap between forums and shared workspaces.
Whichever you choose, the forum is only as durable as its last restored backup. Dump the database on a schedule, copy the uploads directory in the same job, and restore the result somewhere else once to prove the dump is usable. Scheduled restic backups on a VPS covers that part, and it is the one piece of this setup that has no second chance.
FAQ
What are the minimum server requirements for a self-hosted forum?
phpBB with SQLite runs on 1 GB of RAM next to other services, because there is no database server. Flarum wants 1 GB plus MariaDB. NodeBB is comfortable on 2 GB with MongoDB. Discourse publishes 1 GB with swap and 10 GB of disk as its minimum, but 2 GB is the honest floor and 4 GB suits a busy forum, because ./launcher rebuild app recompiles assets in memory on every upgrade and that is the moment a small box is killed by the kernel out of memory handler.
Can I move my phpBB forum to Discourse?
Yes, and it is the best-supported migration path here. Discourse ships script/import_scripts/phpbb3.rb, which you run inside the container against a copy of the phpBB database, never against the live one. Users, categories, topics, posts and attachments come across. Styles and extensions do not, and old topic URLs change, so plan redirects from the phpBB paths before you switch DNS. Large boards take hours, so rehearse the import once on a scratch server and time it.
Why do new users never receive the activation email?
Most VPS providers block outbound port 25, so a local mail server cannot deliver at all and the log shows Connection timed out against the recipient's mail exchanger. When delivery does work, a new IP with no SPF or DKIM records is rejected or filtered, and Google answers with 550 5.7.26 Unauthenticated email ... is not accepted due to domain's DMARC policy. Send through a relay on port 587 and publish the SPF, DKIM and DMARC records that relay gives you, then confirm with a test registration and read the Authentication-Results header of the message you receive.
Which self-hosted forum software needs the least moderation work?
Discourse, because the workflow is in core rather than bolted on. New accounts are rate limited until they have read enough, flags collect in a queue that records who acted on them, and the Akismet plugin is official. phpBB gets close once you enable the Question and Answer anti-spam method, which stops most bot registration on its own. Flarum and NodeBB rely on community extensions for the same jobs. None of this changes the real driver: moderation load scales with how many people post, not with which software they post into.