用 cloud-init + Docker 十分钟搭起这个站

封面:用 cloud-init + Docker 十分钟搭起这个站

这个博客的第一篇文章,就写它自己是怎么搭起来的:一台 DigitalOcean 主机、一份 cloud-init 文件,开机几分钟后 WordPress、个人工作台和 HTTPS 证书全部就位。整套环境是一份纯文本,下次重建只需要再贴一次。

要点速览

  • 一台 2GB 主机 + Docker Compose:Caddy、WordPress、MariaDB 三个容器。
  • Caddy 按域名分流,自动申请和续期 Let's Encrypt 证书。
  • cloud-init 负责从装包到初始化站点的全部步骤,密码开机时随机生成。
  • 踩坑提醒:初始化脚本里别写中文。

整体架构

站点架构图:浏览器、DNS、Droplet 内的 Caddy、WordPress、MariaDB 与工作台
一台主机、三个容器、一个入口;下方是 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 用进日常工作流的尝试。工作台那边则会慢慢长成一个自己用的效率面板。