如果您也是计划本地部署网站,通过DDNS公网能够访问80/443网站的话,且不打算采用内网穿透或其他的方案的话,建议直接看第五章
重要优先看:公网挑战及放弃本地部署网站
1. NAS配置及代码迁移
极空间Z4Pro性能版,8核16G内存; 。
方案一: Docker部署 ;方案二:虚拟机方案;
- 方案选择: 因为本人没买m.2固态硬盘,所以没有办法运行虚机; 直接采用docker容器方案;全部轻量化部署
以上是 NAS容器中部署的三个docker镜像。当然也可以直接找个 LNMP的合成Docker镜像进行运行;这里为了以后独立升级,轻量化和解耦,采用三个独立的容器运行。其中每个容器都采用host主机模式网络进行部署,公用同一个网络环境。
1.1. php-fpm-docker
- 在部署php-fpm的容器时,因为wordpress需要访问mysql, 这里自行安装了php-mysqli相关组件;
目前该容器已推送官方镜像,通过如下命令下载 docker push turbock/custom-php-fpm:latest
FROM php:8.3.17RC1-fpm-alpine3.21
# php:8.3.16-fpm-alpine3.20
# 安装依赖并启用mysqli
RUN apk update && \
apk add --no-cache mysql-client && \
docker-php-ext-install mysqli && \
docker-php-ext-enable mysqli
apt install -y procps vim netools telnet iputils-ping
# 挂载项目代码(假设项目目录为src)
WORKDIR /usr/share/nginx/html
COPY ./src /usr/share/nginx/html/
# # 查看已加载的PHP模块
# php -m | grep mysqli
# # 或检查phpinfo()
# php -r 'phpinfo();' | grep mysqli
# apt install -y php-fpm
# php --version
# apt install -y php8.2-*
# apt install -y php8.2-fpm php8.2-opcache php8.2-cli php8.2-gd php8.2-imap php8.2-mysqlnd php8.2-mbstring php8.2-mcrypt php8.2-pdo php8.2-pecl-* php8.2-xml
# apt remove -y php-yac php-apcu php-imagick
# apt remove -y php8.2-imagick php8.2-apcu
alpine系统,采用apk方式进行安装
docker tag custom-php-fpm turbock/custom-php-fpm:v1.1
docker tag custom-php-fpm turbock/custom-php-fpm:latest
docker push turbock/custom-php-fpm:latest
/usr/local/bin/php
/usr/local/sbin/php-fpm
/usr/local/etc/php-fpm.conf
/usr/local/etc # tree
.
├── pear.conf
├── php
│ ├── conf.d
│ │ ├── docker-fpm.ini
│ │ └── docker-php-ext-sodium.ini
│ ├── php.ini-development
│ └── php.ini-production
├── php-fpm.conf
├── php-fpm.conf.default
└── php-fpm.d
├── docker.conf
├── www.conf
├── www.conf.default
└── zz-docker.conf
1.2. mysql docker
配置环境变量
MYSQL_ROOT_PASSWORD 为自己的mysql 登录密码, 用户名默认root
mysql -h localhost -u root -p
Mysqlturbock79;
SHOW GRANTS FOR 'root'@'%';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
//查询端口是否发布
microdnf --version
microdnf update
microdnf install net-tools
netstat -tunlp | grep 3306
2. 公网EIP及DDNS
2.1. 入户公网IP查询
- 家庭网络POC验证
查询本地网线入户路由器的wan口地址和实际的外网地址端口是否一致,这里可以用网址https://www.ip38.com/ 查询本地实际公网ip;
接入网络采用电信网络, 目前因电信不采用公网IP动态分配,而是做了一层nat, 导致入户网络没有公网。 无论如何使用DDNS,都无法实现 域名到 DDNS的动态转换。因此计划采用公网EIP直接做端口映射;
- 打电话沟通运营商,申请公网EIP;
- 如果您家庭路由器性能较好, 可以将 宽带运营商的 入户路由器 纯作为光猫使用(光信号和网络信号互转),然后采用桥接模式;然后在家庭路由器上进行拨号上网;
2.2. DDNS 地址动态转换
-
通过添加10元改为获取动态IP后, 每天的公网EIP都是变化的,这里就需要启用NAS或如何核心路由器上的DDNS功能了;
DDNS主要是将入户的动态公网IP上传到域名解析地址服务器,即使公网IP变化也能实现域名到IP的正确解析; -
DDNS调研
ddns主要有两种方案,一种是家庭路由器直接配置ddns,另一个是 NAS/主机上安装ddns客户端进行动态检查ip并上报;
本人这里主要还是看家庭的路由器支持的ddns厂商都有哪些,然后针对性的研究ddns厂商设置;因为家里使用核心路由器的DDNS支持厂商我这里都没有申请过,花生壳还需要重新做认证和域名转入。所以计划采用极空间内置的DDNS; -
因采用极空间,内置DDNS的模块进行解析;
-
因为本人原有使用的就是DNSPod解析的,这里还是使用腾讯云的DNSPod进行动态解析;
获取密钥地址API 密钥 - DNSPod-免费智能DNS解析服务商
-
要注意的是,DNSPod Token 而不是腾讯云账号的API
2.3. 域名内部地址映射
- 在路由器上(宽带运营商入户路由器或 个人路由器)进行端口地址转换
网络架构(公网 80/443 端口映射到内网 8880/8443)
3. 内外网重定向统一入口
3.1. 问题描述
现象:
网络架构(公网 80/443 端口映射到内网 8880/8443);nas上部署wordpress, 私网地址是192.168.31.182:8880, 公网地址是 111.111.111.111, 在路由器上做了端口映射 内网8880转公网的80端口, 但是wordpress 因为内部配置了siteurl,默认用80端口, 会不断的改目的端口,导致只能公网访问。私网192.168.31.182:8880 无法访问;
分析:WordPress 的 siteurl 和 home 配置强制指向公网地址 111.111.111.111:80,导致内网用户通过 192.168.31.182:8880 访问时会被重定向到公网地址,而内网环境无法通过公网 IP + 80 端口直接访问(需依赖路由器 NAT 回环支持)。
总结需求,即需要让 WordPress 动态适应内外网环境,或通过技术手段统一访问入口。同时,内外网都能正常访问图片和地址格式;
3.2. 解决方案
基于Nginx 配置方案,确保内外网访问兼容性、HTTPS 重定向和安全性:
3.2.1. 优化后的wordpress wp-config.php 配置
- 更灵活的动态配置(支持多环境)
// 在 wp-config.php 中添加(确保在 require_once(ABSPATH . 'wp-settings.php'); 之前)
$protocol = 'http://';
if (
(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || // 直接 HTTPS 访问
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') // 代理转发(如 Nginx + Cloudflare)
) {
$protocol = 'https://';
}
$current_host = $_SERVER['HTTP_HOST'];
// 判断是否为内网或本地访问
if (
strpos($current_host, '192.168.') === 0 || // 内网 IP 段
strpos($current_host, '127.0.0.1') === 0 || // 本地回环
strpos($current_host, 'localhost') === 0 // 本地域名
) {
define('WP_HOME', $protocol . $current_host);
define('WP_SITEURL', $protocol . $current_host);
} else {
// 公网访问强制使用 HTTPS
define('WP_HOME', 'https://turbock79.com');
define('WP_SITEURL', 'https://turbock79.com');
}
-
代码说明
- 动态协议检测:同时支持直接 HTTPS 访问和反向代理(如 Cloudflare、Nginx 负载均衡器)的 X-Forwarded-Proto 标头。
- 公网强制 HTTPS:无论用户是否通过 HTTP 访问,公网地址始终重定向到 https://test.com
- 动态协议:自动识别 http:// 或 https://。
- 灵活匹配:匹配所有 192.168.x.x 内网 IP(无需写死具体 IP)。支持 127.0.0.1:8880 和 localhost:8880。其他情况自动使用公网域名 test.com。
- 无需硬编码:通过 $current_host 动态获取请求地址。
3.2.2. 数据库修改步骤
-
理想情况下不需要
如果您的 WordPress 站点 完全使用动态配置(通过 wp-config.php 动态设置 WP_HOME 和 WP_SITEURL),并且 所有内容链接均为相对路径,则 无需修改数据库。 -
现实情况可能需要修改
大多数 WordPress 站点会在数据库中硬编码链接(尤其是媒体文件、文章内部链接)。启用 HTTPS 后,需确保数据库中的链接从 http:// 更新为 https:// -
使用 SQL 批量替换旧链接
- 登录数据库 windows可以使用MysqlWorkbench 或者navicat;
- linux 执行命令mysql -h localhost -u root -p 然后输入密码
在 WordPress 数据库执行以下 SQL(通过 phpMyAdmin 或命令行):
-- 替换选项表中的地址 UPDATE wp_options SET option_value = REPLACE(option_value, 'http://test.com', 'https://test.com') WHERE option_name IN ('home', 'siteurl'); -- 替换文章内容中的地址 UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://test.com', 'https://test.com'); -- 替换文章元数据中的地址 UPDATE wp_postmeta SET meta_value = REPLACE(meta_value, 'http://test.com', 'https://test.com'); -- 替换修订历史中的地址(可选) UPDATE wp_posts SET guid = REPLACE(guid, 'http://test.com', 'https://test.com');
-
使用插件自动替换(推荐)
安装插件 Better Search Replace。
进入 Tools > Better Search Replace。
输入替换参数:
Search for: http://test.com
Replace with: http://192.168.31.182:8880
勾选所有表(wp_posts, wp_postmeta, wp_options 等)。
执行替换前备份数据库。
3.2.3. nginx服务配置
- 内外网请求分离:通过 server_name 区分公网域名和内网 IP 请求。
- 公网 HTTP 强制跳转 HTTPS:公网用户访问 80 端口(内网 8880)时,自动跳转到 443 端口(内网 8443)。
- 内网直连 HTTP:内网用户通过 192.168.31.182:8880 访问时不强制跳转 HTTPS。
- 统一 SSL 配置:公网 HTTPS 使用标准安全配置,内网可保持 HTTP。
# ----------------------------
# 公网 HTTP 请求(外网80 → 内网8880),强制跳转 HTTPS
# ----------------------------
server {
listen 8880;
server_name test.com 111.111.111.111; # 公网域名和IP
# 301 永久重定向到 HTTPS(外网443 → 内网8443)
return 301 https://$host$request_uri;
access_log ./host.access.log main;
}
# ----------------------------
# 内网 HTTP 请求(不跳转 HTTPS)
# ----------------------------
server {
listen 8880;
server_name 192.168.31.182; # 内网IP
root /usr/share/nginx/html/wordpress;
index index.php index.html index.htm;
access_log ./host.access.log main;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# ----------------------------
# 公网 HTTPS 请求(外网443 → 内网8443)
# ----------------------------
server {
listen 8443 ssl;
server_name test.com 111.111.111.111;
# SSL 证书路径
ssl_certificate /etc/nginx/conf.d/sec/test.com_bundle.crt;
ssl_certificate_key /etc/nginx/conf.d/sec/test.com.key;
# SSL 安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_buffer_size 4k;
root /usr/share/nginx/html/wordpress;
index index.php index.html index.htm;
access_log ./host.access.log main;
# 安全 HTTP 头
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff2)$ {
expires 365d;
add_header Cache-Control "public, no-transform";
access_log off;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
关键说明
-
分离公网与内网 HTTP 服务
公网 HTTP(8880 端口):
匹配 server_name turbock79.com 115.171.216.250,强制跳转到 HTTPS。
内网 HTTP(8880 端口):
匹配 server_name 192.168.31.182,直接处理请求不跳转。 -
公网 HTTPS 统一入口
监听 8443 端口(映射到公网 443),处理所有 HTTPS 流量。
启用现代 SSL 协议(TLSv1.2/1.3)和强加密套件。
添加安全 HTTP 头,防御 XSS、点击劫持等攻击。 -
静态资源缓存优化
图片、CSS、JS 等静态资源设置长期缓存,减少服务器负载。
关闭静态资源访问日志 (access_log off)。
3.2.4. 注意事项
-
清除缓存
清除浏览器缓存和 WordPress 缓存插件(如 WP Super Cache)的数据。
刷新固定链接:进入 Settings > Permalinks > Save Changes。 -
验证配置
内网访问:
浏览器访问 http://192.168.31.182:8880,检查页面链接是否均为内网地址。公网访问:
通过手机网络访问 http://test.com,确保内容正常加载。
3.2.5. 故障排查
-
检查重定向问题
在 wp-config.php 中临时禁用重定向:
define('WP_HOME', 'http://192.168.31.182:8880'); define('WP_SITEURL', 'http://192.168.31.182:8880'); // define('RELOCATE', true); // 取消注释强制重新定位
-
查看当前配置
在 WordPress 后台 Settings > General 检查 WordPress Address 和 Site Address 是否动态变化。
通过以上优化,您的 WordPress 将自动适应内外网环境,且数据库中的旧链接会被正确替换,无需硬编码 IP!
4. 协议相对路径全局配置方案
4.1. 问题核心分析
混合协议冲突:数据库中存在 HTTP 地址,但公网强制 HTTPS 导致图片无法加载(混合内容被浏览器拦截)
端口残留问题:内网访问时可能遗留端口号,导致重定向异常
动态配置不完善:wp-config.php 的协议判断逻辑需优化
4.2. 步骤1 数据库修改
- 修复数据库中的混合协议内容
执行以下 SQL 替换所有 HTTP 地址为协议相对路径(同时处理内外网地址):
-- 替换所有 HTTP/HTTPS 开头的旧地址为协议相对路径
UPDATE wp_options SET option_value = REPLACE(option_value, 'http://turbock79.com', '//turbock79.com') WHERE option_name IN ('home', 'siteurl');
UPDATE wp_options SET option_value = REPLACE(option_value, 'https://turbock79.com', '//turbock79.com');
UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://192.168.31.182:8880', '//turbock79.com');
UPDATE wp_posts SET post_content = REPLACE(post_content, 'https://192.168.31.182:8880', '//turbock79.com');
UPDATE wp_posts SET guid = REPLACE(guid, 'http://192.168.31.182:8880', '//turbock79.com');
UPDATE wp_postmeta SET meta_value = REPLACE(meta_value, 'http://192.168.31.182:8880', '//turbock79.com');
4.3. 步骤2 强制WordPress使用协议相对路径
4.3.1. 方案一:使用 Must-Use 插件(推荐)
在 WordPress 目录创建新路径:
mkdir -p /path/to/wordpress/wp-content/mu-plugins
创建协议转换插件文件:
vim /path/to/wordpress/wp-content/mu-plugins/protocol-relative.php
文件内容如下(自动对所有输出内容生效):
<?php
// 全局协议相对路径转换
function global_protocol_relative($content) {
$domain = 'turbock79.com'; // 你的公网域名
// 替换所有绝对地址为协议相对路径
$replacements = array(
'http://' . $domain => '//' . $domain,
'https://' . $domain => '//' . $domain,
'http://192.168.31.182:8880' => '//' . $domain,
'https://192.168.31.182:8880' => '//' . $domain
);
return str_replace(array_keys($replacements), array_values($replacements), $content);
}
// 应用范围
add_filter('the_content', 'global_protocol_relative');
add_filter('post_thumbnail_html', 'global_protocol_relative');
add_filter('wp_get_attachment_url', 'global_protocol_relative');
add_filter('stylesheet_uri', 'global_protocol_relative');
add_filter('script_loader_src', 'global_protocol_relative');
add_filter('style_loader_src', 'global_protocol_relative');
4.3.2. 方案二:修改 wp-config.php(次选)
在 wp-config.php 最后添加:
// 在 require_once(ABSPATH . 'wp-settings.php'); 之后添加
add_action('init', function() {
ob_start(function($buffer) {
return str_replace(
['http://turbock79.com', 'https://turbock79.com', 'http://192.168.31.182:8880'],
'//turbock79.com',
$buffer
);
});
});
5. 重要优先看:公网挑战及放弃本地部署网站
国内环境限制,ISP运营商封堵 80和443等端口;
-
即使我把本地DDNS的公网IP通过域名转化,也导致浏览器(默认80和443端口)无法正常访问NAS本地对应http页面。 即使各种备案手续齐全也不行,因为是动态公网IP,备案无法接受动态IP;
-
如果想办理本地,需要本地拉取办理专线(好像最少10w),确定固定公网IP之后, 才可本地化部署网站(80/443浏览器访问)。
-
如果只是本地自己玩,不需要公网也行。或者本地部署其他服务,类似mqtt-server 1883等端口,还是可以公网正常访问的。
-
本人个人NAS小型化, 没必要花费较多办理专线,该NAS+DDNS+公网 方案只能放弃。
-
可以考虑内网穿透方案,类似的产品有花生壳,或frp自行搭建穿透服务;
-
综合成本和开发部署周期,暂计划采用公有云厂商实现了, 顺便安利一下几个云厂商优惠券链接;
微信赞赏
支付宝赞赏