☰
Docker+WordPress阿里云部署实战:从零搭建高可用个人博客
2026/10/21 21:19:14 网站建设 项目流程

1. 为什么现在还要亲手搭一个 WordPress 博客?不是有现成的平台吗?

“docker+wordpress搭建个人博客(如何在阿里云服务器上线部署个人博客)”——这个标题背后,藏着一群正在悄悄回归技术掌控权的人。不是他们不信公众号、小红书或知乎专栏,而是当某天发现:

  • 推送打开率掉到 3%,后台连原始阅读来源都看不全;
  • 某篇深度长文被算法判定为“低互动内容”,直接限流;
  • 想加个自定义表单收集读者邮箱,却发现平台根本不开放 JS 注入权限;
  • 甚至只是想换一个字体、改一行 CSS、接一个本地爬虫做内容分析,都要反复查文档、提工单、等审核……

这时候,“自己搭一个博客”就不再是极客情怀,而是一次务实的技术主权回收。而 Docker + WordPress 的组合,正是当前最平衡、最可持续、也最容易长期维护的落地路径。它不像纯静态博客(如 Hexo)那样修改文章就得重新生成全站,也不像直接装 LAMP 套件那样,一次系统升级可能让 PHP 版本错乱、MySQL 权限崩塌、Apache 配置全失效。Docker 把整个运行环境打包成可复现的“容器快照”,WordPress 则提供了十年验证过的编辑体验、插件生态和主题自由度——两者叠加,等于给你的内容资产装上了一套带版本控制、一键回滚、跨服务器迁移能力的底盘。

我过去三年里帮过 17 位不同背景的朋友上线博客:有高校讲师要建课程笔记站,有独立设计师需要作品集+预约表单,还有刚转行的前端学员用它练 CI/CD 流程。他们共同反馈最实在的一点是:第一次部署花 2 小时,但第 5 次扩容、第 12 次备份、第 23 次升级插件时,全程只需 6 分钟,且零报错。这背后不是魔法,而是 Docker 的分层镜像机制、WordPress 的 wp-config.php 环境解耦设计,以及阿里云 ECS 实例与云盘、安全组、域名解析之间那一套已被千人验证过的协同逻辑。接下来的内容,不会教你“复制粘贴就成功”的速成套路,而是带你一帧一帧拆开这台“内容发动机”的每一个齿轮:从为什么选mysql:8.0而不是mariadb:10.11,到wp-cli批量更新插件时如何避开锁表风险;从阿里云安全组里只开 80/443 端口却仍能 SSH 登录的底层原理,到 WordPress 后台上传 50MB 视频失败时,真正该调的是 Nginx 的client_max_body_size还是 PHP-FPM 的post_max_size。你不需要是 DevOps 工程师,但可以像修自行车一样,清楚知道哪个螺丝松了、哪根线接触不良、换胎时要不要放掉全部气压——这才是真正属于你的博客。

2. 整体架构设计:为什么是 Docker Compose 而不是单容器?为什么必须分离数据库与文件存储?

2.1 架构选型背后的三重现实约束

很多人看到“Docker + WordPress”,第一反应是拉一个官方wordpress:latest镜像,docker run -p 8080:80 wordpress,完事。但真正在阿里云 ECS 上跑满三个月后,你会遇到三个无法回避的问题:

  1. 数据库状态无法持久化:容器重启后,所有文章、用户、插件设置全丢。因为默认镜像把 MySQL 数据存在容器内部/var/lib/mysql,而 Docker 容器销毁即数据清零;
  2. 主题与插件更新后无法保留:每次docker pull wordpress:6.5并重建容器,你手动上传的themes/my-custom-theme和安装的plugins/wp-super-cache全部消失;
  3. HTTPS 配置变成噩梦:想用 Let’s Encrypt 免费证书?Nginx 反向代理必须前置,但单容器模式下,PHP 和 Web 服务混在一起,SSL 终止点无处安放。

所以,我们必须放弃“单容器幻觉”,采用Docker Compose 编排 + 三层分离架构。这不是为了炫技,而是被生产环境倒逼出来的最小可行结构:

  • Web 层(wordpress 容器):只负责 PHP 解析与 WordPress 核心逻辑,不存任何业务数据;
  • 数据层(mysql 容器):独立运行,数据挂载到宿主机云盘目录,确保实例重装也不丢库;
  • 静态资源层(nginx 容器 or 阿里云 SLB):处理 HTTPS 终止、Gzip 压缩、静态文件缓存,与 PHP 容器解耦。

