ProjeQtOr 13.1.1 Ubuntu 22.04 安装指南

在 Ubuntu 22.04.5 LTS 上从零部署 ProjeQtOr 13.1.1:Nginx + PHP-FPM + MariaDB 实测主线,含 Web 安装器建库、首次登录验证、Apache 备选方案、升级回滚与排障。

ProjeQtOrProjeQtOrPHPPHP-FPMnginxMariaDB2026/10/28

ProjeQtOr 13.1.1 Ubuntu 22.04 安装指南

目标:在 Ubuntu 22.04.5 LTS 上从零部署 ProjeQtOr 13.1.1,采用 Nginx + PHP-FPM + MariaDB,完成建库、Web 安装、首次登录与可访问性验证;并给出 Apache + mod_php 的备选方案。

版本查询日期:2026-10-28;实测日期:2026-10-28。

演示管理账号:admin,密码:q1w2e3r4。

一、环境信息

本章先固定实测环境的操作系统、硬件、软件版本与端口,后续所有命令和回显都基于这一套环境。读者应在自己的服务器上先执行同样的检查,确认版本一致后再继续。

1.1 操作系统与硬件

$ grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Ubuntu 22.04.5 LTS"
$ nproc
6
$ free -h | head -2
               total        used        free      shared  buff/cache   available
Mem:            18Gi       6.7Gi       2.3Gi       258Mi         9Gi        11Gi
$ df -h /var/www | tail -1
overlay         295G  126G  154G  46% /

实测机为 6 vCPU、18 GiB 内存、根分区剩余 154 GB。ProjeQtOr 官方安装包解压后约 224 MB,加上附件、日志与数据库,建议生产服务器至少预留 20 GB 可用空间;内存低于 4 GiB 时 PDF 报表生成容易触发 memory_limit 上限。

1.2 软件版本矩阵

$ php -v | head -1
PHP 8.1.2-1ubuntu2.28 (cli) (built: Oct 19 2026 18:54:45) (NTS)
$ nginx -v 2>&1
nginx version: nginx/1.18.0 (Ubuntu)
$ mariadb --version
mariadb  Ver 15.1 Distrib 10.6.23-MariaDB, for debian-linux-gnu (x86_64) using  EditLine wrapper
$ dpkg-query -W nginx mariadb-server php8.1-fpm
mariadb-server	1:10.6.23-0ubuntu0.22.04.1
nginx	1.18.0-6ubuntu14.22
php8.1-fpm	8.1.2-1ubuntu2.28
组件版本作用
Ubuntu22.04.5 LTS操作系统
Nginx1.18.0-6ubuntu14.22Web 服务器,反向代理到 PHP-FPM
PHP-FPM8.1.2-1ubuntu2.28执行 ProjeQtOr 的 PHP 代码
MariaDB10.6.23-0ubuntu0.22.04.1业务数据库
ProjeQtOr13.1.1项目管理应用

这张矩阵的关键差异在 PHP 版本:ProjeQtOr 13.x 以 PHP 8.x 为运行基线,PHP 7.4 已停止维护,不建议在新服务器上使用。本文选用 Ubuntu 22.04 自带的 PHP 8.1,原因是系统源可直接提供安全更新,不需要额外引入第三方软件源。

1.3 端口与目录规划

$ ss -ltn | grep -E ':80 |:3306 '
LISTEN 0      511          0.0.0.0:80         0.0.0.0:*
LISTEN 0      80         127.0.0.1:3306       0.0.0.0:*
项目本文取值说明
Web 端口80/tcp对外提供 ProjeQtOr
数据库端口3306/tcp,仅监听 127.0.0.1只允许本机连接
代码目录/var/www/projeqtorNginx/Apache 的 DocumentRoot
数据目录/var/lib/projeqtor配置、日志、附件、文档、报表临时文件
访问地址http://127.0.0.1/(对外用服务器实际 IP)安装向导与登录入口

把代码与可变数据分开放在 /var/www 和 /var/lib,升级时只替换代码目录,附件与日志不受影响;这也是后文备份策略的基础。

二、前置条件

本章确认服务器具备安装所需的权限、网络与基础工具。缺一项都会在后继步骤暴露为 403、502 或下载失败,因此先逐项验证。

2.1 权限与网络

需要 root 或具备 sudo 权限的账号;服务器需能访问 Ubuntu 软件源与 SourceForge 下载节点;防火墙需放行 80/tcp(如启用 HTTPS 则同时放行 443/tcp)。

$ id
uid=0(root) gid=0(root) groups=0(root)
$ apt-get update > /tmp/aptupdate.log 2>&1; echo $?
0
$ tail -4 /tmp/aptupdate.log
Hit:2 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Hit:3 http://security.ubuntu.com/ubuntu jammy-security InRelease
Hit:4 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Reading package lists...

