SSD Nodes Learn 🎉 VPS từ $5.50/tháng
Hướng dẫn Matt ConnorBởi Matt Connor

Cài Flarum trên VPS với PHP và MariaDB

Cài Flarum 1.8 trên VPS bằng PHP, Composer và MariaDB, chỉ expose /public qua TLS, đồng thời xử lý lỗi mail và extension upgrade làm hỏng forum mới.

Cài đặt Flarum trên VPS với PHP và MariaDB

Cài đặt Flarum trên VPS sẽ cung cấp cho bạn một forum chạy bằng PHP và MariaDB, không cần Docker, Ruby hoặc job runner riêng. Đó là lý do nên chọn Flarum. Cài đặt Discourse trên VPS cần một Docker stack chứa Ruby, PostgreSQL, Redis và background worker, đồng thời 2 GB RAM là mức thực tế tối thiểu trước khi bạn thêm backup hoặc mail service. Discourse phù hợp với một community đông người, có hàng nghìn bài đăng mỗi ngày. Với forum chỉ có vài trăm người, đó là hệ thống bạn phải trả chi phí mỗi tháng nhưng hầu như không dùng đến. Flarum nằm gọn trong PHP stack mà bạn có thể đang chạy, vì vậy một VPS 1 GB với nginx và MariaDB có thể host nó cùng các dịch vụ khác. Nếu bạn vẫn chưa quyết định, bài so sánh rộng hơn về forum software tự host sẽ trình bày các lựa chọn còn lại.

Hướng dẫn này cố định quy trình cài đặt ở Flarum 1.x, hiện thuộc dòng 1.8. Tính đến tháng 8 năm 2026, Flarum 2.0 vẫn là release candidate, vì vậy 1.8 là phiên bản nên chạy cho một forum mà người khác phụ thuộc vào. Extensions ở đây quan trọng hơn phiên bản core, và hầu hết tác giả extension vẫn chưa chuyển sang 2.0.

Flarum 1.8 cần gì trên server

Yêu cầu được Flarum công bố là PHP 7.3 trở lên, MySQL 5.6+ hoặc MariaDB 10.0.5+, cùng nginx hoặc Apache với mod_rewrite. Ubuntu 24.04 đi kèm PHP 8.3 và MariaDB 10.11, nên các package của distribution đáp ứng cả hai yêu cầu mà không cần repository bên thứ ba. Các PHP extension Flarum yêu cầu gồm curl, dom, fileinfo, gd, json, mbstring, openssl, pdo_mysql, tokenizer và zip. Bạn cũng cần quyền truy cập shell vì Composer là thành phần bắt buộc trong trường hợp này: mọi extension của Flarum đều là một Composer package và không có cách nào thêm extension nếu không chạy Composer.

Flarum là một PHP application thông thường. Nếu bạn đã chạy LAMP stack trên Ubuntu 24.04, phần lớn nội dung trong 2 section tiếp theo đã được cài đặt và bạn có thể đọc lướt đến phần database.

Cài đặt PHP và các extension mà Flarum yêu cầu

sudo apt update
sudo apt install -y nginx mariadb-server composer
sudo apt install -y php8.3-fpm php8.3-cli php8.3-curl php8.3-gd php8.3-mbstring php8.3-mysql php8.3-xml php8.3-zip
php -m | grep -E 'curl|dom|gd|mbstring|pdo_mysql|zip'
composer --version

Tên package không khớp hoàn toàn với danh sách của Flarum. Extension dom nằm trong php8.3-xml, còn fileinfo, json, openssltokenizer đã được biên dịch sẵn trong PHP 8.3 trên Ubuntu, nên không có package riêng để cài cho các extension này. grep phải in ra sáu dòng và composer --version phải báo một bản phát hành 2.x. Nên xử lý extension bị thiếu ngay lúc này, vì Composer sẽ từ chối cài Flarum nếu thiếu extension đó và thông báo lỗi sẽ nêu rõ tên extension:

  Problem 1
    - flarum/core[v1.8.0, ..., v1.8.17] require ext-gd * -> it is missing from your system.
      Install or enable PHP's gd extension.

