前情回顾

我还在学校时,就在阿里云使用学生身份购买价格比较优惠的云服务器。因为单纯是托管一下博客,毕业后降配为最低配后价格也还好,但费用仍在逐年增加。直到去年双十一前后,续费价格涨到了令人难以接受的地步。同时双十一又有活动,于是乎果断停掉了老的服务器,购入了价格低廉配置又高的活动服务器。老服务器上运行的是宝塔,托管的都是php网站。工作以来接触java、docker较多,就想着把新服务器直接换用docker部署,用一些portainer、nginxui等来替代宝塔。理想很美好,自己尝试使用php+apache镜像制作typecho博客镜像又通过nginx代理,出了一些问题,整个网页都乱掉了,其实现在想想应该就是css等静态资源没有加载好,大概率是代理搞错了。又发现阿里云的证书越来越麻烦,证书有效期也变短了,索性就懒得搞了,云服务器也就被荒废了很久。

过年时候,使用国补购买mac mini宣传热度很高。我也凑热闹买了一个,正好作为arm架构设备玩一玩。当时用了下mac上的orbstack软件,惊为天人,薄纱docker desktop,不管是docker、k8s甚至是虚拟机的体验都极佳。当时想的是放在老家,研究了半天ddnsgo,没有公网ipv4就绑了ipv6,当一个远程服务器用。结果没多久不知道是因为断电还是断网,连不上了,爸妈也不会处理,就又被搁置了。直到不久前回了一趟老家,没找到hub连不上键盘,索性直接把mac带走了。然而我租的公寓不仅没有公网ipv6,甚至不支持ipv6,就只能用todesk远程用了。

契机始于周五晚上,偶然看内网穿透的帖子,发现了一个叫tailscale的软件。他的理念很神奇,相当于将多个自己的设备组成一个虚拟的局域网,每个设备分配一个ip。突然间灵光一闪,这正是我需要的软件啊。对于mac乃至nas来说,能方便地通过ip使用,甚至可能将域名指向私有ip。既能自己方便使用,又不至于像普通内网穿透那样将设备暴露在公网上,简直完美。

环境搭建

内网穿透

安装tailscale

笔记本、mac、云服务器、手机都装了tailscale。能够很方便的通过ip直接ssh到mac了,都不需要todesk,体验就很哇塞。手机电脑还能很方便的打开使用orbstack部署在mac上的应用。于是想关掉ddnsgo,这家伙让我每天收到n多ip变更导致域名解析改变的邮件,名副其实的在刷屏。悲剧的是找了半天才找到了登录地址,忘记了密码。

mac卸载ddnsgo

#重置密码
./ddns-go -resetPassword newpassword
#卸载
./ddns-go -s uninstall

卸载后很开心的将之前就分配给mac的域名重新解析到tailscale的私有ip。浏览器访问域名后很顺畅打开了mac上的示例应用getting-started,很开心,mac终于不会再躺尸了。

折腾云服务器

portainer重新纳管mac

先前就在云服务器上部署了portainer,买了mac后当时用ddns指向ipv6,艰难的为orbstack版docker配置了ipv6。orbstack中的k8s我记得配置ipv6失败了。所以大概率当时是portainer能纳管mac的docker环境,但是无法纳管k8s。这回直接用域名指向ipv4私有地址,同时纳管了mac的docker和k8s环境。很开心。

nginxui不要配成循环

配置文件在conf.d/nginx-ui.conf中,不需要再额外创建一个nginxui站点。否则会无限循环。

注意www目录位置

这个问题纯属脑子僵住了。想测试一下简单的静态html能否查看,在/var/www中写了个简单的html结果死活解析不出来,后来想到挂载到容器内部的www是在其他路径。

测试java容器

去年觉得ios上记账软件一直不平账,一气之下自己借助ai辅助开始写一个记账软件(开发了基础功能、后来也搁置了)。当时在云服务器上用portainer跑起来了,没有设置alway restart。这次跑起来居然报错了,无法加载capcha。这我就觉得很奇怪,因为当时我记得因为这个问题,找了特殊版本的jdk容器。查看了半天没找到问题,后来莫名其妙自己恢复了。可能是缓存的锅?

配置证书托管