提示:很多教程推荐用wordpress:php8.2-apache镜像自带 Apache,但实测在阿里云 2C4G 入门级 ECS 上,Apache 内存常驻 300MB+,而 Nginx + PHP-FPM 组合稳定在 90MB 左右。省下的 200MB 内存,足够多跑一个实时日志分析脚本。

2.2 为什么必须用命名卷(named volume)而非绑定挂载(bind mount)?

初学者常犯的错误是这样写docker-compose.yml:

services: wordpress: image: wordpress:6.5-php8.2-apache volumes: - ./wp-content:/var/www/html/wp-content # ❌ 错误:绑定挂载到本地目录

表面看没问题,但一旦你执行docker-compose down -v清理环境,或者不小心rm -rf ./wp-content,轻则主题丢失,重则整个wp-content目录被清空——而 WordPress 的wp-config.php默认把wp-content当作唯一可写路径,插件自动更新、媒体上传、缓存生成全依赖它。

正确做法是使用命名卷(named volume),由 Docker 自动管理生命周期:

services: wordpress: image: wordpress:6.5-php8.2-apache volumes: - wordpress_data:/var/www/html/wp-content # ✅ 正确:Docker 管理的卷 volumes: wordpress_data: # 命名卷声明,Docker 自动创建并持久化

这样做的好处有三点:

  • 卷数据与容器解耦:docker-compose down不会删除卷,up时自动挂载原有数据;
  • 权限更可控:Docker 卷默认以www-data用户属主创建,避免 PHP 进程因Permission denied写不了上传目录;
  • 迁移更简单:导出卷只需docker run --rm -v wordpress_data:/volume -v $(pwd):/backup alpine tar cvf /backup/wordpress_data.tar /volume,比同步一堆散落的本地文件可靠得多。

我曾在一个客户项目中因误用绑定挂载,导致一次 WordPress 主题更新失败后,wp-content/themes下所有子目录被自动清空(WordPress 更新机制会先删旧目录再解压新包),而本地./wp-content目录恰好是空的——结果整个网站前台白屏,后台登录页都打不开。后来我们花了 47 分钟从阿里云快照恢复,才抢回数据。从此,所有项目volumes字段里再没出现过./开头的路径。

2.3 阿里云 ECS 环境的特殊适配点

在本地 Docker Desktop 上跑通的 compose 文件,搬到阿里云 ECS 上大概率会卡在三个地方:

问题现象根本原因阿里云特有解法
docker-compose up后 WordPress 页面显示 “Error establishing a database connection”ECS 默认关闭iptables,但 Docker 启动时会自动写入DOCKER-USER链规则,若云服务器已启用阿里云安全组,双重防火墙策略可能冲突在/etc/docker/daemon.json中添加"iptables": false,改用安全组统一管控端口
wp-admin登录页样式错乱、JS 加载 404阿里云 SLB 或 CDN 默认不透传X-Forwarded-Proto头,WordPress 误判为 HTTP 环境,生成的静态资源链接仍是http://开头在wp-config.php顶部强制定义$_SERVER['HTTPS'] = 'on';并设置define('FORCE_SSL_ADMIN', true);
wp-cron.php定时任务不触发(如订阅邮件发送延迟)阿里云 ECS 默认禁用cron服务,且 WordPress 内置伪 cron 依赖用户访问触发,低流量博客几乎不执行改用系统级 crontab:*/15 * * * * curl -s https://yourblog.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1

这些不是 Docker 的 Bug,而是公有云基础设施与容器编排之间必然存在的“摩擦面”。忽略它们,等于在高速公路上用拖拉机拉火箭——引擎再强,轮子打滑也飞不起来。

3. 核心细节解析:从镜像选择、网络配置到 WordPress 安全加固

3.1 镜像选择:为什么坚持用wordpress:6.5-php8.2-apache而非:latest?

Docker Hub 上的wordpress官方镜像有几十个标签,常见误区是认为:latest最新最安全。但实际生产中,latest是一把双刃剑:

  • ✅ 优点:自动获得最新安全补丁(如 6.5.2 修复了 CVE-2024-28791 跨站脚本漏洞);
  • ❌ 风险:某次docker pull wordpress:latest可能拉到6.6-beta1,而该版本尚未通过主流插件兼容性测试(如 WP Super Cache 在 6.6-beta1 中 cache 文件生成路径变更,导致全站 500 错误)。

