最近打算把博客基础环境迁移到 typecho ,其实在 2017 年为的博客就是使用 typecho 搭建的,但是 2019 年考虑到动态网站并且还是基于 php 的博客系统的安全性问题,我就迁移到了静态博客系统 hexo 上,最后 2020 年又迁移到 hugo 上,虽然静态博客系统可以抵抗 xss 反射和 xss 持久化攻击,但是部分功能目前满足不了我,决定迁移会到 typecho 系统上,本篇博客记录一下如何配置 php 运行环境。


php-fpm 环境

作为一个基本的动态的 web 服务来说必须有要数据库和 http 服务器支持,所以这里就诞生了一些基于开源软件的解决方案,例如 LNMP 的架构,php 本身只是一个动态类型的脚本语言不能作为 http 服务器,这里通过将 php-fpm 和 nginx 整合到一起来提供动态网站的服务。

nginx 和 postgresql 服务器采用通过 rpm 软件包的方式安装,相比于通过源代码编译安装的方式要简单多一点,也不需要等待很长的编译时间,而 php-fpm 为了稳定性采用源代码的方式进行编译安装,首先运行下面命令:

# 安装 nginx 
yum install -y nginx

相对于 nginx 而 postgresql 数据库安装要复杂,postgresql 目前有很多版本,安装要去官方网站查询对应的版本,并且还需要设置最新的 yum 仓库信息:

# 安装 postgresql
# Install the repository RPM:
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm

# Disable the built-in PostgreSQL module:
sudo dnf -qy module disable postgresql

# Install PostgreSQL:
sudo dnf install -y postgresql15-server

# Optionally initialize the database and enable automatic start:
sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
sudo systemctl enable postgresql-15
sudo systemctl start postgresql-15

nginx 和 postgresql 配置完成之后,接下来将需要进行编译安装 php-fpm 环境,先要解决相关依赖包问题,如何下载 php8 最新版本源码包:

# 安装依赖的软件包
sudo yum groupinstall "Development Tools"
# 下载 php8 的源码包
wget https://www.php.net/distributions/php-8.2.3.tar.gz
# 解压源代码和进入目录
tar zxf php-8.2.3.tar.gz && cd php-8.2.3

接下来要对 php-fpm 进行源代码编译安装,首先我们要对进行参数设置支持数据库模块,这里要支持 psql 模块,如果使用的是 mysql 使用 --with-mysql 参数,需要指定 psql 的安装目录 :

./configure --prefix=/usr/local/php --with-config-file-path=/usr/local/php/etc --with-pdo-pgsql=/usr/pgsql-15 --with-pgsql=/usr/pgsql-15 --with-freetype --with-jpeg --with-zlib --enable-bcmath --enable-shmop --enable-sysvsem --with-curl --enable-mbstring --with-openssl --with-mhash --enable-pcntl --enable-sockets --with-ldap-sasl --with-xmlrpc --enable-soap --with-gettext  --enable-fpm --with-zip --enable-gd --with-webp

在此过程中会不断检测依赖软件关系和版本,如果遇到版本较低软件可以手动安装和更新,不知道包在 yum 仓库的完整包名可以使用 search 查看:

如果默认 yum 不能正常搜索到软件包,可以尝试手动下载对应的软件包安装,第三方软件包查看地址 pkgs.org ,当 configure 全部跑完之后会提示你欢迎使用 php 说明整个环境配置没有问题了,如下图:

接下来执行 make 命令,make 命令会根据改成的 configure 文件规则来生产二进制文件,最后使用 make install 命令进行安装:

# 生产二进制文件
make
# 安装到配置的目录中
make install

最后要配置 php 一些环境文件,例如 php.ini 文件可以配置运行环境时参数开启和不开启什么样的功能,在安装目录中是没有这个文件的,需要从源代码包中的模版文件中拷贝;php-fpm 全名是 PHP FastCGI 进程管理器,php-fpm.conf 是用来配置进程的文件,php-fpm 启动后会先读 php.ini ,然后再读相应的 conf 配置文件,conf 配置可以覆盖 php.ini 的配置;另外最后为控制 web 网站的文件,可以配置网站连接性能相关参数:

# 配置 ini
cp php.ini-development /usr/local/php/lib/php.ini
# 创建php-fpm进程管理文件
mv /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf
# 配置网站文件
mv /usr/local/php/etc/php-fpm.d/www.conf.default /usr/local/php/etc/php-fpm.d/www.conf

最后一步需要把 php-fpm 的服务加入到启动项中,当重新启动服务器会自动加载生效:

# 加入启动项,某些系统是 init.d 文件夹
cp sapi/fpm/init.d.php-fpm /etc/init/php-fpm

由于 web 服务器在公网上提供服务难免遇到恶意用户情况,并且 php 上一种动态脚本语言,这里需要禁止一些危险的的内置函数,需要在 /usr/local/php/lib/php.ini 的 disable_fucntion 字段添加危险函数列表:

disable_functions = passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv

最后在还需要将 php-fpm 服务整合到 nginx 中,这样才能使得基于 php 环境网站能正常服务,在 nginx 配置文件中加入下列信息:

