HortusFox 安装部署指南

HortusFox v6.4 在 Ubuntu 24.04 裸机上的完整部署实录:MariaDB 11.4 官方源、PHP 8.3-FPM 与 nginx 接入、迁移建表、管理员账号、systemd 定时任务托管、升级路径与五条排障实录,命令输出均为实测回显。

HortusFoxPHP 编程园艺管理Ubuntu24.042026/10/28

HortusFox 安装部署指南

本文全部命令与输出均在实测环境逐条执行并取自真实回显:Ubuntu 24.04.5 LTS(noble)、HortusFox v6.4、PHP 8.3.6、MariaDB 11.4.13、nginx 1.24.0、Composer 2.10.3。示例工作区域名以服务器 IP 直连为前提,读者可替换为自己的域名。

项目定位与功能全景见 《HortusFox 介绍与选型指南》,本文负责把它真正跑起来:从一台裸的 Ubuntu 24.04 出发,完成软件源准备、MariaDB 11.4 部署、代码获取、数据库迁移、Web 服务器接入、管理员账号创建与定时任务托管,最后给出升级路径与排障实录。

一、部署路线总览

官方支持四种安装方式(见官方 README "Installation" 章节):手动安装、内置安装向导、AquaShell 脚本安装,以及随仓库附带的编排文件方式。本文主线采用手动安装,理由有三:

  1. 每一步都在自己的 systemd 服务器上,组件边界清晰,日后排障、升级、迁移都有据可查;
  2. 内置安装向导需要预先搭好 Web 环境再触发 do_install,前置工作量并不少,且过程不如手动透明;
  3. AquaShell 脚本依赖额外解释器,属于作者生态的小众路线。

整体流程:系统准备 → MariaDB 11.4 → 数据库初始化 → 拉代码装依赖 → 配置 .env → 迁移建表 → nginx 接入 → 创建管理员 → 验证登录 → 定时任务托管。

二、系统准备

2.1 基础软件包

Ubuntu 24.04 官方源自带 PHP 8.3,直接安装 nginx、PHP-FPM 与 HortusFox 所需扩展。根据 composer.json,PHP 依赖为 phpmailer、carbon、php-qrcode、tcpdf、htmlpurifier、parsedown(由 Composer 拉取,无需 apt 安装),但底层 PHP 扩展需要:

apt update
apt install -y nginx git curl composer \
    php8.3-fpm php8.3-mysql php8.3-gd php8.3-curl \
    php8.3-mbstring php8.3-xml php8.3-zip php8.3-intl

实测安装后的版本回显:

$ php -v
PHP 8.3.6 (cli) (built: Oct 19 2026 15:16:58) (NTS)

$ nginx -v
nginx version: nginx/1.24.0 (Ubuntu)

$ composer --version
Composer version 2.10.3 2026-08-27 13:34:23

2.2 安装 MariaDB 11.4 官方源

关键坑位:Ubuntu 24.04 自带的 MariaDB 是 10.11(实测 apt policy mariadb-server 显示候选版本 1:10.11.14-0ubuntu0.24.04.1),而 HortusFox 官方要求 MariaDB ^11.4,必须改用 MariaDB 官方源。按官方源页指引,实测服务器上的配置文件 /etc/apt/sources.list.d/mariadb.sources 内容为:

X-Repolib-Name: MariaDB Server
Enabled: yes
Types: deb
URIs: https://dlm.mariadb.com/repo/mariadb-server/11.4/repo/ubuntu
Suites: noble
Components: main main/debug
Architectures: amd64 arm64
Signed-By: /etc/apt/keyrings/mariadb-keyring.gpg

(密钥需先行放入 /etc/apt/keyrings/mariadb-keyring.gpg,方法见 MariaDB 官方源配置页。)随后安装:

apt install -y mariadb-server

实测版本确认:

$ mariadb --version
mariadb from 11.4.13-MariaDB, client 15.2 for debian-linux-gnu (x86_64) using  EditLine wrapper

2.3 启动并固化服务

systemctl enable --now mariadb.service php8.3-fpm.service nginx.service

实测运行状态:

$ systemctl list-units --type=service --state=running --no-pager --no-legend | grep -E "nginx|php|mariadb"
  mariadb.service          loaded active running MariaDB 11.4.13 database server
  nginx.service            loaded active running A high performance web server and a reverse proxy server
  php8.3-fpm.service       loaded active running The PHP 8.3 FastCGI Process Manager

