最近把博客用 FrankenPHP 跑起来了,记录一下配置及部署过程。 下边的 xx 路径修改为你自己的项目路径。
创建项目目录
wd 目录为 wordpress 程序目录
fhy@94nas:/vol2/1000/xx$ pwd /vol2/1000/xx fhy@94nas:/vol2/1000/xx$ ls -l total 8 -rw-rw----+ 1 fhy root 1347 Jun 12 17:04 docker-compose.yml -rw-rw----+ 1 fhy Users 916 Jun 12 16:35 Dockerfile drwxrwx--x+ 1 fhy Users 66 Jun 9 11:09 wd
docker-compose.yml 配置
我这里配置了 redis ,根据需求可自行配置。redis 密码自行修改。
services:
redis:
image: redis:8.8.0
container_name: redis-container
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD:-xxxx} --appendonly yes --appendfsync everysec
ports:
- "127.0.0.1:6379:6379" # 仅宿主机可访问,安全
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-xxx}", "ping"]
interval: 10s
timeout: 5s
retries: 3
networks:
- app-network
frankenphp:
image: dunglas/frankenphp<code> restart: always
build: . # 使用当前目录的 Dockerfile
container_name: frankenphp-container
ports:
- "80:80" # HTTP
- "80:80/udp" # HTTP/3
volumes:
- /vol2/1000/xx/wd:/app # 挂载项目代码
working_dir: /app
command: ["frankenphp", "run", "--config", "/app/Caddyfile"]
environment:
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-xxx}
depends_on:
redis:
condition: service_healthy # 等待 Redis 健康后再启动 FrankenPHP
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
redis-data:fhy@94nas:/vol2/1000/xx
Dockerfile
FROM dunglas/frankenphp
# 安装系统依赖(包括 ImageMagick 开发库)
RUN apt-get update && apt-get install -y \
libfreetype-dev libjpeg62-turbo-dev libpng-dev libwebp-dev libxpm-dev \
libicu-dev libpq-dev libzip-dev libbz2-dev libonig-dev \
libmagickwand-dev \
git && rm -rf /var/lib/apt/lists/*
# 安装其他 PHP 扩展
RUN install-php-extensions \
bz2 \
curl \
exif \
fileinfo \
gd \
intl \
mbstring \
mysqli \
odbc \
openssl \
pdo_mysql \
pdo_odbc \
pgsql \
zip \
redis \
imagick
# (可选)复制自定义 php.ini 覆盖默认配置
# COPY ./php.ini /usr/local/etc/php/php.ini
Caddyfile
{
frankenphp {
num_threads 8
}
auto_https off
}
:80 {
bind 0.0.0.0
root * /app/index
encode zstd br gzip
tls /app/ssl/aiti.crt /app/ssl/aiti.key {
protocols tls1.2 tls1.3
}
# =========================
# LOG(修正:移除非法 time_local)
# =========================
log {
output file /app/log/access.log {
roll_size 100mb
roll_keep 10
roll_keep_for 720h
}
format json
level INFO
}
# =========================
# 隐藏敏感文件
# =========================
@hidden {
path /.git* /.svn* /.env /.user.ini /.htaccess /LICENSE /README.md
}
respond @hidden 404
# =========================
# 安全 Header(修复 IP 伪造问题)
# =========================
header {
-Server
-X-Powered-By
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
Alt-Svc "h3=\":25521\"; ma=2592000"
}
# =========================
# 静态资源缓存
# =========================
@static {
path *.css *.js *.jpg *.jpeg *.png *.gif *.webp *.svg *.ico *.woff *.woff2 *.ttf *.eot
}
header @static Cache-Control "public, max-age=31536000, immutable"
# =========================
# PHP
# =========================
php_server
# =========================
# 错误处理
# =========================
handle_errors {
respond "{err.status_code} {err.status_text}"
}