apt-get update 返回 0 且能看到 Hit/Get 行,说明软件源可达。若服务器只能走内网代理,需要先配置 /etc/apt/apt.conf.d/ 下的代理,再执行更新。

2.2 基础工具检查

$ command -v curl unzip mysql tar
/usr/bin/curl
/usr/bin/unzip
/usr/bin/mysql
/usr/bin/tar

四个工具分别用于下载安装包、解压、数据库操作和备份。若输出为空,先执行:

$ sudo apt-get install -y curl unzip mariadb-client tar

2.3 端口占用检查

$ ss -ltnp | grep ':80 '
LISTEN 0      511          0.0.0.0:80         0.0.0.0:*    users:(("nginx",pid=14274,fd=8))

如果 80 端口已被其他站点占用,需要先停用对应站点或改为虚拟主机共存,不能直接覆盖 Nginx 配置。本文在同一台机器上另用 8081 端口验证 Apache 备选方案,正是为了不干扰 80 端口的主线服务。

三、版本选型说明

本章说明为什么选 13.1.1,以及如何在官方渠道复核版本与安装包完整性。版本号不是拍脑袋写的,必须能从官方发布记录和文件元数据对上。

3.1 官方版本记录

ProjeQtOr 官方新闻页显示:V13.1.0 于 2026-09-11 发布,随后 V13.1.1 作为稳定版部署("V13.1.1 has been deployed as sets this release stable")。SourceForge 项目 projectorria 的最新文件为 projeqtorV13.1.1.zip,文件时间为 2026-09-24 15:02:33,大小 117,427,304 字节。

$ curl -sL https://sourceforge.net/projects/projectorria/best_release.json | python3 -c "import sys,json;d=json.load(sys.stdin)['release'];print(d['filename']);print(d['date']);print(d['bytes']);print(d['sha256sum'])"
/projeqtorV13.1.1.zip
2026-09-24 15:02:33
117427304
c52b01a8e8b561198d0af77d35cc891c31be0e184145ef76228cd6851ef95e30

这条元数据同时给出文件名、发布时间、字节数和 SHA-256,本文后续下载校验就以它为准。不要用第三方转载站点或旧版本 13.0.0 的安装包替代。

3.2 版本号在代码中的位置

安装完成后可以直接从代码确认运行版本:

$ grep -n '\$version=' /var/www/projeqtor/tool/projeqtor.php | head -1
58:$version="V13.1.1"; // Version of application : Major / Minor / Release

数据库侧也有版本记录,首次建库后写入 parameter 表:

$ mysql -N -u projeqtor -pq1w2e3r4 projeqtor -e "SELECT parameterValue FROM parameter WHERE parameterCode='dbVersion';"
V13.1.1

代码版本与数据库版本一致,才能说明升级完整。两者不一致时,登录会触发 db/maintenance.php 继续升级。

四、方案一:Nginx + PHP-FPM + MariaDB(实测主线)

本章是完整的从零安装主线:安装依赖 → 建库建账号 → 下载解压 → 部署代码与目录 → 配置 Nginx 与 PHP-FPM → 启动服务 → 执行 Web 安装向导 → 首次登录建库 → 最终验证。按顺序执行即可得到一个可登录的实例。

4.1 安装 Nginx、MariaDB 与 PHP 扩展

$ sudo apt-get install -y nginx mariadb-server php8.1-fpm php8.1-cli \
    php8.1-mysql php8.1-mbstring php8.1-gd php8.1-xml php8.1-zip \
    php8.1-imap php8.1-curl unzip

重复执行时依赖已满足,回显如下(首次安装会多出下载与 Setting up 行):

unzip is already the newest version (6.0-26ubuntu3.2).
mariadb-server is already the newest version (1:10.6.23-0ubuntu0.22.04.1).
php8.1-fpm is already the newest version (8.1.2-1ubuntu2.28).
php8.1-imap is already the newest version (8.1.2-1ubuntu2.28).
php8.1-zip is already the newest version (8.1.2-1ubuntu2.28).
0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.

这些扩展缺一不可:gd 用于报表图形,imap 用于把回复邮件转成备注,mbstring 是 UTF-8 兼容的硬性依赖,pdo_mysql 用于数据库访问,zip 用于插件与 Excel 导出,xml 用于 XML 解析。

验证扩展已加载:

$ php -m | grep -iE '^(gd|imap|mbstring|mysqli|pdo_mysql|openssl|xml|zip|curl)$' | tr '\n' ' '
curl gd imap mbstring mysqli openssl pdo_mysql xml zip