Kiểm tra để bảo đảm PHP trên command line và trình quản lý tiến trình FastCGI (PHP-FPM) dùng cùng một phiên bản. Composer chạy bằng binary trên command line, còn forum chạy dưới FPM, vì vậy php -vsudo php-fpm8.3 -v phải khớp nhau. Hai phiên bản có thể bị lệch trên máy đã cài nhiều phiên bản PHP từ repository bên thứ ba. Khi đó, extension bạn cài cho một phiên bản sẽ không hiển thị trong phiên bản còn lại.

Tạo database và user database riêng

sudo mariadb-secure-installation
sudo mariadb
CREATE DATABASE flarum CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'flarum'@'localhost' IDENTIFIED BY 'use-a-long-random-password';
GRANT ALL PRIVILEGES ON flarum.* TO 'flarum'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Cấp cho Flarum một user database riêng thay vì root. Grant này chỉ bao phủ flarum.* và không có quyền nào khác, nên lỗi SQL injection trong một extension mà bạn không tự viết sẽ không thể đọc các database khác. Character set cũng rất quan trọng: utf8mb4 lưu emoji và các bộ chữ không phải Latin chính xác, còn utf8 cũ của MySQL chỉ dùng encoding ba byte nên sẽ cắt bài viết tại ký tự đầu tiên cần bốn byte. Hãy xác nhận user hoạt động trước khi tiếp tục.

mariadb -u flarum -p flarum -e 'SELECT DATABASE();'

Lệnh này phải in ra flarum. ERROR 1045 (28000): Access denied for user 'flarum'@'localhost' nghĩa là password không khớp, hoặc user được tạo cho host khác với localhost.

Cài Flarum trên VPS bằng Composer, cố định phiên bản 1.8

Trước tiên, hãy tạo một system user để sở hữu mã nguồn. Chạy Composer bằng root sẽ tạo các file thuộc sở hữu của root trong vendor/storage/. Khi đó PHP không thể ghi cache của chính nó về sau, và forum sẽ trả về lỗi 500 cho mọi request.

sudo useradd --system --home-dir /srv/flarum --shell /bin/bash flarum
sudo install -d -o flarum -g flarum -m 755 /srv/flarum
sudo -iu flarum

Lệnh cuối cùng đưa bạn vào shell với tư cách user flarum, tại /srv/flarum. Từ đây đến cuối hướng dẫn, mọi lệnh đều được chạy bằng user này, trừ khi lệnh bắt đầu bằng sudo.

composer create-project flarum/flarum:^1.8.0 .

Ràng buộc ^1.8.0 là phần cố định phiên bản. Nó chấp nhận các bản vá 1.8.x và từ chối 2.0. Đây là lựa chọn phù hợp khi 2.0 vẫn đang là release candidate. Composer tải skeleton, resolve flarum/core cùng các dependency của nó, rồi tạo public/, storage/, vendor/, composer.json và một script dòng lệnh flarum.

Trên VPS nhỏ, bước này thường phát sinh lỗi và có 2 lỗi khác nhau nhưng biểu hiện gần giống nhau. PHP Fatal error: Allowed memory size of 134217728 bytes exhaustedmemory_limit của PHP. Đặt COMPOSER_MEMORY_LIMIT=-1 trước lệnh sẽ bỏ giới hạn đó trong một lần chạy. Một Killed đứng riêng trên một dòng, không có lỗi PHP, là kernel out-of-memory killer. Bạn có thể xác nhận bằng dmesg | tail. Trường hợp này có nghĩa là máy thực sự đã hết RAM, nên hãy thêm swap. Tăng giới hạn PHP sẽ làm tình hình tệ hơn vì PHP sẽ yêu cầu thêm bộ nhớ trước khi kernel can thiệp.

Vì sao chỉ /public nên được public trên web