最开始我是自己在阿里云上手动申请证书,一开始还能签到一年的长期证书,但没有泛解析。后来每年免费次数变少了,多开几个子域名都不够用,就索性用宝塔自动签发证书,但可能由于我开了ssl,续签很容易失败。私有环境可以自己用openssl签发,后来用mkcert更简单些。但公网认可的还得看certbot,这个我用了一段时间,重新签发会导致文件名变化,挂载到nginxui容器内就比较烦,也没法通过软连接更新。

话说nginxui自己有一个托管证书的功能,看起来是能像宝塔一样自动申请证书的,但最终没成功才又去用了certbot。这次趁热打铁再来试一试。话说nginxui关于自动签发证书如何配置的资料是真的少。ACME用户我是添加成功了的。问题出在DNS凭证上,设置凭证的页面是这样的:

凭证
ALICLOUD_ACCESS_KEY //Access key ID
ALICLOUD_RAM_ROLE //Your instance RAM role
ALICLOUD_SECRET_KEY //Access Key secret
ALICLOUD_SECURITY_TOKEN //STS Security Token (optional)
额外选项
ALICLOUD_HTTP_TIMEOUT //API request timeout in seconds (Default: 10)
ALICLOUD_POLLING_INTERVAL //Time between DNS propagation check in seconds (Default: 2)
ALICLOUD_PROPAGATION_TIMEOUT //Maximum waiting time for DNS propagation in seconds (Default: 60)
ALICLOUD_TTL //The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)

很自然的认为前三个是必填的对吧。一和三很好填写,然后二,我费好大劲创建了角色,却发现无法将角色绑定到RAM用户或者用户组上。在这填写了也不知道有什么用。第四个说了是可选项,研究半天确实没发现怎么调用api获得这个token。实在没办法了,问了deepseek,告诉我第二项就不用写。。。醉了。删掉第二项后,申请证书还是失败了,但是返回的错误日志含了一个网址,告诉我为RAM账户分配的权限少了3种,然而我只找到了前两种,第三种实在没有。又试了一下居然成功了,第一次用nginxui申请到了证书,心情舒畅。

docker配置,更新镜像

最开始云服务器的docker是配了镜像源的,www.geekery.cn上一个脚本就很好用。可惜不知为何这次死活拉不到镜像,又换了xuanyuan.me也不行。最后只能上大招了,安装了trojan和proxychains。是真好用啊,乱拳打死老师傅。成功更新了云服务器的nginxui。windows和mac就更简单了,图形化的。

折腾mac

mac也安装了nginxui,但是目前没能成功被纳管到云服务器的nginxui上,以后再研究吧。
mac也升级了portainer,CE新版本居然换图标了。
mac安装了sunpanel,非常好用的导航页,使我的多环境旋转,爱来自私有ip。

sunpanel无法通过域名访问

配置是简单的proxy_pass http://ip:port;但是一直报错502。后来想明白了,原因是容器内不支持私有ip,也很合理么,毕竟容器内没有安装tailscale。所以代理的时候不如直接配成容器名:内部端口。比如proxy_pass http://sun_panel:3002;

mac的portainer被纳管很慢

虽然说云服务器纳管了mac的docker和k8s,但是慢到令人发指。经常被判定为已经down了。所以觉得不如独立管理,各管各的。

升级agent

升级potainer后发现portainer_agent也要升级。但不管是loadbalancer还是nodeport,官方的yaml有两个问题。一是不存在yaml种指定的imageportainer/agent:2.33.0,只能拉取到portainer/2.33.0-20250811-alpine这种,只能自己重新打一下tag了。另外imagePullPolicy是always,又拉不到指定的tag,所以这里也改成了IfNotPresent。用curl下载到本地,本地编辑后再运行。

curl https://downloads.portainer.io/ce2-33/portainer-agent-k8s-lb.yaml -o portainer-agent-k8s-lb.yaml
docker tag portainer/agent:2.33.0-20250811-alpine portainer/agent:2.33.0
vi portainer-agent-k8s-lb.yaml
kubectl apply -f portainer-agent-k8s-lb.yaml

清理orbstack k8s

