在 Alpine 容器中手动搭建 Discuz 全攻略
—
🧭 架构流程图与请求链路解析
下面这张图清晰地展示了用户访问你的 Discuz! 论坛时,各个组件是如何协同工作的:
步骤说明
| 步骤 | 动作 | 说明 |
|---|---|---|
| 1 | 用户浏览器 → 宿主机 :8080 | 用户在地址栏输入http://服务器IP:8080 |
| 2 | 宿主机 → 容器 :80 | Docker 的端口映射把请求转发到容器内部的 80 端口 |
| 3a | Nginx → 静态文件 | 如果请求的是图片、CSS 等静态资源,Nginx 直接读取文件并返回 |
| 3b | Nginx → PHP-FPM | 如果请求的是.php文件(比如forum.php),Nginx 把请求转给 PHP-FPM 处理 |
| 4 | PHP-FPM → MariaDB | Discuz! 执行过程中需要读取或保存数据(帖子、用户等),PHP 连接数据库 |
| 5 | MariaDB → PHP-FPM | 数据库返回查询结果(比如帖子列表) |
| 6 | PHP-FPM → Nginx | PHP 执行完毕,生成完整的 HTML 页面,返回给 Nginx |
| 7 | 容器 → 宿主机 | Nginx 把响应发送回 Docker 宿主机 |
| 8 | 宿主机 → 用户浏览器 | 宿主机把响应返回给用户的浏览器,用户看到完整的论坛页面 |
核心流程总结:用户 → 宿主机 → 容器 → Nginx → (如果是 PHP) → PHP-FPM → 数据库 → PHP-FPM → Nginx → 宿主机 → 用户。静态文件请求则跳过 PHP-FPM 和数据库,由 Nginx 直接返回。
🐳 第一部分:准备工作 —— 安装 Docker
如果你只想快速部署,可以直接跳到第三部分,一键脚本会自动完成 Docker 的安装和配置。这里仅作知识补充。
什么是 Docker?
Docker 就像是一个“集装箱系统”。你可以把网站、数据库、应用程序全部装进一个独立的“集装箱”(容器)里,在任何有 Docker 的电脑上运行,不用担心环境不一致。
手动安装 Docker 命令(脚本会自动执行)
# 更新系统并安装依赖sudodnf update-ysudodnfinstall-yyum-utils device-mapper-persistent-data lvm2# 添加 Docker 官方仓库(兼容 openEuler)sudoyum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.reposudosed-i's/$releasever/8/g'/etc/yum.repos.d/docker-ce.repo# 安装 Dockersudodnfinstall-ydocker-ce docker-ce-cli containerd.io docker-compose-plugin# 启动并设置开机自启sudosystemctl startdockersudosystemctlenabledocker# 验证安装sudodockerrun hello-world📖 第二部分:手动搭建 Discuz! X5.0(了解原理)
为了让你了解整个搭建过程,我将手动操作的步骤也列在下面。如果你想快速部署,可以直接跳到第三部分,一键脚本会为你自动完成。
2.1 启动 Alpine 容器并进入内部
dockerrun-it--namediscuz-manual alpine:latest /bin/sh2.2 安装必要软件包
# 更新软件源并安装软件apk update apkadd--no-cache nginx php83 php83-fpm php83-mysqli php83-pdo php83-pdo_mysql\php83-session php83-json php83-mbstring php83-tokenizer php83-gd php83-curl\php83-xml php83-openssl php83-zip mariadb mariadb-clientwgetunzip为什么安装这些?
- php83-pdo, php83-pdo_mysql:Discuz! X5.0 推荐使用 PDO 扩展来连接和操作数据库。
- php83-gd:用于处理验证码和图片水印等功能。
- php83-xml, php83-curl, php83-openssl:Discuz! 依赖这些扩展处理 XML、进行网络通信和加密。
- 其他扩展如
json,mbstring,session等,Discuz! 在运行时也需要它们。
2.3 初始化数据库
# 创建运行时目录并设置权限mkdir-p/run/mysqld&&chownmysql:mysql /run/mysqld# 初始化数据库mysql_install_db--user=mysql--datadir=/var/lib/mysql# 以后台模式启动 MariaDBmysqld_safe--user=mysql&sleep5# 设置数据库 root 密码mysqladmin-uroot password'example'# 创建 Discuz! 数据库和用户mysql-uroot -p'example'<<EOF CREATE DATABASE discuz; CREATE USER 'discuzuser'@'localhost' IDENTIFIED BY 'discuzpass'; GRANT ALL PRIVILEGES ON discuz.* TO 'discuzuser'@'localhost'; FLUSH PRIVILEGES; EOF2.4 下载并解压 Discuz! X5.0
# 创建网站根目录mkdir-p/var/www/localhostcd/var/www/localhost# 下载 Discuz! X5.0 简体中文 UTF8 版本# 官方推荐下载地址: https://download.discuz.vip/redirect/?X5.0wgethttps://download.discuz.vip/redirect/?X5.0-ODiscuz_X5.0_SC_UTF8.zip# 解压unzipDiscuz_X5.0_SC_UTF8.zip# 将 upload 目录下的所有文件移动到当前目录mvupload/* ./rm-rfupload# 删除压缩包rmDiscuz_X5.0_SC_UTF8.zip# 设置目录权限(Discuz! 需要 data、config 等目录可写)chown-Rnginx:nginx /var/www/localhostchmod-R755/var/www/localhost2.5 配置 Nginx
cat>/etc/nginx/http.d/default.conf<<'EOF' server { listen 80 default_server; listen [::]:80 default_server; root /var/www/localhost; index index.php index.html; client_max_body_size 20M; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi.conf; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } EOF为什么这样配置?
client_max_body_size 20M;:Discuz! 支持附件上传,因此需要调大上传文件的大小限制。location /:这是 Discuz 的伪静态规则,确保论坛的各种页面能够正确访问。
2.6 配置 PHP-FPM
# 修改监听端口和运行用户sed-i's/^listen = 127.0.0.1:9000/; listen = 127.0.0.1:9000/'/etc/php83/php-fpm.d/www.confecho"listen = 127.0.0.1:9000">>/etc/php83/php-fpm.d/www.confsed-i's/^user = nobody/user = nginx/'/etc/php83/php-fpm.d/www.confsed-i's/^group = nobody/group = nginx/'/etc/php83/php-fpm.d/www.conf2.7 启动服务并保持容器运行
# 启动 PHP-FPMphp-fpm83-F&# 启动 Nginxnginx-g'daemon off;'&# 保持容器不退出tail-f/dev/null按Ctrl + P再按Ctrl + Q退出容器但不停止。
2.8 提交容器为镜像并映射端口
在宿主机执行:
dockercommit discuz-manual discuz:manualdockerstop discuz-manual&&dockerrmdiscuz-manualdockerrun-d--namediscuz-running-p8080:80 discuz:manual\/bin/sh-c"mysqld_safe --user=mysql & php-fpm83 -F & nginx -g 'daemon off;' & tail -f /dev/null"然后访问http://宿主机IP:8080/install/开始安装。
🚀 第三部分:一键部署脚本(带进度条,自动打包镜像)
这里是本指南的核心!你只需要复制下面的脚本,粘贴到虚拟机/服务器的终端中运行,脚本会自动完成所有配置、安装和打包工作。你无需看前面的任何内容,直接运行这个脚本即可!
📜 一键部署脚本(从零开始,包含镜像源配置)
将以下整个代码块保存为deploy_discuz.sh:
#!/bin/bash# ============================================# 一键部署 Discuz! X5.0 并打包为可迁移镜像(带进度条)# 包含:配置国内镜像源、安装 Docker、构建镜像、导出 tar# 使用方法: chmod +x deploy_discuz.sh && sudo ./deploy_discuz.sh# ============================================set-e# 颜色定义RED='\033[0;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'BLUE='\033[0;34m'NC='\033[0m'# 进度条函数progress_bar(){localstep_name=$1localduration=${2:-1}localwidth=40localpercent=0echo-ne"${BLUE}[${step_name}]${NC}"for((i=0;i<=width;i++));dopercent=$((i*100/width))echo-ne"\r${BLUE}[${step_name}]${NC}["for((j=0;j<i;j++));doecho-n"=";donefor((j=i;j<width;j++));doecho-n" ";doneecho-n"]${percent}%"sleep$(echo"$duration/$width"|bc-l2>/dev/null||echo"0.025")doneecho-e"${GREEN}✓${NC}"}# 执行命令并静默输出run_silent(){"$@">/dev/null2>&1}echo-e"${GREEN}========================================${NC}"echo-e"${GREEN}Discuz! X5.0 一键部署 + 打包脚本${NC}"echo-e"${GREEN}========================================${NC}"# ------------------ 步骤0: 配置国内镜像源 ------------------progress_bar"配置系统镜像源(国内加速)"1if[-f/etc/yum.repos.d/openEuler.repo];thencp/etc/yum.repos.d/openEuler.repo /etc/yum.repos.d/openEuler.repo.bak2>/dev/null||trueficat>/etc/yum.repos.d/openEuler.repo<<'EOF' [OS] name=OS baseurl=https://repo.huaweicloud.com/openeuler/openEuler-24.03-LTS/OS/$basearch/ enabled=1 gpgcheck=0 [everything] name=everything baseurl=https://repo.huaweicloud.com/openeuler/openEuler-24.03-LTS/everything/$basearch/ enabled=1 gpgcheck=0 [EPOL] name=EPOL baseurl=https://repo.huaweicloud.com/openeuler/openEuler-24.03-LTS/EPOL/main/$basearch/ enabled=1 gpgcheck=0 EOFrun_silent dnf clean all run_silent dnf makecache# ------------------ 步骤1: 检查/安装 Docker ------------------progress_bar"检查 Docker 环境"0.5if!command-vdocker&>/dev/null;thenecho-e"${YELLOW}Docker 未安装,正在自动安装...${NC}"run_silent dnfinstall-yyum-utils device-mapper-persistent-data lvm2 run_silent yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo run_silentsed-i's/$releasever/8/g'/etc/yum.repos.d/docker-ce.repo run_silent dnfinstall-ydocker-ce docker-ce-cli containerd.io docker-compose-plugin run_silent systemctl startdockerrun_silent systemctlenabledockerecho-e"${GREEN}Docker 安装完成。${NC}"elseecho-e"${GREEN}Docker 已安装。${NC}"fi# 配置 Docker 镜像加速progress_bar"配置 Docker 镜像加速"0.5mkdir-p/etc/dockercat>/etc/docker/daemon.json<<'EOF' { "registry-mirrors": ["https://registry.cn-hangzhou.aliyuncs.com"] } EOFrun_silent systemctl restartdocker# ------------------ 步骤2: 用户输入端口 ------------------read-p"请输入要映射的宿主机端口 (默认 8080): "HOST_PORTHOST_PORT=${HOST_PORT:-8080}# ------------------ 步骤3: 生成随机密码 ------------------progress_bar"生成随机数据库密码"0.5DB_ROOT_PASS=$(openssl rand-base6412|tr-d"=+/"|cut-c1-16)DB_DISCUZ_PASS=$(openssl rand-base6412|tr-d"=+/"|cut-c1-16)echo-e"${YELLOW}数据库 root 密码:${DB_ROOT_PASS}${NC}"echo-e"${YELLOW}Discuz! 数据库用户 discuzuser 密码:${DB_DISCUZ_PASS}${NC}"echo-e"${YELLOW}请保存好这些密码!${NC}"# ------------------ 步骤4: 创建临时目录和文件 ------------------progress_bar"准备 Dockerfile 和启动脚本"0.5TEMP_DIR=$(mktemp-d)cd$TEMP_DIRcat>Dockerfile<<'EOF' FROM alpine:latest # 使用国内镜像源加速下载 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories # 安装软件包 RUN apk update && apk add --no-cache \ nginx php83 php83-fpm php83-mysqli php83-pdo php83-pdo_mysql \ php83-session php83-json php83-mbstring php83-tokenizer php83-gd \ php83-curl php83-xml php83-openssl php83-zip \ mariadb mariadb-client wget unzip # 创建目录 RUN mkdir -p /run/mysqld /var/www/localhost && chown mysql:mysql /run/mysqld # 设置工作目录 WORKDIR /var/www/localhost # 下载并解压 Discuz! X5.0 RUN wget https://download.discuz.vip/redirect/?X5.0 -O Discuz_X5.0_SC_UTF8.zip && \ unzip Discuz_X5.0_SC_UTF8.zip && \ mv upload/* ./ && \ rm -rf upload && \ rm Discuz_X5.0_SC_UTF8.zip && \ chown -R nginx:nginx /var/www/localhost && \ chmod -R 755 /var/www/localhost # 复制启动脚本 COPY start.sh /start.sh RUN chmod +x /start.sh EXPOSE 80 CMD ["/start.sh"] EOFcat>start.sh<<'EOF' #!/bin/sh # 初始化数据库 if [ ! -d "/var/lib/mysql/mysql" ]; then mysql_install_db --user=mysql --datadir=/var/lib/mysql > /dev/null 2>&1 fi # 启动 MariaDB mysqld_safe --user=mysql > /dev/null 2>&1 & sleep 5 # 设置密码和创建数据库(仅首次) if [ ! -f "/var/lib/mysql/.discuz_initialized" ]; then mysqladmin -u root password "${DB_ROOT_PASS}" > /dev/null 2>&1 mysql -u root -p"${DB_ROOT_PASS}" <<EOSQL > /dev/null 2>&1 CREATE DATABASE IF NOT EXISTS discuz; CREATE USER IF NOT EXISTS 'discuzuser'@'localhost' IDENTIFIED BY '${DB_DISCUZ_PASS}'; GRANT ALL PRIVILEGES ON discuz.* TO 'discuzuser'@'localhost'; FLUSH PRIVILEGES; EOSQL touch /var/lib/mysql/.discuz_initialized fi # 配置 Nginx cat > /etc/nginx/http.d/default.conf <<'NGINXCONF' server { listen 80 default_server; listen [::]:80 default_server; root /var/www/localhost; index index.php index.html; client_max_body_size 20M; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi.conf; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } NGINXCONF # 配置 PHP-FPM sed -i 's/^listen = 127.0.0.1:9000/; listen = 127.0.0.1:9000/' /etc/php83/php-fpm.d/www.conf echo "listen = 127.0.0.1:9000" >> /etc/php83/php-fpm.d/www.conf sed -i 's/^user = nobody/user = nginx/' /etc/php83/php-fpm.d/www.conf sed -i 's/^group = nobody/group = nginx/' /etc/php83/php-fpm.d/www.conf # 启动服务 php-fpm83 -F > /dev/null 2>&1 & nginx -g 'daemon off;' > /dev/null 2>&1 & # 保持容器运行 tail -f /dev/null EOFsed-i"s/\${DB_ROOT_PASS}/${DB_ROOT_PASS}/g"start.shsed-i"s/\${DB_DISCUZ_PASS}/${DB_DISCUZ_PASS}/g"start.sh# ------------------ 步骤5: 构建 Docker 镜像 ------------------progress_bar"构建 Docker 镜像 (约2-3分钟)"2run_silentdockerbuild-tdiscuz:auto.# ------------------ 步骤6: 首次运行容器 ------------------progress_bar"启动临时容器"0.5dockerrun-d--namediscuz-temp-p${HOST_PORT}:80 discuz:auto>/dev/nullSERVER_IP=$(iproute get1|awk'{print $NF;exit}')echo-e"${GREEN}========================================${NC}"echo-e"临时容器已启动!请立即打开浏览器访问:${GREEN}http://${SERVER_IP}:${HOST_PORT}/install/${NC}"echo-e"按照 Discuz! 安装向导完成安装:"echo-e" 1. 阅读并同意许可协议"echo-e" 2. 环境检测(全部应为绿色“√”)"echo-e" 3. 设置数据库信息:数据库名 discuz,用户名 discuzuser,密码${YELLOW}${DB_DISCUZ_PASS}${NC}"echo-e" 4. 设置管理员账号"echo-e"${YELLOW}安装完成后,回到本终端按回车键继续...${NC}"read-p""# ------------------ 步骤7: 提交最终镜像 ------------------progress_bar"提交最终镜像"0.5run_silentdockercommit discuz-temp discuz:final# ------------------ 步骤8: 导出 tar 文件 ------------------progress_bar"导出镜像为 tar 文件"1run_silentdockersave-odiscuz-final.tar discuz:finalecho-e"${GREEN}镜像已导出为:$(pwd)/discuz-final.tar${NC}"# ------------------ 步骤9: 清理临时容器 ------------------progress_bar"清理临时资源"0.5run_silentdockerstop discuz-temp run_silentdockerrmdiscuz-temprm-rf$TEMP_DIR# ------------------ 完成 ------------------echo-e"${GREEN}========================================${NC}"echo-e"${GREEN}🎉 全部完成!${NC}"echo-e"最终镜像:${YELLOW}discuz:final${NC}"echo-e"导出文件:${YELLOW}discuz-final.tar${NC}"echo-e""echo-e"${BLUE}迁移方法:${NC}"echo-e"1. 将 discuz-final.tar 复制到另一台 Docker 主机"echo-e"2. 执行:${YELLOW}docker load -i discuz-final.tar${NC}"echo-e"3. 运行:${YELLOW}docker run -d --name discuz -p 8080:80 discuz:final /bin/sh -c\"mysqld_safe --user=mysql & php-fpm83 -F & nginx -g 'daemon off;' & tail -f /dev/null\"${NC}"echo-e"${GREEN}========================================${NC}"🔧 如何使用一键脚本
- 登录你的虚拟机或服务器(例如通过 SSH)。
- 创建脚本文件:
按videploy_discuz.shi进入编辑模式,将上面整个脚本内容完整复制粘贴进去,然后按ESC,输入:wq保存退出。 - 赋予执行权限:
chmod+x deploy_discuz.sh - 运行脚本(需要 root 权限):
sudo./deploy_discuz.sh - 按提示输入端口(直接回车使用默认 8080,或输入其他如 8888)。
- 等待脚本自动完成:
- 脚本会配置国内镜像源(华为云、阿里云)。
- 自动安装 Docker。
- 配置 Docker 镜像加速。
- 生成随机数据库密码。
- 构建镜像(大约2-3分钟)。
- 启动临时容器。
- 打开浏览器,访问脚本输出的地址(如
http://你的服务器IP:8080/install/),按照 Discuz! 安装向导完成安装。安装时,数据库信息请使用脚本输出的discuzuser和对应的密码。 - 安装完成后,回到终端按回车键,脚本会自动将容器提交为最终镜像,并导出
discuz-final.tar文件。 - 完成!你现在拥有:
- 本地 Docker 镜像:
discuz:final - 可迁移的 tar 文件:
discuz-final.tar
- 本地 Docker 镜像:
💾 第四部分:镜像打包与迁移详解
4.1 导出镜像
如果你没有使用一键脚本,或者想要单独导出镜像,可以使用docker save命令:
dockersave-odiscuz-final.tar discuz:final4.2 在另一台机器上导入
dockerload-idiscuz-final.tar4.3 运行迁移后的容器
dockerrun-d--namediscuz-migrated-p8080:80 discuz:final\/bin/sh-c"mysqld_safe --user=mysql & php-fpm83 -F & nginx -g 'daemon off;' & tail -f /dev/null"然后访问http://新机器IP:8080,你的论坛就完整迁移过来了!
🔧 第五部分:常见问题 & 小贴士
❓ 脚本执行过程中卡住了?
- 检查网络是否正常(需要下载 Alpine 包和 Discuz! X5.0)。
- 可以尝试手动运行
docker logs discuz-temp查看容器日志。
❓ 浏览器无法访问?
- 检查防火墙:
sudo firewall-cmd --add-port=8080/tcp --permanent && sudo firewall-cmd --reload - 检查容器状态:
docker ps应显示Up
❓ Discuz! 安装时提示“无法连接数据库”?
- 请确保在安装向导中填写的数据库信息与脚本输出的
discuzuser和密码完全一致。 - 数据库主机应填写
localhost。
❓ Discuz! X5.0 对 PHP 和数据库的版本要求是什么?
Discuz! X5.0 要求PHP >= 8.0(推荐 8.1 - 8.5),MySQL >= 5.7或MariaDB >= 10.2(推荐 8.0)。本指南使用的 PHP 8.3 和 MariaDB 完全满足这些要求。
❓ 如何修改数据库密码?
进入容器后执行:
dockerexec-itdiscuz-temp /bin/sh mysqladmin-uroot -p'旧密码'password'新密码'mysql-uroot -p'新密码'-e"ALTER USER 'discuzuser'@'localhost' IDENTIFIED BY '新新密码';"然后,需要修改 Discuz! 的配置文件config/config_global.php中的数据库密码,才能让论坛正常连接。
❓ 导出的 tar 文件太大怎么办?
可以压缩:gzip discuz-final.tar,得到discuz-final.tar.gz。导入前先解压:gunzip discuz-final.tar.gz。
🎉 结语
通过一键脚本,我们完成了:
- 自动配置国内镜像源,加速下载。
- 自动安装 Docker 并配置加速。
- 自动构建包含最新版 Discuz! X5.0 的 Alpine 镜像。
- 自动启动容器并引导你完成安装。
- 自动提交最终镜像并导出 tar 文件。
如何修改数据库密码?
进入容器后执行:
dockerexec-itdiscuz-temp /bin/sh mysqladmin-uroot -p'旧密码'password'新密码'mysql-uroot -p'新密码'-e"ALTER USER 'discuzuser'@'localhost' IDENTIFIED BY '新新密码';"然后,需要修改 Discuz! 的配置文件config/config_global.php中的数据库密码,才能让论坛正常连接。
❓ 导出的 tar 文件太大怎么办?
可以压缩:gzip discuz-final.tar,得到discuz-final.tar.gz。导入前先解压:gunzip discuz-final.tar.gz。
🎉 结语
通过一键脚本,我们完成了:
- 自动配置国内镜像源,加速下载。
- 自动安装 Docker 并配置加速。
- 自动构建包含最新版 Discuz! X5.0 的 Alpine 镜像。
- 自动启动容器并引导你完成安装。
- 自动提交最终镜像并导出 tar 文件。