Thư mục gốc của project chứa config.php với database password ở dạng plain text, vendor/ với toàn bộ dependency, và storage/ với log cùng các session đã cache. Không nội dung nào trong đó nên được đưa lên public internet. Flarum đặt toàn bộ nội dung có thể truy cập qua web trong một thư mục con là public/. Thư mục này chứa index.php, một thư mục assets/ và hầu như không có gì khác. Trỏ web server root vào /srv/flarum/public. Khi đó, phần còn lại của cây thư mục không thể truy cập qua HTTP ngay từ thiết kế, thay vì phụ thuộc vào một rule mà bạn phải nhớ cấu hình.

Nếu trỏ root vào /srv/flarum, hậu quả là có thật. Request đến /config.php không trả về nội dung hữu ích, vì PHP thực thi file này và file chỉ trả về một array. Nhưng /storage/logs/flarum.log lại đưa stack trace và database error cho người lạ, còn /composer.lock cho họ biết chính xác version của mọi package bạn đang chạy. Đây là danh sách các lỗ hổng đã biết để họ thử khai thác.

Cấp một pool riêng cho PHP-FPM

Flarum cần quyền ghi vào ba đường dẫn: thư mục gốc của project để installer có thể tạo config.php; storage/ để lưu log và cache; và assets/ để lưu avatar và logo đã upload. Các file thuộc về user flarum, nên cách phù hợp là tạo một PHP-FPM pool chạy với user flarum. nginx vẫn chạy với user www-data và chỉ đọc file.

Tạo /etc/php/8.3/fpm/pool.d/flarum.conf:

[flarum]
user = flarum
group = flarum
listen = /run/php/php8.3-fpm-flarum.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 30s
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 16M
php_admin_value[post_max_size] = 17M
sudo systemctl restart php8.3-fpm
ls -l /run/php/php8.3-fpm-flarum.sock

Socket phải được khai báo là srw-rw---- 1 www-data www-data. Process master chạy dưới quyền root và tạo socket, nên process này có thể gán quyền sở hữu cho www-data trong khi các worker chạy với user flarum. Nếu không có socket, sudo journalctl -u php8.3-fpm -n 30 sẽ in dòng FPM rejected. pm = ondemand chỉ khởi chạy worker khi có request đến, nên một forum ít truy cập hầu như không tốn thêm memory giữa các lần truy cập.

Khối server của nginx

Flarum cung cấp một snippet của nginx trong thư mục gốc của project, có tên là .nginx.conf. Snippet này chứa rewrite rule, cache headers và thiết lập compression. Hãy include snippet thay vì sao chép nội dung, để khi Flarum upgrade và thay đổi snippet, server của bạn nhận được thay đổi đó mà không cần chỉnh sửa thủ công.

server {
    listen 80;
    listen [::]:80;
    server_name forum.example.com;

    root /srv/flarum/public;
    index index.php;
    client_max_body_size 16M;

    include /srv/flarum/.nginx.conf;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm-flarum.sock;
    }
}

Lưu nội dung đó thành /etc/nginx/sites-available/flarum, rồi enable nó.

sudo ln -s /etc/nginx/sites-available/flarum /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

nginx -t phải trả về syntax is oktest is successful. Dòng include là dòng thường bị bỏ sót nhất. Nếu thiếu dòng này, triệu chứng rất cụ thể sẽ xảy ra: trang chủ tải bình thường, nhưng mọi link đến discussion đều trả về lỗi 404 từ nginx. Flarum xử lý một URL như /d/1-hello-world bên trong PHP. Đường dẫn đó không phải là file trên disk. Vì vậy, nếu không có rule try_files $uri $uri/ /index.php?$query_string trong snippet, nginx sẽ tìm một directory có tên d, không tìm thấy directory đó và trả về 404 trước khi PHP được xử lý. Apache dùng cùng cơ chế routing từ file .htaccess đã có sẵn trong public/. Cơ chế này chỉ có hiệu lực khi block <Directory> tương ứng đặt AllowOverride All.

Thêm TLS trước khi chạy trình cài đặt

