腾讯云 Ubuntu 服务器部署 Typecho 全流程实战

从零开始在全新 Ubuntu 24.04 腾讯云服务器上用 Docker Compose 部署 Typecho 博客,并解决途中遇到的所有问题。本文按完整流程逐步记录,附每一步的操作命令、遇到的问题和对应解决方案。

目录

  1. 环境概览
  2. 第一步:安装 Docker 与 Compose
  3. 第二步:搭建项目目录与配置文件
  4. 第三步:下载 Typecho 源码
  5. 第四步:启动容器并验证
  6. 常见问题与解决方案(重点)
  7. 最终成果与常用命令

1. 环境概览

项目
操作系统Ubuntu 24.04.4 LTS
云服务商腾讯云
服务器架构50G 磁盘 / 1.9G 内存
虚拟化Docker + Docker Compose
Typecho 版本v1.3.0(latest)
数据库MariaDB 11
Web 服务器Nginx 1.27
PHP8.3-fpm

目标架构:三个 Docker 容器(Nginx + PHP-FPM + MariaDB),通过 Compose 统一编排,Typecho 源码挂载共享。


2. 第一步:安装 Docker 与 Compose

2.1 安装 Docker

腾讯云默认源里没有 Docker,官方安装脚本是:

curl -fsSL https://get.docker.com | sh

⚠️ 遇到的问题:

curl: (35) Recv failure: Connection reset by peer

原因:get.docker.com 域名在服务器上无法连通(网络受限)。

✅ 解决方案:改用 Ubuntu 官方 apt 源安装 Docker:

sudo apt-get update
sudo apt-get install -y docker.io docker-compose-v2

验证安装:

docker --version          # Docker version 29.1.3
docker compose version    # Docker Compose version 2.40.3

将当前用户加入 docker 组,避免日后每次敲 sudo:

sudo usermod -aG docker ubuntu
注:加入 docker 组需要重新登录后才生效,本流程后续用 sudo 操作。

3. 第二步:搭建项目目录与配置文件

3.1 创建项目目录

mkdir -p /home/ubuntu/typecho/www

结构规划:

/home/ubuntu/typecho/
├── docker-compose.yml     # 容器编排
├── nginx.conf             # Nginx 站点配置
├── daemon.json            # Docker 镜像加速(临时)
├── docker-php/            # 自定义 PHP 镜像
│   └── Dockerfile
└── www/                   # Typecho 源码(挂载共享)

3.2 编写 docker-compose.yml

services:
  db:
    image: mariadb:11
    container_name: typecho-db
    restart: unless-stopped
    environment:
      MARIADB_ROOT_PASSWORD: typecho_root_pwd
      MARIADB_DATABASE: typecho
      MARIADB_USER: typecho
      MARIADB_PASSWORD: typecho_pass
    volumes:
      - ./db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 5s
      timeout: 5s
      retries: 20

  php:
    build: ./docker-php
    container_name: typecho-php
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./www:/var/www/html

  web:
    image: nginx:1.27
    container_name: typecho-web
    restart: unless-stopped
    depends_on:
      - php
    ports:
      - "8080:80"
    volumes:
      - ./www:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro

3.3 编写 PHP 自定义镜像(Dockerfile)

PHP 官方镜像不带 Typecho 需要的扩展,需要自行编译:

FROM php:8.3-fpm

# 替换为国内 Debian 源加速
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources

