因为一时兴起,想要自己搭建一个博客,但在动手过程中,遇到了不少问题。于是改为先用AI根据需求出方案,再一步步实施,中间遇到的新问题也都通过AI来解决。最后结合我遇到的困难,在AI辅助下,写成此文。
本篇主要解决把博客真正跑起来,三步走:部署 Typecho → 部署 Caddy → 配 DNS + SSL 上线。
注意/xxx代表的是你实际安装的路径,详见上一篇
一、部署 Typecho
1.1 创建目录
mkdir -p /xxx/typecho/{html,data}html:博客程序文件,挂到容器的/var/www/html;data:Typecho 数据,挂到/app/usr。
1.2 编写 docker-compose.yml
在 /xxx/typecho/docker-compose.yml 写入:
services:
typecho:
image: php:8.2-apache
container_name: typecho
restart: unless-stopped
mem_limit: 256m
mem_reservation: 128m
ports:
- "9000:80" # 搭建阶段临时暴露;Apache 监听 80
volumes:
- ./html:/var/www/html
- ./data:/app/usr
environment:
- TZ=Asia/Shanghai
networks:
- services-network
networks:
services-network:
external: true几个要点(都是踩过坑后定下来的):
- 内存限制用
mem_limit/mem_reservation,而不是deploy.resources——后者在非 Swarm 模式下会静默失效; - 不写
version字段,Compose 已废弃它,写了只会多一行警告; 9000:80只是搭建阶段的临时映射,上线后要注释掉。
1.3 容器内手动安装 Typecho
因为用的是官方 PHP 镜像而非成品 Typecho 镜像,需要进容器手动装:
cd /xxx/typecho
docker compose up -d
docker exec -it typecho bash -c "
apt-get update && apt-get install -y wget unzip sqlite3 libsqlite3-dev && \
docker-php-ext-install pdo_sqlite && \
cd /var/www/html && \
wget https://github.com/typecho/typecho/releases/latest/download/typecho.zip && \
unzip typecho.zip && \
rm typecho.zip && \
chown -R www-data:www-data /var/www/html /app/usr && \
a2enmod rewrite
"
docker restart typecho这段命令干了五件事:
- 装
wget、unzip、sqlite3等工具; - 编译 PHP 的
pdo_sqlite扩展(Typecho 用 SQLite 存储,必须装它); - 下载并解压 Typecho 到网站根目录;
- 把属主改成
www-data(Apache 的运行用户); - 开启 Apache 的
rewrite模块(Typecho 伪静态依赖它)。
1.4 初始化
初始化有个关键坑:建议不要用 http://IP:9000 提前安装,而是等 Caddy 和域名都配好后,用 https://example.com 进安装向导。因为安装时填的「网站地址」会被写进数据库,如果用 IP 装,之后所有链接都会指向 IP,还得回后台手动改。
如果备案等待期想先验证,用 IP 装也行,但记得之后去后台改网站地址。
安装向导几个配置项:
| 配置项 | 填什么 |
|---|---|
| 数据库适配器 | Pdo 驱动适配(SQLite) |
| 数据库文件路径 | 保持默认 |
| 网站地址 | https://example.com |
| 管理员用户名 / 密码 | 自行设置 |
| 邮箱 | 不需要真实邮箱 |
二、部署 Caddy
2.1 编写 Caddyfile
mkdir -p /xxx/caddy
cat > /xxx/caddy/Caddyfile << 'EOF'
example.com {
reverse_proxy typecho:80
}
EOF重点:reverse_proxy typecho:80 里的 typecho 是 Docker 容器名,不是 localhost。因为所有容器都在同一个 services-network 网络里,Docker 会自动做容器名到 IP 的 DNS 解析。而在 Caddy 容器内部,localhost 指向它自己,写 localhost 就会反向代理到自己身上,直接报错。
2.2 编写 docker-compose.yml
cat > /xxx/caddy/docker-compose.yml << 'EOF'
services:
caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
mem_limit: 128m
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./data:/data
networks:
- services-network
networks:
services-network:
external: true
EOF两个易错点:
- 卷挂载区分大小写:Linux 是区分大小写的,
./Caddyfile和./caddyfile是两个不同的文件,拼错会导致挂载失败; - 不要挂载
./config:/config:Caddy 的自动保存功能可能用一份空白配置覆盖你的 Caddyfile。
2.3 启动 Caddy
cd /xxx/caddy
docker start typecho # 确保 Typecho 已启动
ufw allow 80/tcp
ufw allow 443/tcp
docker compose up -d
docker compose logs -f # 看到 "serving initial configuration" 即成功三、DNS + SSL 上线
3.1 添加 DNS A 记录
到域名注册商后台,添加一条 A 记录把域名指向服务器:
| 类型 | 主机记录 | 记录值 |
|---|---|---|
| A | @ | 服务器公网 IP |
这一步放在备案通过之后做(第一篇 3.3 有提)。
3.2 Caddy 自动申请证书
DNS 解析生效后,Caddy 会在第一次收到 HTTPS 请求时自动向 Let's Encrypt 申请证书,全程零配置。你只需要:
- 确认 80 和 443 端口在服务器防火墙和云安全组都已放行;
- 确认域名已解析到服务器 IP(
nslookup example.com); - 浏览器直接访问
https://example.com。
第一次访问会稍慢(Caddy 正在申请证书),看到 HTTPS 小锁后就成功了。之后证书到期 Caddy 会自动续期,无需人工干预。
如果一直卡在「不安全」或申请失败,多半是这两个原因:
- 80 端口没开——Let's Encrypt 的 HTTP-01 验证需要走 80 端口;
- 域名还没解析生效——确认 A 记录已添加、且
nslookup已返回正确 IP。
3.3 验证
浏览器访问 https://example.com,看到 Typecho 页面 + HTTPS 小锁,就算正式上线。
到这里博客已经能通过域名访问了。但还差两件事:公安备案 + 备案号展示,以及日常运维。下一篇讲。
暂无评论