三件套齐了:Web 服务器、FastCGI 进程管理器、数据库,全部由 systemd 托管。

三、数据库初始化

创建专用数据库与账号(示例口令请替换为自己的强口令):

CREATE DATABASE hortusfox CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'hortusfox'@'localhost' IDENTIFIED BY 'q1w2e3r4';
GRANT ALL PRIVILEGES ON hortusfox.* TO 'hortusfox'@'localhost';
FLUSH PRIVILEGES;

连接性实测:

$ mariadb -h 127.0.0.1 -u hortusfox -p hortusfox -e "SELECT VERSION();"
+---------------------------+
| VERSION()                 |
+---------------------------+
| 11.4.13-MariaDB-ubu2404   |
+---------------------------+

四、获取代码与安装依赖

cd /var/www
git clone https://github.com/danielbrendel/hortusfox-web.git hortusfox
cd hortusfox
composer install

实测环境中,仓库由官方 GitHub 地址克隆,Composer 依赖目录最终包含 20 个顶级包(asatru-php-framework、phpmailer、carbon、tcpdf 等)。若 Composer 提示缺扩展,回到 2.1 节核对对应 php8.3-* 包。

五、配置 .env

应用配置集中于项目根目录的 .env(模板为 .env.example):

cp .env.example .env

首次部署至少要核对以下键(完整参数体系见《HortusFox 6.4 配置参数详解》):

键示例值说明
APP_NAMEHortusFox应用名,用于界面标题
APP_DEBUGtrue调试开关;asatru 命令行工具要求其为 true
APP_LANGen界面语言
APP_WORKSPACEMy workspace工作区名
DB_ENABLEtrue必须为 true,否则不连数据库
DB_HOSTlocalhost数据库地址
DB_USER / DB_PASSWORDhortusfox / q1w2e3r4第三节创建的账号
DB_PORT3306端口
DB_DATABASEhortusfox库名
DB_DRIVERmysql驱动,保持不变
DB_CHARSETutf8mb4字符集
SMTP_FROMNAME / SMTP_FROMADDRESSTest / test@domain.tld发件人名与地址
SMTP_HOST / SMTP_PORT / SMTP_USERNAME / SMTP_PASSWORD / SMTP_ENCRYPTION按邮件服务商填不配则邮件功能不可用

实测环境中 .env 的数据库段为:

DB_ENABLE=true
DB_HOST=localhost
DB_USER=hortusfox
DB_PASSWORD="q1w2e3r4"
DB_PORT=3306
DB_DATABASE=hortusfox
DB_DRIVER=mysql
DB_CHARSET="utf8mb4"

六、数据库迁移与初始数据

在项目根目录执行(原因见第十二节排障实录第 1 条):

php asatru migrate:fresh      # 全量建表
php asatru plants:attributes  # 写入默认植物属性
php asatru calendar:classes   # 写入默认日历分类

实测说明:plants:attributes 与 calendar:classes 在默认项已存在时静默通过、无任何输出(退出码 0),不要把"没输出"当成"没执行"。随后插入工作区设置行:

INSERT INTO `AppModel` (id, workspace, language, timezone, created_at) VALUES
    (NULL, 'HortusFox 工作区', 'en', 'Asia/Shanghai', CURRENT_TIMESTAMP);

验证:

$ php asatru product:version
Current product version: 6.4

$ php asatru product:info
HortusFox v6.4 Debug
Developed by Daniel Brendel (daniel@danielbrendel.com)

PHP Version: 8.3.6
MySQL Version: 11.4.13-MariaDB-ubu2404
Server: Linux #38-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep  4 09:10:14 UTC 2026 x86_64
Timezone: 2026-10-28 09:15 (UTC)

GitHub URL: https://github.com/danielbrendel/hortusfox-web
Service URL: https://www.hortusfox.com

(终端原始输出带 ANSI 颜色码,上文为去色后的等价文本。)

七、nginx 站点接入

创建 /etc/nginx/sites-available/hortusfox.conf 并软链到 sites-enabled。实测环境的生产配置全文:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name 10.89.73.10;

    root /var/www/hortusfox/public;
    index index.php;

    client_max_body_size 5500M;

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

    # 防止 index.php 以外的 PHP 脚本被直接执行
    location ~* ^/(?!index\.php$).+\.php[34578]?$ {
        return 403;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_read_timeout 300;
    }

    location ~ /\.ht {
        deny all;
    }
}

