在 Alpine Linux 上从零搭一个 Typecho:nginx + php-fpm + SQLite 的完整清单

在 Alpine Linux 上从零搭一个 Typecho:nginx + php-fpm + SQLite 的完整清单

234
234
2026-10-04 / 0 评论 / 17 阅读 / 4984 字 / 正在检测是否收录...
这篇是服务器搭建笔记,和 DNS 无关。站内的加密 DNS 服务在dns.23-4.cn。

Alpine 做 Web 服务器有几个很实际的好处:镜像小、内存占用低、包管理干净。但它的目录结构、服务管理和多数人熟悉的 Debian 系不一样,第一次搭容易在几个固定位置上卡住。

这篇是把一个 Typecho 博客在 Alpine 上跑起来的完整清单,按顺序执行即可,重点标出容易踩的坑。

一、装包

apk update
apk add nginx \
        php84 php84-fpm php84-session php84-json \
        php84-pdo_sqlite php84-mbstring php84-openssl \
        php84-curl php84-dom php84-fileinfo php84-iconv \
        sqlite

注意几点:

  • Alpine 的 PHP 包按大版本命名(php84),不是 php。装之前先 apk search php84 确认版本号,Alpine 升级后包名会变;
  • php84-pdo_sqlite 必须显式安装。Typecho 用 SQLite 时依赖它,缺了会在安装页报「无法连接数据库」,而错误信息不会告诉你缺的是哪个扩展;
  • php84-session 也是必需的,Typecho 的登录和 CSRF 依赖它。

二、服务管理是 OpenRC,不是 systemd

这是 Debian 用户最容易懵的地方:

rc-update add nginx default      # 开机自启
rc-update add php-fpm84 default
rc-service nginx start
rc-service php-fpm84 start
rc-service nginx status
  • 没有 systemctl,对应的是 rc-service / rc-update;
  • 日志不在 journalctl 里,而是各自的日志文件(nginx 在 /var/log/nginx/,PHP 在 /var/log/php84/error.log);
  • 服务的 init 脚本在 /etc/init.d/。

三、PHP-FPM 监听

确认 /etc/php84/php-fpm.d/www.conf 里的监听方式:

listen = 127.0.0.1:9000
; 或者用 unix socket,性能略好
; listen = /run/php-fpm84/php-fpm.sock

用 TCP 更省事,不用处理 socket 的属主和权限。用 socket 的话记得让 nginx 用户能读写。

四、nginx 站点配置

server {
    listen 80;
    server_name example.com;
    root /var/www/typecho;
    index index.php index.html;
    client_max_body_size 20m;

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

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
        expires 7d;
        add_header Cache-Control "public";
        try_files $uri =404;
    }

    location ~ .*\.php(\/.*)*$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_read_timeout 60s;
    }
}

这里有三个必须理解的点

1. try_files ... /index.php$uri?$query_string —— 这是伪静态的关键。
Typecho 的「重写」打开后,链接是 /archives/1/、/category/xxx/ 这种没有 .php 的形式。这些路径在磁盘上不存在,必须交给 index.php 处理。写成 /index.php?$query_string 会丢掉路径信息,结果是所有伪静态链接都变成首页或 404。

2. fastcgi_split_path_info + PATH_INFO —— 少了它,Typecho 认不出路由。
请求 /index.php/archives/1/ 时,PHP 需要知道 .php 后面那一段是「路径信息」。没有这两行,Typecho 拿不到 /archives/1/,就会走 404 分支。这个坑的症状是:首页正常,但所有文章页、分类页、标签页全部 404。

3. location ~* \.(js|css|...)$ 这个正则块要放在 location / 后面、php 块前面。
nginx 的匹配规则是「正则优先于前缀,正则之间按书写顺序」。顺序写错会让静态资源的 try_files 覆盖掉别的规则,或者反过来让 .php 请求走了静态分支——后者会把 PHP 源码当文本吐出来,非常危险。配完一定要测:

# 如果这条命令返回了 PHP 源码,说明 php 块没匹配上
curl -s http://example.com/index.php | head -3

五、装 Typecho 与 config.inc.php

下载解压到 /var/www/typecho,然后走网页安装。SQLite 的配置在 config.inc.php 里长这样:

$db = new \Typecho\Db('Pdo_SQLite', 'typecho_');
$db->addServer(array(
  'file' => '/var/lib/typecho/typecho.db',
), \Typecho\Db::READ | \Typecho\Db::WRITE);
\Typecho\Db::set($db);

把数据库文件放在 Web 根目录之外(上面放在 /var/lib/typecho/)。放在根目录里的后果是:如果哪天 nginx 配置被人改错、或者多了一个不严谨的 location,.db 文件可能被直接下载——里面是所有用户的密码哈希。

六、权限

# Web 根目录给 web 用户,不要给 root
chown -R nobody:nobody /var/www/typecho
# 数据库目录只给 web 用户
chown -R nobody:nobody /var/lib/typecho
chmod 750 /var/lib/typecho
chmod 640 /var/lib/typecho/typecho.db

Alpine 上 nginx 的 worker 默认跑在 nginx 用户、PHP-FPM 的 pool 默认是 nobody。要让写文件的进程(PHP-FPM)对目录有写权限,否则上传附件、写 session、更新配置都会失败。查当前是谁在跑:

ps aux | grep -E "nginx|php-fpm" | grep -v grep

七、上 HTTPS

apk add certbot
certbot certonly --webroot -w /var/www/acme -d example.com -d www.example.com

在 nginx 里加一个 location /.well-known/acme-challenge/ { root /var/www/acme; },然后 80 端口 301 到 443。

续期一定要验证能跑通,别等三个月后证书过期才发现:

certbot renew --dry-run

八、上线前检查清单

# 1. 伪静态是否生效(文章页应该 200,不是 404)
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/archives/1/

# 2. 分类 / 标签页
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/category/default/

# 3. feed
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/feed/

# 4. PHP 没有被当源码吐出
curl -s https://example.com/index.php | head -1

# 5. 数据库文件不可下载(应该是 403 或 404)
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/typecho.db

# 6. 根分区还剩多少
df -h /

第 5 条尤其要做。小服务器上数据库就几十到几百 KB,很容易被随手放在根目录里。

九、最容易踩的五个坑

症状原因
首页正常,其他页面全 404缺 PATH_INFO / fastcgi_split_path_info
所有伪静态链接跳到首页try_files 写成了 /index.php?$query_string,丢了 $uri
装 Typecho 时报连不上数据库没装 php84-pdo_sqlite
上传附件 / 登录失败PHP-FPM 的运行用户对目录没有写权限
浏览器直接下载到了 .db 文件数据库放在 Web 根目录里,且没有 deny 规则

相关阅读

0个赞
取消