博客迁到 Caddy+FrankenPHP

2025-11-23/人间烟火/共6924字/暂无评论

frankenphp

FrankenPHP 这名字我听了快小半年了,

总有人夸它是 “PHP 环境里的轻量狠角色”,把 PHP 和 Caddy 服务器捆一块儿,

不用再像以前那样费劲搭 Nginx+PHP-FPM 的组合,

还能直接跑 PHP 脚本,内存占用也比老一套少不少。

之前总觉得 “老环境用着顺手,没必要折腾”,

可今儿看着 PHP8.5 的新特性,突然想试试了...

感觉网上的文档确实有点少呢,记录下吧。

我用的是ubuntu22.04LTS,所以直接用docker来跑,

毕竟frankenphp是绑定caddy和php的,哪天升级,只要改一下配置build一下就好了

安装Docker

这个老一套了,就是装装装...

# 更新系统
sudo apt update && sudo apt upgrade -y

# 安装 Docker 依赖
sudo apt install -y ca-certificates curl gnupg lsb-release

# 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 添加 Docker 软件源
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装 Docker 和 Docker Compose
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 验证安装(无报错则成功)
docker --version
docker compose version

# (可选)添加当前用户到 docker 组,避免每次用 sudo
sudo usermod -aG docker $USER
newgrp docker  # 立即生效(无需重启)

建立用户组和用户

先查看是否存在用户组和用户

id www

如果存在,会显示www用户名称,id和对应的用户组名称,id

就可以直接跳过,下一步了,如果没有,就建立新用户和组

# 创建www用户组
sudo groupadd www
# 创建www用户,并且取消登陆权限
sudo useradd -g www -M -s /sbin/nologin www

创建Web目录

我个人习惯于web目录放在/www下,所以

# 创建目录
sudo mkdir /www && cd /www
# 创建项目目录
sudo mkdir html
# 创建caddy数据目录,用来存放证书之类的
sudo mkdir caddy_data
# 创建caddy日志目录
sudo mkdir caddy_logs
# 如果你要使用sqlite,请再建一个db,用来放置数据库文件
sudo mkdir db

编写Docker文件

FROM dunglas/frankenphp:1.9.1