Tạo chứng chỉ ngay từ đầu, không làm sau. Trong quá trình cài đặt, Flarum ghi base URL của nó vào config.php và lấy URL đó từ địa chỉ trong trình duyệt. Nếu cài đặt qua http://, mọi asset URL mà Flarum tạo sau đó sẽ bắt đầu bằng http://. Khi bạn thêm TLS (transport layer security), trình duyệt sẽ chặn các request này vì mixed content. Forum sẽ chỉ tải dưới dạng văn bản không có style và không có JavaScript. Trước tiên, hãy làm theo hướng dẫn cấu hình certbot cho Let's Encrypt trên nginx, xác nhận https://forum.example.com hiển thị được một trang, rồi quay lại.

Nếu bạn đã cài đặt qua HTTP thuần, chỉ cần sửa một dòng. Chỉnh sửa /srv/flarum/config.php để key url có giá trị 'url' => 'https://forum.example.com',, rồi chạy php flarum cache:clear với user flarum.

Chạy installer và khóa chặt config.php

Mở https://forum.example.com trong trình duyệt. Web installer của Flarum yêu cầu tên database, user và password của database mà bạn đã tạo, tiêu đề forum và tài khoản admin. Installer ghi config.php và tạo các bảng. Khi hoàn tất, hãy siết quyền của file đang chứa database password.

sudo chmod 640 /srv/flarum/config.php

File này vẫn có quyền đọc và ghi đối với flarum, là user mà FPM chạy dưới quyền, và không tài khoản nào khác trên máy có thể đọc file. Sau đó kiểm tra cài đặt từ shell.

php flarum info

Lệnh này in ra version của core, version của PHP, các extension đã enable, mail driver và những path đang được sử dụng. Đây là lệnh đầu tiên cần chạy khi có vấn đề, đồng thời cũng là thông tin đầu tiên người hỗ trợ bạn sẽ yêu cầu.

Vì email đăng ký và đặt lại mật khẩu thất bại mà không có thông báo

Phần này quyết định forum của bạn có tồn tại qua tuần đầu tiên hay không. Hai email đầu tiên mà một forum mới gửi là email xác nhận đăng ký và email đặt lại mật khẩu. Cả hai đều được gửi đúng lúc một người lạ đang quyết định cộng đồng của bạn có hoạt động thật hay không. Cả hai đều có thể thất bại mà không báo lỗi. Người không nhận được email không thể cho bạn biết, còn dashboard quản trị cũng không hiển thị cảnh báo.

Flarum có 4 mail driver, được cấu hình trong Administration rồi đến Email: smtp, mail, mailgunlog. Chọn smtp và trỏ nó đến một mail service có khả năng gửi email thực sự. Driver mail chuyển message cho binary sendmail cục bộ. Binary này không có sẵn trên Ubuntu VPS mới cài, nên message không đi đâu cả và cũng không phát sinh lỗi. Driver log ghi nội dung message vào storage/logs/ và hoàn toàn không gửi email, vì driver này chỉ dành cho development.

Lưu các thiết lập, rồi nhấn nút Gửi email kiểm tra trên chính trang đó. Đây là feedback loop duy nhất bạn có, vì vậy hãy dùng nó trước khi mời bất kỳ ai. Nếu email không đến, hãy đọc log.

tail -n 50 /srv/flarum/storage/logs/flarum.log

Kết nối bị từ chối, đăng nhập bị từ chối và lỗi thương lượng TLS đều được ghi tại đó, cùng với host và port đã thử. Dòng có nội dung Connection could not be established with host smtp.example.com nghĩa là port bị chặn hoặc không đúng. Nguyên nhân thường gặp là provider mặc định chặn port outbound 25. Port 587 với trường encryption đặt thành tls là cấu hình hoạt động với gần như mọi mail service.

Khi mail bị lỗi, visitor đăng ký sẽ thấy banner lỗi chung của Flarum, Oops! Something went wrong. Please reload the page and try again., vì request phát sinh lỗi trong lúc gửi email xác nhận. Dù xảy ra theo cách nào, người đó cũng không thể đăng nhập và sẽ không viết cho bạn để báo lỗi.

