这个博客的第一篇文章,就写它自己是怎么搭起来的:一台 DigitalOcean 主机、一份 cloud-init 文件,开机几分钟后 WordPress、个人工作台和 HTTPS 证书全部就位。整套环境是一份纯文本,下次重建只需要再贴一次。
要点速览
- 一台 2GB 主机 + Docker Compose:Caddy、WordPress、MariaDB 三个容器。
- Caddy 按域名分流,自动申请和续期 Let's Encrypt 证书。
- cloud-init 负责从装包到初始化站点的全部步骤,密码开机时随机生成。
- 踩坑提醒:初始化脚本里别写中文。
整体架构

- 主机:DigitalOcean 新加坡节点,1 vCPU / 2GB,Ubuntu 24.04,离国内延迟相对友好。
- 入口:Caddy 监听 80/443。主域名反代到 WordPress;
dash子域名直接提供静态工作台,并加一层 Basic Auth。 - 数据:MariaDB 和 WordPress 文件都放在 Docker 数据卷里,容器可以随时重建。
- 证书:DNS 指向主机后,Caddy 首次访问时自动完成 ACME 验证,不需要 certbot。
为什么用 cloud-init
以前搭环境总是 SSH 上去一条条敲命令,过几个月再搭一次,细节已经忘光。这次把所有步骤写进一个 cloud-init 文件:装基础包、写配置、装 Docker、随机生成密码、启动容器,最后用 wp-cli 初始化站点(中文语言包、上海时区、固定链接)。
环境即文本:能放进版本管理的东西,才是真正可复用的东西。
几个值得记下来的细节
- 反代后的 HTTPS 识别:WordPress 在反向代理后面拿不到 HTTPS 状态,需要根据
X-Forwarded-Proto设置$_SERVER['HTTPS'],否则后台会重定向循环或出现混合内容。 - Compose 里的美元符号:Compose 会插值
$,PHP 变量要写成$$;bcrypt 哈希写进.env时要加单引号。 - 密码不落在脚本里:所有密码开机时随机生成,只保存在服务器 root 目录下,脚本本身可以放心存档。
- 小内存加 swap:MariaDB + PHP 偶尔吃紧,加 1G swap 兜底。
踩坑:一行中文注释让整份配置失效
第一次开机后,主机上什么都没有装。查 /var/log/cloud-init.log 才发现:脚本里的中文注释在提交时被转成了乱码,YAML 解析失败,整份配置被静默跳过,连报错都不显眼。
补救办法是用 cloud-init query userdata 取回原始内容,修正编码后手动执行。教训很简单:初始化脚本全部使用 ASCII,中文说明写在单独的 README 里。
接下来
这个博客会记录我在工业自动化和软件开发之间的实践:上位机、数据库工具、Web 管理系统,以及把 AI 用进日常工作流的尝试。工作台那边则会慢慢长成一个自己用的效率面板。