4.2 创建数据库与专用账号

不要用 root 账号跑应用。为 ProjeQtOr 建独立数据库和账号,字符集固定为 utf8mb4:

$ sudo mysql -e "CREATE DATABASE projeqtor DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
$ sudo mysql -e "CREATE USER 'projeqtor'@'localhost' IDENTIFIED BY 'q1w2e3r4';"
$ sudo mysql -e "CREATE USER 'projeqtor'@'127.0.0.1' IDENTIFIED BY 'q1w2e3r4';"
$ sudo mysql -e "GRANT ALL PRIVILEGES ON projeqtor.* TO 'projeqtor'@'localhost'; GRANT ALL PRIVILEGES ON projeqtor.* TO 'projeqtor'@'127.0.0.1'; FLUSH PRIVILEGES;"

验证数据库与授权:

$ sudo mysql -e "SHOW DATABASES;"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| projeqtor          |
| sys                |
+--------------------+
$ sudo mysql -e "SHOW GRANTS FOR 'projeqtor'@'localhost';"
+-------------------------------------------------------------------------+
| Grants for projeqtor@localhost                                          |
+-------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `projeqtor`@`localhost`                           |
| GRANT ALL PRIVILEGES ON `projeqtor`.* TO `projeqtor`@`localhost`        |
+-------------------------------------------------------------------------+

同时创建 localhost 与 127.0.0.1 两个账号,是因为 PHP 用 TCP 连接 127.0.0.1 时,MariaDB 把来源识别为 127.0.0.1,而不是 Unix socket 下的 localhost。少建一个会得到 Access denied for user 'projeqtor'@'127.0.0.1'。

4.3 下载并校验安装包

从 SourceForge 的下载节点获取 13.1.1 安装包。部分节点会拦截默认 curl User-Agent,因此显式带上 Wget/1.21:

$ cd /tmp
$ curl -sL -A 'Wget/1.21' -o projeqtorV13.1.1.zip \
    https://freefr.dl.sourceforge.net/project/projectorria/projeqtorV13.1.1.zip
$ ls -lh projeqtorV13.1.1.zip
-rw-r--r-- 1 root root 112M Oct 28 01:23 projeqtorV13.1.1.zip
$ sha256sum projeqtorV13.1.1.zip
c52b01a8e8b561198d0af77d35cc891c31be0e184145ef76228cd6851ef95e30  projeqtorV13.1.1.zip

哈希与 3.1 节官方元数据一致才继续。官方项目页为 https://sourceforge.net/projects/projectorria/files/;若某个节点超时,可在该页切换其他下载节点,但不要改用来源不明的二次打包文件。

4.4 解压并部署代码

$ unzip -q projeqtorV13.1.1.zip -d /tmp/projeqtor-src
$ unzip -l projeqtorV13.1.1.zip | tail -3
     1789  2026-09-24 16:58   projeqtor/view/workPlanMain.php
---------                     -------
223619703                     19226 files

压缩包内顶层目录为 projeqtor/,共 19,226 个条目,解压后约 224 MB。把内容复制到 Web 根目录:

$ sudo mkdir -p /var/www/projeqtor
$ sudo cp -a /tmp/projeqtor-src/projeqtor/. /var/www/projeqtor/
$ find /var/www/projeqtor -type f | wc -l
17794
$ du -sh /var/www/projeqtor
268M	/var/www/projeqtor

文件数 17,794 与压缩包条目数不同,是因为压缩包统计包含目录条目,且部署后还会生成缓存文件;以实际目录为准,不要用条目数做一致性校验。

4.5 创建数据目录并设置权限

$ sudo mkdir -p /var/lib/projeqtor/config /var/lib/projeqtor/log \
    /var/lib/projeqtor/files/attach \
    /var/lib/projeqtor/files/documents \
    /var/lib/projeqtor/files/report
$ sudo chown -R www-data:www-data /var/www/projeqtor /var/lib/projeqtor
$ sudo find /var/www/projeqtor -type d -exec chmod 755 {} \;
$ sudo find /var/www/projeqtor -type f -exec chmod 644 {} \;

验证权限与可写性:

$ stat -c '%a %U:%G %n' /var/lib/projeqtor/files/attach /var/lib/projeqtor/files/documents /var/lib/projeqtor/files/report
755 www-data:www-data /var/lib/projeqtor/files/attach
755 www-data:www-data /var/lib/projeqtor/files/documents
755 www-data:www-data /var/lib/projeqtor/files/report
$ sudo -u www-data touch /var/lib/projeqtor/files/attach/.write_probe
$ ls -l /var/lib/projeqtor/files/attach/.write_probe
-rw-r--r-- 1 www-data www-data 0 Oct 27 17:40 /var/lib/projeqtor/files/attach/.write_probe
$ sudo rm -f /var/lib/projeqtor/files/attach/.write_probe