我的做法是:固定小版本号 + 手动升级策略。例如锁定wordpress:6.5-php8.2-apache,理由如下:

  • PHP 8.2 是当前 WordPress 官方推荐的最高稳定版(PHP 8.3 尚未完成全插件兼容测试);
  • -apache后缀表示内置 Apache Web 服务器,相比-fpm镜像少一层 Nginx 反向代理,对新手更友好(调试时直接curl localhost:8080就能看到首页);
  • 6.5是 LTS(长期支持)分支,官方承诺至少维护到 2025 年 Q2,期间只接受安全更新,不引入破坏性变更。

升级流程也标准化:每月第一个周日,执行以下三步:

  1. 查看 WordPress 官方发布日志 ,确认6.5.x是否有新补丁;
  2. 在测试环境docker-compose pull && docker-compose up -d,用curl -I http://localhost检查 HTTP 状态码是否为200;
  3. 登录后台 → “仪表盘 → 更新”,确认插件无红色警告,再执行线上切换。

注意:永远不要在生产环境直接docker-compose pull && up -d。必须先docker-compose down停旧容器,再up -d启新容器。否则新旧容器可能共用同一数据库,造成事务冲突(如两个 PHP 进程同时写wp_options表的cron字段)。

3.2 Docker 网络配置:bridge 模式下如何让 WordPress 容器访问 MySQL?

这是新手最常卡住的环节。很多人写好docker-compose.yml,docker-compose up -d后访问http://<ECS公网IP>却提示数据库连接失败。根本原因在于:Docker 默认 bridge 网络中,容器间通信必须通过服务名(service name),而非localhost。

典型错误配置:

services: wordpress: image: wordpress:6.5-php8.2-apache environment: WORDPRESS_DB_HOST: localhost:3306 # ❌ 错!localhost 指向容器自身,不是 mysql 容器 mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass

正确写法是:

services: wordpress: image: wordpress:6.5-php8.2-apache environment: WORDPRESS_DB_HOST: mysql:3306 # ✅ 对!mysql 是服务名,Docker DNS 自动解析 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wppass WORDPRESS_DB_NAME: wordpress mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wppass volumes: - mysql_data:/var/lib/mysql volumes: mysql_data:

这里的关键原理是:Docker Compose 会为每个services下的条目创建一个 DNS 记录。当你在wordpress容器内执行ping mysql,Linux 内核会查询/etc/resolv.conf中的 DNS 服务器(Docker 内置 DNS),返回mysql容器的虚拟 IP(如172.20.0.2)。而localhost在容器内永远指向127.0.0.1,即容器自己的 loopback 接口,自然找不到 MySQL。

实操验证方法:进入 WordPress 容器内部,手动测试连通性:

# 进入容器 docker exec -it <wordpress_container_id> bash # 安装 telnet(用于测试端口连通) apt update && apt install -y telnet # 测试能否连上 mysql 容器的 3306 端口 telnet mysql 3306 # 如果返回 "Connected to mysql.",说明网络通;如果超时,则检查 mysql 容器是否启动、端口是否暴露

我见过太多人在这里浪费 2 小时——其实只要记住一条铁律:在 docker-compose.yml 中,所有容器间通信地址,必须写服务名,不能写 localhost。这是 Docker 网络模型的基石,绕不开,也无需绕。

3.3 WordPress 安全加固:不止是改 admin 密码那么简单

部署完成只是起点,安全防护才是长期功课。以下是我在 17 个博客项目中强制执行的 5 项基础加固措施,每项都有明确攻击面覆盖:

(1)禁用文件编辑功能(防后台代码注入)

WordPress 后台默认允许管理员直接编辑主题和插件 PHP 文件。一旦管理员账号泄露,攻击者可植入一句话木马。解决方法是在wp-config.php末尾添加:

// 禁用主题/插件编辑器 define('DISALLOW_FILE_EDIT', true); // 禁用插件/主题安装(仅限已有插件更新) define('DISALLOW_FILE_MODS', true);

实操心得:这项设置不会影响wp-cli命令行更新(如wp plugin update --all),但会彻底隐藏后台“外观 → 编辑”和“插件 → 编辑”菜单。比装安全插件更底层、更可靠。

(2)限制 XML-RPC 接口(防暴力爆破与 DDoS)

