当前这个网站,好久没维护了。之前是部署在一台比较老旧的 TencentOS 系统上,并且是比较老旧的 apache 版本,整台服务器都很难维护,迁移就比较麻烦,然后就一直放着没动它。原本部署的这台服务器配置也低,虽然一年几十元,但不打算续费了,今年年底就要到期了,就花了点时间捣鼓一下,先将它所有环境从宿主机迁入到 Docker Compose 中,然后整个 Docker Compose 项目打包迁移。当看到这篇文章的时候,是已经迁移成功了,目前部署在 RackNerd 的美国VPS服务器上,我买的是这款配置(超划算RackNerd服务器),非常不错(还拿来搭建了VPN服务器🚀),配置如下:
$29.89 /年 💰 (29.89 美元/年)
🖥️ 3 vCPU 核心 (3 vCPU Cores)
💾 60 GB SSD 存储 (60 GB SSD Storage)
🧠 3.5 GB 内存 (3.5 GB RAM)
📡 5 TB 月流量 (5 TB Monthly Transfer)
🌐 1Gbps 网络端口 (1Gbps Network Port)
🔑 完全根访问权限 (Full Root Access)
🌍 1 个 IPv4 地址 (1 IPv4 Address)
⚙️ KVM/SolusVM
如果购买的话,尽可能选择 DC3 机房,DC3 机房在中国访问的速度比较友好。在中国访问的速度与国际出入口带宽有关。
目前网站运行状况良好,除了昨天迁移时反复修改了几次 DNS 导致缓存产生而出现 SSL 安全提示之外,今早起来发现也恢复正常了。
现在来回顾一下昨天的迁移过程,怎样把 WordPress 装到 Docker Compose 里面来。主要工作分为三个部分:
第一部分,从宿主机导出 Mysql 数据库。
这个网站使用的是 Mysql 8.0.28 版本,服务器中还有其他网站的数据库,现在需要单独把 WordPress 博客的数据库导出来,也非常简单,只需要在命令行执行以下命令:
1 2 3
| mysqldump -u root -p --databases <数据库名称> --routines --events --triggers --single-transaction > <导出保存的名称>.sql
|
执行之后会提示输出 root 密码,稍等几秒就导出完成了。
此时还需要把原来的 WordPress 网站目录整个复制到 Docker compose 项目根目录下(website)。
也
需要去 wp-config.php 修改 DB_HOST 为 mysql 。
第二部分,编写 docker-compose.yml 以及 Dockerfile。
为了把 WordPress 装到容器里,我给它准备了 Dockerfile 和 docker-compose.yml ,服务器本身就有 docker compose 环境,这里就不把环境准备展开赘述了。
Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| FROM php:8.3.24-fpm
# 接收构建时代理参数
# ARG http_proxy
# ARG https_proxy
# 安装 mysqli, pdo, pdo_mysql 模块
RUN docker-php-ext-install mysqli pdo pdo_mysql
# 设置 PHP 配置(例如:max_execution_time)
RUN echo 'max_execution_time = 90' >> /usr/local/etc/php/conf.d/my-php.ini
# 安装 gd 模块
RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install gd
# 安装 exif 模块
RUN docker-php-ext-install exif
# 安装 imagick 模块
RUN apt-get install -y libmagickwand-dev --no-install-recommends \
&& (pecl install imagick || true) \
&& docker-php-ext-enable imagick
# 安装 zip 模块
RUN apt-get install -y \
libzip-dev \
zip \
&& docker-php-ext-install zip
# 安装 intl 模块
RUN apt-get install -y libicu-dev \
&& docker-php-ext-install intl
# 清理安装后的文件
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
这份 Dockerfile 主要是构建了 php 环境的容器,并且把一些必须的扩展都打包进去了,有了这个环境就能跑 WordPress 或者其他 php 项目。
docker-compose.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| services:
nginx:
image: nginx:1.25.3
restart: always
ports:
- "127.0.0.1:8001:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./website:/var/www/website
- /etc/letsencrypt:/etc/letsencrypt:ro
- ./ssl:/etc/ssl
- ./nginxlog:/var/log/nginx
depends_on:
- php
networks:
- app-network
php:
build:
context: .
dockerfile: Dockerfile
image: php: 8.3.24-fpm
restart: always
volumes:
- ./website:/var/www/website
- ./php/php.ini:/usr/local/etc/php/php.ini
networks:
- app-network
mysql:
image: mysql:8.0.28
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: mysqlrootpassword
volumes:
- ./data:/var/lib/mysql
networks:
- app-network
phpmyadmin:
image: phpmyadmin/phpmyadmin
restart: always
ports:
- "127.0.0.1:8002:80"
environment:
PMA_HOST: mysql
MYSQL_ROOT_PASSWORD: mysqlrootpassword
depends_on:
- mysql
networks:
- app-network
networks:
app-network:
driver: bridge
|
有了这两个文件,Docker Compose 就可以跑起来了。但还需要补充一下 php.ini 和 nginx.conf,因为我让这个 Docker Compose 同时提供了 php 和 nginx 的服务。
php/php.ini:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
| [PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = -1
disable_functions =
disable_classes =
zend.enable_gc = On
zend.exception_ignore_args = Off
expose_php = On
max_execution_time = 30
max_input_time = 60
memory_limit = 128M
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 200M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 60M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
[CLI Server]
cli_server.color = On
[Date]
[filter]
[iconv]
[imap]
[intl]
[sqlite3]
[Pcre]
[Pdo]
pdo_mysql.default_socket=
[Phar]
[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = On
[OCI8]
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[bcmath]
bcmath.scale = 0
[browscap]
[Session]
session.save_handler = files
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.cookie_samesite =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 26
session.trans_sid_tags = "a=href,area=href,frame=src,form="
session.sid_bits_per_character = 5
[Assertion]
zend.assertions = 1
[COM]
[mbstring]
[gd]
[exif]
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[sysvshm]
[ldap]
ldap.max_links = -1
[dba]
[opcache]
[curl]
[openssl]
[ffi]
|
nginx/nginx.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 映射 HTTPS 状态(用于 fastcgi_param)
map $http_x_forwarded_proto $fastcgi_https {
default off;
https on;
}
server {
listen 80;
listen [::]:80;
server_name localhost;
error_log /var/log/nginx/error.log debug;
access_log /var/log/nginx/access.log;
root /var/www/website;
index index.html index.htm index.php;
client_max_body_size 1000M;
# 处理静态文件请求
location ~* \.(ico|gif|jpg|jpeg|png|js|css)$ {
try_files $uri =404;
}
# 防止访问特定文件类型
location ~* \.(bak|inc|lib|sh|tpl|lbi|dwt)$ {
deny all;
return 404;
}
# 处理 PHP 文件
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS $fastcgi_https; # 识别 HTTPS
fastcgi_pass php:9000;
fastcgi_index index.php;
}
# URL 重写规则
location / {
try_files $uri $uri/ @rewrite;
}
location @rewrite {
rewrite ^/(.*)$ /index.php?route=$1 last;
}
}
}
|
至此,第二部分就完成了,使用 docker compose build –no-cache && docker compose up -d 启动容器。
第三部分,数据库导入。
在第二部分中,docker-compose.yml 首次启动时创建的是空的数据库,我们需要把原来备份的数据库文件复制到容器内,并且在容器内恢复数据库以及创建用户和权限。
复制数据库文件到容器:
docker cp <导出保存的名称>.sql.sql mysql:/<导出保存的名称>.sql
进入容器内导入原备份的 .sql 数据到数据库中
1 2 3 4 5 6 7 8 9
| docker exec -it mysql bash
ls -lt /<导出保存的名称>.sql
mysql -u root -p < /<导出保存的名称>.sql
SHOW DATABASES;
|
通过以下三条命令创建用户和权限:
用户名、数据库名、用户密码都必须与 wordpress 一致,并且使用 % 可以从任意 IP 登录。
1 2 3 4 5 6 7 8 9
| CREATE USER 'wwwbg7iaecom'@'%' IDENTIFIED BY 'Web3900,.';
GRANT ALL PRIVILEGES ON wwwbg7iaecom.* TO 'wwwbg7iaecom'@'%';
FLUSH PRIVILEGES;
SELECT user, host FROM mysql.user;
|
完成以上操作之后,退出容器。重启一次 Docker Compose: docker compose down && docker compose up -d
至此,就完成了整个项目的迁移了,现在可以通过 http://127.0.0.1:8001 访问 WordPress 博客了。
还不够,对不对?用户怎么通过 http://127.0.0.1:8001 访问嘛?没错,还需要宿主机的 nginx 反代一下到 http://127.0.0.1:8001 ,或者使用 Cloudflare Tunnel 反代也可以。做完就个动作,整个项目才算真正迁移完毕。
现在你看到的这篇文章,就是已经迁移完的结果了。
(这篇文章发完,才发现这个网站还没支持代码块功能,后面抽个时间给它加上。)