Việc mail được chấp nhận là một vấn đề khác với việc mail được gửi đi. Email gửi từ địa chỉ VPS không có record SPF hoặc DKIM được công bố cho domain của bạn có thể rơi vào thư mục spam hoặc bị loại bỏ mà không có bounce message. Khi đó log vẫn hiển thị gửi thành công nhưng người nhận không thấy gì. Gửi mail ổn định từ các app tự host giải thích cần công bố những record DNS nào và nên dùng những relay service nào.

Extension là các package Composer, nên việc nâng cấp được thực hiện bằng command

Trong Flarum, một extension là một package Composer. Không có nút upload và cũng không có file zip để thả vào một thư mục. Đây là một quyết định thiết kế có chủ đích: các version được resolve dựa trên nhau, bộ package chính xác được ghi trong composer.lock, và extension phụ thuộc vào một PHP library sẽ được cài đúng cách. Đổi lại, mỗi lần thêm extension cần chạy ba command với user flarum.

composer require 'fof/upload:*'
php flarum migrate
php flarum cache:clear

Sau đó, bật extension tại Administration rồi Extensions. Mỗi command thực hiện một việc riêng. composer require ghi code vào disk. php flarum migrate chạy các database migration đi kèm extension, nhờ đó extension có thể tạo các table riêng. php flarum cache:clear build lại các bundle JavaScript và CSS đã compile mà browser tải xuống. Bỏ qua bước cuối sẽ dẫn đến lỗi khó hiểu thường gặp: extension đã xuất hiện trong danh sách, toggle đã bật, nhưng browser không thay đổi gì dù bạn reload bao nhiêu lần.

Việc gỡ extension được thực hiện theo chiều ngược lại. Trước tiên, disable extension trong admin panel, sau đó remove package. Flarum cố ý giữ lại các table của extension, để khi bật lại sau này dữ liệu không bị mất. Nếu cũng muốn xóa các table đó, hãy rollback migration của extension trước khi remove code.

php flarum migrate:reset --extension fof-upload
composer remove fof/upload
php flarum cache:clear

Extension id trong command đó là tên package, với dấu slash được thay bằng dấu hyphen. Nếu muốn click thay vì gõ command, composer require 'flarum/extension-manager:*' sẽ thêm một trang admin chính thức để thao tác với Composer. Trang này chạy cùng các operation như web user, cần cùng lượng memory và cùng quyền ghi, đồng thời cũng gặp cùng các lỗi. Vì vậy, khi có sự cố, CLI vẫn là cách đáng tin cậy hơn.

Vì sao composer update từ chối nâng cấp Flarum

Nâng cấp Flarum và mọi extension chỉ cần một lệnh Composer, sau đó chạy 2 lệnh Flarum. Trước tiên, hãy sao lưu database.

composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies
php flarum migrate
php flarum cache:clear

Hãy đọc output thay vì mặc định rằng lệnh đã chạy thành công. Trường hợp đáng chú ý là khi Composer từ chối thực hiện bất kỳ thay đổi nào:

Your requirements could not be resolved to an installable set of packages.

Thông báo đó có nghĩa là một extension đã cài đặt khai báo constraint flarum/core loại trừ release mà bạn đang nâng cấp lên. Composer sẽ không vi phạm constraint này. Vì vậy, nó giữ toàn bộ install ở version cũ thay vì ghép một tổ hợp mà tác giả extension đã xác nhận là không hoạt động. Hãy tìm package gây ra vấn đề.

composer why-not flarum/core 1.8.17

Output liệt kê mọi package đang chặn version đó và constraint mà từng package khai báo. Từ đây, bạn có 2 lựa chọn: chờ tác giả phát hành một release tương thích, hoặc gỡ extension và tiếp tục sử dụng mà không có nó. Đây là cái giá của mô hình Composer, và bạn nên hiểu điều này trước khi cài 15 extension trên một forum mà người khác đang phụ thuộc vào. Ưu tiên các extension gần đây vẫn phát hành release, và giữ danh sách đủ ngắn để bạn có thể đọc hết.

Cần backup những gì

Hãy backup database và thư mục project. Mọi thứ khác có thể dựng lại.