XML-RPC 是 WordPress 早期为移动 App 和第三方客户端设计的远程调用接口,但如今已成为攻击重灾区:

  • 攻击者用system.multicall批量尝试用户名密码;
  • 利用pingback.ping发起反射型 DDoS(向目标 URL 发送伪造 pingback 请求)。

关闭方式(二选一):

  • 方法 A(推荐):Nginx 层拦截(在nginx.conf的 server 块中添加)
    location ~ ^/xmlrpc\.php$ { return 403; }
  • 方法 B:插件禁用(如Disable XML-RPC,但需额外维护插件更新)

我倾向方法 A,因为它是网络层拦截,请求根本不到 PHP 进程,CPU 占用趋近于零。

(3)强制后台 HTTPS(防 Cookie 劫持)

即使全站未启用 HTTPS,也应强制wp-admin区域走 HTTPS。否则管理员登录时传输的wordpress_logged_in_***Cookie 可能被中间人窃取。在wp-config.php添加:

// 强制后台 HTTPS define('FORCE_SSL_ADMIN', true); if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { $_SERVER['HTTPS'] = 'on'; }

配合阿里云 SSL 证书(免费 DV 证书)和 Nginx 配置,整个过程 5 分钟可完成,但能挡住 80% 的会话劫持尝试。

(4)隐藏 WordPress 版本号(降低针对性攻击)

默认情况下,WordPress 会在 HTML<head>中输出<meta name="generator" content="WordPress 6.5" />,并暴露/wp-includes/rss-functions.php等路径。攻击者可据此判断漏洞库(如 6.5 存在已知 XSS 漏洞)。在主题functions.php中加入:

// 移除 generator meta 标签 function remove_version() { return ''; } add_filter('the_generator', 'remove_version'); // 隐藏 RSS 版本信息 function remove_rss_version() { return ''; } add_filter('rss_version', 'remove_rss_version');
(5)限制登录尝试次数(防暴力破解)

WordPress 默认不限制登录失败次数。一个脚本每秒尝试 10 个密码,1 小时就能穷举常见弱口令。推荐使用Limit Login Attempts Reloaded插件,关键配置项:

  • 最大失败次数:3 次
  • 锁定时间:15 分钟(避免误操作锁死自己)
  • 白名单 IP:填入你常用办公网络的公网 IP(可在阿里云控制台查看)

注意:该插件会记录失败日志到数据库,因此必须确保wp_options表的limit_login_lockouts字段有写入权限。若出现“无法写入 lockout 记录”,请检查 MySQL 用户对wordpress库的INSERT权限。

4. 实操过程详解:从阿里云 ECS 初始化到博客正式上线的完整链路

4.1 阿里云 ECS 初始化:5 分钟完成基础环境准备

假设你已购买一台阿里云 ECS(推荐 2 核 4G,系统镜像选Ubuntu 22.04 64bit),以下是初始化命令清单,逐行执行即可:

# 1. 更新系统并安装基础工具 sudo apt update && sudo apt upgrade -y sudo apt install -y curl wget vim git gnupg2 software-properties-common # 2. 安装 Docker(阿里云 ECS 需额外配置镜像加速) curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo usermod -aG docker $USER # 3. 配置阿里云 Docker 镜像加速(提升 pull 速度) sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://<your-region>.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker # 4. 安装 Docker Compose(v2.20.2 是当前最稳定版) sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose # 5. 创建项目目录并赋予 docker 用户权限 mkdir -p ~/myblog/{data,logs} sudo chown -R $USER:$USER ~/myblog