要点:

  • 站点根必须是 public/ 子目录,指向仓库根会把源码暴露给 Web;
  • client_max_body_size 与 PHP post_max_size(见第八节)要成对放大,植物照片/备份归档的体积都不小;
  • 负向断言规则保证除 index.php 外的 PHP 文件一律 403;
  • PHP-FPM 默认监听 /run/php/php8.3-fpm.sock(实测 www.conf:user = www-data、listen = /run/php/php8.3-fpm.sock、pm = dynamic)。

启用并验证:

ln -s /etc/nginx/sites-available/hortusfox.conf /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx

八、PHP 参数调整

在 /etc/php/8.3/fpm/conf.d/ 下放一个覆盖文件(实测为 99-php.ini):

upload_max_filesize = 5000M
post_max_size = 5500M
memory_limit = 512M
max_execution_time = 0
max_input_time = -1

post_max_size 需大于 upload_max_filesize,且与第七节 nginx 的 client_max_body_size 保持一致量级。调整后 systemctl restart php8.3-fpm。

九、创建管理员账号

两条路线:

  1. 内置安装向导:在项目根目录创建空文件 do_install,浏览器访问 http://<服务器>/install 按向导操作,完成后删除 do_install;
  2. SQL 直插(本文实测采用):先生成口令哈希,再插入用户表:
php -r "echo password_hash('q1w2e3r4', PASSWORD_BCRYPT), PHP_EOL;"

把输出的哈希(而非明文)填入:

INSERT INTO `UserModel` (`name`, `email`, `password`, `admin`) VALUES
    ('admin', 'admin@hortusfox.local', '<上一步的哈希>', 1);

admin=1 即管理员。首次登录后建议立即在个人资料页改密,并到管理后台核对工作区设置。

十、部署验证

10.1 命令行验证

第六节的 php asatru product:version / product:info 输出正常即表明「代码 → 依赖 → .env → 数据库」链路全通。

10.2 Web 登录验证

未登录访问首页会被重定向到认证页,实测报文:

$ curl -sI http://127.0.0.1/
HTTP/1.1 302 Found
Location: /auth?redirect=%2F
Set-Cookie: PHPSESSID=...; path=/
Set-Cookie: COOKIE_LOCALE=en; ...

提交登录表单(字段为 csrf_token、email、password,token 取自 /auth 页面)后实测 302 回首页,随后首页返回 200、页面标题为 HortusFox 工作区,即部署成功。浏览器路径:访问 http://<服务器>/ → 跳转登录页 → 输入管理员邮箱与口令 → 进入工作台。

十一、定时任务托管

HortusFox 的提醒与自动备份依赖外部周期调用以下 HTTP 端点(需携带 cronpw 口令参数,口令即管理后台 AppModel 中的 cronjob_pw 字段):

端点用途官方建议频率
POST /cronjob/tasks/overdue逾期任务提醒每天多次
POST /cronjob/tasks/tomorrow明日到期提醒每天多次
POST /cronjob/tasks/recurring周期任务复位每天至少一次
POST /cronjob/calendar/reminder日历到期提醒每天多次
POST /cronjob/backup/auto工作区自动备份每天至少一次

单端点连通性实测:

$ curl -s -X POST http://127.0.0.1/cronjob/tasks/overdue --data-urlencode "cronpw=q1w2e3r4" -w '\nHTTP %{http_code}\n'
{"code":200}
HTTP 200

推荐用 systemd timer 托管(比 crontab 多了日志与依赖管理)。三个文件如下:

/usr/local/bin/hortusfox-cron.sh:

#!/bin/sh
# HortusFox scheduled tasks: call the built-in cronjob endpoints
BASE="http://127.0.0.1"
TOKEN="q1w2e3r4"
for ep in tasks/overdue tasks/tomorrow tasks/recurring calendar/reminder; do
    curl -s -X POST "$BASE/cronjob/$ep" --data-urlencode "cronpw=$TOKEN" -o /dev/null
done
curl -s -X POST "$BASE/cronjob/backup/auto" --data-urlencode "cronpw=$TOKEN" -o /dev/null

/etc/systemd/system/hortusfox-cron.service:

[Unit]
Description=HortusFox cronjob endpoints trigger
After=network.target nginx.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hortusfox-cron.sh

/etc/systemd/system/hortusfox-cron.timer:

