Date: 2025-06-09
鉴于很多人问和搜索如何使用docker compose部署flarum论坛系统,并且配置msmtpd作为邮件发送服务器,redis作为缓存,meilisearch作为搜索引擎。这里单独发送一个帖子来讨论这个。
注意,此文为分支,汇总贴地址:flarum轻量化开源论坛系统部署 - Piwind Forum
查看部署案例:https://forum.piwind.com/
看到官方没有提供docker部署方式,在dockerhub上找到这个项目:
官方指定的安装方式为:依赖nginx/apache,php 7.3+,mysql 5.6+/8.0.23+,安装PHP仓库管理软件Composer,并通过Composer来下载flarum项目。
本次技术路线:第三方crazymax/flarum构建的docker镜像,后端数据库使用MariaDB,再添加几个辅助容器(msmtpd作为SMTP服务器,redis作为缓存,meilisearch作为搜索引擎)
1. 安装flarum
先从镜像中提取要映射的文件,或者直接手写相应的初始文件(手写注意配owner和权限):
【容器中的/opt/flarum/config.php是每次启动时动态生成的,因此不推荐映射出来,而是通过修改容器环境变量实现修改】
mkdir -p /data/linux/docker_data/flarum/flarum
touch /data/linux/docker_data/flarum/flarum/extend.php
# 注意替换成实际的PUID:PGID
chown 1000:1000 /data/linux/docker_data/flarum/flarum/*
mkdir -p /data/linux/docker_data/flarum/s6-services/flarum-queue
mkdir -p /data/linux/docker_data/flarum/s6-services/cron
touch /data/linux/docker_data/flarum/s6-services/flarum-queue/run
touch /data/linux/docker_data/flarum/s6-services/cron/run
chmod +x /data/linux/docker_data/flarum/s6-services/flarum-queue/run
chmod +x /data/linux/docker_data/flarum/s6-services/cron/run
编写 /data/linux/docker_data/flarum/flarum/extend.php,内容如下:
<?php
use Flarum\Extend;
return [
(new FoF\Redis\Extend\Redis([
'host' => 'flarum_redis',
'password' => 'testpassword',
'port' => 6379,
'database' => 1,
'queue' => [
'retry_after' => 120, // seconds
'block_for' => 5, // seconds
'after_commit' => true
]
]))
->useDatabaseWith('cache', 1)
->useDatabaseWith('queue', 2)
->useDatabaseWith('session', 3)
];
编写 /data/linux/docker_data/flarum/s6-services/flarum-queue/run,内容如下:
#!/usr/bin/execlineb -P
s6-setuidgid 1000:1000 # 注意替换成实际的PUID:PGID
php /opt/flarum/flarum queue:work
编写 /data/linux/docker_data/flarum/s6-services/cron/run,内容如下:
#!/usr/bin/execlineb -P
foreground {
redirfd -w 1 /var/spool/cron/crontabs/root
echo "* * * * * php /opt/flarum/flarum schedule:run"
}
crond -f -L /dev/stdout
在portainer中创建stack,命名为 flarum
,注意点如下:
不能把/opt/flarum整个映射出来
修改FLARUM_BASE_URL为实际
MEILI_MASTER_KEY可以用 uuidgen 来随机生成一个
SMTP_STARTTLS在使用端口587的时候on,使用端口465的时候off
REAL_IP_FROM填写可信代理ip,也就是stack的docker network的Subnet,查看方式为:
docker network inspect flarum_default | grep Subnet
内容如下:
name: flarum
services:
flarum:
image: crazymax/flarum:1.8.9
container_name: flarum
restart: unless-stopped
ports:
- '2042:8000'
volumes:
- '/data/linux/docker_data/flarum/data:/data'
- '/data/linux/docker_data/flarum/flarum/extend.php:/opt/flarum/extend.php'
- '/data/linux/docker_data/flarum/s6-services/flarum-queue:/etc/services.d/flarum-queue'
- '/data/linux/docker_data/flarum/s6-services/cron:/etc/services.d/cron'
environment:
- "TZ=Asia/Hong_Kong"
- "FLARUM_FORUM_TITLE=Piwind Forum"
- "DB_HOST=db"
- "DB_NAME=flarum"
- "DB_USER=flarum"
- "DB_PASSWORD=testpassword"
- "MEMORY_LIMIT=256M"
- "UPLOAD_MAX_SIZE=16M"
- "OPCACHE_MEM_SIZE=128"
- "REAL_IP_FROM=172.21.0.0/16"
- "REAL_IP_HEADER=X-Forwarded-For"
- "LOG_IP_VAR=remote_addr"
- "FLARUM_DEBUG=false"
- "FLARUM_BASE_URL=http://127.0.0.1:8000"
- "FLARUM_POWEREDBY_HEADER=false"
- "FLARUM_REFERRER_POLICY=strict-origin-when-cross-origin"
depends_on:
- db
- msmtpd
- redis
- meilisearch
db:
image: mariadb:10.11.11
container_name: flarum_db
restart: unless-stopped
command:
- "mysqld"
- "--character-set-server=utf8mb4"
- "--collation-server=utf8mb4_unicode_ci"
volumes:
- "/data/linux/docker_data/flarum/db:/var/lib/mysql"
environment:
- "TZ=Asia/Hong_Kong"
- "MARIADB_RANDOM_ROOT_PASSWORD=yes"
- "MYSQL_DATABASE=flarum"
- "MYSQL_USER=flarum"
- "MYSQL_PASSWORD=testpassword"
msmtpd:
image: crazymax/msmtpd:1.8.28
container_name: flarum_msmtpd
restart: unless-stopped
environment:
- "TZ=Asia/Hong_Kong"
- "SMTP_HOST=smtp.gmail.com"
- "SMTP_PORT=587"
- "SMTP_TLS=on"
- "SMTP_STARTTLS=on"
- "SMTP_TLS_CHECKCERT=on"
- "SMTP_AUTH=on"
- "SMTP_USER=foo"
- "SMTP_PASSWORD=bar"
- "SMTP_FROM=foo@gmail.com"
redis:
image: redis:7.4.2
container_name: flarum_redis
restart: unless-stopped
command: redis-server --requirepass testpassword
volumes:
- "/data/linux/docker_data/flarum/redis:/data"
depends_on:
- db
meilisearch:
image: getmeili/meilisearch:v1.13.3
container_name: flarum_meilisearch
restart: unless-stopped
command: /bin/meilisearch
volumes:
- "/data/linux/docker_data/flarum/meili_data:/meili_data"
environment:
- MEILI_MASTER_KEY=xxxxxxxxxxxxxxxx
- MEILI_NO_ANALYTICS=true
- MEILI_ENV=production
depends_on:
- db
- redis
补充解释:
- FLARUM_POWEREDBY_HEADER=false,隐藏网站响应头中的X-Powered-By信息,这个是用来显示技术栈的,比如该应用就是Flarum,没必要暴露出来
- FLARUM_REFERRER_POLICY=strict-origin-when-cross-origin,默认的same-origin会在跨源请求(Cross-Origin)中不发送referer请求头,会影响防盗链策略
stack启动后还需要配置nginx,创建文件 /etc/nginx/conf.d/forum.piwind.com.conf,内容如下:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name forum.piwind.com;
ssl_certificate /data/linux/files/tls_certs/piwind.com.fullchain.cer;
ssl_certificate_key /data/linux/files/tls_certs/piwind.com.key;
# 添加可信代理设置(Docker网关IP范围)
set_real_ip_from 172.21.0.0/16;
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# Gzip compression
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/javascript
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
location / {
proxy_pass http://127.0.0.1:2042/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
add_header 'Access-Control-Allow-Headers' 'Origin, x-requested-with, Content-Type, Accept, Authorization';
add_header 'Access-Control-Expose-Headers' 'Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma';
# 处理预检请求
if ($request_method = 'OPTIONS') {
# 预检请求缓存时间
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_connect_timeout 600;
proxy_read_timeout 600;
}
}
为了msmtpd能够使用gmail的SMTP服务,需要在gmail上开启SMTP服务:
2. 基础配置
通过URL首次登录,输入管理员的默认账密(账号:flarum,密码:flarum)登录
先进入Admin area,Email,设置如下:
Addresses: no-reply@gmail.com
Driver: smtp
Host: msmtpd
Port: 2500
【这里如果填写的Addresses的和gmail SMTP的邮箱不一致的话】,会在邮件源码中添加一行这个信息例如:
X-Google-Original-From: Piwind Forum <noreply@piwind.com>
并且用户收到邮件看到的发件人仍然为SMTP的邮箱地址,而不是这里填写的
需要在gmail中将期望的邮箱地址授权为发件人地址并完成验证,才能将这个地址替换"From"字段
管理员账号修改邮箱,发送修改密码的邮件修改密码
右上角 设置 - 操作 - 编辑,修改昵称和用户名,可以修改为admin
Dashboard中,把基础的Features全都开起来(核心插件)
Flags 帖子旁边添加举报按钮
Approval 让主题和回复变得需要管理员审批才能公开
BBCode 传统的论坛文本格式化语法,例如[b]text[/b],还包括登录可见等专属于论坛的语法
Emoji 表情功能,例如 :cry 就是哭脸表情
Likes 可以赞帖子【不启用,用fof/gamification来替代,但是注意关闭原生Likes插件会导致基于Likes的插件功能故障】
Lock 可以锁定帖子不接受回复(默认只有管理员能锁定帖子)
Markdown 帖子支持markdown(但语法有限,例如表格不行)
Mentions 帖子可以@用户名或昵称(允许@用户名,开启)
Nicknames User Display Name要设置成nickname才能生效,开启唯一昵称,昵称长度6~20
Pusher 新主题或回复发布后,会立即出现,无需手动刷新页面【需要配置】
Statistics 方便管理员统计论坛中的数据
Sticky 管理员可以置顶主题
Subscriptions 允许用户关注讨论并接收新帖子的通知
Suspend 允许管理员禁言用户,在点开用户的主页之后操作禁言
Tags 给论坛添加标签功能,有primary tags和secondary tags,分别起到分类和标签的作用
3. 安装插件
使用docker容器里的脚本extension
,也可以用composer
,命令如下:
## 安装flarum插件
extension require <package> [<package> ...]
## 删除插件
extension remove <package> [<package> ...]
## 列举安装的插件
extension list
## 例如安装 fof/upload
# 其链接为:https://flarum.org/extension/fof/upload
extension require fof/upload
## 可以直接调用,也可以进shell
docker exec -it flarum sh
extension require fof/upload
docker exec -it flarum extension require fof/upload
## 查看所有已安装的composer包(包括 Flarum 核心和插件)【看到296个】
composer show
## 只查看直接依赖的包(不包括依赖的依赖)【看到100个】
composer show --direct
## 查看特定 Flarum 扩展的信息(例如 flarum-tags)
composer show flarum/tags
## Flarum 提供了 info 命令来查看已安装的扩展【看到83个】
php flarum info
## 还可以看composer.json【看到100个】
cat composer.json
## 还有vender下【看到296个】
find vendor/ -maxdepth 2 -mindepth 2 -type d | wc -l
简体中文
docker exec -it flarum extension require flarum-lang/chinese-simplified
在仪表盘中启用即可,再在常规中,设置默认语言,显示语言选择器
Redis配置sessions, cache, queues
docker exec -it flarum extension require fof/redis
检查flarum-redis生效:
默认情况下,队列驱动程序是 sync,会话驱动程序是 file,配置好redis之后在仪表盘可以看到如下:

完成后还需要配置Laravel 队列以持续监听redis中的队列并执行任务:
(不配置的话会导致用户通知收不到等问题)
方法通常有配置supervisor 或 systemd,本次采用镜像中已有的s6-overlay工具,也就是前面安装flarum过程中配置的 s6-services/flarum-queue/run,在容器进程中能看到php /opt/flarum/flarum queue:work
的进程常驻即可。
Meilisearch配置Scout Search【TODO】
docker exec -it flarum extension require clarkwinkelmann/flarum-ext-scout
docker exec -it flarum extension require meilisearch/meilisearch-php
Scout Search,启用,配置如下:
驱动:Meilisearch
处理队列中的索引更新:开
Meilisearch 主机地址:http://flarum_meilisearch:7700
Meilisearch 秘钥:xxxxxxxxxxxxxxxx
配置完之后还需要初始化构建索引:
docker exec -it flarum php flarum scout:import-all
之后就可以正常调用搜索了。
TODO:
最佳回复best-answer
docker exec -it flarum extension require fof/best-answer
FoF Best Answer,启用,必要配置如下(因为可能会和Scout Search冲突):
问答搜索:关
在主搜索中隐藏:关
在搜索结果中展示标签:关
注意:fof/best-answer插件依赖scheduler实现定时提醒任务,需要在cron中配置:
本次使用s6-overlay工具来守护crond -f
的进程,让其每分钟执行php /opt/flarum/flarum schedule:run
,,也就是前面安装flarum过程中配置的 s6-services/cron/run,配置成功后在dashboard中可以看到如下:

Extension Manager
docker exec -it flarum extension require flarum/extension-manager
方便安装和更新扩展程序,可以设置在队列中执行操作,不过没有查看现有扩展列表的功能,管理页面中没有启用的插件,右侧有重置和卸载的按钮
参考链接