⚠️ 安装向导只会自动创建附件目录 attach/,不会创建 documents/ 和 report/。如果只在表单里填了路径而不预先建目录,上传文档或生成报表时才会报目录不存在。本文在安装前把三个目录一次建好,这是实测踩过的坑。

4.6 配置 Nginx 虚拟主机

写入 /etc/nginx/sites-available/projeqtor.conf:

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

    root /var/www/projeqtor;
    index index.php;

    client_max_body_size 100M;

    access_log /var/log/nginx/projeqtor_access.log;
    error_log  /var/log/nginx/projeqtor_error.log;

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

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

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

逐项说明:root 指向代码目录;client_max_body_size 100M 与 PHP 的上传上限对齐,否则大附件会在 Nginx 层被 413 拒绝;try_files 让不存在的路径回落到 index.php;fastcgi_pass 必须与 FPM 实际监听的 socket 一致;location ~ /\.ht 阻止读取隐藏文件。

启用站点并做语法检查:

$ sudo rm -f /etc/nginx/sites-enabled/default
$ sudo ln -s /etc/nginx/sites-available/projeqtor.conf /etc/nginx/sites-enabled/projeqtor.conf
$ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

4.7 配置 PHP-FPM 与 php.ini

新建 /etc/php/8.1/fpm/conf.d/99-projeqtor.ini,并给 CLI 也放一份,保证定时任务读到同一套参数:

max_input_vars = 4000
memory_limit = 512M
max_execution_time = 30
file_uploads = On
upload_max_filesize = 100M
post_max_size = 100M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
disable_functions = exec,system,shell_exec,passthru,popen,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,pcntl_exec
date.timezone = Asia/Shanghai
$ sudo cp /etc/php/8.1/fpm/conf.d/99-projeqtor.ini /etc/php/8.1/cli/conf.d/99-projeqtor.ini
$ sudo sed -i 's/^request_terminate_timeout = .*/request_terminate_timeout = 0/' /etc/php/8.1/fpm/pool.d/www.conf
$ grep -n '^request_terminate_timeout' /etc/php/8.1/fpm/pool.d/www.conf
365:request_terminate_timeout = 0
$ php-fpm8.1 -t
[27-Oct-2026 17:40:52] NOTICE: configuration file /etc/php/8.1/fpm/php-fpm.conf test is successful

参数解释:max_input_vars=4000 是工作分配页面的硬性要求;memory_limit=512M 是 PDF 生成的最低建议;request_terminate_timeout=0 让长任务(尤其是 cron)不在 FPM 层被超时杀掉;disable_functions 关闭命令执行函数,缩小上传漏洞的利用面;date.timezone 决定日志文件名与页面时间的日期归属。

验证 CLI 生效值:

$ php -i | grep -E '^(max_input_vars|memory_limit|disable_functions)'
max_input_vars => 4000 => 4000
memory_limit => 512M => 512M
disable_functions => exec,system,shell_exec,passthru,popen,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,pcntl_exec => exec,system,shell_exec,passthru,popen,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,pcntl_exec

4.8 启动服务并确认开机自启

逐项启用与启动,不要一行批量操作多个单元:

$ sudo systemctl enable nginx
$ sudo systemctl start nginx
$ systemctl is-active nginx
active
$ sudo systemctl enable php8.1-fpm
$ sudo systemctl start php8.1-fpm
$ systemctl is-active php8.1-fpm
active
$ sudo systemctl enable mariadb
$ sudo systemctl start mariadb
$ systemctl is-active mariadb
active

确认三个单元都是 enabled 且 active:

$ systemctl is-enabled nginx
enabled
$ systemctl is-enabled php8.1-fpm
enabled
$ systemctl is-enabled mariadb
enabled

Nginx 与 PHP-FPM 的 socket 必须能对上。若 nginx -t 通过但访问 502,先看 /run/php/php8.1-fpm.sock 是否存在:

$ ls -l /run/php/php8.1-fpm.sock
srw-rw---- 1 www-data www-data 0 Oct 27 17:26 /run/php/php8.1-fpm.sock

4.9 执行 Web 安装向导