# 安装 PHP 扩展编译所需的系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
    libonig-dev \
    libgd-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype-dev \
    libzip-dev \
    libxml2-dev \
    && rm -rf /var/lib/apt/lists/*

# 配置并编译 PHP 扩展
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install pdo_mysql mbstring gd exif zip

WORKDIR /var/www/html

3.4 编写 nginx.conf

server {
    listen 80;
    server_name _;
    root /var/www/html;
    index index.php index.html index.htm;

    client_max_body_size 30M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # 处理 PHP 文件及 PATH_INFO 路由(如 /index.php/action/login)
    location ~ ^(.+\.php)(.*)$ {
        try_files $1 =404;
        include fastcgi_params;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param SCRIPT_FILENAME $document_root$1;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_index index.php;
        fastcgi_pass php:9000;
    }

    location ~ /\. {
        deny all;
    }
}

4. 第三步:下载 Typecho 源码

4.1 查询最新版本

curl -s https://api.github.com/repos/typecho/typecho/releases/latest | grep tag_name
# "tag_name": "v1.3.0"

4.2 下载并解压

cd /home/ubuntu/typecho
wget https://github.com/typecho/typecho/releases/download/v1.3.0/typecho.zip
sudo apt-get install -y unzip
unzip -o typecho.zip -d www

压缩包中的 index.phpinstall.phpadmin/usr/var/ 等文件即 Typecho 程序本体。

⚠️ 遇到的问题:

unzip: command not found

✅ 解决方案:服务器缺少 unzip 工具,用 apt 安装:

sudo apt-get install -y unzip

5. 第四步:启动容器并验证

5.1 启动

cd /home/ubuntu/typecho
sudo docker compose up -d

首次启动会拉取三个镜像(mariadb、nginx、php),并构建自定义 PHP 镜像。

5.2 验证

sudo docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"

NAME          STATUS                    PORTS
typecho-db    Up (healthy)              3306/tcp
typecho-php   Up                        9000/tcp
typecho-web   Up                        0.0.0.0:8080->80/tcp

检查 PHP 扩展与数据库连接:

sudo docker exec typecho-php php -m | grep -E "pdo_mysql|mbstring|gd|exif|zip"
# exif gd mbstring pdo_mysql zip

sudo docker exec typecho-php php -r "new PDO('mysql:host=db;dbname=typecho','typecho','typecho_pass'); echo 'OK';"
# OK

浏览器访问 http://服务器IP:8080 应看到 Typecho 安装向导。


6. 常见问题与解决方案(核心章节)

这一章汇总了部署过程中遇到的全部问题,按出现的顺序整理。

6.1 Docker Hub 镜像拉取超时

现象docker compose up 拉取镜像超时:

Pulling db (mariadb:11)...
Error response from daemon: Get https://registry-1.docker.io/v2/: i/o timeout

原因:服务器访问 Docker Hub(registry-1.docker.io)网络受限,和 get.docker.com 不通是同一类问题。

✅ 解决:配置国内镜像加速器。

// /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.1ms.run",
    "https://hub-mirror.c.163.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://mirror.baidubce.com"
  ]
}
sudo cp daemon.json /etc/docker/daemon.json
sudo systemctl restart docker
# 验证
sudo docker info | grep -A6 "Registry Mirrors"

重启后重新 docker compose up -d 即可成功拉取。

6.2 PHP 扩展编译失败(mbstring 缺 oniguruma)

现象:容器启动后网页返回 502 Bad Gateway,日志显示:

configure: error: Package requirements (oniguruma) were not met:
Package 'oniguruma', required by 'virtual:world', not found

原因:Typecho 需要 mbstring 扩展,但 PHP 镜像里没有编译它所需的基础库(libonig)。

✅ 解决:改用 Dockerfile 方式,先把编译依赖装好再编译扩展(见上文 Dockerfile)。这种方式把 apt 源也换成了中科大国内源,解决网络慢的问题。

6.3 腾讯云安全组未开放端口,公网访问不了

现象:本机 curl localhost:8080 正常(302),但从公网 IP 无法访问。

原因:腾讯云在云控制台层面用安全组过滤入站流量,8080 默认未放行(服务器内 ufw 未启用、iptables 也不控端口,不是服务器本身的问题)。

✅ 解决:登录腾讯云控制台 → 云服务器 → 安全组 → 添加入站规则:

协议: TCP
端口: 8080
来源: 0.0.0.0/0
策略: 允许

6.4 安装程序提示 uploads 目录不可写

现象

提示上传目录无法写入,请手动将安装目录下的 /usr/uploads 目录的权限设置为可写

原因:源码解压后由 ubuntu 用户拥有(drwxr-xr-x ubuntu ubuntu),而 PHP 容器运行时用户是 www-data,对该目录没有写权限。

✅ 解决:设置目录权限为所有人可读写执行:

sudo chmod -R 777 /home/ubuntu/typecho/www/usr/uploads
sudo chmod -R 777 /home/ubuntu/typecho/www/usr

6.5 安装程序无法自动创建 config.inc.php

现象

安装程序无法自动创建 config.inc.php 文件

原因config.inc.php 要写在根目录 /var/www/html 下,该目录同样没有 www-data 写权限。

✅ 解决:放开根目录写权限:

sudo chmod 777 /home/ubuntu/typecho/www

6.6 后台登录 404(PATH_INFO 路由问题)

现象:后台登录请求 /index.php/action/login 返回 404,后台无法登录。

原因:Typecho 使用 PATH_INFO 路由(/index.php/action/login 这种带路径参数的写法)。最初的 nginx.conf 用 location /index.php {}try_files $uri =404,它把整个路径当成一个真实文件去寻找,找不到就 404。正则 \.php$ 也只匹配以 .php 结尾的 URL,匹配不到这类带后缀路径的请求。

✅ 解决:修改 nginx.conf,用能匹配 PATH_INFO 的正则,并正确处理路径参数:

location ~ ^(.+\.php)(.*)$ {
    try_files $1 =404;
    include fastcgi_params;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_param SCRIPT_FILENAME $document_root$1;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_index index.php;
    fastcgi_pass php:9000;
}

⚠️ 附带坑:修改 nginx.conf 后 nginx -s reload 不生效。原因是 write_file 改写文件时会更换文件的 inode,而 Docker bind mount 仍指向旧 inode,容器内读到的还是旧配置。需要重启容器让挂载刷新

cd /home/ubuntu/typecho && sudo docker compose restart web

修正后 /index.php/action/login 从 404 变为 302(正常跳转)。

6.7 Handsome 主题导致白屏

现象:切换 Handsome 主题后首页白屏,实际是 PHP 抛错但被主题自身屏蔽错误显示。

问题一:旧类名未注册

日志报错:

ERROR: Class "Widget_Abstract_Metas" not found

原因:Handsome 主题大量使用旧式类名(如 Widget_Abstract_Metas),而 Typecho 1.3.0 已改用命名空间写法(\Widget\Base\Metas)。虽然 Typecho 定义了 __TYPECHO_CLASS_ALIASES__ 常量数组描述映射,但没有实际执行 class_alias(),旧类名并未真正注册。

✅ 解决:在主题 functions.php 开头补充别名注册:

// 兼容 Typecho 1.3.0:注册旧类名别名
$classAliases = defined('__TYPECHO_CLASS_ALIASES__') ? __TYPECHO_CLASS_ALIASES__ : [];
foreach ($classAliases as $oldName => $newName) {
    if (!class_exists($oldName) && class_exists($newName)) {
        class_alias($newName, $oldName);
    }
}

问题二:PHP 8.3 方法签名不兼容

开启错误显示后:

Fatal error: Declaration of Handsome_Widget_Comments_Archive::select():
Typecho\Db\Query must be compatible with Widget\Base\Comments::select(...$fields):
Typecho\Db\Query

原因:PHP 8 起方法签名必须与父类兼容。父类 Widget\Base\Comments::select(...$fields) 带可变参数,而主题里对应的方法写成 select(): Query,缺少 ...$fields,PHP 8.3 视为致命错误。

✅ 解决:修正签名,补上可变参数:

public function select(...$fields): Typecho\Db\Query

6.8 Handsome 主题授权拦截

现象:整站(含首页)显示 Handsome 主题的授权校验页,要求在授权平台添加域名。

原因:Handsome 是付费主题,首次使用需要到 https://auth.ihewro.com/admin 授权平台绑定博客域名,并在后台主题设置页刷新授权状态。此外还要登录后台手工触发一次授权接口。

✅ 解决:按提示在授权平台添加域名 → 打开后台 Handsome 外观设置界面刷新,授权通过后正常显示。


7. 最终成果与常用命令

7.1 访问地址

  • 网站首页:http://IP:8080/
  • 后台:http://IP:8080/admin/login.php
  • 文章固定链接:http://IP:8080/index.php/archives/{cid}/

(暂未开启伪静态 rewrite,所以链接带 index.php 前缀。)

7.2 数据库连接信息(安装时填写)

参数
数据库地址db(Docker 内部网络域名)
端口3306
数据库名******
用户名******
密码******

7.3 常用管理命令

cd /home/ubuntu/typecho

sudo docker compose ps            # 查看容器状态
sudo docker compose logs -f       # 查看实时日志
sudo docker compose restart web   # 重启某容器
sudo docker compose down          # 停止所有容器
sudo docker compose up -d         # 启动所有容器
sudo docker exec typecho-db mariadb -utypecho -ptypecho_pass typecho  # 进数据库

7.4 关键目录

/home/ubuntu/typecho/
├── www/                  # 网站源码(改这里=改网站)
├── db_data/              # 数据库数据(备份这个)
├── docker-compose.yml    # 编排配置
├── nginx.conf            # Nginx 站点配置
└── docker-php/Dockerfile # 自定义 PHP 镜像

结语

整个部署过程最大的体会是:看似简单的 "一条 docker compose up 拉起来",实际坑都在网络和兼容性上——Docker Hub 网络受限、PHP 扩展编译依赖、腾讯云安全组、PATH_INFO 路由、旧主题与新版 Typecho / PHP 8.3 的兼容,每一个都需要对症排查。

搞定这些之后,Typecho + Docker 的组合非常轻量顺手:升级、迁移、备份都快,以后换机器一个 compose 文件就能复现整个环境。希望这篇实战记录对你有帮助。

最后修改:2026 年 08 月 25 日
如果觉得我的文章对你有用,请随意赞赏