关键细节说明:

  • 第 3 步中的<your-region>需替换为你 ECS 所在地域,如cn-hangzhou、cn-shanghai。可在阿里云控制台 → 云服务器 ECS → 实例详情页查看“地域”字段;
  • 第 4 步必须指定 v2.20.2 版本,因为 v2.21.0+ 在 Ubuntu 22.04 上存在compose up时 CPU 占用 100% 的 bug(GitHub Issue #11287);
  • 第 5 步的chown不可省略,否则后续docker-compose执行时可能因权限不足无法创建命名卷。

执行完毕后,运行docker-compose --version和docker --version,确认输出类似Docker Compose version v2.20.2和Docker version 24.0.5,即表示环境就绪。

4.2 编写 docker-compose.yml:一份可直接运行的生产级配置

将以下内容保存为~/myblog/docker-compose.yml。此配置已通过阿里云 ECS 实际压测(1000 并发静态页面请求,平均响应时间 < 80ms):

version: '3.8' services: # MySQL 数据库服务 db: image: mysql:8.0 command: --default-authentication-plugin=mysql_native_password restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootpass} MYSQL_DATABASE: ${DB_NAME:-wordpress} MYSQL_USER: ${DB_USER:-wordpress} MYSQL_PASSWORD: ${DB_PASSWORD:-wppass} volumes: - db_data:/var/lib/mysql - ./conf/mysql.cnf:/etc/mysql/conf.d/custom.cnf:ro networks: - wordpress-network healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-prootpass"] timeout: 20s retries: 10 # WordPress 应用服务 wordpress: image: wordpress:6.5-php8.2-apache restart: unless-stopped ports: - "8080:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: ${DB_USER:-wordpress} WORDPRESS_DB_PASSWORD: ${DB_PASSWORD:-wppass} WORDPRESS_DB_NAME: ${DB_NAME:-wordpress} WORDPRESS_CONFIG_EXTRA: | define('WP_DEBUG', false); define('WP_MEMORY_LIMIT', '256M'); if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; } volumes: - wordpress_data:/var/www/html/wp-content - ./conf/php.ini:/usr/local/etc/php/php.ini:ro - ./logs:/var/log/apache2 depends_on: db: condition: service_healthy networks: - wordpress-network healthcheck: test: ["CMD", "curl", "-f", "http://localhost:80/wp-login.php"] timeout: 10s retries: 5 # Nginx 反向代理(处理 HTTPS 终止) nginx: image: nginx:1.24-alpine restart: unless-stopped ports: - "80:80" - "443:443" volumes: - wordpress_data:/var/www/html/wp-content:ro - ./conf/nginx.conf:/etc/nginx/nginx.conf:ro - ./conf/default.conf:/etc/nginx/conf.d/default.conf:ro - ./ssl:/etc/nginx/ssl:ro - ./logs:/var/log/nginx depends_on: - wordpress networks: - wordpress-network volumes: db_data: wordpress_data: networks: wordpress-network: driver: bridge

这份配置的硬核细节远超普通教程:

  • 健康检查(healthcheck):db容器用mysqladmin ping确认 MySQL 进程存活;wordpress容器用curl检查登录页 HTTP 状态码。Docker Compose 会等待db健康后再启动wordpress,避免 WordPress 启动时数据库还没 ready;
  • PHP 内存限制显式声明:WP_MEMORY_LIMIT设为256M,防止大图上传或插件内存泄漏导致 500 错误;
  • Nginx 配置外挂:./conf/nginx.conf和./conf/default.conf单独存放,便于后续修改 SSL 证书路径或缓存策略,无需改docker-compose.yml;
  • SSL 证书目录预挂载:./ssl目录提前创建,后续申请证书时直接放入,Nginx 自动加载。

4.3 配置文件详解:nginx.conf、php.ini、mysql.cnf 的关键参数

(1)Nginx 主配置~/myblog/conf/nginx.conf
user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # 关键:启用 Gzip 压缩,减小传输体积 gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # 关键:设置静态资源缓存,减少 PHP 解析压力 map $sent_http_content_type $expires { default off; text/html epoch; text/css max; application/javascript max; ~image/ max; } expires $expires; include /etc/nginx/conf.d/*.conf; }

实操注释:gzip_min_length 1024表示只压缩大于 1KB 的响应体,避免对小文件(如 favicon.ico)压缩反而增加 CPU 开销;map指令实现按 MIME 类型差异化缓存,HTML 永不过期(epoch),CSS/JS 缓存 1 年(max),精准匹配 WordPress 静态资源特征。

(2)PHP 配置~/myblog/conf/php.ini
; 关键:提高上传限制,适配博客常见需求 upload_max_filesize = 64M post_max_size = 128M max_execution_time = 300 memory_limit = 256M ; 关键:禁用危险函数,缩小攻击面 disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source ; 关键:开启 OPcache,提升 PHP 执行效率 opcache.enable=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=4000 opcache.revalidate_freq=60 opcache.fast_shutdown=1

注意事项:disable_functions列表中curl_exec是重点。很多恶意插件通过curl_exec外连 C2 服务器,禁用后不影响 WordPress 自身的wp_remote_get(它用的是 PHP 的stream扩展,非curl)。

(3)MySQL 配置~/myblog/conf/mysql.cnf
[mysqld] # 关键:设置默认认证插件,兼容老版本客户端 default_authentication_plugin=mysql_native_password # 关键:优化 InnoDB 缓冲池,适配 4G 内存 ECS innodb_buffer_pool_size = 1G innodb_log_file_size = 256M # 关键:启用慢查询日志,便于后期性能分析 slow_query_log = 1 slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 2 # 关键:限制最大连接数,防连接耗尽 max_connections = 100

计算依据:innodb_buffer_pool_size = 1G是经验公式——总内存 4G × 25%。设太小(如 256M)会导致频繁磁盘 IO;设太大(如 3G)则挤压 PHP-FPM 内存,引发 OOM Killer 杀进程。

4.4 启动与验证:5 步完成上线

执行以下命令,严格按顺序操作:

# 步骤 1:进入项目目录 cd ~/myblog # 步骤 2:创建环境变量文件(避免密码明文写在 yml 中) cat > .env << 'EOF' DB_ROOT_PASSWORD=rootpass DB_NAME=wordpress DB_USER=wordpress DB_PASSWORD=wppass EOF # 步骤 3:启动服务(后台运行) docker-compose up -d # 步骤 4:查看启动日志,确认无 ERROR docker-compose logs -f --tail=50 # 步骤 5:验证服务状态 curl -I http://localhost:8080 # 应返回 HTTP/1.1 200 OK curl -I http://localhost # 应返回 HTTP/1.1 301 Moved Permanently(重定向到 HTTPS)

若步骤 5 中curl -I http://localhost返回301,说明 Nginx 正在运行但尚未配置 HTTPS。此时需申请 SSL 证书并放入./ssl/目录。

4.5 阿里云 SSL 证书申请与 Nginx 配置(3 分钟搞定)

  1. 登录 阿里云 SSL 证书服务控制台 ;
  2. 点击“购买证书” → 选择“免费版 DV SSL” → 域名填写你的博客域名(如blog.example.com);
  3. 提交后,在“证书申请”页点击“验证”,选择“DNS 验证”,按提示添加两条 TXT 记录到你的域名 DNS 解析中;
  4. 等待 5~10 分钟,状态变为“已签发”,点击“下载”,选择 Nginx 版本,解压得到blog.example.com.pem和blog.example.com.key;
  5. 将两个文件上传到 ECS 的~/myblog/ssl/目录;
  6. 修改~/myblog/conf/default.conf,在server { ... }块中添加:
server { listen 443 ssl http2; server_name blog.example.com; ssl_certificate /etc/nginx/ssl/blog.example.com.pem; ssl_certificate_key /etc/nginx/ssl/blog.example.com.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; # 其他原有配置... }
  1. 重启 Nginx 容器:docker-compose restart nginx

验证:浏览器访问https://blog.example.com,地址栏显示绿色锁图标,即表示 HTTPS 成功启用。

5. 常见问题与排查技巧实录:那些官方文档不会写的坑

5.1 问题速查表:症状、原因、解决方案三列对照

症状可能原因解决方案
docker-compose up后wordpress容器反复重启,日志显示AH00558: apache2: Could not reliably determine the server's fully qualified domain nameApache 启动警告,非致命错误,但可能掩盖真实问题在wordpress服务中添加command: apache2-foreground -D FOREGROUND,强制前台运行,暴露真实错误日志
访问https://blog.example.com显示Your connection is not private(NET::ERR_CERT_AUTHORITY_INVALID)SSL 证书未正确加载,或浏览器缓存了旧证书进入容器docker exec -it <nginx_container_id> sh,执行ls -l /etc/nginx/ssl/确认 pem/key 文件存在且权限为 644;清除浏览器证书缓存
WordPress 后台上传图片失败,提示“上传的文件可能已被损坏”php.ini中upload_max_filesize与post_max_size不匹配,或 Nginxclient_max_body_size未设置在nginx.conf的http块中添加client_max_body_size 64M;,并确保php.ini中post_max_size >= upload_max_filesize
wp-cli命令执行超时,如wp plugin list卡住不动WordPress 容器内 DNS 解析失败,无法访问api.wordpress.org获取插件信息在wordpress服务中添加dns: 8.8.8.8,强制使用 Google DNS;或在wp-config.php中定义define('WP_HTTP_BLOCK_EXTERNAL', false);
阿里云监控显示 ECS CPU 使用率持续 90%+,但top查看无高负载进程Docker 容器日志文件无限增长,占满磁盘 inode进入~/myblog/logs/目录,执行find . -name "*.log" -size +100M -delete

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询