[Unit]
Description=Run HortusFox cronjob triggers several times per day

[Timer]
OnCalendar=*-*-* 07,11,15,19,23:00:00
Persistent=true

[Install]
WantedBy=timers.target

启用与验证(实测回显):

$ chmod +x /usr/local/bin/hortusfox-cron.sh
$ systemctl daemon-reload
$ systemctl enable --now hortusfox-cron.timer
Created symlink /etc/systemd/system/timers.target.wants/hortusfox-cron.timer → /etc/systemd/system/hortusfox-cron.timer.

$ systemctl start hortusfox-cron.service
$ systemctl status hortusfox-cron.service --no-pager
○ hortusfox-cron.service - HortusFox cronjob endpoints trigger
     Loaded: loaded (/etc/systemd/system/hortusfox-cron.service; static)
     Active: inactive (dead)
   TriggeredBy: ● hortusfox-cron.timer
    Process: 20330 ExecStart=/usr/local/bin/hortusfox-cron.sh (code=exited, status=0/SUCCESS)

Oct 28 09:17:05 hortusfox-lab systemd[1]: Finished hortusfox-cron.service - HortusFox cronjob endpoints trigger.

status=0/SUCCESS 且 TriggeredBy 挂上 timer,即定时链路生效;Persistent=true 保证停机错过的时点开机补跑。

十二、排障实录

1. php asatru 报 "CLI tool is only available in debug mode",但 .env 里明明是 APP_DEBUG=true。 原因:在项目根目录之外执行了 CLI(例如 php /var/www/hortusfox/asatru)。CLI 入口用相对路径 file_exists('.env') 加载配置,工作目录不对时 .env 根本没被读到,框架 fallback 认为调试未开。结论:asatru 全部命令必须先 cd /var/www/hortusfox 再执行,脚本里则统一用 cd /var/www/hortusfox && php asatru ... 的写法兜底。

2. 迁移报数据库连接错误 / 版本特性不支持。 先跑 mariadb --version。Ubuntu 24.04 源默认装到 10.11,不满足官方要求的 ^11.4;实测服务器正是改用 MariaDB 官方源(2.2 节)装到 11.4.13 后一次通过。

3. 上传照片 413 或传输中断。 三处要成对检查:nginx client_max_body_size、PHP post_max_size、PHP upload_max_filesize。实测配置为 5500M / 5500M / 5000M(第八节),改完记得 systemctl reload nginx && systemctl restart php8.3-fpm。

4. 除首页外全部 404。 try_files 未回退到 index.php,或站点根指到了仓库根而非 public/。按第七节配置核对,nginx -t 通过后 reload。

5. 邮件不发、密码重置收不到信。 SMTP 段没配或配错。先用 SMTP_FROMADDRESS 对应的真实邮箱做收件人自测;HortusFox 的用户邀请、密码重置、逾期提醒邮件全部走 SMTP,管理后台 AppModel 中还有一套 SMTP 覆盖项(见《HortusFox 6.4 配置参数详解》)。

十三、升级路径

升级 = 换代码 + 装依赖 + 版本迁移,全程冷操作不影响库内数据:

cd /var/www/hortusfox
php asatru backup:export          # 先备份
git pull
composer install
php asatru migrate:version        # 增量更新产品版本号相关结构
php asatru cache:clear
systemctl reload nginx

备份导出、增量迁移与缓存清理的逐条实测用法见《HortusFox 6.4 常用 CLI 命令与工具详解》。跨大版本升级可用 php asatru migrate:upgrade(上一版 → 当前版)或 php asatru migrate:specific <版本>(指定版本迁移)。官方明确"应用测试仍在建设中",所以升级后务必人工回归登录、添加植物、任务提醒三项主链路,备份归档保留到回归通过为止。

十四、收尾检查清单

  • php asatru product:info 版本与 PHP/MySQL 版本正常;
  • 浏览器登录后进入工作台,标题显示工作区名;
  • POST /cronjob/backup/auto 带 cronpw 返回 {"code":200};
  • systemctl list-timers hortusfox-cron.timer 显示下次触发时间;
  • do_install 文件(如用过向导)已删除;
  • 管理员口令已修改,.env 文件权限不为全局可写。

至此部署闭环。接下来按需阅读:《HortusFox 6.4 配置参数详解》调语言/时区/邮件/外部服务,用《HortusFox 6.4 常用 CLI 命令与工具详解》做日常备份、主题与升级运维。