server {
    listen       443 ssl http2;
    #listen      [::]:443 ssl http2;
    server_name  www.ibyte.me;
    root         /var/wwwroot/www.ibyte.me;

    ssl_certificate         "/var/wwwroot/ssl/www.ibyte.me.cer";
    ssl_certificate_key     "/var/wwwroot/ssl/www.ibyte.me.key";
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_ciphers PROFILE=SYSTEM;
    ssl_prefer_server_ciphers on;


    # security headers
    add_header X-XSS-Protection          "1; mode=block" always;
    add_header X-Content-Type-Options    "nosniff" always;
    add_header Referrer-Policy           "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy   "default-src 'self' http: https: ws: wss: data: blob: 'unsafe-inline'; frame-ancestors 'self';" always;
    add_header Permissions-Policy        "interest-cohort=()" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;


    # logging 设置访问日志
    access_log              /var/wwwroot/log/nginx_access.log combined buffer=512k flush=1m;
    error_log               /var/wwwroot/log/nginx_error.log warn;


    # gzip 开启压缩功能
    gzip            on;
    gzip_vary       on;
    gzip_proxied    any;
    gzip_comp_level 6;
    gzip_types      text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;


    location / {
        # 设置默认索引
        index  index.php index.html index.htm;
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    # 这里配置 php-fpm 让 *.php 的请求都去 fastcgi_param 上处理
    location ~ .*\.php(\/.*)*$ {
        # 这里必须和SCRIPT_FILENAME一直,巨坑!
        root                    /var/wwwroot/www.ibyte.me;
        fastcgi_pass            127.0.0.1:9000;
        fastcgi_index           index.php;
        fastcgi_param           SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include                 fastcgi_params;
        fastcgi_buffers         8 16k;
        fastcgi_buffer_size     32k;
    }

}

server {
        listen 80;
        server_name www.ibyte.me;
        return 301 https://$server_name$request_uri;
}

推荐默认不要早默认的 nginx.conf 中修改,应该在 conf.d 目录中单独新建一个域名 conf 文件,配置完成之后使用 systemctl restart nginx 启动,如果启动过程中出现了权限问题添加对应权限即可,我使用机器默认开启了 SELinux 安全功能,这时可能导致读取不到 SSL 文件,关闭 SELinux 功能 setenforce 0

SELinux 功能的配置文件路径 /etc/selinux/config 如果要永久关闭此功能,修改配置为禁止使用,但是这样对于生产系统的安全性就会降低,推荐还是在启动 nginx 和 php-fpm 临时关闭,或者将 php-fpm 加入到白名单中,输入下面命令:

# 查看 SElinux 状态
sestatus
# 加入到白名单中
setsebool -P httpd_read_user_content 1
setsebool -P httpd_can_network_connect 1

到此基础软件运行环境配置完成,为了测试环境是否正常运行可以新建一个 phpinfo.php 测试,内容如下:

<?php
echo phpinfo();
?>

如果能正常显示环境信息说明正常,接下来要去初始化 postgresql 数据库:

# 初始化数据库
postgresql-15-setup initdb
# 修改默认密码
sudo -u postgres psql
# 输入 \password 修改密码

最好开启远程登录功能,相关的数据库配置文件在 /var/lib/pgsql/15/data/ 路径下:

# 允许远程登录 vim postgresql.conf
listen_addresses = '*'
# 最后面修改 pg_hba.conf 添加一行
host    all        all         all                   md5

# 创建新的数据库
create user blog with password 'xxxxx';
create database blog_db owner blog;
GRANT ALL PRIVILEGES ON DATABASE blog_db to blog;

最后设置防火墙开放一些端口允许远程访问,推荐使用基于内核的 netfilter 的 iptables 工具:

# 添加 ssh http https psql
iptables -I INPUT -p tcp --dport 22 -j ACCEPT
iptables -I INPUT -p tcp --dport 80 -j ACCEPT
iptables -I INPUT -p tcp --dport 443 -j ACCEPT
iptables -I INPUT -p tcp --dport 5432 -j ACCEPT
iptables -P INPUT DROP
# 持久化化规则
iptables-save >/etc/iptables-script
# 设置开启自动恢复规则
echo '/sbin/iptables-restore /etc/iptables-script' >>/etc/rc.d/rc.local

另外一种方式为 firewalld 工具,老版本的系统不会安装需要自己手动安装:

yum install -y firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --zone=public --add-port=22/tcp
firewall-cmd --permanent --zone=public --add-port=5432/tcp
firewall-cmd --reload
systmctl enable firewalld

由于使用的是 typecho 系统生成的数据配置文件在网站根目录中,安全起见设置成为不允许所有人通过 http 访问:

    # 禁止访问 config.inc.php 文件
    location =/config.inc.php {
       return 403;
    }

至此配置完成,重启 nignx 和 php-fpm 。


其他资料

便宜 VPS vultr
最后修改:2023 年 07 月 05 日
如果觉得我的文章对你有用,请随意赞赏 🌹 谢谢 !