在 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 命令(脚本会自动执行)
bash
# 更新系统并安装依赖
sudo dnf update -y
sudo dnf install -y yum-utils device-mapper-persistent-data lvm2
# 添加 Docker 官方仓库(兼容 openEuler)
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo sed -i 's/$releasever/8/g' /etc/yum.repos.d/docker-ce.repo
# 安装 Docker
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 验证安装
sudo docker run hello-world
📖 第二部分:手动搭建 Discuz! X5.0(了解原理)
为了让你了解整个搭建过程,我将手动操作的步骤也列在下面。如果你想快速部署,可以直接跳到第三部分,一键脚本会为你自动完成。
2.1 启动 Alpine 容器并进入内部
bash
docker run -it --name discuz-manual alpine:latest /bin/sh
2.2 安装必要软件包
bash
# 更新软件源并安装软件
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
为什么安装这些?
- 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 初始化数据库
bash
# 创建运行时目录并设置权限
mkdir -p /run/mysqld && chown mysql:mysql /run/mysqld
# 初始化数据库
mysql_install_db --user=mysql --datadir=/var/lib/mysql
# 以后台模式启动 MariaDB
mysqld_safe --user=mysql &
sleep 5
# 设置数据库 root 密码
mysqladmin -u root password 'example'
# 创建 Discuz! 数据库和用户
mysql -u root -p'example' <<EOF
CREATE DATABASE discuz;
CREATE USER 'discuzuser'@'localhost' IDENTIFIED BY 'discuzpass';
GRANT ALL PRIVILEGES ON discuz.* TO 'discuzuser'@'localhost';
FLUSH PRIVILEGES;
EOF
2.4 下载并解压 Discuz! X5.0
bash
# 创建网站根目录
mkdir -p /var/www/localhost
cd /var/www/localhost
# 下载 Discuz! X5.0 简体中文 UTF8 版本
# 官方推荐下载地址: https://download.discuz.vip/redirect/?X5.0
wget https://download.discuz.vip/redirect/?X5.0 -O Discuz_X5.0_SC_UTF8.zip
# 解压
unzip Discuz_X5.0_SC_UTF8.zip
# 将 upload 目录下的所有文件移动到当前目录
mv upload/* ./
rm -rf upload
# 删除压缩包
rm Discuz_X5.0_SC_UTF8.zip
# 设置目录权限(Discuz! 需要 data、config 等目录可写)
chown -R nginx:nginx /var/www/localhost
chmod -R 755 /var/www/localhost
2.5 配置 Nginx
bash
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
bash
# 修改监听端口和运行用户
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
2.7 启动服务并保持容器运行
bash
# 启动 PHP-FPM
php-fpm83 -F &
# 启动 Nginx
nginx -g 'daemon off;' &
# 保持容器不退出
tail -f /dev/null
按 Ctrl + P 再按 Ctrl + Q 退出容器但不停止。
2.8 提交容器为镜像并映射端口
在宿主机执行:
bash
docker commit discuz-manual discuz:manual
docker stop discuz-manual && docker rm discuz-manual
docker run -d --name discuz-running -p 8080: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:
bash
#!/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() {
local step_name=$1
local duration=${2:-1}
local width=40
local percent=0
echo -ne "${BLUE}[${step_name}] ${NC}"
for ((i=0; i<=width; i++)); do
percent=$((i * 100 / width))
echo -ne "\r${BLUE}[${step_name}] ${NC}["
for ((j=0; j<i; j++)); do echo -n "="; done
for ((j=i; j<width; j++)); do echo -n " "; done
echo -n "] ${percent}%"
sleep $(echo "$duration / $width" | bc -l 2>/dev/null || echo "0.025")
done
echo -e " ${GREEN}✓${NC}"
}
# 执行命令并静默输出
run_silent() {
"$@" > /dev/null 2>&1
}
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} Discuz! X5.0 一键部署 + 打包脚本 ${NC}"
echo -e "${GREEN}========================================${NC}"
# ------------------ 步骤0: 配置国内镜像源 ------------------
progress_bar "配置系统镜像源(国内加速)" 1
if [ -f /etc/yum.repos.d/openEuler.repo ]; then
cp /etc/yum.repos.d/openEuler.repo /etc/yum.repos.d/openEuler.repo.bak 2>/dev/null || true
fi
cat > /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
EOF
run_silent dnf clean all
run_silent dnf makecache
# ------------------ 步骤1: 检查/安装 Docker ------------------
progress_bar "检查 Docker 环境" 0.5
if ! command -v docker &> /dev/null; then
echo -e "${YELLOW}Docker 未安装,正在自动安装...${NC}"
run_silent dnf install -y yum-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_silent sed -i 's/$releasever/8/g' /etc/yum.repos.d/docker-ce.repo
run_silent dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
run_silent systemctl start docker
run_silent systemctl enable docker
echo -e "${GREEN}Docker 安装完成。${NC}"
else
echo -e "${GREEN}Docker 已安装。${NC}"
fi
# 配置 Docker 镜像加速
progress_bar "配置 Docker 镜像加速" 0.5
mkdir -p /etc/docker
cat > /etc/docker/daemon.json <<'EOF'
{
"registry-mirrors": ["https://registry.cn-hangzhou.aliyuncs.com"]
}
EOF
run_silent systemctl restart docker
# ------------------ 步骤2: 用户输入端口 ------------------
read -p "请输入要映射的宿主机端口 (默认 8080): " HOST_PORT
HOST_PORT=${HOST_PORT:-8080}
# ------------------ 步骤3: 生成随机密码 ------------------
progress_bar "生成随机数据库密码" 0.5
DB_ROOT_PASS=$(openssl rand -base64 12 | tr -d "=+/" | cut -c1-16)
DB_DISCUZ_PASS=$(openssl rand -base64 12 | 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.5
TEMP_DIR=$(mktemp -d)
cd $TEMP_DIR
cat > 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"]
EOF
cat > 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
EOF
sed -i "s/\${DB_ROOT_PASS}/${DB_ROOT_PASS}/g" start.sh
sed -i "s/\${DB_DISCUZ_PASS}/${DB_DISCUZ_PASS}/g" start.sh
# ------------------ 步骤5: 构建 Docker 镜像 ------------------
progress_bar "构建 Docker 镜像 (约2-3分钟)" 2
run_silent docker build -t discuz:auto .
# ------------------ 步骤6: 首次运行容器 ------------------
progress_bar "启动临时容器" 0.5
docker run -d --name discuz-temp -p ${HOST_PORT}:80 discuz:auto > /dev/null
SERVER_IP=$(ip route get 1 | 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.5
run_silent docker commit discuz-temp discuz:final
# ------------------ 步骤8: 导出 tar 文件 ------------------
progress_bar "导出镜像为 tar 文件" 1
run_silent docker save -o discuz-final.tar discuz:final
echo -e "${GREEN}镜像已导出为: $(pwd)/discuz-final.tar${NC}"
# ------------------ 步骤9: 清理临时容器 ------------------
progress_bar "清理临时资源" 0.5
run_silent docker stop discuz-temp
run_silent docker rm discuz-temp
rm -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)。
-
创建脚本文件 :
bashvi deploy_discuz.sh按
i进入编辑模式,将上面整个脚本内容完整复制粘贴进去 ,然后按ESC,输入:wq保存退出。 -
赋予执行权限 :
bashchmod +x deploy_discuz.sh -
运行脚本 (需要 root 权限):
bashsudo ./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 命令:
bash
docker save -o discuz-final.tar discuz:final
4.2 在另一台机器上导入
bash
docker load -i discuz-final.tar
4.3 运行迁移后的容器
bash
docker run -d --name discuz-migrated -p 8080: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 完全满足这些要求。
❓ 如何修改数据库密码?
进入容器后执行:
bash
docker exec -it discuz-temp /bin/sh
mysqladmin -u root -p'旧密码' password '新密码'
mysql -u root -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 文件。
如何修改数据库密码?
进入容器后执行:
bash
docker exec -it discuz-temp /bin/sh
mysqladmin -u root -p'旧密码' password '新密码'
mysql -u root -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 文件。