真是不得不夸一下orbstack,重置k8s非常简单,一键重置。orbstack k8s教程命令硬控了我一段时间,短短的一个语句kubectl run nginx --image=nginx。只建立了一个pod出来,但是存在问题,pullpolicy也是always,于是一直尝试拉取,一直失败。想改成ifnotpresent还改不了。听了deepseek的解释,说这不是静态 Pod(静态 Pod 需要节点上的 manifest 文件),但也不是受控制器管理的 Pod,改成kubectl create deployment nginx --image=nginx就可以编辑了。

mac的portainer域名

想着方便,设置了四级泛域名解析,证书成功申请到了,但是域名解析有问题,全国大部分地区无法解析。还是老老实实用三级吧。

portainer里的k8s

mac域名能在阿里云服务器中被解析,但是mac上的portianer里不行了,跟sunpanel一样的道理,容器内无法使用tailscale的ip。所以解决方案是使用了k8s的external ip。

至此mac中的docker和k8s仅被纳管与mac自己的portainer中,速度很不错,比较顺畅。

k8s的kubectl窗口打不开

loadbalancer换成nodeport也不行。原因是nginx未配置支持websocket。

另外,云服务器的portainer无法进入容器console,也是整个原因,配了就好了。

恢复博客

尝试使用php-fpm的镜像和nginx对接。失败了多次后,索性直接下载了一个现成的镜像joyqi/typecho:nightly-php7.4-apache,非常好用,就不为难自己了,以后再研究吧。

换了现成镜像还是有问题。存在index.php重写和https mix问题。

整体调很困难,决定先撤掉https。用ip:port访问又会触发handsom主题的版权保护,因为购买权限只绑定了域名,使用域名访问有时也会触发版权保护。最后决定趁着http域名访问不触发时,先在http中解决一部分问题。将站点网址、个人主页、音乐播放器都改为http。替换了失效的avatar代理。

index.php重写问题

镜像里工作目录新建.htaccess

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^(.*)$ index.php [L]
</IfModule>

加了重写后发现http自动向https跳转,后来发现应该是缓存的问题。
不升级handsome了,回退后http看着没问题。音乐播放器也是正常的。
再启用https,又出现了mix问题。

https mix问题

表现为css等静态资源因为mix被拦截,导致整个页面歪歪扭扭奇丑无比。
按照deepseek的建议修改后会导致网页看着正常,但是无法登录。一度令我以为自己不小心修改了密码,还尝试重置密码了好久,typecho1.1的密码重置方式变了,找了123456对应的新版本密文也不对。最后找了当初备份的sql比对才确认自己确实没改过密码。不是密码失效,而是登录接口出了问题。
最后又修改了config.inc.php,加了几句才解决。

// 强制识别 HTTPS(关键!)
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
    $_SERVER['HTTPS'] = 'on';
}

// 强制 Cookie 仅 HTTPS 传输(修复 "不安全表单" 警告)
ini_set('session.cookie_secure', '1');
ini_set('session.cookie_httponly', '1');
ini_set('session.cookie_samesite', 'Lax');

这是最后生效的nginx配置

    location / {
        proxy_pass http://ip:port;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cookie_flags ~ secure;
        proxy_set_header X-Forwarded-Port 443;
        proxy_cookie_path / "/; secure; HttpOnly; SameSite=Lax";
    }

deepseek总结了一下

  1. X-Forwarded-Proto $scheme 代替固定值 https 之前写死 X-Forwarded-Proto https 会导致部分情况下协议判断错误,而 $scheme 动态适配 http/https,让 PHP 正确识别请求类型。
  2. 移除 Content-Security-Policy upgrade-insecure-requests 虽然能修复 Mixed Content,但可能干扰登录表单提交,导致 Cookie 失效。
  3. 强化 Cookie 安全设置 proxy_cookie_path + proxy_cookie_flags + PHP 的 session.cookie_secure 确保 Cookie 仅限 HTTPS 传输,解决浏览器 "不安全表单" 警告。
  4. Typecho 正确识别 HTTPS config.inc.php 里的 HTTP_X_FORWARDED_PROTO 检测让 Typecho 生成正确的 https 链接,避免 Mixed Content。

至此本次折腾的主要目的都达到了。舒服。

最后修改:2025 年 08 月 19 日 01 : 23 AM
如果觉得我的文章对你有用,请随意赞赏