mariadb-dump -u flarum -p --single-transaction flarum > flarum-$(date +%F).sql
sudo tar czf flarum-files.tgz -C /srv flarum

Trên các hệ thống cũ, mariadb-dump được gọi là mysqldump; trên Ubuntu 24.04, cả hai tên đều hoạt động. Database chứa mọi bài viết, mọi user và mọi setting. Thư mục project chứa config.php, composer.json (đây mới là nơi ghi nhận chính xác các extension bạn đang chạy) và assets/ cùng các avatar và logo đã upload. Bạn có thể bỏ qua vendor/, vì composer install sẽ dựng lại nó từ composer.lock, còn storage/ sẽ tự tạo lại. Hãy copy cả hai file ra khỏi server, vì một bản backup nằm trên chính máy mà nó bảo vệ thì không phải là backup. Khôi phục cần một Flarum mới cùng version, composer install, đưa các file đã lưu trở lại đúng vị trí và load file SQL.

FAQ

Flarum có chạy được trên VPS 1 GB không?

Có, nếu cộng đồng nhỏ. Khi hoạt động bình thường, Flarum gồm PHP-FPM xử lý request và MariaDB. Với pm = ondemand, các PHP worker chỉ tồn tại khi có người truy cập. Mức sử dụng cao nhất thường xảy ra trong lúc cài đặt: composer create-project phân giải toàn bộ dependency graph trong memory. Đây là bước dễ bị out-of-memory killer dừng nhất. Hãy thêm swap file trước khi cài đặt, hoặc chạy Composer một lần trên máy lớn hơn rồi copy toàn bộ cây thư mục sang.

server block của nginx đang thiếu include /srv/flarum/.nginx.conf;. Flarum xử lý các URL như /d/1-hello-world bên trong PHP. Đường dẫn đó không phải là file trên disk. Nếu không có rule try_files $uri $uri/ /index.php?$query_string trong snippet, nginx sẽ tìm một directory tên d, không tìm thấy rồi tự trả về 404 mà không gọi PHP. Trên Apache, cơ chế routing tương tự đến từ public/.htaccess. Cơ chế này bị bỏ qua nếu block <Directory> không đặt AllowOverride All.

Vì sao forum mất toàn bộ style sau khi tôi bật HTTPS?

Flarum lưu base URL trong config.php. Giá trị này được lấy từ địa chỉ bạn dùng khi chạy installer. Nếu cài đặt qua HTTP thường, Flarum tiếp tục tạo các URL asset dạng http://. Trình duyệt sẽ chặn các URL này dưới dạng mixed content trên trang HTTPS, khiến nội dung chỉ còn văn bản không có style. Sửa key url trong /srv/flarum/config.php thành địa chỉ https://, rồi chạy php flarum cache:clear bằng user sở hữu các file.

Vì sao không ai nhận được email xác nhận đăng ký?

Trước tiên, hãy kiểm tra mail driver. Driver mail cần một binary sendmail cục bộ, nhưng Ubuntu VPS mới cài thường không có binary này. Driver log chỉ ghi vào storage/logs/ và không gửi email. Chuyển sang smtp, dùng port 587 và đặt encryption thành tls vì hầu hết nhà cung cấp chặn port outbound 25, rồi bấm Gửi email kiểm tra. Nếu log cho thấy email đã gửi thành công nhưng vẫn không đến nơi, vấn đề nằm ở deliverability chứ không phải cấu hình. Khi đó, hãy publish bản ghi SPF và DKIM cho sending domain của bạn.

Nên cài Flarum 1.8 hay 2.0?

Cài 1.8. Tính đến August 2026, Flarum 2.0 vẫn là release candidate. Quan trọng hơn, nhiều extension vẫn khai báo constraint flarum/core chỉ hỗ trợ đến 1.x. Cài 2.0 ngay hôm nay nghĩa là bạn đang chạy một forum mà các extension không thể được update đồng bộ. Đây chính là lỗi mà composer why-not dùng để chẩn đoán. Pin phiên bản bằng flarum/flarum:^1.8.0 và xem xét lại sau khi các extension bạn phụ thuộc đã phát hành bản 2.0.