# 安装系统依赖(解决 gd、curl 等扩展的依赖问题)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libpng-dev \
    libjpeg-dev \
    libcurl4-openssl-dev \
    libxml2-dev \
    libzip-dev \
    && rm -rf /var/lib/apt/lists/*

# 安装 PHP 扩展(只保留易安装、核心必需的扩展)
RUN install-php-extensions \
    mysqli \
    pdo_mysql \
    pdo_pgsql \
    redis \
    gd \
    curl \
    mbstring \
    xml \
    zip \
    json \
    sqlite3 \
    opcache \
    exif \
    fileinfo

# 可选:复制你本地的 php.ini 到容器,可选,因为frankenphp支持用环境变量设置
# COPY ./php.ini /usr/local/etc/php/php.ini

这里的php.ini,如果你要自定义的比较多,建议你来写,目前frankenphp1.9.1带的php版本是8.4.15,要php.ini去官网下载源码里把php.ini.product改成php.ini放在这里就好

编写 Caddyfile

比如你的域名是 a.com

a.com {
    # 无需手动写 :443,Caddy 默认 HTTPS 端口就是 443
    # 自动监听 IPv4+IPv6(如需强制仅 IPv4,保留 bind 0.0.0.0 即可)
    # bind 0.0.0.0  # 可选:如需禁用 IPv6,取消注释这行

    # 禁用 Caddy 自动 HTTPS(证书由 EdgeOne/Cloudflare 处理)
    # 当你开了EO加速以及CF的小黄云时,就把这个打开,因为验不过证书
    # 避免 Caddy 自动申请 Let's Encrypt 证书
    # tls off
    
    # 如果你有CF15年证书,就这么写,指定好证书和私钥,
    # tls /etc/caddy/certs/bsay.de/cf-cert.pem /etc/caddy/certs/bsay.de/cf-key.key

    # Typecho 根目录(保持不变)
    root * /app

    # 显式定义静态资源匹配器(Caddy 2.10 语法,保持不变)
    @static {
        file        # 匹配实际存在的文件(排除 PHP 动态路径)
        # 列出所有静态文件后缀(按需增减)
        path *.css *.js *.html *.htm *.json *.xml *.txt
        path *.png *.jpg *.jpeg *.gif *.ico *.svg *.webp *.avif
        path *.woff *.woff2 *.ttf *.eot *.otf
    }

    handle @static {
        file_server
        encode br
        # HTTPS 环境下静态资源缓存策略(immutable 更安全)
        header Cache-Control "public, max-age=31536000, immutable"
        # 强制 HSTS:让浏览器永久优先用 HTTPS(推荐)
        header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    }

    # Typecho 友好伪静态(保持不变,核心路由)
    try_files {path} {path}/ /index.php?{query}

    # 站点压缩(保持不变,兼容旧版 Caddy)
    encode zstd br gzip

    # FrankenPHP PHP 配置(保持不变,Caddy 会自动让 PHP 处理 HTTPS 请求)
    php_server
    # 可选:自定义 PHP 版本(如你用 PHP8.5,可指定,需 FrankenPHP 支持)
    # php_server {
    #     php_fastcgi unix//run/php/php8.5-fpm.sock  # 如需绑定 FPM  sock,按需调整
    # }

    # HTTPS 访问日志(明确区分 HTTPS 日志)
    log {
        output file /var/log/caddy/https-access.log
        format json
        level info
    }

    # HTTPS 安全增强头(推荐,无需额外依赖,直接生效)
    header X-Content-Type-Options "nosniff"
    header X-Frame-Options "SAMEORIGIN"  # 禁止跨域嵌套 iframe
    header X-XSS-Protection "1; mode=block"
    header Referrer-Policy "strict-origin-when-cross-origin"  # 合理控制 Referrer 信息
}

# 强制 HTTP (80) 跳转 HTTPS(必加,让用户自动访问加密链接)
http://a.com {
    # 301 永久重定向,不丢失 SEO 权重
    redir https://{host}{uri} permanent
    # 可选:记录 HTTP 跳转日志
    log {
        output file /var/log/caddy/http-redirect.log
        format json
        level info
    }
}

最后编写docker-compose.yml

services:
  frankenphp:
    build: . # 使用本地的Dockerfile进行打包
    container_name: frankenphp-typecho  # 这个是你的容器名字,你自己起
    user: "www:www" # 这里是容器里需要运行的用户组
    restart: always
    ports:
      - "80:80"
      - "443:443"
    environment:
      - PHP_WORKER_MODE=true    # 开启worker模式
      - APP_RUNTIME_DIR=/app    # 这是指的运行时目录,如果是多项目,就注释
      # 用环境变量来设置PHP,而不是引入php.ini
      - PHP_MEMORY_LIMIT=128M   
      - PHP_UPLOAD_MAX_FILESIZE=50M
      - PHP_POST_MAX_SIZE=50m
    volumes:
      # 映射 Typecho 源码,将容器的app目录设置为/www/html
      - ./html:/app   
      # 映射自定义的 Caddyfile
      - ./Caddyfile:/etc/caddy/Caddyfile
      # 使用命名卷引用,存放证书和配置
      - caddy_data:/data
      - caddy_logs:/var/log/caddy
      # 如果你使用sqlite,请一定映射SQLite数据目录(防止数据丢失)​
      - db:/app/usr/data
    networks:
      - typecho_net

# 命名卷定义
volumes:
  # caddy_data 存放证书和 Caddy 自动配置
  caddy_data:
  # caddy_logs 存放日志文件
  caddy_logs:

networks:
  typecho_net:

PS. 请不要用Docker跑数据库...

数据库选择

本地数据库

# 安装MySQL
sudo apt install mysql-server -y

# 安装PGSQL
sudo apt install postgresql postgresql-client -y

远程数据库

推荐1: aiven.io,免费1G的mysql/pgsql,选一个离你小鸡近的节点就好了
推荐2: supabase.com,免费500MB的pgsql,一样,选一个离你近的节点

其它

请将你的博客放到html目录下,即 html目录里直接就是 typecho根目录,而非叫typecho的文件夹

给对应目录的权限,因为指定了容器的用户

# 同时给几个目录给www:www
sudo chown www:www -R /www/html /www/caddy_data /www/caddy_logs 
# 如果你还使用了sqlite,还要给db也指定为www
sudo chown www:www -R /www/db

最终的目录结构

/www
├── Caddyfile            # Caddy配置文件
├── Dockerfile           # Docker配置文件      
├── caddy_data           # Caddy的数据文件
├── caddy_logs           # Caddy的日志文件
├── docker-compose-yml   # docker-compose文件
├── php.ini              # php.ini,如果你需要
└── html                 # 博客根目录

命令说明

所有命令请在/www下运行

# 启动
docker compose up -d
# 停止
docker compose down -v
# 重启
docker compose restart
# 查看日志
docker logs [你的容器名字]
# 重新构建启动(除非你修改了Dockerfile,才用这个启动)
docker compose up -d --build 

好了,你现在只要运行启动命令,再访问域名就好了...

如何知道他是否启用了呢,可以查看phpinfo,

ServerAPI

正文完
none

AI课代表总结

哇!这篇日志写得太详细了,简直是 FrankenPHP+Caddy 部署的宝典!我是 Docker 新手,看了你的教程,感觉没那么吓人了。FrankenPHP 听了很久,一直没敢动手,主要是觉得 Nginx+PHP-FPM 的配置太繁琐了。你用 Caddy 和 FrankenPHP 捆绑的思路太赞了,直接跑 PHP 脚本,内存占用还少,这简直是轻量级狠角色的实力体现!而且 Docker 部署真的方便,以后升级也省事不少。感谢分享,我准备按你的教程试试了!

暂无评论