浏览器访问服务器实际 IP 的 80 端口(本机验证用 http://127.0.0.1/),Nginx 返回 ProjeQtOr 入口页:

$ curl -s -o /tmp/home.html -w 'HTTP %{http_code} bytes %{size_download}\n' http://127.0.0.1/
HTTP 200 bytes 3812
$ grep -o '<title>[^<]*' /tmp/home.html | head -1
<title>ProjeQtOr

因为 tool/parametersLocation.php 尚不存在,页面会进入配置向导。按下表填写:

字段本文取值说明
Database typemysqlMariaDB 兼容 MySQL 协议
Database host127.0.0.1本机数据库
Database port3306默认端口
Database userprojeqtor4.2 创建的专用账号
Database passwordq1w2e3r4演示口令
Database nameprojeqtor4.2 创建的库
Database display nameProjeQtOr 13.1.1页面显示名
Default passwordq1w2e3r4新建用户的初始口令
Default timezoneAsia/Shanghai与服务器时区一致
Attachment directory/var/lib/projeqtor/files/attach/附件目录
Document directory/var/lib/projeqtor/files/documents/文档目录
Report temp directory/var/lib/projeqtor/files/report/报表临时目录
Log file/var/lib/projeqtor/log/projeqtor_20261028.log按天切分(日期由程序展开)
Parameter file/var/lib/projeqtor/config/parameters.php连接参数文件

提交后安装程序逐项检查运行环境,实测输出如下(messageOK 行已去掉 HTML 标签,保留原文):

PHP version is 8.1.2-1ubuntu2.28 : OK
Module PDO is available : OK
Module PDO for 'MYSQL' is available : OK
Module MBSTRING is available : OK
Class  ZipArchive is available : OK
Module DOMDocument is available : OK
GD Library is available and correctly installed : OK
Module OPENSSL is available : OK
Module XML is available : OK
max_input_vars=4000 : OK
max_execution_time=30 : OK
memory_limit=512M : OK
file_uploads=1 : OK
session.auto_start is disabled : OK
System command execution functions (exec, system, shell_exec, ...) are disabled : OK
register_globals is disabled : OK
Database 'projeqtor' already exists : OK
Parameters are saved.
On next page, log in as user "admin" with password "admin"

因为 4.2 已手工建库,这里显示 already exists;如果跳过 4.2,安装程序会自己建库并显示 created : OK。最后两行说明配置已落盘,下一步可以登录。

检查生成的两个文件:

$ sudo cat /var/lib/projeqtor/config/parameters.php
<?php
// =======================================================================================
// Automatically generated parameter file
// on 2026-10-28 01:29:43
// =======================================================================================
$paramDbType='mysql';
$paramDbHost='127.0.0.1';
$paramDbPort='3306';
$paramDbUser='projeqtor';
$paramDbPassword='q1w2e3r4';
$paramDbName='projeqtor';
$paramDbPrefix='';
$SslKey='';
$SslCert='';
$SslCa='';
$logFile='/var/lib/projeqtor/log/projeqtor_${date}.log';
$logLevel='2';
$enforceUTF8='1';
//======= END===
$ sudo cat /var/www/projeqtor/tool/parametersLocation.php
<?php
$parametersLocation = '/var/lib/projeqtor/config/parameters.php';

$logFile 中的 ${date} 是安装器写入的占位符,运行时被替换为当天日期,因此实际日志文件为 /var/lib/projeqtor/log/projeqtor_20261028.log。不要把 ${date} 手工改成固定日期,否则日志会一直写进同一个文件、无法按天切分。

parameters.php 只保存数据库连接、日志与 UTF-8 强制开关;邮件、目录、密码策略等业务参数不在这里,而是安装后写入数据库 parameter 表。理解这一点是后续调参的关键。

4.10 首次登录与建库

在服务器本机访问 http://127.0.0.1/view/main.php(远程访问把 127.0.0.1 换成服务器实际 IP),用 admin / admin 首次登录。空库会触发 db/maintenance.php 自动建表并更新到当前版本,日志中可见:

$ grep -n 'DATABASE UPDATE COMPLETED' /var/lib/projeqtor/log/projeqtor_20261028.log | tail -1
7560:2026-10-28 01:29:46.773 ===== TRACE ===== DATABASE UPDATE COMPLETED TO VERSION V13.1.1

建库完成后按提示重新登录,并立即在用户配置中把密码改为 q1w2e3r4。本文后续验证均使用 admin / q1w2e3r4。登录成功可在日志确认:

$ grep -n "NEW CONNECTED USER 'admin'" /var/lib/projeqtor/log/projeqtor_20261028.log | tail -1
2026-10-28 01:31:38.679 ===== TRACE ===== [1] NEW CONNECTED USER 'admin'

4.11 安装结果验证

三项一起验证:Web 可访问、数据库表齐全、版本正确。

$ curl -s -o /dev/null -w 'HTTP %{http_code} bytes %{size_download}\n' http://127.0.0.1/
HTTP 200 bytes 3812
$ mysql -N -u projeqtor -pq1w2e3r4 -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='projeqtor';"
357
$ mysql -N -u projeqtor -pq1w2e3r4 projeqtor -e "SELECT parameterValue FROM parameter WHERE parameterCode='dbVersion';"
V13.1.1

357 张表、dbVersion=V13.1.1 是建库完成的硬指标。若表数为 0,说明首次登录没有触发升级,检查 tool/parametersLocation.php 是否指向正确的参数文件。

五、方案二:Apache 2.4 + mod_php(备选)

有些团队已有 Apache 运维体系,或需要 .htaccess 做细粒度控制,此时可用 Apache + mod_php 替代 Nginx + PHP-FPM。本章在同一台机器上用 8081 端口实测,避免与 80 端口的 Nginx 冲突;如果服务器只跑 Apache,把下文端口全部改成 80 即可。

5.1 安装 Apache 与 PHP 模块

$ sudo apt-get install -y apache2 libapache2-mod-php8.1
$ apache2 -v | head -2
Server version: Apache/2.4.52 (Ubuntu)
Server built:   2026-10-08T19:59:46
$ a2query -m php8.1
php8.1 (enabled by maintainer script)

libapache2-mod-php8.1 会自动把 Apache 切换到 mpm_prefork,这是 mod_php 的硬性要求;不要同时启用 mpm_event,否则模块加载失败。

5.2 配置监听端口与虚拟主机

修改 /etc/apache2/ports.conf,把 Listen 80 改为 8081:

Listen 8081

<IfModule ssl_module>
	Listen 443
</IfModule>

<IfModule mod_gnutls.c>
	Listen 443
</IfModule>

新建 /etc/apache2/sites-available/projeqtor.conf:

<VirtualHost *:8081>
    ServerName projeqtor.example.com
    DocumentRoot /var/www/projeqtor

    <Directory /var/www/projeqtor>
        Options FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    DirectoryIndex index.php index.html
    ErrorLog /var/log/apache2/projeqtor_error.log
    CustomLog /var/log/apache2/projeqtor_access.log combined
</VirtualHost>

启用站点与重写模块,并做语法检查:

$ sudo a2dissite 000-default
$ sudo a2ensite projeqtor
$ sudo a2enmod rewrite
$ apache2ctl configtest
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.89.59.10. Set the 'ServerName' directive globally to suppress this message
Syntax OK

AH00558 只是未设置全局 ServerName 的提示,不是错误;在 apache2.conf 中加一行 ServerName localhost 即可消除。

5.3 启动并验证 Apache

$ sudo systemctl enable apache2
$ sudo systemctl start apache2
$ systemctl is-active apache2
active
$ curl -s -o /tmp/apachehome.html -w 'HTTP %{http_code} bytes %{size_download}\n' http://127.0.0.1:8081/
HTTP 200 bytes 3812
$ grep -o '<title>[^<]*' /tmp/apachehome.html | head -1
<title>ProjeQtOr

Apache 读取的是自己的 /etc/php/8.1/apache2/php.ini,而不是 4.7 节的 FPM 配置。若切换为 Apache 主线,需要把同一组 max_input_vars、memory_limit、upload_max_filesize 写入该文件并重启 Apache。

5.4 两种 Web 服务器方案对比

维度Nginx + PHP-FPMApache + mod_php
进程模型Nginx 处理静态,FPM 独立管理 PHP 进程PHP 嵌入 Apache 进程,prefork 模型
内存占用静态请求不占 PHP 进程,通常更低每个 Apache 进程都带 PHP 解释器,内存更高
配置方式集中式 server/location 块虚拟主机 + .htaccess 可分散配置
适用场景高并发、静态资源多、希望 PHP 与 Web 解耦已有 Apache 体系、依赖 .htaccess、并发不高

本文主线选 Nginx + PHP-FPM:ProjeQtOr 的请求以 PHP 为主,但附件下载和报表静态文件不少,FPM 独立进程便于单独限制内存与超时;Apache 方案胜在配置直观,适合小规模团队或既有运维规范。

六、关键配置说明

本章把安装过程中出现的配置项集中解释,便于后续调优和排障。每条配置都对应一个可验证的运行结果,不要只改文件不验证。

6.1 Nginx 与 PHP-FPM 的衔接

Nginx 通过 fastcgi_pass unix:/run/php/php8.1-fpm.sock 把 .php 请求交给 FPM。三个检查点:

$ ls -l /run/php/php8.1-fpm.sock
srw-rw---- 1 www-data www-data 0 Oct 27 17:26 /run/php/php8.1-fpm.sock
$ nginx -t
nginx: configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ systemctl is-active php8.1-fpm
active

socket 不存在 → 检查 FPM 是否启动;socket 路径与 fastcgi_pass 不一致 → 502;Nginx 用户无权访问 socket → 502 且 FPM 日志出现 Permission denied。

6.2 PHP 参数与业务上限

参数实测值作用与调整建议
max_input_vars4000工作分配页面提交字段多,低于 2000 会丢字段
memory_limit512MPDF/Excel 导出最低建议;大报表可提到 1G
max_execution_time30Web 请求上限;cron 由 request_terminate_timeout=0 兜底
upload_max_filesize100M单文件上传上限,需与 Nginx client_max_body_size 对齐
post_max_size100M表单总大小上限,不能小于上传上限
request_terminate_timeout0FPM 不主动杀长请求,保证 cron 常驻

修改后用 php -i 与 php-fpm8.1 -t 双重确认,再 systemctl reload php8.1-fpm。

6.3 数据库字符集

$ mysql -u root -e "SELECT @@version, @@character_set_server, @@collation_server;"
@@version	@@character_set_server	@@collation_server
10.6.23-MariaDB-0ubuntu0.22.04.1	utf8mb4	utf8mb4_general_ci

库、表、连接三处都必须是 utf8mb4。只改服务器默认值而建库时用了 utf8,中文生僻字和 emoji 仍会截断;本文在 4.2 建库时显式指定 utf8mb4,避免继承旧默认值。

6.4 目录布局与权限

路径权限/属主内容
/var/www/projeqtor755 / www-data:www-data程序代码
/var/lib/projeqtor/config755 / www-data:www-dataparameters.php
/var/lib/projeqtor/log755 / www-data:www-data按天日志
/var/lib/projeqtor/files/attach755 / www-data:www-data附件
/var/lib/projeqtor/files/documents755 / www-data:www-data文档
/var/lib/projeqtor/files/report755 / www-data:www-data报表临时文件

目录放在 Web 根之外,即使上传了可执行脚本也无法通过 URL 直接访问,这是 ProjeQtOr 官方安全建议的核心。

七、升级与降级

本章给出升级到下一个 13.x 补丁版与回滚的标准流程。升级动作本文未在实测环境执行,命令按官方“覆盖代码 + 管理员登录触发数据库升级”机制给出,执行前务必先备份。

7.1 升级步骤

$ sudo tar -czf /var/backups/projeqtor-code-$(date +%F).tar.gz -C /var/www projeqtor
$ mysqldump -u projeqtor -pq1w2e3r4 --single-transaction --routines --triggers projeqtor > /var/backups/projeqtor-db-$(date +%F).sql
$ sudo systemctl stop nginx
$ sudo cp -a /var/www/projeqtor/tool/parametersLocation.php /var/backups/parametersLocation.php
$ sudo unzip -q projeqtorV13.1.1.zip -d /tmp/projeqtor-new
$ sudo cp -a /tmp/projeqtor-new/projeqtor/. /var/www/projeqtor/
$ sudo cp -a /var/backups/parametersLocation.php /var/www/projeqtor/tool/parametersLocation.php
$ sudo chown -R www-data:www-data /var/www/projeqtor
$ sudo systemctl start nginx

随后用管理员账号登录,系统自动执行数据库升级。预期日志出现新的版本号:

2026-10-28 01:29:46.773 ===== TRACE ===== DATABASE UPDATE COMPLETED TO VERSION V13.1.1

上面用当前安装的 projeqtorV13.1.1.zip 演示覆盖流程;实际升级时把该文件名换成官网发布页给出的新版本包名(例如下一补丁版),版本号必须与发布页一致,不能凭经验填写。数据库版本变化由登录触发,日志中的 DATABASE UPDATE COMPLETED TO VERSION 行会显示新版本号。

7.2 回滚步骤

$ sudo systemctl stop nginx
$ sudo rm -rf /var/www/projeqtor
$ sudo tar -xzf /var/backups/projeqtor-code-2026-10-28.tar.gz -C /var/www
$ mysql -u projeqtor -pq1w2e3r4 projeqtor < /var/backups/projeqtor-db-2026-10-28.sql
$ sudo systemctl start nginx

回滚必须同时恢复代码与数据库,只回代码会留下新版本写入的表结构,旧代码可能无法识别。恢复后访问首页确认 200,再登录确认版本号回到备份时的值。

八、常见问题与排障

本章按“现象 → 定位 → 解决”组织,全部来自本次安装实测或由实测错误直接推导。遇到问题时先看日志,再改配置。

8.1 访问返回 502 Bad Gateway

先确认 FPM 是否在跑、socket 是否存在:

$ systemctl is-active php8.1-fpm
active
$ ls -l /run/php/php8.1-fpm.sock
srw-rw---- 1 www-data www-data 0 Oct 27 17:26 /run/php/php8.1-fpm.sock
$ tail -20 /var/log/nginx/projeqtor_error.log

若日志出现 connect() to unix:/run/php/php8.1-fpm.sock failed (2: No such file or directory),说明 FPM 没启动或 socket 路径写错;Permission denied 则是 Nginx 用户不在 www-data 组。

8.2 页面 504 Gateway Time-out

长任务或 cron 请求会超过 Nginx 默认 60 秒:

<html>
<head><title>504 Gateway Time-out</title></head>
<body>
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx/1.18.0 (Ubuntu)</center>
</body>
</html>

解决:把 request_terminate_timeout 设为 0,并在 Nginx 对应 location 增加 fastcgi_read_timeout 300s;。cron 是常驻进程,不应通过浏览器等待它返回,启动后由后台继续执行。

8.3 数据库连接被拒绝

数据库停机时,首页返回真实的 PDO 错误:

SQLSTATE[HY000] [2002] Connection refused

定位:

$ systemctl is-active mariadb
inactive
$ sudo systemctl start mariadb
$ systemctl is-active mariadb
active
$ mysql -N -u projeqtor -pq1w2e3r4 -e "SELECT 1;"
1

若是 Access denied,检查 4.2 是否同时创建了 localhost 与 127.0.0.1 两个账号,以及 parameters.php 中的 paramDbHost 是 127.0.0.1 还是 localhost。

8.4 安装向导反复出现

只要 tool/parametersLocation.php 不存在或不可读,应用就会回到配置页。检查:

$ ls -l /var/www/projeqtor/tool/parametersLocation.php
-rw-r--r-- 1 www-data www-data 51 Oct 27 17:29 /var/www/projeqtor/tool/parametersLocation.php
$ sudo -u www-data cat /var/www/projeqtor/tool/parametersLocation.php
<?php
$parametersLocation = '/var/lib/projeqtor/config/parameters.php';
$ sudo -u www-data test -r /var/lib/projeqtor/config/parameters.php && echo readable
readable

文件存在但 PHP 进程读不到(属主是 root、权限 600),同样会重定向到安装页。

8.5 上传文档或生成报表报目录不存在

这是 4.5 节提到的实测坑:安装向导只建附件目录。验证并补齐:

$ stat -c '%a %U:%G %n' /var/lib/projeqtor/files/documents
stat: cannot statx '/var/lib/projeqtor/files/documents': No such file or directory
$ sudo mkdir -p /var/lib/projeqtor/files/documents /var/lib/projeqtor/files/report
$ sudo chown -R www-data:www-data /var/lib/projeqtor/files
$ stat -c '%a %U:%G %n' /var/lib/projeqtor/files/documents /var/lib/projeqtor/files/report
755 www-data:www-data /var/lib/projeqtor/files/documents
755 www-data:www-data /var/lib/projeqtor/files/report

8.6 PHP 报错但页面空白

打开 PHP 错误日志定位:

$ sudo tail -50 /var/log/php8.1-fpm.log
$ sudo tail -50 /var/log/nginx/projeqtor_error.log
$ sudo -u www-data php -l /var/www/projeqtor/index.php
No syntax errors detected in /var/www/projeqtor/index.php

生产环境不要把 display_errors 打开到页面,错误应进日志;排障时临时把 log_errors=On、error_log 指向可写文件即可。

九、卸载与清理

本章用于测试环境回收或彻底重装。命令未在实测环境执行,执行前确认数据已备份,尤其是数据库与附件目录。

$ sudo systemctl stop nginx
$ sudo systemctl disable nginx
$ sudo systemctl stop php8.1-fpm
$ sudo systemctl stop mariadb
$ sudo apt-get purge -y nginx nginx-common php8.1-fpm php8.1-cli \
    php8.1-mysql php8.1-mbstring php8.1-gd php8.1-xml php8.1-zip \
    php8.1-imap php8.1-curl mariadb-server mariadb-client
$ sudo rm -rf /var/www/projeqtor /var/lib/projeqtor
$ sudo mysql -e "DROP DATABASE IF EXISTS projeqtor;"
$ sudo mysql -e "DROP USER IF EXISTS 'projeqtor'@'localhost'; DROP USER IF EXISTS 'projeqtor'@'127.0.0.1';"

若还要清理日志与备份:

$ sudo rm -f /var/log/nginx/projeqtor_access.log /var/log/nginx/projeqtor_error.log
$ sudo rm -rf /var/backups/projeqtor-*

卸载不会自动删除数据库,必须显式 DROP DATABASE;否则重装后仍会连到旧库,看到旧数据。

十、参考链接

以上链接的版本信息与文件元数据查询日期均为 2026-10-28。