[{"data":1,"prerenderedAt":199},["ShallowReactive",2],{"content:\u002Ffiddling\u002Fone-trek-twenty-stacks":3,"surround:\u002Ffiddling\u002Fone-trek-twenty-stacks":188},{"id":4,"title":5,"body":6,"categories":164,"date":166,"description":167,"draft":168,"extension":169,"image":170,"meta":171,"navigation":173,"path":174,"permalink":170,"published":170,"readingTime":175,"recommend":170,"references":170,"seo":180,"sitemap":181,"stem":182,"tags":183,"type":186,"__hash__":187},"content\u002Fposts\u002Ffiddling\u002Fone-trek-twenty-stacks.md","一个 TREK 引发的二十个 stack",{"type":7,"value":8,"toc":154},"minimark",[9,13,16,19,24,27,30,33,36,40,43,46,49,70,81,84,88,96,99,102,109,112,115,118,121,124,127,138,145,148,151],[10,11,12],"p",{},"前几天刷 GitHub trending，看到一个叫 TREK 的项目，让一群人在同一张地图上排路线、订住宿、列预算，做完还能丢给别人接着改。点进 demo 站玩了一圈，很精致。",[10,14,15],{},"跟 npy 出去玩的行程一直是拿 Obsidian 拼的，几个 daily note 来回链着写，越写越乱，到出门那天往往还是粗糙的「早上去哪下午去哪」。作者的 demo 可以直接用，但行程这种东西放在别人机器上多少有点不放心，早晚得自己部署。",[10,17,18],{},"既然要自己部署，索性开一台新 VPS。",[20,21,23],"h3",{"id":22},"netcup-arm","Netcup ARM",[10,25,26],{},"挑 VPS 纠结了一阵。DigitalOcean 和 Linode 同配置贵一倍以上，直接排除。Hetzner 性价比是有的，可惜 ARM 节点选址不灵活。国内小厂便宜，但备案是大坑，而且带宽小得可怜。兜了一圈还是 Netcup。",[10,28,29],{},"型号是 VPS 2000 ARM G11，10 vCore、16G 内存、512G NVMe、2.5 Gbps，月价 €13.41 含税。同样的配置放到 x86 至少得贵一倍。流量走 flatrate，24 小时滑动平均超过 2 TB 才限速到 200 Mbps，我这种小破站根本碰不到。",[10,31,32],{},"下单前 Google 了一圈，捞到一张 -50% coupon，首期直接砍到 €6.7 出头，续费回原价，香就完事了。",[10,34,35],{},"机房有 Nuremberg、Wien、Amsterdam 和美东 Manassas 四个。最后挑了 Manassas，国内常见路由走过去 ping 比三个欧洲点都低一截。至于邮件 IP 信誉，我出站邮件全走 Resend 的 HTTPS 桥接（后面会讲），不落本地 IP，没必要为这个死磕欧洲机房。",[20,37,39],{"id":38},"从零到-trek","从零到 TREK",[10,41,42],{},"下单到收到登录信息大概 5 分钟。第一件事不是装东西，而是先收紧 SSH 权限：禁 root、禁密码登录、改端口、ufw 默认 deny in。fail2ban 跑两天看日志，22 端口换掉之前一天 5000+ 次暴力尝试。",[10,44,45],{},"ARM64 镜像生态这两年好了很多。后面陆陆续续装的二十来个 stack 里，Caddy、Postgres、Stalwart、SnappyMail、Open WebUI、Vaultwarden、Dagu、Glance、Karakeep、Paperless 全都有官方多架构镜像，docker pull 直接 work。唯一费点事的是 Forgejo runner：base 镜像 ARM64 没问题，但我要在 runner 里跑 docker compose 当 deploy 工具，得自己加 docker-cli 和 docker-compose-plugin。最后用 buildx 推了一份 ARM64 镜像到自己的 Forgejo registry，runner 起来直接拉。",[10,47,48],{},"终于轮到 TREK 本身。仓库 mauriceboe\u002FTREK 有官方 docker-compose.yml，照抄过来改了几行：",[50,51,52,56,64,67],"ul",{},[53,54,55],"li",{},"端口收成只对 web 这个 docker 网络可见",[53,57,58,59,63],{},"ENCRYPTION_KEY 用 ",[60,61,62],"code",{"code":62},"openssl rand -base64 32"," 新生成一把",[53,65,66],{},"DATABASE_URL 走 SQLite，自己用够了",[53,68,69],{},"加上 web 这个 external network，跟 Caddy 接通",[10,71,72,73,76,77,80],{},"Caddyfile 那边一行 ",[60,74,75],{"code":75},"reverse_proxy trek:3000"," 收尾。从 ",[60,78,79],{"code":79},"docker compose up -d"," 到 trek.shinya.click 出登录页，前后不到 15 分钟。",[10,82,83],{},"看着空荡荡的 dashboard 注册完第一个账号，我下意识琢磨的不是「行程从哪开始拉」，而是「还能往这台机器里塞点啥」。",[20,85,87],{"id":86},"二十来个-stack","二十来个 stack",[10,89,90,91,95],{},"后半夜的折腾大概就是从这个念头开始的。",[92,93,94],"del",{},"手痒","反正配置富裕，闲着也是闲着，干脆把一直想自托管的东西都搬上来。",[10,97,98],{},"第二天起床顺手装了 Forgejo 负责代码托管，博客也借此机会翻新了一遍，下面单独说。邮件是 Stalwart + SnappyMail + 自己写的 Resend bridge 三件套。AI 那条线挂 CLIProxyAPI，把 OpenAI \u002F Claude \u002F Gemini 几家订阅统一起来，前端是 Open WebUI。再往后是密码、网盘、图床、笔记、稍后读、RSS、PDF 工具集，能自托管的几乎都尝试了一遍。SSO 用 Authelia。备份是 Dagu 起一个 DAG，每天加密快照到 R2。",[10,100,101],{},"陆陆续续装完，整套结构大概是这样：",[10,103,104],{},[105,106],"img",{"alt":107,"src":108},"画的时候还没把博客算进去，现在看只会更满","https:\u002F\u002Fblog-img.774352199.xyz\u002F4F9LtW.png",[10,110,111],{},"入口侧走 Cloudflare SaaS 智能解析回源，Caddy 是唯一的外向 TLS 终点，按 Host 头反代到对应容器。需要登录的服务统一挂 Authelia forward_auth。出站邮件走 Resend 的 HTTPS API 桥接，绕开 Netcup 封掉的 25 端口。",[10,113,114],{},"Dockge 面板里二十来个 stack 全绿着。当然，这里面相当一部分是部署成瘾上头——本来只想要一个 TREK，最后 TREK 在这张图里只占一个小格子。",[20,116,117],{"id":117},"迁博客",[10,119,120],{},"之前博客是 Astro + retypeset，markdown push 上去走 CI 构建发布。用了一年多没出过大问题，但有几个点一直膈应：改个错别字也要 commit、push、等 build；想加个友链或者独立页面，还得重新折腾文件树。游记照片一多，构建慢得离谱。",[10,122,123],{},"于是趁此机会重构一下。",[10,125,126],{},"新栈是 SvelteKit 2 + adapter-node SSR + UnoCSS，视觉沿用 retypeset，样式按 UnoCSS 重写了一份。内容后端换成 PocketBase，建了 7 个 collection，把文章、标签、游记、游记天数、游记照片、独立页面、友链全收进 SQLite。i18n 改成 zh \u002F en \u002F ja 三语并存。Astro 那边导出来的 markdown 写了个 migration 脚本一锅倒进 PB，123 篇文章、4 篇游记、148 张游记照片记录，加上 pages 和 friends 全部落库。",[10,128,129,130,133,134,137],{},"部署改成蓝绿。blog-blue 和 blog-green 两个容器常驻，活跃的由 ",[60,131,132],{"code":132},"\u002Fopt\u002Fapp\u002Fblog\u002Factive"," 标记，Caddy 的反代上游从 ",[60,135,136],{"code":136},"\u002Fopt\u002Fapp\u002Fcaddy-blog\u002Fupstream.caddy"," 这个文件 import。CI 推完新镜像跑 switch.sh：起 target 色、等 healthcheck、改 import 文件、caddy reload 切流，失败自动回滚。做完之后发文章不用再等三分钟 build，PB 后台改一下，保存即生效。",[10,139,140,141,144],{},"后台是 SvelteKit 内部的 SPA，挂在 \u002Fadmin 下，走 Authelia forward_auth。admin 到 PB 的写请求经 Caddy 同源反代 ",[60,142,143],{"code":143},"\u002Fapi\u002Fpb\u002F*","，token 由 Caddy 注入，浏览器和 git 仓库都摸不到这把 key。PB 写入会触发一个 JS 钩子 POST 到 blog 容器的内部端点，做服务端缓存失效，再调一次 Cloudflare API purge 边缘缓存，公开页平均还是 CDN 命中。",[10,146,147],{},"整个迁移两个晚上搞定。",[20,149,150],{"id":150},"后记",[10,152,153],{},"折腾了好几天，trek 到现在一篇规划也还没做 = =",{"title":155,"searchDepth":156,"depth":156,"links":157},"",4,[158,160,161,162,163],{"id":22,"depth":159,"text":23},3,{"id":38,"depth":159,"text":39},{"id":86,"depth":159,"text":87},{"id":117,"depth":159,"text":117},{"id":150,"depth":159,"text":150},[165],"折腾","2026-05-11 22:43:00","刷 GitHub trending 刷到一个旅行规划工具，想自己跑一台。既然都要开新 VPS，那就顺手多装亿点点。",false,"md",null,{"slots":172},{},true,"\u002Ffiddling\u002Fone-trek-twenty-stacks",{"text":176,"minutes":177,"time":178,"words":179},"8 min read",7.085,425100,1417,{"title":5,"description":167},{"loc":174},"posts\u002Ffiddling\u002Fone-trek-twenty-stacks",[165,184,185],"vps","自托管","tech","p3eeZXGZBHWv1d624kWtGYT9MANLOI-5ZopFs-wwMIw",[189,194],{"title":190,"path":191,"stem":192,"date":193,"type":186,"children":-1},"微软模拟飞行 2024 折腾记录","\u002Ffiddling\u002Fmsfs2024-joystick-and-pico","posts\u002Ffiddling\u002Fmsfs2024-joystick-and-pico","2025-12-14 14:31:00",{"title":195,"path":196,"stem":197,"date":198,"type":186,"children":-1},"国行 Mac 折腾 Apple 智能：从换区到把 ChatGPT 抠出来","\u002Ffiddling\u002Fmacos-27-apple-intelligence-chatgpt","posts\u002Ffiddling\u002Fmacos-27-apple-intelligence-chatgpt","2026-06-11 10:00:00",1787554443805]